cozy-sharing 37.5.5 → 37.6.0

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.
@@ -0,0 +1,134 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
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
+
7
+ import { mapEffectiveRecipients } from './effectiveRecipients';
8
+
9
+ var makeAncestorSource = function makeAncestorSource() {
10
+ var rootName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Parent Folder';
11
+ return {
12
+ sharing_id: 'sharing-1',
13
+ root_id: 'root-1',
14
+ root_name: rootName,
15
+ kind: 'ancestor',
16
+ member_index: 1,
17
+ read_only: false,
18
+ manageable: false
19
+ };
20
+ };
21
+
22
+ var makeSelfSource = function makeSelfSource() {
23
+ var _opts$memberIndex, _opts$readOnly, _opts$manageable;
24
+
25
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
26
+ return {
27
+ sharing_id: opts.sharing_id || 'sharing-2',
28
+ root_id: 'root-2',
29
+ root_name: 'Child Folder',
30
+ kind: 'self',
31
+ member_index: (_opts$memberIndex = opts.memberIndex) !== null && _opts$memberIndex !== void 0 ? _opts$memberIndex : 1,
32
+ read_only: (_opts$readOnly = opts.readOnly) !== null && _opts$readOnly !== void 0 ? _opts$readOnly : false,
33
+ manageable: (_opts$manageable = opts.manageable) !== null && _opts$manageable !== void 0 ? _opts$manageable : true
34
+ };
35
+ };
36
+
37
+ var makeRecipient = function makeRecipient() {
38
+ var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
39
+ return _objectSpread({
40
+ id: 'recip-1',
41
+ name: 'Alice',
42
+ email: 'alice@example.com',
43
+ instance: 'https://alice.mycozy.cloud',
44
+ status: 'ready',
45
+ read_only: false,
46
+ can_edit_here: false,
47
+ sources: overrides.sources || []
48
+ }, overrides);
49
+ };
50
+
51
+ describe('mapEffectiveRecipients', function () {
52
+ it('returns empty array for empty input', function () {
53
+ expect(mapEffectiveRecipients([])).toEqual([]);
54
+ });
55
+ it('returns empty array for null or undefined', function () {
56
+ expect(mapEffectiveRecipients(null)).toEqual([]);
57
+ expect(mapEffectiveRecipients(undefined)).toEqual([]);
58
+ });
59
+ it('maps a recipient with a self source using the self source', function () {
60
+ var recipient = makeRecipient({
61
+ sources: [makeSelfSource()]
62
+ });
63
+ var result = mapEffectiveRecipients([recipient]);
64
+ expect(result).toHaveLength(1);
65
+ expect(result[0].sharingId).toBe('sharing-2');
66
+ expect(result[0].memberIndex).toBe(1);
67
+ expect(result[0].avatarPath).toBe('/sharings/sharing-2/recipients/1/avatar');
68
+ expect(result[0].type).toBe('two-way');
69
+ });
70
+ it('maps a recipient with only ancestor sources using the ancestor source', function () {
71
+ var recipient = makeRecipient({
72
+ sources: [makeAncestorSource('Shared Parent')]
73
+ });
74
+ var result = mapEffectiveRecipients([recipient]);
75
+ expect(result).toHaveLength(1);
76
+ expect(result[0].sharingId).toBe('sharing-1');
77
+ expect(result[0].memberIndex).toBe(1);
78
+ expect(result[0].name).toBe('Alice');
79
+ expect(result[0].email).toBe('alice@example.com');
80
+ });
81
+ it('maps an owner (self source, index 0) correctly', function () {
82
+ var recipient = makeRecipient({
83
+ status: 'owner',
84
+ read_only: true,
85
+ sources: [makeSelfSource({
86
+ memberIndex: 0,
87
+ manageable: false
88
+ })]
89
+ });
90
+ var result = mapEffectiveRecipients([recipient]);
91
+ expect(result).toHaveLength(1);
92
+ expect(result[0].status).toBe('owner');
93
+ expect(result[0].type).toBe('one-way');
94
+ });
95
+ it('maps an owner with only ancestor sources correctly', function () {
96
+ var recipient = makeRecipient({
97
+ status: 'owner',
98
+ sources: [makeAncestorSource('Parent Folder')]
99
+ });
100
+ var result = mapEffectiveRecipients([recipient]);
101
+ expect(result).toHaveLength(1);
102
+ expect(result[0].status).toBe('owner');
103
+ expect(result[0].sharingId).toBe('sharing-1');
104
+ expect(result[0].memberIndex).toBe(1);
105
+ });
106
+ it('sets type to one-way for read_only recipients', function () {
107
+ var recipient = makeRecipient({
108
+ read_only: true,
109
+ sources: [makeSelfSource({
110
+ readOnly: true
111
+ })]
112
+ });
113
+ var result = mapEffectiveRecipients([recipient]);
114
+ expect(result[0].type).toBe('one-way');
115
+ });
116
+ it('handles all recipients in the same array regardless of source kind', function () {
117
+ var selfRecipient = makeRecipient({
118
+ id: 'self-1',
119
+ name: 'Bob',
120
+ email: 'bob@example.com',
121
+ sources: [makeSelfSource()]
122
+ });
123
+ var ancestorRecipient = makeRecipient({
124
+ id: 'ancestor-1',
125
+ name: 'Carol',
126
+ email: 'carol@example.com',
127
+ sources: [makeAncestorSource('Root Folder')]
128
+ });
129
+ var result = mapEffectiveRecipients([selfRecipient, ancestorRecipient]);
130
+ expect(result).toHaveLength(2);
131
+ expect(result[0].sharingId).toBe('sharing-2');
132
+ expect(result[1].sharingId).toBe('sharing-1');
133
+ });
134
+ });
package/dist/state.js CHANGED
@@ -1,3 +1,4 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
1
2
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
3
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
4
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
@@ -23,6 +24,9 @@ var ADD_SHARING_LINK = 'ADD_SHARING_LINK';
23
24
  var UPDATE_SHARING_LINK = 'UPDATE_SHARING_LINK';
24
25
  var REVOKE_SHARING_LINK = 'REVOKE_SHARING_LINK';
25
26
  var RECEIVE_PATHS = 'RECEIVE_PATHS';
27
+ var RECEIVE_EFFECTIVE_RECIPIENTS = 'RECEIVE_EFFECTIVE_RECIPIENTS';
28
+ var UPDATE_EFFECTIVE_RECIPIENT = 'UPDATE_EFFECTIVE_RECIPIENT';
29
+ var INVALIDATE_EFFECTIVE_RECIPIENTS = 'INVALIDATE_EFFECTIVE_RECIPIENTS';
26
30
  export var SHARING_TYPE = {
27
31
  TWO_WAY: 'two-way',
28
32
  ONE_WAY: 'one-way'
@@ -136,6 +140,27 @@ export var receivePaths = function receivePaths(paths) {
136
140
  paths: paths
137
141
  };
138
142
  };
143
+ export var receiveEffectiveRecipients = function receiveEffectiveRecipients(docId, recipients) {
144
+ return {
145
+ type: RECEIVE_EFFECTIVE_RECIPIENTS,
146
+ docId: docId,
147
+ recipients: recipients
148
+ };
149
+ };
150
+ export var updateEffectiveRecipient = function updateEffectiveRecipient(sharingId, memberIndex, readOnly) {
151
+ return {
152
+ type: UPDATE_EFFECTIVE_RECIPIENT,
153
+ sharingId: sharingId,
154
+ memberIndex: memberIndex,
155
+ readOnly: readOnly
156
+ };
157
+ };
158
+ export var invalidateEffectiveRecipients = function invalidateEffectiveRecipients(docId) {
159
+ return {
160
+ type: INVALIDATE_EFFECTIVE_RECIPIENTS,
161
+ docId: docId
162
+ };
163
+ };
139
164
  export var matchingInstanceName = function matchingInstanceName() {
140
165
  var instanceUri = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
141
166
  return function (shareMember) {
@@ -373,6 +398,42 @@ var sharedPaths = function sharedPaths() {
373
398
  }
374
399
  };
375
400
 
401
+ var effectiveRecipients = function effectiveRecipients() {
402
+ var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
403
+ var action = arguments.length > 1 ? arguments[1] : undefined;
404
+
405
+ switch (action.type) {
406
+ case RECEIVE_EFFECTIVE_RECIPIENTS:
407
+ return _objectSpread(_objectSpread({}, state), {}, _defineProperty({}, action.docId, action.recipients));
408
+
409
+ case UPDATE_EFFECTIVE_RECIPIENT:
410
+ return Object.fromEntries(Object.entries(state).map(function (_ref2) {
411
+ var _ref3 = _slicedToArray(_ref2, 2),
412
+ docId = _ref3[0],
413
+ recipients = _ref3[1];
414
+
415
+ return [docId, recipients.map(function (r) {
416
+ return r.sharingId === action.sharingId && r.memberIndex === action.memberIndex ? _objectSpread(_objectSpread({}, r), {}, {
417
+ read_only: action.readOnly,
418
+ type: action.readOnly ? 'one-way' : 'two-way'
419
+ }) : r;
420
+ })];
421
+ }));
422
+
423
+ case INVALIDATE_EFFECTIVE_RECIPIENTS:
424
+ {
425
+ var _action$docId2 = action.docId,
426
+ _ = state[_action$docId2],
427
+ rest = _objectWithoutProperties(state, [_action$docId2].map(_toPropertyKey));
428
+
429
+ return rest;
430
+ }
431
+
432
+ default:
433
+ return state;
434
+ }
435
+ };
436
+
376
437
  var reducer = function reducer() {
377
438
  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
378
439
  var action = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -380,7 +441,8 @@ var reducer = function reducer() {
380
441
  byDocId: byDocId(state.byDocId, action),
381
442
  sharings: sharings(state.sharings, action),
382
443
  permissions: permissions(state.permissions, action),
383
- sharedPaths: sharedPaths(state.sharedPaths, action)
444
+ sharedPaths: sharedPaths(state.sharedPaths, action),
445
+ effectiveRecipients: effectiveRecipients(state.effectiveRecipients, action)
384
446
  };
385
447
  };
386
448
 
@@ -643,6 +705,11 @@ export var getSharedParentPath = function getSharedParentPath(state, documentPat
643
705
  }
644
706
 
645
707
  return null;
708
+ };
709
+ export var getEffectiveRecipients = function getEffectiveRecipients(state, docId) {
710
+ var _state$effectiveRecip;
711
+
712
+ return ((_state$effectiveRecip = state.effectiveRecipients) === null || _state$effectiveRecip === void 0 ? void 0 : _state$effectiveRecip[docId]) || [];
646
713
  }; // helpers
647
714
 
648
715
  export var getSharedDocIds = function getSharedDocIds(doc) {
@@ -13,7 +13,8 @@ describe('Sharing state', function () {
13
13
  byDocId: {},
14
14
  sharings: [],
15
15
  permissions: [],
16
- sharedPaths: []
16
+ sharedPaths: [],
17
+ effectiveRecipients: {}
17
18
  });
18
19
  });
19
20
  it('should index received sharings', function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-sharing",
3
- "version": "37.5.5",
3
+ "version": "37.6.0",
4
4
  "description": "Provides sharing login for React applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -59,7 +59,7 @@
59
59
  "cozy-intent": "^2.31.1",
60
60
  "cozy-minilog": "^3.10.1",
61
61
  "cozy-ui": "^140.5.0",
62
- "cozy-ui-plus": "^12.3.14",
62
+ "cozy-ui-plus": "^12.3.15",
63
63
  "jest": "30.3.0",
64
64
  "jest-environment-jsdom": "30.3.0",
65
65
  "react": "16.12.0",
@@ -85,5 +85,5 @@
85
85
  "sideEffects": [
86
86
  "*.css"
87
87
  ],
88
- "gitHead": "319c4890af0fbee641e25a2cb7c1bd2501b57024"
88
+ "gitHead": "aa6c91c03a8b734177fddb3075aa26110516c218"
89
89
  }
@@ -9,6 +9,7 @@ import {
9
9
  } from './components/ShareRestrictionModal/helpers'
10
10
  import SharingContext from './context'
11
11
  import { fetchNextPermissions } from './fetchNextPermissions'
12
+ import { mapEffectiveRecipients } from './helpers/effectiveRecipients'
12
13
  import { fetchFilesPaths } from './helpers/files'
13
14
  import {
14
15
  getSharingObject,
@@ -28,6 +29,10 @@ import reducer, {
28
29
  revokeGroup as revokeGroupFromState,
29
30
  revokeSelf,
30
31
  receivePaths,
32
+ receiveEffectiveRecipients,
33
+ updateEffectiveRecipient,
34
+ invalidateEffectiveRecipients,
35
+ getEffectiveRecipients,
31
36
  isOwner,
32
37
  isSharedDrive,
33
38
  isOrgSharedDrive,
@@ -109,7 +114,11 @@ export class SharingProvider extends Component {
109
114
  refresh: this.fetchAllSharings,
110
115
  hasWriteAccess: this.hasWriteAccess,
111
116
  renameSharedDrive: this.renameSharedDrive,
112
- updateSharingMemberType: this.updateSharingMemberType
117
+ updateSharingMemberType: this.updateSharingMemberType,
118
+ getEffectiveRecipients: docId =>
119
+ getEffectiveRecipients(this.state, docId),
120
+ fetchEffectiveRecipients: this.fetchEffectiveRecipients,
121
+ invalidateEffectiveRecipients: this.invalidateEffectiveRecipients
113
122
  }
114
123
  this.isPublic = props.isPublic ?? false
115
124
  this.realtime = null
@@ -261,6 +270,11 @@ export class SharingProvider extends Component {
261
270
 
262
271
  await this.state.onShared({ document, recipients, readOnlyRecipients })
263
272
 
273
+ await this.fetchEffectiveRecipients(
274
+ getDocumentId(document),
275
+ document.driveId
276
+ )
277
+
264
278
  return sharingResult
265
279
  }
266
280
 
@@ -284,6 +298,10 @@ export class SharingProvider extends Component {
284
298
  )
285
299
 
286
300
  await this.state.onShared({ document, recipients, readOnlyRecipients })
301
+ await this.fetchEffectiveRecipients(
302
+ getDocumentId(document),
303
+ document.driveId
304
+ )
287
305
  return data
288
306
  }
289
307
 
@@ -318,6 +336,10 @@ export class SharingProvider extends Component {
318
336
  )
319
337
  )
320
338
  })
339
+ await this.fetchEffectiveRecipients(
340
+ getDocumentId(document),
341
+ document.driveId
342
+ )
321
343
  }
322
344
 
323
345
  revoke = async (document, sharingId, recipientIndex) => {
@@ -331,6 +353,10 @@ export class SharingProvider extends Component {
331
353
  document.path || (await fetchFilesPaths(client, doctype, [document]))
332
354
  )
333
355
  )
356
+ await this.fetchEffectiveRecipients(
357
+ getDocumentId(document),
358
+ document.driveId
359
+ )
334
360
  }
335
361
 
336
362
  revokeGroup = async (document, sharingId, recipientIndex) => {
@@ -350,6 +376,10 @@ export class SharingProvider extends Component {
350
376
  const sharing = getSharingForSelf(this.state, document.id)
351
377
  await this.sharingCol.revokeSelf(sharing)
352
378
  this.dispatch(revokeSelf(sharing))
379
+ await this.fetchEffectiveRecipients(
380
+ getDocumentId(document),
381
+ document.driveId
382
+ )
353
383
  }
354
384
 
355
385
  /**
@@ -386,6 +416,9 @@ export class SharingProvider extends Component {
386
416
  }
387
417
 
388
418
  this.dispatch(updateSharing(optimisticSharing))
419
+ this.dispatch(
420
+ updateEffectiveRecipient(sharingId, memberIndex, makeReadOnly)
421
+ )
389
422
 
390
423
  try {
391
424
  if (makeReadOnly) {
@@ -411,12 +444,39 @@ export class SharingProvider extends Component {
411
444
  }
412
445
 
413
446
  this.dispatch(updateSharing(rollbackSharing))
447
+ this.dispatch(
448
+ updateEffectiveRecipient(sharingId, memberIndex, !makeReadOnly)
449
+ )
414
450
  log.error(
415
451
  `Failed to change member ${member.email} permission type to ${newType}`,
416
452
  error
417
453
  )
418
454
  throw error
419
455
  }
456
+
457
+ const docId = Object.keys(this.state.byDocId).find(id =>
458
+ this.state.byDocId[id].sharings?.includes(sharingId)
459
+ )
460
+ if (docId) {
461
+ const driveId = this.state.byDocId[docId].driveId
462
+ await this.fetchEffectiveRecipients(docId, driveId)
463
+ }
464
+ }
465
+
466
+ fetchEffectiveRecipients = async (fileId, driveId) => {
467
+ const resp = await this.sharingCol.fetchEffectiveRecipients(fileId, {
468
+ driveId
469
+ })
470
+ this.dispatch(
471
+ receiveEffectiveRecipients(
472
+ fileId,
473
+ mapEffectiveRecipients(resp?.data || [])
474
+ )
475
+ )
476
+ }
477
+
478
+ invalidateEffectiveRecipients = docId => {
479
+ this.dispatch(invalidateEffectiveRecipients(docId))
420
480
  }
421
481
 
422
482
  shareByLink = async (document, options) => {
@@ -533,7 +533,8 @@ describe('shared drive recipient revocation', () => {
533
533
  sharingCol = {
534
534
  addRecipients: jest.fn(),
535
535
  create: jest.fn().mockResolvedValue({ data: NEW_SHARING }),
536
- revokeRecipient: jest.fn().mockResolvedValue({})
536
+ revokeRecipient: jest.fn().mockResolvedValue({}),
537
+ fetchEffectiveRecipients: jest.fn().mockResolvedValue({ data: [] })
537
538
  }
538
539
  provider.sharingCol = sharingCol
539
540
  })
@@ -792,7 +793,8 @@ describe('updateSharingMemberType', () => {
792
793
  )
793
794
  instance.sharingCol = {
794
795
  setReadOnly: jest.fn().mockResolvedValue({}),
795
- setReadWrite: jest.fn().mockResolvedValue({})
796
+ setReadWrite: jest.fn().mockResolvedValue({}),
797
+ fetchEffectiveRecipients: jest.fn().mockResolvedValue({ data: [] })
796
798
  }
797
799
  })
798
800
 
@@ -913,6 +915,12 @@ describe('updateSharingMemberType', () => {
913
915
  }
914
916
  })
915
917
  expect(instance.dispatch).toHaveBeenNthCalledWith(2, {
918
+ type: 'UPDATE_EFFECTIVE_RECIPIENT',
919
+ sharingId: 'sharing-123',
920
+ memberIndex: 1,
921
+ readOnly: true
922
+ })
923
+ expect(instance.dispatch).toHaveBeenNthCalledWith(3, {
916
924
  type: 'UPDATE_SHARING',
917
925
  sharing: {
918
926
  ...mockSharing,
@@ -928,6 +936,12 @@ describe('updateSharingMemberType', () => {
928
936
  }
929
937
  }
930
938
  })
939
+ expect(instance.dispatch).toHaveBeenNthCalledWith(4, {
940
+ type: 'UPDATE_EFFECTIVE_RECIPIENT',
941
+ sharingId: 'sharing-123',
942
+ memberIndex: 1,
943
+ readOnly: false
944
+ })
931
945
  })
932
946
 
933
947
  it('should preserve realtime changes when rolling back an API failure', async () => {
@@ -964,6 +978,12 @@ describe('updateSharingMemberType', () => {
964
978
  ).rejects.toThrow('Network error')
965
979
 
966
980
  expect(instance.dispatch).toHaveBeenNthCalledWith(2, {
981
+ type: 'UPDATE_EFFECTIVE_RECIPIENT',
982
+ sharingId: 'sharing-123',
983
+ memberIndex: 1,
984
+ readOnly: true
985
+ })
986
+ expect(instance.dispatch).toHaveBeenNthCalledWith(3, {
967
987
  type: 'UPDATE_SHARING',
968
988
  sharing: {
969
989
  ...realtimeSharing,
@@ -979,6 +999,12 @@ describe('updateSharingMemberType', () => {
979
999
  }
980
1000
  }
981
1001
  })
1002
+ expect(instance.dispatch).toHaveBeenNthCalledWith(4, {
1003
+ type: 'UPDATE_EFFECTIVE_RECIPIENT',
1004
+ sharingId: 'sharing-123',
1005
+ memberIndex: 1,
1006
+ readOnly: false
1007
+ })
982
1008
  })
983
1009
  })
984
1010
 
@@ -16,7 +16,6 @@ import { getOrCreateFromArray } from '../../helpers/contacts'
16
16
  import withLocales from '../../hoc/withLocales'
17
17
  import { usePendingRecipients } from '../../hooks/usePendingRecipients'
18
18
  import { useSharingContext } from '../../hooks/useSharingContext'
19
- import { getRecipientsFromSharing } from '../../state'
20
19
  import styles from '../../styles/share.styl'
21
20
  import AntivirusAlert from '../AntivirusAlert'
22
21
  import { default as DumbShareByEmail } from '../ShareByEmail'
@@ -29,6 +28,7 @@ const FederatedFolderModalContent = ({
29
28
  onClose,
30
29
  onRevokeSuccess,
31
30
  document: existingDocument,
31
+ recipients,
32
32
  autoOpenShareRestriction,
33
33
  showGenerateLinkButton
34
34
  }) => {
@@ -48,10 +48,6 @@ const FederatedFolderModalContent = ({
48
48
  getFederatedShareLink,
49
49
  getDocumentPermissions,
50
50
  fetchSharedDriveSharingLinks,
51
- getRecipients,
52
- getSharedParentPath,
53
- hasSharedChild,
54
- hasSharedParent,
55
51
  isOwner,
56
52
  revoke,
57
53
  revokeSelf
@@ -70,11 +66,9 @@ const FederatedFolderModalContent = ({
70
66
  useState(null)
71
67
  const [frozenDoc, setFrozenDoc] = useState(null)
72
68
  const [frozenRecipients, setFrozenRecipients] = useState(null)
73
- const [sharedParentFolder, setSharedParentFolder] = useState(null)
74
69
 
75
70
  const documentId = existingDocument?._id || existingDocument?.id
76
71
  const folderName = existingDocument?.name || ''
77
- const documentPath = existingDocument?.path
78
72
  const sharedDriveSharing = existingDocument?.driveId
79
73
  ? getSharingById(existingDocument.driveId)
80
74
  : null
@@ -83,25 +77,7 @@ const FederatedFolderModalContent = ({
83
77
  (ids, rule) => ids.concat(rule.values || []),
84
78
  []
85
79
  ) || []
86
- // Owner case: when document is inside a shared folder (via path) but has no driveId,
87
- // find the parent shared folder to use its _id for recipient/permission lookups.
88
- const hasSharedParentByPath = Boolean(
89
- documentPath && hasSharedParent(documentPath)
90
- )
91
- const sharedParentPath =
92
- !sharedDriveSharing && hasSharedParentByPath && documentPath
93
- ? getSharedParentPath(documentPath)
94
- : null
95
- const sharingReferenceId =
96
- !sharedDriveSharing && sharedParentFolder?._id
97
- ? sharedParentFolder._id
98
- : documentId
99
- const existingRecipients =
100
- sharedDriveSharing?.attributes?.members && documentId
101
- ? getRecipientsFromSharing(sharedDriveSharing, documentId)
102
- : sharingReferenceId
103
- ? getRecipients(sharingReferenceId)
104
- : []
80
+
105
81
  const documentPermissions = documentId
106
82
  ? getDocumentPermissions(documentId)
107
83
  : []
@@ -124,11 +100,6 @@ const FederatedFolderModalContent = ({
124
100
  ? isOwner(documentId)
125
101
  : false
126
102
  const isMemberReadOnly = isInsideSharedDrive && !isCurrentUserOwner
127
- const hasParentRestriction = isInsideSharedDrive || hasSharedParentByPath
128
- const hasChildRestriction = Boolean(
129
- documentPath && hasSharedChild(documentPath)
130
- )
131
- const canShareByEmail = !hasParentRestriction && !hasChildRestriction
132
103
  const canManageSharing =
133
104
  isCurrentUserOwner || (documentId ? canReshare(documentId) : false)
134
105
 
@@ -181,7 +152,7 @@ const FederatedFolderModalContent = ({
181
152
 
182
153
  setIsSending(true)
183
154
  setFrozenDoc(existingDocument)
184
- setFrozenRecipients(existingRecipients)
155
+ setFrozenRecipients(recipients)
185
156
 
186
157
  try {
187
158
  const contacts = await getOrCreateFromArray(
@@ -219,21 +190,6 @@ const FederatedFolderModalContent = ({
219
190
  }
220
191
  }
221
192
 
222
- useEffect(() => {
223
- if (!sharedParentPath) return
224
- const fetchParentFolder = async () => {
225
- try {
226
- const res = await client
227
- .collection('io.cozy.files')
228
- .statByPath(sharedParentPath)
229
- if (res.data) setSharedParentFolder(res.data)
230
- } catch (err) {
231
- log.error('Failed to fetch shared parent folder', err)
232
- }
233
- }
234
- fetchParentFolder()
235
- }, [sharedParentPath, client])
236
-
237
193
  useEffect(() => {
238
194
  if (!existingDocument?.driveId) return
239
195
  if (!documentId) return
@@ -283,7 +239,7 @@ const FederatedFolderModalContent = ({
283
239
  <AntivirusAlert
284
240
  document={isSending ? frozenDoc : existingDocument}
285
241
  />
286
- {!canShareByEmail && (
242
+ {isInsideSharedDrive ? (
287
243
  <div className={styles['share-byemail-onlybylink']}>
288
244
  {t('Files.share.shareByEmail.onlyByLink', {
289
245
  type: t(
@@ -292,26 +248,15 @@ const FederatedFolderModalContent = ({
292
248
  }`
293
249
  )
294
250
  })}{' '}
295
- <strong>
296
- {t(
297
- `Files.share.shareByEmail.${
298
- hasParentRestriction
299
- ? 'hasSharedParent'
300
- : 'hasSharedChild'
301
- }`
302
- )}
303
- </strong>
251
+ <strong>{t('Files.share.shareByEmail.hasSharedParent')}</strong>
304
252
  </div>
305
- )}
306
- {canShareByEmail && (
253
+ ) : (
307
254
  <>
308
255
  <Typography variant="h6" className="u-mt-1-half u-mb-half">
309
256
  {t('Share.contacts.addUsers')}
310
257
  </Typography>
311
258
  <DumbShareByEmail
312
- currentRecipients={
313
- isSending ? frozenRecipients : existingRecipients
314
- }
259
+ currentRecipients={isSending ? frozenRecipients : recipients}
315
260
  document={isSending ? frozenDoc : existingDocument}
316
261
  documentType="Files"
317
262
  pendingRecipients={pendingRecipients}
@@ -329,7 +274,7 @@ const FederatedFolderModalContent = ({
329
274
  isSharedDrive
330
275
  canManageMembers={!isMemberReadOnly}
331
276
  canManageLink={true}
332
- recipients={isSending ? frozenRecipients : existingRecipients}
277
+ recipients={isSending ? frozenRecipients : recipients}
333
278
  document={isSending ? frozenDoc : existingDocument}
334
279
  documentType="Files"
335
280
  className={styles['share-dialog-members']}
@@ -348,7 +293,7 @@ const FederatedFolderModalContent = ({
348
293
  showGenerateLinkButton={showGenerateLinkButton}
349
294
  autoOpenShareRestriction={autoOpenShareRestriction}
350
295
  />
351
- {canShareByEmail && (
296
+ {!isInsideSharedDrive && (
352
297
  <Button
353
298
  variant="primary"
354
299
  label={t('FederatedFolder.share')}
@@ -362,9 +307,49 @@ const FederatedFolderModalContent = ({
362
307
  )
363
308
  }
364
309
 
310
+ FederatedFolderModalContent.propTypes = {
311
+ onClose: PropTypes.func.isRequired,
312
+ onRevokeSuccess: PropTypes.func,
313
+ document: PropTypes.object.isRequired,
314
+ recipients: PropTypes.array,
315
+ autoOpenShareRestriction: PropTypes.bool,
316
+ showGenerateLinkButton: PropTypes.bool
317
+ }
318
+
319
+ const FederatedFolderModalWrapper = ({ document, ...props }) => {
320
+ const fileId = document._id || document.id
321
+ const {
322
+ getEffectiveRecipients,
323
+ fetchEffectiveRecipients,
324
+ invalidateEffectiveRecipients
325
+ } = useSharingContext()
326
+
327
+ useEffect(() => {
328
+ fetchEffectiveRecipients(fileId, document.driveId).catch(log.error)
329
+ return () => {
330
+ invalidateEffectiveRecipients(fileId)
331
+ }
332
+ }, [
333
+ fileId,
334
+ document.driveId,
335
+ fetchEffectiveRecipients,
336
+ invalidateEffectiveRecipients
337
+ ])
338
+
339
+ const recipients = getEffectiveRecipients(fileId)
340
+
341
+ return (
342
+ <FederatedFolderModalContent
343
+ document={document}
344
+ recipients={recipients}
345
+ {...props}
346
+ />
347
+ )
348
+ }
349
+
365
350
  export const FederatedFolderModal = withLocales(props => (
366
351
  <ConfirmDialogProvider>
367
- <FederatedFolderModalContent {...props} />
352
+ <FederatedFolderModalWrapper {...props} />
368
353
  </ConfirmDialogProvider>
369
354
  ))
370
355