strapi-plugin-keycloak-realm-users 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +485 -0
  3. package/__tests__/constants.test.mjs +207 -0
  4. package/__tests__/mocks/strapi.mjs +182 -0
  5. package/__tests__/services/audit-log.test.mjs +283 -0
  6. package/__tests__/services/keycloak-client.test.mjs +651 -0
  7. package/__tests__/services/permission.test.mjs +374 -0
  8. package/__tests__/services/realm.test.mjs +415 -0
  9. package/__tests__/services/user.test.mjs +487 -0
  10. package/__tests__/utils/errors.test.mjs +109 -0
  11. package/admin/src/components/Initializer.jsx +14 -0
  12. package/admin/src/components/RealmBadge.jsx +17 -0
  13. package/admin/src/constants.js +14 -0
  14. package/admin/src/hooks/useAuditLogs.js +142 -0
  15. package/admin/src/hooks/useKeycloakRoles.js +182 -0
  16. package/admin/src/hooks/useKeycloakUsers.js +477 -0
  17. package/admin/src/hooks/useRealmAdmins.js +249 -0
  18. package/admin/src/hooks/useRealms.js +269 -0
  19. package/admin/src/index.js +46 -0
  20. package/admin/src/pages/App.jsx +21 -0
  21. package/admin/src/pages/AuditPage/index.jsx +213 -0
  22. package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
  23. package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
  24. package/admin/src/pages/RealmsPage/index.jsx +7 -0
  25. package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
  26. package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
  27. package/admin/src/pages/UsersPage/index.jsx +7 -0
  28. package/admin/src/pluginId.js +2 -0
  29. package/admin/src/translations/en.json +77 -0
  30. package/admin/src/translations/fr.json +77 -0
  31. package/babel.config.cjs +17 -0
  32. package/coverage/clover.xml +422 -0
  33. package/coverage/coverage-final.json +8 -0
  34. package/coverage/lcov-report/base.css +224 -0
  35. package/coverage/lcov-report/block-navigation.js +87 -0
  36. package/coverage/lcov-report/favicon.png +0 -0
  37. package/coverage/lcov-report/index.html +146 -0
  38. package/coverage/lcov-report/prettify.css +1 -0
  39. package/coverage/lcov-report/prettify.js +2 -0
  40. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  41. package/coverage/lcov-report/sorter.js +210 -0
  42. package/coverage/lcov-report/src/bootstrap.js.html +346 -0
  43. package/coverage/lcov-report/src/config/index.html +116 -0
  44. package/coverage/lcov-report/src/config/index.js.html +106 -0
  45. package/coverage/lcov-report/src/constants.js.html +850 -0
  46. package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
  47. package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
  48. package/coverage/lcov-report/src/content-types/index.html +116 -0
  49. package/coverage/lcov-report/src/content-types/index.js.html +112 -0
  50. package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
  51. package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
  52. package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
  53. package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
  54. package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
  55. package/coverage/lcov-report/src/controllers/index.html +161 -0
  56. package/coverage/lcov-report/src/controllers/index.js.html +112 -0
  57. package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
  58. package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
  59. package/coverage/lcov-report/src/destroy.js.html +100 -0
  60. package/coverage/lcov-report/src/index.html +116 -0
  61. package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
  62. package/coverage/lcov-report/src/policies/index.html +146 -0
  63. package/coverage/lcov-report/src/policies/index.js.html +106 -0
  64. package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
  65. package/coverage/lcov-report/src/register.js.html +106 -0
  66. package/coverage/lcov-report/src/routes/admin.js.html +844 -0
  67. package/coverage/lcov-report/src/routes/index.html +131 -0
  68. package/coverage/lcov-report/src/routes/index.js.html +109 -0
  69. package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
  70. package/coverage/lcov-report/src/services/index.html +176 -0
  71. package/coverage/lcov-report/src/services/index.js.html +124 -0
  72. package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
  73. package/coverage/lcov-report/src/services/permission.js.html +955 -0
  74. package/coverage/lcov-report/src/services/realm.js.html +1207 -0
  75. package/coverage/lcov-report/src/services/user.js.html +1924 -0
  76. package/coverage/lcov-report/src/utils/errors.js.html +274 -0
  77. package/coverage/lcov-report/src/utils/index.html +116 -0
  78. package/coverage/lcov-report/src/utils/index.js.html +103 -0
  79. package/coverage/lcov.info +804 -0
  80. package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
  81. package/dist/_chunks/App-DO6syS77.js +1975 -0
  82. package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
  83. package/dist/_chunks/en-aCyfgNfr.js +72 -0
  84. package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
  85. package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
  86. package/dist/_chunks/index-DwDO4-0C.js +69 -0
  87. package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
  88. package/dist/admin/index.js +3 -0
  89. package/dist/admin/index.mjs +4 -0
  90. package/dist/server/index.js +3003 -0
  91. package/dist/server/index.mjs +3004 -0
  92. package/jest.config.cjs +50 -0
  93. package/package.json +55 -0
  94. package/server/src/bootstrap.js +87 -0
  95. package/server/src/config/index.js +7 -0
  96. package/server/src/constants.js +255 -0
  97. package/server/src/content-types/audit-log/index.js +3 -0
  98. package/server/src/content-types/audit-log/schema.json +61 -0
  99. package/server/src/content-types/index.js +9 -0
  100. package/server/src/content-types/realm-admin/index.js +3 -0
  101. package/server/src/content-types/realm-admin/schema.json +45 -0
  102. package/server/src/content-types/realm-config/index.js +3 -0
  103. package/server/src/content-types/realm-config/schema.json +56 -0
  104. package/server/src/controllers/audit.js +144 -0
  105. package/server/src/controllers/index.js +9 -0
  106. package/server/src/controllers/realm.js +324 -0
  107. package/server/src/controllers/user.js +413 -0
  108. package/server/src/destroy.js +5 -0
  109. package/server/src/index.js +21 -0
  110. package/server/src/policies/can-access-realm.js +26 -0
  111. package/server/src/policies/index.js +7 -0
  112. package/server/src/policies/is-authenticated.js +5 -0
  113. package/server/src/register.js +7 -0
  114. package/server/src/routes/admin.js +253 -0
  115. package/server/src/routes/index.js +8 -0
  116. package/server/src/services/audit-log.js +196 -0
  117. package/server/src/services/index.js +13 -0
  118. package/server/src/services/keycloak-client.js +758 -0
  119. package/server/src/services/permission.js +290 -0
  120. package/server/src/services/realm.js +374 -0
  121. package/server/src/services/user.js +613 -0
  122. package/server/src/utils/errors.js +63 -0
  123. package/server/src/utils/index.js +6 -0
@@ -0,0 +1,413 @@
1
+ import { PLUGIN_ID, SERVICES, ERROR_MESSAGES } from '../constants.js';
2
+
3
+ const userController = ({ strapi }) => ({
4
+ /**
5
+ * List users in a realm
6
+ */
7
+ async find(ctx) {
8
+ const user = ctx.state.user;
9
+ const { realmId } = ctx.params;
10
+ const { search, page = 1, pageSize = 25 } = ctx.query;
11
+
12
+ if (!user) {
13
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
14
+ }
15
+
16
+ try {
17
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
18
+ const result = await userService.listUsers(
19
+ realmId,
20
+ { search, page: parseInt(page, 10), pageSize: parseInt(pageSize, 10) },
21
+ user
22
+ );
23
+
24
+ ctx.body = { data: result };
25
+ } catch (err) {
26
+ strapi.log.error(`[${PLUGIN_ID}] user.find error:`, err);
27
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
28
+ }
29
+ },
30
+
31
+ /**
32
+ * Get a single user
33
+ */
34
+ async findOne(ctx) {
35
+ const user = ctx.state.user;
36
+ const { realmId, id } = ctx.params;
37
+
38
+ if (!user) {
39
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
40
+ }
41
+
42
+ try {
43
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
44
+ const keycloakUser = await userService.getUser(realmId, id, user);
45
+
46
+ ctx.body = { data: keycloakUser };
47
+ } catch (err) {
48
+ strapi.log.error(`[${PLUGIN_ID}] user.findOne error:`, err);
49
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
50
+ }
51
+ },
52
+
53
+ /**
54
+ * Create a new user
55
+ */
56
+ async create(ctx) {
57
+ const user = ctx.state.user;
58
+ const { realmId } = ctx.params;
59
+ const { data } = ctx.request.body;
60
+
61
+ if (!user) {
62
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
63
+ }
64
+
65
+ try {
66
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
67
+ const keycloakUser = await userService.createUser(realmId, data, user);
68
+
69
+ ctx.body = { data: keycloakUser };
70
+ } catch (err) {
71
+ strapi.log.error(`[${PLUGIN_ID}] user.create error:`, err);
72
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
73
+ }
74
+ },
75
+
76
+ /**
77
+ * Update a user
78
+ */
79
+ async update(ctx) {
80
+ const user = ctx.state.user;
81
+ const { realmId, id } = ctx.params;
82
+ const { data } = ctx.request.body;
83
+
84
+ if (!user) {
85
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
86
+ }
87
+
88
+ try {
89
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
90
+ const keycloakUser = await userService.updateUser(realmId, id, data, user);
91
+
92
+ ctx.body = { data: keycloakUser };
93
+ } catch (err) {
94
+ strapi.log.error(`[${PLUGIN_ID}] user.update error:`, err);
95
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
96
+ }
97
+ },
98
+
99
+ /**
100
+ * Delete a user
101
+ */
102
+ async delete(ctx) {
103
+ const user = ctx.state.user;
104
+ const { realmId, id } = ctx.params;
105
+
106
+ if (!user) {
107
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
108
+ }
109
+
110
+ try {
111
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
112
+ await userService.deleteUser(realmId, id, user);
113
+
114
+ ctx.body = { data: { success: true } };
115
+ } catch (err) {
116
+ strapi.log.error(`[${PLUGIN_ID}] user.delete error:`, err);
117
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
118
+ }
119
+ },
120
+
121
+ /**
122
+ * Reset user password
123
+ */
124
+ async resetPassword(ctx) {
125
+ const user = ctx.state.user;
126
+ const { realmId, id } = ctx.params;
127
+ const { data } = ctx.request.body;
128
+
129
+ if (!user) {
130
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
131
+ }
132
+
133
+ try {
134
+ const { password, temporary = true } = data;
135
+
136
+ if (!password) {
137
+ return ctx.badRequest('Password is required.');
138
+ }
139
+
140
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
141
+ await userService.resetPassword(realmId, id, password, temporary, user);
142
+
143
+ ctx.body = { data: { success: true } };
144
+ } catch (err) {
145
+ strapi.log.error(`[${PLUGIN_ID}] user.resetPassword error:`, err);
146
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
147
+ }
148
+ },
149
+
150
+ /**
151
+ * Enable a user
152
+ */
153
+ async enable(ctx) {
154
+ const user = ctx.state.user;
155
+ const { realmId, id } = ctx.params;
156
+
157
+ if (!user) {
158
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
159
+ }
160
+
161
+ try {
162
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
163
+ await userService.enableUser(realmId, id, user);
164
+
165
+ ctx.body = { data: { success: true } };
166
+ } catch (err) {
167
+ strapi.log.error(`[${PLUGIN_ID}] user.enable error:`, err);
168
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
169
+ }
170
+ },
171
+
172
+ /**
173
+ * Disable a user
174
+ */
175
+ async disable(ctx) {
176
+ const user = ctx.state.user;
177
+ const { realmId, id } = ctx.params;
178
+
179
+ if (!user) {
180
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
181
+ }
182
+
183
+ try {
184
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
185
+ await userService.disableUser(realmId, id, user);
186
+
187
+ ctx.body = { data: { success: true } };
188
+ } catch (err) {
189
+ strapi.log.error(`[${PLUGIN_ID}] user.disable error:`, err);
190
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
191
+ }
192
+ },
193
+
194
+ /**
195
+ * Send verification email
196
+ */
197
+ async sendVerifyEmail(ctx) {
198
+ const user = ctx.state.user;
199
+ const { realmId, id } = ctx.params;
200
+
201
+ if (!user) {
202
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
203
+ }
204
+
205
+ try {
206
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
207
+ await userService.sendVerificationEmail(realmId, id, user);
208
+
209
+ ctx.body = { data: { success: true } };
210
+ } catch (err) {
211
+ strapi.log.error(`[${PLUGIN_ID}] user.sendVerifyEmail error:`, err);
212
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
213
+ }
214
+ },
215
+
216
+ /**
217
+ * Send password reset email
218
+ */
219
+ async sendResetPasswordEmail(ctx) {
220
+ const user = ctx.state.user;
221
+ const { realmId, id } = ctx.params;
222
+
223
+ if (!user) {
224
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
225
+ }
226
+
227
+ try {
228
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
229
+ await userService.sendResetPasswordEmail(realmId, id, user);
230
+
231
+ ctx.body = { data: { success: true } };
232
+ } catch (err) {
233
+ strapi.log.error(`[${PLUGIN_ID}] user.sendResetPasswordEmail error:`, err);
234
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
235
+ }
236
+ },
237
+
238
+ /**
239
+ * Get realm roles
240
+ */
241
+ async getRoles(ctx) {
242
+ const user = ctx.state.user;
243
+ const { realmId } = ctx.params;
244
+
245
+ if (!user) {
246
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
247
+ }
248
+
249
+ try {
250
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
251
+ const roles = await userService.getRoles(realmId, user);
252
+
253
+ ctx.body = { data: roles };
254
+ } catch (err) {
255
+ strapi.log.error(`[${PLUGIN_ID}] user.getRoles error:`, err);
256
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
257
+ }
258
+ },
259
+
260
+ /**
261
+ * Get user's roles
262
+ */
263
+ async getUserRoles(ctx) {
264
+ const user = ctx.state.user;
265
+ const { realmId, id } = ctx.params;
266
+
267
+ if (!user) {
268
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
269
+ }
270
+
271
+ try {
272
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
273
+ const roles = await userService.getUserRoles(realmId, id, user);
274
+
275
+ ctx.body = { data: roles };
276
+ } catch (err) {
277
+ strapi.log.error(`[${PLUGIN_ID}] user.getUserRoles error:`, err);
278
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
279
+ }
280
+ },
281
+
282
+ /**
283
+ * Assign roles to user
284
+ */
285
+ async assignRoles(ctx) {
286
+ const user = ctx.state.user;
287
+ const { realmId, id } = ctx.params;
288
+ const { data } = ctx.request.body;
289
+
290
+ if (!user) {
291
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
292
+ }
293
+
294
+ try {
295
+ const { roles } = data;
296
+
297
+ if (!roles || !Array.isArray(roles)) {
298
+ return ctx.badRequest('Roles array is required.');
299
+ }
300
+
301
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
302
+ await userService.assignRoles(realmId, id, roles, user);
303
+
304
+ ctx.body = { data: { success: true } };
305
+ } catch (err) {
306
+ strapi.log.error(`[${PLUGIN_ID}] user.assignRoles error:`, err);
307
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
308
+ }
309
+ },
310
+
311
+ /**
312
+ * Remove roles from user
313
+ */
314
+ async removeRoles(ctx) {
315
+ const user = ctx.state.user;
316
+ const { realmId, id } = ctx.params;
317
+ const { data } = ctx.request.body;
318
+
319
+ if (!user) {
320
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
321
+ }
322
+
323
+ try {
324
+ const { roles } = data;
325
+
326
+ if (!roles || !Array.isArray(roles)) {
327
+ return ctx.badRequest('Roles array is required.');
328
+ }
329
+
330
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
331
+ await userService.removeRoles(realmId, id, roles, user);
332
+
333
+ ctx.body = { data: { success: true } };
334
+ } catch (err) {
335
+ strapi.log.error(`[${PLUGIN_ID}] user.removeRoles error:`, err);
336
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
337
+ }
338
+ },
339
+
340
+ /**
341
+ * Bulk import users
342
+ */
343
+ async bulkImport(ctx) {
344
+ const user = ctx.state.user;
345
+ const { realmId } = ctx.params;
346
+ const { data } = ctx.request.body;
347
+
348
+ if (!user) {
349
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
350
+ }
351
+
352
+ try {
353
+ const { users } = data;
354
+
355
+ if (!users || !Array.isArray(users)) {
356
+ return ctx.badRequest('Users array is required.');
357
+ }
358
+
359
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
360
+ const result = await userService.bulkImport(realmId, users, user);
361
+
362
+ ctx.body = { data: result };
363
+ } catch (err) {
364
+ strapi.log.error(`[${PLUGIN_ID}] user.bulkImport error:`, err);
365
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
366
+ }
367
+ },
368
+
369
+ /**
370
+ * Export users
371
+ */
372
+ async exportUsers(ctx) {
373
+ const user = ctx.state.user;
374
+ const { realmId } = ctx.params;
375
+ const { format = 'json' } = ctx.query;
376
+
377
+ if (!user) {
378
+ return ctx.unauthorized(ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS);
379
+ }
380
+
381
+ try {
382
+ const userService = strapi.plugin(PLUGIN_ID).service(SERVICES.USER);
383
+ const users = await userService.exportUsers(realmId, user);
384
+
385
+ if (format === 'csv') {
386
+ // Convert to CSV
387
+ const headers = ['id', 'username', 'email', 'firstName', 'lastName', 'enabled', 'emailVerified'];
388
+ const csvRows = [headers.join(',')];
389
+
390
+ for (const u of users) {
391
+ const row = headers.map((h) => {
392
+ const val = u[h];
393
+ if (val === undefined || val === null) return '';
394
+ if (typeof val === 'string' && val.includes(',')) return `"${val}"`;
395
+ return String(val);
396
+ });
397
+ csvRows.push(row.join(','));
398
+ }
399
+
400
+ ctx.set('Content-Type', 'text/csv');
401
+ ctx.set('Content-Disposition', `attachment; filename="keycloak-users-${realmId}.csv"`);
402
+ ctx.body = csvRows.join('\n');
403
+ } else {
404
+ ctx.body = { data: users };
405
+ }
406
+ } catch (err) {
407
+ strapi.log.error(`[${PLUGIN_ID}] user.exportUsers error:`, err);
408
+ ctx.throw(400, err.sanitizedMessage || ERROR_MESSAGES.UNKNOWN_ERROR);
409
+ }
410
+ },
411
+ });
412
+
413
+ export default userController;
@@ -0,0 +1,5 @@
1
+ const destroy = ({ strapi }) => {
2
+ // Cleanup if needed
3
+ };
4
+
5
+ export default destroy;
@@ -0,0 +1,21 @@
1
+ import bootstrap from './bootstrap.js';
2
+ import register from './register.js';
3
+ import destroy from './destroy.js';
4
+ import config from './config/index.js';
5
+ import contentTypes from './content-types/index.js';
6
+ import controllers from './controllers/index.js';
7
+ import services from './services/index.js';
8
+ import policies from './policies/index.js';
9
+ import routes from './routes/index.js';
10
+
11
+ export default {
12
+ bootstrap,
13
+ register,
14
+ destroy,
15
+ config,
16
+ contentTypes,
17
+ controllers,
18
+ services,
19
+ policies,
20
+ routes,
21
+ };
@@ -0,0 +1,26 @@
1
+ import { PLUGIN_ID, SERVICES } from '../constants.js';
2
+
3
+ const canAccessRealm = async (policyContext, config, { strapi }) => {
4
+ const { realmId, id } = policyContext.params;
5
+ const user = policyContext.state.user;
6
+
7
+ // Determine which parameter holds the realm ID
8
+ const targetRealmId = realmId || id;
9
+
10
+ if (!user || !targetRealmId) {
11
+ return false;
12
+ }
13
+
14
+ const permissionService = strapi.plugin(PLUGIN_ID).service(SERVICES.PERMISSION);
15
+
16
+ // Super admins can access all realms
17
+ if (permissionService.isSuperAdmin(user)) {
18
+ return true;
19
+ }
20
+
21
+ // Check specific permission
22
+ const permission = config?.permission || 'canRead';
23
+ return permissionService.canAccessRealm(user, targetRealmId, permission);
24
+ };
25
+
26
+ export default canAccessRealm;
@@ -0,0 +1,7 @@
1
+ import isAuthenticated from './is-authenticated.js';
2
+ import canAccessRealm from './can-access-realm.js';
3
+
4
+ export default {
5
+ 'is-authenticated': isAuthenticated,
6
+ 'can-access-realm': canAccessRealm,
7
+ };
@@ -0,0 +1,5 @@
1
+ const isAuthenticated = (policyContext) => {
2
+ return Boolean(policyContext.state.user);
3
+ };
4
+
5
+ export default isAuthenticated;
@@ -0,0 +1,7 @@
1
+ import { PLUGIN_ID } from './constants.js';
2
+
3
+ const register = ({ strapi }) => {
4
+ strapi.log.info(`[${PLUGIN_ID}] Plugin registered successfully`);
5
+ };
6
+
7
+ export default register;