diff --git a/docs/api/cozy-stack-client.md b/docs/api/cozy-stack-client.md index 981d2105f..0c560e42d 100644 --- a/docs/api/cozy-stack-client.md +++ b/docs/api/cozy-stack-client.md @@ -282,6 +282,9 @@ not.

TwoFactorNeededRes
+
PermissionCollectionOptions : object
+

Options that can be passed to PermissionCollection's constructor

+
PermissionPermission

async getOwnPermissions - deprecated: please use fetchOwnPermissions instead

@@ -1762,6 +1765,7 @@ Implements `DocumentCollection` API along with specific methods for `io.cozy.per **Kind**: global class * [PermissionCollection](#PermissionCollection) + * [new PermissionCollection(doctype, stackClient, [options])](#new_PermissionCollection_new) * [.create(permission)](#PermissionCollection+create) * [.add(document, permission, options)](#PermissionCollection+add) ⇒ Promise * ~~[.findApps()](#PermissionCollection+findApps)~~ @@ -1770,6 +1774,16 @@ Implements `DocumentCollection` API along with specific methods for `io.cozy.per * [.fetchAllLinks(document)](#PermissionCollection+fetchAllLinks) ⇒ object * [.revokeSharingLink(document)](#PermissionCollection+revokeSharingLink) + + +### new PermissionCollection(doctype, stackClient, [options]) + +| Param | Type | Description | +| --- | --- | --- | +| doctype | string | Doctype of the collection (should be `io.cozy.permissions`) | +| stackClient | [CozyStackClient](#CozyStackClient) | The client used to make requests to the server | +| [options] | [PermissionCollectionOptions](#PermissionCollectionOptions) | The collection options | + ### permissionCollection.create(permission) @@ -3473,6 +3487,18 @@ Options that can be passed to NotesCollection's constructor | --- | --- | --- | | two_factor_token | string | The 2FA token | + + +## PermissionCollectionOptions : object +Options that can be passed to PermissionCollection's constructor + +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| [driveId] | string | ID of the shared drive targeted by the collection | + ## Permission ⇒ [Permission](#Permission) diff --git a/packages/cozy-stack-client/src/PermissionCollection.js b/packages/cozy-stack-client/src/PermissionCollection.js index 73a4c5b09..263a49e78 100644 --- a/packages/cozy-stack-client/src/PermissionCollection.js +++ b/packages/cozy-stack-client/src/PermissionCollection.js @@ -1,19 +1,35 @@ import DocumentCollection from './DocumentCollection' import { normalizeDoc } from './normalize' import { isFile } from './FileCollection' -import { uri } from './utils' +import { uri, sharedDriveApiPrefix } from './utils' import logger from './logger' const normalizePermission = perm => normalizeDoc(perm, 'io.cozy.permissions') +/** + * Options that can be passed to PermissionCollection's constructor + * + * @typedef {object} PermissionCollectionOptions + * @property {string} [driveId] - ID of the shared drive targeted by the collection + */ + /** * Implements `DocumentCollection` API along with specific methods for `io.cozy.permissions`. */ class PermissionCollection extends DocumentCollection { + /** + * @param {string} doctype - Doctype of the collection (should be `io.cozy.permissions`) + * @param {CozyStackClient} stackClient -The client used to make requests to the server + * @param {PermissionCollectionOptions} [options] - The collection options + */ + constructor(doctype, stackClient, options = {}) { + super(doctype, stackClient, options) + this.prefix = options.driveId ? sharedDriveApiPrefix(options.driveId) : '' + } async get(id) { const resp = await this.stackClient.fetchJSON( 'GET', - uri`/permissions/${id}` + this.prefix + uri`/permissions/${id}` ) return { data: normalizePermission(resp.data) @@ -42,7 +58,7 @@ class PermissionCollection extends DocumentCollection { if (tiny) searchParams.append('tiny', true) const resp = await this.stackClient.fetchJSON( 'POST', - `/permissions?${searchParams}`, + `${this.prefix}/permissions?${searchParams}`, { data: { type: 'io.cozy.permissions', @@ -85,13 +101,13 @@ class PermissionCollection extends DocumentCollection { let endpoint switch (document._type) { case 'io.cozy.apps': - endpoint = `/permissions/apps/${document.slug}` + endpoint = `${this.prefix}/permissions/apps/${document.slug}` break case 'io.cozy.konnectors': - endpoint = `/permissions/konnectors/${document.slug}` + endpoint = `${this.prefix}/permissions/konnectors/${document.slug}` break case 'io.cozy.permissions': - endpoint = `/permissions/${document._id}` + endpoint = `${this.prefix}/permissions/${document._id}` break default: throw new Error( @@ -122,14 +138,14 @@ class PermissionCollection extends DocumentCollection { destroy(permission) { return this.stackClient.fetchJSON( 'DELETE', - uri`/permissions/${permission.id}` + this.prefix + uri`/permissions/${permission.id}` ) } async findLinksByDoctype(doctype) { const resp = await this.stackClient.fetchJSON( 'GET', - uri`/permissions/doctype/${doctype}/shared-by-link` + this.prefix + uri`/permissions/doctype/${doctype}/shared-by-link` ) return { ...resp, @@ -174,7 +190,7 @@ class PermissionCollection extends DocumentCollection { const resp = await this.stackClient.fetchJSON( 'POST', - `/permissions?${searchParams}`, + `${this.prefix}/permissions?${searchParams}`, { data: { type: 'io.cozy.permissions', @@ -257,7 +273,10 @@ class PermissionCollection extends DocumentCollection { * @returns {Permission} permission */ async fetchOwnPermissions() { - const resp = await this.stackClient.fetchJSON('GET', '/permissions/self') + const resp = await this.stackClient.fetchJSON( + 'GET', + `${this.prefix}/permissions/self` + ) return { data: normalizePermission(resp.data), included: resp.included ? resp.included.map(normalizePermission) : [] diff --git a/packages/cozy-stack-client/src/PermissionCollection.spec.js b/packages/cozy-stack-client/src/PermissionCollection.spec.js index 8c773ca68..a5b1dac81 100644 --- a/packages/cozy-stack-client/src/PermissionCollection.spec.js +++ b/packages/cozy-stack-client/src/PermissionCollection.spec.js @@ -429,3 +429,139 @@ describe('getPermissionsFor', () => { expect(perms2.files.verbs).toEqual(expect.arrayContaining(verbs)) }) }) + +describe('PermissionCollection with driveId', () => { + const client = new CozyStackClient() + const driveId = 'abc123drive' + const collection = new PermissionCollection('io.cozy.permissions', client, { + driveId + }) + + beforeEach(() => { + client.fetchJSON.mockReset() + client.fetchJSON.mockResolvedValue({ data: [] }) + }) + + it('should set the correct API prefix for shared drives', () => { + expect(collection.prefix).toEqual('/sharings/drives/abc123drive') + }) + + describe('get', () => { + it('calls the API with the shared drive prefix', async () => { + client.fetchJSON.mockResolvedValue({ + data: { type: 'io.cozy.permissions', id: 'test-perm-id' } + }) + await collection.get('test-perm-id') + expect(client.fetchJSON).toHaveBeenCalledWith( + 'GET', + '/sharings/drives/abc123drive/permissions/test-perm-id' + ) + }) + }) + + describe('create', () => { + it('calls the API with the shared drive prefix', async () => { + client.fetchJSON.mockResolvedValue({ + data: { type: 'io.cozy.permissions', id: 'new-perm-id' } + }) + await collection.create({ _type: 'io.cozy.permissions', codes: 'code' }) + expect(client.fetchJSON).toHaveBeenCalledWith( + 'POST', + '/sharings/drives/abc123drive/permissions?codes=code', + { data: { attributes: {}, type: 'io.cozy.permissions' } } + ) + }) + + it('includes ttl and tiny options', async () => { + client.fetchJSON.mockResolvedValue({ + data: { type: 'io.cozy.permissions', id: 'new-perm-id' } + }) + await collection.create({ + _type: 'io.cozy.permissions', + codes: 'a,b', + ttl: '1D', + tiny: true + }) + expect(client.fetchJSON).toHaveBeenCalledWith( + 'POST', + '/sharings/drives/abc123drive/permissions?codes=a%2Cb&ttl=1D&tiny=true', + { data: { attributes: {}, type: 'io.cozy.permissions' } } + ) + }) + }) + + describe('add', () => { + it('uses shared drive prefix for permissions document', async () => { + await collection.add( + { + _type: 'io.cozy.permissions', + _id: 'a340d5e0d64711e6b66c5fc9ce1e17c6' + }, + fixtures.permission + ) + expect(client.fetchJSON).toHaveBeenCalledWith( + 'PATCH', + '/sharings/drives/abc123drive/permissions/a340d5e0d64711e6b66c5fc9ce1e17c6', + { + data: { + type: 'io.cozy.permissions', + attributes: { + permissions: fixtures.permission + } + } + } + ) + }) + }) + + describe('destroy', () => { + it('calls the API with the shared drive prefix', async () => { + await collection.destroy({ id: 'perm-to-delete' }) + expect(client.fetchJSON).toHaveBeenCalledWith( + 'DELETE', + '/sharings/drives/abc123drive/permissions/perm-to-delete' + ) + }) + }) + + describe('createSharingLink', () => { + it('calls the API with the shared drive prefix', async () => { + client.fetchJSON.mockResolvedValue({ + data: { type: 'io.cozy.permissions', id: 'new-perm-id' } + }) + const document = { _type: 'io.cozy.files', _id: '1234' } + await collection.createSharingLink(document) + expect(client.fetchJSON).toHaveBeenCalledWith( + 'POST', + '/sharings/drives/abc123drive/permissions?codes=code', + { + data: { + type: 'io.cozy.permissions', + attributes: { + permissions: { + files: { + type: 'io.cozy.files', + verbs: ['GET'], + values: ['1234'] + } + } + } + } + } + ) + }) + }) + + describe('fetchOwnPermissions', () => { + it('calls the API with the shared drive prefix', async () => { + client.fetchJSON.mockResolvedValue({ + data: { type: 'io.cozy.permissions', id: 'self-perm' } + }) + await collection.fetchOwnPermissions() + expect(client.fetchJSON).toHaveBeenCalledWith( + 'GET', + '/sharings/drives/abc123drive/permissions/self' + ) + }) + }) +})