0

I'm running a provider-hosted Add-In in SharePoint Online. I want to do some stuff in Remote Event Receivers that change list items that connected users cannot do.

The problem I'm facing is the user that appears when made the changes to the list item is the add-In itself or a user with full permission (if I use a brand new forced clientContext to make changes). But I need the connected user to appear in the last modification.

In custom actions or Requests, it is possible to manage. Because I have access to the clientContext of the connected user. But not in RER.

Reading the following article seems using low trust authorization should work, but I get Acces denied permissions message. And I've set web and site collection permissions to full control. https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/elevated-privileges-in-sharepoint-add-ins

<AppPermissionRequests AllowAppOnlyPolicy="false">
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
  </AppPermissionRequests>

I read a lot about it and I figure out in RER, the only way to operate in "elevated permissions" is to set AllowAppOnlyPolicy="true" But this eliminates the possibility to view the connected user as the user who made modifications, as explained here.

https://www.sharepointnutsandbolts.com/2014/07/remote-event-receivers-on-host-web-ClientContext.html

I also tried to claim for TENANT permissions, but when start debugging, confirm button is disabled. My user is tenant admin, so I don't know how to pass this step.

I spent a lot of time on it and run out of ideas. Any ideas about how to do it?

1 Answer 1

0

Finally I did some workaround to solve this. In my project actually changes to list items are made after "ItemAdded" event on such lists.

In this event, I use a boolean variable to check if some change to list item has been made. If yes, at the end of event I overwrite listItem["Editor"] field with it's own value, to propagate it to "AfterProperties" of the following "ItemUpdating". So I'll can read it.

First, let's mark AppManifest.xml with AllowAppOnlyPolicy="true"

<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />

Sample code ItemAdded

public void ItemAdded(SPRemoteItemEventProperties itemEventProperties, ClientContext clientContext)
{
    try
    {
        List list = clientContext.Web.Lists.GetByTitle(itemEventProperties.ListTitle);
        ListItem listItem = list.GetItemById(itemEventProperties.ListItemId);
        // 0.initialize to false
        bool itemChanged = false;
        clientContext.Load(listItem);
        clientContext.ExecuteQuery();
    if (listItem["SomeField"] != null && listItem["SomeField"].ToString() != String.Empty)
    {
        listItem["Title"] = listItem["SomeField"].ToString();
        //Set to true!!! after every change
        itemChanged = true;
    }
    
    // Some other changes here maybe
    
    if (itemChanged)
    {
        // Overwrite Editor field (in itemAdded is the person who uses the browser)
        FieldUserValue editor = (FieldUserValue)listItem["Editor"];
        listItem["Editor"] = null;
        listItem["Editor"] = editor.LookupId.ToString();
        // Mark List Item for update
        listItem.Update();

        //put it in the if if there are only changes to same List Item in this event
        contextElevated.ExecuteQuery();
    }
    //put it outside the if if there are pending changes to other lists
    contextElevated.ExecuteQuery();
}
catch (Exception ex)
{
    //Log Error
}

}

After this, on "ItemUpdate" Event I do the same things with boolean and at the end comes how to preserve the human user.

    ... Event UpdateItem code with changes to same list item controled by boolean 
    
    if (itemChanged)
    {
        // First, check if user has come from "afterProperties"
        if (itemEventProperties.AfterProperties.ContainsKey("Editor"))
        {
            listItem["Editor"] = itemEventProperties.AfterProperties["Editor"].ToString();
        }
        else
        {
            // if not, overWrite the user
            FieldUserValue editor = (FieldUserValue)listItem["Editor"];
            listItem["Editor"] = null;
            listItem["Editor"] = editor.LookupId.ToString();
        }
        // Mark List Item for update
        listItem.Update();
        //put it in the if if there are only changes to same List Item in this event
        contextElevated.ExecuteQuery();
    }
    //put it outside the if if there are pending changes to other lists
    contextElevated.ExecuteQuery();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.