Exception: Cannot retrieve the next object: iterator has reached the end - google-apps-script

im trying to get files in different folders and get some cell values from them and put it in a sheet.
but i get below error
Exception: Cannot retrieve the next object: iterator has reached the end
im using below code and when i run it. it returns error on line 14
it seems code returns some values from first and second folders but for third one it returns error
after running macro it gives log below:
5:24:43 PM Notice Execution started
5:24:45 PM Info [[]]
5:24:45 PM Info [[]]
5:24:46 PM Error
Exception: Cannot retrieve the next object: iterator has reached the end.
list_files_in_folders # macros.gs:14
my code : line 14 error
function list_files_in_folders(){
var sh = SpreadsheetApp.getActiveSheet();
var mainfolder = DriveApp.getFolderById('id-here'); // I change the folder ID here
var mfolders = mainfolder.getFolders();
var data = [];
data.push(['Person Name','File Name','Value 1','Value 2']);
while (mfolders.hasNext){
var mfolder = mfolders.next();
var personfolder = DriveApp.getFolderById(mfolder.getId());
var pfiles = personfolder.getFiles();
data.push([personfolder.getName,,,]);
while(pfiles.hasNext){
var pfile = pfiles.next(); //error here
var personfile = SpreadsheetApp.openById(pfile.getId());
var value1 = personfile.getSheetValues(2,9,1,1);
//var value2 = personfile.getSheetValues();
Logger.log(value1);
data.push(["",pfile.getName,value1,""]);
}
}
sh.getRange(1,1,data.length,data[0].length).setValues(data);
}

Folder or File hasNext() is a method, not a property.
Replace both
mfolders.hasNext
pfiles.hasNext
With
mfolders.hasNext()
pfiles.hasNext()
Reference
FolderIterator.hasNext()
FileIterator.hasNext()

You can make your list_files_in_folders() function easier to adapt by doing report building in one function and the recursive subfolder iteration in another, using closures to process the files.
More lines of code are required, but making changes becomes much easier, and you can apply these functions in other use cases more smoothly — just modify the _fileAction and _folderAction closures as required.
This pattern also lets you handle errors and timeouts more gracefully.
/** #NotOnlyCurrentDoc */
'use strict';
function list_files_in_folders() {
const mainFolder = DriveApp.getFolderById('...put folder ID here...');
const data = generateReport_(mainFolder);
SpreadsheetApp.getActiveSheet().getRange('A1')
.offset(0, 0, data.length, data[0].length)
.setValues(data);
}
/**
* Generates a report based on spreadsheets organized by subfolder.
*
* #param {DriveApp.Folder} folder A folder with files and subfolders.
* #return {String[][]} A 2D array that contains a report of files organized by subfolder.
*/
function generateReport_(folder) {
const data = [];
const _errorHandler = (error) => console.log(error.message);
const _prefix = (folderName, nestingLevel) => ' '.repeat(nestingLevel) + folderName;
const _folderAction = (folder, nestingLevel) => {
data.push([_prefix(folder.getName(), nestingLevel), '', '', '']);
};
const _fileAction = (file) => {
const ss = getSpreadsheetFromFile_(file, _errorHandler);
if (ss) {
data.push(['', ss.getName(), ss.getSheetValues(2, 9, 1, 1), '']);
} else {
data.push(['', file.getName(), '(not a Google Sheet)', '']);
}
};
const timelimit = new Date().getTime() + 4 * 60 * 1000; // stop when 4 minutes have passed
const error = processFilesInFolderRecursively_(folder, _folderAction, _fileAction, _errorHandler, 1, timelimit);
if (error) {
data.push([error.message, '', '', '']);
_errorHandler(error);
}
return [['Person Name', 'File Name', 'Value 1', 'Value 2']].concat(
data.length ? data : [['(Could not find any files. Check folder ID.)', '', '', '']]
);
}
/**
* Iterates files in a folder and its subfolders, executing
* _folderAction with each folder and _fileAction with each file.
*
* #param {DriveApp.Folder} folder The folder to process.
* #param {Function} _folderAction The function to run with each folder.
* #param {Function} _fileAction The function to run with each file.
* #param {Function} _errorHandler The function to call when an error occurs.
* #param {String} nestingLevel Optional. A number that indicates the current folder nesting nevel.
* #param {Number} timelimit Optional. The moment in milliseconds that indicates when to stop processing.
* #return {Error} An error when the function ran out of time, otherwise undefined.
* #license https://www.gnu.org/licenses/gpl-3.0.html
*/
function processFilesInFolderRecursively_(folder, _folderAction, _fileAction, _errorHandler, nestingLevel, timelimit) {
// version 1.2, written by --Hyde, 1 December 2022
nestingLevel = nestingLevel || 0;
const outOfTime = new Error('Ran out of time.');
if (new Date().getTime() > timelimit) {
return outOfTime;
}
const files = folder.getFiles();
while (files.hasNext()) {
if (new Date().getTime() > timelimit) {
return outOfTime;
}
try {
_fileAction(files.next());
} catch (error) {
_errorHandler(error);
}
}
const subfolders = folder.getFolders();
while (subfolders.hasNext()) {
const folder = subfolders.next();
_folderAction(folder, nestingLevel);
const error = processFilesInFolderRecursively_(folder, _folderAction, _fileAction, _errorHandler, nestingLevel + 1, timelimit);
if (error) {
return error; // outOfTime
};
}
}
/**
* Gets a spreadsheet object from a file object.
*
* #param {DriveApp.File} file The file that contains a spreadsheet.
* #param {Function} _errorHandler The function to call when an error occurs.
* #return {SpreadsheetApp.Spreadsheet} The spreadsheet object, or null if file is not a spreadsheet or cannot be accessed.
* #license https://www.gnu.org/licenses/gpl-3.0.html
*/
function getSpreadsheetFromFile_(file, _errorHandler) {
// version 1.0, written by --Hyde, 9 October 2022
if (file.getMimeType() !== 'application/vnd.google-apps.spreadsheet') {
return null;
}
let ss;
try {
ss = SpreadsheetApp.open(file);
} catch (error) {
_errorHandler(error);
return null;
}
return ss;
}

Related

list activities on google drive

I would like to be able to upload my file activities with API from google drive activity or other ideas. Each of my files are stored in a tree structure that contains the name of my client. And in the following put it in an excel file in order to be able to sort it correctly for example if a file has been modified more than 2 times in one day, it is validated
Currently, I used the code provided by google but I can't find the directory of these modified files
I thank you in advance, I really block, other ideas or API are welcome.
Sincerly
/**
* Lists 10 activity for a Drive user.
* #see https://developers.google.com/drive/activity/v2/reference/rest/v2/activity/query
*/
function listDriveActivity() {
const request = {
"ancestor_name": "items/root",
"filter": "time >= \"2022-06-01T00:00:00Z\" time < \"2022-06-30T00:00:00Z\" detail.action_detail_case:EDIT",
"consolidation_strategy": { "legacy": {} },
"page_size": 10,
};
try {
// Activity.query method is used Query past activity in Google Drive.
const response = DriveActivity.Activity.query(request);
const activities = response.activities;
if (!activities || activities.length === 0) {
console.log('No activity.');
return;
}
console.log('Recent activity:');
for (const activity of activities) {
// get time information of activity.
const time = getTimeInfo(activity);
// get the action details/information
const action = getActionInfo(activity.primaryActionDetail);
// get the actor's details of activity
const actors = activity.actors.map(getActorInfo);
// get target information of activity.
const targets = activity.targets.map(getTargetInfo);
// print the time,actor,action and targets of drive activity.
console.log('%s: %s, %s, %s', time, actors, action, targets);
}
} catch (err) {
// TODO (developer) - Handle error from drive activity API
console.log('Failed with an error %s', err.message);
}
}
/**
* #param {object} object
* #return {string} Returns the name of a set property in an object, or else "unknown".
*/
function getOneOf(object) {
for (const key in object) {
return key;
}
return 'unknown';
}
/**
* #param {object} activity Activity object.
* #return {string} Returns a time associated with an activity.
*/
function getTimeInfo(activity) {
if ('timestamp' in activity) {
return activity.timestamp;
}
if ('timeRange' in activity) {
return activity.timeRange.endTime;
}
return 'unknown';
}
/**
* #param {object} actionDetail The primary action details of the activity.
* #return {string} Returns the type of action.
*/
function getActionInfo(actionDetail) {
return getOneOf(actionDetail);
}
/**
* #param {object} user The User object.
* #return {string} Returns user information, or the type of user if not a known user.
*/
function getUserInfo(user) {
if ('knownUser' in user) {
const knownUser = user.knownUser;
const isMe = knownUser.isCurrentUser || false;
return isMe ? 'people/me' : knownUser.personName;
}
return getOneOf(user);
}
/**
* #param {object} actor The Actor object.
* #return {string} Returns actor information, or the type of actor if not a user.
*/
function getActorInfo(actor) {
if ('user' in actor) {
return getUserInfo(actor.user);
}
return getOneOf(actor);
}
/**
* #param {object} target The Target object.
* #return {string} Returns the type of a target and an associated title.
*/
function getTargetInfo(target) {
if ('driveItem' in target) {
const title = target.driveItem.title || 'unknown';
return 'driveItem:"' + title + '"';
}
if ('drive' in target) {
const title = target.drive.title || 'unknown';
return 'drive:"' + title + '"';
}
if ('fileComment' in target) {
const parent = target.fileComment.parent || {};
const title = parent.title || 'unknown';
return 'fileComment:"' + title + '"';
}
return getOneOf(target) + ':unknown';
}
Final goal: to get the amount of days I work for all my clients.
That a idea
After some search and code (some help with GTP so sorry for begin code)
function listDriveActivity(sheet,timezone) {
let pageToken = null;
do {
try {
// Activity.query method is used Query past activity in Google Drive.
const response = DriveActivity.Activity.query({ "ancestor_name": "items/13oHhdSDQqnM4ppO48FPJq7HAmVjR27H5", //"items/root",
"filter": "time >= \"2022-01-01T00:00:00Z\" time < \"2022-01-31T00:00:00Z\" detail.action_detail_case:EDIT",
"consolidation_strategy": { "legacy": {} },"pageSize": 10,pageToken: pageToken});
//Logger.log(response);
const activities = response.activities;
if (!activities || activities.length === 0) {
console.log('No activity.');
return;
}
//console.log('Recent activity:');
for (const activity of activities) {
// get time information of activity.
const time = getTimeInfo(activity);
// get the action details/information
const action = getActionInfo(activity.primaryActionDetail);
// get the actor's details of activity
//const actors = activity.actors.map(getActorInfo);
// get target information of activity.
const targets = activity.targets.map(getTargetInfo);
// print the time,actor,action and targets of drive activity.
// const folderName = activity.targets.map(getFileArborescenceByName);
const folderName = activity.targets.map(getFileArborescenceByID);
var NomDossier = JSON.stringify(folderName).replace(/\[\"|\"\]/g,'');
const ClientName = getClient(NomDossier);
//console.log('%s: %s, %s, %s, %s', time, action, targets, folderName, ClientName);
const timeAsDate = new Date(time);
const lastModified = Utilities.formatDate(timeAsDate, "UTC", "dd-MM-yyyy HH:mm");
var Nomfichier = JSON.stringify(targets).replace(/\[\"|\"\]/g,'');
sheet.appendRow([lastModified, action, Nomfichier, NomDossier, ClientName]);
}
pageToken = response.nextPageToken;
}
catch (err) {
// TODO (developer) - Handle error from drive activity API
console.log('Failed with an error %s', err.message);
}
} while (pageToken);
return sheet;
}
function getFileArborescenceByID(activity) {
if ('driveItem' in activity) {
try {
const fileName = activity.driveItem.name;
var modif = getLastPart (fileName);
var file = DriveApp.getFileById(modif);
var folders = [];
var parent = file.getParents();
while (parent.hasNext()) {
parent = parent.next();
folders.push(parent.getName());
parent = parent.getParents();
}
if (folders.length) {
// Display the full folder path
var folderName = (folders.reverse().join("/"));
}
//var ClientName = getClient(folderName);
}
catch (err) {
// TODO (developer) - Handle error from drive activity API
console.log('Failed with an error %s', err.message);
}
}
//return 'folderName:"' + folderName + '", Client :"' + ClientName + '"';
return folderName;

GitHub Rest Api SHA of file that contains special characters

Main issue
This code works, but the areReallyEqual should not be necessary. In fact it is not necessary for files that don't contain special characters ("ñ", "é", "à", etc), so: all of my files except for 2 of them.
if (internalFileTextSha !== repositoryFile.sha) {
// The sha might not be equal due to special characters in the text ("ñ", "é", "à", etc)... doing a second check...
const remoteFileText = this._gitHubApi.fetchGitHubGetUrl(repositoryFile.download_url).getContentText();
const remoteFileTextSha = GitHubCrypto.getSha(remoteFileText);
const areReallyEqual = remoteFileTextSha === internalFileTextSha;
if(!areReallyEqual) {
// The file has been modified, creating a new commit with the updated file...
this._gitHubApi.commitUpdatedFile(repositoryName, repositoryFile, internalFile.source);
} else {
// The second check determined that both files were equal
}
}
More details
internalFile comes from here:
/**
* #typedef {Object} InternalFile
* #property {string} id - The ID of the internal file.
* #property {string} name - The name of the internal file.
* #property {string} type - The type of the internal file.
* #property {string} source - The source code of the internal file.
*/
/**
* Gets all the internal files of a Google Apps Script file.
*
* #returns {InternalFile[]} An array of objects.
*/
static getScriptInternalFiles(file) {
// Check that the file is a Google Apps Script file
if (file.getMimeType() == 'application/vnd.google-apps.script') {
// Get the script content as a string
const fileId = file.getId();
const params = {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
'Accept-Charset': 'utf-8'
},
followRedirects: true,
muteHttpExceptions: true,
};
const url =
'https://script.google.com/feeds/download/export?id='
+ fileId
+ '&format=json';
const response = UrlFetchApp.fetch(url, params);
const json = JSON.parse(response);
return json.files;
} else {
throw new Error("The file is not a Google Apps Script file.");
}
}
...while remoteFile comes from here:
/**
* #typedef {Object} RepositoryFile
* #property {string} name - The name of the file.
* #property {string} path - The file path in the repository.
* #property {string} sha - The SHA hash of the file.
* #property {Number} size - The size of the file in bytes.
* #property {string} url - The URL of the file's contents.
* #property {string} html_url - The URL to the file's page on the repository website.
* #property {string} git_url - The URL to the file's git contents.
* #property {string} download_url - The URL to download the file.
* #property {string} type - The type of the file, usually "file".
*/
/**
* Gets all the internal files of a Google Apps Script file.
*
* #returns {RepositoryFile[]} An array of objects.
*/
listFilesInRepository(repositoryName) {
let repositoryFiles = [];
try {
const options = {
headers: {
...this._authorizationHeader,
},
};
const response = UrlFetchApp.fetch(`${this._buildRepositoryUrl(repositoryName)}/contents`, options);
repositoryFiles = JSON.parse(response);
} catch(e) {
const errorMessage = GitHubApi._getErrorMessage(e);
if(errorMessage === 'This repository is empty.') {
// do nothing
} else {
// unknown error
throw e;
}
}
return repositoryFiles;
}
...and the SHA calculation:
class GitHubCrypto {
/**
* #param {string} fileContent
* #returns {string} SHA1 hash string
*/
static getSha(fileContent) {
// GitHub is computing the sum of `blob <length>\x00<contents>`, where `length` is the length in bytes of the content string and `\x00` is a single null byte.
// For the Sha1 implementation, see: www.movable-type.co.uk/scripts/sha1.html
const sha = Sha1.hash('blob ' + fileContent.length + '\x00' + fileContent);
return sha;
}
}
I believe your goal is as follows.
You want to retrieve the has value of 430f370909821443112064cd149a4bebd271bfc4 from a value of ñèàü using Google Apps Script.
In this case, how about the following sample script?
Sample script:
function myFunction() {
const fileContent = 'ñèàü'; // This is from your comment.
const value = 'blob ' + fileContent.length + '\x00' + fileContent;
const bytes = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_1, value, Utilities.Charset.UTF_8);
const res = bytes.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
console.log(res); // 430f370909821443112064cd149a4bebd271bfc4
}
When this script is run, the has value of 430f370909821443112064cd149a4bebd271bfc4 is obtained.
When aaaa is directly used like const res = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_1, "aaaa", Utilities.Charset.UTF_8).map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join(''), 70c881d4a26984ddce795f6f71817c9cf4480e79 is obtained.
Reference:
computeDigest(algorithm, value)
I have finally found the problem... the problem was in the "bytes length":
GitHub is computing the sum of blob <length>\x00<contents>, where length is the length in bytes of the content string and \x00 is a single null byte.
When there are no special characters, lengthInBytes == inputStr.length, but when there are special characters this is no longer true:
// For the Sha1 implementation, see: www.movable-type.co.uk/scripts/sha1.html
function simpleShaTest1() {
const fileContent = 'ñèàü';
const expectedSha = '56c9357fcf2589619880e1978deb8365454ece11';
const sha = Sha1.hash('blob ' + byteLength(fileContent) + '\x00' + fileContent);
const areEqual = (sha === expectedSha); // true
}
function simpleShaTest2() {
const fileContent = 'aaa';
const expectedSha = '7c4a013e52c76442ab80ee5572399a30373600a2';
const sha = Sha1.hash('blob ' + lengthInUtf8Bytes(fileContent) + '\x00' + fileContent);
const areEqual = (sha === expectedSha); // true
}
function lengthInUtf8Bytes(str) {
// Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
var m = encodeURIComponent(str).match(/%[89ABab]/g);
// `m` is `null` when there are no special characters, thus returning `m.length`
return str.length + (m ? m.length : 0);
}

2nd Function not executing - suitescript

I have the below code. I want the function called execute2 to run after the function execute. When I put the script task inside the first function and don't include execute2 then it all runs fine and the second separate script runs. But when I run it in the below format it does not. What is preventing execute 2 from actually running here?
Thank you
/**
* #NApiVersion 2.x
* #NScriptType ScheduledScript
* #NModuleScope SameAccount
*/
define(['N/task'],
/**
* #param {record} record
* #param {search} search
*/
function(task) {
var FILE_ID = 433961;
var SEARCH_ID = 1610;
function execute(scriptContext) {
var searchTask1 = task.create({
taskType: task.TaskType.SEARCH
});
searchTask1.savedSearchId = SEARCH_ID;
searchTask1.fileId = FILE_ID;
var searchTaskId1 = searchTask1.submit();
//
//Next Task
//
FILE_ID = 433963;
SEARCH_ID = 1606;
var searchTask2 = task.create({
taskType: task.TaskType.SEARCH
});
searchTask2.savedSearchId = SEARCH_ID;
searchTask2.fileId = FILE_ID;
var searchTaskId2 = searchTask2.submit();
//
//Next Task
//
FILE_ID = 434489;
SEARCH_ID = 1637;
var searchTask3 = task.create({
taskType: task.TaskType.SEARCH
});
searchTask3.savedSearchId = SEARCH_ID;
searchTask3.fileId = FILE_ID;
var searchTaskId3 = searchTask3.submit();
//
// Next Task
//
FILE_ID = 434490;
SEARCH_ID = 1606;
var searchTask4 = task.create({
taskType: task.TaskType.SEARCH
});
searchTask4.savedSearchId = SEARCH_ID;
searchTask4.fileId = FILE_ID;
var searchTaskId4 = searchTask4.submit();
}
function execute2(scriptContext){
var scriptTask = task.create({
taskType: task.TaskType.SCHEDULED_SCRIPT,
scriptId: "customscript_email_sender",
deploymentId: "customdeploy_email_sender_d"
});
var scriptTaskId = scriptTask.submit();
}
return {
execute: execute,
execute2: execute2,
};
});
Building on the comment from W.S., all you need to do is to define two functions that encapsulate your business logic and then call those functions in order within your scheduled script's entry point.
Below is a simple example, showing the scheduled script executing doFirstTask() followed by doSecondTask(). You can redefine those however you like to meet your own needs.
/**
* #NApiVersion 2.x
* #NScriptType ScheduledScript
*/
define([], function() {
return {
execute: function (context)
{
doFirstTask(context);
doSecondTask(context);
}
}
});
/**
* This function contains all of the logic you need to execute
* for the first of your two tasks.
*
* #param context Passed in from the scheduled script's entry point.
*/
function doFirstTask(context) {
log.debug({
title: context.type + ': First Task',
details: 'The first of many great feats.'
});
}
/**
* This function contains all of the logic you need to execute
* for the second of your two tasks.
*
* #param context Passed in from the scheduled script's entry point.
*/
function doSecondTask(context) {
log.debug({
title: context.type + ': Second Task',
details: 'Second, even more impressive than the first.'
});
}
Here's a screenshot showing what the output looks like.

Google Calendar API App Script - "Error: Not Found: Skipping"

I'm using this App Script Populate a team vacation calendar
I'm receiving the following error for 1 person in a Google Group of 50 users.
'Error retriving events for email#email.com, vacation:
GoogleJsonResponseException: API call to calendar.events.list failed
with error: Not Found; skipping'
When setting a breakpoint, it fails on this import event.
function importEvent(username, event) {
event.summary = '[' + username + '] ' + event.summary;
event.organizer = {
id: TEAM_CALENDAR_ID,
};
event.attendees = [];
console.log('Importing: %s', event.summary);
try {
Calendar.Events.import(event, TEAM_CALENDAR_ID);
} catch (e) {
console.error('Error attempting to import event: %s. Skipping.',
e.toString());
}
}
do {
params.pageToken = pageToken;
let response;
try {
response = Calendar.Events.list(user.getEmail(), params);
} catch (e) {
console.error('Error retriving events for %s, %s: %s; skipping',
user, keyword, e.toString());
continue;
}
events = events.concat(response.items.filter(function(item) {
return shoudImportEvent(user, keyword, item);
}));
pageToken = response.nextPageToken;
} while (pageToken);
return events;
}
This is the stack:
"GoogleJsonResponseException: API call to calendar.events.list failed
with error: Not Found at findEvents (Code:111:34) at Code:48:20 at
Array.forEach () at Code:47:14 a…"
This is the full code
// Set the ID of the team calendar to add events to. You can find the calendar's
// ID on the settings page.
let TEAM_CALENDAR_ID = 'CALENDAR ID';
// Set the email address of the Google Group that contains everyone in the team.
// Ensure the group has less than 500 members to avoid timeouts.
let GROUP_EMAIL = 'GROUP EMAIL';
let KEYWORDS = ['vacation', 'ooo', 'out of office', 'offline'];
let MONTHS_IN_ADVANCE = 3;
/**
* Sets up the script to run automatically every hour.
*/
function setup() {
let triggers = ScriptApp.getProjectTriggers();
if (triggers.length > 0) {
throw new Error('Triggers are already setup.');
}
ScriptApp.newTrigger('sync').timeBased().everyHours(1).create();
// Runs the first sync immediately.
sync();
}
/**
* Looks through the group members' public calendars and adds any
* 'vacation' or 'out of office' events to the team calendar.
*/
function sync() {
// Defines the calendar event date range to search.
let today = new Date();
let maxDate = new Date();
maxDate.setMonth(maxDate.getMonth() + MONTHS_IN_ADVANCE);
// Determines the time the the script was last run.
let lastRun = PropertiesService.getScriptProperties().getProperty('lastRun');
lastRun = lastRun ? new Date(lastRun) : null;
// Gets the list of users in the Google Group.
let users = GroupsApp.getGroupByEmail(GROUP_EMAIL).getUsers();
// For each user, finds events having one or more of the keywords in the event
// summary in the specified date range. Imports each of those to the team
// calendar.
let count = 0;
users.forEach(function(user) {
let username = user.getEmail().split('#')[0];
KEYWORDS.forEach(function(keyword) {
let events = findEvents(user, keyword, today, maxDate, lastRun);
events.forEach(function(event) {
importEvent(username, event);
count++;
}); // End foreach event.
}); // End foreach keyword.
}); // End foreach user.
PropertiesService.getScriptProperties().setProperty('lastRun', today);
console.log('Imported ' + count + ' events');
}
/**
* Imports the given event from the user's calendar into the shared team
* calendar.
* #param {string} username The team member that is attending the event.
* #param {Calendar.Event} event The event to import.
*/
function importEvent(username, event) {
event.summary = '[' + username + '] ' + event.summary;
event.organizer = {
id: TEAM_CALENDAR_ID,
};
event.attendees = [];
console.log('Importing: %s', event.summary);
try {
Calendar.Events.import(event, TEAM_CALENDAR_ID);
} catch (e) {
console.error('Error attempting to import event: %s. Skipping.',
e.toString());
}
}
/**
* In a given user's calendar, looks for occurrences of the given keyword
* in events within the specified date range and returns any such events
* found.
* #param {Session.User} user The user to retrieve events for.
* #param {string} keyword The keyword to look for.
* #param {Date} start The starting date of the range to examine.
* #param {Date} end The ending date of the range to examine.
* #param {Date} optSince A date indicating the last time this script was run.
* #return {Calendar.Event[]} An array of calendar events.
*/
function findEvents(user, keyword, start, end, optSince) {
let params = {
q: keyword,
timeMin: formatDateAsRFC3339(start),
timeMax: formatDateAsRFC3339(end),
showDeleted: true,
};
if (optSince) {
// This prevents the script from examining events that have not been
// modified since the specified date (that is, the last time the
// script was run).
params.updatedMin = formatDateAsRFC3339(optSince);
}
let pageToken = null;
let events = [];
do {
params.pageToken = pageToken;
let response;
try {
response = Calendar.Events.list(user.getEmail(), params);
} catch (e) {
console.error('Error retriving events for %s, %s: %s; skipping',
user, keyword, e.toString());
continue;
}
events = events.concat(response.items.filter(function(item) {
return shoudImportEvent(user, keyword, item);
}));
pageToken = response.nextPageToken;
} while (pageToken);
return events;
}
/**
* Determines if the given event should be imported into the shared team
* calendar.
* #param {Session.User} user The user that is attending the event.
* #param {string} keyword The keyword being searched for.
* #param {Calendar.Event} event The event being considered.
* #return {boolean} True if the event should be imported.
*/
function shoudImportEvent(user, keyword, event) {
// Filters out events where the keyword did not appear in the summary
// (that is, the keyword appeared in a different field, and are thus
// is not likely to be relevant).
if (event.summary.toLowerCase().indexOf(keyword.toLowerCase) < 0) {
return false;
}
if (!event.organizer || event.organizer.email == user.getEmail()) {
// If the user is the creator of the event, always imports it.
return true;
}
// Only imports events the user has accepted.
if (!event.attendees) return false;
let matching = event.attendees.filter(function(attendee) {
return attendee.self;
});
return matching.length > 0 && matching[0].responseStatus == 'accepted';
}
/**
* Returns an RFC3339 formated date String corresponding to the given
* Date object.
* #param {Date} date a Date.
* #return {string} a formatted date string.
*/
function formatDateAsRFC3339(date) {
return Utilities.formatDate(date, 'UTC', 'yyyy-MM-dd\'T\'HH:mm:ssZ');
}

question on accessing or getting specific google app script query parameter

I was wondering if I can access a specific query parameter from a method from activities.list API
specifically this piece of code
activity.events[0].parameters
I've already tried accessing through array like this:
activity.events[0].parameters[2]
but the output is not consistent, for instance index 2 is not what I need instead its a different query parameter. What I need is for example I need to access
organizer_email
parameter specifically from the API (https://developers.google.com/admin-sdk/reports/v1/appendix/activity/meet)
I'll attach my sample code here. its from google api examples
(https://developers.google.com/admin-sdk/reports/v1/quickstart/apps-script)
/**
* List login events for a G Suite domain.
* #see https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list
*/
function getData() {
var today = new Date();
var oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
var timezone = Session.getScriptTimeZone();
var date = Utilities.formatDate(oneWeekAgo, timezone, 'yyyy-MM-dd');
const userKey = 'all';
const applicationName = 'meet';
var pageToken;
const optionalArgs = {
maxResults: 10,
pageToken: pageToken,
};
try {
const response = AdminReports.Activities.list(userKey, applicationName, optionalArgs);
const activities = response.items;
if (!activities || activities.length === 0) {
Logger.log('No logins found.');
return;
}
// Print login events
Logger.log('MEET LOGS:');
for (const activity of activities) {
Logger.log('(%s) %s %s', activity.events[0].parameters, activity.id.time, activity.id.time);
}
} catch (err) {
// TODO (developer)- Handle exception from the Report API
Logger.log('Failed with error %s', err.message);
}
}
sample array / json result (2 results)
[
{"name":"video_send_seconds","intValue":"40"},
{"name":"screencast_recv_bitrate_kbps_mean","intValue":"128"},
{"value":"email_address","name":"identifier_type"},
{"name":"audio_send_bitrate_kbps_mean","intValue":"2"},
{"name":"video_send_packet_loss_max","intValue":"1"},
{"value":"meetings_android_214151224321356190","name":"endpoint_id"},
{"name":"device_type","value":"android"},{"intValue":"0","name":"video_send_packet_loss_mean"},
{"intValue":"240","name":"video_recv_long_side_median_pixels"},
{"name":"screencast_recv_long_side_median_pixels","intValue":"1072"},
{"name":"screencast_send_seconds","intValue":"0"},
{"name":"video_send_fps_mean","intValue":"15"},
{"intValue":"4","name":"audio_send_packet_loss_max"},
{"intValue":"132","name":"video_recv_short_side_median_pixels"},
{"intValue":"0","name":"video_recv_packet_loss_mean"},
{"name":"screencast_recv_fps_mean","intValue":"8"},
{"intValue":"1267","name":"audio_recv_seconds"},
{"intValue":"0","name":"network_congestion"},
{"name":"network_estimated_download_kbps_mean","intValue":"1398"},
{"intValue":"0","name":"audio_send_packet_loss_mean"},
{"name":"network_transport_protocol","value":"udp"},
{"intValue":"1269","name":"duration_seconds"},
{"intValue":"103","name":"video_send_bitrate_kbps_mean"},
{"name":"identifier","value":"xxxxxx.xxxxx#xxxx.xxx"},
{"intValue":"78","name":"audio_recv_packet_loss_max"},
{"intValue":"10","name":"video_recv_fps_mean"},
{"intValue":"3","name":"audio_recv_packet_loss_mean"},
{"name":"network_recv_jitter_msec_max","intValue":"205"},
{"name":"organizer_email","value":"xxxxxx#xxxxx.xxx"},
{"name":"screencast_recv_short_side_median_pixels","intValue":"480"},
{"name":"network_recv_jitter_msec_mean","intValue":"19"},
{"name":"audio_send_seconds","intValue":"1267"},
{"value":"xxxxxxxxxx","name":"display_name"},
{"name":"screencast_recv_packet_loss_max","intValue":"0"},
{"name":"video_recv_seconds","intValue":"71"},
{"intValue":"35","name":"network_rtt_msec_mean"},
{"name":"video_send_long_side_median_pixels","intValue":"240"},
{"name":"screencast_recv_packet_loss_mean","intValue":"0"},
{"value":"fjqip32o1ru139DFSA2wer23","name":"conference_id"},
{"intValue":"883","name":"screencast_recv_seconds"},
{"name":"product_type","value":"meet"},
{"name":"network_estimated_upload_kbps_mean","intValue":"87"},
{"name":"video_send_short_side_median_pixels","intValue":"132"},
{"intValue":"0","name":"video_recv_packet_loss_max"},
{"name":"meeting_code","value":"ZXWEREHXSG"},
{"name":"is_external","boolValue":true}
]
2nd result:
[
{"name":"video_send_seconds","intValue":"0"},
{"name":"identifier_type","value":"email_address"},
{"name":"audio_send_bitrate_kbps_mean","intValue":"5"},
{"value":"meetings_android_23adjfuhvioalu23xpiow;","name":"endpoint_id"},
{"name":"device_type","value":"android"},
{"intValue":"0","name":"screencast_send_seconds"},
{"intValue":"0","name":"audio_recv_seconds"},
{"intValue":"0","name":"network_congestion"},
{"name":"network_estimated_download_kbps_mean","intValue":"0"},
{"value":"udp","name":"network_transport_protocol"},
{"name":"duration_seconds","intValue":"9"},
{"value":"xxxxxxxxxx.xxxxxxxxx#xxxxxx.xxxxxx","name":"identifier"},
{"value":"xxxxxxxxxxx#xxxxxxxx.xxxxx","name":"organizer_email"},
{"name":"audio_send_seconds","intValue":"7"},
{"name":"display_name","value":"xxxxxxxxxxxxx"},
{"intValue":"0","name":"video_recv_seconds"},
{"intValue":"30","name":"network_rtt_msec_mean"},
{"name":"conference_id","value":"4ersdfgwe3re43edf3s"},
{"name":"screencast_recv_seconds","intValue":"0"},
{"name":"product_type","value":"meet"},
{"name":"network_estimated_upload_kbps_mean","intValue":"0"},
{"name":"meeting_code","value":"43eradsfdas23hgrf"},
{"boolValue":true,"name":"is_external"}
]
found the answer
example usage:
activity.events[0].parameters.find(x => x.name ==='duration_seconds').intValue