How to change course owner using Classroom.Courses.patch() - google-apps-script

I'm trying to use Apps Script to change the owner of a Google Classroom course.
According to the documentation I can do it using .patch(). This is the relevant script:
var body = {
ownerId: owner
}
var mask={
mask:'ownerId'
}
var optArgs = (mask, body);
var course = {
name: classname,
courseState: state,
description: desc,
descriptionHeading: descHead,
room: room,
section: section
};
Classroom.Courses.patch(course, courseId, optArgs )
When I run it to update the owner I get the following error message
Could not be updated Invalid JSON payload received. Unknown name "ownerId": Cannot bind query parameter. Field 'ownerId' could not be found in request message.
Just to demonstrate a contrast, when I run .update() instead:
Classroom.Courses.update(course, courseId)
...the rest of the course details are updated perfectly, however .update() doesn't allow you to change the owner; it has to be a .patch() to do that.

Just had the same problem, the issue is the optArgs - you just want the mask in there, not your changed data.
var optArgs = { mask: 'ownerId' };
var course = {
name: classname,
courseState: state,
description: desc,
descriptionHeading: descHead,
room: room,
section: section,
ownerId: owner
};
Classroom.Courses.patch(course, courseId, optArgs );

I just tried this a few moments ago and it worked. Take into account that, for this to work, the user must already be a teacher in the specific class, and then this will make that teacher the owner.
function changeTeacherOwner() {
var course = { 'ownerId': "EMAIL OF TEACHER" };
Classroom.Courses.patch(course, "COURSE ID", {'updateMask':'ownerId'});
}

Based on documentation, this is working as intended.
courses.update has no ownerId parameters, only id.
But if you check courses.patch it has the updateMask parameter which accepts ownerId as a valid field.
For detailed information on this service, see the reference documentation for the Classroom API.

Related

Added spaces and LRs in JSON via Appmaker

I'm working in AppMaker to create a new employee/user provisioning workflow. I'm at the point where I am creating a new G Suite user, and I have a very weird problem with spaces in my JSON. It's leading to an error: GoogleJsonResponseException: API call to directory.users.insert failed with error:
Invalid Input at provisionUser (AdminDirectory:5)
I've been troubleshooting this for a while, and it seems that somewhere between AppMaker and the AdminDirectory call, some extra spaces and hard returns are inserted into my user data. Below I'm going to show:
The client-side code for gathering user information
The server-side user creation script
The console output of the user JSON
The output of the user JSON that comes to my email for troubleshooting
The emailed output as seen in Notepad++
Client-Side Code
...a bunch of data gathering from a form, then...
var user = {
primaryEmail: email,
name: {
givenName: firstName,
familyName: lastName
},
addresses: [{
type: 'work',
formatted: address
}],
organizations: [{
title: title,
department: department,
fullTimeEquivalent: ftpt
}],
phones: [{
type: 'work',
value: phone
}],
locations: [{
buildingId: building,
type: 'desk',
area: 'desk'
}],
password: 'xxxxxxxx',
changePasswordAtNextLogin: true,
orgUnitPath: orgUnit,
relations: [{
type: 'manager',
value: supervisor
}],
customSchemas: {
sclsnj: {
startDate: effective,
mls: mls,
location: location
}
}
};
google.script.run.provisionUser(user, grouparray);
Server-Side Code
function provisionUser(user, grouparray) {
user = JSON.stringify(user);
MailApp.sendEmail('lhoffman#xxxxxxxx.org', 'New Google User', user);
console.log(user);
user = AdminDirectory.Users.insert(user);
for (var g = 0; g < grouparray.length; g++) {
var groupEmail = grouparray[g] + '#xxxxxxxx.org';
var member = {
email: user,
role: 'MEMBER'
};
Logger.log(groupEmail);
AdminDirectory.Members.insert(member, groupEmail);
}
}
Console Output
{"primaryEmail":"jsmith#xxxxxxxx.org","name":{"givenName":"John","familyName":"Smith"},"addresses":[{"type":"work","formatted":"Bound Brook branch\n402 E High Street, Bound Brook, NJ 08805"}],"organizations":[{"title":"Library Technician","department":"Adult Services","fullTimeEquivalent":100000}],"phones":[{"type":"work","value":"908-458-8410"}],"locations":[{"buildingId":"BBROOK","type":"desk","area":"desk"}],"password":"xxxxxxxx","changePasswordAtNextLogin":true,"orgUnitPath":"/Branches/Bound Brook branch","relations":[{"type":"manager","value":"msmith#xxxxxxxx.org"}],"customSchemas":{"sclsnj":{"startDate":"2019-05-20T04:00:00.000Z","mls":false,"location":"Bound Brook branch"}}}
Email Output
{"primaryEmail":"jsmith#xxxxxxxx.org","name":{"givenName":"John","familyName":"Smith"},"addresses":[{"type":"work","formatted":"Bound
Brook
branch\n402 E High Street, Bound Brook, NJ
08805"}],"organizations":[{"title":"Library Technician","department":"Adult
Services","fullTimeEquivalent":100000}],"phones":[{"type":"work","value":"908-458-8410"}],"locations":[{"buildingId":"BBROOK","type":"desk","area":"desk"}],"password":"xxxxxxxx","changePasswordAtNextLogin":true,"orgUnitPath":"/Branches/Bound
Brook
branch","relations":[{"type":"manager","value":"msmith#xxxxxxxx.org"}],"customSchemas":{"sclsnj":{"startDate":"2019-05-20T04:00:00.000Z","mls":false,"location":"Bound
Brook branch"}}}
Email Output in Notepad++ (with control characters)
NOTE: I realize the JSON is actually represented in the image twice, but you can definitely see the extra space and left feed characters there.
I've confirmed that I can provision a user with the console output by using the Google API Explorer and copying and pasting it into the request body for the Directory API Users.insert.
I've also confirmed that the emailed version of the output does not work using the same method. When I paste that version into the request body in the API Explorer, I get an error alert and it's clear from the color-coding in the body field that it is not correct. Even when I don't email the output to myself, I get the same error behavior, so I'm pretty sure that the act of emailing isn't messing things up.
Help!!
The invalid input is a result of a specific field not correclty formatted. In your case, I see that you are using custom schemas. There is a specific filed in the custom schema that is not properly formatted, that is startDate. Instead of providing the value of 2019-05-20T04:00:00.000Z, just use 2019-05-20.
The reason for that is because the field is expecting a complete date only value instead of a complete date plus hours and minutes. As you can see on the ISO-8601 date format, the complete date format is YYYY-MM-DD.
Reference: https://developers.google.com/admin-sdk/directory/v1/reference/schemas/insert
What happens if you do it this way?
function provisionUser(user, grouparray) {
var user = JSON.stringify(user);
MailApp.sendEmail('lhoffman#xxxxxxxx.org', 'New Google User', user);
console.log(user);
AdminDirectory.Users.insert(user);
for (var g = 0; g < grouparray.length; g++) {
var groupEmail = grouparray[g] + '#xxxxxxxx.org';
var member = {
email: user,
role: 'MEMBER'
};
Logger.log(groupEmail);
AdminDirectory.Members.insert(member, groupEmail);
}
}

Retrieve custom attribute from user profile in Google API Scripts- Google Admin Directory

This is about G suite users.The following works in Google Admin Directory using Google Admin SDK. It retrieves email address and full name of user.
var myemail = Session.getActiveUser().getEmail();
var mycontact = AdminDirectory.Users.get(myemail);
var myname = mycontact.name.fullName;
There is a custom attribute in user profile named "Department". The following does NOT retrieve anything. It throws null
var mydept = mycontact.Department;
How can one retrieve custom attribute from user profile in G suite?
According to Directory Api - Users: get you need to set the projection to "custom".
projection - What subset of fields to fetch for this user.
Acceptable values are:
"basic": Do not include any custom fields for the user. (default)
"custom": Include custom fields from schemas requested in customFieldMask.
"full": Include all fields associated with this user.
Then you should define a Schema for the custom data
customFieldMask (string) A comma-separated list of schema names. All fields from these schemas are fetched. This should only be set when projection=custom.
So something like:
var mycontact = AdminDirectory.Users.get({
"userKey": myemail,
"projection": "full",
"customFieldMask": "Define Schema Here"
});
You can then Logger.log(mycontact); to see how to access the returned custom fields
For a custom schema, you can just use the full projection to get all custom schema fields.
For the standard department field, see user.organizations[0].department
https://developers.google.com/admin-sdk/directory/v1/reference/users
If you got an error :
Resource Not Found: userKey
Try this :
mycontact = AdminDirectory.Users.get(
myemail,{
projection: 'full'
});

GAS adding a non domain member to google group doesnt work

I'd like to create a spreadsheet to let user create his own google groups for mailing list purpose.
I can add domain's member to grups with this code:
function addGroupMember (groupEmail, userEmail,ruolo) {
var member = {
email: userEmail,
role: ruolo
};
try {
member = AdminDirectory.Members.insert(member, groupEmail);
Logger.log('User %s added as a member of group %s.', userEmail, groupEmail);
}catch(e){
Logger.log("adding in:" + groupEmail + " failed user email: "+ userEmail + " role: " + ruolo + " error:" + e);
}
But if i try to add a non domain's user (i can do it in group management) it fails with this error:
[16-08-12 14:54:13:113 CEST] adding in: mygropu#mydomain.it failed user e mail: user#otherdomanin.it role: MEMBER error: Exception: Invalid Input: memberKey
As the error log shows exception Invalid Input: memberKey, it means that you may not able to give the real memberKey/ authentic memberKey. memberKey is the user's or group priary email address, user's alias email address or the user's unique id
To get the memberKey, you can use the Members:get to retrieves a group members properties.
HTTP request:
GET https://www.googleapis.com/admin/directory/v1/groups/groupKey/members/memberKey
Response:
{
"kind": "admin#directory#member",
"etag": etag,
"id": string,
"email": string,
"role": string,
"type": string
}
id is the unique ID of the group member. A member id can be used as a member request URI's memberKEy
I made some test more, and found the clue!
The Exception: "Resource Not Found: email#otherdomain.com" rises up when the otherdomain is gmail.com and the mail address does not exist.
Using any other domain works even for non existent addresses! I think that G.A.S. checks only for his own domain addresses, but can't do it for other domains.

Node.js JSON extract certain data

I'm trying to get certain data from a json link:
bittrex.com/api/v1.1/public/getticker?market=BTC-DRS
in my node IRC bot using:
https://www.npmjs.org/package/node.bittrex.api
Part of the code:
var url = ('https://bittrex.com/api/v1.1/public/getticker?market=BTC-DRS');
bittrex.options({
'apikey' : settings.ticker.apikey,
'apisecret' : settings.ticker.secretkey,
'stream' : false,
'verbose' : false,
'cleartext' : true,
});
case 'ticker':
var user = from.toLowerCase();
bittrex.sendCustomRequest(url, function(ticker, err) {
if(err) {
winston.error('Error in !ticker command.', err);
client.say(channel, settings.messages.error.expand({name: from}));
return;
}
winston.info('Fetched Price From BitTrex', ticker);
client.say(channel, settings.messages.ticker.expand({name: user, price: ticker}));
});
break;
It works but outputs in IRC
[1:21am] <nrpatten> !ticker
[1:21am] <DRSTipbot> nrpatten The current DRS price at BitTrex {"success":true,"message":"","result":{"Bid":0.00000155,"Ask":0.00000164,"Last":0.00000155}}
I have used a couple of things to get it to show only "Last" from the reply but i keep getting errors.
Or get certain data from https://bittrex.com/api/v1.1/public/getmarketsummaries
Like any info i want from:
{"MarketName":"BTC-DRS","High":0.00000161,"Low":0.00000063,"Volume":280917.11022708,"Last":0.00000155,"BaseVolume":0.33696054,"TimeStamp":"2014-10-04T15:14:19.66","Bid":0.00000155,"Ask":0.00000164,"OpenBuyOrders":33,"OpenSellOrders":138,"PrevDay":0.00000090,"Created":"2014-06-18T04:35:38.437"}
Thanks for any help
Assuming you've parsed the JSON (e.g. via JSON.parse(str);), you just use whatever property name you want to get at. For example:
var info = JSON.parse('{"MarketName":"BTC-DRS","High":0.00000161,"Low":0.00000063,"Volume":280917.11022708,"Last":0.00000155,"BaseVolume":0.33696054,"TimeStamp":"2014-10-04T15:14:19.66","Bid":0.00000155,"Ask":0.00000164,"OpenBuyOrders":33,"OpenSellOrders":138,"PrevDay":0.00000090,"Created":"2014-06-18T04:35:38.437"}');
console.log(info.Bid);
Also, on an unrelated matter, typically callback parameters follow the error-first format (e.g. (err, result) instead of (result, err)) in order to be consistent with node core and most other modules on npm.

Make dynamic name text field in Postman

I'm using Postman to make REST API calls to a server. I want to make the name field dynamic so I can run the request with a unique name every time.
{
"location":
{
"name": "Testuser2", // this should be unique, eg. Testuser3, Testuser4, etc
"branding_domain_id": "52f9f8e2-72b7-0029-2dfa-84729e59dfee",
"parent_id": "52f9f8e2-731f-b2e1-2dfa-e901218d03d9"
}
}
In Postman you want to use Dynamic Variables.
The JSON you post would look like this:
{
"location":
{
"name": "{{$guid}}",
"branding_domain_id": "52f9f8e2-72b7-0029-2dfa-84729e59dfee",
"parent_id": "52f9f8e2-731f-b2e1-2dfa-e901218d03d9"
}
}
Note that this will give you a GUID (you also have the option to use ints or timestamps) and I'm not currently aware of a way to inject strings (say, from a test file or a data generation utility).
In Postman you can pass random integer which ranges from 0 to 1000, in your data you can use it as
{
"location":
{
"name": "Testuser{{$randomInt}}",
"branding_domain_id": "52f9f8e2-72b7-0029-2dfa-84729e59dfee",
"parent_id": "52f9f8e2-731f-b2e1-2dfa-e901218d03d9"
}
}
Just my 5 cents to this matter. When using randomInt there is always a chance that the number might eventually be present in the DB which can cause issues.
Solution (for me at least) is to use $timestamp instead.
Example:
{
"username": "test{{$timestamp}}",
"password": "test"
}
For anyone who's about to downvote me this post was made before the discussion in comments with the OP (see below). I'm leaving it in place so the comment from the OP which eventually described what he needs isn't removed from the question.
From what I understand you're looking for, here's a basic solution. It's assuming that:
you're developing some kind of script where you need test data
the name field should be unique each time it's run
If your question was more specific then I'd be able to give you a more specific answer, but this is the best I can do from what's there right now.
var counter = location.hash ? parseInt(location.hash.slice(1)) : 1; // get a unique counter from the URL
var unique_name = 'Testuser' + counter; // create a unique name
location.hash = ++counter; // increase the counter by 1
You can forcibly change the counter by looking in the address bar and changing the URL from ending in #1 to #5, etc.
You can then use the variable name when you build your object:
var location = {
name: unique_name,
branding_domain_id: 'however-you-currently-get-it',
parent_id: 'however-you-currently-get-it'
};
Add the below text in pre-req:
var myUUID = require('uuid').v4();
pm.environment.set('myUUID', myUUID);
and use the myUUID wherever you want
like
name: "{{myUUID}}"
It will generate a random unique GUID for every request
var uuid = require('uuid');
pm.globals.set('unique_name', 'testuser' + uuid.v4());
add above code to the pre-request tab.
this was you can reuse the unique name for subsequent api calls.
Dynamic variable like randomInt, or guid is dynamic ie : you donot know what was send in the request. there is no way to refer it again, unless it is send back in response. even if you store it in a variable,it will still be dynamic
another way is :
var allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var shuffled_unique_str = allowed.split('').sort(function(){return 0.5-Math.random()}).join('');
courtsey refer this link for more options