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 +12 -0
- package/dist/state.js +23 -5
- package/dist/state.spec.js +179 -1
- package/package.json +2 -2
- package/src/state.js +25 -6
- package/src/state.spec.js +242 -0
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
|
|
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
|
-
|
|
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';
|
package/dist/state.spec.js
CHANGED
|
@@ -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.
|
|
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": "
|
|
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 =>
|
|
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 (
|
|
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 (
|
|
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
|
|
453
|
+
if (sharing.attributes?.owner) return type
|
|
454
|
+
|
|
444
455
|
const me = sharing.attributes.members.find(matchingInstanceName(instanceUri))
|
|
445
|
-
|
|
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', () => {
|