AclRole for Commenter - google-docs-api

I have an issue updating the Acl for a Google Document.
I want to share the document with some users but only allow COMMENTER privileges.
This is the code:
AclEntry newAclEntry = getDservice().insert(new URL(aclFeedUrl), new AclScope( AclScope.Type.USER, "user1#domain.com"), AclRole.COMMENTER);
Now Eclipse tells me AclRole.COMMENTER is a valid type but when I run the code I get the following exception:
Service Exception: The posted entry has an invalid value for the field(s): role
If I change this to AclRole.READER it works fine.
So I thought I'd do a bit of investigation. You can set COMMENTER access from a Google Doc via 'share'. So I did that and then read the ACL's for the doc via:
AclFeed feed = getDservice().getFeed(new URL(doc.getAclFeedLink().getHref()),AclFeed.class);
if (feed == null)
System.out.println("Feed is null");
else {
for (AclEntry a: feed.getEntries()) {
System.out.println("acl role:" + a.getRole().getValue());
System.out.println("acl scope:" + a.getScope().getValue());
}
}
The output for user1 with COMMENTER access, and user2 with READER access was:
acl role:reader
acl scope:user1#domain.com
acl role:reader
acl scope:user2#domain.com
So even when user1 is explicitly a COMMENTER, it's being reported as a 'reader'
If I access the online documentation for AclRole there is no COMMENTER enumeration (https://developers.google.com/gdata/javadoc/com/google/gdata/data/acl/AclRole).
So, how do I set an ACL for Comment only privileges? Clearly it's supported in Google Docs, and Eclipse is picking it up from the GData jars I'm using.
What am I missing?

The thing missing here is checking the additionalRole field of the ACL entry. The user is a reader and a commenter. Check out this raw XML response from the Documents List API:
<entry gd:etag='W/"D0UFQH4_eCt7ImAe9WhJREEk."'>
<id>https://docs.google.com/feeds/id/user%3Aa%40b.com</id>
<updated>2012-07-11T22:20:11.040Z</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>2012-07-11T22:20:11.040Z</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<title>Document Permission - a#b.com</title>
<link rel='self' type='application/atom+xml' href='https://docs.google.com/feeds/default/private/expandAcl/document%3A1lD_aQPqe33JI4mObm2zc7FADUH-ypXcGekwAovPY2OpMw/acl/user%3Aa%40b.com'/>
<link rel='edit' type='application/atom+xml' href='https://docs.google.com/feeds/default/private/expandAcl/document%3A1lD_aQPqe33JI4mObm2zc7FADUH-ypXcGekwAovPY2OpMw/acl/user%3Aa%40b.com'/>
<gAcl:role xmlns:gAcl='http://schemas.google.com/acl/2007' value='reader'/>
<gAcl:scope xmlns:gAcl='http://schemas.google.com/acl/2007' type='user' value='a#b.com' name='Anderson Jones'/>
<gAcl:additionalRole xmlns:gAcl='http://schemas.google.com/acl/2007' value='commenter'/>
</entry>
Note the value of gAcl:additionalRole is commenter.
Try this code to create a commenter entry:
AclEntry aclEntry = new AclEntry();
aclEntry.setScope(new AclScope("user", "user1#domain.com"));
aclEntry.setRole(AclRole.READER);
aclEntry.addAdditionalRole(AdditionalRole.COMMENTER);
And to determine if an entry has the commenter additionalRole, do this:
if (aclEntry.getAdditionalRoles().contains(AdditionalRole.COMMENTER)) {
// Do something knowing this user is a commenter
}
However, you really should upgrade to the Drive API v2, which makes this easier. The following code sample is for the Drive API:
Permission permission = new Permission();
permission.setType("user");
permission.setValue("user1#domain.com");
permission.setRole("reader");
permission.setAdditionalRoles(Arrays.asList("commenter"));
Thanks to Alain Vongsouvanh for providing parts of this answer!

Related

How to get file content on O365 sharepoint folder using graph API

Using Python and the adal and requests packages I'm attempting to use the MS graph API to find files on sharepoint (when providing a sharepoint site name, folder name where the file is expected to be, and name of file.
Using various calls I can manage to do the following
Get an authentication token (using user auth to an app which has full permission to use users credentials and do all read/write on files being accessed)
establish a valid session
search sites and obtain details on my current site
microsoft_info = SESSION.get('https://graph.microsoft.com/v1.0/sites?search=nameOfSite')
Obtain drive information associated with the site
for site in microsoft_info['value']:
if site['displayName'] == siteDisplayNameInput:
siteId = site['id']
drives = SESSION.get("https://graph.microsoft.com/v1.0/sites/"+siteId+"/drives")
drives = drives.json()
Obtain file information from drive of interest
for drive in drives['value']:
if(drive['name']) == folderNameInput:
driveId = drive['id']
files = SESSION.get("https://graph.microsoft.com/v1.0/drives/" + driveId +"/root/search(q='')")
files = files.json()
And then at point 6 everything falls apart and I get 404 errors returned saying that resource is not found - despite using the identifiers provided by the API which are clearly indicating the presence of a resource.
if file['name'] == 'Pipeline Pilot Forms.pptx':
print("List of properties on file")
for x in file:
print(x+" "+str(file[x]))
fileId = file['id']
print(fileId)
callToDLFile = SESSION.get("https://graph.microsoft.com/v1.0/drives/"+driveId+"/items/"+fileId+"/content"
appears to be the code that should work for this (indentation appears to have failed copying things into this, but it is all good) but it returns 404 errors - any help would be greatly appreciated on this, I don't see (in a reasonably lengthy search) anything which matches this issue exactly out there.

How to create JIRA issue ticket from a template using REST api?

I want to create JIRA Change Request Ticket using a template.
I use JIRA API endpoint '/rest/api/2/issue'.
Below is the format of the data sent to JIRA.
Could anyone please help?
payload =
{ fields:
{ project: { key: "CRQ"},
customfield_15630: "SampleTemplateName",
summary: "Testing",
customfield_17679: "N.A" ,
customfield_14530:"2018-06-17T00:00:00.0+0000 ",
customfield_14531: "2018-06-17T00:00:00.0+0000 " } }
Here is the XML format of template I want to use in the issue ticket.
<item>
<title>[TMPL-167] NTW-8 [Network_Interface_configuration]</title>
<link>https://jiraqa.com/browse/TMPL-167</link>
<project id="15980" key="TMPL">Templates</project>
<description>Test</description>
<environment />
<key id="492895">TMPL-167</key>
<summary>NTW-8 [Network_Interface_configuration]</summary>
</item>
You are definitely lacking an issue type there. Here is an example of a proper issue creation using the REST API: https://docs.atlassian.com/software/jira/docs/api/REST/7.6.1/#api/2/issue-createIssue
Certain fields may be required or not depending on the project settings, but the project ID, the summary and the issue type are an absolute minimum.
Another thing is that you want to use a template in addition to this. Jira may simply not be able to automatically fetch the data from there, but if anything went wrong, you'd receive an error message anyway.
Could you describe in more detail what exactly do you need to do? It would be easier to come up with a solution ;)

Gmail API returns 403 error code and "Delegation denied for <user email>"

Gmail API fails for one domain when retrieving messages with this error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 OK
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Delegation denied for <user email>",
"reason" : "forbidden"
} ],
"message" : "Delegation denied for <user email>"
}
I am using OAuth 2.0 and Google Apps Domain-Wide delegation of authority to access the user data. The domain has granted data access rights to the application.
Seems like best thing to do is to just always have userId="me" in your requests. That tells the API to just use the authenticated user's mailbox--no need to rely on email addresses.
I had the same issue before, the solution is super tricky, you need to impersonate the person you need to access gmail content first, then use userId='me' to run the query. It works for me.
here is some sample code:
users = # coming from directory service
for user in users:
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
####IMPORTANT######
credentials_delegated = credentials.with_subject(user['primaryEmail'])
gmail_service = build('gmail', 'v1', credentials=credentials_delegated)
results = gmail_service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
for label in labels:
print(label['name'])
Our users had migrated into a domain and their account had aliases attached to it. We needed to default the SendAs address to one of the imported aliases and want a way to automate it. The Gmail API looked like the solution, but our privileged user with roles to make changes to the accounts was not working - we kept seeing the "Delegation denied for " 403 error.
Here is a PHP example of how we were able to list their SendAs settings.
<?PHP
//
// Description:
// List the user's SendAs addresses.
//
// Documentation:
// https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs
// https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs/list
//
// Local Path:
// /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail.php
// /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail/Resource/UsersSettingsSendAs.php
//
// Version:
// Google_Client::LIBVER == 2.1.1
//
require_once $API_PATH . '/path/to/google-api-php-client/vendor/autoload.php';
date_default_timezone_set('America/Los_Angeles');
// this is the service account json file used to make api calls within our domain
$serviceAccount = '/path/to/service-account-with-domain-wide-delagation.json';
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $serviceAccount );
$userKey = 'someuser#my.domain';
// In the Admin Directory API, we may do things like create accounts with
// an account having roles to make changes. With the Gmail API, we cannot
// use those accounts to make changes. Instead, we impersonate
// the user to manage their account.
$impersonateUser = $userKey;
// these are the scope(s) used.
define('SCOPES', implode(' ', array( Google_Service_Gmail::GMAIL_SETTINGS_BASIC ) ) );
$client = new Google_Client();
$client->useApplicationDefaultCredentials(); // loads whats in that json service account file.
$client->setScopes(SCOPES); // adds the scopes
$client->setSubject($impersonateUser); // account authorized to perform operation
$gmailObj = new Google_Service_Gmail($client);
$res = $gmailObj->users_settings_sendAs->listUsersSettingsSendAs($userKey);
print_r($res);
?>
I wanted to access the emails of fresh email id/account but what happened was, the recently created folder with '.credentials' containing a JSON was associated with the previous email id/account which I tried earlier. The access token and other parameters present in JSON are not associated with new email id/account. So, in order make it run you just have to delete the '.credentails' folder and run the program again. Now, the program opens the browser and asks you to give permissions.
To delete the folder containing files in python
import shutil
shutil.rmtree("path of the folder to be deleted")
you may add this at the end of the program
Recently I started exploring Gmail API and I am following the same approach as Guo mentioned. However, it is going to take of time and too many calls when we the number of users or more. After domain wide delegation my expectation was admin id will be able to access the delegated inboxes, but seems like we need to create service for each user.

Getting Google file picker to work with drive.file scope

I'm trying to use the Google file picker to select a document and then update its permissions. I don't need access to all Drive files, just those selected.
However, when using the https://www.googleapis.com/auth/drive.file scope, I'm getting a 404 error when I try to change the permissions of the doc. I don't get this error if I use the https://www.googleapis.com/auth/drive scope, but this gives me more access than I need.
Is there any way to get the file picker working with the more limited https://www.googleapis.com/auth/drive.file scope?
Here's my file picker code:
<!-- The standard Google Loader script. -->
<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// Use the Google Loader script to load the google.picker script.
//google.setOnLoadCallback(createPicker);
google.load('picker', '1');
// Create and render a Picker object
function createPicker() {
var view = new google.picker.DocsView(google.picker.ViewId.DOCS);
view.setMode(google.picker.DocsViewMode.LIST);
//view.setMimeTypes("image/png,image/jpeg,image/jpg");
var picker = new google.picker.PickerBuilder()
//.enableFeature(google.picker.Feature.NAV_HIDDEN)
//.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setAppId("<%= ENV['GOOGLE_ID']%>")
.setOAuthToken("<%= current_user.token %>") //Optional: The auth token used in the current Drive API session.
.addView(view)
.addView(new google.picker.DocsUploadView())
.setCallback(pickerCallback)
.build();
picker.setVisible(true);
}
// callback implementation.
function pickerCallback(data) {
var url = 'nothing';
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
url = doc[google.picker.Document.URL];
title = doc.name;
id = doc.id;
type = doc.type;
embed = doc[google.picker.Document.EMBEDDABLE_URL ];
}
Answering my own question thanks to help from folks on the Google Drive Developer discussion on Google Plus:
This does work. I was using the wrong App_ID in my picker implementation - I needed to use only the numeric string at the beginning of the client ID. The other problem, it doesn't work on localhost, only in production.
Full discussion here: https://plus.google.com/u/0/108228914813783364664/posts/RgvmZwJcbE8
If you're modifying a file that's not created by your application, there is no more restricted scope other than the drive scope.

How to Add Tag via Asana API

I am trying to do a simple Salesforce-Asana integration. I have many functions working, but I am having trouble with adding a tag to a workspace. Since I can't find documentation on the addTag method, I'm sort of guessing at what is required.
If I post the following JSON to https://app.asana.com/api/1.0/workspaces/WORKSPACEID/tasks:
{"data":{"name":"MyTagName","notes":"Test Notes"}}
The tag gets created in Asana, but with blank notes and name fields. If I try to get a bit more fancy and post:
{"data":{"name":"MyTagName","notes":"Test Notes","followers":[{"id":"MY_USER_ID"}]}}
I receive:
{"errors":[{"message":"Invalid field: {\"data\":{\"name\":\"MyTagName\",\"notes\":\"Test Notes\",\"followers\":[{\"id\":\"MY_USER_ID\"}]}}"}]}
I'm thinking the backslashes may mean that my request is being modified by the post, though debug output shows a properly formatted json string before the post.
Sample Code:
JSONGenerator jsongen = JSON.createGenerator(false);
jsongen.writeStartObject();
jsongen.writeFieldName('data');
jsongen.writeStartObject();
jsongen.writeStringField('name', 'MyTagName');
jsongen.writeStringField('notes', 'Test Notes');
jsongen.writeFieldName('followers');
jsongen.writeStartArray();
jsongen.writeStartObject();
jsongen.writeStringField('id', 'MY_USER_ID');
jsongen.writeEndObject();
jsongen.writeEndArray();
jsongen.writeEndObject();
jsongen.writeEndObject();
String requestbody = jsongen.getAsString();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://app.asana.com/api/1.0/workspaces/WORKSPACEID/tags');
req.setMethod('POST');
//===Auth header created here - working fine===
req.setBody(requestbody);
Http http = new Http();
HTTPResponse res = http.send(req);
return res.getBody();
Any help appreciated. I am inexperienced using JSON as well as the Asana API.
The problem was that I was posting to the wrong endpoint. Instead of workspaces/workspaceid/tags, I should have been using /tags and including workspaceid in the body of the request.
Aha, so you can add tags and even set followers despite the API not mentioning that you can or claiming that followers are read-only.
So to sum up for anyone else interested: POSTing to the endpoint https://app.asana.com/api/1.0/tags you can create a tag like this:
{ "data" : { "workspace": 1234567, "name" : "newtagname", "followers": [45678, 6789] } }
where 1234567 is your workspace ID and 45678 and 6789 are your new followers.
Since you posted this question, Asana's API and developer has introduced Tags. You documentation lays out the answer to your question pretty clearly:
https://asana.com/developers/api-reference/tags
I'm a bit confused by your question. Your ask "how to add a tag" but the first half of your question talks about adding a task. The problem with what you describe there is that you are trying to set a task's followers but the followers field is currently read-only according to Asana's API documentation. That is why you are getting an error. You can not set followers with the API right now.
The second part of your question - with the sample code - does look like you are trying to add a tag. However, right now the Asana API does not support this (at least according to the API documentation). You can update an existing tag but you can't add one.
So, to sum up: at this time the API does not allow you to add followers to a task or to create new tags.

Resources