共享表单绑定脚本,让它以使用表单的用户身份运行

时间:2015-11-24 21:59:15

标签: google-apps-script google-sheets google-form

我创建了一个表单绑定脚本,该脚本获取表单内容,生成PDF和HTML电子邮件,最终通过电子邮件发送所有内容。

这将由同事使用。目前,在我分享脚本后,发送的电子邮件都在Google帐户下,因为我是该脚本的所有者。

如何强制脚本以使用表单的用户身份运行?

注意:由于我与多个用户共享了工作表,因此我计划让他们打开编辑工作表,然后点击"查看实时表单"并从那里填写。

我以前没有处理过共享脚本。我有一种感觉,我需要使脚本成为独立脚本,将其作为库共享并共享表单。然后员工可以将库添加到共享表单并在他们自己的帐户下运行而不是我的?希望有一个比这更容易的过程。

1 个答案:

答案 0 :(得分:3)

  

目前,在我分享脚本之后,发送的电子邮件都在(我的)Google帐户下,因为我是该脚本的所有者。

由于描述的行为here可安装的[trigger]版本在创建触发器的用户的授权下运行,即使具有编辑权限的其他用户打开电子表格也是如此

正如您所确定的,解决方案是让每个用户自己安装一个触发器。但是,不是强迫他们触摸Google Apps脚本编辑器,您有三种选择来提供用户界面,让他们可以在共享的电子表格中管理自己的触发器

表单提交触发器

这是一个简单的触发器功能,它会发送一封电子邮件,其中包含对编程触发器的用户的响应,并且仅针对他们自己的响应。

function mailMeMyResponse(e) {
  // This only works in forms collecting user names.
  if (!e.namedValues.hasOwnProperty("Username")) {
    //throw new Error( "Form not collecting user names." );
    return;
  }

  var me = Session.getActiveUser().getEmail();

  // If the current form response is mine, email it to me
  if (me == e.namedValues["Username"]) {
    var body = "Your responses were:\n\n";
    for (var resp in e.namedValues) {
      body += resp + ": " + e.namedValues[resp] + "\n";
    }
    MailApp.sendEmail(me, "Your form responses", body);
  }
}

UI选项1:自定义菜单

这组功能为电子表格提供了一个标有" MailMe"的自定义菜单。菜单中包含一个项目,该项目根据用户通知触发器的当前状态而变化。

具有编辑权限的用户首次打开电子表格时,菜单选项将为"启用响应通知"。通过选择它们,它们将触发脚本的授权,并设置其触发功能以开始监视电子表格中的响应。 (这就是它的全部内容!)之后,他们总是可以通过同一菜单禁用通知。

触发器的ID保存在用户的属性中,用于随后管理菜单和触发状态。

function onOpen(e) {
  // Set up custom menu      
  updateMenu(e);
}

function updateMenu() {
  var menu = SpreadsheetApp.getUi().createMenu("MailMe");

  var props = PropertiesService.getUserProperties();

  // Check whether a trigger function is defined for this user
  var triggerId = props.getProperty("triggerId");
  if (triggerId) {
    menu.addItem('Disable response notification', 'deleteFormTrigger');
  } else {
    menu.addItem('Enable response notification', 'createFormTrigger');
  }
  menu.addToUi();
}

function createFormTrigger() {
  var props = PropertiesService.getUserProperties();

  // Check whether a trigger function is defined for this user
  var triggerId = props.getProperty("triggerId");
  if (triggerId == null) {  
    // Set up form submission trigger for this user
    var ss = SpreadsheetApp.getActive();
    var triggerId = ScriptApp.newTrigger("mailMeMyResponse")
                             .forSpreadsheet(ss)
                             .onFormSubmit()
                             .create()
                             .getUniqueId();
    // Remember triggerId
    props.setProperty("triggerId", triggerId);
  }

  // Update menu
  updateMenu();
}

function deleteFormTrigger() {
  var props = PropertiesService.getUserProperties();

  // Check whether a trigger function is defined for this user
  var triggerId = props.getProperty("triggerId");
  if (triggerId !== null) {
    if (deleteTriggerById( triggerId )) {
      // Trigger was deleted, delete property
      props.deleteProperty("triggerId");

      // Update menu
      updateMenu();
    }
  }
}

function deleteTriggerById(triggerId) {      
  if (triggerId !== null) {
    // Search all triggers
    var triggers = ScriptApp.getProjectTriggers();
    for (var i=0; i<triggers.length; i++) {
      if (triggers[i].getUniqueId() == triggerId) {
        // Found our trigger, delete it.
        ScriptApp.deleteTrigger(triggers[i]);
        return true;
      }
    }
    return false; // Didn't find trigger
  }
  return true;  // Nothing to do
}

UI选项2:加载项

方法优于自定义菜单脚本的优势在于它不依赖于任何特定的电子表格文件。它可以在您域中的任何电子表格中使用,而无需复制脚本。

加载项的代码比自定义菜单更复杂,因为它需要处理来自商店的安装和授权流程。但是,代码的结构大致相同,只需稍作调整即可满足更广泛的要求。 (例如,查找用于驱动菜单刷新的事件对象。)

处理创作的功能&amp;删除触发功能与选项1相同。

function onInstall(e) {
  onOpen(e);
}

function onOpen(e) {  
  if (e && e.authMode == ScriptApp.AuthMode.NONE) {
    // Add a normal menu item (works in all authorization modes).
    updateMenu(e);
  } else {
    // Privileged setup, based on properties (doesn't work in AuthMode.NONE).
    createFormTrigger();
  }
}

function updateMenu(e) {
  var menu = SpreadsheetApp.getUi().createAddonMenu();
  if (e && e.authMode == ScriptApp.AuthMode.NONE) {
    // Add a normal menu item (works in all authorization modes).
    menu.addItem('Authorize & enable response notification', 'createFormTrigger');
  } else {
    // Add a menu item based on properties (doesn't work in AuthMode.NONE).
    var props = PropertiesService.getUserProperties();

    // Check whether a trigger function is defined for this user
    var triggerId = props.getProperty("triggerId");
    if (triggerId) {
      menu.addItem('Disable response notification', 'deleteFormTrigger');
    } else {
      menu.addItem('Enable response notification', 'createFormTrigger');
    }
  }
  menu.addToUi();
}

function deleteFormTrigger() {
  var props = PropertiesService.getUserProperties();

  // Check whether a trigger function is defined for this user
  var triggerId = props.getProperty("triggerId");
  if (triggerId !== null) {
    if (deleteTriggerById( triggerId )) {
      // Trigger was deleted, delete property
      props.deleteProperty("triggerId");

      // Update menu, using fake event
      updateMenu({authMode:ScriptApp.AuthMode.FULL});
    }
  }
}

function deleteTriggerById(triggerId) {      
  if (triggerId !== null) {
    // Search all triggers
    var triggers = ScriptApp.getProjectTriggers();
    for (var i=0; i<triggers.length; i++) {
      if (triggers[i].getUniqueId() == triggerId) {
        // Found our trigger, delete it.
        ScriptApp.deleteTrigger(triggers[i]);
        return true;
      }
    }
    return false; // Didn't find trigger
  }
  return true;  // Nothing to do
}

function createFormTrigger() {
  var props = PropertiesService.getUserProperties();

  // Check whether a trigger function is defined for this user
  var triggerId = props.getProperty("triggerId");
  if (triggerId == null) {  
    // Set up form submission trigger for this user
    var ss = SpreadsheetApp.getActive();
    var triggerId = ScriptApp.newTrigger("mailMeMyResponse")
                             .forSpreadsheet(ss)
                             .onFormSubmit()
                             .create()
                             .getUniqueId();
    // Remember triggerId
    props.setProperty("triggerId", triggerId);
  }

  // Update menu, using fake event
  updateMenu({authMode:ScriptApp.AuthMode.FULL});
}

UI选项3:启用通知的Webapp

另一种可能使用户无需打开电子表格的方法就是将早期的createFormTrigger()功能调整为独立的脚本Web应用程序,共享并设置为以单个用户身份运行,可能有自己的简单UI来打开和关闭通知。