【问题标题】:Simplifying a Protection script简化保护脚本
【发布时间】:2021-12-10 05:28:26
【问题描述】:

我仍在学习 Javascript 的基础知识,但我知道有一种方法可以简化这一点,但我就是想不通。我修改了在这里找到的脚本:Protect spreadsheet then unprotect specific cells and ranges with script

我正在与多个用户共享一张工作表,并且希望每张工作表的大部分内容都受到保护。上面的链接脚本帮助我确保我的用户需要访问的范围可以被所有人编辑,即使工作表扩展也是如此。但是,每张纸上的可编辑范围都不同,所以我最终回收了unlockCertainRanges() 部分以将其单独应用于每张纸。这使得脚本最多需要 70 秒才能运行。我很确定我可以使用一个数组和一个 for 循环来遍历每张纸,但我无法弄清楚。

这是我目前所拥有的:

    function mainProtection(){ //Main function to run
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  var disregard = ["NetSuite INV", "Sales", "Delivery Schedule", "TO", "APP Arch", "ACC Arch", "INV REF"]; //ADD SHEET NAMES HERE THAT YOU WANT TO BE DISREGARDED

  for(var x=0; x<sheets.length; x++){
    if(disregard.some(data => sheets[x].getName().includes(data))){ 
      //E.g. Disregard any sheet names added on the "disregard" array
    }else{
      unlockOrderingRanges(sheets[x]);
      unlockPendingTORanges(sheets[x]);
      unlockAccessoryRanges(sheets[x]);
      unlockApparelRanges(sheets[x]);
    }
  }
}


function unlockOrderingRanges(){ //Function to unlock ranges on Ordering spreadshseet
  var sheet = SpreadsheetApp.getActive().getSheetByName("Ordering");
  // Remove all range protections in the spreadsheet
  var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
  for (var i = 0; i < protections.length; i++) {
    var protection = protections[i];
    protection.remove();
  }

  var protection = sheet.protect();
  //restrict editors to owner
  protection.getRange().getA1Notation();
  var eds = protection.getEditors();
  protection.removeEditors(eds);

  //set unprotected ranges
  var ranges = protection.getUnprotectedRanges();
  var data = ["O5:P", "C2:E2"]; // ADD YOUR RANGES HERE
  data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
    ranges.push(sheet.getRange(res));
    protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
  });
}

为了简化这篇文章,我省略了 unlockPendingTORanges();unlockAccessoryRanges();unlockApparelRanges(); 脚本,因为它们与 unlockOrderingRanges() 脚​​本相同,它们只是更改了定义的工作表名称和范围。

非常感谢任何指导!

unlockPendingTORanges();unlockAccessoryRanges();unlockApparelRanges(); 的 ETA 详细信息

function unlockPendingTORanges(){ //Function to unlock ranges on Pending TOs spreadshseet
  var sheet = SpreadsheetApp.getActive().getSheetByName("Pending TOs");
  // Remove all range protections in the spreadsheet
  var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
  for (var i = 0; i < protections.length; i++) {
    var protection = protections[i];
    protection.remove();
  }

  var protection = sheet.protect();
  //restrict editors to owner
  protection.getRange().getA1Notation();
  var eds = protection.getEditors();
  protection.removeEditors(eds);

  //set unprotected ranges
  var ranges = protection.getUnprotectedRanges();
  var data = ["E6:H"]; // ADD YOUR RANGES HERE
  data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
    ranges.push(sheet.getRange(res));
    protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
  });
}


    function unlockAccessoryRanges(){ //Function to unlock ranges on Accessory INV spreadshseet
      var sheet = SpreadsheetApp.getActive().getSheetByName("Accessory INV");
      // Remove all range protections in the spreadsheet
      var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
      for (var i = 0; i < protections.length; i++) {
        var protection = protections[i];
        protection.remove();
      }
    
      var protection = sheet.protect();
      //restrict editors to owner
      protection.getRange().getA1Notation();
      var eds = protection.getEditors();
      protection.removeEditors(eds);
    
      //set unprotected ranges
      var ranges = protection.getUnprotectedRanges();
      var data = ["E5:H"]; // ADD YOUR RANGES HERE
      data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
        ranges.push(sheet.getRange(res));
        protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
      });
    }
    
    
    function unlockApparelRanges(){ //Function to unlock ranges on Apparel INV spreadshseet
      var sheet = SpreadsheetApp.getActive().getSheetByName("Apparel INV");
      // Remove all range protections in the spreadsheet
      var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
      for (var i = 0; i < protections.length; i++) {
        var protection = protections[i];
        protection.remove();
      }
    
      var protection = sheet.protect();
      //restrict editors to owner
      protection.getRange().getA1Notation();
      var eds = protection.getEditors();
      protection.removeEditors(eds);
    
      //set unprotected ranges
      var ranges = protection.getUnprotectedRanges();
      var data = ["E5:F"]; // ADD YOUR RANGES HERE
      data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
        ranges.push(sheet.getRange(res));
        protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
      });
    }

【问题讨论】:

  • 可以问一下they just change the defined sheet name and ranges.的详细信息吗?
  • @Tanaike,我编辑了原始帖子以澄清这些。抱歉,如果不清楚,我试图缩短帖子。谢谢!

标签: javascript google-apps-script google-sheets google-sheets-api


【解决方案1】:

我相信你的目标如下。

  • 您希望降低脚本的处理成本。

在这种情况下,我想建议使用 Sheets API。我认为当您的脚本使用 Sheets API 时,流程成本会降低一点。当 Sheets API 反映在您的脚本中时,它变为如下。

修改脚本:

在使用此脚本之前,please enable Sheets API at Advanced Google Services

// This script is from https://tanaikech.github.io/2017/07/31/converting-a1notation-to-gridrange-for-google-sheets-api/
function a1notation2gridrange1(a1notation) {
  var data = a1notation.match(/(^.+)!(.+):(.+$)/);
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(data[1]);
  var range = ss.getRange(data[2] + ":" + data[3]);
  var gridRange = {
    sheetId: ss.getSheetId(),
    startRowIndex: range.getRow() - 1,
    endRowIndex: range.getRow() - 1 + range.getNumRows(),
    startColumnIndex: range.getColumn() - 1,
    endColumnIndex: range.getColumn() - 1 + range.getNumColumns(),
  };
  if (!data[2].match(/[0-9]/)) delete gridRange.startRowIndex;
  if (!data[3].match(/[0-9]/)) delete gridRange.endRowIndex;
  return gridRange;
}

// Please run this function.
function myFunction() {
  // Please set your sheet names and unprotected ranges you want to use.
  const obj = [ 
  { sheetName: "Ordering", unprotectedRanges: ["O5:P", "C2:E2"] },  
  { sheetName: "Accessory INV", unprotectedRanges: ["E5:H"] },  
  { sheetName: "Apparel INV", unprotectedRanges: ["E5:F"] },  
  {sheetName: "Pending TOs", unprotectedRanges: ["E6:H"] }, 
  {sheetName: "INV REF", unprotectedRanges: ["C6:C"] },
];

  // 1. Retrieve sheet IDs and protected range IDs.
  const spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
  const sheets = Sheets.Spreadsheets.get(spreadsheetId, { ranges: obj.map(({ sheetName }) => sheetName), fields: "sheets(protectedRanges(protectedRangeId),properties(sheetId))" }).sheets;
  const { protectedRangeIds, sheetIds } = sheets.reduce((o, { protectedRanges, properties: { sheetId } }) => {
    if (protectedRanges && protectedRanges.length > 0) o.protectedRangeIds.push(protectedRanges.map(({ protectedRangeId }) => protectedRangeId));
    o.sheetIds.push(sheetId);
    return o;
  }, { protectedRangeIds: [], sheetIds: [] });
  
  // 2. Convert A1Notation to Gridrange.
  const gridranges = obj.map(({ sheetName, unprotectedRanges }, i) => unprotectedRanges.map(f => a1notation2gridrange1(`${sheetName}!${f}`)));

  // 3. Create request body.
  const deleteProptectedRanges = protectedRangeIds.flatMap(e => e.map(id => ({ deleteProtectedRange: { protectedRangeId: id } })));
  const protects = sheetIds.map((sheetId, i) => ({ addProtectedRange: { protectedRange: { range: { sheetId }, unprotectedRanges: gridranges[i] } } }));
  
  // 4. Request to Sheets API with the created request body.
  Sheets.Spreadsheets.batchUpdate({ requests: [...deleteProptectedRanges, ...protects] }, spreadsheetId);
}

注意:

  • 不幸的是,来自您的问题的I omitted the unlockPendingTORanges(); , unlockAccessoryRanges(); and unlockApparelRanges(); scripts for the sake of simplifying this post, as they are identical to the unlockOrderingRanges() script, they just change the defined sheet name and ranges.,我无法理解其他工作表名称和不受保护的范围。所以在这个修改后的脚本中,使用了一种模式。请将您的其他模式添加到obj 的变量中。

参考资料:

【讨论】:

  • '如果我理解:const obj = [ { sheetName: "Ordering", unprotectedRanges: ["O5:P", "C2:E2"] }, { sheetName: "Accessory INV", unprotectedRanges: ["E5:H"] }, { sheetName: "Apparel INV", unprotectedRanges: ["E5:F"] }, {sheetName: "Pending TOs", unprotectedRanges: ["E6:H"] }, ];
  • @Tyler 感谢您的回复。当您使用修改后的obj 时,您会得到什么结果?如果我提出的脚本没有用,我必须为此道歉。
  • 我很确定我正确启用了 Sheets API,但我以前从未这样做过,所以也许就是这样?我得到以下信息: TypeError: Cannot read property 'map' of undefined sheet.reduce.protectedRangeIds @ APIProtectionsTest.gs:34 myFunction @ APIProtectionsTest.gs:33
  • @Tyler 感谢您的回复。我必须为我糟糕的技能道歉。不幸的是,我无法复制您的情况。当我测试我提出的脚本时,没有发生错误。我深表歉意,没有发生错误。那么,您能否提供包含当前脚本的示例电子表格以正确复制您的问题?借此,我想确认一下。
  • 您好田池,再次感谢您的帮助!你单枪匹马地让我的工作表更加用户友好,并且能够在没有我监督的情况下在其他地方实施。它创造了奇迹。我真的很感激。
猜你喜欢
  • 2016-09-28
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
相关资源
最近更新 更多