Загрузка файлов на Google Диск из Google Forms

Уровень владения программированием : начинающий
Продолжительность : 10 минут
Тип проекта : Автоматизация с использованием триггера, управляемого событиями.

Цели

  • Поймите, для чего предназначено это решение.
  • Разберитесь, что делают службы Apps Script в рамках данного решения.
  • Настройте скрипт.
  • Запустите скрипт.

Об этом решении

Одновременно загружайте и упорядочивайте файлы в Google Drive с помощью Google Forms. Форма содержит поля для ввода файлов для загрузки и для указания способа их организации.

Скриншот формы для загрузки файлов

Как это работает

Функция настройки создает папку для хранения всех загруженных файлов и триггер, который срабатывает каждый раз, когда кто-то отправляет форму. Когда пользователь заполняет форму, он выбирает файлы для загрузки и подпапку для их хранения. После отправки формы скрипт перенаправляет файлы в соответствующую подпапку. Если папка еще не существует, скрипт создает ее.

Сервисы Apps Script

Данное решение использует следующие сервисы:

  • Скриптовая служба — создает триггер, который срабатывает каждый раз, когда кто-то отправляет форму.
  • Служба свойств — хранит идентификатор триггера, который скрипт создает во время настройки, чтобы предотвратить дублирование триггеров.
  • Служба Google Диска — во время настройки получает местоположение формы в Google Диске и создает папку в том же месте. Когда пользователь отправляет форму, служба Google Диска направляет файлы в эту папку, а при необходимости — в указанную подпапку. Если подпапка еще не существует, скрипт создает ее.
  • Служба форм — получает имена файлов и папок, выбранные пользователем после отправки формы, и отправляет их в службу Google Диска.

Предварительные требования

Для использования этого примера необходимы следующие условия:

  • Для работы потребуется учетная запись Google (для учетных записей Google Workspace может потребоваться подтверждение администратора).
  • Веб-браузер с доступом в интернет.

Настройте скрипт

Создайте форму

  1. Перейдите на сайт forms.google.com и нажмите «Пустая .
  2. Щелкните по форме «Без названия» и переименуйте ее в «Загрузка файлов на Диск» .
  3. Щёлкните по вопросу без названия и переименуйте вопрос в «Подпапка» .
  4. В разделе «Подпапка» нажмите > «Описание» .
  5. В поле «Описание» введите «Выберите подпапку для хранения файлов». Если вы выберете <Нет>, файлы будут сохранены в папке «Загруженные файлы».
  6. Добавьте следующие параметры к вопросу о подпапке :
    • <нет>
    • Проект А
    • Проект Б
    • Проект С
  7. Чтобы сделать вопрос обязательным для ответа, нажмите «Обязательный» .
  8. Нажмите «Добавить вопрос» .
  9. Нажмите «Множественный выбор» и выберите «Загрузка файла» .
  10. Нажмите «Продолжить» .
  11. В поле «Вопрос» введите «Файлы для загрузки» . Вы можете выбрать типы файлов и максимальное количество файлов, которые вы разрешаете загружать.
  12. Чтобы сделать вопрос обязательным для ответа, нажмите «Обязательный» .

Создайте проект Apps Script.

  1. В форме нажмите > «Редактор скриптов» .
  2. Щёлкните по проекту «Без названия» и переименуйте его в «Загрузить файлы на Диск» .
  3. Чтобы создать еще один файл сценария, нажмите « файл» > «Сценарий» . Назовите файл Setup .
  4. Замените содержимое обоих файлов скриптов следующим содержимым:

    Code.gs

    solutions/automations/upload-files/Code.js
    // TODO Before you start using this sample, you must run the setUp()
    // function in the Setup.gs file.
    
    // Application constants
    const APP_TITLE = "Upload files to Drive from Forms";
    const APP_FOLDER_NAME = "Upload files to Drive (File responses)";
    
    // Identifies the subfolder form item
    const APP_SUBFOLDER_ITEM = "Subfolder";
    const APP_SUBFOLDER_NONE = "<None>";
    
    /**
     * Gets the file uploads from a form response and moves files to the corresponding subfolder.
     *
     * @param {object} event - Form submit.
     */
    function onFormSubmit(e) {
      try {
        // Gets the application root folder.
        let destFolder = getFolder_(APP_FOLDER_NAME);
    
        // Gets all form responses.
        const itemResponses = e.response.getItemResponses();
    
        // Determines the subfolder to route the file to, if any.
        let subFolderName;
        const dest = itemResponses.filter(
          (itemResponse) =>
            itemResponse.getItem().getTitle().toString() === APP_SUBFOLDER_ITEM,
        );
    
        // Gets the destination subfolder name, but ignores if APP_SUBFOLDER_NONE was selected;
        if (dest.length > 0) {
          if (dest[0].getResponse() !== APP_SUBFOLDER_NONE) {
            subFolderName = dest[0].getResponse();
          }
        }
        // Gets the subfolder or creates it if it doesn't exist.
        if (subFolderName !== undefined) {
          destFolder = getSubFolder_(destFolder, subFolderName);
        }
        console.log(`Destination folder to use:
        Name: ${destFolder.getName()}
        ID: ${destFolder.getId()}
        URL: ${destFolder.getUrl()}`);
    
        // Gets the file upload response as an array to allow for multiple files.
        const fileUploads = itemResponses
          .filter(
            (itemResponse) =>
              itemResponse.getItem().getType().toString() === "FILE_UPLOAD",
          )
          .map((itemResponse) => itemResponse.getResponse())
          .reduce((a, b) => a.concat(b), []);
    
        // Moves the files to the destination folder.
        if (fileUploads.length > 0) {
          for (const fileId of fileUploads) {
            DriveApp.getFileById(fileId).moveTo(destFolder);
            console.log(`File Copied: ${fileId}`);
          }
        }
      } catch (err) {
        console.log(err);
      }
    }
    
    /**
     * Returns a Drive folder under the passed in objParentFolder parent
     * folder. Checks if folder of same name exists before creating, returning
     * the existing folder or the newly created one if not found.
     *
     * @param {object} objParentFolder - Drive folder as an object.
     * @param {string} subFolderName - Name of subfolder to create/return.
     * @return {object} Drive folder
     */
    function getSubFolder_(objParentFolder, subFolderName) {
      // Iterates subfolders of parent folder to check if folder already exists.
      const subFolders = objParentFolder.getFolders();
      while (subFolders.hasNext()) {
        const folder = subFolders.next();
    
        // Returns the existing folder if found.
        if (folder.getName() === subFolderName) {
          return folder;
        }
      }
      // Creates a new folder if one doesn't already exist.
      return objParentFolder
        .createFolder(subFolderName)
        .setDescription(
          `Created by ${APP_TITLE} application to store uploaded Forms files.`,
        );
    }

    Setup.gs

    solutions/automations/upload-files/Setup.js
    // TODO You must run the setUp() function before you start using this sample.
    
    /**
     * The setUp() function performs the following:
     *  - Creates a Google Drive folder named by the APP_FOLDER_NAME
     *    variable in the Code.gs file.
     *  - Creates a trigger to handle onFormSubmit events.
     */
    function setUp() {
      // Ensures the root destination folder exists.
      const appFolder = getFolder_(APP_FOLDER_NAME);
      if (appFolder !== null) {
        console.log(`Application folder setup.
        Name: ${appFolder.getName()}
        ID: ${appFolder.getId()}
        URL: ${appFolder.getUrl()}`);
      } else {
        console.log("Could not setup application folder.");
      }
      // Calls the function that creates the Forms onSubmit trigger.
      installTrigger_();
    }
    
    /**
     * Returns a folder to store uploaded files in the same location
     * in Drive where the form is located. First, it checks if the folder
     * already exists, and creates it if it doesn't.
     *
     * @param {string} folderName - Name of the Drive folder.
     * @return {object} Google Drive Folder
     */
    function getFolder_(folderName) {
      // Gets the Drive folder where the form is located.
      const ssId = FormApp.getActiveForm().getId();
      const parentFolder = DriveApp.getFileById(ssId).getParents().next();
    
      // Iterates through the subfolders to check if folder already exists.
      // The script checks for the folder name specified in the APP_FOLDER_NAME variable.
      const subFolders = parentFolder.getFolders();
      while (subFolders.hasNext()) {
        const folder = subFolders.next();
    
        // Returns the existing folder if found.
        if (folder.getName() === folderName) {
          return folder;
        }
      }
      // Creates a new folder if one doesn't already exist.
      return parentFolder
        .createFolder(folderName)
        .setDescription(
          `Created by ${APP_TITLE} application to store uploaded files.`,
        );
    }
    
    /**
     * Installs trigger to capture onFormSubmit event when a form is submitted.
     * Ensures that the trigger is only installed once.
     * Called by setup().
     */
    function installTrigger_() {
      // Ensures existing trigger doesn't already exist.
      const propTriggerId =
        PropertiesService.getScriptProperties().getProperty("triggerUniqueId");
      if (propTriggerId !== null) {
        const triggers = ScriptApp.getProjectTriggers();
        for (const t in triggers) {
          if (triggers[t].getUniqueId() === propTriggerId) {
            console.log(
              `Trigger with the following unique ID already exists: ${propTriggerId}`,
            );
            return;
          }
        }
      }
      // Creates the trigger if one doesn't exist.
      const triggerUniqueId = ScriptApp.newTrigger("onFormSubmit")
        .forForm(FormApp.getActiveForm())
        .onFormSubmit()
        .create()
        .getUniqueId();
      PropertiesService.getScriptProperties().setProperty(
        "triggerUniqueId",
        triggerUniqueId,
      );
      console.log(
        `Trigger with the following unique ID was created: ${triggerUniqueId}`,
      );
    }
    
    /**
     * Removes all script properties and triggers for the project.
     * Use primarily to test setup routines.
     */
    function removeTriggersAndScriptProperties() {
      PropertiesService.getScriptProperties().deleteAllProperties();
      // Removes all triggers associated with project.
      const triggers = ScriptApp.getProjectTriggers();
      for (const t in triggers) {
        ScriptApp.deleteTrigger(triggers[t]);
      }
    }
    
    /**
     * Removes all form responses to reset the form.
     */
    function deleteAllResponses() {
      FormApp.getActiveForm().deleteAllResponses();
    }

Запустите скрипт

  1. В редакторе Apps Script перейдите к файлу Setup.gs .
  2. В раскрывающемся списке функций выберите setUp .
  3. Нажмите «Выполнить» .
  4. При появлении запроса авторизуйте скрипт. Если на экране согласия OAuth отобразится предупреждение « Это приложение не проверено» , продолжите, выбрав «Дополнительно» > «Перейти к {Название проекта} (небезопасно)» .

  5. Вернитесь к форме и нажмите «Предварительный просмотр». значок предварительного просмотра .

  6. В форме выберите подпапку и загрузите файл.

  7. Нажмите «Отправить» .

  8. Перейдите в Google Диск и откройте папку « Загрузка файлов в Google Диск (Ответы на файлы)» . Ваши загруженные файлы находятся в подпапке, которую вы выбрали в форме.

Авторы

Данный пример поддерживается компанией Google при содействии экспертов-разработчиков Google.

Следующие шаги