Error while creating document in Firestore through Google App Script - google-apps-script

I am following grahamearley's guide in setting up my google sheets to read/write to my firestore database. I have created a service account assigned to be the project owner, generated the key and stored the relevant strings in my testFunction as follows:
function testFunction() {
var key = "-----BEGIN PRIVATE KEY-----\n<my private key>\n-----END PRIVATE KEY-----\n";
var email = "xxxx#<projectId>.iam.gserviceaccount.com";
var projectId = "<projectId>";
var firestore = FirestoreApp.getFirestore(email, key, projectId);
const data = {
"name": "test!!"
};
firestore.createDocument("FirstCollection", data);
}
However, when I try running this, I obtain the following error:
Error: Missing or insufficient permissions. (line 33, file "Util",
project "FirestoreApp")
I tried setting my database rule as follows, but the function still returned an error:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if false;
}
}
}
I have searched here for questions with the same error of insufficient permissions, but have not found anything that helps me.
Could someone please advise me on finding out the issue and fixing it? Thank you.
Manifest:
{
"timeZone": "Europe/Paris",
"dependencies": {
"libraries": [{
"userSymbol": "FirestoreApp",
"libraryId": "1VUSl4b1r1eoNcRWotZM3e87ygkxvXltOgyDZhixqncz9lQ3MjfT1iKFw",
"version": "22"
}]
},
"exceptionLogging": "STACKDRIVER"
}
EDIT1: Added manifest file
EDIT2: Added db rules

I have since resolved this issue. It seems the problem was with my service account. I had selected Project>Owner instead of Datastore>Cloud Datastore Owner.
Thank you for all your help rendered.

Related

GoogleJsonResponseException: Field name is required

I'm working with the Google Analytics API for the first time and I'm trying to create a new property. I wrote a JS function in Google App Script:
function insertProperty() {
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
var accountID = '177832616';
var request = Analytics.Management.Webproperties.insert(resource, accountID);
// request.execute(function (response) { console.log(property.id) });
}
This is the error the API throws:
GoogleJsonResponseException: API call to analytics.management.webproperties.insert failed with error: Field name is required. (line 56, file "Code")
The insert() method seems to take two parameters: insert(Webproperty resource, string accountId);
Since it's not recognizing the name key/value I added to resource, my guess is I haven't declared the variable as a Webproperty type and I'm not sure how to do this. I assumed Webproperty was a { } variable type, but at this point I'm not sure what to try next. Doing research online, I'm not able to find anything regarding the API's Webproperty so any context/info is helpful.
From your question, I could understand that Google Analytics API is used with Advanced Google services of Google Apps Script. In this case, resource of Analytics.Management.Webproperties.insert(resource, accountId) can directly use the request body of the method of "Web Properties: insert". I think that the reason of your error is due to this. So please modify as follows and test it again.
From:
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
To:
var resource = {
"name": "Test Property 7",
"websiteUrl": "https://www.test.com"
}
Note:
When accountId is not correct, an error occurs. Please be careful this.
From iansedano's comment, in this case, request of var request = Analytics.Management.Webproperties.insert(resource, accountID); directly returns the values. So you can see the value like console.log(request) and console.log(request.toString()).
Reference:
Web Properties: insert

Unable to use DriveApp.getFileById(id).getLastUpdated();

I want to know the latest updated date of a file at location "https://drive.google.com/open?id=XYZ". This address is present in A1 cell of my sheet.
But every time it throws this error: "You do not have permission to call DriveApp.getFileById. Required permissions: (https://www.googleapis.com/auth/drive.readonly || https://www.googleapis.com/auth/drive) (line 3)."
I have made changes in appScript.jason file also.
This is the code that I have written in script editor and call from B1 cell:
function useThis(url){
var id = getIdFromUrl(url);
return DriveApp.getFileById(id).getLastUpdated();
}
function getIdFromUrl(url) {
return url.match(/[-\w]{25,}/);
}
Also, my appscript.json looks like this:
{
"timeZone": "Asia/Kolkata",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.readonly",
"https://www.googleapis.com/auth/userinfo.email"
]
}
Is there a way I can resolve this. Or any other easier way to get last updated date of a file in google drive?
Custom functions are not applicable to your use case as they can only call services that do not require access to personal data. See GAS documentation on custom functions
If your custom function throws the error message You do not have
permission to call X service., the service requires user authorization
and thus cannot be used in a custom function.

API Download File from BIM360 Doc Plans folder

I am trying to download file from Autodesk BIM360 Doc (https://docs.b360.autodesk.com) with the Forge API so the files can be then afterward archieved to our local storage.
I have managed to download any files from "Project Files" folder using the data management API https://forge.autodesk.com/en/docs/data/v2/reference/http/projects-project_id-versions-version_id-GET/, with which i can get the storage id under data.relationships.storage.data.id.
however with the same API i cannot get the storage Id when querying files under "Plan" folder,
So is there any way with Forge API we can download a file from Plan folder? any help is appreciated.
The item listed in the Plan folder is a type of items:autodesk.bim360:Document, this type item won't have storage attribute shown in its responses of GET versions/:version_id and GET items/:item_id directly.
To obtain the physical file location, you should call GET versions/:version_id/relationships/refs instead, see here for the similar thread: Download a Document with Autodesk API
Update for copied item
While accessing the relationship data of version of the copied item via GET versions/:version_id/relationships/refs, you would see a data attribute telling the relationship between the copied item and the source item with my experience:
"data": [
{
"type": "versions",
"id": "urn:adsk.wipprod:fs.file:vf.34Xvlw1jTcSQ_XkIVh07cg?version=2",
"meta": {
"refType": "derived",
"fromId": "urn:adsk.wipprod:fs.file:vf.34Xvlw1jTcSQ_XkIVh07cg?version=2",
"fromType": "versions",
"toId": "urn:adsk.wipprod:fs.file:vf.y3L7YbfAQJWwumMgqjJUxg?version=1",
"toType": "versions",
"direction": "to",
"extension": {
"type": "derived:autodesk.bim360:CopyDocument",
"version": "1.0",
"schema": {
"href": "https://developer.api.autodesk.com/schema/v1/versions/derived:autodesk.bim360:CopyDocument-1.0"
},
"data": {}
}
}
}
],
Afterward, you have to access the version relationship dat of the fromId via calling GET versions/:version_id/relationships/refs.
In this case, it's {PROJ_ID}/versions/urn:adsk.wipprod:fs.file:vf.34Xvlw1jTcSQ_XkIVh07cg%3Fversion=2/relationships/refs, then you will see the storage attribute inside the response with my investigation.
Just in case anyone else run into the same issue, i post my code with which i finally managed to get the file storage information. However please feel free to suggest other approaches than iteration to the full relationship trees.
internal static ForgeFileInfo getItemVersion(string token, string projectID, string versionID)
{
ForgeFileInfo forgeFileInfo = new ForgeFileInfo();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
versionApi.Configuration.AccessToken = token;
var version = versionApi.GetVersion(projectID, versionID);
string fileType = version.data.attributes.extension.type;
switch (fileType) {
case "versions:autodesk.bim360:File":
//File from Project File library or is regual file
forgeFileInfo.FileName = version.data.attributes.displayName;
forgeFileInfo.FileLocation = version.data.relationships.storage.meta.link.href;
forgeFileInfo.StorageId = version.data.relationships.storage.data.id;
return forgeFileInfo;
case "versions:autodesk.bim360:Document":
//File from Plan Library
var versionRelationship=versionApi.GetVersionRelationshipsRefs(projectID, versionID);
// the GET Relationship has data node where we can get the related document
var relationshipData = new DynamicDictionaryItems(versionRelationship.data);
// let's start iterating the relationship DATA
foreach (KeyValuePair<string, dynamic> relationshipItem in relationshipData)
{
//Have to loop until we found "derived:autodesk.bim360:FileToDocument"
var relationType = relationshipItem.Value.meta.extension.type;
var relation = relationshipItem.Value.meta.direction;
if ("derived:autodesk.bim360:FileToDocument".Equals(relationType))
{
if ("to".Equals(relation))
{
//Go up stream
return getItemVersion(token, projectID, relationshipItem.Value.id);
}
}
else if ("derived:autodesk.bim360:CopyDocument".Equals(relationType))
{
if ("to".Equals(relation))
{
//Go up stream
return getItemVersion(token, projectID, relationshipItem.Value.id);
}
continue;
}
}
break;
}
return forgeFileInfo;
}

GSuite Admin SDK > Directory API: How do I add values to a custom schema for a user?

We are setting up some automation around SSO into AWS, but I have run into a problem.
There is a custom user attribute called AWSLab, and if a user does not have any IAMRole values populated for this attribute, then I need to add one.
The IAMRole field has Info type set to Text and No. of values set to Multi-value on the GSuite side, so I am putting it into an array for this API request.
Also, when I do a GET on the user and look at other schemas attached, I see this key named type set to work so I include that too.
Below is my function in Google Apps Script:
function check_user_access(){
var email = 'user#domain.com';
var role = [
'arn:aws:iam::123456789012:role/User',
'arn:aws:iam::123456789012:saml-provider/GoogleAppsProvider'
].join(',')
optArgs = {
projection: "full"
}
var user = AdminDirectory.Users.get(email, optArgs)
var schema = user.customSchemas
Logger.log("typeof(schema): %s", typeof(schema))
if(schema["AWSLab"]) {
Logger.log("schema[\"AWSLab\"] found on user '%s': %s", email, schema["AWSLab"])
} else {
Logger.log("schema[\"AWSLab\"] not found! Updating...")
Logger.log("schema before:\n\n%s\n", JSON.stringify(schema))
schema["AWSLab"] = { "IAMRole": [{ "type": "work", "value": role }] }
Logger.log("schema after:\n\n%s\n", JSON.stringify(schema))
AdminDirectory.Users.update(userFull, email) // line 35
}
}
When this function runs, I see this error:
Invalid Input: [AWSLab] (line 35, file "Labs")
I have some extra lines in there right now, to output some details for troubleshooting, but it's not helping me see the problem.
As it turns out, the issue was with the name of the custom schema.
At creation, the schema had a different name which was then edited at some point.
The key to figuring this out was populating the schema fields in question on a user with some dummy data, then pulling the user out via the API with a GET and examining the JSON.

Not getting Authorization dialog for App Script accessing BigQuery Service

I am trying to fix some App Scripts which use the BigQuery "Advanced Service" to install some BigQuery jobs. The first new script I ran popped a BigQuery authorization dialog, and everything worked fine, now running hourly. The second new script ran initially, but is now failing with:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Login Required",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Login Required"
}
}
This began about 12 hours after the initial authorization, so it seems like something expired. But, I can't figure out how to trigger the authorization dialog to appear. Also, I expected an authorization would be required for each distinct function, yet the second one initially ran without asking for BigQuery permissions.
Additional Info:
Here is the .gs file I am executing:
function runQuery() {
var projectId = redacted;
var configuration = {
"query": {
"useQueryCache": false,
"destinationTable": {
"projectId": projectId,
"datasetId": redacted,
"tableId": redacted
},
"writeDisposition": "WRITE_TRUNCATE",
"createDisposition": "CREATE_IF_NEEDED",
"allowLargeResults": true,
"query": redacted
}
};
var job = {
"configuration": configuration
};
var jobResult = BigQuery.Jobs.insert(job, projectId);
var jobId = jobResult.jobReference.jobId;
Logger.log(jobResult);
}
The first time I ran a very similar query, I got a dialog prompting me for BigQuery permissions, as documented here:
https://developers.google.com/apps-script/guides/services/authorization
I subsequently ran this same script successfully (with slightly different query config). But, then, about 12 hours after first run, I started getting the authorization return quoted above. I thought it might refresh with time, but still get same failure.
Turns out this has been working all along. The authorization error was being generated by my attempt to look at the job results, not by the job itself. Doh!