cozy-sharing 33.5.1 → 33.6.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/SharingProvider.spec.js +242 -113
  3. package/dist/components/FederatedFolder/FederatedFolderModal.js +1 -4
  4. package/dist/components/Recipient/LinkRecipient.js +40 -17
  5. package/dist/components/Recipient/LinkRecipientPermissions.js +7 -6
  6. package/dist/components/Recipient/MemberRecipient.js +1 -4
  7. package/dist/components/Recipient/MemberRecipientPermissions.js +4 -6
  8. package/dist/components/Recipient/RecipientConfirm.js +1 -4
  9. package/dist/components/Recipient/RecipientList.js +2 -0
  10. package/dist/components/ShareByEmail.js +1 -4
  11. package/dist/components/ShareDialogCozyToCozy.js +1 -4
  12. package/dist/components/ShareModal/ShareModal.js +1 -5
  13. package/dist/components/ShareModal/SharingDetailsModal.js +6 -38
  14. package/dist/components/SharedDrive/EditSharedDriveModal.js +1 -4
  15. package/dist/components/WhoHasAccess.js +4 -0
  16. package/dist/state.js +5 -4
  17. package/dist/state.spec.js +44 -27
  18. package/dist/styles/share.styl +0 -21
  19. package/dist/stylesheet.css +0 -22
  20. package/locales/en.json +1 -2
  21. package/locales/fr.json +1 -2
  22. package/locales/ru.json +1 -2
  23. package/locales/vi.json +1 -2
  24. package/package.json +2 -2
  25. package/src/SharingProvider.spec.jsx +115 -1
  26. package/src/components/Recipient/LinkRecipient.jsx +50 -15
  27. package/src/components/Recipient/LinkRecipientPermissions.jsx +27 -20
  28. package/src/components/Recipient/MemberRecipient.jsx +1 -1
  29. package/src/components/Recipient/MemberRecipientPermissions.jsx +10 -5
  30. package/src/components/Recipient/RecipientList.jsx +2 -0
  31. package/src/components/ShareModal/ShareModal.jsx +1 -5
  32. package/src/components/ShareModal/SharingDetailsModal.jsx +3 -47
  33. package/src/components/WhoHasAccess.jsx +3 -0
  34. package/src/state.js +5 -13
  35. package/src/state.spec.js +63 -29
  36. package/src/styles/share.styl +0 -21
@@ -5,7 +5,12 @@ import { createMockClient } from 'cozy-client'
5
5
 
6
6
  import { SharingProvider } from './SharingProvider'
7
7
  import SharingContext from './context'
8
- import reducer, { addSharingLink, getDocumentPermissions } from './state'
8
+ import reducer, {
9
+ addSharingLink,
10
+ getDocumentPermissions,
11
+ getDocumentSharing,
12
+ receiveSharings
13
+ } from './state'
9
14
  import AppLike from '../test/AppLike'
10
15
 
11
16
  const AppWrapper = ({ children, client, isPublic }) => {
@@ -291,6 +296,115 @@ describe('updateDocumentPermissions', () => {
291
296
  })
292
297
  })
293
298
 
299
+ describe('shared drive recipient revocation', () => {
300
+ const SHARED_DRIVE = {
301
+ _id: 'sharing_123',
302
+ id: 'sharing_123',
303
+ type: 'io.cozy.sharings',
304
+ attributes: {
305
+ drive: true,
306
+ owner: true,
307
+ description: 'Shared folder',
308
+ rules: [
309
+ {
310
+ title: 'Shared folder',
311
+ doctype: 'io.cozy.files',
312
+ values: ['folder_123'],
313
+ add: 'none',
314
+ update: 'none',
315
+ remove: 'none'
316
+ }
317
+ ],
318
+ members: [
319
+ {
320
+ status: 'owner',
321
+ email: 'owner@cozy.local',
322
+ instance: 'http://cozy.local'
323
+ },
324
+ {
325
+ status: 'pending',
326
+ email: 'recipient@cozy.local',
327
+ instance: 'http://recipient.cozy.local'
328
+ }
329
+ ]
330
+ }
331
+ }
332
+ const NEW_SHARING = {
333
+ ...SHARED_DRIVE,
334
+ _id: 'sharing_456',
335
+ id: 'sharing_456'
336
+ }
337
+ const document = {
338
+ _id: 'folder_123',
339
+ id: 'folder_123',
340
+ path: '/Shared folder'
341
+ }
342
+ const recipient = {
343
+ _id: 'contact_123',
344
+ id: 'contact_123',
345
+ _type: 'io.cozy.contacts',
346
+ email: 'recipient@cozy.local'
347
+ }
348
+
349
+ let provider
350
+ let sharingCol
351
+
352
+ beforeEach(() => {
353
+ const mockClient = createMockClient({})
354
+ mockClient.getStackClient = () => ({ uri: 'http://cozy.local' })
355
+ mockClient.collection = jest.fn().mockReturnValue({})
356
+
357
+ provider = new SharingProvider({ client: mockClient })
358
+ provider.state = {
359
+ ...provider.state,
360
+ ...reducer(undefined, receiveSharings({ sharings: [SHARED_DRIVE] }))
361
+ }
362
+ provider.dispatch = jest.fn(action => {
363
+ provider.state = {
364
+ ...provider.state,
365
+ ...reducer(provider.state, action)
366
+ }
367
+ })
368
+ sharingCol = {
369
+ addRecipients: jest.fn(),
370
+ create: jest.fn().mockResolvedValue({ data: NEW_SHARING }),
371
+ revokeRecipient: jest.fn().mockResolvedValue({})
372
+ }
373
+ provider.sharingCol = sharingCol
374
+ })
375
+
376
+ it('forgets the shared drive when revoking its last recipient', async () => {
377
+ await provider.revoke(document, SHARED_DRIVE.id, 1)
378
+
379
+ expect(sharingCol.revokeRecipient).toHaveBeenCalledWith(SHARED_DRIVE, 1)
380
+ expect(getDocumentSharing(provider.state, document.id)).toBeNull()
381
+ })
382
+
383
+ it('creates a new sharing when re-adding after the last recipient was revoked', async () => {
384
+ await provider.revoke(document, SHARED_DRIVE.id, 1)
385
+
386
+ await provider.share({
387
+ document,
388
+ recipients: [recipient],
389
+ readOnlyRecipients: [],
390
+ description: 'Shared folder',
391
+ openSharing: true,
392
+ sharedDrive: true
393
+ })
394
+
395
+ expect(sharingCol.addRecipients).not.toHaveBeenCalled()
396
+ expect(sharingCol.create).toHaveBeenCalledWith({
397
+ document,
398
+ recipients: [recipient],
399
+ readOnlyRecipients: [],
400
+ description: 'Shared folder',
401
+ previewPath: '/preview',
402
+ openSharing: true,
403
+ sharedDrive: true
404
+ })
405
+ })
406
+ })
407
+
294
408
  describe('fetchSharedDriveSharingLinks', () => {
295
409
  const PERM_DRIVE_FILE = {
296
410
  type: 'io.cozy.permissions',
@@ -24,16 +24,51 @@ import { FADE_IN_DURATION } from '../../helpers/recipients'
24
24
  import { useSharingContext } from '../../hooks/useSharingContext'
25
25
  import { ShareRestrictionModal } from '../ShareRestrictionModal/ShareRestrictionModal'
26
26
 
27
+ const LinkRecipientTextReadOnly = ({ textPrimary, textSecondary }) => {
28
+ return (
29
+ <ListItemText
30
+ primary={
31
+ <div className="u-flex u-flex-items-center">
32
+ <Typography>{textPrimary}</Typography>
33
+ </div>
34
+ }
35
+ secondary={textSecondary}
36
+ />
37
+ )
38
+ }
39
+
40
+ const LinkRecipientText = ({ onClick, textPrimary, textSecondary }) => {
41
+ return (
42
+ <ListItemText
43
+ onClick={onClick}
44
+ primary={
45
+ <div className="u-flex u-flex-items-center">
46
+ <Typography className="u-c-pointer ">{textPrimary}</Typography>
47
+ <IconButton size="small" className="u-ml-half">
48
+ <Icon icon={Gear} />
49
+ </IconButton>
50
+ </div>
51
+ }
52
+ secondary={textSecondary}
53
+ />
54
+ )
55
+ }
56
+
27
57
  const LinkRecipient = props => {
28
58
  const { t, f, lang } = useI18n()
29
59
  const { isMobile } = useBreakpoints()
30
60
  const { getDocumentPermissions } = useSharingContext()
31
61
 
32
- const { recipientConfirmationData, verifyRecipient, fadeIn, document } = props
62
+ const {
63
+ recipientConfirmationData,
64
+ verifyRecipient,
65
+ fadeIn,
66
+ document,
67
+ isReadOnly
68
+ } = props
33
69
 
34
70
  const [openShareRestrictionModal, setOpenShareRestrictionModal] =
35
71
  useState(false)
36
-
37
72
  const permissions = getDocumentPermissions(document?._id)
38
73
  const hasPassword = checkIsPermissionHasPassword(permissions)
39
74
  const expiresDate = getPermissionExpiresDate(permissions)
@@ -57,7 +92,7 @@ const LinkRecipient = props => {
57
92
  verifyRecipient={verifyRecipient}
58
93
  />
59
94
  ) : (
60
- <LinkRecipientPermissions {...props} className="u-flex-shrink-0" />
95
+ <LinkRecipientPermissions {...props} />
61
96
  )
62
97
 
63
98
  return (
@@ -68,18 +103,18 @@ const LinkRecipient = props => {
68
103
  <Icon icon={LinkIcon} />
69
104
  </Avatar>
70
105
  </ListItemIcon>
71
- <ListItemText
72
- onClick={() => setOpenShareRestrictionModal(true)}
73
- primary={
74
- <div className="u-flex u-flex-items-center">
75
- <Typography className="u-c-pointer ">{textPrimary}</Typography>
76
- <IconButton size="small" className="u-ml-half">
77
- <Icon icon={Gear} />
78
- </IconButton>
79
- </div>
80
- }
81
- secondary={textSecondary}
82
- />
106
+ {isReadOnly ? (
107
+ <LinkRecipientTextReadOnly
108
+ textPrimary={textPrimary}
109
+ textSecondary={textSecondary}
110
+ />
111
+ ) : (
112
+ <LinkRecipientText
113
+ onClick={() => setOpenShareRestrictionModal(true)}
114
+ textPrimary={textPrimary}
115
+ textSecondary={textSecondary}
116
+ />
117
+ )}
83
118
  {RightPart}
84
119
  {openShareRestrictionModal && (
85
120
  <ShareRestrictionModal
@@ -7,6 +7,7 @@ import {
7
7
  divider
8
8
  } from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
9
9
  import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
10
+ import Typography from 'cozy-ui/transpiled/react/Typography'
10
11
  import { useI18n } from 'twake-i18n'
11
12
 
12
13
  import { revokeLink } from './actions/revokeLink'
@@ -17,7 +18,7 @@ import { checkIsReadOnlyPermissions } from '../../helpers/permissions'
17
18
  import { useSharingContext } from '../../hooks/useSharingContext'
18
19
  import { WRITE_PERMS, READ_ONLY_PERMS } from '../ShareRestrictionModal/helpers'
19
20
 
20
- const LinkRecipientPermissions = ({ className, document }) => {
21
+ const LinkRecipientPermissions = ({ document, isReadOnly }) => {
21
22
  const { t } = useI18n()
22
23
  const buttonRef = useRef()
23
24
  const [isMenuDisplayed, setMenuDisplayed] = useState(false)
@@ -56,30 +57,36 @@ const LinkRecipientPermissions = ({ className, document }) => {
56
57
  handleRevocation
57
58
  })
58
59
 
60
+ const shouldShowMenu = !isReadOnly
61
+
59
62
  return (
60
- <div className={className}>
61
- <>
62
- <DropdownButton
63
- ref={buttonRef}
64
- textVariant="body2"
65
- onClick={toggleMenu}
66
- >
67
- {t(`Share.type.${type}`)}
68
- </DropdownButton>
69
- <ActionsMenu
70
- ref={buttonRef}
71
- open={isMenuDisplayed}
72
- actions={actions}
73
- autoClose
74
- onClose={hideMenu}
75
- />
76
- </>
77
- </div>
63
+ <>
64
+ {!shouldShowMenu && (
65
+ <Typography variant="body2">{t(`Share.type.${type}`)}</Typography>
66
+ )}
67
+ {shouldShowMenu && (
68
+ <>
69
+ <DropdownButton
70
+ ref={buttonRef}
71
+ textVariant="body2"
72
+ onClick={toggleMenu}
73
+ >
74
+ {t(`Share.type.${type}`)}
75
+ </DropdownButton>
76
+ <ActionsMenu
77
+ ref={buttonRef}
78
+ open={isMenuDisplayed}
79
+ actions={actions}
80
+ autoClose
81
+ onClose={hideMenu}
82
+ />
83
+ </>
84
+ )}
85
+ </>
78
86
  )
79
87
  }
80
88
 
81
89
  LinkRecipientPermissions.propTypes = {
82
- className: PropTypes.string,
83
90
  document: PropTypes.object.isRequired
84
91
  }
85
92
 
@@ -46,7 +46,7 @@ const MemberRecipient = props => {
46
46
  verifyRecipient={verifyRecipient}
47
47
  />
48
48
  ) : (
49
- <MemberRecipientPermissions {...props} className="u-flex-shrink-0" />
49
+ <MemberRecipientPermissions {...props} />
50
50
  )
51
51
 
52
52
  return (
@@ -21,11 +21,11 @@ const log = minilog('MemberRecipientPermissions')
21
21
 
22
22
  const MemberRecipientPermissions = ({
23
23
  isOwner,
24
+ isReadOnly,
24
25
  status,
25
26
  instance,
26
27
  type,
27
28
  document,
28
- className,
29
29
  onRevoke,
30
30
  onRevokeSelf,
31
31
  sharingId,
@@ -44,6 +44,7 @@ const MemberRecipientPermissions = ({
44
44
  instance !== undefined && instance === client.options.uri
45
45
  const contactIsOwner = status === 'owner'
46
46
  const shouldShowMenu =
47
+ !isReadOnly &&
47
48
  !revoking &&
48
49
  !contactIsOwner &&
49
50
  ((instanceMatchesClient && !isOwner) || isOwner)
@@ -107,10 +108,14 @@ const MemberRecipientPermissions = ({
107
108
  )
108
109
 
109
110
  return (
110
- <div className={className}>
111
+ <>
111
112
  {revoking && <Spinner />}
112
- {!shouldShowMenu && !revoking && (
113
- <Typography variant="body2">{t(`Share.status.${status}`)}</Typography>
113
+ {!shouldShowMenu && (
114
+ <Typography variant="body2">
115
+ {contactIsOwner
116
+ ? t(`Share.status.${status}`)
117
+ : t(`Share.type.${type}`)}
118
+ </Typography>
114
119
  )}
115
120
  {shouldShowMenu && (
116
121
  <>
@@ -140,7 +145,7 @@ const MemberRecipientPermissions = ({
140
145
  </IconButton>
141
146
  </>
142
147
  )}
143
- </div>
148
+ </>
144
149
  )
145
150
  }
146
151
 
@@ -10,6 +10,7 @@ const RecipientList = ({
10
10
  recipientsToBeConfirmed,
11
11
  isOwner,
12
12
  isSharedDrive,
13
+ isReadOnly,
13
14
  document,
14
15
  documentType,
15
16
  onRevoke,
@@ -49,6 +50,7 @@ const RecipientList = ({
49
50
  key={recipient.index}
50
51
  isOwner={isOwner}
51
52
  isSharedDrive={isSharedDrive}
53
+ isReadOnly={isReadOnly}
52
54
  document={document}
53
55
  documentType={documentType}
54
56
  onRevoke={onRevoke}
@@ -22,8 +22,6 @@ export const ShareModal = withLocales(props => {
22
22
  isOwner,
23
23
  canReshare,
24
24
  documentType,
25
- getOwner,
26
- getSharingType,
27
25
  getRecipients,
28
26
  revokeSelf,
29
27
  allLoaded
@@ -48,11 +46,9 @@ export const ShareModal = withLocales(props => {
48
46
 
49
47
  return (
50
48
  <SharingDetailsModal
49
+ recipients={getRecipients(document.id)}
51
50
  document={document}
52
51
  documentType={documentType}
53
- owner={getOwner(document.id)}
54
- sharingType={getSharingType(document.id)}
55
- recipients={getRecipients(document.id)}
56
52
  onRevoke={revokeSelf}
57
53
  onRevokeSelf={handleRevokeSelf}
58
54
  {...rest}
@@ -1,29 +1,21 @@
1
- import cx from 'classnames'
2
1
  import PropTypes from 'prop-types'
3
2
  import React from 'react'
4
3
 
5
4
  import { Dialog } from 'cozy-ui/transpiled/react/CozyDialogs'
6
- import Divider from 'cozy-ui/transpiled/react/Divider'
7
- import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'
8
5
  import { useI18n } from 'twake-i18n'
9
6
 
10
- import { getDisplayName } from '../../models'
11
7
  import styles from '../../styles/share.styl'
12
- import OwnerIdentity from '../Identity/OwnerIdentity'
13
8
  import WhoHasAccess from '../WhoHasAccess'
14
9
 
15
10
  export const SharingDetailsModal = ({
16
11
  onClose,
17
- sharingType,
18
- owner,
19
12
  recipients,
20
13
  document,
21
14
  documentType = 'Document',
22
15
  onRevoke,
23
16
  onRevokeSelf
24
17
  }) => {
25
- const { t, f } = useI18n()
26
- const { isMobile } = useBreakpoints()
18
+ const { t } = useI18n()
27
19
 
28
20
  return (
29
21
  <Dialog
@@ -34,50 +26,14 @@ export const SharingDetailsModal = ({
34
26
  title={t(`${documentType}.share.details.title`)}
35
27
  content={
36
28
  <div className={styles['share-modal-content']}>
37
- <div
38
- className={cx(
39
- styles['share-details'],
40
- isMobile ? 'u-ph-1 u-pt-1-half' : 'u-ph-2 u-pt-1'
41
- )}
42
- >
43
- {owner ? (
44
- <OwnerIdentity
45
- name={t(`${documentType}.share.sharedBy`, {
46
- name: getDisplayName(owner)
47
- })}
48
- url={owner.instance}
49
- />
50
- ) : null}
51
- <div className={styles['share-details-created']}>
52
- {t(`${documentType}.share.details.createdAt`, {
53
- date: f(document.created_at || null, 'do LLLL yyyy')
54
- })}
55
- </div>
56
- <div className={styles['share-details-perm']}>
57
- {t(
58
- `${documentType}.share.details.${
59
- sharingType === 'one-way' ? 'ro' : 'rw'
60
- }`
61
- )}
62
- </div>
63
- <div className={styles['share-details-perm-desc']}>
64
- {t(
65
- `${documentType}.share.details.desc.${
66
- sharingType === 'one-way' ? 'ro' : 'rw'
67
- }`
68
- )}
69
- </div>
70
- </div>
71
- <Divider className="u-mv-1" />
72
29
  <WhoHasAccess
73
- title={t('Share.recipients.accessCount', {
74
- count: recipients.length
75
- })}
30
+ isReadOnly
76
31
  recipients={recipients}
77
32
  document={document}
78
33
  documentType={documentType}
79
34
  onRevoke={onRevoke}
80
35
  onRevokeSelf={onRevokeSelf}
36
+ link="ok"
81
37
  />
82
38
  </div>
83
39
  }
@@ -29,6 +29,7 @@ const RecipientWaitingForConfirmationAlert = ({ recipientsToBeConfirmed }) => {
29
29
  const WhoHasAccess = ({
30
30
  isOwner = false,
31
31
  isSharedDrive = false,
32
+ isReadOnly = false,
32
33
  showOwner = true,
33
34
  recipients,
34
35
  recipientsToBeConfirmed = [],
@@ -53,6 +54,7 @@ const WhoHasAccess = ({
53
54
  <List>
54
55
  {link && (
55
56
  <LinkRecipient
57
+ isReadOnly={isReadOnly}
56
58
  document={document}
57
59
  documentType={documentType}
58
60
  onRevoke={onRevoke}
@@ -69,6 +71,7 @@ const WhoHasAccess = ({
69
71
  recipientsToBeConfirmed={recipientsToBeConfirmed}
70
72
  isOwner={isOwner}
71
73
  isSharedDrive={isSharedDrive}
74
+ isReadOnly={isReadOnly}
72
75
  document={document}
73
76
  documentType={documentType}
74
77
  onRevoke={onRevoke}
package/src/state.js CHANGED
@@ -184,10 +184,7 @@ const byDocId = (state = {}, action) => {
184
184
  case REVOKE_GROUP:
185
185
  case REVOKE_RECIPIENT:
186
186
  case UPDATE_SHARING:
187
- if (
188
- !isSharingADrive(action.sharing) &&
189
- areAllRecipientsRevoked(action.sharing)
190
- ) {
187
+ if (areAllRecipientsRevoked(action.sharing)) {
191
188
  return forgetSharing(state, action.sharing)
192
189
  }
193
190
  return state
@@ -258,10 +255,7 @@ const sharings = (state = [], action) => {
258
255
  case UPDATE_SHARING:
259
256
  case REVOKE_GROUP:
260
257
  case REVOKE_RECIPIENT:
261
- if (
262
- !isSharingADrive(action.sharing) &&
263
- areAllRecipientsRevoked(action.sharing)
264
- ) {
258
+ if (areAllRecipientsRevoked(action.sharing)) {
265
259
  return state.filter(s => s.id !== action.sharing.id)
266
260
  }
267
261
  return state.map(s => {
@@ -287,10 +281,8 @@ const sharedPaths = (state = [], action) => {
287
281
  return newState
288
282
  case REVOKE_GROUP:
289
283
  case REVOKE_RECIPIENT:
290
- if (
291
- !isSharingADrive(action.sharing) &&
292
- areAllRecipientsRevoked(action.sharing)
293
- ) {
284
+ case UPDATE_SHARING:
285
+ if (areAllRecipientsRevoked(action.sharing)) {
294
286
  return state.filter(p => p !== action.path)
295
287
  }
296
288
  return state
@@ -351,7 +343,7 @@ export const canReshare = (state, docId, instanceUri) => {
351
343
  const sharing = getDocumentSharing(state, docId)
352
344
  const me = sharing.attributes.members.find(matchingInstanceName(instanceUri))
353
345
  if (sharing.drive) {
354
- return me && !me.read_only
346
+ return !sharing.org_drive && me && !me.read_only
355
347
  } else {
356
348
  return sharing.attributes.open_sharing === true && me && !me.read_only
357
349
  }
package/src/state.spec.js CHANGED
@@ -6,6 +6,7 @@ import reducer, {
6
6
  revokeSharingLink,
7
7
  getRecipients,
8
8
  getRecipientsFromSharing,
9
+ revokeGroup,
9
10
  revokeRecipient,
10
11
  revokeSelf,
11
12
  updateSharing,
@@ -143,7 +144,7 @@ describe('Sharing state', () => {
143
144
  expect(state.sharings).toEqual([SHARING_1, SHARED_DRIVE_WITHOUT_RECIPIENTS])
144
145
  })
145
146
 
146
- it('should not forget shared drives without recipients when updating', () => {
147
+ it('should forget shared drives without recipients when updating', () => {
147
148
  const SHARED_DRIVE_WITHOUT_RECIPIENTS = {
148
149
  ...SHARING_1,
149
150
  id: 'shared_drive_no_recipients',
@@ -184,16 +185,65 @@ describe('Sharing state', () => {
184
185
  }
185
186
  }
186
187
  const state = reducer(initialState, updateSharing(updatedSharing))
187
- expect(state.byDocId).toEqual({
188
- shared_drive_folder: {
189
- sharings: [SHARED_DRIVE_WITHOUT_RECIPIENTS.id],
190
- permissions: []
188
+
189
+ expect(state.byDocId).toEqual({})
190
+ expect(state.sharings).toEqual([])
191
+ })
192
+
193
+ it('should forget a shared drive when revoking its last group', () => {
194
+ const SHARED_DRIVE_WITH_GROUP = {
195
+ ...SHARING_1,
196
+ id: 'shared_drive_group',
197
+ attributes: {
198
+ ...SHARING_1.attributes,
199
+ drive: true,
200
+ members: [
201
+ {
202
+ status: 'owner',
203
+ name: 'Jane Doe',
204
+ email: 'jane@doe.com',
205
+ instance: 'http://cozy.tools:8080'
206
+ }
207
+ ],
208
+ groups: [
209
+ {
210
+ name: 'Last group',
211
+ addedBy: 0
212
+ }
213
+ ],
214
+ rules: [
215
+ {
216
+ title: 'My Shared Drive',
217
+ doctype: 'io.cozy.files',
218
+ values: ['shared_drive_group_folder'],
219
+ add: 'sync',
220
+ update: 'sync',
221
+ remove: 'sync'
222
+ }
223
+ ]
191
224
  }
192
- })
193
- expect(state.sharings).toEqual([updatedSharing])
225
+ }
226
+ const sharedDrivePath = '/shared_drive_group_folder'
227
+ const initialState = reducer(
228
+ reducer(
229
+ undefined,
230
+ receiveSharings({
231
+ sharings: [SHARED_DRIVE_WITH_GROUP]
232
+ })
233
+ ),
234
+ addSharing(SHARED_DRIVE_WITH_GROUP, sharedDrivePath)
235
+ )
236
+ const state = reducer(
237
+ initialState,
238
+ revokeGroup(SHARED_DRIVE_WITH_GROUP, 0, sharedDrivePath)
239
+ )
240
+
241
+ expect(state.byDocId).toEqual({})
242
+ expect(state.sharings).toEqual([])
243
+ expect(state.sharedPaths).toEqual([])
194
244
  })
195
245
 
196
- it('should not remove shared drive path when revoking last recipient', () => {
246
+ it('should forget a shared drive when revoking last recipient', () => {
197
247
  const SHARED_DRIVE_WITH_ONE_RECIPIENT = {
198
248
  ...SHARING_1,
199
249
  id: 'shared_drive_one_recipient',
@@ -236,30 +286,14 @@ describe('Sharing state', () => {
236
286
  ),
237
287
  addSharing(SHARED_DRIVE_WITH_ONE_RECIPIENT, sharedDrivePath)
238
288
  )
239
- const sharingAfterRevoke = {
240
- ...SHARED_DRIVE_WITH_ONE_RECIPIENT,
241
- attributes: {
242
- ...SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes,
243
- members: [
244
- SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[0],
245
- {
246
- ...SHARED_DRIVE_WITH_ONE_RECIPIENT.attributes.members[1],
247
- status: 'revoked'
248
- }
249
- ]
250
- }
251
- }
252
289
  const state = reducer(
253
290
  initialState,
254
- revokeRecipient(sharingAfterRevoke, 1, sharedDrivePath)
291
+ revokeRecipient(SHARED_DRIVE_WITH_ONE_RECIPIENT, 1, sharedDrivePath)
255
292
  )
256
- expect(state.sharedPaths).toContain(sharedDrivePath)
257
- expect(state.byDocId).toEqual({
258
- shared_drive_folder: {
259
- sharings: [SHARED_DRIVE_WITH_ONE_RECIPIENT.id],
260
- permissions: []
261
- }
262
- })
293
+
294
+ expect(state.byDocId).toEqual({})
295
+ expect(state.sharings).toEqual([])
296
+ expect(state.sharedPaths).toEqual([])
263
297
  })
264
298
 
265
299
  it('should index received permissions', () => {