Why am I unable to retrieve a list of users when using query to search the orgUnitPath? When I try the same parameters on the Google API Explorer (https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/list) the response returns the expected result of users. However, in my code, the response returned is undefined because the full response does not seem to be pulled. Code.gs for reference:
function myFunction() {
var options = {
domain: schoolDomain, // Google Workspace domain name
query: orgUnitPath='/School Staff',
type: 'all',
maxResults: 5,
orderBy: 'familyName',
viewType: 'admin_view'
};
var response = AdminDirectory.Users.list(options);
console.log(response.users);
}
I'm writing this answer as a community wiki since the solution was provided by the OP in the comments section.
The issue was related to the syntax of the query, when using the query for orgUnitPath, it needs to be inside '' like this:
"orgUnitPath='/School Staff'"
or
'orgUnitPath="/School Staff"'
This information can be found in the Google Documentation here.
Related
ScriptApp.getService().getUrl() is generating a dev URL. How can I make it generate the exec production URL?
How about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
If you are enabling V8 runtime, in the current stage, it seems that when V8 runtime is enabled, ScriptApp.getService().getUrl() returns the dev URL like https://script.google.com/macros/s/###/dev, and when V8 runtime is disabled, it returns the exec URL like https://script.google.com/macros/s/###/exec. I think that this might be one of bugs for V8.
If you want to directly retrieve the exec URL with enabling V8, as the current workaround, how about retrieving it using the method of projects.deployments.list in Apps Script API? You can test it at "Try this API". Of course, this can be used with Google Apps Script.
Reference:
Method: projects.deployments.list
If I misunderstood your situation and this was not the direction you want, I apologize.
For those poor souls that get here, an expansion on J. G.'s comment: confirmed that the result of the getService().getURL() call is dependent on which URL (/exec or /dev) is accessed by the end-user.
There is also an explicit clarification on that (not sure if it was present before) in the method documentation, so it seems to be by-design:
If you are running the development mode web app, this returns the development mode URL.
Note that to get the correct URL you need to use a workaround suggested by Tanaike. When using it, remember that it requires a standard GCP to enable the Apps Script API (technically, you can use a default one for that, but it will only work for G Suite (Google Workspace) accounts with access to system-gsuite/apps-script/ resources).
An implementation of deployment getter would be:
const getDeployments = (options = {}) => {
const {
version = 1,
id = ScriptApp.getScriptId(),
token = ScriptApp.getOAuthToken(),
page = "",
size = 50,
type = "WEB_APP",
} = options;
const uri = `https://script.googleapis.com/v${version}/projects/${id}/deployments`;
const fullURI = `${uri}?pageSize=${size}${page ? `&pageToken=${page}` : ""}`;
const params = {
contentType: "application/json",
headers: {
Authorization: `Bearer ${token}`,
},
muteHttpExceptions: true,
method: "get",
};
const deps = [];
const response = UrlFetchApp.fetch(fullURI, params);
if (response.getResponseCode() !== 200) {
console.log(response.getContentText());
return deps;
}
const { deployments, nextPageToken } = JSON.parse(response.getContentText());
const requested = deployments.filter(({ entryPoints }) =>
entryPoints.some(({ entryPointType }) => entryPointType === type)
);
deps.push(...requested);
if (nextPageToken) {
deps.push(...getDeployments(options));
}
return deps;
};
After a successful response, check the entryPoints collection to get the deployment you need. Each entry point will have a webApp nested object - you are interested in the url property of it.
First timer when it comes to connecting to API. I'm trying to pull data from Toggl using my API token but I can't get credentials working. I tried to replicate the method by Chris Webb (https://blog.crossjoin.co.uk/2014/03/26/working-with-web-services-in-power-query/) but I can't get it working. Here's my M code:
let
Source = Web.Contents(
"https://toggl.com/reports/api/v2/details?workspace_id=xxxxx&client=xxxxxx6&billable=yes&user_agent=xxxxxxx",
[
Query=[ #"filter"="", #"orderBy"=""],
ApiKeyName="api-token"
])
in
Source
After that I'm inputting my API Token into Web API method in Access Web content windows but I get an error that credentials could not be authenticated. Here's Toggl API specification:
https://github.com/toggl/toggl_api_docs/blob/master/reports.md
Web.Contents function receives two parameters: url + options
Inside options, you define the headers and the api_key, and other queryable properties, such as:
let
baseUrl = "https://toggl.com/",
// the token part can vary depending on the requisites of the API
accessToken = "Bearer" & "insert api token here"
options = [
Headers = [Authorization = accessToken, #"Content-Type" =
"application/Json"], RelativePath ="reports/api/v2/details", Query =
[workspace_id=xxxxx, client=xxxxxx6 , billable=yes, user_agent=xxxxxxx]
]
Source = Web.Contents(baseUrl, options)
// since Web.Contents() doesn't parse the binaries it fetches, you must use another
// function to see if the data was retreived, based on the datatype of the data
parsedData = Json.Document(Source)
in
parsedData
The baseUrl is the smallest url that works and never changes;
The RelativePath is the next part of the url before the first "?".
The Query record is where you define all the attributes to query as a record.
This is usually the format, but check the documentation of the API you're querying to see if it is similar.
I am trying to write an Apps Script function to archive a whole bunch of courses in Google Classroom.
function myFunction() {
var response = Classroom.Courses.list();
var optionalArgs = {'courseState': 'ARCHIVED'};
var courses = response.courses;
if (courses && courses.length > 0) {
for (i = 0; i < courses.length; i++) {
var course = courses[i];
Classroom.Courses.update(course.name, course.id, {'updateMask':'courseState'}, body=optionalArgs); // Line 10
//Logger.log('%s (%s) [%s]', course.name, course.id, course.enrollmentCode);
}
}
}
I get the following error when running the above code:
Invalid number of arguments provided. Expected 2-3 only (line 10, file "ArchiveAll")
What is the correct way of doing this with Google Apps Script and the Classroom advanced service?
Based on the code, it looks like you may have previously used the Python client libraries (specifically the body=optionalArgs portion). In JavaScript / Google Apps Script, keyword parameter assignment isn't a thing, at least not like it is in Python.
The format expected by class methods in Google's "Advanced Services" client libraries are derived from the HTTP REST API specification for the associated API. For the Classroom.Courses.update call, this is courses#update (or per your title, courses#patch).
The REST API spec for update is for 1 path parameter (the course id), and a request body with a Course resource. As with all Google APIs, you can additionally add any of the Standard Query Parameters as an optional argument. This count - 2 required, 1 optional) corresponds with the error message you received:
Invalid number of arguments provided. Expected 2-3 only
Thus, your function should be something like:
function updateCourse_(course) {
course.courseState = 'ARCHIVED';
const options = {
fields: "id,name,courseState" // data sent back in the response.
};
return Classroom.Courses.update(course, course.id, options);
}
The patch method has an additional optional argument, the updateMask query parameter. As with other optional parameters (like Standard Query Parameters), this is passed in an object as the last parameter to the class method:
function patchCourse_(courseId) {
const newMetaData = {
courseState: 'ARCHIVED',
// other options, must be valid Course fields per patch documentation:
// https://developers.google.com/classroom/reference/rest/v1/courses/patch#query-parameters
};
const options = {
updateMask: "courseState", // CSV string of things you alter in the metadata object
fields: "id,name,courseState" // data sent back in the response
};
return Classroom.Courses.patch(newMetaData, courseId, options);
}
The updateMask allows you to use some template Course resource and only apply the specified portions of it to a specified course. If you were to use update instead of patch, you would alter all fields to use the template's values:
function patchedViaTemplate_(templateCourse, courseId, fieldsToAlter) {
const options = { updateMask: fieldsToAlter };
return Classroom.Courses.patch(templateCourse, courseId, options);
}
I'm new to Google Apps Scripts and I've been trying to make a simple Get call to a URL. I make this call from my browser: https://accounting.sageone.co.za/api/1.1.1/Supplier/Get?apikey={4CFEEFE1-CE04-425F-82C3-DCB179C817D5}&companyid=164740 and get the respons I'm looking for. I now try to make the call from Google Apps Scripts using the following code:
function myFunction() {
var url = 'https://accounting.sageone.co.za/api/1.1.1/Supplier/Get?apikey={4CFEEFE1-CE04-425F-82C3-DCB179C817D5}&companyid=164740
var response = UrlFetchApp.fetch(url);
Logger.log(response);
}'
I get a respons stating '
Message details
Invalid argument: https://accounting.sageone.co.za/api/1.1.1/Supplier/Get?apikey={4CFEEFE1-CE04-425F-82C3-DCB179C817D5}&companyid=164740 (line 4, file "Code")'
I've tried a whole bunch of permutations with no luck...
When using UrlFetchApp, you need to enter your URL parameters as part of a request parameters rather than in the URL itself. For a GET request these go directy as part of the parameters, for a POST request the parameters would be part of a payload object. Reference Documentation
Here is a modified function:
function myFunction() {
var url = 'https://accounting.sageone.co.za/api/1.1.1/Supplier/Get'
var params = {
"method": 'GET',
"apikey": "{4CFEEFE1-CE04-425F-82C3-DCB179C817D5}",
"companyid": "164740"
}
var response = UrlFetchApp.fetch(url, params);
Logger.log(response)
}
Note: This corrects your method, however, the server still requires further authentication. If you run into issues with that, ask another questions specific to that issue as well.
I'm trying to use Maps API from my mobile application in a similar manner as I can do using my Firefox browser:
http://maps.googleapis.com/maps/api/geocode/json?address=First Avenue New York Manhattan&sensor=true
Unfortunately, I always receive this error result: The 'sensor' parameter specified in the request must be set to either 'true' or 'false'
I tried TRUE, True, true... no way.
I also tried to use my API Key associated to my google account following this guide: https://developers.google.com/maps/documentation/javascript/tutorial?hl=it#api_key
In fact, I did:
http://maps.googleapis.com/maps/api/geocode/json?key={my_key}&address=First Avenue New York Manhattan&sensor=true
So, finally, I suppose my problems are related to the POST Request I prepared.
This is the code I use for my Request:
request = new CIwHTTP; // The http pointer
const char* c1 = text.getCString(); // This is the string "address=First Avenue New York Manhattan&sensor=true"
int length = strlen(c1);
request->SetRequestHeader("Content-Type", "text/javascript; charset=utf-8");
request->Post("http://maps.googleapis.com/maps/api/geocode/json", c1, length, callback, NULL);
In the callback I got my result string, hopefully the JSON string coming from Google telling me the address list. I'm not so sure about the Header, but I changed few of them without results.
I use Marmalade, so my code is fully C++.
Could you help me?
It seems Google doesn't like spaces in the address string and the call should be a GET call.
This is my working code:
CCString gURL = "http://maps.googleapis.com/maps/api/geocode/json?"; // URL base
CCString *string_final = CCString::createWithFormat( (
std::string(gURL.getCString()) +
std::string(text.getCString()) /* i.e. "address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false" */
).c_str() );
request->Get(string_final->getCString(),callback, NULL);