import * as wmill from "windmill-client";
import createClient, { type Middleware } from "openapi-fetch";
// Nextcloud webhook payload types
export interface NextcloudWebhookPayload {
event: NextcloudEvent;
user: NextcloudUser;
time: number; // UNIX timestamp in seconds
}
export interface NextcloudEvent {
node: NextcloudNode;
class: string; // e.g. "OCP\\Files\\Events\\Node\\NodeWrittenEvent"
}
export interface NextcloudNode {
id: number;
path: string;
// optional fields you may see in other events
storage?: string;
size?: number;
name?: string;
}
export interface NextcloudUser {
uid: string;
displayName?: string;
}
/**
* Nextcloud Trigger Preprocessor
*
* This function runs BEFORE the main function.
*
* It processes raw Nextcloud webhook trigger data before passing it to `main()`.
* Supports the available Nextcloud events:
* - FormSubmittedEvent: Form submissions from Nextcloud Forms
* - NodeWrittenEvent: File/folder operations (create, update, delete)
*
* The returned object determines `main()` parameters based on event type.
*
* @param event - Nextcloud trigger data and details
* @returns Processed data for `main()`
*/
export async function preprocessor(
event: {
kind: 'nextcloud',
headers: Record<string, string>,
payload: NextcloudWebhookPayload,
},
) {
if (event.kind === 'nextcloud') {
const payload = event.payload;
const baseEvent = {
eventType: payload.event.class,
userId: payload.user.uid,
timestamp: new Date(payload.time * 1000).toISOString(), // Convert UNIX timestamp to ISO
headers: event.headers || {},
};
// Extract event type from class name
const eventTypeMatch = payload.event.class.match(/(\w+)Event$/);
const eventType = eventTypeMatch ? eventTypeMatch[1] : 'Unknown';
// Handle specific Nextcloud event types
switch (eventType) {
case 'FormSubmitted':
return {
...baseEvent,
category: 'form',
user: {
uid: payload.user.uid,
displayName: payload.user.displayName || ''
},
rawPayload: payload
};
case 'NodeWritten':
return {
...baseEvent,
category: 'file',
user: {
uid: payload.user.uid,
displayName: payload.user.displayName || ''
},
node: {
id: payload.event.node.id,
path: payload.event.node.path,
storage: payload.event.node.storage,
size: payload.event.node.size,
name: payload.event.node.name
},
rawPayload: payload
};
default:
return {
...baseEvent,
category: 'other',
eventClass: payload.event.class,
data: payload.event,
rawPayload: payload
};
}
}
throw new Error(`Expected nextcloud trigger kind, got: ${event.kind}`);
}
/**
* Main Function - Handles processed Nextcloud events
*
* Called AFTER `preprocessor()`, with its return values.
*
* This example demonstrates integrating with Nextcloud APIs using openapi-fetch
* and windmill-client, following the official Nextcloud Hub example patterns.
*
* @param eventType - Type of Nextcloud event class name
* @param category - Event category ('form', 'file', or 'other')
* @param userId - ID of the user who triggered the event
* @param user - User information
* @param node - Node information (for file events)
* @param eventClass - Full event class name (for other events)
* @param data - Generic event data (for other events)
* @param timestamp - Event timestamp
* @param rawPayload - Raw event payload from Nextcloud
* @param nextcloud_resource - Nextcloud resource containing server URL and credentials
*/
export async function main(
eventType: string,
category: string,
userId?: string,
user?: {
uid: string;
displayName: string;
},
node?: {
id?: number;
path?: string;
storage?: string;
size?: number;
name?: string;
},
eventClass?: string,
data?: any,
timestamp?: string,
rawPayload?: NextcloudWebhookPayload,
nextcloud_resource?: string
) {
const resource = await wmill.getResource(nextcloud_resource)
const client = createClient({ baseUrl: resource.baseUrl });
console.log(`Processing Nextcloud event: ${eventType}`);
console.log(`Category: ${category}`);
console.log(`User: ${user?.uid} (${user?.displayName})`);
console.log(`Timestamp: ${timestamp}`);
try {
// Add authentication middleware
const authMiddleware: Middleware = {
async onRequest({ request }: { request: Request }) {
// Add Basic Authentication header
request.headers.set(
"Authorization",
`Basic ${btoa(resource.username + ':' + resource.password)}`
);
// Add required Nextcloud headers
request.headers.set("OCS-APIRequest", "true");
request.headers.set("Content-Type", "application/json");
request.headers.set("Accept", "application/json");
return request;
},
};
client.use(authMiddleware);
console.log(`Connected to Nextcloud at: ${resource.baseUrl}`);
} catch (error) {
console.error('Failed to setup Nextcloud API client:', error);
return { success: false, error: 'Failed to configure Nextcloud API' };
}
// Handle specific event types
switch (category) {
case 'form':
console.log(`Form event processed: ${eventType}`);
break;
case 'file':
console.log(`File event: ${node?.path} (ID: ${node?.id})`);
console.log(`Node details:`, {
path: node?.path,
size: node?.size,
storage: node?.storage,
name: node?.name
});
break;
case 'other':
console.log(`Other event type: ${eventClass}`);
console.log('Event data:', data);
if (client && userId) {
try {
// Example: Log unknown events (adjust endpoint based on your Nextcloud setup)
console.log('Logging unknown event to system');
} catch (error) {
console.error('Failed to log unknown event:', error);
}
}
break;
}
// Return event summary
return {
success: true,
eventType,
category,
userId,
timestamp,
processed: true,
message: `Successfully processed ${eventType} event`,
eventDetails: {
user: user || null,
node: node || null,
data: data || null,
eventClass: eventClass || null
}
};
}Submitted by dieriba.pro916 214 days ago
import * as wmill from "windmill-client";
import createClient, { type Middleware } from "openapi-fetch";
/**
* Nextcloud Trigger Preprocessor
*
* This function runs BEFORE the main function.
*
* It processes raw Nextcloud webhook trigger data before passing it to `main()`.
* Supports the available Nextcloud events:
* - FormSubmittedEvent: Form submissions from Nextcloud Forms
* - NodeWrittenEvent: File/folder operations (create, update, delete)
*
* The returned object determines `main()` parameters based on event type.
*
* @param event - Nextcloud trigger data and details
* @returns Processed data for `main()`
*/
export async function preprocessor(
event: {
kind: 'nextcloud',
payload: string,
event_type: string,
user_id?: string,
timestamp?: string,
headers?: Record<string, string>,
webhook_id?: string,
resource_path: string
},
) {
if (event.kind === 'nextcloud') {
let parsedPayload: any;
try {
// Parse the JSON payload from Nextcloud
parsedPayload = JSON.parse(event.payload);
} catch (err) {
throw new Error(`Invalid JSON payload from Nextcloud: ${err}`);
}
const baseEvent = {
eventType: event.event_type,
userId: event.user_id || parsedPayload.user?.uid,
timestamp: event.timestamp || parsedPayload.time || new Date().toISOString(),
webhookId: event.webhook_id,
headers: event.headers || {},
resource_path: event.resource_path
};
// Handle specific Nextcloud event types
switch (event.event_type) {
case 'FormSubmittedEvent':
return {
...baseEvent,
category: 'form',
user: {
uid: parsedPayload.user?.uid || '',
displayName: parsedPayload.user?.displayName || ''
},
form: {
id: parsedPayload.event?.form?.id,
hash: parsedPayload.event?.form?.hash,
title: parsedPayload.event?.form?.title,
description: parsedPayload.event?.form?.description,
ownerId: parsedPayload.event?.form?.ownerId
},
submission: {
id: parsedPayload.event?.submission?.id,
formId: parsedPayload.event?.submission?.formId,
userId: parsedPayload.event?.submission?.userId,
timestamp: parsedPayload.event?.submission?.timestamp
},
rawPayload: parsedPayload
};
case 'NodeWrittenEvent':
return {
...baseEvent,
category: 'file',
user: {
uid: parsedPayload.user?.uid || '',
displayName: parsedPayload.user?.displayName || ''
},
node: {
id: parsedPayload.event?.node?.id,
path: parsedPayload.event?.node?.path
},
rawPayload: parsedPayload
};
default:
// Generic event handling for future events
return {
...baseEvent,
category: 'other',
data: parsedPayload.event || parsedPayload,
rawPayload: parsedPayload
};
}
}
throw new Error(`Expected nextcloud trigger kind, got: ${event.kind}`);
}
/**
* Main Function - Handles processed Nextcloud events
*
* Called AFTER `preprocessor()`, with its return values.
*
* This example demonstrates integrating with Nextcloud APIs using openapi-fetch
* and windmill-client, following the official Nextcloud Hub example patterns.
*
* @param eventType - Type of Nextcloud event ('FormSubmittedEvent' or 'NodeWrittenEvent')
* @param category - Event category ('form', 'file', or 'other')
* @param userId - ID of the user who triggered the event
* @param user - User information
* @param form - Form information (for FormSubmittedEvent)
* @param submission - Submission details (for FormSubmittedEvent)
* @param node - Node information (for NodeWrittenEvent)
* @param data - Generic event data (for other events)
* @param timestamp - Event timestamp
* @param rawPayload - Raw event payload from Nextcloud
* @param nextcloud_resource - Nextcloud resource containing server URL and credentials
*/
export async function main(
eventType: string,
category: string,
userId?: string,
user?: {
uid: string;
displayName: string;
},
form?: {
id?: number;
hash?: string;
title?: string;
description?: string;
ownerId?: string;
},
submission?: {
id?: number;
formId?: number;
userId?: string;
timestamp?: number;
},
node?: {
id?: string;
path?: string;
},
data?: any,
timestamp?: string,
rawPayload?: any,
resource_path?: string
) {
const nextcloud_resource = await wmill.getResource(resource_path)
const client = createClient({ baseUrl: nextcloud_resource.baseUrl });
console.log(`Processing Nextcloud event: ${eventType}`);
console.log(`Category: ${category}`);
console.log(`User: ${user?.uid} (${user?.displayName})`);
console.log(`Timestamp: ${timestamp}`);
try {
// Add authentication middleware
const authMiddleware: Middleware = {
async onRequest({ request }: { request: Request }) {
// Add Basic Authentication header
request.headers.set(
"Authorization",
`Basic ${btoa(nextcloud_resource.username + ':' + nextcloud_resource.password)}`
);
// Add required Nextcloud headers
request.headers.set("OCS-APIRequest", "true");
request.headers.set("Content-Type", "application/json");
request.headers.set("Accept", "application/json");
return request;
},
};
client.use(authMiddleware);
console.log(`Connected to Nextcloud at: ${nextcloud_resource.baseUrl}`);
} catch (error) {
console.error('Failed to setup Nextcloud API client:', error);
return { success: false, error: 'Failed to configure Nextcloud API' };
}
// Handle specific event types
switch (eventType) {
case 'FormSubmittedEvent':
console.log(`Form submitted: "${form?.title}" (ID: ${form?.id})`);
console.log(`Submission ID: ${submission?.id}`);
break;
case 'NodeWrittenEvent':
console.log(`Node written: ${node?.path} (ID: ${node?.id})`);
break;
default:
console.log(`Unhandled event type: ${eventType}`);
console.log('Raw payload:', rawPayload);
if (client && userId) {
try {
// Log unknown events to activity stream
const activityResponse = await client.POST("/ocs/v2.php/apps/activity/api/v2/activity", {
params: {
header: {
"OCS-APIRequest": true,
},
query: {
format: "json",
},
},
body: {
type: "unknown_event",
affecteduser: userId || "system",
subject: `Unknown event: ${eventType}`,
message: `Unhandled event logged at ${timestamp}`
},
});
if (activityResponse.error) {
console.error('Failed to log unknown event:', activityResponse.error);
} else {
console.log('Logged unknown event to activity stream');
}
} catch (error) {
console.error('Failed to log unknown event:', error);
}
}
break;
}
// Return event summary
return {
success: true,
eventType,
category,
userId,
timestamp,
processed: true,
message: `Successfully processed ${eventType} event`,
eventDetails: {
user: user || null,
form: form || null,
submission: submission || null,
node: node || null,
data: data || null
}
};
}Submitted by dieriba.pro916 214 days ago