Adding Collaborators and annotating documents with web app users

Hi everyone,


We are using GroupDocs with a Salesforce instance to allow users to collaborate and annotate PDF’s related to Salesforce objects. I’ve implemented the SDK into our Salesforce instance and I’ve gone through all the samples. When I run sample 13, which is to add a collaborator, the Apex code executes fine, and I can see on the document that the collaborator was added.

The first issue I’m running into however, is when I try to add another collaborator. I obviously specify the file ID, private key, client ID, and the email address for the collaborator. Then I submit the form in Salesforce. I then enter a different email address to represent a different collaborator and it overwrites the first collaborator. When I view the document on the apps.groupdocs.com viewer, it only ever shows the most recently added collaborator.


My second issue is, I get the new collaborators guid, and try to load up the iframe viewer for that user to annotate. I use the following url:

https://apps.groupdocs.com

The viewer loads up, but when I create an annotation, its always created as the groupdocs account user. Is there another parameter I’m missing in the URL? Do I need to give the collaborator certain permissions?


I could really use some help here. I’m stumped. I really appreciate anything you can do!

Thanks,

Bob

Hello Bob,

Thank you for using GroupDocs Cloud Service.

In the Salesforce sample 13 used SetAnnotationCollaborator method, this method allows you to add first collaborator or several collaborators at once. If you will use this method to add second collaborator, it will rewrite existing collaborator with new collaborator because the method changes the collaborator instead adding new collaborators. In your case you should use a AddAnnotationCollaborator method.

As for the second issue - the url for iframe is correct, but if you want to annotate the document as a collaborator , you should log-off from GroupDocs and clear the browser cache or use another browser .

Also if needed you can set collaborator access rights such as: CanView, CanAnnotate, CanDownload, CanExport, CanDelete, CanRedact or All. For this you should use a SetReviewerRights method.

If you will have more questions please feel free to contact us.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Thanks for the reply Evgen,


I’m now able to add multiple collaborators. I am setting the access_rights value for the GD_ReviewerInfo to ‘2’ and I’m also populating firstName, lastName and primary_email. The response is good and I can see the collaborators in the list of collaborators.

The only issue I have now is, when I try to access the PDF in the embedded viewer using the url https://apps.groupdocs.com , every annotation I add is recorded as “Anonymous” instead of the user whose uid I’ve specified. Any idea? Thanks! :slight_smile:

Hello Bob,

Thank you for posting.

Glad to hear that your issue with multiple collaborators was resolved. Could you please share with us an example of url with the all guids for document and for collaborator that we can check logs for it on our server.

Please come back with your details and we will be glad to help you.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Hi there,


Here is an example where my annotations are being entered as Anonymous:

https://apps.groupdocs.com//document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=7d42aa1c1846da2c

Ok, I’ve gotten to a point where I can give a collaborator All permissions using the value “63”. I do that in the code when I create the collaborator, and when I try with this URL:

https://apps.groupdocs.com//document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=2daee3dddffddb4a

I get the following error:
This reviewer has no permission to view this document.
Hello Bob,

Thank you for the URL sharing.

We have checked your details and found out you missed signing of the url "https://apps.groupdocs.com//document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=7d42aa1c1846da2c" and in such case our server will authorize it as a anonymous user. You should sign the url using such code:

string url = new GD_GroupDocsSecurityHandler("your private key").sign("https://apps.groupdocs.com//document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=7d42aa1c1846da2c");

and then use signed url for annotating the document (sample url) . Also you can check for how it works in our Java samples as an example.

As for the second issue - the error "This reviewer has no permission to view this document."
Seems that you logged in GroupDocs, as another user which not added to this document as collaborator.
Please log-off from GroupDocs and try to annotate your document again .

If you will have more questions please feel free to contact us.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Hi Evgen,


I’ve implemented signing the url and when I try the signed url, all of my annotations are being entered as Anonymous.

Let me see if I can describe what we’re doing. First, I upload the document to GD from Salesforce. Once the document is uploaded, I create a new collaborator for the document using the logged in user’s email address and give All permissions. Once I have the fileId and new collaborators guid, I build the url and sign it.

Below I’ve copied your sample url, and underneath that, my url. They appear to be exactly the same.

Sample URL (works fine): https://apps.groupdocs.com/

My URL (annotates as Anonymous): https://apps.groupdocs.com/

The code I’m using to sign the URL is:
String signature = new GD_GroupDocsSecurityHandler(GD_Utils.privateKey).sign('https://apps.groupdocs.com/);
String signedURL='https://apps.groupdocs.com/

I just did another test, using the same fileId and uid as the one you provided in the sample url, and when I generated the signature, it was different than the one from the sample url.


URL with signature from our system:https://apps.groupdocs.com/document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=2daee3dddffddb4a&signature=yQzwAI%2FHMJE0fvwfBxa5nPmBYEA

URL in the same you provided: https://apps.groupdocs.com

The code to create a signature is as follows:
First, we call:
String testUrl=new GD_GroupDocsSecurityHandler(GD_Utils.privateKey).handleURL(‘https://apps.groupdocs.com/document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=2daee3dddffddb4a’, null);

handleURL:
public String handleURL(String url, Map<String, String> headers){
URL resourceURL = new URL(url);
String pathAndQuery = resourceURL.getFile();
if(url.endsWith(’ ‘)){
pathAndQuery = pathAndQuery + ’ ‘;
}
String signature = sign(GD_Utils.encodeURI(pathAndQuery));
String signedURL = url + (resourceURL.getQuery() == null ? ‘?’ : ‘&’) + ‘signature=’ + GD_Utils.encodeURIComponent(signature);
return signedURL;
}

public String sign(String toSign){
Blob mac = Crypto.generateMac(SIGN_ALG, Blob.valueOf(toSign), Blob.valueOf(this.privateKey));
String signature = EncodingUtil.base64Encode(mac);
if(signature.endsWith(’=’)){
signature = signature.substring(0, signature.length() - 1);
}
return signature;
}



the handleURL calls the sign method, which generates the signature.

Hop you can help…we’re so close! :slight_smile:

Hello Bob,

We have checked the code:

string url =
new GD_GroupDocsSecurityHandler('private key').handleURL('https://apps.groupdocs.com/document-annotation2/embed/<<>>?uid=<<>>', null)

And on our side with our data it works well and we got correct signature for such url.
We also tried to check again your document, but we see that you have deleted it.

Could you please share with us full code of the controller, where you make these operations(adding collaborators and signing url) , that we will be able to check it.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

We switched over to Google Cloud storage yesterday to test that out and I guess that wiped out our GroupDocs documents. I just uploaded a new one.


Here is the URL:

https://apps.groupdocs.com/document-annotation2/embed/12896d348bf8c7c8f3343873f1558bf226897d25a060c7899ac55b0777e4c671?uid=b85fe6e152f26c8d&signature=Z8FhGma6rQsn4dRByCktuplVWog


Controller code is:

public PageReference uploadDrawing() {
docId = docId.substring(0, 15);
callbackurl = null;
GD_GroupDocsSecurityHandler securityHandler = new GD_GroupDocsSecurityHandler(GD_Utils.privateKey);
GD_ApiClient api = new GD_ApiClient(securityHandler);
GD_StorageApi storageApi = new GD_StorageApi(api);
String folder = docId;
if (folder.endsWith(‘/’) == false && folder.endsWith(‘\’) == false) {
folder = folder + ‘/’;
}
if (folder.startsWith(‘/’)) {
folder = folder.substringAfter(‘/’);
}
if (folder.startsWith(‘\’)) {
folder = folder.substringAfter(‘\’);
}
GD_UploadResponse response = storageApi.Upload(GD_Utils.clientId, folder +name, ‘’, callbackurl,true, body);
string status = response.status;
if (status.containsIgnoreCase(‘ok’)) {

GD_UploadRequestResult result = response.result;

String collab = setCollaborator(result.guid);

NCA_Drawing__c drawing = [SELECT id, Drawing_GUIDs__c from NCA_Drawing__c WHERE id =: docId];
drawing.Drawing_GUIDs__c = drawing.Drawing_GUIDs__c+‘;’+result.guid;
update drawing;
//Add the uploader as a collaborator
// List<GD_ReviewerInfo> reviewers = new List<GD_ReviewerInfo>();
String testUrl=new //GD_GroupDocsSecurityHandler(GD_Utils.privateKey).handleURL(‘https://apps.groupdocs.com/document-annotation2/embed/ed0246b4389d2a795430869151886a50f1966081870d7855bdec49d14345471a?uid=2daee3dddffddb4a’, null);
String signedURL = new GD_GroupDocsSecurityHandler(GD_Utils.privateKey).handleURL('https://apps.groupdocs.com/ , null);
this.status='Results: ’ + signedURL;
this.embed = signedURL;
this.error = null;
}
else {
this.message = response.error_message;
this.status=‘Results: Upload Failed’;
}
return null;
}

public String setCollaborator(String fileId){
GD_ReviewerInfo info = new GD_ReviewerInfo();
info.primary_email= UserInfo.getUserEmail();
List USER = [SELECT FirstName, LastName FROM User WHERE Email=:UserInfo.getUserEmail() LIMIT 1];
info.firstName = USER[0].FirstName;
info.lastName = USER[0].LastName;
info.access_rights=‘63’;
// reviewers.add(info);
GD_GroupDocsSecurityHandler securityHandler = new GD_GroupDocsSecurityHandler(GD_Utils.privateKey);
GD_ApiClient api = new GD_ApiClient(securityHandler);
GD_AntApi antApi = new GD_AntApi(api);
GD_AddCollaboratorResponse collabresponse = antApi.AddAnnotationCollaborator(GD_Utils.clientId, fileId, info);
string status = collabresponse.status;
if (status.containsIgnoreCase(‘ok’)) {
GD_SetCollaboratorsResult result =collabresponse.result;
return result.collaborators[0].guid;
}
return null;
}

Hello Bob,

Thank you for sharing your details.

We have checked your code of controller and we not found a functionality of adding the collaborators as users to your account. You should add new user to the account and then add his as a collaborator to the document. Please check this code:

GD_GroupDocsSecurityHandler securityHandler = new GD_GroupDocsSecurityHandler("private key");
GD_ApiClient api = new GD_ApiClient(securityHandler);
GD_MgmtApi mgmtApi = new GD_MgmtApi(api)
GD_UserInfo user = new GD_UserInfo();
GD_RoleInfo role = new GD_RoleInfo();
List rolesList = new List()
//Set user role Id. Can be: 1 - SysAdmin, 2 - Admin, 3 - User, 4 - Guest
role.id = 3;
//Set user role name. Can be: SysAdmin, Admin, User, Guest
role.name = "User";
user.firstname = "first name";
user.lastname = "last name";
rolesList.add(role)
user.roles(rolesList);
user.primary_email = "email of user"

GD_UpdateAccountUserResponse updateAccountUserResponse = mgmtApi.UpdateAccountUser("client Id", "email of user", user);
GD_UpdateAccountUserResult result = updateAccountUserResponse.result;
String userid = result.guid

Also you can check our Java sample, it is providing the functionality of adding the new user to the account.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Hi Evgen,


I’ve tried adding users in two different ways, both failing at GD_ClientAPI.callAPI.

I’ve tried using mgmtApi.UpdateAccountUser as well as mgmtApi.CreateUser. Both throw the same error.

12:19:11.940 (3940262044)|CALLOUT_REQUEST|[57]|System.HttpRequest[Endpoint=https://api.groupdocs.com/v2.0/mgmt/b85fe6e152f26c8d/users?signature=DlHy1YgAh%2FXPqm4tEL3gGu1rdqw, Method=POST]
12:19:12.388 (4388742645)|CALLOUT_RESPONSE|[57]|System.HttpResponse[Status=Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686., StatusCode=400]
12:19:12.388 (4388792061)|SYSTEM_METHOD_EXIT|[57]|System.Http.send(ANY)
12:19:12.388 (4388821046)|SYSTEM_METHOD_ENTRY|[58]|system.Type.getName()
12:19:12.388 (4388843602)|SYSTEM_METHOD_EXIT|[58]|system.Type.getName()
12:19:12.388 (4388872696)|SYSTEM_METHOD_ENTRY|[61]|System.HttpResponse.getBody()
12:19:12.388 (4388917072)|SYSTEM_METHOD_EXIT|[61]|System.HttpResponse.getBody()
12:19:12.388 (4388938365)|SYSTEM_METHOD_ENTRY|[62]|System.debug(ANY)
12:19:12.388 (4388946698)|USER_DEBUG|[62]|DEBUG|JSON response from server: {“composedOn”:1433175553031,“error_message”:“Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686.”,“result”:{},“status”:“Failed”}
12:19:12.388 (4388954007)|SYSTEM_METHOD_EXIT|[62]|System.debug(ANY)


This is the code I’m using to create the user:

 public GD_UserInfo createUser() {
    GD_GroupDocsSecurityHandler securityHandler = new GD_GroupDocsSecurityHandler(GD_Utils.privateKey);
    GD_ApiClient api = new GD_ApiClient(securityHandler);
    GD_MgmtApi mgmtApi = new GD_MgmtApi(api);
    //Check if user exists:
    String userEmail = UserInfo.getUserEmail();
    GD_GetAccountUsersResponse userResp = mgmtApi.GetAccountUsers(GD_Utils.clientId);
    List<GD_UserInfo> users = userResp.result.users;
    for(GD_UserInfo user : users){
        if(userEmail.equalsIgnoreCase(user.primary_email)){
            //User found, don't recreate
            status += 'createUser guid (found): ' + user.guid;
            return user;
        }
    }

    GD_UserInfo userObj = new GD_UserInfo();
    GD_RoleInfo role = new GD_RoleInfo();
    List<GD_RoleInfo> rolesList = new List<GD_RoleInfo>();

//Set user role Id. Can be: 1 - SysAdmin, 2 - Admin, 3 - User, 4 - Guest
role.name = ‘User’;
role.id = 3;
//Set user role name. Can be: SysAdmin, Admin, User, Guest
List USER = [SELECT FirstName, LastName FROM User WHERE Email = :userEmail LIMIT 1];
userObj.firstname = USER[0].FirstName;
userObj.lastname = USER[0].LastName;
userObj.primary_email = userEmail;
rolesList.add(role);
userObj.roles=rolesList;

    <b>GD_CreateUserResponse createAccountUserResponse = mgmtApi.CreateUser(GD_Utils.clientId, userObj);</b>
     string status = createAccountUserResponse.status;
    if (status.containsIgnoreCase('ok')) {
        GD_CreateUserResult result = createAccountUserResponse.result;
        String newUserGuid = result.user.guid;
        status += 'newUserGuid: ' + newUserGuid;
        userObj.guid = newUserGuid;
    }else {
            this.status =createAccountUserResponse.error_message;
            
        }
    return userObj;
}</span></font></pre><pre class="codeBlock" style="background-color: rgb(248, 248, 248);">I've also confirmed that the email, firstname and lastname being used in the GD_UserInfo object are not null.</pre><pre class="codeBlock" style="background-color: rgb(248, 248, 248);"><br></pre><pre class="codeBlock" style="background-color: rgb(248, 248, 248);">Any idea?</pre></div>
Hello Bob,

Thank you for your inquiry.

We have checked your plan and on your plan you haven't opportunity to add new user to the account, it has only one user. But for testing we have added to your plan additional user and now you can try to add the user as we showed in a previous our post.

Please try to add the new user to the plan and then add its as a collaborator to document again.

Also you will be able to delete this user and create a new one if you needed.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Hi Evgen,


I’m still seeing the same error message: Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686.

When I view my account on GroupDocs, it says I cannot create a new user from the console.
Hello Bob,

We updated your plan again. Please try to add the user now.

We apologize for your inconvenience.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Thanks Evgen,


When I try creating a user using the following code, I get an error:

GD_UpdateAccountUserResponse createAccountUserResponse = mgmtApi.UpdateAccountUser(GD_Utils.clientId, userEmail, userObj);
string status = createAccountUserResponse.status;
if (status.containsIgnoreCase(‘ok’)) {
GD_UpdateAccountUserResult result = createAccountUserResponse.result;
String newUserGuid = result.guid;
status += 'newUserGuid: ’ + newUserGuid;
userObj.guid = newUserGuid;
}else {
this.status =createAccountUserResponse.error_message;
}

Error: Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686.

Its the same error I got yesterday. Log can be found below:

12:19:11.940 (3940262044)|CALLOUT_REQUEST|[57]|System.HttpRequest[Endpoint=https://api.groupdocs.com/v2.0/mgmt/b85fe6e152f26c8d/users?signature=DlHy1YgAh%2FXPqm4tEL3gGu1rdqw, Method=POST]
12:19:12.388 (4388742645)|CALLOUT_RESPONSE|[57]|System.HttpResponse[Status=Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686., StatusCode=400]
12:19:12.388 (4388792061)|SYSTEM_METHOD_EXIT|[57]|System.Http.send(ANY)
12:19:12.388 (4388821046)|SYSTEM_METHOD_ENTRY|[58]|system.Type.getName()
12:19:12.388 (4388843602)|SYSTEM_METHOD_EXIT|[58]|system.Type.getName()
12:19:12.388 (4388872696)|SYSTEM_METHOD_ENTRY|[61]|System.HttpResponse.getBody()
12:19:12.388 (4388917072)|SYSTEM_METHOD_EXIT|[61]|System.HttpResponse.getBody()
12:19:12.388 (4388938365)|SYSTEM_METHOD_ENTRY|[62]|System.debug(ANY)
12:19:12.388 (4388946698)|USER_DEBUG|[62]|DEBUG|JSON response from server: {“composedOn”:1433175553031,“error_message”:“Error converting value {null} to type ‘System.Int64’. Path ‘id’, line 1, position 2686.”,“result”:{},“status”:“Failed”}
Hello Bob,

We are sorry to hear that you have such issue. We have checked the scenario and we found out that the apex sends to our server a parameter id as "null". To fix this error just add such code when create GD_UserInfo:
user.id = 0;

and then the UpdateAccountUser method should work.

If you will have more questions please feel free to contact us.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+

Another error:


the error is: Cannot convert null value to Groupdocs.Common.Applications. Path ‘apps’, line 1, position 2746.

it seems the apps field for UserInfo object is required, but I cannot find any documentation as to what are valid values for that field.


Hello,


Please try to add such code:

user.apps = ‘127’

If you will have more questions please feel free to contact us.

Best regards
Evgen Efimov

http://groupdocs.com
Your Document Collaboration APIs
Follow us on LinkedIn, Twitter, Facebook and Google+