How to Enable Push Notifications for File Changes in Google Drive with Apps Script

Are you looking for a way to receive notifications in real-time when an important spreadsheet in your Google Drive get modified or is accidently deleted by sometimes? Well, Google Drive offers an API to help you set up a watch on any file in your Google Drive be it a document, presentation or even a PDF file. This means that you can receive instant notifications whenever the content or even permissions of that file changes.

This tutorial explains how you can setup watch notifications on any file in your Google Drive with the help of Google Apps Script.

Setup a File Watch in Google Drive

To get started, type script.new in the browser to open the Apps Script editor and add the code below to create a watch. You’d need the unique ID of the Google Drive file and the webhook URL where the notifications would be send when the file gets modified.

const API_BASE_URL = 'https://www.googleapis.com/drive/v3';
const SUBSCRIPTION_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours in milliseconds

/**
 * Starts a subscription for receiving notifications about changes to a Google Drive file.
 *
 * @param {string} fileId - The ID of the file to watch for changes.
 * @param {string} webhookUrl - The URL where notifications will be sent.
 * @returns {void}
 */
const startSubscription = (fileId, webhookUrl) => {
  try {
    // Prepare the payload for the channel subscription
    const channelPayload = {
      id: Utilities.getUuid(), // Generate a unique ID for the channel
      address: webhookUrl,
      expiration: Date.now() + SUBSCRIPTION_DURATION_MS,
      type: 'web_hook',
      token: `fileId=${fileId}&source=labnol.org`,
    };

    // Construct the API endpoint URL for starting the subscription
    const endPoint = Utilities.formatString(`${API_BASE_URL}/files/%s/watch?supportsAllDrives=true`, fileId);

    // Call the Drive API to start the subscription
    const response = UrlFetchApp.fetch(endPoint, {
      method: 'POST',
      contentType: 'application/json',
      headers: {
        Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
      },
      payload: JSON.stringify(channelPayload), // Convert payload to JSON string
    });

    // Parse the response to extract subscription information
    const { id, resourceId } = JSON.parse(response);

    // Store subscription information in script properties
    const subscriptions = { id, resourceId, fileId, webhookUrl };
    PropertiesService.getScriptProperties().setProperty('subscriptions', JSON.stringify(subscriptions));
  } catch (error) {
    // Handle errors that might occur during subscription setup
    console.error(`Error starting subscription: ${error.message}`);
  }
};

Initialize Drive Watch Trigger

By default, a file watch expires in an hour. To extend this duration to 24 hours, we’ll use the SUBSCRIPTION_DURATION_MS variable. Please note that there’s no way to set up an indefinite watch. We’ll thus setup a time-based trigger in Apps Script to automatically renew the watch every 24 hours.

const initializeWatchApp = () => {
  const fileId = '<<Drive File Id>>';
  const webhookUrl = 'https://<<Webhook URL>>';

  startSubscription(fileId, webhookUrl);

  ScriptApp.getProjectTriggers().forEach((trigger) => {
    ScriptApp.deleteTrigger(trigger);
  });

  ScriptApp.newTrigger('triggerRenewSubscription').timeBased().everyHours(24).create();

  // Used to add the necessary Drive Scope
  const file = DriveApp.getFileById(fileId);
  console.log(`Push notifications activated for ${file.getName()}`);
};

Renew File Watch Automatically

The trigger functions manages the process of creating and renewing channel subscriptions for receiving notifications about changes to specific files in Google Drive. It leverages UrlFetchApp.fetch method instead of the Drive.Files.watch service since the latter uses the older version v2 of Google Drive API.

Since we do not want multiple notifications for the same file, we manually stop any existing subscriptions for a file before adding a new watch.

const triggerRenewSubscription = () => {
  try {
    // Retrieve subscription information from script properties
    const data = PropertiesService.getScriptProperties().getProperty('subscriptions');
    const subscriptions = JSON.parse(data);
    const { resourceId, id, fileId, webhookUrl } = subscriptions;

    // Stop the current subscription
    UrlFetchApp.fetch(`${API_BASE_URL}/channels/stop`, {
      method: 'POST',
      contentType: 'application/json',
      headers: {
        Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
      },
      payload: JSON.stringify({ id, resourceId }),
    });

    // Start a new subscription with the same details
    startSubscription(fileId, webhookUrl);

    console.log('Channel subscription renewed successfully!');
  } catch (error) {
    console.error(`Error renewing subscription: ${error.message}`);
  }
};

Handline watch notfications

You may use a web service like webhook.site or requestbin.com to test webhook notifications for file changes.

It is also possible to publish a Google Script as a web app to handle POST notifications from the Drive API but there’s a limitation - Apps Script cannot read the header of an incoming web require and Drive notifications include the data in the X-Goog-Channel-ID, X-Goog-Channel-Token and X-Goog-Resource-State headers of the request.



source:https://ift.tt/9K3PeA5

Comments

Popular posts from this blog

The 101 Most Useful Websites

Compare MacBook Prices Worldwide with Google Sheets

Interesting Websites to Visit When You’re Bored