Use appscript to track user installs of google marketplace app - google-apps-script

We've developed a Google Marketplace app using AppsScript which we've now made live on the marketplace (https://workspace.google.com/marketplace/app/report_connector_for_salesforce_beta/977246938879). However, we're struggling to work out how to use the Google Marketplace API (https://developers.google.com/workspace/marketplace/example-calls-marketplace-api) to access the license data. Has anyone else successfully managed this?
Has anyone else managed to get this working? It would be great if there was an app for this by the way on the marketplace!
Many thanks
Andy
So far, we've created a separate Google Sheet (in the same domain as our app), and we've written a simple API call function as follows:
function getUsers() {
const options = {
muteHttpExceptions: true,
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
}
};
let response = UrlFetchApp.fetch("https://appsmarket.googleapis.com/appsmarket/v2/licenseNotification/<our app Id>",options);
Logger.log("Refresh Response:"+response);
}
We've created a new project in the GCP, and have enabled:
Google Workspace Marketplace API
Google Workspace Marketplace SDK
We've added the following scopes to the project:
Connect to an external service https://www.googleapis.com/auth/script.external_request
View your installed application's licensing information https://www.googleapis.com/auth/appsmarketplace.license
But, when we run the code, we just keep getting the following:
Info Refresh Response:{
"error": {
"code": 403,
"message": "Not authorized to access the application ID",
"errors": [
{
"message": "Not authorized to access the application ID",
"domain": "global",
"reason": "forbidden"
}
]
}
}

This worked for me, but I needed to add "https://*.googleapis.com/" in the urlFetchWhitelist.
Is your App Id correct? Check it out at https://console.cloud.google.com/apis/api/appsmarket-component.googleapis.com/googleapps_sdk?project=*projectName*

Related

403 error when attempting to fetch google analytics 4 data from app script

I am attempting to connect a custom community connector to google analytics 4 in order to get data from analytics and be able to modify it in app script and then send it to data studio. However I am having difficulty connecting and retrieving data from google analytics.
The error:
{ error:
{ code: 403,
message: 'Google Analytics Data API has not been used in project 640397821842 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/analyticsdata.googleapis.com/overview?project=640397821842 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.',
status: 'PERMISSION_DENIED',
details: [ [Object], [Object] ] } }
I have the scopes set up
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/analytics.readonly"
],
The code i am trying to test:
function testFetch(){
const options = {
entry: { propertyId: 263290444},
"dateRanges": [{ "startDate": "2020-12-01", "endDate": "2021-03-01" }],
"dimensions": [{ "name": "country" }],
"metrics": [{ "name": "activeUsers" }],
// etc.
}
var response = UrlFetchApp.fetch(
'https://analyticsdata.googleapis.com/v1alpha:runReport', {
method: 'POST',
muteHttpExceptions: true,
headers: {
Authorization : `Bearer ${ScriptApp.getOAuthToken()}`
},
contentType: 'application/json; charset=utf-8',
payload: JSON.stringify(options)
});
var result = JSON.parse(response.getContentText());
console.log(result);
'Google Analytics Data API has not been used in project 640397821842 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/analyticsdata.googleapis.com/overview?project=640397821842 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.',
status:
The problem you are having is that you have not enabled the API in Google developer console You need to follow the link in the error message then go to library and look for Google analytics data api and enable it.
Once you have enabled it try and run your application again.
For those with the same issue who may have overlooked some steps:
Create an API project at https://console.cloud.google.com/
Make sure to connect your appscript project to your cloud API project by changing the Google Cloud Platform (GCP) Project in appscript settings (It is set to a default project when you start).
Enable the required APIs from the API Library in the cloud project.
Now you will be able to fetchurls related to the APIs you have enabled.

Using custom libraries from apps script in App Maker: Authorization problem

I am using this code in Apps script
function getUserObjByEmail(email){
// Same as using AdminDirectory class.
var apiUrl = "https://www.googleapis.com/admin/directory/v1/users/"+email+"?fields=id";
var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method": "GET",
"headers": header
};
var response = JSON.parse(UrlFetchApp.fetch(apiUrl, options));
return response;
}
which I run as a function from App Maker project. Things go smoothly when I use the app since I have an admin role( I guess, not sure ) but the problem arises when other normal users in our domain start using the deployed app maker app. I checked the server logs and its full of this message:
Exception: Request failed for
https://www.googleapis.com/admin/directory/v1/users/email#domain.com?fields=id
returned code 403.
Truncated server response: { "error": { "errors": [ { "domain": "global",
"reason": "forbidden", "message": "Not Authorized to access this
resource/api" ... (use muteHttpExceptions option to examine full response)
Any idea how to fix this? I have manually added the required scopes for the apps script library, I added the following:
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/admin.directory.user"
The reason this happens is because YOU have admin rights, otherwise you'd be getting the same error message. The other users don't have admin rights hence they get the error. To solve this problem, you can either deploy the application running it as the developer or you can use a service account to impersonate an admin and do the process.
Regarding the first approach, you can find more info here https://developers.google.com/appmaker/security/identity.
Regarding the second approach, you can use the following app script library https://github.com/gsuitedevs/apps-script-oauth2#using-service-accounts
Moreover, if you do not require to get custom schemas information, then you can simply use a directory model and that should work for all users. Check the reference here: https://developers.google.com/appmaker/models/directory

How can I trigger a Google Apps Script function from the Google API PHP Client with the authentication I have set already?

I'm struggling to trigger a Google Apps Script Function which builds many dropdowns of a Google Spreadsheet.
I need this data to be updated daily on this Google Spreadsheet so I must call the function.
Seems like I'm required to have a client-side authentication which I'm reluctant to force it to happen.
I have set already the Google API PHP Client which does batch updates, get requests and control users and its roles.
Here's how the code looks like:
public function updateTemplate ()
{
$client = $this->getClient();
$service = new Google_Service_Script($client);
$scriptId = $this->gScriptId;
// Create an execution request object.
$request = new Google_Service_Script_ExecutionRequest();
$request->setFunction('SetUpNewSpreadsheet');
try {
// Make the API request.
$response = $service->scripts->run($scriptId, $request);
echo "here<pre>";
print_r($response);
exit;
I'm getting the following response error:
Caught exception: {
"error": {
"code": 401,
"message": "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.",
"errors": [ {
"message": "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.",
"domain": "global",
"reason": "unauthorized"
} ]
, "status": "UNAUTHENTICATED"
}
}
I've checked the message errors and docs already. I'm wondering if maybe I'm missing something or if I can find a way to execute that request without forcing a client-side login?
Has anyone been through it?

File not found error Google Drive API

I am using the Drive REST API to download a file. I am making a GET request using the file id and I get a file not found exception.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "File not found: xxxxx",
"locationType": "other",
"location": "file"
}
],
"code": 404,
"message": "File not found: xxxxx"
}
}
I have also generated the apikey and I am using it in my GET request.The file does exist so I am unsure what I am missing here.
Make sure scopes are corrects
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: ['https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.metadata'
]
});
Drive API declares the following scopes. Select which ones you want to grant to APIs Explorer.
https://www.googleapis.com/auth/drive
View and manage the files in your Google Drive
https://www.googleapis.com/auth/drive.appdata
View and manage its own configuration data in your Google Drive
https://www.googleapis.com/auth/drive.file
View and manage Google Drive files and folders that you have opened or created with this app
https://www.googleapis.com/auth/drive.metadata
View and manage metadata of files in your Google Drive
https://www.googleapis.com/auth/drive.metadata.readonly
View metadata for files in your Google Drive
https://www.googleapis.com/auth/drive.photos.readonly
View the photos, videos and albums in your Google Photos
https://www.googleapis.com/auth/drive.readonly
View the files in your Google Drive
https://www.googleapis.com/auth/drive.scripts
Modify your Google Apps Script scripts' behaviour
Sorce: https://developers.google.com/apis-explorer/#p/drive/v3/drive.files.get
This is resolved. I wasn't providing the correct access_token when making the GET request for file metadata. I regenerated the authorization code, access_token and my code is working now.
In my case, I simply had not given access to the folder to my service account. Simply sharing it via the web interface solved the problem.
What email address to use:
Check the email address of your service account here:
https://console.cloud.google.com/iam-admin/serviceaccounts?project=NAME_OF_PROJECT&supportedpurview=project
The email address will look like this:
name-of-service-account#name-of-project.iam.gserviceaccount.com
I would check to see if the file you are trying to retrieve the metadata for is part of a team drive; if it is then you have to set supportsTeamDrives=True in the request.
If you are getting a response like this:
<HttpError 404 when requesting https://www.googleapis.com/drive/v3/files/REDACTED_FILE_ID/copy?alt=json returned "File not found: REDACTED_FILE_ID.". Details: "[{'domain': 'global', 'reason': 'notFound', 'message': 'File not found: REDACTED_FILE_ID.', 'locationType': 'parameter', 'location': 'fileId'}]">
And the fileId points to a file on a Shared Drive, you'll need to include supportsSharedDrives=true in your request parameters.
Google provides more detail on this in their Implement shared drive support article.
Here's a small example with Python for creating a copy:
googledrive = build('drive', 'v3', credentials=creds)
copy_response = googledrive.files().copy(
fileId=TEMPLATE_SPREADSHEET_ID,
body={
"parents": [
report_folder_id,
],
'title': report_title
},
supportsAllDrives=True
).execute()
In order to run that, you'll want to mix it into the example code from the Python Quickstart for Google Drive API.
I got to this question because I was getting a "File not found" error when using the update method.
I was using this line in Python to execute the method:
files_res.update(fileId=f_id, body={"name": f_name}).execute()
I could list the shared file and its parent fine, but update failed, no matter what the scope with this error:
...
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "File not found: 1YqV...",
"locationType": "parameter",
"location": "fileId"
}
],
"code": 404,
...
I added the supportsAllDrives=True param to the method and it worked:
files_res.update(fileId=f_id, body={"name": f_name}, supportsAllDrives=True).execute()
In my case, I was using the file client_secret.json that I had created with the gmail address I use all the time, but I was creating the credentials with another e-mail.

Chrome Web Store: how to check for Payment with google apps script

We put two Google Apps Script web services succesfully into the chrome web store. One is f.e.
https://chrome.google.com/webstore/detail/aagmbfbgdjhkilafppdjihnafgcahpbc
Now we want to check for Payment like described in
https://developers.google.com/chrome/web-store/docs/check_for_payment?hl=de
But
1. How to get a user ID for the current user (an OpenID URL corresponding to a Google account)
2. How to make a request with the Licensing API
with Google Apps Script code?
Do you just use the verify payment method:
google.payments.inapp.getPurchases({
'success': onLicenseUpdate,
'failure': onLicenseUpdateFail
});
responds with:
{
"response": {
"details": [
{
"kind": "chromewebstore#payment",
"itemId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"sku": "giant_tv",
"createdTime": "1387221267248",
"state": "ACTIVE"
}
]
}
}
https://developer.chrome.com/webstore/payments-iap