Nextcloud supports several techniques as an auth provider:
For our current purpose we should focus on OAuth2/OIDC, as we want our OpenProject backend to work as a client to the nextcloud server. Besides tunneled requests from the browser with the OP frontend, we also want to make server to server request to e.g. fetch meta data of our file references.
Those are the facts about the nextcloud server as an OAuth2 provider:
The following BASH script contains a number of "curl" calls to the Nextcloud API in order to validate a basic synchronization algorithm.
#!/usr/bin/bash
# OpenProject -> Nextcloud Sync Algorithm:
#
# We represent OpenProject project membership by sharing the project folder
# with the respective users or groups in Nextcloud:
#
# Go through the list of OpenProject Projects:
# Identify the project folder below the OpenProject root in Nextcloud
# Create a project folder (using WebDAV Folder API) if it doesn't exist yet
# Go through the list of OpenProject project members (groups an users from LDAP)
# and their permissions and compare with Nextcloud shares
# Create a new Nextcloud share for the user or group if necessary
# Delete an old NC share if not in OpenProject
#
# Synchroneous operation (as part of the GUI):
# New project: Sync the new project
# New project member: Just sync the specific share
#
# Special cases:
# New group member in LDAP:
# This could be an issue in the case of a new employee
# because both systems need to be synced with LDAP.
# Implement getting/setting of "Advanced Permissions" (ACL) via OCS API #1256
# https://github.com/nextcloud/groupfolders/issues/1256
# - Managing
# -------------------------------------------------------
# Run Nextcloud OCC CLI commands
# Taken from nextcloud-link - Node.js interface for Nextcloud including Group Folders
# From: https://github.com/tentwentyfour/nextcloud-link/blob/master/tests/groupfolders-jest.ts
#
# docker exec -u 33 -it integration_openproject_nc bash -c 'php occ list'
# docker exec -u 33 -it integration_openproject_nc bash -c 'php occ app:install groupfolders'
# -------------------------------------------------------
# Get the list of users:
curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/ocs/v1.php/cloud/users'
# {"ocs":{...},"data":{"users":["admin","user1","user2","user3"]}}}
# Get detailed information about one user:
curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/ocs/v1.php/cloud/users/admin'
# {"ocs":{...},"data":{"enabled":true,"storageLocation":"\/var\/www\/html\/data\/admin","id":"admin","email":"admin@example.com","displayname":"admin","groups":["admin"],"language":"en", ...}}}
# -------------------------------------------------------
# Capabilities API:
curl -u admin:admin -X GET -H "OCS-APIRequest: true" -H 'Accept: application/json' 'http://localhost/ocs/v1.php/cloud/capabilities'
# {"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"version":{"major":23,"minor":0,"micro":2,"string":"23.0.2","edition":"","extendedSupport":false}, ...}
# -------------------------------------------------------
# Group Folders API:
# Not working:
# curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/ocs/v2.php/apps/groupfolders/folders'
# Not working:
# curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/ocs/v2.php/apps/groupfolders/folders/1'
# Working:
# curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/ocs/v2.php/apps/activity/api/v2/activity'
# Get the list of group folders (working):
# curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/index.php/apps/groupfolders/folders'
# {"ocs":{"meta":{...},"data":{"1":{"id":1,"mount_point":"My Group Folder","groups":{"Test Group":31,"admin":31},"quota":-3,"size":0,"acl":true,"manage":[{"type":"group","id":"admin","displayname":"admin"}]}}}}
# Get details for one folder (working):
curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/index.php/apps/groupfolders/folders/1'
# {"ocs":{"meta":{...},"data":{"id":1,"mount_point":"My Group Folder","groups":{"Test Group":31,"admin":31},"quota":-3,"size":0,"acl":true}}}
# Not Working (error page):
curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -H "Content-Type: application/json" \
# -X POST 'http://localhost/index.php/apps/groupfolders/folders' --data-raw '{"mount_point":"My Group Folder 2"}'
# Group Folders set ACL (not working):
curl -u admin:admin -X POST -H "OCS-APIRequest: true" -H 'Accept: application/json' 'http://localhost/index.php/apps/groupfolders/folders/1/acs' --data-raw '{"acl":0}'
curl -u admin:admin -X POST -H "OCS-APIRequest: true" -H 'Accept: application/json' 'http://localhost/index.php/apps/groupfolders/folders/1/acs' --data-raw '{"acl":"0"}'
curl -u admin:admin -X POST -H "OCS-APIRequest: true" -H 'Accept: application/json' 'http://localhost/index.php/apps/groupfolders/folders/1/acs' --data-raw '{"acl":"false"}'
curl -u admin:admin -X POST -H "OCS-APIRequest: true" -H 'Accept: application/json' 'http://localhost/index.php/apps/groupfolders/folders/1/acs' --data-raw '{"acl":false}'
# Check if acs:true still set in folder info
curl -u admin:admin -H "OCS-APIRequest: true" -H 'Accept: application/json' -X GET 'http://localhost/index.php/apps/groupfolders/folders/1'
# -------------------------------------------------------
# WebDAV Protocol for Nextcloud:
# https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/basic.html
# Get the list of files for user admin in user's home directory
curl -u admin:admin -X PROPFIND 'http://localhost/remote.php/dav/files/admin/' | xml_pp
# Get the list only for Depth=1
curl -u admin:admin -X PROPFIND -H "Depth: 1" 'http://localhost/remote.php/dav/files/admin/' | xml_pp
# List directory with specific attributes with proper XML namespaces
curl -u admin:admin -X PROPFIND \
-d '<?xml version="1.0"?><d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"><d:prop><d:getlastmodified />' \
'http://localhost/remote.php/dav/files/admin/'
# List directory with specific attributes with abbreviated namespaces
curl -u admin:admin -X PROPFIND \
-d '<d:propfind xmlns:d="DAV:"><d:prop><d:getlastmodified /></d:prop></d:propfind>' \
'http://localhost/remote.php/dav/files/admin/' | xml_pp
# Download a file
curl -u admin:admin -X GET 'http://localhost/remote.php/dav/files/admin/Nextcloud.png' --output Nextcloud.png
# Create a new folder
curl -u admin:admin -X MKCOL 'http://localhost/remote.php/dav/files/admin/TestFolder'
# Upload same file with different name
curl -u admin:admin -X PUT 'http://localhost/remote.php/dav/files/admin/TestFolder/Nextcloud2.png' --upload-file Nextcloud.png
# -------------------------------------------------------
# Nextcloud Shares API:
# https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
# Get the list of all shares for a given user:
curl -u admin:admin -H 'Accept: application/json' -H 'OCS-APIRequest: true' http://localhost/ocs/v2.php/apps/files_sharing/api/v1/shares
# {"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[
# {"id":"2","share_type":0,"uid_owner":"admin","displayname_owner":"admin","permissions":19,"can_edit":true,"can_delete":true,"stime":1646926576,"parent":null,"expiration":null,"token":null,"uid_file_owner":"admin","note":"","label":null,"displayname_file_owner":"admin","path":"\/test.txt","item_type":"file","mimetype":"text\/plain","has_preview":true,"storage_id":"home::admin","storage":2,"item_source":348,"file_source":348,"file_parent":6,"file_target":"\/test-user1.txt","share_with":"user1","share_with_displayname":"User1","share_with_displayname_unique":"user1@example.com","status":{"status":"offline","message":null,"icon":null,"clearAt":null},"mail_send":0,"hide_download":0},
# {"id":"1","share_type":3,"uid_owner":"admin","displayname_owner":"admin","permissions":17,"can_edit":true,"can_delete":true,"stime":1646923228,"parent":null,"expiration":null,"token":"KDSfefYx8cycGoG","uid_file_owner":"admin","note":"","label":"","displayname_file_owner":"admin","path":"\/Photos\/Readme.md","item_type":"file","mimetype":"text\/markdown","has_preview":true,"storage_id":"home::admin","storage":2,"item_source":29,"file_source":29,"file_parent":28,"file_target":"\/Readme.md","share_with":null,"share_with_displayname":"(Shared link)","password":null,"send_password_by_talk":false,"url":"http:\/\/localhost\/s\/KDSfefYx8cycGoG","mail_send":0,"hide_download":0}
# ]}}
This pagee contains some usefule information about the development process in this project.
... and when to use them
used for most functional increments built for the project
must be written with acceptance criteria to be testable by QA
usually is QAed by OpenProject
used for everything that does not work as expected and defined
must NOT be used for things that do not work but were not defined before
used as smaller, easier to review and merge chunks that are part of a bigger feature
developers could slice down every FEATURE or BUG into IMPLEMENTATION chunks to structure work and enable parallelization
is not QAed by OpenProject
Using a docker development environment is strongly suggested, due to the very restrictive methods of installing a Nextcloud instance natively. The only way is installing a web server natively and making the Nextcloud repository readable from within the web server directory, including several owning rights configurations.
To install docker on your system, please follow the instructions provided by docker itself. You'll need docker-compose, too.
After installing docker, clone the repository and follow the instructions in the README. After running the docker-compose, a nextcloud instance will be launched at http://localhost:8210 with some seeded users. The admin user is admin:admin.
There are alternatives to run containers in virtual environments on linux, like podman if you prefer a non-root executing tool.
There is already an integration app for OpenProject available in nextcloud. To enable it, follow the step described here
Hint: This guide only enables the link with a users API key. It is also possible to connect to an OAuth2 provider app configured in OpenProject. The settings to do so are located in nextcloud "Settings > Administration > Connected Accounts".
I've got Nextcloud running based on the Docker installation as described in the GitHub page: https://github.com/nextcloud/integration_openproject
The instructions more or less work, but there were a few issues. Please see my quick notes ("OpenProject_Nextcloud_YYYY_MM_DD.odp") attached below for the corrections.
In particular these notes include the fixes to the Nextcloud PHP code to make the Nextcloud -> OP integration work (thank to Wieland!).
Considerations about files and fileIds in Nextcloud to keep in mind
item here means files or folder
OCP\Filles\Folder::getById() he will receive two objects and in case he renamed one of the representations of the file both of the objects will show different namesJulien approves all above statements.
At any point, we will want to implement an upload mechanism in our nextcloud integration. Uploads with the Nextcloud API need logic in the frontend, especially for uploading folders or big files that need chunking.
Nextcloud has a very restrictive CORS policy, forbidding sending requests to the API from browsers, that are not same origin. For the upload, this will be necessary, as mentioned above. The proposed solution is, using the nextcloud extension WebAppPassword to whitelist additional domains to the CORS policy. In a succeeding step we can check the code of the WebAppPassword , to reimplement the configuration of whitelisted domains to eliminate the need of manual configuration.
As the authentication is done by the backend (see explanation), the question remains, how the frontend would authenticate an upload request. Here nextcloud's app passwords could solve the issue. Those are generated, permanent passwords, that can be used together with this user's name in a request.
openfile=0 the viewer will not open, available in Nextcloud 24 (April)Single file and folder uploads to nextcloud all go over the webdav API of the nextcloud server. For standard use cases like downloading and uploading, the API is pretty straight forward. When it comes to upload larger files, nextcloud provides a chunking API.
An edge instance of OpenProject can be found here. This instance is temporarily available for testing the integration and reading the API docs.
A rendered version of the OpenAPI specification of OpenProject can be found here. This specification is updated together with the whole edge instance, whenever the development branch of OpenProject is pushed. Hence the specification documentation represents the development state of the API.
There are further instructions readable at the page itself, like how to download the spec file.
The relevant endpoints are all grouped under the File links tag.
If needed, we can provide user accounts for every developer on that instance. We can also provide admin rights for those accounts, as those will be necessary to create the storage objects, the representer of the nextcloud instance on OP side. To interact with the work packages and projects and seeing the file links, no admin rights are necessary.
HINT: The implementation is not yet evolved enough to actually test it on the edge environments. This is up to be announced in the jour fixes meetings.
Summarizes the work that was done to create a working hypothesis and some technical background for the Nextcloud integration.
When to start - entry criteria?
When is the next release?
Stable process for Nextcloud version bumps
Release preparation
What steps are taken, who is doing what?
Timelines and Timeframes
QA process
How is giving the green light?
How is doing and communicating with whom?
Release - exit criteria
When is the final release?
Have a checklist to know what conditions need to be met.
After release
Handing over process
Communication, who to ping
When to start a release - entry criteria?
External reasons
Nextcloud Major version release
Have it released between 4 to 2 weeks before Nextcloud release
Have version bump released with other Bugs or Features id possible
If not a NC version bump in the release is a patch release
Dependencies change or break
Security issues
Do not create a work package in the a public accessible project
Release as soon as possible
Internal reasons
Features is finished
No hard rules and based on strategy.
Normally features/epics should be released within 2 weeks.
Bugs are fixed
Release preparation
What steps are taken, who is doing what?
Version should have been already created in OpenProject before, if not create one (Dominic)
Query should have been already created in OpenProject in the Nextcloud project beforehand and mark it as favorite, if not create one (Dominic)
Mage sure all work package are assigned to the version (Dominic)
Announce planned release to team (Product owner - Dominic)
Create work package for release. (Or template project for release) (Dominic)
Create branch if needed in GitHub (Sajan)
Change deployment target if needed on QA deployment script (DevOps)
Add change logs (Sajan)
Tag version in Github (Sajan)
Ping QA (Cécile) that release is ready for testing (Sajan)
Timelines and Timeframes
QA process
How is giving the green light?
How is doing and communicating with whom?
Release - exit criteria
When is the final release?
After release
OpenProject -> Nextcloud integration sequence diagram:
This diagram shows the control flow starting off with a user visiting a OpenProject page with an embedded WebDAV client to actually showing the results, for example a directly list via WebDAV.
This is the Wiki for the Nextcloud integration project.