DEV Community

Jaime López
Jaime López

Posted on • Originally published at intranetfromthetrenches.substack.com

Technical dive for Implementing Blockchain for Shipment Management in SharePoint

Embark on a journey where innovation meets real-world application! This post delves into the realm of integrating blockchain into SharePoint, demystifying its simplicity through a practical case. Picture a global company specializing in NBA shirt sales, our focal point today, grappling with the intricacies of shipments and deliveries. This scenario serves as a tangible example to unravel the role of blockchain in SharePoint amidst everyday business challenges.

This marks the second part, exploring the intricate technical aspects of the solution. Meanwhile, the initial segment, titled Implementing Blockchain for Shipment and Delivery Management in SharePoint, offers a comprehensive view of the business side and solution. We hope you find both segments enlightening!

This exploration is not just for tech enthusiasts; it's an invitation to witness the magic of technological simplification.

The article is divided into three parts, breaking down the data layer, the API layer, and the implementation of the business layer in Azure Logic Apps. Gain a comprehensive view with the accompanying technical diagram.

Technical blueprint diagram of the solution

Data layer

The app data resides in SharePoint Online, requiring three lists: shipments, deliveries, and an event log capturing creation, modification, and deletion events for both. Essentially, this last list functions as our blockchain storage.

The Shipment Information list handles shipment management, featuring custom columns alongside standard SharePoint Online columns:

  • Shipment ID records the shipment identifier.
  • Shipment Date designates the shipment's scheduled date.
  • Shipment Information captures additional details about the shipment.

 raw `Shipment Information` endraw  list

The Delivery Details list manages delivery content and includes custom columns alongside standard SharePoint Online columns:

  • Delivery ID records the delivery identifier.
  • Delivery Date designates the scheduled delivery date.
  • Shipment ID records the associated shipment identifier, linking to the corresponding shipment record.
  • Recipient Information captures additional details about the delivery.

 raw `Delivery Details` endraw  list

Finally, the list that will be the store of our blockchain is called Event Tracking Information and, apart from the standard SharePoint columns, it has the following custom columns distributed in 2 types of content:

  • For the Shipment Block Event content type:
    • Shipment ID,
    • Shipment Date,
    • Shipment Author,
    • Record Creation,
    • Block Hash
  • For the Delivery Block Event content type:
    • Delivery ID,
    • Delivery Date,
    • Shipment ID,
    • Delivery Author,
    • Record Creation,
    • Block Hash

Finally, the list designated as our blockchain repository is named Event Tracking Information. In addition to standard SharePoint columns, it includes the following custom columns distributed across two content types.

For the Shipment Block Event content type: Shipment ID, Shipment Date, Shipment Author, Record Creation, and Block Hash.

For the Delivery Block Event content type: Delivery ID, Delivery Date, Shipment ID, Delivery Author, Record Creation, and Block Hash.

 raw `Event Tracking Information` endraw  list settings

API Layer

The API layer implementation in this exercise is straightforward. It consists of a single function developed in Azure Functions using Node.js as the engine for executing functionality.

Below, you'll find the source code for the function, allowing you to observe its simplicity despite being packed with validations and log messages.

const crypto = require("crypto");
const { app } = require('@azure/functions');

const secret = 'YOUR SECRET HERE';


function getSourceParameterNotFoundBodyAnswer() {
    return {
        jsonBody: {
            message: 'source parameter must be provided'
        },
        status: 400
    };
}


app.http('generateHashFromText', {
    methods: ['post'],
    route: 'hash/text',
    authLevel: 'anonymous',
    handler: async (request, context) => {
        try {
            context.log(`Http function processed request for url "${request.url}"`);
            
            context.trace(`Obtaining body parameters...`);
            
            // Checking if there is something in the body content...
            if(request.body === undefined || request.body === null) {
                context.warn(`No body parameters have been provided.`);
                return getSourceParameterNotFoundBodyAnswer();
            }

            // Checking if there is something in the body out of being empty...
            const bodyContent = await request.body.getReader().read();
            if(bodyContent.value.length === 0) {
                context.warn(`No body parameters have been provided.`);
                return getSourceParameterNotFoundBodyAnswer();
            }

            // Reading source parameter from the body
            const body = JSON.parse(new TextDecoder().decode(bodyContent.value));
            const source = body.source;

            if(source === undefined || source === null || source === '') {
                context.info(`source query parameter not found.`);
                return getSourceParameterNotFoundBodyAnswer();
            }

            context.info(`source query parameter value: ${source}`);

            // Doing the hash to the source parameter content...
            context.trace(`Do the hash for source value...`);
            const hasher = crypto.createHmac("sha256", secret);
            const result = hasher.update(source).digest('hex');

            context.trace(`Hash obtained is ${result}`);

            // Returning the hash....
            return {
                jsonBody: {
                    hash: result,
                    source: source,
                },
                status: 200
            };
        }
        catch(err) {
            context.error(`An unknow error has ocurred: ${err}`);
            return {
                jsonBody: {
                    err: err
                },
                status: 500
            };
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

Azure Logic Apps and Custom Connector

Custom connector configuration

The setup of the Custom Connector is straightforward. After implementing the API, adding the relevant information is all that's required. If you're acquainted with OpenAPI or Swagger, this process is intuitive. For those unfamiliar, Microsoft's guide, Create a custom connector from scratch, provides step-by-step instructions. Pay attention to the settings in the third step, which become visible when you select it as an action during the deployment of Azure Logic Apps.

Step 3 of the Custom Connector configuration

When a new Shipment is created in Azure Logic Apps

I'd like to walk you through the implementation details of a specific Azure Logic App—specifically, the one triggered after a new item is submitted. The rest of the Azure Logic Apps work in a similar way but with the corresponding trigger for modification and deletion.

The implementation unfolds in six phases, each with a distinct and detailed objective.

Azure Logic Apps On Shipment Creation Event

1. The trigger

The trigger is set up to identify any newly created item in the Shipment list within SharePoint Online. It's a straightforward process where we simply specify the SharePoint Online site and choose the relevant list.

Phase 1 - SharePoint Online Trigger

2. Variable initialization

I want to underscore the significance of establishing these two stream variables. Initially, to preserve the hash of our blockchain's latest block, we initialize a variable named LatestBlockHash. Given that hashes are alphanumeric, we set its type to string. The default value is set to 0, serving as the hash for the genesis block or the chain's first block in case no blocks exist yet.

Conversely, we also initialize the ShipmentBlockHash variable, also of type string, to store the hash of the upcoming block. This variable guides us throughout the process and provides a traceable record of the value generated at each stage if needed.

Phase 2 - Variable set up

3. Get the latest block hash

At this stage, we navigate to our repository housing the blockchain to fetch the latest block and consequently, obtain the value of the property where its hash is stored. Our blockchain resides in a SharePoint Online list, and that's where we retrieve the latest block.

As illustrated in the image, we utilize the action to fetch items from the SharePoint Online list. We specify the site and list, and for enhanced performance, we arrange the items based on the creation date column, ordered from newest to oldest. Additionally, we opt to retrieve only one item, streamlining the process for the system to efficiently return the desired item.

Following this, we assign the value of the Block Hash column to the LatestBlockHash variable, initialized earlier, enabling its incorporation into the new block.

Phase 3 - Obtaining the latest block hash

4. Generate the shipment block

This step is straightforward; we only need to provide the necessary information to our Custom Connector. As mentioned earlier, Azure Logic Apps lacks an action to generate a hash value. Hence, we've created an API to fulfill this need and configured an Azure Logic Apps Custom Connector for its utilization.

The text string we transmit to generate a new block comprises the properties of the created Shipment and the hash value of the last block in the blockchain. The configuration of the source parameter in the Custom Connector is outlined below:

concat('Shipment#;#',triggerBody()?['Shipment_x0020_ID'],'#;#',triggerBody()?['Shipment_x0020_Date'],'#;#',triggerBody()?['Author']?['Email'],'#;#',triggerBody()?['Created'],'#;#',variables('LatestBlockHash'))
Enter fullscreen mode Exit fullscreen mode

Commencing with the text string 'Shipment' for block type identification, the following parameters consist of the ID field, shipment date, SharePoint item creator, item creation date, and ultimately, the hash of the last blockchain block. The string '#;#' functions as a separator for these values.

Following that, we assign the generated hash value to the ShipmentBlockHash variable.

Phase 4 - Generation of the new hash

5. Add block event to the blockchain list

By utilizing the function to append a new item to a SharePoint Online list, we store our recently created block, capturing the transaction, such as the initiation of a new shipment in this instance.

The setup is straightforward; we commence by designating the SharePoint Online site and the list associated with the event log. Subsequently, we input the appropriate values into the corresponding fields. Notably, the Block Hash field is of particular importance, as it receives the freshly generated hash from the preceding stage, stored in the ShipmentBlockHash variable.

Phase 5 - Adding the new block to the blockchain

6. Notification

The final stage is discretionary. In my scenario, I opted to dispatch an email to the administrator whenever a block is generated, serving as a notification for the completed activity. Alternatively, this step can be substituted with any other form of notification or annotation within another system, or it can be omitted from the workflow entirely.

Phase 6 - Notification

Conclusion

I trust that engaging in this exercise has sparked inspiration for various ideas as you reflect on its content. The underlying objective is to explore diverse technologies, understand their potential, and gain hands-on experience. Through this process, my aim is to share these insights with you, not only as a record of experimentation but also as a source of encouragement for your own ventures and explorations in the realm of technology and innovation.

By delving into this exercise, we open doors to new possibilities and discoveries. It's a testament to the spirit of experimentation, demonstrating the potential of blending different technologies. As we navigate through these technical intricacies, the ultimate goal is not only to showcase what's achievable but also to inspire a community of enthusiasts, encouraging them to embark on their unique journeys of exploration and technological experimentation.

References

Top comments (0)