Cloud development - All about M365, .NET, SharePoint and more…
About Me
Contact Me
  • About Me
  • Contact Me
Cloud development - All about M365, .NET, SharePoint and more…
Development, Latest

Building SharePoint Online Remote Event Receivers for Document Review Flows

SharePoint Online has provided a myriad of collaboration and productivity tools for businesses. Among these, Remote Event Receivers and Microsoft Flow (now known as Power Automate) stand out as potent tools for automation and integration.

In this blog post, we will demonstrate how to use SharePoint Online Remote Event Receivers in combination with Power Automate to trigger a review Flow whenever a document’s status is set to “Pending” in a Document Library.

Understanding the Concepts

SharePoint Online Remote Event Receivers

Remote Event Receivers are components that handle events such as additions, updates, and deletions in SharePoint Online. Unlike their counterparts in SharePoint Server, they handle events remotely, meaning they respond to events in SharePoint Online from an external web service.

Power Automate (Flow)

Power Automate is a service offered by Microsoft that allows creation of automated workflows between apps and services to synchronise files, get notifications, collect data, and more.

Getting Started

The process is fairly straightforward and consists of the following steps:

  1. Creating an Azure Function
  2. Creating a Remote Event Receiver
  3. Creating a Power Automate Flow
  4. Attaching the Event Receiver to the Document Library

Please Note: The solution described in this post assumes you have access to and basic knowledge of Azure Functions, SharePoint Online, and Power Automate.

Step 1: Creating an Azure Function

Azure Functions is a serverless solution that allows you to write less code, maintain less infrastructure, and save costs. We’ll use it to host our Remote Event Receiver.

  1. Log into the Azure Portal.
  2. Create a new Function App.
  3. Once the Function App is created, create a new function within it. Use the HTTP trigger template, name your function and choose the Authorisation level (Function level should suffice).

Here is a basic example of how to structure your function:

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    string content = await req.Content.ReadAsStringAsync();
    log.Info(content);
    // Add your code to trigger the Power Automate flow here
    return req.CreateResponse(HttpStatusCode.OK);
}

This function merely logs the incoming request content and returns an OK response. You will add the logic to trigger the Power Automate flow later.

Step 2: Creating a Remote Event Receiver

In SharePoint, go to the list settings for the Document Library you want to use. Under “General Settings”, click on “Advanced settings”, and allow the management of content types by choosing “Yes”.

Now, add a new column to the Document content type. Name it “Status” and make it a Choice type field with “Pending” as one of the choices.

Once done, we will add our Remote Event Receiver. SharePoint does not provide an out-of-the-box interface to add Remote Event Receivers to lists or content types, so you will have to use the Client Side Object Model (CSOM) to attach the Event Receiver to the list.

Here is an example PowerShell script using CSOM to attach the Event Receiver to your Document Library:

# Input parameters
$siteUrl = "https://your-domain.sharepoint.com/sites/your-site"
$listTitle = "Documents"
$username = "your-username@your-domain.com"
$password = "your-password"
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $securePassword
$addInOnly = $False
# Connect to the site
Connect-PnPOnline -Url $siteUrl -Credentials $credentials -CreateDrive
# Define the event receiver properties
$eventReceiverName = "ItemUpdated"
$eventReceiverUrl = "https://your-azure-function-url"
$eventReceiverType = [Microsoft.SharePoint.Client.EventReceiverType]::ItemUpdated
$synchronization = [Microsoft.SharePoint.Client.EventReceiverSynchronization]::Asynchronous
# Add the event receiver
Add-PnPEventReceiver -List $listTitle -Name $eventReceiverName -Url $eventReceiverUrl -EventReceiverType $eventReceiverType -Synchronization $synchronization

This script adds an ItemUpdated event receiver to your Document Library. This event receiver will trigger your Azure Function whenever an item in the Document Library is updated.

Step 3: Creating a Power Automate Flow

Next, we’ll create a Power Automate flow that will be triggered by the Azure Function whenever a document status is set to “Pending”.

  1. Go to Power Automate.
  2. Create a new Flow. Use the HTTP request trigger.
  3. Add a new step to send an email (or any other action you want the Flow to take).
  4. Save your Flow. You will be provided with an HTTP POST URL.

Step 4: Finalizing the Azure Function

Finally, we will modify the Azure Function to trigger the Power Automate flow whenever a document’s status is set to “Pending”.

  1. In the Azure Function, add logic to parse the incoming request content to get the item data.
  2. Check if the item’s status is set to “Pending”.
  3. If it is, send a POST request to the Power Automate flow’s URL to trigger the flow.

Here is the modified Azure Function:

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    string content = await req.Content.ReadAsStringAsync();
    log.Info(content);
    // Parse the content as XML
    var doc = new XmlDocument();
    doc.LoadXml(content);
    var mgr = new XmlNamespaceManager(doc.NameTable);
    mgr.AddNamespace("s", "http://schemas.microsoft.com/sharepoint/soap/");
    mgr.AddNamespace("z", "#RowsetSchema");
    // Get the item data
    var itemDataNode = doc.SelectSingleNode("//s:Changes/s:Object/s:Properties/s:SharedFields", mgr);
    var itemData = itemDataNode.ChildNodes.Cast<XmlNode>().ToDictionary(n => n.LocalName, n => n.InnerText);
    // Check if the item's status is set to "Pending"
    if (itemData.ContainsKey("Status") && itemData["Status"] == "Pending")
    {
        // Trigger the Power Automate flow
        var flowUrl = "https://your-power-automate-flow-url";
        await new HttpClient().PostAsync(flowUrl, new StringContent(""));
    }
    return req.CreateResponse(HttpStatusCode.OK);
}

That’s it! You have now successfully set up a Remote Event Receiver in SharePoint Online that triggers a Power Automate flow whenever a document’s status is set to “Pending”.

This post provided a step-by-step guide on setting up this process, however, please note that this is a simplistic example and a real-world scenario would potentially be more complex.

June 4, 2023by Luke
Development, Latest, SharePoint

Using the SPO Search REST API to create a Webpart showing Recently Modified Documents containing specific keywords

SharePoint Online provides a powerful Search API that allows developers to query against SharePoint’s search index. In this blog post, we will create a custom web part that utilizes the Search API to retrieve and display the most recently modified documents matching specific keywords.

Our tool of choice for developing custom SharePoint Online web parts is the SharePoint Framework (SPFx). We will write our web part in TypeScript and use ReactJS for the front-end. To follow along, ensure you have administrative access to your SharePoint Online and Office 365 environment.

Here’s our roadmap:

  1. Setup the Development Environment
  2. Create a New SharePoint Framework Solution
  3. Develop the Web Part
  4. Deploy and Test the Web Part

Step 1: Setup the Development Environment

Firstly, we need to setup our development environment. This involves installing Node.js, Yeoman SharePoint generator, and Gulp. You can install these dependencies with the following commands:

npm install -g yo gulp
npm install -g @microsoft/generator-sharepoint

Step 2: Create a New SharePoint Framework Solution

After setting up the environment, navigate to the folder where you want to create the solution and run the following command:

yo @microsoft/sharepoint

When prompted:

  • For the solution name, enter “DocumentSearchWebPart”
  • Choose “Use the current folder” for where to place the files
  • Choose “Y” to allow tenant admin to deploy the solution to all sites immediately
  • Choose “N” for unique permissions to access web APIs
  • Choose “WebPart” as the component type
  • For the web part name, enter “DocumentSearch”
  • For the description, enter “A web part that displays recently modified documents based on search keywords”
  • For the framework, choose “React”

Step 3: Develop the Web Part

After creating the solution, navigate to the src/webparts/documentSearch/components/DocumentSearch.tsx file. This is where we’ll write the code to fetch and display documents from the SharePoint Search API.

import * as React from 'react';
import { IDocumentSearchProps } from './IDocumentSearchProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
export interface IDocumentSearchState {
  results: any[];
}
export default class DocumentSearch extends React.Component<IDocumentSearchProps, IDocumentSearchState> {
  constructor(props: IDocumentSearchProps) {
    super(props);
    this.state = {
      results: []
    };
  }
  public componentDidMount() {
    const keywords = 'your-keywords'; // replace this with your keywords
    this.props.context.spHttpClient.get(`${this.props.context.pageContext.web.absoluteUrl}/_api/search/query?querytext='FileType:docx+AND+${escape(keywords)}'&sortlist='LastModifiedTime:descending'&rowlimit=10`, SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => {
        return response.json();
      })
      .then((json) => {
        this.setState({ results: json.PrimaryQueryResult.RelevantResults.Table.Rows });
      });
  }
  public render(): React.ReactElement<IDocumentSearchProps> {
    return (
      <div>
        {this.state.results.map((result, index) => {
          const cells = result.Cells.map((cell) => {
            return cell.Value;
          });
          return (
            <div key={index}>
              <h3>{cells.Title}</h3>
              <p>Last Modified: {new Date(cells.LastModifiedTime).toLocaleString()}</p>
              <a href={cells.Path}>Open Document</a>
            </div>
          );
        })}
      </div>
    );
  }
}

Here, we’re making a GET request to the SharePoint Search API, passing our query text and sort order as parameters. The query text includes the file type (docx in this case) and our search keywords, and we’re sorting the results by Last Modified Time in descending order, which will give us the most recently modified documents first. We’re limiting the results to the top 10.

Step 4: Deploy and Test the Web Part

Finally, we will deploy and test our web part.

To bundle the web part, run the following command:

gulp bundle --ship

And to package the solution:

gulp package-solution --ship

These commands create a .sppkg package in the sharepoint/solution folder. Upload this package to the SharePoint App Catalog. You can now add the web part to a page by editing the page and clicking the ‘+’ button to add a new web part.

And there you have it, a custom SharePoint Online web part that utilises the SharePoint Search API to display the most recently modified documents that match specific keywords. You can further customise this web part as needed. Happy coding!

June 4, 2023by Luke

Recent Posts

  • Mastering SharePoint Online REST APIs A Step-by-Step Guide
  • Building SharePoint Online Remote Event Receivers for Document Review Flows
  • Working with SharePoint Online REST Search API 101
  • Using the SPO Search REST API to create a Webpart showing Recently Modified Documents containing specific keywords
  • Creating a Custom SharePoint Online Webpart to Display Contact Details with Photos

Categories

  • Development
  • Latest
  • Patching
  • SharePoint
  • Testing
  • Tools

“I believe in doing what you enjoy, what drives you, what keeps you coming back for more. Code is life! Well it at least it pays the bills and lets me blog about it in my spare time!”

© 2019 copyright lukeosborne.dev // All rights reserved // Privacy Policy