Tải tệp lên Google Drive bằng Google Biểu mẫu

Cấp độ lập trình: Người mới bắt đầu
Thời lượng: 10 phút
Loại dự án: Tự động hoá bằng trình kích hoạt do sự kiện điều khiển

Mục tiêu

  • Tìm hiểu chức năng của giải pháp.
  • Tìm hiểu chức năng của các dịch vụ Apps Script trong giải pháp.
  • Thiết lập tập lệnh.
  • Chạy tập lệnh.

Giới thiệu về giải pháp này

Đồng thời tải lên và sắp xếp các tệp trong Google Drive bằng Google Biểu mẫu. Biểu mẫu này bao gồm các mục nhập cho tệp cần tải lên và cách sắp xếp các tệp.

Ảnh chụp màn hình của biểu mẫu để tải tệp lên

Cách hoạt động

Hàm thiết lập sẽ tạo một thư mục để lưu trữ tất cả tệp đã tải lên và một trình kích hoạt sẽ kích hoạt mỗi khi có người gửi biểu mẫu. Khi người dùng điền vào biểu mẫu, họ sẽ chọn các tệp để tải lên và một thư mục con để lưu trữ các tệp đó. Sau khi người dùng gửi biểu mẫu, tập lệnh sẽ định tuyến các tệp đến thư mục con tương ứng. Nếu thư mục chưa tồn tại, tập lệnh sẽ tạo thư mục đó.

Dịch vụ Apps Script

Giải pháp này sử dụng các dịch vụ sau:

  • Dịch vụ tập lệnh – Tạo điều kiện kích hoạt sẽ kích hoạt mỗi khi có người gửi biểu mẫu.
  • Dịch vụ thuộc tính – Lưu trữ mã của trình kích hoạt mà tập lệnh tạo ra trong quá trình thiết lập để ngăn các trình kích hoạt trùng lặp.
  • Dịch vụ Drive – Trong quá trình thiết lập, tìm vị trí của biểu mẫu trong Drive và tạo một thư mục ở cùng vị trí. Khi người dùng gửi biểu mẫu, dịch vụ Drive sẽ định tuyến các tệp đến thư mục đó và nếu được chọn, một thư mục con được chỉ định. Nếu thư mục con chưa tồn tại, tập lệnh sẽ tạo thư mục con đó.
  • Dịch vụ biểu mẫu – Lấy tên tệp và thư mục mà người dùng đã chọn sau khi họ gửi biểu mẫu và gửi biểu mẫu đó đến dịch vụ Drive.

Điều kiện tiên quyết

Để sử dụng mẫu này, bạn cần có các điều kiện tiên quyết sau:

  • Tài khoản Google (có thể cần có sự phê duyệt của quản trị viên đối với tài khoản Google Workspace).
  • Một trình duyệt web có quyền truy cập Internet.

Thiết lập tập lệnh

Tạo biểu mẫu

  1. Truy cập vào forms.google.com rồi nhấp vào biểu tượng Biểu mẫu trống .
  2. Nhấp vào Mẫu không có tiêu đề rồi đổi tên mẫu thành Tải tệp lên Drive.
  3. Nhấp vào Câu hỏi chưa có tiêu đề rồi đổi tên câu hỏi thành Thư mục con.
  4. Trên câu hỏi Thư mục con, hãy nhấp vào biểu tượng Tuỳ chọn khác > Mô tả.
  5. Đối với Mô tả, hãy nhập Chọn thư mục con để lưu trữ tệp. Nếu bạn chọn <Không có>, các tệp sẽ được lưu trữ trong thư mục Tệp đã tải lên.
  6. Thêm các lựa chọn sau vào câu hỏi Thư mục con:
    • <none>
    • Dự án A
    • Dự án B
    • Dự án C
  7. Để đặt câu hỏi là bắt buộc, hãy nhấp vào Bắt buộc.
  8. Nhấp vào biểu tượng Thêm câu hỏi .
  9. Nhấp vào Trắc nghiệm rồi chọn Tải tệp lên.
  10. Nhấp vào Tiếp tục.
  11. Đối với mục Câu hỏi, hãy nhập Tệp cần tải lên. Bạn có thể chọn loại tệp và số lượng tệp tối đa mà bạn muốn cho phép mọi người tải lên.
  12. Để đặt câu hỏi là bắt buộc, hãy nhấp vào Bắt buộc.

Tạo dự án Apps Script

  1. Trong biểu mẫu, hãy nhấp vào biểu tượng Tuỳ chọn khác > Trình chỉnh sửa tập lệnh.
  2. Nhấp vào Untitled project (Dự án chưa có tên) rồi đổi tên dự án thành Upload files to Drive (Tải tệp lên Drive).
  3. Để tạo một tệp tập lệnh khác, hãy nhấp vào biểu tượng Thêm tệp > Tập lệnh. Đặt tên Setup cho tệp.
  4. Thay thế nội dung của cả hai tệp tập lệnh bằng nội dung sau:

    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.
        var destFolder = getFolder_(APP_FOLDER_NAME);
    
        // Gets all form responses.
        let itemResponses = e.response.getItemResponses();
    
        // Determines the subfolder to route the file to, if any.
        var subFolderName;
        let 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.
        let fileUploads = itemResponses.filter((itemResponse) => itemResponse.getItem().getType().toString() === "FILE_UPLOAD")
          .map((itemResponse) => itemResponse.getResponse())
          .reduce((a, b) => [...a, ...b], []);
    
        // Moves the files to the destination folder.
        if (fileUploads.length > 0) {
          fileUploads.forEach((fileId) => {
            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()) {
        let 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()) {
        let 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.
      let propTriggerId = PropertiesService.getScriptProperties().getProperty('triggerUniqueId')
      if (propTriggerId !== null) {
        const triggers = ScriptApp.getProjectTriggers();
        for (let 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.
      let 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 (let t in triggers) {
        ScriptApp.deleteTrigger(triggers[t]);
      }
    }
    
    /**
     * Removes all form responses to reset the form.
     */
    function deleteAllResponses() {
      FormApp.getActiveForm().deleteAllResponses();
    }

Chạy tập lệnh

  1. Trong trình chỉnh sửa Apps Script, hãy chuyển sang tệp Setup.gs.
  2. Trong trình đơn thả xuống hàm, hãy chọn setUp.
  3. Nhấp vào Chạy.
  4. Khi được nhắc, hãy cho phép tập lệnh chạy. Nếu màn hình đồng ý OAuth hiển thị cảnh báo Ứng dụng này chưa được xác minh, hãy tiếp tục bằng cách chọn Nâng cao > Chuyển đến {Project Name} (không an toàn).

  5. Quay lại biểu mẫu rồi nhấp vào biểu tượng Xem trước Biểu tượng xem trước.

  6. Trên biểu mẫu, hãy chọn một thư mục con rồi tải tệp lên.

  7. Nhấp vào Gửi.

  8. Chuyển đến Drive rồi mở thư mục Tải tệp lên Drive (Câu trả lời bằng tệp). Các tệp bạn đã tải lên nằm trong thư mục con mà bạn đã chọn trên biểu mẫu.

Người đóng góp

Mẫu này do Google duy trì với sự trợ giúp của Chuyên gia phát triển của Google.

Các bước tiếp theo