cozy-sharing 38.1.5 → 38.1.7

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
+ ## [38.1.7](https://github.com/cozy/cozy-libs/compare/cozy-sharing@38.1.6...cozy-sharing@38.1.7) (2026-10-02)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **cozy-sharing:** Clear effective recipients when the sharing is gone ([24897a7](https://github.com/cozy/cozy-libs/commit/24897a7ed7381a2f9f6bd2c229622689756a23ad)), closes [linagora/twake-drive#4264](https://github.com/linagora/twake-drive/issues/4264)
11
+
12
+ ## [38.1.6](https://github.com/cozy/cozy-libs/compare/cozy-sharing@38.1.5...cozy-sharing@38.1.6) (2026-10-01)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **cozy-sharing:** Keep an unshared folder shareable by its owner ([d0bdac7](https://github.com/cozy/cozy-libs/commit/d0bdac725d3b854be789def6c67ae31ca8db59bd)), closes [linagora/twake-drive#4264](https://github.com/linagora/twake-drive/issues/4264)
17
+
6
18
  ## [38.1.5](https://github.com/cozy/cozy-libs/compare/cozy-sharing@38.1.4...cozy-sharing@38.1.5) (2026-09-30)
7
19
 
8
20
  **Note:** Version bump only for package cozy-sharing
@@ -618,21 +618,39 @@ export var SharingProvider = /*#__PURE__*/function (_Component) {
618
618
  return _regeneratorRuntime.wrap(function _callee11$(_context11) {
619
619
  while (1) switch (_context11.prev = _context11.next) {
620
620
  case 0:
621
- _context11.next = 2;
621
+ _context11.prev = 0;
622
+ _context11.next = 3;
622
623
  return _this2.sharingCol.fetchEffectiveRecipients(fileId, {
623
624
  driveId: driveId
624
625
  });
625
626
 
626
- case 2:
627
+ case 3:
627
628
  resp = _context11.sent;
628
629
 
629
630
  _this2.dispatch(receiveEffectiveRecipients(fileId, mapEffectiveRecipients((resp === null || resp === void 0 ? void 0 : resp.data) || [])));
630
631
 
631
- case 4:
632
+ _context11.next = 12;
633
+ break;
634
+
635
+ case 7:
636
+ _context11.prev = 7;
637
+ _context11.t0 = _context11["catch"](0);
638
+
639
+ if (!((_context11.t0 === null || _context11.t0 === void 0 ? void 0 : _context11.t0.status) !== 404)) {
640
+ _context11.next = 11;
641
+ break;
642
+ }
643
+
644
+ throw _context11.t0;
645
+
646
+ case 11:
647
+ _this2.dispatch(receiveEffectiveRecipients(fileId, []));
648
+
649
+ case 12:
632
650
  case "end":
633
651
  return _context11.stop();
634
652
  }
635
- }, _callee11);
653
+ }, _callee11, null, [[0, 7]]);
636
654
  }));
637
655
 
638
656
  return function (_x19, _x20) {
@@ -12,7 +12,7 @@ import React from 'react';
12
12
  import { createMockClient } from 'cozy-client';
13
13
  import { SharingProvider } from './SharingProvider';
14
14
  import SharingContext from './context';
15
- import reducer, { addSharingLink, getDocumentPermissions, getDocumentSharing, receiveSharings } from './state';
15
+ import reducer, { addSharingLink, getDocumentPermissions, getDocumentSharing, getEffectiveRecipients, receiveEffectiveRecipients, receiveSharings } from './state';
16
16
  import AppLike from '../test/AppLike';
17
17
 
18
18
  var AppWrapper = function AppWrapper(_ref) {
@@ -831,6 +831,45 @@ describe('shared drive recipient revocation', function () {
831
831
  }
832
832
  }, _callee15);
833
833
  })));
834
+ it('clears effective recipients when the sharing was deleted (404)', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16() {
835
+ return _regeneratorRuntime.wrap(function _callee16$(_context16) {
836
+ while (1) switch (_context16.prev = _context16.next) {
837
+ case 0:
838
+ provider.dispatch(receiveEffectiveRecipients(document.id, [{
839
+ sharingId: SHARED_DRIVE.id,
840
+ memberIndex: 1
841
+ }]));
842
+ sharingCol.fetchEffectiveRecipients.mockRejectedValue(Object.assign(new Error('deleted'), {
843
+ status: 404
844
+ }));
845
+ _context16.next = 4;
846
+ return expect(provider.fetchEffectiveRecipients(document.id, SHARED_DRIVE.id)).resolves.toBeUndefined();
847
+
848
+ case 4:
849
+ expect(getEffectiveRecipients(provider.state, document.id)).toEqual([]);
850
+
851
+ case 5:
852
+ case "end":
853
+ return _context16.stop();
854
+ }
855
+ }, _callee16);
856
+ })));
857
+ it('rethrows non-404 errors from fetching effective recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee17() {
858
+ return _regeneratorRuntime.wrap(function _callee17$(_context17) {
859
+ while (1) switch (_context17.prev = _context17.next) {
860
+ case 0:
861
+ sharingCol.fetchEffectiveRecipients.mockRejectedValue(Object.assign(new Error('boom'), {
862
+ status: 500
863
+ }));
864
+ _context17.next = 3;
865
+ return expect(provider.fetchEffectiveRecipients(document.id, SHARED_DRIVE.id)).rejects.toThrow('boom');
866
+
867
+ case 3:
868
+ case "end":
869
+ return _context17.stop();
870
+ }
871
+ }, _callee17);
872
+ })));
834
873
  });
835
874
  describe('fetchSharedDriveSharingLinks', function () {
836
875
  var PERM_DRIVE_FILE = {
@@ -855,10 +894,10 @@ describe('fetchSharedDriveSharingLinks', function () {
855
894
  id: 'file_in_drive',
856
895
  driveId: 'drive_123'
857
896
  };
858
- it('fetches shared drive sharing links by file id', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16() {
897
+ it('fetches shared drive sharing links by file id', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee18() {
859
898
  var mockFindLinksByIds, mockClient, provider, result, permissions;
860
- return _regeneratorRuntime.wrap(function _callee16$(_context16) {
861
- while (1) switch (_context16.prev = _context16.next) {
899
+ return _regeneratorRuntime.wrap(function _callee18$(_context18) {
900
+ while (1) switch (_context18.prev = _context18.next) {
862
901
  case 0:
863
902
  mockFindLinksByIds = jest.fn().mockResolvedValue({
864
903
  data: [PERM_DRIVE_FILE]
@@ -868,11 +907,11 @@ describe('fetchSharedDriveSharingLinks', function () {
868
907
  findLinksByIds: mockFindLinksByIds
869
908
  });
870
909
  provider = setupProvider(mockClient);
871
- _context16.next = 6;
910
+ _context18.next = 6;
872
911
  return provider.fetchSharedDriveSharingLinks(driveFile);
873
912
 
874
913
  case 6:
875
- result = _context16.sent;
914
+ result = _context18.sent;
876
915
  expect(mockClient.collection).toHaveBeenCalledWith('io.cozy.permissions', {
877
916
  driveId: 'drive_123'
878
917
  });
@@ -885,14 +924,14 @@ describe('fetchSharedDriveSharingLinks', function () {
885
924
 
886
925
  case 14:
887
926
  case "end":
888
- return _context16.stop();
927
+ return _context18.stop();
889
928
  }
890
- }, _callee16);
929
+ }, _callee18);
891
930
  })));
892
- it('returns an empty array and skips the API call for non-shared-drive documents', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee17() {
931
+ it('returns an empty array and skips the API call for non-shared-drive documents', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19() {
893
932
  var mockClient, findLinksByIds, provider, result;
894
- return _regeneratorRuntime.wrap(function _callee17$(_context17) {
895
- while (1) switch (_context17.prev = _context17.next) {
933
+ return _regeneratorRuntime.wrap(function _callee19$(_context19) {
934
+ while (1) switch (_context19.prev = _context19.next) {
896
935
  case 0:
897
936
  mockClient = createMockClient({});
898
937
  findLinksByIds = jest.fn();
@@ -901,27 +940,27 @@ describe('fetchSharedDriveSharingLinks', function () {
901
940
  });
902
941
  provider = setupProvider(mockClient);
903
942
  provider.dispatch = jest.fn();
904
- _context17.next = 7;
943
+ _context19.next = 7;
905
944
  return provider.fetchSharedDriveSharingLinks({
906
945
  _id: 'regular_file'
907
946
  });
908
947
 
909
948
  case 7:
910
- result = _context17.sent;
949
+ result = _context19.sent;
911
950
  expect(result).toEqual([]);
912
951
  expect(findLinksByIds).not.toHaveBeenCalled();
913
952
  expect(provider.dispatch).not.toHaveBeenCalled();
914
953
 
915
954
  case 11:
916
955
  case "end":
917
- return _context17.stop();
956
+ return _context19.stop();
918
957
  }
919
- }, _callee17);
958
+ }, _callee19);
920
959
  })));
921
- it('uses document.id as a fallback when _id is missing', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee18() {
960
+ it('uses document.id as a fallback when _id is missing', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
922
961
  var mockFindLinksByIds, mockClient, provider;
923
- return _regeneratorRuntime.wrap(function _callee18$(_context18) {
924
- while (1) switch (_context18.prev = _context18.next) {
962
+ return _regeneratorRuntime.wrap(function _callee20$(_context20) {
963
+ while (1) switch (_context20.prev = _context20.next) {
925
964
  case 0:
926
965
  mockFindLinksByIds = jest.fn().mockResolvedValue({
927
966
  data: [PERM_DRIVE_FILE]
@@ -931,7 +970,7 @@ describe('fetchSharedDriveSharingLinks', function () {
931
970
  findLinksByIds: mockFindLinksByIds
932
971
  });
933
972
  provider = setupProvider(mockClient);
934
- _context18.next = 6;
973
+ _context20.next = 6;
935
974
  return provider.fetchSharedDriveSharingLinks({
936
975
  id: 'file_in_drive',
937
976
  driveId: 'drive_123'
@@ -942,14 +981,14 @@ describe('fetchSharedDriveSharingLinks', function () {
942
981
 
943
982
  case 7:
944
983
  case "end":
945
- return _context18.stop();
984
+ return _context20.stop();
946
985
  }
947
- }, _callee18);
986
+ }, _callee20);
948
987
  })));
949
- it('does not dispatch when the response has no data', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19() {
988
+ it('does not dispatch when the response has no data', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee21() {
950
989
  var mockFindLinksByIds, mockClient, provider, result;
951
- return _regeneratorRuntime.wrap(function _callee19$(_context19) {
952
- while (1) switch (_context19.prev = _context19.next) {
990
+ return _regeneratorRuntime.wrap(function _callee21$(_context21) {
991
+ while (1) switch (_context21.prev = _context21.next) {
953
992
  case 0:
954
993
  mockFindLinksByIds = jest.fn().mockResolvedValue({
955
994
  data: []
@@ -960,19 +999,19 @@ describe('fetchSharedDriveSharingLinks', function () {
960
999
  });
961
1000
  provider = setupProvider(mockClient);
962
1001
  provider.dispatch = jest.fn();
963
- _context19.next = 7;
1002
+ _context21.next = 7;
964
1003
  return provider.fetchSharedDriveSharingLinks(driveFile);
965
1004
 
966
1005
  case 7:
967
- result = _context19.sent;
1006
+ result = _context21.sent;
968
1007
  expect(result).toEqual([]);
969
1008
  expect(provider.dispatch).not.toHaveBeenCalled();
970
1009
 
971
1010
  case 10:
972
1011
  case "end":
973
- return _context19.stop();
1012
+ return _context21.stop();
974
1013
  }
975
- }, _callee19);
1014
+ }, _callee21);
976
1015
  })));
977
1016
  });
978
1017
  describe('shareByLink shared drive 409 recovery', function () {
@@ -998,10 +1037,10 @@ describe('shareByLink shared drive 409 recovery', function () {
998
1037
  id: 'file_in_drive',
999
1038
  driveId: 'drive_123'
1000
1039
  };
1001
- it('falls back to fetching existing links when create returns 409', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
1040
+ it('falls back to fetching existing links when create returns 409', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee22() {
1002
1041
  var conflict, mockCreateSharingLink, mockFindLinksByIds, mockClient, provider, resp;
1003
- return _regeneratorRuntime.wrap(function _callee20$(_context20) {
1004
- while (1) switch (_context20.prev = _context20.next) {
1042
+ return _regeneratorRuntime.wrap(function _callee22$(_context22) {
1043
+ while (1) switch (_context22.prev = _context22.next) {
1005
1044
  case 0:
1006
1045
  conflict = Object.assign(new Error('Conflict'), {
1007
1046
  status: 409
@@ -1016,27 +1055,27 @@ describe('shareByLink shared drive 409 recovery', function () {
1016
1055
  findLinksByIds: mockFindLinksByIds
1017
1056
  });
1018
1057
  provider = setupProvider(mockClient);
1019
- _context20.next = 8;
1058
+ _context22.next = 8;
1020
1059
  return provider.shareByLink(driveFile, {
1021
1060
  verbs: ['GET']
1022
1061
  });
1023
1062
 
1024
1063
  case 8:
1025
- resp = _context20.sent;
1064
+ resp = _context22.sent;
1026
1065
  expect(mockCreateSharingLink).toHaveBeenCalled();
1027
1066
  expect(mockFindLinksByIds).toHaveBeenCalledWith(['file_in_drive']);
1028
1067
  expect(resp.data.id).toBe(PERM_DRIVE_FILE.id);
1029
1068
 
1030
1069
  case 12:
1031
1070
  case "end":
1032
- return _context20.stop();
1071
+ return _context22.stop();
1033
1072
  }
1034
- }, _callee20);
1073
+ }, _callee22);
1035
1074
  })));
1036
- it('does not duplicate existing links when 409 recovery refetches them', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee21() {
1075
+ it('does not duplicate existing links when 409 recovery refetches them', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee23() {
1037
1076
  var conflict, mockCreateSharingLink, mockFindLinksByIds, mockClient, provider, resp, permissions;
1038
- return _regeneratorRuntime.wrap(function _callee21$(_context21) {
1039
- while (1) switch (_context21.prev = _context21.next) {
1077
+ return _regeneratorRuntime.wrap(function _callee23$(_context23) {
1078
+ while (1) switch (_context23.prev = _context23.next) {
1040
1079
  case 0:
1041
1080
  conflict = Object.assign(new Error('Conflict'), {
1042
1081
  status: 409
@@ -1051,13 +1090,13 @@ describe('shareByLink shared drive 409 recovery', function () {
1051
1090
  findLinksByIds: mockFindLinksByIds
1052
1091
  });
1053
1092
  provider = setupProvider(mockClient, {}, reducer(undefined, addSharingLink(PERM_DRIVE_FILE)));
1054
- _context21.next = 8;
1093
+ _context23.next = 8;
1055
1094
  return provider.shareByLink(driveFile, {
1056
1095
  verbs: ['GET']
1057
1096
  });
1058
1097
 
1059
1098
  case 8:
1060
- resp = _context21.sent;
1099
+ resp = _context23.sent;
1061
1100
  permissions = getDocumentPermissions(provider.state, 'file_in_drive');
1062
1101
  expect(resp.data.id).toBe(PERM_DRIVE_FILE.id);
1063
1102
  expect(provider.dispatch).not.toHaveBeenCalled();
@@ -1065,14 +1104,14 @@ describe('shareByLink shared drive 409 recovery', function () {
1065
1104
 
1066
1105
  case 13:
1067
1106
  case "end":
1068
- return _context21.stop();
1107
+ return _context23.stop();
1069
1108
  }
1070
- }, _callee21);
1109
+ }, _callee23);
1071
1110
  })));
1072
- it('rethrows the original error when 409 happens and no link is found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee22() {
1111
+ it('rethrows the original error when 409 happens and no link is found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee24() {
1073
1112
  var conflict, mockCreateSharingLink, mockFindLinksByIds, mockClient, provider;
1074
- return _regeneratorRuntime.wrap(function _callee22$(_context22) {
1075
- while (1) switch (_context22.prev = _context22.next) {
1113
+ return _regeneratorRuntime.wrap(function _callee24$(_context24) {
1114
+ while (1) switch (_context24.prev = _context24.next) {
1076
1115
  case 0:
1077
1116
  conflict = Object.assign(new Error('Conflict'), {
1078
1117
  status: 409
@@ -1088,16 +1127,16 @@ describe('shareByLink shared drive 409 recovery', function () {
1088
1127
  });
1089
1128
  provider = setupProvider(mockClient);
1090
1129
  provider.dispatch = jest.fn();
1091
- _context22.next = 9;
1130
+ _context24.next = 9;
1092
1131
  return expect(provider.shareByLink(driveFile, {
1093
1132
  verbs: ['GET']
1094
1133
  })).rejects.toBe(conflict);
1095
1134
 
1096
1135
  case 9:
1097
1136
  case "end":
1098
- return _context22.stop();
1137
+ return _context24.stop();
1099
1138
  }
1100
- }, _callee22);
1139
+ }, _callee24);
1101
1140
  })));
1102
1141
  });
1103
1142
  describe('updateSharingMemberType', function () {
@@ -1140,37 +1179,37 @@ describe('updateSharingMemberType', function () {
1140
1179
  })
1141
1180
  };
1142
1181
  });
1143
- it('should throw when sharing is not found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee23() {
1144
- return _regeneratorRuntime.wrap(function _callee23$(_context23) {
1145
- while (1) switch (_context23.prev = _context23.next) {
1182
+ it('should throw when sharing is not found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee25() {
1183
+ return _regeneratorRuntime.wrap(function _callee25$(_context25) {
1184
+ while (1) switch (_context25.prev = _context25.next) {
1146
1185
  case 0:
1147
- _context23.next = 2;
1186
+ _context25.next = 2;
1148
1187
  return expect(instance.updateSharingMemberType('unknown-id', 1, 'one-way')).rejects.toThrow('Sharing not found');
1149
1188
 
1150
1189
  case 2:
1151
1190
  case "end":
1152
- return _context23.stop();
1191
+ return _context25.stop();
1153
1192
  }
1154
- }, _callee23);
1193
+ }, _callee25);
1155
1194
  })));
1156
- it('should throw when member is not found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee24() {
1157
- return _regeneratorRuntime.wrap(function _callee24$(_context24) {
1158
- while (1) switch (_context24.prev = _context24.next) {
1195
+ it('should throw when member is not found', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee26() {
1196
+ return _regeneratorRuntime.wrap(function _callee26$(_context26) {
1197
+ while (1) switch (_context26.prev = _context26.next) {
1159
1198
  case 0:
1160
- _context24.next = 2;
1199
+ _context26.next = 2;
1161
1200
  return expect(instance.updateSharingMemberType('sharing-123', 99, 'one-way')).rejects.toThrow('Member not found');
1162
1201
 
1163
1202
  case 2:
1164
1203
  case "end":
1165
- return _context24.stop();
1204
+ return _context26.stop();
1166
1205
  }
1167
- }, _callee24);
1206
+ }, _callee26);
1168
1207
  })));
1169
- it('should call setReadOnly when switching to one-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee25() {
1170
- return _regeneratorRuntime.wrap(function _callee25$(_context25) {
1171
- while (1) switch (_context25.prev = _context25.next) {
1208
+ it('should call setReadOnly when switching to one-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee27() {
1209
+ return _regeneratorRuntime.wrap(function _callee27$(_context27) {
1210
+ while (1) switch (_context27.prev = _context27.next) {
1172
1211
  case 0:
1173
- _context25.next = 2;
1212
+ _context27.next = 2;
1174
1213
  return instance.updateSharingMemberType('sharing-123', 1, 'one-way');
1175
1214
 
1176
1215
  case 2:
@@ -1179,15 +1218,15 @@ describe('updateSharingMemberType', function () {
1179
1218
 
1180
1219
  case 4:
1181
1220
  case "end":
1182
- return _context25.stop();
1221
+ return _context27.stop();
1183
1222
  }
1184
- }, _callee25);
1223
+ }, _callee27);
1185
1224
  })));
1186
- it('should call setReadWrite when switching to two-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee26() {
1187
- return _regeneratorRuntime.wrap(function _callee26$(_context26) {
1188
- while (1) switch (_context26.prev = _context26.next) {
1225
+ it('should call setReadWrite when switching to two-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee28() {
1226
+ return _regeneratorRuntime.wrap(function _callee28$(_context28) {
1227
+ while (1) switch (_context28.prev = _context28.next) {
1189
1228
  case 0:
1190
- _context26.next = 2;
1229
+ _context28.next = 2;
1191
1230
  return instance.updateSharingMemberType('sharing-123', 1, 'two-way');
1192
1231
 
1193
1232
  case 2:
@@ -1196,15 +1235,15 @@ describe('updateSharingMemberType', function () {
1196
1235
 
1197
1236
  case 4:
1198
1237
  case "end":
1199
- return _context26.stop();
1238
+ return _context28.stop();
1200
1239
  }
1201
- }, _callee26);
1240
+ }, _callee28);
1202
1241
  })));
1203
- it('should optimistically dispatch a state update when switching to one-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee27() {
1204
- return _regeneratorRuntime.wrap(function _callee27$(_context27) {
1205
- while (1) switch (_context27.prev = _context27.next) {
1242
+ it('should optimistically dispatch a state update when switching to one-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee29() {
1243
+ return _regeneratorRuntime.wrap(function _callee29$(_context29) {
1244
+ while (1) switch (_context29.prev = _context29.next) {
1206
1245
  case 0:
1207
- _context27.next = 2;
1246
+ _context29.next = 2;
1208
1247
  return instance.updateSharingMemberType('sharing-123', 1, 'one-way');
1209
1248
 
1210
1249
  case 2:
@@ -1221,15 +1260,15 @@ describe('updateSharingMemberType', function () {
1221
1260
 
1222
1261
  case 3:
1223
1262
  case "end":
1224
- return _context27.stop();
1263
+ return _context29.stop();
1225
1264
  }
1226
- }, _callee27);
1265
+ }, _callee29);
1227
1266
  })));
1228
- it('should optimistically dispatch a state update when switching to two-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee28() {
1229
- return _regeneratorRuntime.wrap(function _callee28$(_context28) {
1230
- while (1) switch (_context28.prev = _context28.next) {
1267
+ it('should optimistically dispatch a state update when switching to two-way', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee30() {
1268
+ return _regeneratorRuntime.wrap(function _callee30$(_context30) {
1269
+ while (1) switch (_context30.prev = _context30.next) {
1231
1270
  case 0:
1232
- _context28.next = 2;
1271
+ _context30.next = 2;
1233
1272
  return instance.updateSharingMemberType('sharing-123', 1, 'two-way');
1234
1273
 
1235
1274
  case 2:
@@ -1246,44 +1285,44 @@ describe('updateSharingMemberType', function () {
1246
1285
 
1247
1286
  case 3:
1248
1287
  case "end":
1249
- return _context28.stop();
1288
+ return _context30.stop();
1250
1289
  }
1251
- }, _callee28);
1290
+ }, _callee30);
1252
1291
  })));
1253
- it('should rethrow error if setReadOnly fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee29() {
1254
- return _regeneratorRuntime.wrap(function _callee29$(_context29) {
1255
- while (1) switch (_context29.prev = _context29.next) {
1292
+ it('should rethrow error if setReadOnly fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee31() {
1293
+ return _regeneratorRuntime.wrap(function _callee31$(_context31) {
1294
+ while (1) switch (_context31.prev = _context31.next) {
1256
1295
  case 0:
1257
1296
  instance.sharingCol.setReadOnly.mockRejectedValue(new Error('Network error'));
1258
- _context29.next = 3;
1297
+ _context31.next = 3;
1259
1298
  return expect(instance.updateSharingMemberType('sharing-123', 1, 'one-way')).rejects.toThrow('Network error');
1260
1299
 
1261
1300
  case 3:
1262
1301
  case "end":
1263
- return _context29.stop();
1302
+ return _context31.stop();
1264
1303
  }
1265
- }, _callee29);
1304
+ }, _callee31);
1266
1305
  })));
1267
- it('should rethrow error if setReadWrite fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee30() {
1268
- return _regeneratorRuntime.wrap(function _callee30$(_context30) {
1269
- while (1) switch (_context30.prev = _context30.next) {
1306
+ it('should rethrow error if setReadWrite fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee32() {
1307
+ return _regeneratorRuntime.wrap(function _callee32$(_context32) {
1308
+ while (1) switch (_context32.prev = _context32.next) {
1270
1309
  case 0:
1271
1310
  instance.sharingCol.setReadWrite.mockRejectedValue(new Error('Network error'));
1272
- _context30.next = 3;
1311
+ _context32.next = 3;
1273
1312
  return expect(instance.updateSharingMemberType('sharing-123', 1, 'two-way')).rejects.toThrow('Network error');
1274
1313
 
1275
1314
  case 3:
1276
1315
  case "end":
1277
- return _context30.stop();
1316
+ return _context32.stop();
1278
1317
  }
1279
- }, _callee30);
1318
+ }, _callee32);
1280
1319
  })));
1281
- it('should rollback optimistic state update if API call fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee31() {
1282
- return _regeneratorRuntime.wrap(function _callee31$(_context31) {
1283
- while (1) switch (_context31.prev = _context31.next) {
1320
+ it('should rollback optimistic state update if API call fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee33() {
1321
+ return _regeneratorRuntime.wrap(function _callee33$(_context33) {
1322
+ while (1) switch (_context33.prev = _context33.next) {
1284
1323
  case 0:
1285
1324
  instance.sharingCol.setReadOnly.mockRejectedValue(new Error('Network error'));
1286
- _context31.next = 3;
1325
+ _context33.next = 3;
1287
1326
  return expect(instance.updateSharingMemberType('sharing-123', 1, 'one-way')).rejects.toThrow('Network error');
1288
1327
 
1289
1328
  case 3:
@@ -1322,14 +1361,14 @@ describe('updateSharingMemberType', function () {
1322
1361
 
1323
1362
  case 7:
1324
1363
  case "end":
1325
- return _context31.stop();
1364
+ return _context33.stop();
1326
1365
  }
1327
- }, _callee31);
1366
+ }, _callee33);
1328
1367
  })));
1329
- it('should preserve realtime changes when rolling back an API failure', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee33() {
1368
+ it('should preserve realtime changes when rolling back an API failure', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee35() {
1330
1369
  var realtimeSharing;
1331
- return _regeneratorRuntime.wrap(function _callee33$(_context33) {
1332
- while (1) switch (_context33.prev = _context33.next) {
1370
+ return _regeneratorRuntime.wrap(function _callee35$(_context35) {
1371
+ while (1) switch (_context35.prev = _context35.next) {
1333
1372
  case 0:
1334
1373
  realtimeSharing = _objectSpread(_objectSpread({}, mockSharing), {}, {
1335
1374
  attributes: _objectSpread(_objectSpread({}, mockSharing.attributes), {}, {
@@ -1341,9 +1380,9 @@ describe('updateSharingMemberType', function () {
1341
1380
  })]
1342
1381
  })
1343
1382
  });
1344
- instance.sharingCol.setReadOnly.mockImplementation( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee32() {
1345
- return _regeneratorRuntime.wrap(function _callee32$(_context32) {
1346
- while (1) switch (_context32.prev = _context32.next) {
1383
+ instance.sharingCol.setReadOnly.mockImplementation( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee34() {
1384
+ return _regeneratorRuntime.wrap(function _callee34$(_context34) {
1385
+ while (1) switch (_context34.prev = _context34.next) {
1347
1386
  case 0:
1348
1387
  instance.state = _objectSpread(_objectSpread({}, instance.state), {}, {
1349
1388
  sharings: instance.state.sharings.map(function (sharing) {
@@ -1354,11 +1393,11 @@ describe('updateSharingMemberType', function () {
1354
1393
 
1355
1394
  case 2:
1356
1395
  case "end":
1357
- return _context32.stop();
1396
+ return _context34.stop();
1358
1397
  }
1359
- }, _callee32);
1398
+ }, _callee34);
1360
1399
  })));
1361
- _context33.next = 4;
1400
+ _context35.next = 4;
1362
1401
  return expect(instance.updateSharingMemberType('sharing-123', 1, 'one-way')).rejects.toThrow('Network error');
1363
1402
 
1364
1403
  case 4:
@@ -1387,9 +1426,9 @@ describe('updateSharingMemberType', function () {
1387
1426
 
1388
1427
  case 7:
1389
1428
  case "end":
1390
- return _context33.stop();
1429
+ return _context35.stop();
1391
1430
  }
1392
- }, _callee33);
1431
+ }, _callee35);
1393
1432
  })));
1394
1433
  }); // TODO Convert with react-testing-library
1395
1434
  // describe('hasWriteAccess', () => {
@@ -123,8 +123,9 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
123
123
  var displayedLink = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? getFederatedShareLink(existingDocument) : getSharingLink(existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument._id);
124
124
  var isSharedDriveRoot = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && sharedDriveRootIds.some(function (id) {
125
125
  return id === (existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument._id) || id === (existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.id);
126
- }));
127
- var isInsideSharedDrive = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && !isSharedDriveRoot);
126
+ })); // Ignore a stale driveId left after an owner revokes the last recipient, so their own folder isn't wrongly restricted to link-only (linagora/twake-drive#4264).
127
+
128
+ var isInsideSharedDrive = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && !isSharedDriveRoot && (sharedDriveSharing || !isOwner(documentId)));
128
129
  var isCurrentUserOwner = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? Boolean(sharedDriveSharing === null || sharedDriveSharing === void 0 || (_sharedDriveSharing$a2 = sharedDriveSharing.attributes) === null || _sharedDriveSharing$a2 === void 0 ? void 0 : _sharedDriveSharing$a2.owner) : documentId ? isOwner(documentId) : false;
129
130
  var isMemberReadOnly = isInsideSharedDrive && !isCurrentUserOwner && !hasWriteAccess(documentId, existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId);
130
131
  var canManageSharing = isCurrentUserOwner || (documentId ? canReshare(documentId) : false);