cozy-sharing 27.0.6 → 27.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [27.1.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@27.1.0...cozy-sharing@27.1.1) (2025-11-27)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **cozy-sharing:** Fix shared drive write access display for recipients ([3f2eaa2](https://github.com/cozy/cozy-libs/commit/3f2eaa25c3a2023f92040c98e972cdfa6e277133))
11
+
12
+ # [27.1.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@27.0.6...cozy-sharing@27.1.0) (2025-11-25)
13
+
14
+ ### Features
15
+
16
+ - Enhance sharing logic to retain shared drives without recipients ([ab91186](https://github.com/cozy/cozy-libs/commit/ab911869e5f49aafaf5ca16b3323bd9826072b35))
17
+
6
18
  ## [27.0.6](https://github.com/cozy/cozy-libs/compare/cozy-sharing@27.0.5...cozy-sharing@27.0.6) (2025-11-14)
7
19
 
8
20
  ### Bug Fixes
package/dist/state.js CHANGED
@@ -39,7 +39,9 @@ export var receiveSharings = function receiveSharings(_ref) {
39
39
  type: RECEIVE_SHARINGS,
40
40
  data: {
41
41
  sharings: sharings.filter(function (s) {
42
- return !areAllRecipientsRevoked(s) && !hasBeenSelfRevoked(s, instanceUri);
42
+ return (// Shared drives without recipients are valid and should be kept
43
+ (isSharingADrive(s) || !areAllRecipientsRevoked(s)) && !hasBeenSelfRevoked(s, instanceUri)
44
+ );
43
45
  }),
44
46
  permissions: permissions,
45
47
  apps: apps
@@ -235,7 +237,7 @@ var byDocId = function byDocId() {
235
237
  case REVOKE_GROUP:
236
238
  case REVOKE_RECIPIENT:
237
239
  case UPDATE_SHARING:
238
- if (areAllRecipientsRevoked(action.sharing)) {
240
+ if (!isSharingADrive(action.sharing) && areAllRecipientsRevoked(action.sharing)) {
239
241
  return forgetSharing(state, action.sharing);
240
242
  }
241
243
 
@@ -367,7 +369,7 @@ var sharedPaths = function sharedPaths() {
367
369
 
368
370
  case REVOKE_GROUP:
369
371
  case REVOKE_RECIPIENT:
370
- if (areAllRecipientsRevoked(action.sharing)) {
372
+ if (!isSharingADrive(action.sharing) && areAllRecipientsRevoked(action.sharing)) {
371
373
  return state.filter(function (p) {
372
374
  return p !== action.path;
373
375
  });
@@ -539,12 +541,24 @@ export var getSharingForSelf = function getSharingForSelf(state, docId) {
539
541
  return getDocumentSharing(state, docId);
540
542
  };
541
543
  export var getSharingType = function getSharingType(state, docId, instanceUri) {
544
+ var _sharing$attributes;
545
+
542
546
  var sharing = getSharingForSelf(state, docId);
543
547
  if (!sharing) return false;
544
548
  var type = getDocumentSharingType(sharing, docId);
545
- if (sharing.attributes.owner) return type;
549
+ if ((_sharing$attributes = sharing.attributes) !== null && _sharing$attributes !== void 0 && _sharing$attributes.owner) return type;
546
550
  var me = sharing.attributes.members.find(matchingInstanceName(instanceUri));
547
- return me && me.read_only ? 'one-way' : type;
551
+ if (!me) return type;
552
+
553
+ if (me.read_only) {
554
+ return 'one-way';
555
+ }
556
+
557
+ if (sharing.attributes.drive) {
558
+ return 'two-way';
559
+ }
560
+
561
+ return type;
548
562
  };
549
563
  export var getDocumentSharing = function getDocumentSharing(state, docId) {
550
564
  return getDocumentSharings(state, docId)[0] || null;
@@ -667,6 +681,10 @@ export var getPermissionDocIds = function getPermissionDocIds(perm) {
667
681
  }, []);
668
682
  };
669
683
 
684
+ var isSharingADrive = function isSharingADrive(sharing) {
685
+ return sharing.attributes.drive === true;
686
+ };
687
+
670
688
  var areAllRecipientsRevoked = function areAllRecipientsRevoked(sharing) {
671
689
  return sharing.attributes.owner && sharing.attributes.members.filter(function (m) {
672
690
  return m.status !== 'revoked';
@@ -4,7 +4,7 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
4
4
 
5
5
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
6
 
7
- import reducer, { receiveSharings, addSharing, addSharingLink, updateSharingLink, revokeSharingLink, getRecipients, revokeRecipient, revokeSelf, matchingInstanceName, getSharingLink, hasSharedParent, hasSharedChild, getSharedDocIdsBySharings, getSharingType, getPermissionDocIds, getDocumentSharingType, getSharedParentPath, getExternalSharingIds, getRecipientsWithGroups } from './state';
7
+ import reducer, { receiveSharings, addSharing, addSharingLink, updateSharingLink, revokeSharingLink, getRecipients, revokeRecipient, revokeSelf, updateSharing, matchingInstanceName, getSharingLink, hasSharedParent, hasSharedChild, getSharedDocIdsBySharings, getSharingType, getPermissionDocIds, getDocumentSharingType, getSharedParentPath, getExternalSharingIds, getRecipientsWithGroups } from './state';
8
8
  import { SHARING_1, SHARING_2, SHARING_3, SHARING_READ_ONLY, PERM_1, PERM_2, PERM_WITHOUT_DOC, SHARING_NO_ACTIVE, SHARING_WITH_SHORTCUT, APPS } from '../__tests__/fixtures';
9
9
  describe('Sharing state', function () {
10
10
  it('should have a default state', function () {
@@ -69,6 +69,133 @@ describe('Sharing state', function () {
69
69
  });
70
70
  expect(state.sharings).toEqual([SHARING_1]);
71
71
  });
72
+ it('should not filter out shared drives without recipients', function () {
73
+ var SHARED_DRIVE_WITHOUT_RECIPIENTS = _objectSpread(_objectSpread({}, SHARING_1), {}, {
74
+ id: 'shared_drive_no_recipients',
75
+ attributes: _objectSpread(_objectSpread({}, SHARING_1.attributes), {}, {
76
+ drive: true,
77
+ members: [{
78
+ status: 'owner',
79
+ name: 'Jane Doe',
80
+ email: 'jane@doe.com',
81
+ instance: 'http://cozy.tools:8080'
82
+ }],
83
+ rules: [{
84
+ title: 'My Shared Drive',
85
+ doctype: 'io.cozy.files',
86
+ values: ['shared_drive_folder'],
87
+ add: 'sync',
88
+ update: 'sync',
89
+ remove: 'sync'
90
+ }]
91
+ })
92
+ });
93
+
94
+ var state = reducer(undefined, receiveSharings({
95
+ sharings: [SHARING_1, SHARED_DRIVE_WITHOUT_RECIPIENTS]
96
+ }));
97
+ expect(state.byDocId).toEqual({
98
+ folder_1: {
99
+ sharings: [SHARING_1.id],
100
+ permissions: []
101
+ },
102
+ shared_drive_folder: {
103
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS.id],
104
+ permissions: []
105
+ }
106
+ });
107
+ expect(state.sharings).toEqual([SHARING_1, SHARED_DRIVE_WITHOUT_RECIPIENTS]);
108
+ });
109
+ it('should not forget shared drives without recipients when updating', function () {
110
+ var SHARED_DRIVE_WITHOUT_RECIPIENTS = _objectSpread(_objectSpread({}, SHARING_1), {}, {
111
+ id: 'shared_drive_no_recipients',
112
+ attributes: _objectSpread(_objectSpread({}, SHARING_1.attributes), {}, {
113
+ drive: true,
114
+ members: [{
115
+ status: 'owner',
116
+ name: 'Jane Doe',
117
+ email: 'jane@doe.com',
118
+ instance: 'http://cozy.tools:8080'
119
+ }],
120
+ rules: [{
121
+ title: 'My Shared Drive',
122
+ doctype: 'io.cozy.files',
123
+ values: ['shared_drive_folder'],
124
+ add: 'sync',
125
+ update: 'sync',
126
+ remove: 'sync'
127
+ }]
128
+ })
129
+ });
130
+
131
+ var initialState = reducer(undefined, receiveSharings({
132
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS]
133
+ }));
134
+
135
+ var updatedSharing = _objectSpread(_objectSpread({}, SHARED_DRIVE_WITHOUT_RECIPIENTS), {}, {
136
+ attributes: _objectSpread(_objectSpread({}, SHARED_DRIVE_WITHOUT_RECIPIENTS.attributes), {}, {
137
+ description: 'Updated description'
138
+ })
139
+ });
140
+
141
+ var state = reducer(initialState, updateSharing(updatedSharing));
142
+ expect(state.byDocId).toEqual({
143
+ shared_drive_folder: {
144
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS.id],
145
+ permissions: []
146
+ }
147
+ });
148
+ expect(state.sharings).toEqual([updatedSharing]);
149
+ });
150
+ it('should not remove shared drive path when revoking last recipient', function () {
151
+ var SHARED_DRIVE_WITH_ONE_RECIPIENT = _objectSpread(_objectSpread({}, SHARING_1), {}, {
152
+ id: 'shared_drive_one_recipient',
153
+ attributes: _objectSpread(_objectSpread({}, SHARING_1.attributes), {}, {
154
+ drive: true,
155
+ members: [{
156
+ status: 'owner',
157
+ name: 'Jane Doe',
158
+ email: 'jane@doe.com',
159
+ instance: 'http://cozy.tools:8080'
160
+ }, {
161
+ status: 'ready',
162
+ name: 'John Doe',
163
+ email: 'john@doe.com',
164
+ instance: 'http://cozy.local:8080'
165
+ }],
166
+ rules: [{
167
+ title: 'My Shared Drive',
168
+ doctype: 'io.cozy.files',
169
+ values: ['shared_drive_folder'],
170
+ add: 'sync',
171
+ update: 'sync',
172
+ remove: 'sync'
173
+ }]
174
+ })
175
+ });
176
+
177
+ var sharedDrivePath = '/shared_drive_folder';
178
+ var initialState = reducer(reducer(undefined, receiveSharings({
179
+ sharings: [SHARED_DRIVE_WITH_ONE_RECIPIENT]
180
+ })), addSharing(SHARED_DRIVE_WITH_ONE_RECIPIENT, sharedDrivePath));
181
+
182
+ var sharingAfterRevoke = _objectSpread(_objectSpread({}, SHARED_DRIVE_WITH_ONE_RECIPIENT), {}, {
183
+ attributes: _objectSpread(_objectSpread({}, SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes), {}, {
184
+ members: [SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[0], _objectSpread(_objectSpread({}, SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[1]), {}, {
185
+ status: 'revoked'
186
+ })]
187
+ })
188
+ });
189
+
190
+ var state = reducer(initialState, revokeRecipient(sharingAfterRevoke, 1, sharedDrivePath));
191
+ expect(state.sharedPaths).toContain(sharedDrivePath);
192
+ expect(state.byDocId).toEqual({
193
+ shared_drive_folder: {
194
+ sharings: [SHARED_DRIVE_WITH_ONE_RECIPIENT.id],
195
+ permissions: []
196
+ }
197
+ });
198
+ });
72
199
  it('should index received permissions', function () {
73
200
  var state = reducer(undefined, receiveSharings({
74
201
  sharings: [SHARING_1, SHARING_2],
@@ -425,6 +552,57 @@ describe('getSharingType selector', function () {
425
552
  }));
426
553
  expect(getSharingType(newState, SHARING_READ_ONLY.attributes.rules[0].values[0], '')).toBe('one-way');
427
554
  });
555
+ it('should return two-way for a shared drive member with write access', function () {
556
+ var SHARED_DRIVE = _objectSpread(_objectSpread({}, SHARING_3), {}, {
557
+ id: 'shared_drive',
558
+ attributes: _objectSpread(_objectSpread({}, SHARING_3.attributes), {}, {
559
+ drive: true,
560
+ owner: false,
561
+ members: [{
562
+ status: 'owner',
563
+ name: 'Jane Doe',
564
+ email: 'jane@doe.com',
565
+ instance: 'http://cozy.tools:8080'
566
+ }, {
567
+ status: 'ready',
568
+ name: 'John Doe',
569
+ email: 'john@doe.com',
570
+ instance: 'http://cozy.local:8080'
571
+ }]
572
+ })
573
+ });
574
+
575
+ var newState = reducer({}, receiveSharings({
576
+ sharings: [SHARED_DRIVE]
577
+ }));
578
+ expect(getSharingType(newState, SHARED_DRIVE.attributes.rules[0].values[0], 'http://cozy.local:8080')).toBe('two-way');
579
+ });
580
+ it('should return one-way for a shared drive member with read-only access', function () {
581
+ var SHARED_DRIVE_READ_ONLY = _objectSpread(_objectSpread({}, SHARING_3), {}, {
582
+ id: 'shared_drive_read_only',
583
+ attributes: _objectSpread(_objectSpread({}, SHARING_3.attributes), {}, {
584
+ drive: true,
585
+ owner: false,
586
+ members: [{
587
+ status: 'owner',
588
+ name: 'Jane Doe',
589
+ email: 'jane@doe.com',
590
+ instance: 'http://cozy.tools:8080'
591
+ }, {
592
+ status: 'ready',
593
+ name: 'John Doe',
594
+ email: 'john@doe.com',
595
+ instance: 'http://cozy.local:8080',
596
+ read_only: true
597
+ }]
598
+ })
599
+ });
600
+
601
+ var newState = reducer({}, receiveSharings({
602
+ sharings: [SHARED_DRIVE_READ_ONLY]
603
+ }));
604
+ expect(getSharingType(newState, SHARED_DRIVE_READ_ONLY.attributes.rules[0].values[0], 'http://cozy.local:8080')).toBe('one-way');
605
+ });
428
606
  });
429
607
  describe('getDocumentSharingType', function () {
430
608
  it('should return null if no sharing', function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-sharing",
3
- "version": "27.0.6",
3
+ "version": "27.1.1",
4
4
  "description": "Provides sharing login for React applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -81,5 +81,5 @@
81
81
  "sideEffects": [
82
82
  "*.css"
83
83
  ],
84
- "gitHead": "3a0c0103636a6365a7d2a380960d7e7d773078eb"
84
+ "gitHead": "d6ec4ab71e49b266623d00d1a3d8a72da495b72a"
85
85
  }
package/src/state.js CHANGED
@@ -27,7 +27,10 @@ export const receiveSharings = ({
27
27
  type: RECEIVE_SHARINGS,
28
28
  data: {
29
29
  sharings: sharings.filter(
30
- s => !areAllRecipientsRevoked(s) && !hasBeenSelfRevoked(s, instanceUri)
30
+ s =>
31
+ // Shared drives without recipients are valid and should be kept
32
+ (isSharingADrive(s) || !areAllRecipientsRevoked(s)) &&
33
+ !hasBeenSelfRevoked(s, instanceUri)
31
34
  ),
32
35
  permissions,
33
36
  apps
@@ -181,7 +184,10 @@ const byDocId = (state = {}, action) => {
181
184
  case REVOKE_GROUP:
182
185
  case REVOKE_RECIPIENT:
183
186
  case UPDATE_SHARING:
184
- if (areAllRecipientsRevoked(action.sharing)) {
187
+ if (
188
+ !isSharingADrive(action.sharing) &&
189
+ areAllRecipientsRevoked(action.sharing)
190
+ ) {
185
191
  return forgetSharing(state, action.sharing)
186
192
  }
187
193
  return state
@@ -275,7 +281,10 @@ const sharedPaths = (state = [], action) => {
275
281
  return newState
276
282
  case REVOKE_GROUP:
277
283
  case REVOKE_RECIPIENT:
278
- if (areAllRecipientsRevoked(action.sharing)) {
284
+ if (
285
+ !isSharingADrive(action.sharing) &&
286
+ areAllRecipientsRevoked(action.sharing)
287
+ ) {
279
288
  return state.filter(p => p !== action.path)
280
289
  }
281
290
  return state
@@ -439,10 +448,19 @@ export const getSharingForSelf = (state, docId) =>
439
448
  export const getSharingType = (state, docId, instanceUri) => {
440
449
  const sharing = getSharingForSelf(state, docId)
441
450
  if (!sharing) return false
451
+
442
452
  const type = getDocumentSharingType(sharing, docId)
443
- if (sharing.attributes.owner) return type
453
+ if (sharing.attributes?.owner) return type
454
+
444
455
  const me = sharing.attributes.members.find(matchingInstanceName(instanceUri))
445
- return me && me.read_only ? 'one-way' : type
456
+ if (!me) return type
457
+ if (me.read_only) {
458
+ return 'one-way'
459
+ }
460
+ if (sharing.attributes.drive) {
461
+ return 'two-way'
462
+ }
463
+ return type
446
464
  }
447
465
 
448
466
  export const getDocumentSharing = (state, docId) =>
@@ -551,6 +569,8 @@ export const getPermissionDocIds = perm =>
551
569
  )
552
570
  .reduce((acc, val) => [...acc, ...val], [])
553
571
 
572
+ const isSharingADrive = sharing => sharing.attributes.drive === true
573
+
554
574
  const areAllRecipientsRevoked = sharing =>
555
575
  sharing.attributes.owner &&
556
576
  sharing.attributes.members.filter(m => m.status !== 'revoked').length === 1
@@ -608,7 +628,6 @@ export const getDocumentSharingType = (sharing, docId) => {
608
628
  const rule = getSharingRule(sharing, docId)
609
629
  const directorySharingType = getDirectorySharingType(rule)
610
630
  const fileSharingType = getFileSharingType(rule)
611
-
612
631
  return directorySharingType === SHARING_TYPE.TWO_WAY ||
613
632
  fileSharingType === SHARING_TYPE.TWO_WAY
614
633
  ? SHARING_TYPE.TWO_WAY
package/src/state.spec.js CHANGED
@@ -7,6 +7,7 @@ import reducer, {
7
7
  getRecipients,
8
8
  revokeRecipient,
9
9
  revokeSelf,
10
+ updateSharing,
10
11
  matchingInstanceName,
11
12
  getSharingLink,
12
13
  hasSharedParent,
@@ -98,6 +99,168 @@ describe('Sharing state', () => {
98
99
  expect(state.sharings).toEqual([SHARING_1])
99
100
  })
100
101
 
102
+ it('should not filter out shared drives without recipients', () => {
103
+ const SHARED_DRIVE_WITHOUT_RECIPIENTS = {
104
+ ...SHARING_1,
105
+ id: 'shared_drive_no_recipients',
106
+ attributes: {
107
+ ...SHARING_1.attributes,
108
+ drive: true,
109
+ members: [
110
+ {
111
+ status: 'owner',
112
+ name: 'Jane Doe',
113
+ email: 'jane@doe.com',
114
+ instance: 'http://cozy.tools:8080'
115
+ }
116
+ ],
117
+ rules: [
118
+ {
119
+ title: 'My Shared Drive',
120
+ doctype: 'io.cozy.files',
121
+ values: ['shared_drive_folder'],
122
+ add: 'sync',
123
+ update: 'sync',
124
+ remove: 'sync'
125
+ }
126
+ ]
127
+ }
128
+ }
129
+ const state = reducer(
130
+ undefined,
131
+ receiveSharings({
132
+ sharings: [SHARING_1, SHARED_DRIVE_WITHOUT_RECIPIENTS]
133
+ })
134
+ )
135
+ expect(state.byDocId).toEqual({
136
+ folder_1: { sharings: [SHARING_1.id], permissions: [] },
137
+ shared_drive_folder: {
138
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS.id],
139
+ permissions: []
140
+ }
141
+ })
142
+ expect(state.sharings).toEqual([SHARING_1, SHARED_DRIVE_WITHOUT_RECIPIENTS])
143
+ })
144
+
145
+ it('should not forget shared drives without recipients when updating', () => {
146
+ const SHARED_DRIVE_WITHOUT_RECIPIENTS = {
147
+ ...SHARING_1,
148
+ id: 'shared_drive_no_recipients',
149
+ attributes: {
150
+ ...SHARING_1.attributes,
151
+ drive: true,
152
+ members: [
153
+ {
154
+ status: 'owner',
155
+ name: 'Jane Doe',
156
+ email: 'jane@doe.com',
157
+ instance: 'http://cozy.tools:8080'
158
+ }
159
+ ],
160
+ rules: [
161
+ {
162
+ title: 'My Shared Drive',
163
+ doctype: 'io.cozy.files',
164
+ values: ['shared_drive_folder'],
165
+ add: 'sync',
166
+ update: 'sync',
167
+ remove: 'sync'
168
+ }
169
+ ]
170
+ }
171
+ }
172
+ const initialState = reducer(
173
+ undefined,
174
+ receiveSharings({
175
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS]
176
+ })
177
+ )
178
+ const updatedSharing = {
179
+ ...SHARED_DRIVE_WITHOUT_RECIPIENTS,
180
+ attributes: {
181
+ ...SHARED_DRIVE_WITHOUT_RECIPIENTS.attributes,
182
+ description: 'Updated description'
183
+ }
184
+ }
185
+ const state = reducer(initialState, updateSharing(updatedSharing))
186
+ expect(state.byDocId).toEqual({
187
+ shared_drive_folder: {
188
+ sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS.id],
189
+ permissions: []
190
+ }
191
+ })
192
+ expect(state.sharings).toEqual([updatedSharing])
193
+ })
194
+
195
+ it('should not remove shared drive path when revoking last recipient', () => {
196
+ const SHARED_DRIVE_WITH_ONE_RECIPIENT = {
197
+ ...SHARING_1,
198
+ id: 'shared_drive_one_recipient',
199
+ attributes: {
200
+ ...SHARING_1.attributes,
201
+ drive: true,
202
+ members: [
203
+ {
204
+ status: 'owner',
205
+ name: 'Jane Doe',
206
+ email: 'jane@doe.com',
207
+ instance: 'http://cozy.tools:8080'
208
+ },
209
+ {
210
+ status: 'ready',
211
+ name: 'John Doe',
212
+ email: 'john@doe.com',
213
+ instance: 'http://cozy.local:8080'
214
+ }
215
+ ],
216
+ rules: [
217
+ {
218
+ title: 'My Shared Drive',
219
+ doctype: 'io.cozy.files',
220
+ values: ['shared_drive_folder'],
221
+ add: 'sync',
222
+ update: 'sync',
223
+ remove: 'sync'
224
+ }
225
+ ]
226
+ }
227
+ }
228
+ const sharedDrivePath = '/shared_drive_folder'
229
+ const initialState = reducer(
230
+ reducer(
231
+ undefined,
232
+ receiveSharings({
233
+ sharings: [SHARED_DRIVE_WITH_ONE_RECIPIENT]
234
+ })
235
+ ),
236
+ addSharing(SHARED_DRIVE_WITH_ONE_RECIPIENT, sharedDrivePath)
237
+ )
238
+ const sharingAfterRevoke = {
239
+ ...SHARED_DRIVE_WITH_ONE_RECIPIENT,
240
+ attributes: {
241
+ ...SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes,
242
+ members: [
243
+ SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[0],
244
+ {
245
+ ...SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[1],
246
+ status: 'revoked'
247
+ }
248
+ ]
249
+ }
250
+ }
251
+ const state = reducer(
252
+ initialState,
253
+ revokeRecipient(sharingAfterRevoke, 1, sharedDrivePath)
254
+ )
255
+ expect(state.sharedPaths).toContain(sharedDrivePath)
256
+ expect(state.byDocId).toEqual({
257
+ shared_drive_folder: {
258
+ sharings: [SHARED_DRIVE_WITH_ONE_RECIPIENT.id],
259
+ permissions: []
260
+ }
261
+ })
262
+ })
263
+
101
264
  it('should index received permissions', () => {
102
265
  const state = reducer(
103
266
  undefined,
@@ -545,6 +708,85 @@ describe('getSharingType selector', () => {
545
708
  )
546
709
  ).toBe('one-way')
547
710
  })
711
+
712
+ it('should return two-way for a shared drive member with write access', () => {
713
+ const SHARED_DRIVE = {
714
+ ...SHARING_3,
715
+ id: 'shared_drive',
716
+ attributes: {
717
+ ...SHARING_3.attributes,
718
+ drive: true,
719
+ owner: false,
720
+ members: [
721
+ {
722
+ status: 'owner',
723
+ name: 'Jane Doe',
724
+ email: 'jane@doe.com',
725
+ instance: 'http://cozy.tools:8080'
726
+ },
727
+ {
728
+ status: 'ready',
729
+ name: 'John Doe',
730
+ email: 'john@doe.com',
731
+ instance: 'http://cozy.local:8080'
732
+ }
733
+ ]
734
+ }
735
+ }
736
+ const newState = reducer(
737
+ {},
738
+ receiveSharings({
739
+ sharings: [SHARED_DRIVE]
740
+ })
741
+ )
742
+ expect(
743
+ getSharingType(
744
+ newState,
745
+ SHARED_DRIVE.attributes.rules[0].values[0],
746
+ 'http://cozy.local:8080'
747
+ )
748
+ ).toBe('two-way')
749
+ })
750
+
751
+ it('should return one-way for a shared drive member with read-only access', () => {
752
+ const SHARED_DRIVE_READ_ONLY = {
753
+ ...SHARING_3,
754
+ id: 'shared_drive_read_only',
755
+ attributes: {
756
+ ...SHARING_3.attributes,
757
+ drive: true,
758
+ owner: false,
759
+ members: [
760
+ {
761
+ status: 'owner',
762
+ name: 'Jane Doe',
763
+ email: 'jane@doe.com',
764
+ instance: 'http://cozy.tools:8080'
765
+ },
766
+ {
767
+ status: 'ready',
768
+ name: 'John Doe',
769
+ email: 'john@doe.com',
770
+ instance: 'http://cozy.local:8080',
771
+ read_only: true
772
+ }
773
+ ]
774
+ }
775
+ }
776
+ const newState = reducer(
777
+ {},
778
+ receiveSharings({
779
+ sharings: [SHARED_DRIVE_READ_ONLY]
780
+ })
781
+ )
782
+ expect(
783
+ getSharingType(
784
+ newState,
785
+ SHARED_DRIVE_READ_ONLY.attributes.rules[0].values[0],
786
+ 'http://cozy.local:8080'
787
+ )
788
+ ).toBe('one-way')
789
+ })
548
790
  })
549
791
 
550
792
  describe('getDocumentSharingType', () => {