Skip to Content
Technical Articles

Integrating SAP Document Management in CAP Application

Previous Post

In the previous blog post, I’ve shown how to create a basic ui5 app and integrated it with document management reuse ui.

https://blogs.sap.com/2020/10/22/integrating-sap-cp-document-management-service-ui-in-the-fiori-app/

 

This Blog Post

Now in this blog post, I will show a simple use case of integrating document management service with your CAP Based UI5 app.

We will reuse most of the stuff that was created from the previous blog like repositoryId, service instance name..,

 

Final Application Demo

 

GIT Repo URL

https://github.com/mahesh0431/CommunityDMCAPApp

Steps:

Step 1: Create a CAP Application in the CAP Space using Business Application Studio.

There are lot of tutorials to create a CAP Application, so I am skipping that part.

Just create a basic CAP app with one entity. and use the GIT Repo that I mentioned earlier to adjust any missing code. I will now only add the information that is only needed to show the Document Management Reuse UI in a CAP App.

 

I generated the CAP app by selecting the below options.

 

Then delete the data folder in the db folder.

Open the data-model.cds and add repositoryId and folderId. Then change the entity to UUID based as shown below.

namespace my.bookshop;
using { managed ,cuid} from '@sap/cds/common';

entity Books: cuid,managed {
  booknumber : Integer;
  title  : String;
  stock  : Integer;
  repositoryId : String;
  folderId: String;
}

Now update the srv/cat-service.cds by removing the “@readonly”.

using my.bookshop as my from '../db/data-model';

service CatalogService {
    entity Books as projection on my.Books;
}

Add index.cds file to srv folder and add the below content.

using {CatalogService as my} from './cat-service';

annotate my.Books with @odata.draft.enabled;
 
annotate my.Books with @(UI : {
    SelectionFields  : [ booknumber, title ],
    LineItem         : [
    {
        Value : booknumber,
        Label : 'ID'
    },
    {
        Value : title,
        Label : 'Title'
    }
    ],
    Facets           : [{
        $Type  : 'UI.CollectionFacet',
        ID     : 'General',
        Label  : 'Book Info',
        Facets : [{
            $Type  : 'UI.ReferenceFacet',
            Target : '@UI.FieldGroup#Main',
            Label  : 'Main Facet'
        }]
    }],
    FieldGroup #Main : {Data : [
    {Value : booknumber},
    {Value : title}
    ]}
});

Now create cat-service.js file in the srv folder and add below code. I’ve added enough comments to understand the business logic here.

const cds = require('@sap/cds')
const axios = require('axios').default;
const FormData = require('form-data');

const VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES);
// Access the sdm credentials (Document management, Integration option instance)
const sdmCredentials = VCAP_SERVICES.sdm[0].credentials

const _fetchJwtToken = async function (oauthUrl, oauthClient, oauthSecret) {
    // This is to get the oauth token , which is used to create the folder ID
    return new Promise((resolve, reject) => {
        const tokenUrl = oauthUrl + '/oauth/token?grant_type=client_credentials&response_type=token'
        const config = {
            headers: {
                Authorization: "Basic " + Buffer.from(oauthClient + ':' + oauthSecret).toString("base64")
            }
        }
        axios.get(tokenUrl, config)
            .then(response => {
                resolve(response.data.access_token)
            })
            .catch(error => {
                reject(error)
            })
    })
}

// This is to create a folder in the repository for every new book that is getting created.
// So basically we create a new folder for every book id and user can add their respective attachments in that folder.
const _createFolder = async function (sdmUrl, jwtToken, repositoryId, rootFolderId, forlderName) {
    return new Promise((resolve, reject) => {
        const folderCreateURL = sdmUrl + "browser/" + repositoryId + "/root"

        const formData = new FormData();
        formData.append("objectId", rootFolderId);
        formData.append("cmisaction", "createFolder");
        formData.append("propertyId[0]", "cmis:name");
        formData.append("propertyValue[0]", forlderName);
        formData.append("propertyId[1]", "cmis:objectTypeId");
        formData.append("propertyValue[1]", "cmis:folder");
        formData.append("succinct", 'true');


        let headers = formData.getHeaders();
        headers["Authorization"] = "Bearer " + jwtToken;
        
        const config = {
            headers: headers
        }

        axios.post(folderCreateURL, formData, config)
            .then(response => {
                resolve(response.data.succinctProperties["cmis:objectId"])
            })
            .catch(error => {
                reject(error)
            })
    })
}

module.exports = cds.service.impl(async (service) => {
    // This will be called whenever a new draft book is getting created
    service.before("NEW", 'Books', async (context) => {
        // Fill the repositoryId
        context.data.repositoryId = "3a6fbabb-1c19-4014-80cd-e9d4443fd311";
        const connJwtToken = await _fetchJwtToken(sdmCredentials.uaa.url, sdmCredentials.uaa.clientid, sdmCredentials.uaa.clientsecret)
        // Creating the folder id and fill it
        context.data.folderId = await _createFolder(sdmCredentials.endpoints.ecmservice.url, connJwtToken, context.data.repositoryId, "SYNsY7aoCEVirXnHScSBm3SQsSAvCy8zsAkZJjAjUE8", context.data.ID);
    });
});

In the above code, the repositoryId will be same as the one we created in the earlier blog post.

for the folderId, use the earlier post admin ui5 app and create a dummy folder (CAP Books App folder), so now to get that folderId, we need to use postman query. Highlighted is the CAP BooksApp document folder id.

query I’ve used is:

https://api-sdm-di.cfapps.eu10.hana.ondemand.com/browser/3a6fbabb-1c19-4014-80cd-e9d4443fd311/root?objectId=cec9627000c878b437e809f5&cmisSelector=children

objectId is nothing but the root folderId that we have seen in the previous blogpost.

 

Now create server.js file in srv folder, this is because we will use OData V2 service for our Fiori app.

"use strict";

const cds = require("@sap/cds");
const proxy = require("@sap/cds-odata-v2-adapter-proxy");

cds.on("bootstrap", app => app.use(proxy()));

module.exports = cds.server;

add these entries to package.json dependencies in the root folder

        "@sap/cds-odata-v2-adapter-proxy": "^1.4.48",
        "axios": "^0.20.0",
        "form-data": "^3.0.0",

Any missing things, you can refer to git hub project.

 

Step 2: Add a Fiori Element Application

Download the ui5 app(booksapp) that is the git link and paste it in the app folder, just update the appid in your manifest.json to your desired app id. Make sure you update this ide in the package.json file from app/booksapp folder.

This is basically a V2 Fiori element template application. I’ve extended the object page(added a new Facet and controller) as you can see in the below manfest.json

In the attachment fragment, i will use the component container to show the document management reuseui, as shown the previous blogpost.

The additional thing here is, I written a code to manually pass the repositoryId and folderId to the DocumentManagement UI. as shown below ( the data here is the one we created in the cap handler)

 

Step 3: Create AppRouter

let’s create a approuter folder, you can copy the package.json and xs-app.json files from the git url.

approuter/package.json

{
	"name": "approuter",
	"description": "Node.js based application router service for html5-apps",
	"engines": {
		"node": "^8.0.0 || ^10.0.0"
	},
	"dependencies": {
		"@sap/approuter": "8.5.1"
	},
	"devDependencies": {
		"@sap/html5-repo-mock": "1.6.0"
	},
	"scripts": {
		"start": "node node_modules/@sap/approuter/approuter.js"
	}
}

approuter/xs-app.json

{
    "welcomeFile": "/communitydmcapbooksapp/index.html",
    "authenticationMethod": "route",
    "routes": [
        {
            "source": "^/v2/catalog/(.*)$",
            "authenticationType": "xsuaa",
            "destination": "srv-api",
            "csrfProtection": false
        }
    ]
}

 

Step 4: Update MTA.YAML

You can refer to this section from the git project mta.yaml file for more info.

add approuter module

We will reuse the same SDM (Document Management IntegrationOption) instance here in this project in resources:

We will also add another module to get the ui5 app and to deploy it to cf.

The remaining modules and resources are pretty straightforward, which you can get from the git project.

Step 5: Deploy and Run

BUILD MTA and Deploy.

Access the approuter url

Open the URL:

 

That’s it folks, remaining part you can check the video at the top 🙂  Let me know your thoughts or any improvements needed here.

 

PS: I’ve used many of the community blogs and the one I referred mostly to do this is Mio Yasutake blog, check it out.

https://blogs.sap.com/2020/09/06/developing-a-fiori-elements-app-with-cap-and-fiori-tools/

 

Thanks

Mahesh

1 Comment
You must be Logged on to comment or reply to a post.