@saooti/octopus-sdk 42.0.0-beta → 42.0.0-beta2
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/eslint-config.d.ts +3 -0
- package/eslint-config.mjs +54 -0
- package/package.json +5 -2
- package/tests/api/podcastApi.spec.ts +43 -0
- package/tests/api/transcriptionApi.spec.ts +58 -0
- package/tests/components/composable/player/usePlayerTranscript.spec.ts +238 -0
- package/tests/components/composable/useAdvancedParamInit.spec.ts +91 -0
- package/tests/components/composable/usePresentationItem.spec.ts +164 -0
- package/tests/components/composable/useRights.spec.ts +838 -0
- package/tests/components/composable/useSeasonsManagement.spec.ts +35 -0
- package/tests/components/composable/useTranslation.spec.ts +209 -0
- package/tests/components/display/RightsIndicator.spec.ts +481 -0
- package/tests/components/display/comments/item/CommentMoreActions.spec.ts +75 -0
- package/tests/components/display/comments/modal/RecaptchaModal.spec.ts +43 -0
- package/tests/components/display/emission/EmissionItem.spec.ts +54 -0
- package/tests/components/display/emission/EmissionPresentationItem.spec.ts +46 -0
- package/tests/components/display/filter/AdvancedSearch.spec.ts +187 -0
- package/tests/components/display/podcasts/PodcastFilterList.spec.ts +34 -0
- package/tests/components/display/podcasts/PodcastInlineListTemplate.spec.ts +24 -0
- package/tests/components/display/podcasts/PodcastItemInfo.spec.ts +99 -0
- package/tests/components/display/podcasts/PodcastModuleBox.spec.ts +279 -0
- package/tests/components/display/podcasts/PodcastPresentationList.spec.ts +108 -0
- package/tests/components/display/podcasts/PodcastRawTranscript.spec.ts +254 -0
- package/tests/components/display/sharing/ShareNewsletter.spec.ts +68 -0
- package/tests/components/display/sharing/SharePlayer.spec.ts +59 -0
- package/tests/components/display/sharing/SharePlayerRadio.spec.ts +55 -0
- package/tests/components/form/ClassicButtonGroup.spec.ts +78 -0
- package/tests/components/form/ClassicInputText.spec.ts +24 -0
- package/tests/components/form/OctopusMultiselect.spec.ts +506 -0
- package/tests/components/form/OctopusSelect.spec.ts +240 -0
- package/tests/components/layouts/PresentationItem.spec.ts +37 -0
- package/tests/components/misc/ClassicAvatar.spec.ts +68 -0
- package/tests/components/misc/ClassicPopover.spec.ts +260 -0
- package/tests/components/misc/FooterSection.spec.ts +49 -0
- package/tests/components/misc/HomeDropdown.spec.ts +44 -0
- package/tests/components/misc/modal/ClipboardModal.spec.ts +51 -0
- package/tests/components/misc/player/PlayerLarge.spec.ts +72 -0
- package/tests/components/pages/EmissionPage.spec.ts +253 -0
- package/tests/components/pages/EmissionsPage.spec.ts +18 -0
- package/tests/components/pages/ParticipantPage.spec.ts +65 -0
- package/tests/components/pages/PlaylistPage.spec.ts +60 -0
- package/tests/components/pages/PodcastPage.spec.ts +89 -0
- package/tests/components/pages/PodcastsPage.spec.ts +18 -0
- package/tests/components/pages/RadioPage.spec.ts +65 -0
- package/tests/components/pages/SmartLinkPage.spec.ts +90 -0
- package/tests/helper/language.spec.ts +45 -0
- package/tests/index.ts +9 -0
- package/tests/localisation.ts +10 -0
- package/tests/mocks/i18n.ts +13 -0
- package/tests/mocks/index.ts +11 -0
- package/tests/mocks/rights.ts +17 -0
- package/tests/mocks/useAdvancedParamInit.ts +22 -0
- package/tests/mocks/useRouter.ts +11 -0
- package/tests/stores/CacheStore.spec.ts +110 -0
- package/tests/utils.ts +178 -0
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { setupPinia, setupAuthStore } from '@tests/utils';
|
|
3
|
+
import { mockEmission, mockPodcast } from '@tests/mocks/rights';
|
|
4
|
+
import { useAuthStore } from '@/stores/AuthStore';
|
|
5
|
+
import { useRights, ActionRight } from '@/components/composable/useRights';
|
|
6
|
+
import type { Organisation } from '@/stores/class/general/organisation';
|
|
7
|
+
import type { Emission } from '@/stores/class/general/emission';
|
|
8
|
+
import type { Podcast } from '@/stores/class/general/podcast';
|
|
9
|
+
import type { Mix } from '@/stores/class/radio/mix';
|
|
10
|
+
import { PlaylistMedia } from '@/stores/class/radio/playlistMedia';
|
|
11
|
+
import { Cartouchier } from '@/stores/class/cartouchier/cartouchier';
|
|
12
|
+
import type { Media } from '@/stores/class/general/media';
|
|
13
|
+
import type { Rubrique } from '@/stores/class/rubrique/rubrique';
|
|
14
|
+
|
|
15
|
+
async function setup(roles: string[], userId = 'test-user-123', scope: Array<number> = []): Promise<void> {
|
|
16
|
+
setupPinia();
|
|
17
|
+
await setupAuthStore({ roles })();
|
|
18
|
+
useAuthStore().$patch({ authProfile: { userId, scope } });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('useRights', () => {
|
|
22
|
+
describe('Emission permissions', () => {
|
|
23
|
+
describe('canCreateEmission', () => {
|
|
24
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RESTRICTED_PRODUCTION'].forEach(role => {
|
|
25
|
+
it(`allows ${role}`, async () => {
|
|
26
|
+
await setup([role]);
|
|
27
|
+
expect(useRights().canCreateEmission()).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('denies unrelated roles', async () => {
|
|
32
|
+
await setup(['PLAYLISTS']);
|
|
33
|
+
expect(useRights().canCreateEmission()).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('canEditEmission', () => {
|
|
38
|
+
it('allows ADMIN to edit any emission', async () => {
|
|
39
|
+
await setup(['ADMIN']);
|
|
40
|
+
expect(useRights().canEditEmission(mockEmission({ createdByUserId: 'other-user' }))).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('allows RESTRICTED_PRODUCTION to edit own emission', async () => {
|
|
44
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
45
|
+
expect(useRights().canEditEmission(mockEmission({ createdByUserId: 'test-user-123' }))).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('denies RESTRICTED_PRODUCTION editing others\' emission', async () => {
|
|
49
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
50
|
+
expect(useRights().canEditEmission(mockEmission({ createdByUserId: 'other-user' }))).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('allows editing new emissions if can create', async () => {
|
|
54
|
+
await setup(['PRODUCTION']);
|
|
55
|
+
const newEmission = {
|
|
56
|
+
emissionId: undefined,
|
|
57
|
+
beneficiaries: [],
|
|
58
|
+
description: '',
|
|
59
|
+
monetisable: false,
|
|
60
|
+
name: 'New Emission',
|
|
61
|
+
orga: {} as Organisation,
|
|
62
|
+
rubriqueIds: []
|
|
63
|
+
} as unknown as Emission;
|
|
64
|
+
expect(useRights().canEditEmission(newEmission)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('canDeleteEmission', () => {
|
|
69
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RESTRICTED_PRODUCTION'].forEach(role => {
|
|
70
|
+
it(`allows ${role}`, async () => {
|
|
71
|
+
await setup([role]);
|
|
72
|
+
expect(useRights().canDeleteEmission(mockEmission({}))).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('denies unrelated roles', async () => {
|
|
77
|
+
await setup(['PLAYLISTS']);
|
|
78
|
+
expect(useRights().canDeleteEmission(mockEmission({}))).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('Podcast permissions', () => {
|
|
84
|
+
describe('canCreatePodcast', () => {
|
|
85
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
86
|
+
it(`allows ${role}`, async () => {
|
|
87
|
+
await setup([role]);
|
|
88
|
+
expect(useRights().canCreatePodcast()).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('denies unrelated roles', async () => {
|
|
93
|
+
await setup(['PLAYLISTS']);
|
|
94
|
+
expect(useRights().canCreatePodcast()).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('canDuplicatePodcast', () => {
|
|
99
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RESTRICTED_PRODUCTION'].forEach(role => {
|
|
100
|
+
it(`allows ${role}`, async () => {
|
|
101
|
+
await setup([role]);
|
|
102
|
+
expect(useRights().canDuplicatePodcast()).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('denies unrelated roles', async () => {
|
|
107
|
+
await setup(['PLAYLISTS']);
|
|
108
|
+
expect(useRights().canDuplicatePodcast()).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('canEditPodcast', () => {
|
|
113
|
+
const ownPodcast = mockPodcast({ createdByUserId: 'test-user-123', valid: true });
|
|
114
|
+
const otherPodcast = mockPodcast({ createdByUserId: 'other-user', valid: true });
|
|
115
|
+
|
|
116
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION'].forEach(role => {
|
|
117
|
+
it(`allows ${role} to edit any podcast`, async () => {
|
|
118
|
+
await setup([role]);
|
|
119
|
+
expect(useRights().canEditPodcast(otherPodcast)).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('allows PODCAST_CRUD to edit own non-valid podcast', async () => {
|
|
124
|
+
await setup(['PODCAST_CRUD']);
|
|
125
|
+
const podcast = mockPodcast({ valid: false, publisher: { userId: 'test-user-123' } });
|
|
126
|
+
expect(useRights().canEditPodcast(podcast)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('denies PODCAST_CRUD editing own valid podcast', async () => {
|
|
130
|
+
await setup(['PODCAST_CRUD']);
|
|
131
|
+
const podcast = mockPodcast({ valid: true, publisher: { userId: 'test-user-123' } });
|
|
132
|
+
expect(useRights().canEditPodcast(podcast)).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('denies PODCAST_CRUD editing others\' podcast', async () => {
|
|
136
|
+
await setup(['PODCAST_CRUD']);
|
|
137
|
+
const podcast = mockPodcast({ valid: false, publisher: { userId: 'other-user' } });
|
|
138
|
+
expect(useRights().canEditPodcast(podcast)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
['RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
142
|
+
it(`allows ${role} to edit own podcast`, async () => {
|
|
143
|
+
await setup([role]);
|
|
144
|
+
expect(useRights().canEditPodcast(ownPodcast)).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it(`denies ${role} editing others' podcast`, async () => {
|
|
148
|
+
await setup([role]);
|
|
149
|
+
expect(useRights().canEditPodcast(otherPodcast)).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('denies unrelated roles', async () => {
|
|
154
|
+
await setup(['PLAYLISTS']);
|
|
155
|
+
expect(useRights().canEditPodcast(ownPodcast)).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Regression: RESTRICTED_* must take priority over PODCAST_CRUD when both roles are present.
|
|
159
|
+
['RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
160
|
+
it(`allows ${role} + PODCAST_CRUD to edit own valid podcast`, async () => {
|
|
161
|
+
await setup([role, 'PODCAST_CRUD']);
|
|
162
|
+
const podcast = mockPodcast({ createdByUserId: 'test-user-123', valid: true, publisher: { userId: 'test-user-123' } });
|
|
163
|
+
expect(useRights().canEditPodcast(podcast)).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('denies RESTRICTED_PRODUCTION + PODCAST_CRUD editing others\' valid podcast', async () => {
|
|
168
|
+
await setup(['RESTRICTED_PRODUCTION', 'PODCAST_CRUD']);
|
|
169
|
+
const podcast = mockPodcast({ createdByUserId: 'other-user', valid: true, publisher: { userId: 'other-user' } });
|
|
170
|
+
expect(useRights().canEditPodcast(podcast)).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('canDeletePodcast', () => {
|
|
175
|
+
it('delegates to canEditPodcast', async () => {
|
|
176
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
177
|
+
expect(useRights().canDeletePodcast(mockPodcast({ createdByUserId: 'test-user-123'}))).toBe(true);
|
|
178
|
+
expect(useRights().canDeletePodcast(mockPodcast({ createdByUserId: 'other-user' }))).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('canValidatePodcast', () => {
|
|
183
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'PODCAST_VALIDATION'].forEach(role => {
|
|
184
|
+
it(`allows ${role}`, async () => {
|
|
185
|
+
await setup([role]);
|
|
186
|
+
expect(useRights().canValidatePodcast()).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
['PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'PLAYLISTS'].forEach(role => {
|
|
191
|
+
it(`denies ${role}`, async () => {
|
|
192
|
+
await setup([role]);
|
|
193
|
+
expect(useRights().canValidatePodcast()).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('Playlist permissions', () => {
|
|
200
|
+
['canCreatePlaylist', 'canEditPlaylist', 'canDeletePlaylist'].forEach(method => {
|
|
201
|
+
describe(method, () => {
|
|
202
|
+
['ADMIN', 'ORGANISATION', 'PLAYLISTS'].forEach(role => {
|
|
203
|
+
it(`allows ${role}`, async () => {
|
|
204
|
+
await setup([role]);
|
|
205
|
+
expect(useRights()[method as 'canCreatePlaylist']()).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('denies unrelated roles', async () => {
|
|
210
|
+
await setup(['PRODUCTION']);
|
|
211
|
+
expect(useRights()[method as 'canCreatePlaylist']()).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Participant permissions', () => {
|
|
218
|
+
describe('canCreateParticipant', () => {
|
|
219
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RESTRICTED_PRODUCTION'].forEach(role => {
|
|
220
|
+
it(`allows ${role}`, async () => {
|
|
221
|
+
await setup([role]);
|
|
222
|
+
expect(useRights().canCreateParticipant()).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('denies unrelated roles', async () => {
|
|
227
|
+
await setup(['PLAYLISTS']);
|
|
228
|
+
expect(useRights().canCreateParticipant()).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
['canEditParticipant', 'canDeleteParticipant'].forEach(method => {
|
|
233
|
+
describe(method, () => {
|
|
234
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RESTRICTED_PRODUCTION'].forEach(role => {
|
|
235
|
+
it(`allows ${role}`, async () => {
|
|
236
|
+
await setup([role]);
|
|
237
|
+
expect(await useRights()[method as 'canEditParticipant'](123)).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('allows undefined id (new participant)', async () => {
|
|
242
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
243
|
+
expect(await useRights()[method as 'canEditParticipant'](undefined)).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('denies unrelated roles for existing participant', async () => {
|
|
247
|
+
await setup(['PLAYLISTS']);
|
|
248
|
+
expect(await useRights()[method as 'canEditParticipant'](123)).toBe(false);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe('canEditTranscript', () => {
|
|
255
|
+
const ownPodcast = mockPodcast({ createdByUserId: 'test-user-123' });
|
|
256
|
+
const otherPodcast = mockPodcast({ createdByUserId: 'other-user' });
|
|
257
|
+
|
|
258
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION'].forEach(role => {
|
|
259
|
+
it(`allows ${role} to edit transcript of any podcast`, async () => {
|
|
260
|
+
await setup([role]);
|
|
261
|
+
expect(useRights().canEditTranscript(otherPodcast)).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
['RESTRICTED_PRODUCTION', 'PODCAST_CRUD'].forEach(role => {
|
|
266
|
+
it(`${role} can only edit transcript of own podcast`, async () => {
|
|
267
|
+
await setup([role]);
|
|
268
|
+
expect(useRights().canEditTranscript(ownPodcast)).toBe(true);
|
|
269
|
+
expect(useRights().canEditTranscript(otherPodcast)).toBe(false);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('denies unrelated roles', async () => {
|
|
274
|
+
await setup(['RESTRICTED_ANIMATION']);
|
|
275
|
+
expect(useRights().canEditTranscript(ownPodcast)).toBe(false);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe('canEditTranslation', () => {
|
|
280
|
+
const ownPodcast = mockPodcast({ createdByUserId: 'test-user-123' });
|
|
281
|
+
const otherPodcast = mockPodcast({ createdByUserId: 'other-user' });
|
|
282
|
+
|
|
283
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION'].forEach(role => {
|
|
284
|
+
it(`allows ${role} to edit transcript of any podcast`, async () => {
|
|
285
|
+
await setup([role]);
|
|
286
|
+
expect(useRights().canEditTranslation(otherPodcast)).toBe(true);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
['RESTRICTED_PRODUCTION', 'PODCAST_CRUD'].forEach(role => {
|
|
291
|
+
it(`${role} can only edit transcript of own podcast`, async () => {
|
|
292
|
+
await setup([role]);
|
|
293
|
+
expect(useRights().canEditTranslation(ownPodcast)).toBe(true);
|
|
294
|
+
expect(useRights().canEditTranslation(otherPodcast)).toBe(false);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('denies unrelated roles', async () => {
|
|
299
|
+
await setup(['RESTRICTED_ANIMATION']);
|
|
300
|
+
expect(useRights().canEditTranslation(ownPodcast)).toBe(false);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe('canEditTranscriptVisibility', () => {
|
|
305
|
+
const ownPodcast = mockPodcast({ createdByUserId: 'test-user-123' });
|
|
306
|
+
const otherPodcast = mockPodcast({ createdByUserId: 'other-user' });
|
|
307
|
+
|
|
308
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION'].forEach(role => {
|
|
309
|
+
it(`allows ${role} to edit transcript of any podcast`, async () => {
|
|
310
|
+
await setup([role]);
|
|
311
|
+
expect(useRights().canEditTranscriptVisibility(otherPodcast)).toBe(true);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('denies unrelated roles', async () => {
|
|
316
|
+
await setup(['PODCAST_CRUD']);
|
|
317
|
+
expect(useRights().canEditTranscriptVisibility(ownPodcast)).toBe(false);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
describe('Rubrique/Rubriquage permissions', () => {
|
|
322
|
+
describe('canCreateRubriques', () => {
|
|
323
|
+
['ADMIN', 'ORGANISATION', 'EDITION'].forEach(role => {
|
|
324
|
+
it(`allows ${role}`, async () => {
|
|
325
|
+
await setup([role]);
|
|
326
|
+
expect(useRights().canCreateRubriques()).toBe(true);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('denies unrelated roles', async () => {
|
|
331
|
+
await setup(['PLAYLISTS']);
|
|
332
|
+
expect(useRights().canCreateRubriques()).toBe(false);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe('canEditRubriques', () => {
|
|
337
|
+
['ADMIN', 'ORGANISATION', 'EDITION'].forEach(role => {
|
|
338
|
+
it(`allows ${role}`, async () => {
|
|
339
|
+
await setup([role]);
|
|
340
|
+
expect(useRights().canEditRubriques({ rubriqueId: 1, name: 'Test' } as Rubrique)).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('denies unrelated roles', async () => {
|
|
345
|
+
await setup(['PLAYLISTS']);
|
|
346
|
+
expect(useRights().canEditRubriques({ rubriqueId: 1, name: 'Test' } as Rubrique)).toBe(false);
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe('Aggregator permissions', () => {
|
|
352
|
+
['canCreateAggregator', 'canEditAggregator', 'canDeleteAggregator'].forEach(method => {
|
|
353
|
+
describe(method, () => {
|
|
354
|
+
['ADMIN', 'ORGANISATION'].forEach(role => {
|
|
355
|
+
it(`allows ${role}`, async () => {
|
|
356
|
+
await setup([role]);
|
|
357
|
+
expect(useRights()[method as 'canCreateAggregator']()).toBe(true);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('denies unrelated roles', async () => {
|
|
362
|
+
await setup(['PRODUCTION']);
|
|
363
|
+
expect(useRights()[method as 'canCreateAggregator']()).toBe(false);
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('Cartouchier permissions', () => {
|
|
370
|
+
const ownCartouchier = { ownerId: 'test-user-123' } as Cartouchier;
|
|
371
|
+
const otherCartouchier = { ownerId: 'other-user' } as Cartouchier;
|
|
372
|
+
const noOwnerCartouchier = {} as Cartouchier;
|
|
373
|
+
|
|
374
|
+
describe('canCreateCartouchier', () => {
|
|
375
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION', 'PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
376
|
+
it(`allows ${role}`, async () => {
|
|
377
|
+
await setup([role]);
|
|
378
|
+
expect(useRights().canCreateCartouchier()).toBe(true);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('denies unrelated roles', async () => {
|
|
383
|
+
await setup(['PLAYLISTS']);
|
|
384
|
+
expect(useRights().canCreateCartouchier()).toBe(false);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
describe('canEditCartouchier', () => {
|
|
389
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION'].forEach(role => {
|
|
390
|
+
it(`allows ${role} to edit any element`, async () => {
|
|
391
|
+
await setup([role]);
|
|
392
|
+
expect(useRights().canEditCartouchier(otherCartouchier)).toBe(true);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
['RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION', 'PODCAST_CRUD'].forEach(role => {
|
|
397
|
+
it(`${role} can only edit own element`, async () => {
|
|
398
|
+
await setup([role]);
|
|
399
|
+
expect(useRights().canEditCartouchier(ownCartouchier)).toBe(true);
|
|
400
|
+
expect(useRights().canEditCartouchier(otherCartouchier)).toBe(false);
|
|
401
|
+
expect(useRights().canEditCartouchier(noOwnerCartouchier)).toBe(false);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('denies unrelated roles', async () => {
|
|
406
|
+
await setup(['PLAYLISTS']);
|
|
407
|
+
expect(useRights().canEditCartouchier(ownCartouchier)).toBe(false);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
describe('canDeleteCartouchier', () => {
|
|
412
|
+
it('restricted user can delete own element but not others\'', async () => {
|
|
413
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
414
|
+
expect(useRights().canDeleteCartouchier(ownCartouchier)).toBe(true);
|
|
415
|
+
expect(useRights().canDeleteCartouchier(otherCartouchier)).toBe(false);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
describe('Bac/PlaylistMedia permissions', () => {
|
|
421
|
+
const ownBac = { ownerId: 'test-user-123' } as PlaylistMedia;
|
|
422
|
+
const otherBac = { ownerId: 'other-user' } as PlaylistMedia;
|
|
423
|
+
const noOwnerBac = {} as PlaylistMedia;
|
|
424
|
+
|
|
425
|
+
describe('canCreatePlaylistMedia', () => {
|
|
426
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION', 'PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
427
|
+
it(`allows ${role}`, async () => {
|
|
428
|
+
await setup([role]);
|
|
429
|
+
expect(useRights().canCreatePlaylistMedia()).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('denies unrelated roles', async () => {
|
|
434
|
+
await setup(['PLAYLISTS']);
|
|
435
|
+
expect(useRights().canCreatePlaylistMedia()).toBe(false);
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
describe('canEditPlaylistMedia', () => {
|
|
440
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION'].forEach(role => {
|
|
441
|
+
it(`allows ${role} to edit any element`, async () => {
|
|
442
|
+
await setup([role]);
|
|
443
|
+
expect(useRights().canEditPlaylistMedia(otherBac)).toBe(true);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
['RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION', 'PODCAST_CRUD'].forEach(role => {
|
|
448
|
+
it(`${role} can only edit own element`, async () => {
|
|
449
|
+
await setup([role]);
|
|
450
|
+
expect(useRights().canEditPlaylistMedia(ownBac)).toBe(true);
|
|
451
|
+
expect(useRights().canEditPlaylistMedia(otherBac)).toBe(false);
|
|
452
|
+
expect(useRights().canEditPlaylistMedia(noOwnerBac)).toBe(false);
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('denies unrelated roles', async () => {
|
|
457
|
+
await setup(['PLAYLISTS']);
|
|
458
|
+
expect(useRights().canEditPlaylistMedia(ownBac)).toBe(false);
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
describe('canDeletePlaylistMedia', () => {
|
|
463
|
+
it('restricted user can delete own element but not others\'', async () => {
|
|
464
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
465
|
+
expect(useRights().canDeletePlaylistMedia(ownBac)).toBe(true);
|
|
466
|
+
expect(useRights().canDeletePlaylistMedia(otherBac)).toBe(false);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
describe('Media permissions', () => {
|
|
472
|
+
const ownMedia = { mediaId: 1, ownerId: 'test-user-123' } as Media;
|
|
473
|
+
const otherMedia = { mediaId: 2, ownerId: 'other-user' } as Media;
|
|
474
|
+
const noOwnerMedia = { mediaId: 3 } as Media;
|
|
475
|
+
|
|
476
|
+
describe('canCreateMedia', () => {
|
|
477
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION',
|
|
478
|
+
'PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION'].forEach(role => {
|
|
479
|
+
it(`allows ${role}`, async () => {
|
|
480
|
+
await setup([role]);
|
|
481
|
+
expect(useRights().canCreateMedia()).toBe(true);
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it('denies unrelated roles', async () => {
|
|
486
|
+
await setup(['PLAYLISTS']);
|
|
487
|
+
expect(useRights().canCreateMedia()).toBe(false);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe('canEditMedia', () => {
|
|
492
|
+
['ADMIN', 'ORGANISATION', 'PRODUCTION', 'RADIO', 'ANIMATION'].forEach(role => {
|
|
493
|
+
it(`allows ${role} to edit any element`, async () => {
|
|
494
|
+
await setup([role]);
|
|
495
|
+
expect(useRights().canEditMedia(otherMedia)).toBe(true);
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
['RESTRICTED_PRODUCTION', 'RESTRICTED_ANIMATION', 'PODCAST_CRUD'].forEach(role => {
|
|
500
|
+
it(`${role} can only edit own element`, async () => {
|
|
501
|
+
await setup([role]);
|
|
502
|
+
expect(useRights().canEditMedia(ownMedia)).toBe(true);
|
|
503
|
+
expect(useRights().canEditMedia(otherMedia)).toBe(false);
|
|
504
|
+
expect(useRights().canEditMedia(noOwnerMedia)).toBe(false);
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it('denies unrelated roles', async () => {
|
|
509
|
+
await setup(['PLAYLISTS']);
|
|
510
|
+
expect(useRights().canEditMedia(ownMedia)).toBe(false);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
describe('canDeleteMedia', () => {
|
|
515
|
+
it('delegates to canEditMedia', async () => {
|
|
516
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
517
|
+
expect(useRights().canDeleteMedia(ownMedia)).toBe(true);
|
|
518
|
+
expect(useRights().canDeleteMedia(otherMedia)).toBe(false);
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
describe('Mix permissions', () => {
|
|
524
|
+
const ownMix = { ownerId: 'test-user-123' } as Mix;
|
|
525
|
+
const otherMix = { ownerId: 'other-user' } as Mix;
|
|
526
|
+
|
|
527
|
+
describe('canCreateMix', () => {
|
|
528
|
+
['ADMIN', 'RADIO'].forEach(role => {
|
|
529
|
+
it(`allows ${role}`, async () => {
|
|
530
|
+
await setup([role]);
|
|
531
|
+
expect(useRights().canCreateMix()).toBe(true);
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('denies unrelated roles', async () => {
|
|
536
|
+
await setup(['PLAYLISTS']);
|
|
537
|
+
expect(useRights().canCreateMix()).toBe(false);
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
describe('canEditMix', () => {
|
|
542
|
+
['ADMIN', 'RADIO'].forEach(role => {
|
|
543
|
+
it(`allows ${role} to edit any element`, async () => {
|
|
544
|
+
await setup([role]);
|
|
545
|
+
expect(useRights().canEditMix(otherMix)).toBe(true);
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it('denies unrelated roles', async () => {
|
|
550
|
+
await setup(['PLAYLISTS']);
|
|
551
|
+
expect(useRights().canEditMix(ownMix)).toBe(false);
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
describe('canDeleteMix', () => {
|
|
556
|
+
['ADMIN', 'RADIO'].forEach(role => {
|
|
557
|
+
it(`allows ${role} to delete any element`, async () => {
|
|
558
|
+
await setup([role]);
|
|
559
|
+
expect(useRights().canDeleteMix(otherMix)).toBe(true);
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('denies unrelated roles', async () => {
|
|
564
|
+
await setup(['PLAYLISTS']);
|
|
565
|
+
expect(useRights().canDeleteMix(ownMix)).toBe(false);
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
describe('Other permissions', () => {
|
|
571
|
+
describe('canEditCodeInsertPlayer', () => {
|
|
572
|
+
['ADMIN', 'ORGANISATION'].forEach(role => {
|
|
573
|
+
it(`allows ${role}`, async () => {
|
|
574
|
+
await setup([role]);
|
|
575
|
+
expect(useRights().canEditCodeInsertPlayer()).toBe(true);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
['PRODUCTION', 'PODCAST_CRUD', 'RESTRICTED_PRODUCTION', 'PLAYLISTS'].forEach(role => {
|
|
580
|
+
it(`denies ${role}`, async () => {
|
|
581
|
+
await setup([role]);
|
|
582
|
+
expect(useRights().canEditCodeInsertPlayer()).toBe(false);
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
describe('ActionRight detailed reasons', () => {
|
|
589
|
+
describe('getEditEmissionRight', () => {
|
|
590
|
+
it('returns Allowed for PRODUCTION', async () => {
|
|
591
|
+
await setup(['PRODUCTION']);
|
|
592
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'other' }))).toBe(ActionRight.Allowed);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('returns Allowed for RESTRICTED_PRODUCTION editing own emission', async () => {
|
|
596
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
597
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'test-user-123' }))).toBe(ActionRight.Allowed);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it('returns DeniedNotOwner for RESTRICTED_PRODUCTION editing others\' emission', async () => {
|
|
601
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
602
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'other' }))).toBe(ActionRight.DeniedNotOwner);
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
it('returns DeniedNoRight for role without emission access', async () => {
|
|
606
|
+
await setup(['PLAYLISTS']);
|
|
607
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'test-user-123' }))).toBe(ActionRight.DeniedNoRight);
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
describe('getEditPodcastRight', () => {
|
|
612
|
+
it('returns Allowed for PRODUCTION on any podcast', async () => {
|
|
613
|
+
await setup(['PRODUCTION']);
|
|
614
|
+
expect(useRights().getEditPodcastRight(mockPodcast({ createdByUserId: 'other', valid: true }))).toBe(ActionRight.Allowed);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('returns Allowed for RESTRICTED_PRODUCTION editing own podcast', async () => {
|
|
618
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
619
|
+
expect(useRights().getEditPodcastRight(mockPodcast({ createdByUserId: 'test-user-123', valid: true }))).toBe(ActionRight.Allowed);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it('returns DeniedNotOwner for RESTRICTED_PRODUCTION editing others\' podcast', async () => {
|
|
623
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
624
|
+
expect(useRights().getEditPodcastRight(mockPodcast({ createdByUserId: 'other', valid: true }))).toBe(ActionRight.DeniedNotOwner);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('returns DeniedNotOwner for PODCAST_CRUD editing others\' podcast', async () => {
|
|
628
|
+
await setup(['PODCAST_CRUD']);
|
|
629
|
+
expect(useRights().getEditPodcastRight(mockPodcast({ valid: false, publisher: { userId: 'other' } }))).toBe(ActionRight.DeniedNotOwner);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it('returns DeniedNoRight for role without podcast access', async () => {
|
|
633
|
+
await setup(['PLAYLISTS']);
|
|
634
|
+
expect(useRights().getEditPodcastRight(mockPodcast({ createdByUserId: 'test-user-123', valid: true }))).toBe(ActionRight.DeniedNoRight);
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
describe('getEditCartouchierRight', () => {
|
|
639
|
+
it('returns Allowed for ANIMATION on any element', async () => {
|
|
640
|
+
await setup(['ANIMATION']);
|
|
641
|
+
expect(useRights().getEditCartouchierRight({ ownerId: 'other' } as Cartouchier)).toBe(ActionRight.Allowed);
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it('returns Allowed for RESTRICTED_PRODUCTION editing own element', async () => {
|
|
645
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
646
|
+
expect(useRights().getEditCartouchierRight({ ownerId: 'test-user-123' } as Cartouchier)).toBe(ActionRight.Allowed);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it('returns DeniedNotOwner for RESTRICTED_PRODUCTION editing others\' element', async () => {
|
|
650
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
651
|
+
expect(useRights().getEditCartouchierRight({ ownerId: 'other' } as Cartouchier)).toBe(ActionRight.DeniedNotOwner);
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it('returns DeniedNoRight for role without cartouchier access', async () => {
|
|
655
|
+
await setup(['PLAYLISTS']);
|
|
656
|
+
expect(useRights().getEditCartouchierRight({ ownerId: 'test-user-123' } as Cartouchier)).toBe(ActionRight.DeniedNoRight);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
describe('getEditMediaRight', () => {
|
|
661
|
+
it('returns Allowed for ANIMATION on any element', async () => {
|
|
662
|
+
await setup(['ANIMATION']);
|
|
663
|
+
expect(useRights().getEditMediaRight({ mediaId: 1, ownerId: 'other' } as Media)).toBe(ActionRight.Allowed);
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
it('returns Allowed for RESTRICTED_PRODUCTION editing own element', async () => {
|
|
667
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
668
|
+
expect(useRights().getEditMediaRight({ mediaId: 1, ownerId: 'test-user-123' } as Media)).toBe(ActionRight.Allowed);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it('returns DeniedNotOwner for RESTRICTED_PRODUCTION editing others\' element', async () => {
|
|
672
|
+
await setup(['RESTRICTED_PRODUCTION']);
|
|
673
|
+
expect(useRights().getEditMediaRight({ mediaId: 1, ownerId: 'other' } as Media)).toBe(ActionRight.DeniedNotOwner);
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it('returns DeniedNotOwner when ownerId is absent', async () => {
|
|
677
|
+
await setup(['PODCAST_CRUD']);
|
|
678
|
+
expect(useRights().getEditMediaRight({ mediaId: 1 } as Media)).toBe(ActionRight.DeniedNotOwner);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
it('returns DeniedNoRight for role without media access', async () => {
|
|
682
|
+
await setup(['PLAYLISTS']);
|
|
683
|
+
expect(useRights().getEditMediaRight({ mediaId: 1, ownerId: 'test-user-123' } as Media)).toBe(ActionRight.DeniedNoRight);
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
describe('getEditRubriquesRight', () => {
|
|
688
|
+
it('returns Allowed for EDITION', async () => {
|
|
689
|
+
await setup(['EDITION']);
|
|
690
|
+
expect(useRights().getEditRubriquesRight({ rubriqueId: 1, name: 'Test' } as Rubrique)).toBe(ActionRight.Allowed);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
it('returns DeniedNoRight for role without rubrique access', async () => {
|
|
694
|
+
await setup(['PLAYLISTS']);
|
|
695
|
+
expect(useRights().getEditRubriquesRight({ rubriqueId: 1, name: 'Test' } as Rubrique)).toBe(ActionRight.DeniedNoRight);
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
describe('getEditTranscriptRight', () => {
|
|
700
|
+
it('returns Allowed for PRODUCTION on any podcast', async () => {
|
|
701
|
+
await setup(['PRODUCTION']);
|
|
702
|
+
expect(useRights().getEditTranscriptRight({ createdByUserId: 'other' } as Podcast)).toBe(ActionRight.Allowed);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('returns Allowed for PODCAST_CRUD editing own transcript', async () => {
|
|
706
|
+
await setup(['PODCAST_CRUD']);
|
|
707
|
+
expect(useRights().getEditTranscriptRight({ createdByUserId: 'test-user-123' } as Podcast)).toBe(ActionRight.Allowed);
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
it('returns DeniedNotOwner for PODCAST_CRUD editing others\' transcript', async () => {
|
|
711
|
+
await setup(['PODCAST_CRUD']);
|
|
712
|
+
expect(useRights().getEditTranscriptRight({ createdByUserId: 'other' } as Podcast)).toBe(ActionRight.DeniedNotOwner);
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
it('returns DeniedNoRight for role without transcript access', async () => {
|
|
716
|
+
await setup(['RESTRICTED_ANIMATION']);
|
|
717
|
+
expect(useRights().getEditTranscriptRight({ createdByUserId: 'test-user-123' } as Podcast)).toBe(ActionRight.DeniedNoRight);
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
describe('Scope permissions', () => {
|
|
723
|
+
describe('getEditEmissionRight scope', () => {
|
|
724
|
+
it('denies PRODUCTION with insufficient scope', async () => {
|
|
725
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
726
|
+
expect(useRights().getEditEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.DeniedInsufficientScope);
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
it('allows PRODUCTION with matching scope', async () => {
|
|
730
|
+
await setup(['PRODUCTION'], 'test-user-123', [1]);
|
|
731
|
+
expect(useRights().getEditEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
it('denies RESTRICTED_PRODUCTION with insufficient scope even on own emission', async () => {
|
|
735
|
+
await setup(['RESTRICTED_PRODUCTION'], 'test-user-123', [999]);
|
|
736
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'test-user-123', rubriqueIds: [1] })))
|
|
737
|
+
.toBe(ActionRight.DeniedInsufficientScope);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('allows RESTRICTED_PRODUCTION with matching scope on own emission', async () => {
|
|
741
|
+
await setup(['RESTRICTED_PRODUCTION'], 'test-user-123', [1]);
|
|
742
|
+
expect(useRights().getEditEmissionRight(mockEmission({ createdByUserId: 'test-user-123', rubriqueIds: [1] })))
|
|
743
|
+
.toBe(ActionRight.Allowed);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it('allows ADMIN regardless of scope', async () => {
|
|
747
|
+
await setup(['ADMIN'], 'test-user-123', [999]);
|
|
748
|
+
expect(useRights().getEditEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
it('canEditEmission forwards the scope-driven denial', async () => {
|
|
752
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
753
|
+
expect(useRights().canEditEmission(mockEmission({ rubriqueIds: [1] }))).toBe(false);
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
describe('getDeleteEmissionRight scope', () => {
|
|
758
|
+
it('denies PRODUCTION with insufficient scope', async () => {
|
|
759
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
760
|
+
expect(useRights().getDeleteEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.DeniedInsufficientScope);
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
it('allows PRODUCTION with matching scope', async () => {
|
|
764
|
+
await setup(['PRODUCTION'], 'test-user-123', [1]);
|
|
765
|
+
expect(useRights().getDeleteEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it('allows ADMIN regardless of scope', async () => {
|
|
769
|
+
await setup(['ADMIN'], 'test-user-123', [999]);
|
|
770
|
+
expect(useRights().getDeleteEmissionRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
describe('getCreatePodcastRight scope', () => {
|
|
775
|
+
it('allows creation without an emission arg regardless of scope', async () => {
|
|
776
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
777
|
+
expect(useRights().getCreatePodcastRight()).toBe(ActionRight.Allowed);
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
it('denies PRODUCTION with insufficient scope when an emission is passed', async () => {
|
|
781
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
782
|
+
expect(useRights().getCreatePodcastRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.DeniedInsufficientScope);
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it('allows PRODUCTION with matching scope when an emission is passed', async () => {
|
|
786
|
+
await setup(['PRODUCTION'], 'test-user-123', [1]);
|
|
787
|
+
expect(useRights().getCreatePodcastRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('allows ADMIN regardless of scope', async () => {
|
|
791
|
+
await setup(['ADMIN'], 'test-user-123', [999]);
|
|
792
|
+
expect(useRights().getCreatePodcastRight(mockEmission({ rubriqueIds: [1] }))).toBe(ActionRight.Allowed);
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
describe('getEditPodcastRight scope', () => {
|
|
797
|
+
it('denies PRODUCTION when neither podcast nor emission rubriques match scope', async () => {
|
|
798
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
799
|
+
const podcast = mockPodcast({ rubriqueIds: [1], emission: mockEmission({ rubriqueIds: [2] }) });
|
|
800
|
+
expect(useRights().getEditPodcastRight(podcast)).toBe(ActionRight.DeniedInsufficientScope);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
it('allows PRODUCTION when the podcast\'s own rubriques match scope', async () => {
|
|
804
|
+
await setup(['PRODUCTION'], 'test-user-123', [1]);
|
|
805
|
+
const podcast = mockPodcast({ rubriqueIds: [1], emission: mockEmission({ rubriqueIds: [2] }) });
|
|
806
|
+
expect(useRights().getEditPodcastRight(podcast)).toBe(ActionRight.Allowed);
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('allows PRODUCTION when only the emission\'s rubriques match scope', async () => {
|
|
810
|
+
await setup(['PRODUCTION'], 'test-user-123', [2]);
|
|
811
|
+
const podcast = mockPodcast({ rubriqueIds: [1], emission: mockEmission({ rubriqueIds: [2] }) });
|
|
812
|
+
expect(useRights().getEditPodcastRight(podcast)).toBe(ActionRight.Allowed);
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
it('denies RESTRICTED_PRODUCTION with insufficient scope even on own podcast', async () => {
|
|
816
|
+
await setup(['RESTRICTED_PRODUCTION'], 'test-user-123', [999]);
|
|
817
|
+
const podcast = mockPodcast({
|
|
818
|
+
createdByUserId: 'test-user-123',
|
|
819
|
+
rubriqueIds: [1],
|
|
820
|
+
emission: mockEmission({ rubriqueIds: [2] })
|
|
821
|
+
});
|
|
822
|
+
expect(useRights().getEditPodcastRight(podcast)).toBe(ActionRight.DeniedInsufficientScope);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it('allows ADMIN regardless of scope', async () => {
|
|
826
|
+
await setup(['ADMIN'], 'test-user-123', [999]);
|
|
827
|
+
const podcast = mockPodcast({ rubriqueIds: [1], emission: mockEmission({ rubriqueIds: [2] }) });
|
|
828
|
+
expect(useRights().getEditPodcastRight(podcast)).toBe(ActionRight.Allowed);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it('canEditPodcast forwards the scope-driven denial', async () => {
|
|
832
|
+
await setup(['PRODUCTION'], 'test-user-123', [999]);
|
|
833
|
+
const podcast = mockPodcast({ rubriqueIds: [1], emission: mockEmission({ rubriqueIds: [2] }) });
|
|
834
|
+
expect(useRights().canEditPodcast(podcast)).toBe(false);
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
});
|