Google Contacts(People API)查询在从触发脚本调用的脚本中不起作用。

huangapple go评论90阅读模式
英文:

Google Contacts (People API) query not working in script called from trigger script

问题

UPDATE

我已经确定这是一个身份验证问题。由于某种原因,当我从编辑器运行该函数时,我可以执行People API查询,但是从触发器运行时,我从执行日志中收到以下消息:

> GoogleJsonResponseException: 调用people.people.searchContacts的API调用失败,错误为:请求缺少必需的身份验证凭据。预期的OAuth 2访问令牌、登录Cookie或其他有效的身份验证凭据。请参见https://developers.google.com/identity/sign-in/web/devconsole-project。
> at searchContactsMain(searchContactsMain:6:29)
> at onEdit(onEdit:21:7)

有人能指导我正确的方向吗?


ORIGINAL POST

首先,我有一个脚本,它获取工作表A1单元格中的文本并使用它查询我的Google联系人。它将所有结果列在B列中。这个脚本是有效的。

function searchContactsTest() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet()
                            .getSheetByName("MAIN");
  var query = sheet.getRange('A1').getValue();

  let found = People.People.searchContacts({
    "query": query,
    "readMask": "names,addresses"
  });

  if (found.results) {
    var contactNames = [];

    for (i = 0; i < found.results.length; i++) {
      let thisResult = found.results[i];
      contactNames[i] = [];
      contactNames[i].push(thisResult.person.names[0].displayName);
      Logger.log(`Result ${i}: ${thisResult.person.names[0].displayName}`);
      if(thisResult.person.addresses){
        Logger.log(`Result ${i}: ${thisResult.person.addresses[0].streetAddress}`);
      }
    }
  } else {
    Logger.log(`No results for ${query}`);
  }

  if (found.results.length > 0) {
    // Write results to column B starting from row 2
    sheet.getRange("B2:B").clearContent(); // Clear previous results
    var outputRange = sheet.getRange(2, 2, contactNames.length, contactNames[0].length);
    outputRange.setValues(contactNames);
  }
}

接下来,我想在另一个上下文中使用People.searchContacts查询:当用户点击包含姓名的单元格时。我使用onSelectionChange触发器进行此操作。作为触发器的测试,我将点击的单元格背景颜色设为红色,然后调用我的函数displayContact(range)。

function onSelectionChange(e) {
  const range = e.range;
  sheetID = range.getSheet().getSheetId().toString();

  if (sheetID == "1060200918") //Main front end sheet
  {
    if (range.getNumRows() === 1 &&
      range.getNumColumns() === 1 &&
      range.getCell(1, 1).getValue() != '') 
      {
        range.setBackground('red');
        displayContact(e);
      }
  }
}

这也有效。接下来,在displayContact中,我执行People.searchContacts,使用触发事件的单元格值。脚本应该将返回的联系人地址写入A2。

function displayContact(e) {
  range = e.range;             //**** Getting range from event object ****

  sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("MAIN");
  testOut = sheet.getRange("A2");

  //range = sheet.getRange("B2"); //**** Hardcoding the range ****
  var query = range.getValue();

  //Test to see if we're accessing the cell that was clicked on.
  testOut.setValue(query);   

  let found = People.People.searchContacts({
    "query": query,
    "readMask": "names,addresses"
    //"readMask": "names,addresses,emailAddresses,phoneNumbers"
  });
  
  range.setBackground('blue');

  if (found.results) 
  {
    let thisResult = found.results[0];
    let contactAddress = thisResult.person.addresses[0].streetAddress;
  
    //sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("MAIN");
    outRange = sheet.getRange("A3");
    outRange.clearContent(); // Clear previous results
    outRange.setValue(contactAddress);
  }
  
  else 
  {
    Logger.log(`No results for ${query}`);
  }
}

第11行将我点击的单元格的值(我使用B2)写入A2单元格,以测试事件对象是否被正确传递。这个操作有效。然而,第19行,将单元格背景颜色设为蓝色的测试(Logger对触发的事件不生成任何输出)从不执行。查询从不发生,人的地址从不写入A3。

然而,如果我注释掉第2行,取消注释第7行,并从编辑器中运行它而不是让触发处理程序运行它,一切都完美运行。第7行硬编码范围与我点击的精确相同的单元格。相同的值写入A2。一切都完全相同,唯一的区别是我手动设置范围而不是从事件对象获取,并从编辑器运行脚本

我做错了什么?

英文:

UPDATE

I've determined that this is an authentication problem. For some reason I can perform People API queries when I'm running the function from the editor, but from the trigger I get this message from the executions log:

> GoogleJsonResponseException: API call to people.people.searchContacts
> failed with error: Request is missing required authentication
> credential. Expected OAuth 2 access token, login cookie or other valid
> authentication credential. See
> https://developers.google.com/identity/sign-in/web/devconsole-project.
> at searchContactsMain(searchContactsMain:6:29)
> at onEdit(onEdit:21:7)

Anyone can point me to the right direction?


ORIGINAL POST

First, I have a script that takes the text in cell A1 of a sheet and queries my Google Contacts using it. It lists all the results to column B. This script works.

function searchContactsTest() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet()
                            .getSheetByName(&quot;MAIN&quot;);
  var query = sheet.getRange(&#39;A1&#39;).getValue();

  let found = People.People.searchContacts({
    &quot;query&quot;: query,
    &quot;readMask&quot;: &quot;names,addresses&quot;
  });

  if (found.results) {
    var contactNames = [];

    for (i = 0; i &lt; found.results.length; i++) {
      let thisResult = found.results[i];
      contactNames[i] = [];
      contactNames[i].push(thisResult.person.names[0].displayName);
      Logger.log(`Result ${i}: ${thisResult.person.names[0].displayName}`);
      if(thisResult.person.addresses){
        Logger.log(`Result ${i}: ${thisResult.person.addresses[0].streetAddress}`);
      }
    }
  } else {
    Logger.log(`No results for ${query}`);
  }

  if (found.results.length &gt; 0) {
    // Write results to column B starting from row 2
    sheet.getRange(&quot;B2:B&quot;).clearContent(); // Clear previous results
    var outputRange = sheet.getRange(2, 2, contactNames.length, contactNames[0].length);
    outputRange.setValues(contactNames);
  }
}

Now then, I want to use the People.searchContacts query in another context: when the user clicks on a cell containing a name. I'm using the onSelectionChange trigger for this. I'm turning the clicked cell background red as a test of the trigger, then I call my function displayContact(range).

function onSelectionChange(e) {
  const range = e.range;
  sheetID = range.getSheet().getSheetId().toString();

  if (sheetID == &quot;1060200918&quot;) //Main front end sheet
  {
    if (range.getNumRows() === 1 &amp;&amp;
      range.getNumColumns() === 1 &amp;&amp;
      range.getCell(1, 1).getValue() != &#39;&#39;) 
      {
        range.setBackground(&#39;red&#39;);
        displayContact(e);
      }
  }
}

This works too.
Next, in displayContact, I do a People.searchContacts, using the value of the cell that triggered the event. The script should write the address of the contact returned to A2.

function displayContact(e) {
  range = e.range;             //**** Getting range from event object ****

  sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&quot;MAIN&quot;);
  testOut = sheet.getRange(&quot;A2&quot;);

  //range = sheet.getRange(&quot;B2&quot;); //**** Hardcoding the range ****
  var query = range.getValue();

  //Test to see if we&#39;re accessing the cell that was clicked on.
  testOut.setValue(query);   

  let found = People.People.searchContacts({
    &quot;query&quot;: query,
    &quot;readMask&quot;: &quot;names,addresses&quot;
    //&quot;readMask&quot;: &quot;names,addresses,emailAddresses,phoneNumbers&quot;
  });
  
  range.setBackground(&#39;blue&#39;);

  if (found.results) 
  {
    let thisResult = found.results[0];
    let contactAddress = thisResult.person.addresses[0].streetAddress;
  
    //sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&quot;MAIN&quot;);
    outRange = sheet.getRange(&quot;A3&quot;);
    outRange.clearContent(); // Clear previous results
    outRange.setValue(contactAddress);
  }
  
  else 
  {
    Logger.log(`No results for ${query}`);
  }
}

Line 11 writes the value of the cell I'm clicking on (I'm using B2) to cell A2, to test whether the event object is being passed correctly. That works. However, line 19 which turns the cell background blue as a test (Logger produces no output for triggered events) never executes. The query never happens, and the person's address never gets written to A3.

HOWEVER, if I comment out line 2, uncomment line 7, and run it from the editor instead of letting the trigger handler run it, everything works perfectly. Line 7 hardcodes the range to the exact same cell I'm clicking on. The same value gets written to A2. Everything is exactly the same except that I'm setting the range manually rather than getting it from the event object, and running the script from the editor.

What am I doing wrong?

答案1

得分: 2

错误消息与简单触发器相关。在Google文档中这里,它在简单触发器的限制下说明了以下内容:

他们无法访问需要授权的服务。例如,简单触发器无法发送电子邮件,因为Gmail服务需要授权,但简单触发器可以使用匿名的Language服务来翻译短语。

这就是为什么在编辑器下工作,但无法在触发器中进行身份验证的原因。

我建议在这种情况下可能使用可安装触发器,而不是简单触发器。可以通过手动添加触发器(链接)或通过编程方式添加触发器(链接)来实现。但是,请考虑onSelectionChange(e)不可用的情况。

也许您可以使用onEdit触发器,并限制更改范围。例如,在单元格A1中添加一个下拉列表,其中包含所有联系人的名称。一旦用户更改值,它将在B列中粘贴结果,并返回A2中的地址或代码需要执行的任何内容。

添加一个if语句,只有在更改仅在A1中完成的条件下才会执行这些更改。您可以使用getA1Notation()方法(链接)进行条件判断。

英文:

The error message is related to the simple trigger. In the Google Documentation here, it states the following under the restriction of Simple triggers:

> They cannot access services that require authorization. For example, a
> simple trigger cannot send an email because the Gmail service requires
> authorization, but a simple trigger can translate a phrase with the
> Language service, which is anonymous.

That is why, is working under the editor, but is unable to authenticate using the trigger.

I will recommend to maybe use an installable trigger for this situation, instead of a simple trigger. Either by adding the trigger manually or adding it programmatically. However, take in consideration that the onSelectionChange(e) is not available.

Maybe you can use an onEdit trigger, and limit the change to a specific range. For example, adding a drop-down in cell A1 with all the names of the contacts. Once the user change the value, it will paste the results in column B, and return the Address in A2 or whatever the codes need to do.

Add an If statement that it will only do those changes under the condition that the change is only done in A1. You can use the method getA1Notation() for the if statement.

答案2

得分: -3

用这段代码我与特定人员分享了Google表格通讯录添加了一个名为"schools"的群组并将它们添加到该群组并分享

Google允许最多进行200次查询所以我获取了整个通讯录和表格并遇到了 `if(!veri3.includes(veri2[i]))`

检查通讯录中是否有名为"schools"的群组如果没有则添加一个名为"schools"的群组

英文:

With this code, I share the Google Spreadsheet Phonebook with certain people, add a group called schools to the directory and add them to that group and share them.
Google allows to make a maximum of 200 queries, so I get the whole phonebook and table in Array list and encounter if(!veri3.includes(veri2[i]))

check if there is a group named schools in the phone book, if not, add a group named schools
Google Contacts(People API)查询在从触发脚本调用的脚本中不起作用。

 var groupName = &quot;Okullar&quot;;
  var groups = People.ContactGroups.list()[&quot;contactGroups&quot;];
  var group = groups.find(group =&gt; group[&quot;name&quot;] === groupName);
  // 3. CREATE GROUP IF DOESN&#39;T EXIST:
  if (!group) {
    var groupResource = {
      contactGroup: {
        name: groupName
      }
    }
    group = People.ContactGroups.create(groupResource);
  }
  var groupResourceName = group[&quot;resourceName&quot;];

get data of sheet named list from table

 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&quot;Liste&quot;);
var dataRange = sheet.getRange(2, 1, sheet.getLastRow()-1, 7)
var data = dataRange.getValues();

Getting the sheet named List in the table into Array list

  //Tabloyu Listeye alma
      var veri1=[];
    for (var i=0;i&lt;data.length;i++){
      veri1.push([data[i][3]]); 
     }
    veri3=veri1.flat()


  var veri1=[];
for (var i=0;i&lt;data.length;i++){
  veri1.push([data[i][3]]); 
 }
veri3=veri1.flat()

import data from phonebook to Array List

//Rehberi Listeye ALma
  var options = {
    pageSize:1000,
    personFields: &#39;names,emailAddresses,phoneNumbers,metadata&#39;
  };
  var callback = People.People.Connections.list
  do{

    response = callback(&#39;people/me&#39;,options)

//response.connections.forEach(connection =&gt; connection.names ? isim.push(Utilities.formatDate(new Date(connection.metadata.sources[0].updateTime),&quot;GMT&quot;, &quot;dd.MM.yyyy&quot;)) : &#39;&#39;);
response.connections.forEach(connection =&gt; connection.emailAddresses ? veri.push(connection.emailAddresses?.map(email =&gt; email.value)):&#39;&#39;);

  options.pageToken = response.nextPageToken
  } while(options.pageToken)


veri2=veri.flat()

People Api asks for tokens for subsequent records after a certain registration, that is, there are 2500 contacts in your phone book, it does not show you 2500 records at once, it shows 1000 records so that you can get the next 1000

records options.pageToken = response.nextPageToken
   } while(options.pageToken)

this part must be in your code

this section compares two array lists

 for (var i=0;i&lt;veri3.length;i++){

if(!veri2.includes(veri3[i]))  

Adding a contact that is in the table but not in the phonebook to the phonebook

 for (var i=0;i&lt;veri3.length;i++){

if(!veri2.includes(veri3[i]))  


 {
   var contactResource = {
     &quot;names&quot;: [{
      &quot;givenName&quot;: data[i][0],
      &quot;familyName&quot;: data[i][1],
    }],
     &quot;phoneNumbers&quot;: [{
      &#39;value&#39;: &quot;0&quot;+data[i][4]
    }],
    &quot;emailAddresses&quot;: [{
      &#39;value&#39;: data[i][3]
    }],
    &quot;organizations&quot;: [{
       &quot;name&quot;: data[i][6],
      &quot;title&quot;: data[i][5],
      &quot;type&quot;: &quot;work&quot;

    }],
  }

add the contact you added to the phone book to the group called schools

 var contactResourceName = People.People.createContact(contactResource)[&quot;resourceName&quot;];
 var groupResourceName = group[&quot;resourceName&quot;];
  // 4. ADD CONTACT TO GROUP:
  var membersResource = {
    &quot;resourceNamesToAdd&quot;: [
      contactResourceName
    ]
  }
  People.ContactGroups.Members.modify(membersResource, groupResourceName); 

this code is to delete the person deleted from the table from the phone book

function tablodansilinenlerirehberdensilme() 

the whole code

function sharephonebook() {
      var veri=[];
  var veri2=[];
    var veri3=[];
  var response;

// grup yapma........................................................

  var groupName = &quot;Okullar&quot;;
  var groups = People.ContactGroups.list()[&quot;contactGroups&quot;];
  var group = groups.find(group =&gt; group[&quot;name&quot;] === groupName);
  // 3. CREATE GROUP IF DOESN&#39;T EXIST:
  if (!group) {
    var groupResource = {
      contactGroup: {
        name: groupName
      }
    }
    group = People.ContactGroups.create(groupResource);
  }
  var groupResourceName = group[&quot;resourceName&quot;];



  // tabloyu alma
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&quot;Liste&quot;);
var dataRange = sheet.getRange(2, 1, sheet.getLastRow()-1, 7)
var data = dataRange.getValues();

//Tabloyu Listeye alma
  var veri1=[];
for (var i=0;i&lt;data.length;i++){
  veri1.push([data[i][3]]); 
 }
veri3=veri1.flat()


//Rehberi Listeye ALma
  var options = {
    pageSize:1000,
    personFields: &#39;names,emailAddresses,phoneNumbers,metadata&#39;
  };
  var callback = People.People.Connections.list
  do{

    response = callback(&#39;people/me&#39;,options)
    
//response.connections.forEach(connection =&gt; connection.names ? isim.push(Utilities.formatDate(new Date(connection.metadata.sources[0].updateTime),&quot;GMT&quot;, &quot;dd.MM.yyyy&quot;)) : &#39;&#39;);
response.connections.forEach(connection =&gt; connection.emailAddresses ? veri.push(connection.emailAddresses?.map(email =&gt; email.value)):&#39;&#39;);
  
  options.pageToken = response.nextPageToken
  } while(options.pageToken)


veri2=veri.flat()


  for (var i=0;i&lt;veri3.length;i++){

if(!veri2.includes(veri3[i]))  


 {
   var contactResource = {
     &quot;names&quot;: [{
      &quot;givenName&quot;: data[i][0],
      &quot;familyName&quot;: data[i][1],
    }],
     &quot;phoneNumbers&quot;: [{
      &#39;value&#39;: &quot;0&quot;+data[i][4]
    }],
    &quot;emailAddresses&quot;: [{
      &#39;value&#39;: data[i][3]
    }],
    &quot;organizations&quot;: [{
       &quot;name&quot;: data[i][6],
      &quot;title&quot;: data[i][5],
      &quot;type&quot;: &quot;work&quot;

    }],
  }
  var contactResourceName = People.People.createContact(contactResource)[&quot;resourceName&quot;];
 var groupResourceName = group[&quot;resourceName&quot;];
  // 4. ADD CONTACT TO GROUP:
  var membersResource = {
    &quot;resourceNamesToAdd&quot;: [
      contactResourceName
    ]
  }
  People.ContactGroups.Members.modify(membersResource, groupResourceName);  

Logger.log(&quot;bulunmadu&quot;+ veri3[i])

  } 



 }

tablodansilinenlerirehberdensilme()

  };




function tablodansilinenlerirehberdensilme() {
//Sabitler  
  var veri=[];
  var veri2=[];
  var veri4=[];
  let x=1;
//OKullar Grubunun Kodunu Alma
  const people = People.ContactGroups.list();
  const group1 = people[&#39;contactGroups&#39;].find((group) =&gt; group[&#39;name&#39;] === &#39;Okullar&#39;);
  //console.log(group1.resourceName);
  
    // tabloyu alma
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(&quot;Liste&quot;);
var dataRange = sheet.getRange(2, 1, sheet.getLastRow()-1, 7)
var data = dataRange.getValues();

//Tabloyu Listeye alma
  var veri1=[];
for (var i=0;i&lt;data.length;i++){
  veri1.push([data[i][3]]); 
 }
veri3=veri1.flat()
//Logger.log(veri3)

//Okullar Rehberini Listeye Alma
  var options = {
    pageSize:1000,
    personFields: &#39;names,emailAddresses,phoneNumbers,metadata,memberships&#39;
  };
  var callback = People.People.Connections.list
    do{
     response = callback(&#39;people/me&#39;,options)
     response.connections.forEach((person) =&gt; {
      // if contacts/connections is available, print the name of person.
      if (person.memberships[0].contactGroupMembership.contactGroupResourceName === group1.resourceName) {
        veri.push(person.emailAddresses[0].value);
        veri4.push(person.resourceName);
        return;
      }
      });
      options.pageToken = response.nextPageToken
      } while(options.pageToken)
 
   veri2=veri.flat()
  // Logger.log(veri2)
//Tabloyu Listeye Alma
 //veri2 flatlanmış Rehberlistesi
  for (var i=0;i&lt;veri2.length;i++){

if(!veri3.includes(veri2[i]))  {
  
  People.People.deleteContact(veri4[i])
 
}
  }
  
}


`

huangapple
  • 本文由 发表于 2023年5月28日 15:07:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76350342.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定