Edits history of script submission #14001 for ' Nextcloud script with preprocessor template (windmill)'

  • bun
    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

  • bun
    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