共享表单绑定脚本,作为使用表单的用户运行
Share form bound script, have it run as the user using the form
我创建了一个表单绑定脚本,它获取表单内容,生成 PDF 和 HTML 电子邮件,并最终将所有内容发送到电子邮件中。
这将由同事使用。目前在我分享脚本后,发送的电子邮件在 Google 帐户下,因为我是脚本的所有者。
如何以使用表单的用户身份强制执行脚本 运行?
注意:由于我与多个用户共享 sheet,我计划让他们打开编辑 sheet,然后单击 "view live form" 并从那里填写。
我以前没有处理过共享脚本。我有一种感觉,我需要使脚本成为一个独立的脚本,将其作为库共享并共享表单。然后员工可以将图书馆添加到共享表单中,并 运行 它在他们自己的帐户而不是我的帐户下?希望有比这更简单的过程。
Currently after I shared the scripts, the emails sent are under (my) google account, since I am the owner of the script.
这是由于描述的行为 here,可安装 [trigger] 版本 运行s 具有创建触发器的用户的授权,即使另一个用户具有编辑权限打开电子表格。
正如您所确定的那样,解决方案是让每个用户自己安装一个触发器。但是,您不必强迫他们接触 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"。菜单中只有一个项目,它会根据用户通知触发器的当前状态而变化。
具有编辑权限的用户第一次打开电子表格时,菜单选项将为 "Enable response notification"。通过选择它,他们将触发脚本的授权,并设置他们的触发功能以开始监控电子表格中的响应。 (仅此而已!)之后,他们始终可以通过同一菜单禁用通知。
触发器的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:附加组件
与自定义菜单脚本相比,此方法的优势在于它不依赖于任何特定的电子表格文件。它可以用于您域中的任何电子表格,而无需复制脚本。
插件的代码比自定义菜单的代码更复杂,因为它需要处理从商店安装和授权流程。但是,代码的结构在很大程度上是相同的,只是为了适应更广泛的需求而进行了细微的调整。 (例如,查找用于驱动菜单刷新的事件对象。)
创建和删除触发函数的函数与选项 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 来打开和关闭通知。
我创建了一个表单绑定脚本,它获取表单内容,生成 PDF 和 HTML 电子邮件,并最终将所有内容发送到电子邮件中。
这将由同事使用。目前在我分享脚本后,发送的电子邮件在 Google 帐户下,因为我是脚本的所有者。
如何以使用表单的用户身份强制执行脚本 运行?
注意:由于我与多个用户共享 sheet,我计划让他们打开编辑 sheet,然后单击 "view live form" 并从那里填写。
我以前没有处理过共享脚本。我有一种感觉,我需要使脚本成为一个独立的脚本,将其作为库共享并共享表单。然后员工可以将图书馆添加到共享表单中,并 运行 它在他们自己的帐户而不是我的帐户下?希望有比这更简单的过程。
Currently after I shared the scripts, the emails sent are under (my) google account, since I am the owner of the script.
这是由于描述的行为 here,可安装 [trigger] 版本 运行s 具有创建触发器的用户的授权,即使另一个用户具有编辑权限打开电子表格。
正如您所确定的那样,解决方案是让每个用户自己安装一个触发器。但是,您不必强迫他们接触 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"。菜单中只有一个项目,它会根据用户通知触发器的当前状态而变化。
具有编辑权限的用户第一次打开电子表格时,菜单选项将为 "Enable response notification"。通过选择它,他们将触发脚本的授权,并设置他们的触发功能以开始监控电子表格中的响应。 (仅此而已!)之后,他们始终可以通过同一菜单禁用通知。
触发器的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:附加组件
与自定义菜单脚本相比,此方法的优势在于它不依赖于任何特定的电子表格文件。它可以用于您域中的任何电子表格,而无需复制脚本。
插件的代码比自定义菜单的代码更复杂,因为它需要处理从商店安装和授权流程。但是,代码的结构在很大程度上是相同的,只是为了适应更广泛的需求而进行了细微的调整。 (例如,查找用于驱动菜单刷新的事件对象。)
创建和删除触发函数的函数与选项 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 来打开和关闭通知。