Technical Articles
How to use the Document Repository Service in your UI5 app
Introduction
I used the Document Repository Service in the FaceRecognition app: https://blogs.sap.com/2019/05/28/face-recognition-app/
During the developments of this app, I never new if the upload of an image was succefull or not. There is no visual tool to validate this. Therefore, I created the “Document Repository Viewer”. It’s a very small UI5 app to view what’s in your Document Repository: https://blogs.sap.com/2019/07/29/document-repository-viewer/
The code in this app is simple but it was hard to get there. There is not much documentation on how to implement this in a UI5 app. The only thing I found was this: https://help.sap.com/viewer/b0cc1109d03c4dc299c215871eed8c42/Cloud/en-US/ee63e43b719e4e5e94ad3fdbe84cc73f.html
A basic html page that show a list of documents and an upload function. But how to delete an image? And what if you want to upload a document via a custom http ajax request instead of a generated form request?
Therefore, I will share and explain the code that I’ve used behind the “Document Repository Viewer”.
I’m going to start from the beginning, from enabling to Document Repository Service till explaining the UI5 code. Just for the completeness of the blog post so everyone will be able to try it:
- Activate the Document Repository Service
- Install the Proxy Bridge
- Destination
- UI5 Code
Compared to the blog of Sharaha K, I’m only using the Proxy Bridge: https://blogs.sap.com/2019/05/08/sap-cloud-platform-document-services-upload-files-from-fiori-application/ |
Activate the Document Repository Service
Activate the Document Service in you SCP account:
Go to Services and search for Document Service. This should be enabled by default, otherwise you need to enable it yourself.
Once it’s active (normally this is active by default), you’ll can open it directly from “Document Repositories”:
Create a repository:
And fill in all the details. Note down the Repository Key, you’ll need it later:
Install the Proxy Bridge
Build a Proxy Bridge like explained in SAP Help:
Deploy this Proxy Bridge on your SCP account by using the Eclipse tools or directly in the SCP Cockpit:
Destination
Create a destination to access the proxy bridge in the UI5 app in SCP and SAP Web IDE.
Name=documentservicewl URL=https://cmisproxysaps0007914286trial.hanatrial.ondemand.com ProxyType=Internet Type=HTTP Authentication=BasicAuthentication Description=Connection to Proxy Bridge App Wouter Lemaire User=wouter.lemaire@flexso.com Password=xxxx |
UI5 code
Setup
Start with a UI5 template in SAP Web IDE. I started with the basic template but any other will also work:
Add the configuration to the destination to the “neo-app.json”:
,{
"path": "/cmisproxysap",
"target": {
"type": "destination",
"name": "documentservicewl",
"entryPath": "/cmisproxysap"
},
"description": "CMIS Connection Document Service"
}
In case you are using a different name for the destination, then you need to change the property “name”.
For all my http requests to the Proxy Bridge I’m using “XMLHttpRequest” which I wrapped into promises. This is very generic and done in the UI5 object “HTTPService”. I’m not going to explain in detail but you can always look at the code here: https://github.com/lemaiwo/DocumentRepositoryViewer/blob/master/webapp/service/HTTPService.js
This generic HTTPService is being used by the object RepoService, which is a short name for Repository Service. In the RepoService are all the requests related to the Repository Document Service: https://github.com/lemaiwo/DocumentRepositoryViewer/blob/master/webapp/service/RepoService.js
Get repository id
Before we can read the data from the repository or do anything else, we need the repository id. This id is needed for any action on the repository because it’s part of the root url.
To know this, you open the Proxy Bridge and add the following
/cmisproxysap/cmis/json
Like this:
https://cmisproxysaps0007914286trial.hanatrial.ondemand.com/cmisproxysap/cmis/json
This will give you all the details of your repository:
This should be dynamic in the app, so it shouldn’t be changed for every new repository. Therefore, I’ve added the following two functions in the RepoService:
getRepoId: function () {
if (this.RepoId) {
return Promise.resolve(this.RepoId);
}
return this.getRepoInfo().then(function (info) {
for (var field in info) {
this.ReposId = info[field].repositoryId;
break;
}
return this.ReposId;
}.bind(this));
},
getRepoInfo: function () {
return this.http("/cmisproxysap/cmis/json").get();
}
“getRepoInfo” will get all the information of the repository. The “getRepoId” will use “getRepoInfo” but only returns the Repository id and store it in RepoService. This will avoid that the app will need to fetch this id again for each action. The Repository id normally doesn’t change.
Reading all the documents
Reading all the files from the Repository Document service was the easiest one. This is just a HTTP GET request to the root of the repository. You only need to know the root url to the repository…
The root url exists out of the same part as the repository information together with the repository id followed by root:
/cmisproxysap/cmis/json/<ReposId>/root/
In the RepositoryService, there is a function getFiles which will first get the repository id and use this id to get all the files on root level. This will give a list of all files.
getFiles: function () {
return this.getRepoId().then(function (ReposId) {
return this.http("/cmisproxysap/cmis/json/" + ReposId + "/root/").get();
}.bind(this));
},
Upload document
The upload function is based on the example html snippet from the documentation. This is now converted to pass all the properties as formdata in an HTTP Ajax request instead of via a form submit action.
The uploaded file object is wrapped into a FormData object together with some other properties:
- Cmisaction: defines what you what to do, we want to create a new document -> “createDocument”
- Objecttypeid: the type that it needs to create, can be document or folder
- Name: the name of the file.
This formdata can then be posted to the same path as for reading all the documents. Again, this needs the repository id and will use the getRepoId function. (this function will cache the repositoryid and won’t send the request twice but use the cached id instead)
uploadFile: function (file) {
var form = new FormData();
form.append("datafile", file);
form.append("cmisaction", "createDocument");
form.append("propertyId[0]", "cmis:objectTypeId");
form.append("propertyValue[0]", "cmis:document");
form.append("propertyId[1]", "cmis:name");
form.append("propertyValue[1]", file.name);
return this.getRepoId().then(function (ReposId) {
return this.http("/cmisproxysap/cmis/json/"+ReposId+"/root").post(false, form);
}.bind(this));
},
Delete document
This one is probably the easiest, but it was the hardest to find! Deleting a document requires the full path to that document with the cmisaction delete. Finding the action “delete” took me a lot of time. In the cmis documentation I found the action “deleteDocument”. Delete was just a lucky guess ?
Again, this needs the repository id.
deleteFile: function (name) {
var form = new FormData();
form.append("cmisaction", "delete");
return this.getRepoId().then(function (ReposId) {
return this.http("/cmisproxysap/cmis/json/"+ReposId+"/root/" + name).post(false, form);
}.bind(this));
},
Controller
Now, this RepoService is ready to use in the controller. Define the RepoService at the top of the controller and start using it.
Load the files and convert them to the format that you like: (The Document Repository Service uses property names that are not easy to use in your UI5 bindings. Therefor, I converted them to something that’s easier to understand and use.)
var result = await RepoService.getFiles();
var files = result.objects.map(file => ({
name: file.object.properties["cmis:name"].value,
id: file.object.properties["cmis:objectId"].value,
isImage: file.object.properties["cmis:contentStreamMimeType"].value.indexOf("image") > -1 ? true : false
}));
this.getView().setModel(new JSONModel({
files: files
}), "repo");
return files;
Upload the file and update the list so the newly uploaded file will show up:
var file = oEvent.getParameter("files")[0];
// RepoService.uploadFile(file).then(() => this.loadFiles());
await RepoService.uploadFile(file);
await this.loadFiles();
Same for delete:
//RepoService.deleteFile(oEvent.getSource().getBindingContext("repo").getProperty("name")).then(() => this.loadFiles());
await RepoService.deleteFile(oEvent.getSource().getBindingContext("repo").getProperty("name"));
await this.loadFiles();
In the code examples in the controller I used Async and Await but also with arrow functions in comment. In both cases you’ll need to change it to “old school JS” or use a transpiler.
You’re ready to use the RepoService in your own project!
The full code example is available on GitHub: https://github.com/lemaiwo/DocumentRepositoryViewer
Kr, Wouter
Thank you so much, your tutorial is very useful.
Hi,
Can you tell me how can i change permissions of certain users to read, write, delete a file.For example - user 1 can do all activites but user2 can just read the file