Event Creation impersonation - google-apps-script

Trying to create events using Sheets/Calendar for users in our Workspace
The events must be owned by the user so that they have ownership of the Meet to control access to invitees outside of Google. The user doesn't manage the creation of the event though - this is done by another team
The events can be created easily enough, but not with the ownership. Any way around this?
Using an installable trigger allows the function creating the event to be executed by the user. The problem is two-fold:
the trigger needs to be owned by the user, so onOpen or onEdit, so
the call to the CalendarApp to get the user's calendar fails (see error below)
Exception: The script doesn't have permission to perform that action. Required permission: (https://www.googleapis.com/auth/calendar || https://www.googleapis.com/auth/calendar.readonly || https://www.google.com/calendar/feeds)
minimal reproducible example:
const USER = 'user#domain.co.uk';
const CAL = CalendarApp.getCalendarById(USER);
function createSlots() { // data comes from Sheet
var event = CAL.createEvent(
'slot',
new Date('2022-12-05T12:00Z'),
new Date('2022-12-05T13:00Z'),
{
guests: USER // includes user as a guest to create the Meet code
}
);
}
function makeTrigger() {
var trigger = ScriptApp.newTrigger('createSlots')
.forSpreadsheet(SHEET)
.onOpen()
.create();
}
Strangely - in doing the minimal reproducible example I thought about triggering the function createSlots directly instead of inside another function. This works!
So having the code as the post works, but my original effectively was
const USER = 'user#domain.co.uk';
const CAL = CalendarApp.getCalendarById(USER);
function createSlots() { // data comes from Sheet
var event = CAL.createEvent(
'slot',
new Date('2022-12-05T12:00Z'),
new Date('2022-12-05T13:00Z'),
{
guests: USER // includes user as a guest to create the Meet code
}
);
}
function onOpen() {
createSlots;
}
function makeTrigger() {
var trigger = ScriptApp.newTrigger('onOpen')
.forSpreadsheet(SHEET)
.onOpen()
.create();
}

Yes you can do this. However you will need to use a service account and configure domain wide delegation. This needs to be configured by the domain admin.
Once properly configured the service account will be able to login and impersonate the users on your domain.
setup
In app script under library you will need to include Oauth the script id is 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF.
The service account you created open the credetinals.json file and find the private key and the client email you will needs those in this script.
Note this sample just lists a users primary calendar but i can see that it is listing for different users when i change the delegated user. I assume you can get the rest working you just need the authorization part.
// Oauth script id 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
function run() {
var email = 'XXXX#daimto.com';
var service = getDomainWideDelegationService('Calendar: ', 'https://www.googleapis.com/auth/calendar', email);
if (!service.hasAccess()) {
Logger.log('failed to authenticate as user ' + email);
} else Logger.log('successfully authenticated as user ' + email);
Logger.log('access token ' + service.getAccessToken())
getCalendar(service)
}
function getCalendar(service){
var requestBody = {};
requestBody.headers = {'Authorization': 'Bearer ' + service.getAccessToken()};
requestBody.contentType = "application/json";
requestBody.method = "GET";
requestBody.muteHttpExceptions = false;
var url = 'https://www.googleapis.com/calendar/v3/users/me/calendarList/primary';
var calendarGetResponse = UrlFetchApp.fetch(url, requestBody);
Logger.log('response ' + calendarGetResponse)
}
// these two things are included in the .JSON file that you download when creating the service account and service account key
var OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY = '[REDACTED]';
var OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = '[REDACTED]';
function getDomainWideDelegationService(serviceName, scope, email) {
Logger.log('starting getDomainWideDelegationService for email: ' + email);
return OAuth2.createService(serviceName + email)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY)
.setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(email)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope(scope);
}
The key to the above code is the line .setSubject(email) this is where you define which user the service account is to delegate as.

Related

OAuth2 Library Yields Property Storage Quota Error

I have a script using Google's OAuth2 library, which recently started to fail with the error
You have exceeded the property storage quota. Please remove some properties and try again.
I inspected the properties and did not find any unexpected differences from my original configuration. The full stringified text length of my properties is around 5000 characters, which is well below the 500kB/property store quota and the longest individual property ~2500 characters (below the 9kB/value quota).
I've discovered that this error only occurs when I use Google's OAuth2 library with a service account. However, if I include the library dist directly in my project, the error disappears.
Why is there a difference in how the properties service behaves between the library and the local copy if they appear to be the same versions?
(In other scripts where I use the OAuth2 library with a standard authorization code grant flow, I have no issues.)
This script will replicate the error, but requires that you create a service account and set the correct script properties as defined in getAdminDirectory_(). (Using Rhino interpreter.)
/**
* Get a GSuite User.
*/
function getUser() {
var email = "name#exampledomain.com";
var user = AdminDirectory_getUser_(email);
Logger.log(user);
}
/**
* Gets a user from the GSuite organization by their email address.
* #returns {User} - https://developers.google.com/admin-sdk/directory/v1/reference/users#resource
*/
function AdminDirectory_getUser_(email) {
var service = getAdminDirectory_();
if (service.hasAccess()) {
var url = "https://www.googleapis.com/admin/directory/v1/users/" + email;
var options = {
method: "get",
headers: {
Authorization: "Bearer " + service.getAccessToken()
}
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
return result;
} else {
throw service.getLastError();
}
}
/**
* Configures the service.
*/
function getAdminDirectory_() {
// Get service account from properties
var scriptProperties = PropertiesService.getScriptProperties();
var serviceAccount = JSON.parse(scriptProperties.getProperty("service_account"));
// Email address of the user to impersonate.
var user_email = scriptProperties.getProperty("service_account_user");
return OAuth2.createService("AdminDirectory:" + user_email)
// Set the endpoint URL.
.setTokenUrl("https://oauth2.googleapis.com/token")
// Set the private key and issuer.
.setPrivateKey(serviceAccount.private_key)
.setIssuer(serviceAccount.client_email)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(user_email)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(scriptProperties)
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope("https://www.googleapis.com/auth/admin.directory.user");
}
This seems to be a known issue. Consider adding a star(on top left) to this issue to let Google developers know that you're affected. Consider adding a comment to the tracker with details requested from #7
Possible solutions:
As said in the question, directly use the library code by copy pasting instead of using the buggy library feature.
Switch to v8-#21
Wait for random/Auto resolution -#14

Apps Script bot for webhooks

I'm looking to see if anyone has created a chatbot in google apps script to handle webhooks for hangouts? I have a bot created but I'm not sure on how to input the webhook url into the bots code so that the message can be deployed into the chat room.
I have not exactly created what you are looking for, however I believe the answer you are looking for can be found here. Basically there is an event whenever your bot enters a space. When that event is triggered you can add the space id to a list stored somewhere.(Spreadsheet , PropertiesService,etc)
Once the list is stored you can deploy your application as a web app. You can read more about web apps here but two things you need to know is google gives you a url to make web requests to, as well as pair of events called doGet (when someone makes a get request) and doPost (when someone makes a post request). You can create the function do post and get the parameters when your web app is posted to.
Finally upon receiving the post you can do a fetch call to the google api to post the message you just received from the request to all of the spaces you are in by doing a api fetch call to each ID.
Below will be code directly posted from the API in the first link.
// Example bot for Hangouts Chat that demonstrates bot-initiated messages
// by spamming the user every minute.
//
// This bot makes use of the Apps Script OAuth2 library at:
// https://github.com/googlesamples/apps-script-oauth2
//
// Follow the instructions there to add the library to your script.
// When added to a space, we store the space's ID in ScriptProperties.
function onAddToSpace(e) {
PropertiesService.getScriptProperties()
.setProperty(e.space.name, '');
return {
'text': 'Hi! I\'ll post a message here every minute. ' +
'Please remove me after testing or I\'ll keep spamming you!'
};
}
// When removed from a space, we remove the space's ID from ScriptProperties.
function onRemoveFromSpace(e) {
PropertiesService.getScriptProperties()
.deleteProperty(e.space.name);
}
// Add a trigger that invokes this function every minute via the
// "Edit > Current Project's Triggers" menu. When it runs, it will
// post in each space the bot was added to.
function onTrigger() {
var spaceIds = PropertiesService.getScriptProperties()
.getKeys();
var message = { 'text': 'Hi! It\'s now ' + (new Date()) };
for (var i = 0; i < spaceIds.length; ++i) {
postMessage(spaceIds[i], message);
}
}
var SCOPE = 'https://www.googleapis.com/auth/chat.bot';
// The values below are copied from the JSON file downloaded upon
// service account creation.
var SERVICE_ACCOUNT_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE
KEY-----\n';
var SERVICE_ACCOUNT_EMAIL = 'service-account#project-id.iam.gserviceaccount.com';
// Posts a message into the given space ID via the API, using
// service account authentication.
function postMessage(spaceId, message) {
var service = OAuth2.createService('chat')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(SERVICE_ACCOUNT_PRIVATE_KEY)
.setClientId(SERVICE_ACCOUNT_EMAIL)
.setPropertyStore(PropertiesService.getUserProperties())
.setScope(SCOPE);
if (!service.hasAccess()) {
Logger.log('Authentication error: %s', service.getLastError());
return;
}
var url = 'https://chat.googleapis.com/v1/' + spaceId + '/messages';
UrlFetchApp.fetch(url, {
method: 'post',
headers: { 'Authorization': 'Bearer ' + service.getAccessToken() },
contentType: 'application/json',
payload: JSON.stringify(message),
});
}

Client ID no longer exists

When I try to run an Appscript I get error ..
[17-02-08 01:00:35:160 PST] Open the following URL and re-run the script: https://accounts.google.com/o/oauth2/auth?client_id=317559754348->0p1ti3fmjae175i06hn07jrbia6701q6.apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd>%2F1pgAT7ZCwiKrHx_7Iys770hJNRqTYwn9zioe9Qjvmhzc9rfIxO04P8Uum%2Fusercallback&state=ADEpC8xV9BMj3kqytygKLnjEYT7PX918NJg0i1oSCAsUTRwXcOgdzDStZA3lzGDK98CJ6OOhlDnlYEyyji5rx6P8haao8oDop->PMQBZsMMjk2Jl_GtsPnsifFDt1XjqSXtCS2Wx6X3fdLDHTlBzfwqvqrinfkHhW1dVw0oNv6-MaqDhimE912Po&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth>%2Fdevstorage.read_write&access_type=offline&approval_prompt=force&login_hint=imerrywe%40jaguarlandrover.com
Trouble is Client ID 317559754348-0p1ti3fmjae175i06hn07jrbia6701q6.apps.googleusercontent.com
no longer exists. Looks like it has accidentaly been deleted.
I have tried created new Oauth2 credentials but my appscript wants to use the old one.
How do I get my appscripts to use new credentials. ?
Regards,
Ian
// Global Project variables
var CLIENT_ID = 'xxxxxxxxxx-
leuap166eur7gi5ufr6kiau2nqefknci.apps.googleusercontent.com';
var CLIENT_SECRET = 'xxxxxxxxxx';
// OAuth2.0 Access token
var token;
function oAuth() {
// Check we have access to the service
Logger.log(Session.getActiveUser().getEmail());
Logger.log( Session.getEffectiveUser().getEmail());
var service = getService();
Logger.log('Access '+service.hasAccess());
var authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL);
Logger.log(authInfo.getAuthorizationStatus());
if (!service.hasAccess()) {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s',
authorizationUrl);
return;
}
}
function getService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('xxxxxxxxxx')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
// this is admin access for the sqlservice and access to the cloud- platform:
.setScope('https://www.googleapis.com/auth/sqlservice.admin
https://www.googleapis.com/auth/cloud-platform')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
That’s an error.
Error: redirect_uri_mismatch
The redirect URI in the request, does not match the ones authorized for the OAuth >client. Visit >1 to update the authorized redirect URIs.
Just to address the
That’s an error. Error: redirect_uri_mismatch
Go to your new clientID, below it you may need to add the "oauth2callback" redirect uri like:
http://www.mywebsite.com/oauth2callback

How to use the Gmail API, OAuth2 for Apps Script, and Domain-Wide Delegation to set email signatures for users in a G Suite domain

This is a follow-up to a previous question/answer I posted (How to use the Google Email Settings API and the OAuth2 for Apps Script Library to set email signatures for users in a Google Apps domain), but I'm creating a new question since the Email Settings API has been deprecated and the process is significantly different now.
As the administrator of a G Suite domain, how do you use the Gmail API to programmatically set the email signatures of users in your domain through Google Apps Script?
This method uses the Gmail API, the OAuth2 for Apps Script library, and "Domain-wide Delegation of Authority", which is a way for G Suite admins to make API calls on behalf of users within their domain.
Step 1: Make sure the OAuth2 For Apps Script library is added to your project.
Step 2: Set up "Domain-Wide Delegation of Authority." There's a page here explaining how to do it for the Drive API, but it's pretty much the same for any Google API, including the Gmail API. Follow the steps on that page up to, and including, the "Delegate domain-wide authority to your service account" step.
Step 3: The code below includes how to set the signature after the previous steps are complete:
function setSignatureTest() {
var email = 'test#test.com';
var signature = 'test signature';
var test = setSignature(email, signature);
Logger.log('test result: ' + test);
}
function setSignature(email, signature) {
Logger.log('starting setSignature');
var signatureSetSuccessfully = false;
var service = getDomainWideDelegationService('Gmail: ', 'https://www.googleapis.com/auth/gmail.settings.basic', email);
if (!service.hasAccess()) {
Logger.log('failed to authenticate as user ' + email);
Logger.log(service.getLastError());
signatureSetSuccessfully = service.getLastError();
return signatureSetSuccessfully;
} else Logger.log('successfully authenticated as user ' + email);
var username = email.split("#")[0];
var resource = { signature: signature };
var requestBody = {};
requestBody.headers = {'Authorization': 'Bearer ' + service.getAccessToken()};
requestBody.contentType = "application/json";
requestBody.method = "PUT";
requestBody.payload = JSON.stringify(resource);
requestBody.muteHttpExceptions = false;
var emailForUrl = encodeURIComponent(email);
var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs/' + emailForUrl;
var maxSetSignatureAttempts = 20;
var currentSetSignatureAttempts = 0;
do {
try {
currentSetSignatureAttempts++;
Logger.log('currentSetSignatureAttempts: ' + currentSetSignatureAttempts);
var setSignatureResponse = UrlFetchApp.fetch(url, requestBody);
Logger.log('setSignatureResponse on successful attempt:' + setSignatureResponse);
signatureSetSuccessfully = true;
break;
} catch(e) {
Logger.log('set signature failed attempt, waiting 3 seconds and re-trying');
Utilities.sleep(3000);
}
if (currentSetSignatureAttempts >= maxSetSignatureAttempts) {
Logger.log('exceeded ' + maxSetSignatureAttempts + ' set signature attempts, deleting user and ending script');
throw new Error('Something went wrong when setting their email signature.');
}
} while (!signatureSetSuccessfully);
return signatureSetSuccessfully;
}
// these two things are included in the .JSON file that you download when creating the service account and service account key
var OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n';
var OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = 'xxxxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com';
function getDomainWideDelegationService(serviceName, scope, email) {
Logger.log('starting getDomainWideDelegationService for email: ' + email);
return OAuth2.createService(serviceName + email)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY)
.setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(email)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope(scope);
}
Please note: the do-while loop with the maxSetSignatureAttempts and currentSetSignatureAttempts variables is not necessary. I added it because if you're trying to set signatures immediately after creating the Google account and assigning a G Suite license, sometimes the Gmail API returns an error as if the user wasn't created yet. That do-while loop basically waits 3 seconds if it gets an error, then tries again, up to x number of times. You shouldn't have that issue if you're setting signatures for existing users. Also, originally I just had a fixed 10-second sleep, but most of the time it didn't need to take that long, but other times it would still fail. So this loop is better than a fixed sleep amount.

Transfer ownership of a file to another user in Google Apps Script

I have created a little upload UI which I include in a Google Sites page. It let's a user upload a document. Since the script is published it runs under my account and the uploaded file is uploaded to my google drive. I can from apps script add the person that uploaded the file as an editor, but what I would like to do is make them the owner of a file. (from apps script you can do a .getOwner() on a file... but not a .setOwner() ..... does anyone know a workaround?
Unfortunately changing the owner of a file isn't supported in Apps Script. Issue 74 is a feature request to add this ability, and if you star the issue you'll show your support for the feature and get notified of updates.
------EDITED------
Now there is a handy method called setOwner, which can be found here: https://developers.google.com/apps-script/reference/drive/file#setOwner(User)
There's also the possibility to pass the new owner's email address instead of the User object, which is even more handy in some cases:
https://developers.google.com/apps-script/reference/drive/file#setOwner(String)
Updated 12 Sep 2016:
This code uses a service account that's been granted Google Apps Domain-Wide Delegation of Authority. This lets you change the owner of any file owned by any user on the domain. This code uses the Google apps-script-oauth2 library by Eric Koleda.
var PRIVATE_KEY = PropertiesService.getScriptProperties().getProperty('PRIVATE_KEY');
var CLIENT_EMAIL = PropertiesService.getScriptProperties().getProperty('CLIENT_EMAIL');
/**
* Transfers ownership of a file or folder to another account on the domain.
*
* #param {String} fileId The id of the file or folder
* #param {String} ownerEmail The email address of the new owner.
*/
function transferOwnership(fileId, ownerEmail) {
var file = DriveApp.getFileById(fileId);
var currentOwnerEmail = file.getOwner().getEmail(); //the user that we need to impersonate
var service = getService(currentOwnerEmail);
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/drive/v2/files/' + fileId + '/permissions';
var payload = {value: ownerEmail,
type: 'user',
role: 'owner'};
var options = {method: "post",
contentType: "application/json",
headers : {
Authorization: 'Bearer ' + service.getAccessToken()
},
payload: JSON.stringify(payload)//,
,muteHttpExceptions: true
};
//debugger;
//throw 'test my errors';
var response = UrlFetchApp.fetch(url, options);
if (response.getResponseCode() === 200 ||
(response.getResponseCode() === 400 && response.getContentText().indexOf('were successfully shared'))
) {
return response.getContentText();
}
if (response.getResponseCode() === 401 && response.getContentText().indexOf('Invalid Credentials')) {
throw 'Unable to transfer ownership from owner ' + currentOwnerEmail + ' ... ' +
'Please make sure the file\'s owner has a Google Apps license (and not a Google Apps Vault - Former Employee license) and try again.';
}
throw response.getContentText();
} else {
throw service.getLastError();
}
}
/**
* Reset the authorization state, so that it can be re-tested.
*/
function reset() {
var service = getService();
service.reset();
}
/**
* Configures the service.
*/
function getService(userEmail) {
return OAuth2.createService('GoogleDrive:' + userEmail)
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(userEmail)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope('https://www.googleapis.com/auth/drive');
}
Old answer (obsolete now as the Document List API is deprecated):
You can achieve this in Google Apps Script by accessing the Document List API using the raw atom xml protocol. You need to be a super admin of the domain. Here's an example that works for me:
/**
* Change Owner of a file or folder
* Run this as admin and authorise first in the script editor.
*/
function changeOwner(newOwnerEmail, fileOrFolderId){
var file = DocsList.getFileById(fileOrFolderId);
var oldOwnerEmail = file.getOwner().getEmail();
if (oldOwnerEmail === newOwnerEmail) {
return;
}
file.removeEditor(newOwnerEmail);
var base = 'https://docs.google.com/feeds/';
var fetchArgs = googleOAuth_('docs', base);
fetchArgs.method = 'POST';
var rawXml = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'>"
+"<category scheme='http://schemas.google.com/g/2005#kind' "
+"term='http://schemas.google.com/acl/2007#accessRule'/>"
+"<gAcl:role value='owner'/>"
+"<gAcl:scope type='user' value='"+newOwnerEmail+"'/>"
+"</entry>";
fetchArgs.payload = rawXml;
fetchArgs.contentType = 'application/atom+xml';
var url = base + encodeURIComponent(oldOwnerEmail) + '/private/full/'+fileOrFolderId+'/acl?v=3&alt=json';
var content = UrlFetchApp.fetch(url, fetchArgs).getContentText();
}
//Google oAuth
function googleOAuth_(name,scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey("anonymous");
oAuthConfig.setConsumerSecret("anonymous");
return {oAuthServiceName:name, oAuthUseToken:"always"};
}
Try this out! (at least it worked for me)
var newFolder = DriveApp.createFolder(folderName).addEditor(ownerEmail).setOwner(ownerEmail).addEditor(group.getEmail()).removeEditor(Session.getActiveUser().getEmail());
The above creates a folder and adds a new editor, sets the new editor to be the owner, adds another group to the editors and finally removes the user who has just created the folder from the editors.
I figured out a work-around -- not sure if it's exactly what you all are looking for. Simply give access to the account you'd like to switch ownership to. Access the document/form/etc. from that account and then make a copy of the said document. You are now the owner. You'll have to re-invite others.