strapi-plugin-magic-sessionmanager 4.2.4 → 4.2.6

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 (62) hide show
  1. package/README.md +0 -2
  2. package/dist/server/index.js +1 -1
  3. package/dist/server/index.mjs +1 -1
  4. package/package.json +1 -3
  5. package/admin/jsconfig.json +0 -10
  6. package/admin/src/components/Initializer.jsx +0 -11
  7. package/admin/src/components/LicenseGuard.jsx +0 -591
  8. package/admin/src/components/OnlineUsersWidget.jsx +0 -212
  9. package/admin/src/components/PluginIcon.jsx +0 -8
  10. package/admin/src/components/SessionDetailModal.jsx +0 -449
  11. package/admin/src/components/SessionInfoCard.jsx +0 -151
  12. package/admin/src/components/SessionInfoPanel.jsx +0 -385
  13. package/admin/src/components/index.jsx +0 -5
  14. package/admin/src/hooks/useLicense.js +0 -103
  15. package/admin/src/index.js +0 -149
  16. package/admin/src/pages/ActiveSessions.jsx +0 -12
  17. package/admin/src/pages/Analytics.jsx +0 -735
  18. package/admin/src/pages/App.jsx +0 -12
  19. package/admin/src/pages/HomePage.jsx +0 -1212
  20. package/admin/src/pages/License.jsx +0 -603
  21. package/admin/src/pages/Settings.jsx +0 -1646
  22. package/admin/src/pages/SettingsNew.jsx +0 -1204
  23. package/admin/src/pages/UpgradePage.jsx +0 -448
  24. package/admin/src/pages/index.jsx +0 -3
  25. package/admin/src/pluginId.js +0 -4
  26. package/admin/src/translations/de.json +0 -299
  27. package/admin/src/translations/en.json +0 -299
  28. package/admin/src/translations/es.json +0 -287
  29. package/admin/src/translations/fr.json +0 -287
  30. package/admin/src/translations/pt.json +0 -287
  31. package/admin/src/utils/getTranslation.js +0 -5
  32. package/admin/src/utils/index.js +0 -2
  33. package/admin/src/utils/parseUserAgent.js +0 -79
  34. package/admin/src/utils/theme.js +0 -85
  35. package/server/jsconfig.json +0 -10
  36. package/server/src/bootstrap.js +0 -492
  37. package/server/src/config/index.js +0 -23
  38. package/server/src/content-types/index.js +0 -9
  39. package/server/src/content-types/session/schema.json +0 -84
  40. package/server/src/controllers/controller.js +0 -11
  41. package/server/src/controllers/index.js +0 -11
  42. package/server/src/controllers/license.js +0 -266
  43. package/server/src/controllers/session.js +0 -433
  44. package/server/src/controllers/settings.js +0 -122
  45. package/server/src/destroy.js +0 -22
  46. package/server/src/index.js +0 -23
  47. package/server/src/middlewares/index.js +0 -5
  48. package/server/src/middlewares/last-seen.js +0 -62
  49. package/server/src/policies/index.js +0 -3
  50. package/server/src/register.js +0 -36
  51. package/server/src/routes/admin.js +0 -149
  52. package/server/src/routes/content-api.js +0 -60
  53. package/server/src/routes/index.js +0 -9
  54. package/server/src/services/geolocation.js +0 -182
  55. package/server/src/services/index.js +0 -13
  56. package/server/src/services/license-guard.js +0 -316
  57. package/server/src/services/notifications.js +0 -319
  58. package/server/src/services/service.js +0 -7
  59. package/server/src/services/session.js +0 -393
  60. package/server/src/utils/encryption.js +0 -121
  61. package/server/src/utils/getClientIp.js +0 -118
  62. package/server/src/utils/logger.js +0 -84
@@ -1,266 +0,0 @@
1
- /**
2
- * License Controller for Magic Session Manager Plugin
3
- * Manages licenses directly from the Admin Panel
4
- */
5
-
6
- module.exports = ({ strapi }) => ({
7
- /**
8
- * Auto-create license with logged-in admin user data
9
- */
10
- async autoCreate(ctx) {
11
- try {
12
- // Get the logged-in admin user
13
- const adminUser = ctx.state.user;
14
-
15
- if (!adminUser) {
16
- return ctx.unauthorized('No admin user logged in');
17
- }
18
-
19
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
20
-
21
- // Use admin user data for license creation
22
- const license = await licenseGuard.createLicense({
23
- email: adminUser.email,
24
- firstName: adminUser.firstname || 'Admin',
25
- lastName: adminUser.lastname || 'User',
26
- });
27
-
28
- if (!license) {
29
- return ctx.badRequest('Failed to create license');
30
- }
31
-
32
- // Store the license key
33
- await licenseGuard.storeLicenseKey(license.licenseKey);
34
-
35
- // Start pinging
36
- const pingInterval = licenseGuard.startPinging(license.licenseKey, 15);
37
-
38
- // Update global license guard
39
- strapi.licenseGuard = {
40
- licenseKey: license.licenseKey,
41
- pingInterval,
42
- data: license,
43
- };
44
-
45
- return ctx.send({
46
- success: true,
47
- message: 'License automatically created and activated',
48
- data: license,
49
- });
50
- } catch (error) {
51
- strapi.log.error('[magic-sessionmanager] Error auto-creating license:', error);
52
- return ctx.badRequest('Error creating license');
53
- }
54
- },
55
-
56
- /**
57
- * Get current license status
58
- */
59
- async getStatus(ctx) {
60
- try {
61
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
62
- const pluginStore = strapi.store({
63
- type: 'plugin',
64
- name: 'magic-sessionmanager'
65
- });
66
- const licenseKey = await pluginStore.get({ key: 'licenseKey' });
67
-
68
- if (!licenseKey) {
69
- strapi.log.debug('[magic-sessionmanager] No license key in store - demo mode');
70
- return ctx.send({
71
- success: false,
72
- demo: true,
73
- valid: false,
74
- message: 'No license found. Running in demo mode.',
75
- });
76
- }
77
-
78
- strapi.log.info(`[magic-sessionmanager/license-controller] Checking stored license: ${licenseKey}`);
79
-
80
- const verification = await licenseGuard.verifyLicense(licenseKey);
81
- const license = await licenseGuard.getLicenseByKey(licenseKey);
82
-
83
- strapi.log.info('[magic-sessionmanager/license-controller] License data from MagicAPI:', {
84
- licenseKey: license?.licenseKey,
85
- email: license?.email,
86
- featurePremium: license?.featurePremium,
87
- isActive: license?.isActive,
88
- pluginName: license?.pluginName,
89
- });
90
-
91
- return ctx.send({
92
- success: true,
93
- valid: verification.valid,
94
- demo: false,
95
- data: {
96
- licenseKey,
97
- email: license?.email || null,
98
- firstName: license?.firstName || null,
99
- lastName: license?.lastName || null,
100
- isActive: license?.isActive || false,
101
- isExpired: license?.isExpired || false,
102
- isOnline: license?.isOnline || false,
103
- expiresAt: license?.expiresAt,
104
- lastPingAt: license?.lastPingAt,
105
- deviceName: license?.deviceName,
106
- deviceId: license?.deviceId,
107
- ipAddress: license?.ipAddress,
108
- features: {
109
- premium: license?.featurePremium || false,
110
- advanced: license?.featureAdvanced || false,
111
- enterprise: license?.featureEnterprise || false,
112
- custom: license?.featureCustom || false,
113
- },
114
- maxDevices: license?.maxDevices || 1,
115
- currentDevices: license?.currentDevices || 0,
116
- },
117
- });
118
- } catch (error) {
119
- strapi.log.error('[magic-sessionmanager] Error getting license status:', error);
120
- return ctx.badRequest('Error getting license status');
121
- }
122
- },
123
-
124
- /**
125
- * Create and activate a new license
126
- */
127
- async createAndActivate(ctx) {
128
- try {
129
- const { email, firstName, lastName } = ctx.request.body;
130
-
131
- if (!email || !firstName || !lastName) {
132
- return ctx.badRequest('Email, firstName, and lastName are required');
133
- }
134
-
135
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
136
- const license = await licenseGuard.createLicense({ email, firstName, lastName });
137
-
138
- if (!license) {
139
- return ctx.badRequest('Failed to create license');
140
- }
141
-
142
- // Store the license key
143
- await licenseGuard.storeLicenseKey(license.licenseKey);
144
-
145
- // Start pinging
146
- const pingInterval = licenseGuard.startPinging(license.licenseKey, 15);
147
-
148
- // Update global license guard
149
- strapi.licenseGuard = {
150
- licenseKey: license.licenseKey,
151
- pingInterval,
152
- data: license,
153
- };
154
-
155
- return ctx.send({
156
- success: true,
157
- message: 'License created and activated successfully',
158
- data: license,
159
- });
160
- } catch (error) {
161
- strapi.log.error('[magic-sessionmanager] Error creating license:', error);
162
- return ctx.badRequest('Error creating license');
163
- }
164
- },
165
-
166
- /**
167
- * Manually ping the current license
168
- */
169
- async ping(ctx) {
170
- try {
171
- const pluginStore = strapi.store({
172
- type: 'plugin',
173
- name: 'magic-sessionmanager'
174
- });
175
- const licenseKey = await pluginStore.get({ key: 'licenseKey' });
176
-
177
- if (!licenseKey) {
178
- return ctx.badRequest('No license key found');
179
- }
180
-
181
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
182
- const pingResult = await licenseGuard.pingLicense(licenseKey);
183
-
184
- if (!pingResult) {
185
- return ctx.badRequest('Ping failed');
186
- }
187
-
188
- return ctx.send({
189
- success: true,
190
- message: 'License pinged successfully',
191
- data: pingResult,
192
- });
193
- } catch (error) {
194
- strapi.log.error('[magic-sessionmanager] Error pinging license:', error);
195
- return ctx.badRequest('Error pinging license');
196
- }
197
- },
198
-
199
- /**
200
- * Store and validate an existing license key
201
- */
202
- async storeKey(ctx) {
203
- try {
204
- const { licenseKey, email } = ctx.request.body;
205
-
206
- if (!licenseKey || !licenseKey.trim()) {
207
- return ctx.badRequest('License key is required');
208
- }
209
-
210
- if (!email || !email.trim()) {
211
- return ctx.badRequest('Email address is required');
212
- }
213
-
214
- const trimmedKey = licenseKey.trim();
215
- const trimmedEmail = email.trim().toLowerCase();
216
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
217
-
218
- // Verify the license key first
219
- const verification = await licenseGuard.verifyLicense(trimmedKey);
220
-
221
- if (!verification.valid) {
222
- strapi.log.warn(`[magic-sessionmanager] [WARNING] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
223
- return ctx.badRequest('Invalid or expired license key');
224
- }
225
-
226
- // Get license details to verify email
227
- const license = await licenseGuard.getLicenseByKey(trimmedKey);
228
-
229
- if (!license) {
230
- strapi.log.warn(`[magic-sessionmanager] [WARNING] License not found in database: ${trimmedKey.substring(0, 8)}...`);
231
- return ctx.badRequest('License not found');
232
- }
233
-
234
- // Verify email matches
235
- if (license.email.toLowerCase() !== trimmedEmail) {
236
- strapi.log.warn(`[magic-sessionmanager] [WARNING] Email mismatch for license key: ${trimmedKey.substring(0, 8)}... (Attempted: ${trimmedEmail})`);
237
- return ctx.badRequest('Email address does not match this license key');
238
- }
239
-
240
- // Store the license key
241
- await licenseGuard.storeLicenseKey(trimmedKey);
242
-
243
- // Start pinging
244
- const pingInterval = licenseGuard.startPinging(trimmedKey, 15);
245
-
246
- // Update global license guard
247
- strapi.licenseGuard = {
248
- licenseKey: trimmedKey,
249
- pingInterval,
250
- data: verification.data,
251
- };
252
-
253
- strapi.log.info(`[magic-sessionmanager] [SUCCESS] Existing license key validated and stored: ${trimmedKey.substring(0, 8)}... (Email: ${trimmedEmail})`);
254
-
255
- return ctx.send({
256
- success: true,
257
- message: 'License key validated and activated successfully',
258
- data: verification.data,
259
- });
260
- } catch (error) {
261
- strapi.log.error('[magic-sessionmanager] Error storing license key:', error);
262
- return ctx.badRequest('Error validating license key');
263
- }
264
- },
265
- });
266
-
@@ -1,433 +0,0 @@
1
- 'use strict';
2
-
3
- const { decryptToken } = require('../utils/encryption');
4
-
5
- const SESSION_UID = 'plugin::magic-sessionmanager.session';
6
- const USER_UID = 'plugin::users-permissions.user';
7
-
8
- /**
9
- * Session Controller
10
- * Handles HTTP requests for session management
11
- */
12
- module.exports = {
13
- /**
14
- * Get ALL sessions (active + inactive) - Admin only
15
- * GET /magic-sessionmanager/sessions
16
- */
17
- async getAllSessionsAdmin(ctx) {
18
- try {
19
- const sessionService = strapi
20
- .plugin('magic-sessionmanager')
21
- .service('session');
22
-
23
- const sessions = await sessionService.getAllSessions();
24
-
25
- ctx.body = {
26
- data: sessions,
27
- meta: {
28
- count: sessions.length,
29
- active: sessions.filter(s => s.isTrulyActive).length,
30
- inactive: sessions.filter(s => !s.isTrulyActive).length,
31
- },
32
- };
33
- } catch (err) {
34
- ctx.throw(500, 'Error fetching sessions');
35
- }
36
- },
37
-
38
- /**
39
- * Get active sessions only
40
- * GET /magic-sessionmanager/sessions/active
41
- */
42
- async getActiveSessions(ctx) {
43
- try {
44
- const sessionService = strapi
45
- .plugin('magic-sessionmanager')
46
- .service('session');
47
-
48
- const sessions = await sessionService.getActiveSessions();
49
-
50
- ctx.body = {
51
- data: sessions,
52
- meta: {
53
- count: sessions.length,
54
- },
55
- };
56
- } catch (err) {
57
- ctx.throw(500, 'Error fetching active sessions');
58
- }
59
- },
60
-
61
- /**
62
- * Get own sessions (authenticated user)
63
- * GET /api/magic-sessionmanager/my-sessions
64
- * Automatically uses the authenticated user's documentId
65
- */
66
- async getOwnSessions(ctx) {
67
- try {
68
- // Strapi v5: Use documentId from authenticated user
69
- const userId = ctx.state.user?.documentId;
70
-
71
- if (!userId) {
72
- return ctx.throw(401, 'Unauthorized');
73
- }
74
-
75
- const sessionService = strapi
76
- .plugin('magic-sessionmanager')
77
- .service('session');
78
-
79
- const sessions = await sessionService.getUserSessions(userId);
80
-
81
- ctx.body = {
82
- data: sessions,
83
- meta: {
84
- count: sessions.length,
85
- },
86
- };
87
- } catch (err) {
88
- strapi.log.error('[magic-sessionmanager] Error fetching own sessions:', err);
89
- ctx.throw(500, 'Error fetching sessions');
90
- }
91
- },
92
-
93
- /**
94
- * Get user's sessions
95
- * GET /magic-sessionmanager/user/:userId/sessions (Admin API)
96
- * GET /api/magic-sessionmanager/user/:userId/sessions (Content API)
97
- * SECURITY: Admins can view any user, Content API users only their own
98
- */
99
- async getUserSessions(ctx) {
100
- try {
101
- const { userId } = ctx.params;
102
-
103
- // Check if this is an admin request
104
- const isAdminRequest = ctx.state.userAbility || ctx.state.admin;
105
- // Strapi v5: Use documentId instead of numeric id
106
- const requestingUserDocId = ctx.state.user?.documentId;
107
-
108
- // SECURITY CHECK: Content API users can only see their own sessions
109
- // Admins can see any user's sessions
110
- if (!isAdminRequest && requestingUserDocId && String(requestingUserDocId) !== String(userId)) {
111
- strapi.log.warn(`[magic-sessionmanager] Security: User ${requestingUserDocId} tried to access sessions of user ${userId}`);
112
- return ctx.forbidden('You can only access your own sessions');
113
- }
114
-
115
- const sessionService = strapi
116
- .plugin('magic-sessionmanager')
117
- .service('session');
118
-
119
- const sessions = await sessionService.getUserSessions(userId);
120
-
121
- ctx.body = {
122
- data: sessions,
123
- meta: {
124
- count: sessions.length,
125
- },
126
- };
127
- } catch (err) {
128
- ctx.throw(500, 'Error fetching user sessions');
129
- }
130
- },
131
-
132
- /**
133
- * Logout handler - terminates current session
134
- * POST /api/magic-sessionmanager/logout
135
- */
136
- async logout(ctx) {
137
- try {
138
- // Strapi v5: Use documentId instead of numeric id
139
- const userId = ctx.state.user?.documentId;
140
- const token = ctx.request.headers.authorization?.replace('Bearer ', '');
141
-
142
- if (!userId) {
143
- return ctx.throw(401, 'Unauthorized');
144
- }
145
-
146
- const sessionService = strapi
147
- .plugin('magic-sessionmanager')
148
- .service('session');
149
-
150
- // Find current session by decrypting and comparing tokens
151
- const sessions = await strapi.documents(SESSION_UID).findMany({
152
- filters: {
153
- user: { documentId: userId },
154
- isActive: true,
155
- },
156
- });
157
-
158
- // Find matching session by decrypting tokens
159
- const matchingSession = sessions.find(session => {
160
- if (!session.token) return false;
161
- try {
162
- const decrypted = decryptToken(session.token);
163
- return decrypted === token;
164
- } catch (err) {
165
- return false;
166
- }
167
- });
168
-
169
- if (matchingSession) {
170
- // Terminate only the current session
171
- await sessionService.terminateSession({ sessionId: matchingSession.documentId });
172
- strapi.log.info(`[magic-sessionmanager] User ${userId} logged out (session ${matchingSession.documentId})`);
173
- }
174
-
175
- ctx.body = {
176
- message: 'Logged out successfully',
177
- };
178
- } catch (err) {
179
- strapi.log.error('[magic-sessionmanager] Logout error:', err);
180
- ctx.throw(500, 'Error during logout');
181
- }
182
- },
183
-
184
- /**
185
- * Logout from all devices - terminates all sessions for current user
186
- * POST /api/magic-sessionmanager/logout-all
187
- */
188
- async logoutAll(ctx) {
189
- try {
190
- // Strapi v5: Use documentId instead of numeric id
191
- const userId = ctx.state.user?.documentId;
192
-
193
- if (!userId) {
194
- return ctx.throw(401, 'Unauthorized');
195
- }
196
-
197
- const sessionService = strapi
198
- .plugin('magic-sessionmanager')
199
- .service('session');
200
-
201
- // Terminate all sessions for this user
202
- await sessionService.terminateSession({ userId });
203
-
204
- strapi.log.info(`[magic-sessionmanager] User ${userId} logged out from all devices`);
205
-
206
- ctx.body = {
207
- message: 'Logged out from all devices successfully',
208
- };
209
- } catch (err) {
210
- strapi.log.error('[magic-sessionmanager] Logout-all error:', err);
211
- ctx.throw(500, 'Error during logout');
212
- }
213
- },
214
-
215
- /**
216
- * Terminate specific session
217
- * DELETE /magic-sessionmanager/sessions/:sessionId
218
- */
219
- async terminateSession(ctx) {
220
- try {
221
- const { sessionId } = ctx.params;
222
- const sessionService = strapi
223
- .plugin('magic-sessionmanager')
224
- .service('session');
225
-
226
- await sessionService.terminateSession({ sessionId });
227
-
228
- ctx.body = {
229
- message: `Session ${sessionId} terminated`,
230
- };
231
- } catch (err) {
232
- ctx.throw(500, 'Error terminating session');
233
- }
234
- },
235
-
236
- /**
237
- * Terminate a single session (Admin action)
238
- * POST /magic-sessionmanager/sessions/:sessionId/terminate
239
- */
240
- async terminateSingleSession(ctx) {
241
- try {
242
- const { sessionId } = ctx.params;
243
-
244
- const sessionService = strapi
245
- .plugin('magic-sessionmanager')
246
- .service('session');
247
-
248
- await sessionService.terminateSession({ sessionId });
249
-
250
- ctx.body = {
251
- message: `Session ${sessionId} terminated`,
252
- success: true,
253
- };
254
- } catch (err) {
255
- strapi.log.error('[magic-sessionmanager] Error terminating session:', err);
256
- ctx.throw(500, 'Error terminating session');
257
- }
258
- },
259
-
260
- /**
261
- * Terminate ALL sessions for a specific user (Admin action)
262
- * POST /magic-sessionmanager/user/:userId/terminate-all
263
- */
264
- async terminateAllUserSessions(ctx) {
265
- try {
266
- const { userId } = ctx.params;
267
-
268
- const sessionService = strapi
269
- .plugin('magic-sessionmanager')
270
- .service('session');
271
-
272
- await sessionService.terminateSession({ userId });
273
-
274
- ctx.body = {
275
- message: `All sessions terminated for user ${userId}`,
276
- success: true,
277
- };
278
- } catch (err) {
279
- strapi.log.error('[magic-sessionmanager] Error terminating all user sessions:', err);
280
- ctx.throw(500, 'Error terminating all user sessions');
281
- }
282
- },
283
-
284
- /**
285
- * Get IP Geolocation data (Premium feature)
286
- * GET /magic-sessionmanager/geolocation/:ipAddress
287
- */
288
- async getIpGeolocation(ctx) {
289
- try {
290
- const { ipAddress } = ctx.params;
291
-
292
- if (!ipAddress) {
293
- return ctx.badRequest('IP address is required');
294
- }
295
-
296
- // Check if user has premium license
297
- const licenseGuard = strapi.plugin('magic-sessionmanager').service('license-guard');
298
- const pluginStore = strapi.store({
299
- type: 'plugin',
300
- name: 'magic-sessionmanager'
301
- });
302
- const licenseKey = await pluginStore.get({ key: 'licenseKey' });
303
-
304
- if (!licenseKey) {
305
- return ctx.forbidden('Premium license required for geolocation features');
306
- }
307
-
308
- const license = await licenseGuard.getLicenseByKey(licenseKey);
309
-
310
- if (!license || !license.featurePremium) {
311
- return ctx.forbidden('Premium license required for geolocation features');
312
- }
313
-
314
- // Get geolocation data
315
- const geolocationService = strapi.plugin('magic-sessionmanager').service('geolocation');
316
- const ipData = await geolocationService.getIpInfo(ipAddress);
317
-
318
- ctx.body = {
319
- success: true,
320
- data: ipData,
321
- };
322
- } catch (err) {
323
- strapi.log.error('[magic-sessionmanager] Error getting IP geolocation:', err);
324
- ctx.throw(500, 'Error fetching IP geolocation data');
325
- }
326
- },
327
-
328
- /**
329
- * Delete a single session permanently (Admin action)
330
- * DELETE /magic-sessionmanager/sessions/:sessionId
331
- */
332
- async deleteSession(ctx) {
333
- try {
334
- const { sessionId } = ctx.params;
335
-
336
- const sessionService = strapi
337
- .plugin('magic-sessionmanager')
338
- .service('session');
339
-
340
- await sessionService.deleteSession(sessionId);
341
-
342
- ctx.body = {
343
- message: `Session ${sessionId} permanently deleted`,
344
- success: true,
345
- };
346
- } catch (err) {
347
- strapi.log.error('[magic-sessionmanager] Error deleting session:', err);
348
- ctx.throw(500, 'Error deleting session');
349
- }
350
- },
351
-
352
- /**
353
- * Delete all inactive sessions (Admin action)
354
- * POST /magic-sessionmanager/sessions/clean-inactive
355
- */
356
- async cleanInactiveSessions(ctx) {
357
- try {
358
- const sessionService = strapi
359
- .plugin('magic-sessionmanager')
360
- .service('session');
361
-
362
- const deletedCount = await sessionService.deleteInactiveSessions();
363
-
364
- ctx.body = {
365
- message: `Successfully deleted ${deletedCount} inactive sessions`,
366
- success: true,
367
- deletedCount,
368
- };
369
- } catch (err) {
370
- strapi.log.error('[magic-sessionmanager] Error cleaning inactive sessions:', err);
371
- ctx.throw(500, 'Error deleting inactive sessions');
372
- }
373
- },
374
-
375
- /**
376
- * Toggle user blocked status
377
- * POST /magic-sessionmanager/user/:userId/toggle-block
378
- * Supports both numeric id (from Content Manager) and documentId
379
- */
380
- async toggleUserBlock(ctx) {
381
- try {
382
- const { userId } = ctx.params;
383
-
384
- // Strapi v5: userId from params could be numeric id or documentId
385
- // If numeric, look up the documentId first using entityService (fallback)
386
- let userDocumentId = userId;
387
- let user = null;
388
-
389
- // Try to find by documentId first (preferred)
390
- user = await strapi.documents(USER_UID).findOne({ documentId: userId });
391
-
392
- // If not found, try numeric id lookup via entityService (fallback for Content Manager)
393
- if (!user && !isNaN(userId)) {
394
- const numericUser = await strapi.entityService.findOne(USER_UID, parseInt(userId, 10));
395
- if (numericUser) {
396
- userDocumentId = numericUser.documentId;
397
- user = numericUser;
398
- }
399
- }
400
-
401
- if (!user) {
402
- return ctx.throw(404, 'User not found');
403
- }
404
-
405
- // Toggle blocked status
406
- const newBlockedStatus = !user.blocked;
407
-
408
- await strapi.documents(USER_UID).update({
409
- documentId: userDocumentId,
410
- data: {
411
- blocked: newBlockedStatus,
412
- },
413
- });
414
-
415
- // If blocking user, terminate all their sessions
416
- if (newBlockedStatus) {
417
- const sessionService = strapi
418
- .plugin('magic-sessionmanager')
419
- .service('session');
420
- await sessionService.terminateSession({ userId: userDocumentId });
421
- }
422
-
423
- ctx.body = {
424
- message: `User ${newBlockedStatus ? 'blocked' : 'unblocked'} successfully`,
425
- blocked: newBlockedStatus,
426
- success: true,
427
- };
428
- } catch (err) {
429
- strapi.log.error('[magic-sessionmanager] Error toggling user block:', err);
430
- ctx.throw(500, 'Error toggling user block status');
431
- }
432
- },
433
- };