cozy-sharing 40.1.9 → 40.2.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 +14 -0
- package/README.md +1 -0
- package/dist/SharingOwnerAvatar.js +2 -2
- package/dist/SharingProvider.js +3 -1
- package/dist/components/Avatar/AvatarList.js +2 -2
- package/dist/components/Avatar/MemberAvatar.js +8 -33
- package/dist/components/Avatar/MemberAvatar.spec.js +17 -77
- package/dist/components/Avatar/MemberAvatarWrapper.js +20 -0
- package/dist/components/ConfirmTrustedRecipientsDialog.js +5 -1
- package/dist/components/ContactSuggestion.js +5 -2
- package/dist/components/Recipient/MemberRecipient.js +6 -3
- package/dist/components/Recipient/MemberRecipient.spec.js +1 -9
- package/dist/components/Recipient/MemberRecipientLite.js +2 -2
- package/dist/components/Recipient/PermissionTypeMenuWrapper.spec.js +3 -1
- package/dist/components/ShareAutosuggest.js +93 -16
- package/dist/components/ShareAutosuggest.spec.js +126 -3
- package/dist/components/ShareAutosuggest.stories.js +3 -0
- package/dist/components/ShareAutosuggestWrapper.js +65 -5
- package/dist/components/ShareAutosuggestWrapper.spec.js +113 -11
- package/dist/components/WhoHasAccessWrapper.js +6 -2
- package/dist/helpers/contacts.js +75 -16
- package/dist/helpers/contacts.spec.js +150 -1
- package/dist/helpers/recipients.js +38 -0
- package/dist/helpers/recipients.spec.js +53 -1
- package/dist/hooks/useResolveRecipients.js +6 -2
- package/dist/hooks/useResolveRecipients.spec.js +11 -2
- package/dist/index.js +1 -1
- package/dist/queries/queries.js +16 -3
- package/package.json +3 -3
- package/src/SharingOwnerAvatar.jsx +2 -2
- package/src/SharingProvider.jsx +6 -1
- package/src/components/Avatar/AvatarList.jsx +2 -2
- package/src/components/Avatar/MemberAvatar.jsx +4 -34
- package/src/components/Avatar/MemberAvatar.spec.jsx +13 -73
- package/src/components/Avatar/MemberAvatarWrapper.jsx +22 -0
- package/src/components/ConfirmTrustedRecipientsDialog.jsx +7 -0
- package/src/components/ContactSuggestion.jsx +8 -3
- package/src/components/Recipient/MemberRecipient.jsx +4 -2
- package/src/components/Recipient/MemberRecipient.spec.jsx +1 -8
- package/src/components/Recipient/MemberRecipientLite.jsx +2 -2
- package/src/components/Recipient/PermissionTypeMenuWrapper.spec.jsx +3 -1
- package/src/components/ShareAutosuggest.jsx +56 -9
- package/src/components/ShareAutosuggest.spec.jsx +60 -2
- package/src/components/ShareAutosuggest.stories.jsx +1 -0
- package/src/components/ShareAutosuggestWrapper.jsx +36 -4
- package/src/components/ShareAutosuggestWrapper.spec.jsx +78 -5
- package/src/components/WhoHasAccessWrapper.jsx +14 -2
- package/src/helpers/contacts.js +31 -1
- package/src/helpers/contacts.spec.js +102 -1
- package/src/helpers/recipients.js +40 -0
- package/src/helpers/recipients.spec.js +83 -1
- package/src/hooks/useResolveRecipients.js +5 -2
- package/src/hooks/useResolveRecipients.spec.js +8 -2
- package/src/index.jsx +1 -1
- package/src/queries/queries.js +6 -3
package/src/helpers/contacts.js
CHANGED
|
@@ -2,13 +2,30 @@ import { models } from 'cozy-client'
|
|
|
2
2
|
import flag from 'cozy-flags'
|
|
3
3
|
|
|
4
4
|
import { validateEmail } from '../helpers/email'
|
|
5
|
+
import { DOCTYPE_CONTACTS, DOCTYPE_GROUPS } from '../models'
|
|
5
6
|
|
|
6
7
|
const ContactModel = models.contact
|
|
7
8
|
|
|
8
9
|
// Return the contact object if present
|
|
9
10
|
// Else check if a contact exist with this email address, if yes return it
|
|
10
11
|
// if not create it
|
|
11
|
-
|
|
12
|
+
// With contactsSuggestEnabled, people are sent by email and the
|
|
13
|
+
// stack finds or creates the contact: an org member's id is not on this instance
|
|
14
|
+
export const getOrCreateFromArray = async (
|
|
15
|
+
client,
|
|
16
|
+
contacts,
|
|
17
|
+
createContact,
|
|
18
|
+
contactsSuggestEnabled
|
|
19
|
+
) => {
|
|
20
|
+
if (contactsSuggestEnabled) {
|
|
21
|
+
return contacts.map(contact => {
|
|
22
|
+
if (contact._type === DOCTYPE_GROUPS) return contact
|
|
23
|
+
const email = ContactModel.getPrimaryEmail(contact)
|
|
24
|
+
if (validateEmail(email)) return { _type: DOCTYPE_CONTACTS, email }
|
|
25
|
+
return contact._id ? contact : undefined
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
12
29
|
return await Promise.all(
|
|
13
30
|
contacts.map(async contact => {
|
|
14
31
|
if (contact.id) {
|
|
@@ -45,6 +62,19 @@ export const getOrCreateFromArray = async (client, contacts, createContact) => {
|
|
|
45
62
|
)
|
|
46
63
|
}
|
|
47
64
|
|
|
65
|
+
// A suggestion without id has no contact document, and only a fullname,
|
|
66
|
+
// which getDisplayName does not read
|
|
67
|
+
export const suggestContacts = async (client, q) => {
|
|
68
|
+
const { data } = await client
|
|
69
|
+
.getStackClient()
|
|
70
|
+
.fetchJSON('GET', `/contacts/suggest?q=${encodeURIComponent(q)}`)
|
|
71
|
+
return data.map(({ id, type, attributes }) => ({
|
|
72
|
+
...attributes,
|
|
73
|
+
...(id ? { _id: id, id } : { displayName: attributes.fullname }),
|
|
74
|
+
_type: type
|
|
75
|
+
}))
|
|
76
|
+
}
|
|
77
|
+
|
|
48
78
|
export const getContactsFromGroupId = (contacts = [], groupId) => {
|
|
49
79
|
return contacts.filter(contact => {
|
|
50
80
|
return contact.relationships?.groups?.data?.some(
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import flag from 'cozy-flags'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
computeContactsAndGroups,
|
|
5
|
+
getOrCreateFromArray,
|
|
6
|
+
suggestContacts
|
|
7
|
+
} from './contacts'
|
|
4
8
|
|
|
5
9
|
jest.mock('cozy-flags', () => ({
|
|
6
10
|
__esModule: true,
|
|
@@ -128,3 +132,100 @@ describe('computeContactsAndGroups', () => {
|
|
|
128
132
|
expect(contactsAndGroups.map(c => c._id)).toEqual(['alice', 'bob'])
|
|
129
133
|
})
|
|
130
134
|
})
|
|
135
|
+
|
|
136
|
+
describe('getOrCreateFromArray with contactsSuggestEnabled', () => {
|
|
137
|
+
it('should send people by email and keep groups, without creating contacts', async () => {
|
|
138
|
+
const createContact = jest.fn()
|
|
139
|
+
const group = { _id: 'group-1', _type: 'io.cozy.contacts.groups' }
|
|
140
|
+
|
|
141
|
+
const recipients = await getOrCreateFromArray(
|
|
142
|
+
mockClient,
|
|
143
|
+
[
|
|
144
|
+
{
|
|
145
|
+
_id: 'org-member-1',
|
|
146
|
+
_type: 'io.cozy.contacts',
|
|
147
|
+
email: [{ address: 'member@org.example', primary: true }],
|
|
148
|
+
meta: { kind: 'member' }
|
|
149
|
+
},
|
|
150
|
+
{ email: 'unknown@friends.example' },
|
|
151
|
+
group
|
|
152
|
+
],
|
|
153
|
+
createContact,
|
|
154
|
+
true
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
expect(recipients).toEqual([
|
|
158
|
+
{ _type: 'io.cozy.contacts', email: 'member@org.example' },
|
|
159
|
+
{ _type: 'io.cozy.contacts', email: 'unknown@friends.example' },
|
|
160
|
+
group
|
|
161
|
+
])
|
|
162
|
+
expect(createContact).not.toHaveBeenCalled()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('should keep a contact without email by id, and drop a recipient with neither', async () => {
|
|
166
|
+
const cozyOnlyContact = {
|
|
167
|
+
_id: 'contact-1',
|
|
168
|
+
_type: 'io.cozy.contacts',
|
|
169
|
+
cozy: [{ url: 'https://bob.example' }]
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const recipients = await getOrCreateFromArray(
|
|
173
|
+
mockClient,
|
|
174
|
+
[cozyOnlyContact, { instance: 'https://alice.example' }],
|
|
175
|
+
jest.fn(),
|
|
176
|
+
true
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
expect(recipients).toEqual([cozyOnlyContact, undefined])
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe('suggestContacts', () => {
|
|
184
|
+
it('should map the suggestions of the stack to contacts', async () => {
|
|
185
|
+
const fetchJSON = jest.fn().mockResolvedValue({
|
|
186
|
+
data: [
|
|
187
|
+
{
|
|
188
|
+
type: 'io.cozy.contacts',
|
|
189
|
+
id: 'org-member-1',
|
|
190
|
+
attributes: {
|
|
191
|
+
fullname: 'Jean Dupont',
|
|
192
|
+
name: { givenName: 'Jean', familyName: 'Dupont' },
|
|
193
|
+
email: [{ address: 'jean@org.example', primary: true }]
|
|
194
|
+
},
|
|
195
|
+
meta: { kind: 'member' }
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'io.cozy.contacts',
|
|
199
|
+
attributes: {
|
|
200
|
+
fullname: 'Paul Dupuis',
|
|
201
|
+
email: [{ address: 'paul@friends.example', primary: true }]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
})
|
|
206
|
+
const client = { getStackClient: () => ({ fetchJSON }) }
|
|
207
|
+
|
|
208
|
+
const contacts = await suggestContacts(client, 'dup & co')
|
|
209
|
+
|
|
210
|
+
expect(fetchJSON).toHaveBeenCalledWith(
|
|
211
|
+
'GET',
|
|
212
|
+
'/contacts/suggest?q=dup%20%26%20co'
|
|
213
|
+
)
|
|
214
|
+
expect(contacts).toEqual([
|
|
215
|
+
{
|
|
216
|
+
_id: 'org-member-1',
|
|
217
|
+
id: 'org-member-1',
|
|
218
|
+
_type: 'io.cozy.contacts',
|
|
219
|
+
fullname: 'Jean Dupont',
|
|
220
|
+
name: { givenName: 'Jean', familyName: 'Dupont' },
|
|
221
|
+
email: [{ address: 'jean@org.example', primary: true }]
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
_type: 'io.cozy.contacts',
|
|
225
|
+
fullname: 'Paul Dupuis',
|
|
226
|
+
displayName: 'Paul Dupuis',
|
|
227
|
+
email: [{ address: 'paul@friends.example', primary: true }]
|
|
228
|
+
}
|
|
229
|
+
])
|
|
230
|
+
})
|
|
231
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getPrimaryCozy } from 'cozy-client/dist/models/contact'
|
|
1
2
|
import flag from 'cozy-flags'
|
|
2
3
|
|
|
3
4
|
import { DOCTYPE_GROUPS } from '../models'
|
|
@@ -143,3 +144,42 @@ export const hasMemberActions = ({
|
|
|
143
144
|
canManageMembers &&
|
|
144
145
|
status !== 'owner' &&
|
|
145
146
|
((isCurrentUser && !isOwner) || canManageSharing)
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* makeAvatarUrl derives the avatar image URL for the recipient.
|
|
150
|
+
* - If the recipient has an avatarPath (sharing context), it is
|
|
151
|
+
* used directly with a base URI prefix (unless it is already
|
|
152
|
+
* a full URL for a remote Cozy).
|
|
153
|
+
* - If the recipient has no avatarPath but has a cozy URL
|
|
154
|
+
* (contact context), it points to that Cozy's public avatar.
|
|
155
|
+
* - The status is used as a cache-buster in the URL so the
|
|
156
|
+
* browser refreshes the image when the sharing status changes.
|
|
157
|
+
* For non-sharing recipients, 'contact' is the stable default.
|
|
158
|
+
*/
|
|
159
|
+
export const makeAvatarUrl = (recipient, instanceUri) => {
|
|
160
|
+
const avatarPath = recipient.avatarPath
|
|
161
|
+
const cozyUrl = !avatarPath ? getPrimaryCozy(recipient) : null
|
|
162
|
+
if (!avatarPath && !cozyUrl) return null
|
|
163
|
+
|
|
164
|
+
const finalPath =
|
|
165
|
+
avatarPath ||
|
|
166
|
+
`${cozyUrl.replace(/\/$/, '')}/public/avatar?fallback=initials`
|
|
167
|
+
const status = recipient.status || 'contact'
|
|
168
|
+
const isFullPath = finalPath.startsWith('http')
|
|
169
|
+
const base = isFullPath ? '' : instanceUri
|
|
170
|
+
return `${base}${finalPath}${finalPath.includes('?') ? '&' : '?'}v=${status}`
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Adds to the recipients, except groups, the URL of their avatar
|
|
175
|
+
*
|
|
176
|
+
* @param {object[]} recipients - Recipients of a sharing
|
|
177
|
+
* @param {string} instanceUri - URI of the current user's instance
|
|
178
|
+
* @returns {object[]} The recipients with their `avatarUrl`
|
|
179
|
+
*/
|
|
180
|
+
export const addAvatarUrls = (recipients, instanceUri) =>
|
|
181
|
+
recipients.map(recipient =>
|
|
182
|
+
recipient.members
|
|
183
|
+
? recipient
|
|
184
|
+
: { ...recipient, avatarUrl: makeAvatarUrl(recipient, instanceUri) }
|
|
185
|
+
)
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
addAvatarUrls,
|
|
3
|
+
hasMemberActions,
|
|
4
|
+
makeAvatarUrl,
|
|
5
|
+
markCurrentUser
|
|
6
|
+
} from './recipients'
|
|
2
7
|
|
|
3
8
|
const instanceUri = 'https://alice.cozy.cc'
|
|
4
9
|
|
|
@@ -80,3 +85,80 @@ describe('hasMemberActions', () => {
|
|
|
80
85
|
expect(hasMemberActions({ ...memberRights, status: 'ready' })).toBe(false)
|
|
81
86
|
})
|
|
82
87
|
})
|
|
88
|
+
|
|
89
|
+
describe('makeAvatarUrl', () => {
|
|
90
|
+
const instanceUri = 'http://cozy.example.com'
|
|
91
|
+
|
|
92
|
+
it('prefixes the avatarPath with the instance URI and the status', () => {
|
|
93
|
+
expect(
|
|
94
|
+
makeAvatarUrl(
|
|
95
|
+
{ status: 'owner', avatarPath: '/sharings/123/recipients/0/avatar' },
|
|
96
|
+
instanceUri
|
|
97
|
+
)
|
|
98
|
+
).toBe('http://cozy.example.com/sharings/123/recipients/0/avatar?v=owner')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('appends the status with & when avatarPath already has a query string', () => {
|
|
102
|
+
expect(
|
|
103
|
+
makeAvatarUrl(
|
|
104
|
+
{ status: 'owner', avatarPath: '/public/avatar?fallback=initials' },
|
|
105
|
+
instanceUri
|
|
106
|
+
)
|
|
107
|
+
).toBe('http://cozy.example.com/public/avatar?fallback=initials&v=owner')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('does not prefix a full URL avatarPath with the instance URI', () => {
|
|
111
|
+
expect(
|
|
112
|
+
makeAvatarUrl(
|
|
113
|
+
{
|
|
114
|
+
status: 'contact',
|
|
115
|
+
avatarPath:
|
|
116
|
+
'https://jonsnow.mycozy.cloud/public/avatar?fallback=initials'
|
|
117
|
+
},
|
|
118
|
+
instanceUri
|
|
119
|
+
)
|
|
120
|
+
).toBe(
|
|
121
|
+
'https://jonsnow.mycozy.cloud/public/avatar?fallback=initials&v=contact'
|
|
122
|
+
)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('points to the public avatar of the contact cozy when there is no avatarPath', () => {
|
|
126
|
+
expect(
|
|
127
|
+
makeAvatarUrl(
|
|
128
|
+
{
|
|
129
|
+
_type: 'io.cozy.contacts',
|
|
130
|
+
cozy: [{ url: 'https://jonsnow.mycozy.cloud' }]
|
|
131
|
+
},
|
|
132
|
+
instanceUri
|
|
133
|
+
)
|
|
134
|
+
).toBe(
|
|
135
|
+
'https://jonsnow.mycozy.cloud/public/avatar?fallback=initials&v=contact'
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('returns null when there is no avatarPath and no cozy URL', () => {
|
|
140
|
+
expect(
|
|
141
|
+
makeAvatarUrl(
|
|
142
|
+
{ _type: 'io.cozy.contacts', public_name: 'Bob' },
|
|
143
|
+
instanceUri
|
|
144
|
+
)
|
|
145
|
+
).toBe(null)
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('addAvatarUrls', () => {
|
|
150
|
+
it('adds the avatar URL to the members but not to the groups', () => {
|
|
151
|
+
const [member, group] = addAvatarUrls(
|
|
152
|
+
[
|
|
153
|
+
{ status: 'ready', avatarPath: '/sharings/123/recipients/1/avatar' },
|
|
154
|
+
{ name: 'Team', members: [] }
|
|
155
|
+
],
|
|
156
|
+
'http://cozy.example.com'
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
expect(member.avatarUrl).toBe(
|
|
160
|
+
'http://cozy.example.com/sharings/123/recipients/1/avatar?v=ready'
|
|
161
|
+
)
|
|
162
|
+
expect(group).not.toHaveProperty('avatarUrl')
|
|
163
|
+
})
|
|
164
|
+
})
|
|
@@ -2,6 +2,7 @@ import { useCallback } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { useClient } from 'cozy-client'
|
|
4
4
|
|
|
5
|
+
import { useSharingContext } from './useSharingContext'
|
|
5
6
|
import { getOrCreateFromArray } from '../helpers/contacts'
|
|
6
7
|
import { DOCTYPE_CONTACTS } from '../models'
|
|
7
8
|
|
|
@@ -14,6 +15,7 @@ import { DOCTYPE_CONTACTS } from '../models'
|
|
|
14
15
|
*/
|
|
15
16
|
export const useResolveRecipients = () => {
|
|
16
17
|
const client = useClient()
|
|
18
|
+
const contactsSuggestEnabled = useSharingContext()?.contactsSuggestEnabled
|
|
17
19
|
|
|
18
20
|
return useCallback(
|
|
19
21
|
async (
|
|
@@ -24,7 +26,8 @@ export const useResolveRecipients = () => {
|
|
|
24
26
|
const contacts = await getOrCreateFromArray(
|
|
25
27
|
client,
|
|
26
28
|
pendingRecipients,
|
|
27
|
-
createContact
|
|
29
|
+
createContact,
|
|
30
|
+
contactsSuggestEnabled
|
|
28
31
|
)
|
|
29
32
|
const isReadOnly = selectedOption === 'readOnly'
|
|
30
33
|
|
|
@@ -33,6 +36,6 @@ export const useResolveRecipients = () => {
|
|
|
33
36
|
readOnlyRecipients: isReadOnly ? contacts : []
|
|
34
37
|
}
|
|
35
38
|
},
|
|
36
|
-
[client]
|
|
39
|
+
[client, contactsSuggestEnabled]
|
|
37
40
|
)
|
|
38
41
|
}
|
|
@@ -13,6 +13,10 @@ jest.mock('../helpers/contacts', () => ({
|
|
|
13
13
|
getOrCreateFromArray: jest.fn()
|
|
14
14
|
}))
|
|
15
15
|
|
|
16
|
+
jest.mock('./useSharingContext', () => ({
|
|
17
|
+
useSharingContext: () => ({ contactsSuggestEnabled: true })
|
|
18
|
+
}))
|
|
19
|
+
|
|
16
20
|
const contacts = [{ _id: 'alice' }, { _id: 'bob' }]
|
|
17
21
|
|
|
18
22
|
describe('useResolveRecipients', () => {
|
|
@@ -48,7 +52,8 @@ describe('useResolveRecipients', () => {
|
|
|
48
52
|
expect(getOrCreateFromArray).toHaveBeenCalledWith(
|
|
49
53
|
mockClient,
|
|
50
54
|
pendingRecipients,
|
|
51
|
-
expect.any(Function)
|
|
55
|
+
expect.any(Function),
|
|
56
|
+
true
|
|
52
57
|
)
|
|
53
58
|
expect(mockClient.create).toHaveBeenCalledWith('io.cozy.contacts', {
|
|
54
59
|
email: [{ address: 'alice@cozy.cc' }]
|
|
@@ -64,7 +69,8 @@ describe('useResolveRecipients', () => {
|
|
|
64
69
|
expect(getOrCreateFromArray).toHaveBeenCalledWith(
|
|
65
70
|
mockClient,
|
|
66
71
|
[],
|
|
67
|
-
createContact
|
|
72
|
+
createContact,
|
|
73
|
+
true
|
|
68
74
|
)
|
|
69
75
|
})
|
|
70
76
|
})
|
package/src/index.jsx
CHANGED
|
@@ -10,7 +10,7 @@ export { useSharingContext } from './hooks/useSharingContext'
|
|
|
10
10
|
export { useFetchDocumentPath } from './hooks/useFetchDocumentPath'
|
|
11
11
|
|
|
12
12
|
export { GroupAvatar } from './components/Avatar/GroupAvatar'
|
|
13
|
-
export { MemberAvatar } from './components/Avatar/
|
|
13
|
+
export { MemberAvatarWrapper as MemberAvatar } from './components/Avatar/MemberAvatarWrapper'
|
|
14
14
|
export { SharedDocument } from './SharedDocument'
|
|
15
15
|
export { SharedStatus } from './SharedStatus'
|
|
16
16
|
export { SharedBadge } from './SharedBadge'
|
package/src/queries/queries.js
CHANGED
|
@@ -16,7 +16,7 @@ export const buildSharingsByIdQuery = sharingId => ({
|
|
|
16
16
|
}
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
export const buildReachableContactsQuery = () => ({
|
|
19
|
+
export const buildReachableContactsQuery = ({ inGroups } = {}) => ({
|
|
20
20
|
definition: Q(DOCTYPE_CONTACTS)
|
|
21
21
|
.where({
|
|
22
22
|
_id: {
|
|
@@ -42,12 +42,15 @@ export const buildReachableContactsQuery = () => ({
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
]
|
|
45
|
+
],
|
|
46
|
+
...(inGroups && { 'relationships.groups.data': { $exists: true } })
|
|
46
47
|
})
|
|
47
48
|
.indexFields(['_id'])
|
|
48
49
|
.limitBy(1000),
|
|
49
50
|
options: {
|
|
50
|
-
as:
|
|
51
|
+
as: inGroups
|
|
52
|
+
? 'io.cozy.contacts/reachable-with-groups'
|
|
53
|
+
: 'io.cozy.contacts/reachable'
|
|
51
54
|
}
|
|
52
55
|
})
|
|
53
56
|
|