GAS adding a non domain member to google group doesnt work - google-apps-script

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.

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'
});

How to change course owner using Classroom.Courses.patch()

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.

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.

Get reviews from google map api

I have to get reviews from Google map API. details are on this page.
https://developers.google.com/places/documentation/details#PlaceDetailsResults
the details will fetch from this page:-
https://maps.googleapis.com/maps/api/place/details/json?reference=CmRYAAAAciqGsTRX1mXRvuXSH2ErwW-jCINE1aLiwP64MCWDN5vkXvXoQGPKldMfmdGyqWSpm7BEYCgDm-iv7Kc2PF7QA7brMAwBbAcqMr5i1f4PwTpaovIZjysCEZTry8Ez30wpEhCNCXpynextCld2EBsDkRKsGhSLayuRyFsex6JA6NPh9dyupoTH3g&sensor=true&key=AddYourOwnKeyHere
My problem is I can't find what is reference in request. and how I find this parameter value from my Google plus page.
A more recent way to do this:
https://maps.googleapis.com/maps/api/place/details/json?placeid={place_id}&key={api_key}
place_id: https://developers.google.com/places/place-id
api_key: https://developers.google.com/places/web-service/get-api-key
Response:
{
"html_attributions": [],
"result": {
...
"rating": 4.6,
"reviews": [
{
"author_name": "John Smith",
"author_url": "https://www.google.com/maps/contrib/106615704148318066456/reviews",
"language": "en",
"profile_photo_url": "https://lh4.googleusercontent.com/-2t1b0vo3t-Y/AAAAAAAAAAI/AAAAAAAAAHA/0TUB0z30s-U/s150-c0x00000000-cc-rp-mo/photo.jpg",
"rating": 5,
"relative_time_description": "in the last week",
"text": "Great time! 5 stars!",
"time": 1508340655
}
]
}
}
Reviews are limited to the 5 latest.
For fetching a google review you need reference id for the place.In order to get this reference key you can use google places search api request.
https://maps.googleapis.com/maps/api/place/textsearch/xml?query=restaurants+in+bangalore&sensor=true&key=AddYourOwnKeyHere
Its response will have reference id which you can use in your request.
<PlaceSearchResponse>
<status>OK</status>
<result>
<name>Koshy's Restaurant</name>
<type>bar</type>
<type>restaurant</type>
<type>food</type>
<type>establishment</type>
<formatted_address>
39, St Marks Road,Shivajinagar,Bangalore, Karnataka, 560001, India
</formatted_address>
<geometry>
<rating>3.7</rating>
<icon>
http://maps.gstatic.com/mapfiles/place_api/icons/bar-71.png
</icon>
**<reference>**
CnRwAAAA1z8aCeII_F2wIVcCnDVPQHQi5zdd-3FsDl6Xhb_16OGrILvvvI4X4M8bFk2U8YvuDCKcFBn_a2rjvYDtvUZJrHykDAntE48L5UX9hUy71Z4n80cO7ve_JXww6zUkoisfFnu6jEHcnKeeTUE42PCA4BIQGhGz0VrXWbADarhKwCQnKhoUOR-Xa9R6Skl0TZmOI4seqt8rO8I
**</reference>**
<id>2730db556ca6707ef517e5c165adda05d2395b90</id>
<opening_hours>
<open_now>true</open_now>
</opening_hours>
<html_attribution>
Ujaval Gandhi
</html_attribution>
</photo>
</result>
$reqUri = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?key='.YOURSERVERKEY;
$reqUri .= '&sensor=false&radius=500';
$reqUri .= '&location=38.908310,-104.784035&name='.urlencode(LOCATION NAME);
$reqUri .= '&keyword='.urlencode(WEBSITE PHONE);
I made it through PHP, Now call like this URL and you get original result with reference key.
Then parse it like:
$data = cURL($reqUri);
$data = json_decode($data);
echo $data ->results[0]->reference;
Hope it will help you
***Note: location=38.908310,-104.784035 this var is not auto you must have it.
Using Python and Google Places APIs, you can retrieve business details and reviews (up to 5 reviews) as follows:
api = GooglePlaces("Your API key")
places = api.search_places_by_coordinate("40.819057,-73.914048", "100", "restaurant")
for place in places:
details = api.get_place_setails(place['place_id'], fields)
try:
website = details['result']['website']
except KeyError:
website = ""
try:
name = details['result']['name']
except KeyError:
name = ""
try:
address = details['result']['formatted_address']
except KeyError:
address = ""
try:
phone_number = details['result']['international_phone_number']
except KeyError:
phone_number = ""
try:
reviews = details['result']['reviews']
except KeyError:
reviews = []
print("===================PLACE===================")
print("Name:", name)
print("Website:", website)
print("Address:", address)
print("Phone Number", phone_number)
print("==================REVIEWS==================")
for review in reviews:
author_name = review['author_name']
rating = review['rating']
text = review['text']
time = review['relative_time_description']
profile_photo = review['profile_photo_url']
print("Author Name:", author_name)
print("Rating:", rating)
print("Text:", text)
print("Time:", time)
print("Profile photo:", profile_photo)
print("-----------------------------------------")
For more details about this code and Google Places API, you can check this tutorial: https://python.gotrained.com/google-places-api-extracting-location-data-reviews/
I had problems making it work on localhost. I added my example.com.test domain, but of course I could not verify it, because it cannot be reached from outside (except ngrok variant).
I found an amazing dirty hack on GitHub: gaffling/PHP-Grab-Google-Reviews.
Worked great for me, except I had to change the /* CHECK SORT */ line to if (isset($option['sort_by_reating_best_1']) and $option['sort_by_reating_best_1'] == true) and I also limited the foreach to only 5 reviews via optional second function parameter.
No API_KEY required at all