strapi-plugin-magic-mark 2.0.0 → 3.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.
- package/README.md +488 -209
- package/dist/_chunks/{App-CMSut1pt.js → App-C5UU0yUr.js} +2 -2
- package/dist/_chunks/{App-7ZH1Reka.mjs → App-Dt-v39BQ.mjs} +3 -3
- package/dist/_chunks/{index-DYHEyGJr.mjs → index-BAmZV8aX.mjs} +1 -1
- package/dist/_chunks/{index-DkkmdRgb.js → index-RuDV4dTy.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +265 -184
- package/dist/server/index.mjs +260 -179
- package/dist/server/src/content-types/index.d.ts +10 -0
- package/dist/server/src/controllers/controller.d.ts +38 -0
- package/dist/server/src/index.d.ts +20 -22
- package/dist/server/src/services/index.d.ts +10 -22
- package/dist/server/src/services/service.d.ts +67 -22
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import os from "os";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
3
5
|
const magicMarkActions = {
|
|
4
6
|
actions: [
|
|
5
7
|
{
|
|
@@ -32,7 +34,7 @@ const bootstrap = ({ strapi }) => {
|
|
|
32
34
|
const licenseStatus = await licenseGuardService2.initialize();
|
|
33
35
|
if (!licenseStatus.valid) {
|
|
34
36
|
strapi.log.error("╔════════════════════════════════════════════════════════════════╗");
|
|
35
|
-
strapi.log.error("║
|
|
37
|
+
strapi.log.error("║ [ERROR] MAGICMARK PLUGIN - NO VALID LICENSE ║");
|
|
36
38
|
strapi.log.error("║ ║");
|
|
37
39
|
strapi.log.error("║ This plugin requires a valid license to operate. ║");
|
|
38
40
|
strapi.log.error("║ Please activate your license via Admin UI: ║");
|
|
@@ -48,7 +50,7 @@ const bootstrap = ({ strapi }) => {
|
|
|
48
50
|
});
|
|
49
51
|
const storedKey = await pluginStore.get({ key: "licenseKey" });
|
|
50
52
|
strapi.log.info("╔════════════════════════════════════════════════════════════════╗");
|
|
51
|
-
strapi.log.info("║
|
|
53
|
+
strapi.log.info("║ [SUCCESS] MAGICMARK PLUGIN LICENSE ACTIVE ║");
|
|
52
54
|
strapi.log.info("║ ║");
|
|
53
55
|
if (licenseStatus.data) {
|
|
54
56
|
strapi.log.info(`║ License: ${licenseStatus.data.licenseKey} ║`);
|
|
@@ -59,12 +61,12 @@ const bootstrap = ({ strapi }) => {
|
|
|
59
61
|
strapi.log.info(`║ Status: Grace Period Active ║`);
|
|
60
62
|
}
|
|
61
63
|
strapi.log.info("║ ║");
|
|
62
|
-
strapi.log.info("║
|
|
64
|
+
strapi.log.info("║ [PING] Auto-pinging every 15 minutes ║");
|
|
63
65
|
strapi.log.info("╚════════════════════════════════════════════════════════════════╝");
|
|
64
66
|
}
|
|
65
67
|
}, 3e3);
|
|
66
68
|
} catch (error) {
|
|
67
|
-
strapi.log.error("
|
|
69
|
+
strapi.log.error("[ERROR] Error initializing License Guard:", error);
|
|
68
70
|
}
|
|
69
71
|
strapi.log.info("[Magic-Mark] Plugin bootstrapped successfully");
|
|
70
72
|
};
|
|
@@ -73,10 +75,10 @@ const destroy = ({ strapi }) => {
|
|
|
73
75
|
const licenseGuardService2 = strapi.plugin("magic-mark")?.service("license-guard");
|
|
74
76
|
if (licenseGuardService2) {
|
|
75
77
|
licenseGuardService2.cleanup();
|
|
76
|
-
strapi.log.info("
|
|
78
|
+
strapi.log.info("[SUCCESS] License Guard cleanup completed");
|
|
77
79
|
}
|
|
78
80
|
} catch (error) {
|
|
79
|
-
strapi.log.error("
|
|
81
|
+
strapi.log.error("[ERROR] Error during License Guard cleanup:", error);
|
|
80
82
|
}
|
|
81
83
|
};
|
|
82
84
|
const config = {
|
|
@@ -125,9 +127,9 @@ const contentTypes = {
|
|
|
125
127
|
},
|
|
126
128
|
emoji: {
|
|
127
129
|
type: "string",
|
|
128
|
-
default: "
|
|
130
|
+
default: "bookmark",
|
|
129
131
|
configurable: false,
|
|
130
|
-
maxLength:
|
|
132
|
+
maxLength: 50
|
|
131
133
|
},
|
|
132
134
|
isPinned: {
|
|
133
135
|
type: "boolean",
|
|
@@ -143,17 +145,30 @@ const contentTypes = {
|
|
|
143
145
|
type: "text",
|
|
144
146
|
configurable: false
|
|
145
147
|
},
|
|
146
|
-
//
|
|
148
|
+
// Creator's documentId (stored as string, not relation)
|
|
149
|
+
// We store documentId instead of relation to avoid admin::user permission issues
|
|
150
|
+
creatorId: {
|
|
151
|
+
type: "string",
|
|
152
|
+
configurable: false,
|
|
153
|
+
description: "documentId of the admin user who created this bookmark"
|
|
154
|
+
},
|
|
155
|
+
// Last updater's documentId
|
|
156
|
+
updaterId: {
|
|
157
|
+
type: "string",
|
|
158
|
+
configurable: false,
|
|
159
|
+
description: "documentId of the admin user who last updated this bookmark"
|
|
160
|
+
},
|
|
161
|
+
// Array of role documentIds that have access to this bookmark
|
|
147
162
|
sharedWithRoles: {
|
|
148
163
|
type: "json",
|
|
149
164
|
configurable: false,
|
|
150
|
-
description: "Array of role
|
|
165
|
+
description: "Array of role documentIds that have access to this bookmark"
|
|
151
166
|
},
|
|
152
|
-
// Array of user
|
|
167
|
+
// Array of user documentIds that have direct access to this bookmark
|
|
153
168
|
sharedWithUsers: {
|
|
154
169
|
type: "json",
|
|
155
170
|
configurable: false,
|
|
156
|
-
description: "Array of user
|
|
171
|
+
description: "Array of user documentIds that have direct access to this bookmark"
|
|
157
172
|
},
|
|
158
173
|
// Whether this bookmark is public to all admin users
|
|
159
174
|
isPublic: {
|
|
@@ -166,14 +181,21 @@ const contentTypes = {
|
|
|
166
181
|
}
|
|
167
182
|
}
|
|
168
183
|
};
|
|
184
|
+
const ADMIN_ROLE_UID = "admin::role";
|
|
185
|
+
const ADMIN_USER_UID$1 = "admin::user";
|
|
169
186
|
const bookmarkController = ({ strapi }) => ({
|
|
187
|
+
/**
|
|
188
|
+
* Get all bookmarks for current user
|
|
189
|
+
* GET /magic-mark/bookmarks
|
|
190
|
+
*/
|
|
170
191
|
async getAll(ctx) {
|
|
171
192
|
try {
|
|
172
193
|
const user = ctx.state.user;
|
|
173
194
|
if (!user) {
|
|
174
195
|
return ctx.throw(401, "User not authenticated");
|
|
175
196
|
}
|
|
176
|
-
const
|
|
197
|
+
const userId = user.documentId || String(user.id);
|
|
198
|
+
const bookmarks = await strapi.plugin("magic-mark").service("bookmarks").findAll(userId);
|
|
177
199
|
ctx.body = {
|
|
178
200
|
data: bookmarks,
|
|
179
201
|
meta: {
|
|
@@ -184,6 +206,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
184
206
|
ctx.throw(500, `Error fetching bookmarks: ${error}`);
|
|
185
207
|
}
|
|
186
208
|
},
|
|
209
|
+
/**
|
|
210
|
+
* Create a new bookmark
|
|
211
|
+
* POST /magic-mark/bookmarks
|
|
212
|
+
*/
|
|
187
213
|
async create(ctx) {
|
|
188
214
|
try {
|
|
189
215
|
const user = ctx.state.user;
|
|
@@ -197,8 +223,9 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
197
223
|
if (!path || path.trim().length === 0) {
|
|
198
224
|
return ctx.throw(400, "Path is required");
|
|
199
225
|
}
|
|
226
|
+
const userId = user.documentId || String(user.id);
|
|
200
227
|
const service = strapi.plugin("magic-mark").service("bookmarks");
|
|
201
|
-
const bookmark = await service.create(name, path, query, emoji, description,
|
|
228
|
+
const bookmark = await service.create(name, path, query, emoji, description, userId, sharedWithRoles, sharedWithUsers, isPublic);
|
|
202
229
|
ctx.body = {
|
|
203
230
|
data: bookmark
|
|
204
231
|
};
|
|
@@ -206,6 +233,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
206
233
|
ctx.throw(500, `Error creating bookmark: ${error}`);
|
|
207
234
|
}
|
|
208
235
|
},
|
|
236
|
+
/**
|
|
237
|
+
* Update an existing bookmark
|
|
238
|
+
* PUT /magic-mark/bookmarks/:id
|
|
239
|
+
*/
|
|
209
240
|
async update(ctx) {
|
|
210
241
|
try {
|
|
211
242
|
const user = ctx.state.user;
|
|
@@ -220,7 +251,8 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
220
251
|
if (!path || path.trim().length === 0) {
|
|
221
252
|
return ctx.throw(400, "Path is required");
|
|
222
253
|
}
|
|
223
|
-
const
|
|
254
|
+
const userId = user.documentId || String(user.id);
|
|
255
|
+
const bookmark = await strapi.plugin("magic-mark").service("bookmarks").update(id, { name, path, query, emoji, description, isPinned, order, sharedWithRoles, sharedWithUsers, isPublic }, userId);
|
|
224
256
|
ctx.body = {
|
|
225
257
|
data: bookmark
|
|
226
258
|
};
|
|
@@ -228,6 +260,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
228
260
|
ctx.throw(500, `Error updating bookmark: ${error}`);
|
|
229
261
|
}
|
|
230
262
|
},
|
|
263
|
+
/**
|
|
264
|
+
* Delete a bookmark
|
|
265
|
+
* DELETE /magic-mark/bookmarks/:id
|
|
266
|
+
*/
|
|
231
267
|
async delete(ctx) {
|
|
232
268
|
try {
|
|
233
269
|
const user = ctx.state.user;
|
|
@@ -243,6 +279,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
243
279
|
ctx.throw(500, `Error deleting bookmark: ${error}`);
|
|
244
280
|
}
|
|
245
281
|
},
|
|
282
|
+
/**
|
|
283
|
+
* Pin or unpin a bookmark
|
|
284
|
+
* PUT /magic-mark/bookmarks/:id/pin
|
|
285
|
+
*/
|
|
246
286
|
async pin(ctx) {
|
|
247
287
|
try {
|
|
248
288
|
const user = ctx.state.user;
|
|
@@ -251,7 +291,8 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
251
291
|
}
|
|
252
292
|
const { id } = ctx.params;
|
|
253
293
|
const { isPinned } = ctx.request.body;
|
|
254
|
-
const
|
|
294
|
+
const userId = user.documentId || String(user.id);
|
|
295
|
+
const bookmark = await strapi.plugin("magic-mark").service("bookmarks").pin(id, isPinned, userId);
|
|
255
296
|
ctx.body = {
|
|
256
297
|
data: bookmark
|
|
257
298
|
};
|
|
@@ -259,6 +300,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
259
300
|
ctx.throw(500, `Error pinning bookmark: ${error}`);
|
|
260
301
|
}
|
|
261
302
|
},
|
|
303
|
+
/**
|
|
304
|
+
* Reorder bookmarks
|
|
305
|
+
* PUT /magic-mark/bookmarks/reorder
|
|
306
|
+
*/
|
|
262
307
|
async reorder(ctx) {
|
|
263
308
|
try {
|
|
264
309
|
const user = ctx.state.user;
|
|
@@ -269,7 +314,8 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
269
314
|
if (!bookmarkIds || !Array.isArray(bookmarkIds)) {
|
|
270
315
|
return ctx.throw(400, "Bookmark IDs array is required");
|
|
271
316
|
}
|
|
272
|
-
const
|
|
317
|
+
const userId = user.documentId || String(user.id);
|
|
318
|
+
const bookmarks = await strapi.plugin("magic-mark").service("bookmarks").reorder(bookmarkIds, userId);
|
|
273
319
|
ctx.body = {
|
|
274
320
|
data: bookmarks
|
|
275
321
|
};
|
|
@@ -277,30 +323,28 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
277
323
|
ctx.throw(500, `Error reordering bookmarks: ${error}`);
|
|
278
324
|
}
|
|
279
325
|
},
|
|
326
|
+
/**
|
|
327
|
+
* Get all admin roles for sharing
|
|
328
|
+
* GET /magic-mark/roles
|
|
329
|
+
*/
|
|
280
330
|
async getRoles(ctx) {
|
|
281
331
|
try {
|
|
282
332
|
const user = ctx.state.user;
|
|
283
333
|
if (!user) {
|
|
284
334
|
return ctx.throw(401, "User not authenticated");
|
|
285
335
|
}
|
|
286
|
-
const roles = await strapi.
|
|
287
|
-
"
|
|
288
|
-
{
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
sort: { name: "asc" },
|
|
292
|
-
populate: ["users"]
|
|
293
|
-
// Also get user count for each role
|
|
294
|
-
}
|
|
295
|
-
);
|
|
336
|
+
const roles = await strapi.documents(ADMIN_ROLE_UID).findMany({
|
|
337
|
+
fields: ["name", "code", "description", "createdAt", "updatedAt"],
|
|
338
|
+
sort: { name: "asc" },
|
|
339
|
+
populate: ["users"]
|
|
340
|
+
});
|
|
296
341
|
const rolesWithDetails = roles?.map((role) => ({
|
|
297
|
-
id: role.
|
|
342
|
+
id: role.documentId,
|
|
298
343
|
name: role.name,
|
|
299
344
|
code: role.code,
|
|
300
345
|
description: role.description,
|
|
301
346
|
userCount: role.users?.length || 0,
|
|
302
347
|
isCustom: !["super_admin", "editor", "author"].includes(role.code)
|
|
303
|
-
// Mark custom roles
|
|
304
348
|
})) || [];
|
|
305
349
|
ctx.body = {
|
|
306
350
|
data: {
|
|
@@ -311,6 +355,10 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
311
355
|
ctx.throw(500, `Error fetching roles: ${error}`);
|
|
312
356
|
}
|
|
313
357
|
},
|
|
358
|
+
/**
|
|
359
|
+
* Get all admin users for sharing
|
|
360
|
+
* GET /magic-mark/users
|
|
361
|
+
*/
|
|
314
362
|
async getUsers(ctx) {
|
|
315
363
|
try {
|
|
316
364
|
const user = ctx.state.user;
|
|
@@ -332,37 +380,36 @@ const bookmarkController = ({ strapi }) => ({
|
|
|
332
380
|
users = await adminUserService.find();
|
|
333
381
|
}
|
|
334
382
|
} catch (err) {
|
|
335
|
-
|
|
383
|
+
strapi.log.debug("[magic-mark] Admin service not available, trying Document Service");
|
|
336
384
|
}
|
|
337
385
|
if (!users || users.length === 0) {
|
|
338
386
|
try {
|
|
339
|
-
users = await strapi.
|
|
387
|
+
users = await strapi.documents(ADMIN_USER_UID$1).findMany({
|
|
340
388
|
limit: 100
|
|
341
389
|
});
|
|
342
390
|
} catch (err) {
|
|
343
|
-
|
|
391
|
+
strapi.log.debug("[magic-mark] Document Service error for admin::user");
|
|
344
392
|
}
|
|
345
393
|
}
|
|
346
394
|
if (!users || users.length === 0) {
|
|
347
395
|
try {
|
|
348
|
-
users = await strapi.
|
|
396
|
+
users = await strapi.entityService.findMany(ADMIN_USER_UID$1, {
|
|
349
397
|
limit: 100
|
|
350
398
|
});
|
|
351
399
|
} catch (err) {
|
|
352
|
-
|
|
400
|
+
strapi.log.warn("[magic-mark] entityService fallback also failed");
|
|
353
401
|
}
|
|
354
402
|
}
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
})));
|
|
403
|
+
const currentUserId = user.documentId || String(user.id);
|
|
404
|
+
const filteredUsers = users.filter((u) => {
|
|
405
|
+
const uId = u.documentId || String(u.id);
|
|
406
|
+
return uId !== currentUserId;
|
|
407
|
+
});
|
|
408
|
+
strapi.log.debug(`[magic-mark] Total admin users found: ${users.length}`);
|
|
362
409
|
ctx.body = {
|
|
363
410
|
data: {
|
|
364
411
|
data: filteredUsers.map((u) => ({
|
|
365
|
-
id: u.id,
|
|
412
|
+
id: u.documentId || u.id,
|
|
366
413
|
firstname: u.firstname || "",
|
|
367
414
|
lastname: u.lastname || "",
|
|
368
415
|
email: u.email,
|
|
@@ -540,16 +587,16 @@ const license = ({ strapi }) => ({
|
|
|
540
587
|
const licenseGuard = strapi.plugin("magic-mark").service("license-guard");
|
|
541
588
|
const verification = await licenseGuard.verifyLicense(trimmedKey);
|
|
542
589
|
if (!verification.valid) {
|
|
543
|
-
strapi.log.warn(
|
|
590
|
+
strapi.log.warn(`[WARN] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
|
|
544
591
|
return ctx.badRequest("Invalid or expired license key");
|
|
545
592
|
}
|
|
546
593
|
const license2 = await licenseGuard.getLicenseByKey(trimmedKey);
|
|
547
594
|
if (!license2) {
|
|
548
|
-
strapi.log.warn(
|
|
595
|
+
strapi.log.warn(`[WARN] License not found in database: ${trimmedKey.substring(0, 8)}...`);
|
|
549
596
|
return ctx.badRequest("License not found");
|
|
550
597
|
}
|
|
551
598
|
if (license2.email.toLowerCase() !== trimmedEmail) {
|
|
552
|
-
strapi.log.warn(
|
|
599
|
+
strapi.log.warn(`[WARN] Email mismatch for license key: ${trimmedKey.substring(0, 8)}... (Attempted: ${trimmedEmail})`);
|
|
553
600
|
return ctx.badRequest("Email address does not match this license key");
|
|
554
601
|
}
|
|
555
602
|
await licenseGuard.storeLicenseKey(trimmedKey);
|
|
@@ -559,7 +606,7 @@ const license = ({ strapi }) => ({
|
|
|
559
606
|
pingInterval,
|
|
560
607
|
data: verification.data
|
|
561
608
|
};
|
|
562
|
-
strapi.log.info(
|
|
609
|
+
strapi.log.info(`[SUCCESS] Existing license key validated and stored: ${trimmedKey.substring(0, 8)}... (Email: ${trimmedEmail})`);
|
|
563
610
|
return ctx.send({
|
|
564
611
|
success: true,
|
|
565
612
|
message: "License key validated and activated successfully",
|
|
@@ -720,12 +767,12 @@ const licenseCheck$1 = (config2, { strapi }) => {
|
|
|
720
767
|
});
|
|
721
768
|
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
722
769
|
if (!licenseKey) {
|
|
723
|
-
strapi.log.warn("
|
|
770
|
+
strapi.log.warn("[WARN] MagicMark: No license key found");
|
|
724
771
|
return await next();
|
|
725
772
|
}
|
|
726
773
|
const verification = await licenseGuard.verifyLicense(licenseKey, true);
|
|
727
774
|
if (!verification.valid && !verification.gracePeriod) {
|
|
728
|
-
strapi.log.warn("
|
|
775
|
+
strapi.log.warn("[WARN] MagicMark: Invalid license detected");
|
|
729
776
|
}
|
|
730
777
|
return await next();
|
|
731
778
|
} catch (error) {
|
|
@@ -743,25 +790,25 @@ const licenseCheck = async (policyContext, config2, { strapi }) => {
|
|
|
743
790
|
const pluginStore = strapi.store({ type: "plugin", name: "magic-mark" });
|
|
744
791
|
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
745
792
|
if (!licenseKey) {
|
|
746
|
-
strapi.log.warn("
|
|
793
|
+
strapi.log.warn("[WARN] API access denied: No license key found");
|
|
747
794
|
return policyContext.unauthorized("No license found. Please activate the plugin first.");
|
|
748
795
|
}
|
|
749
796
|
const verification = await licenseGuard.verifyLicense(licenseKey);
|
|
750
797
|
if (!verification.valid) {
|
|
751
|
-
strapi.log.warn("
|
|
798
|
+
strapi.log.warn("[WARN] API access denied: Invalid license");
|
|
752
799
|
return policyContext.unauthorized("Invalid or expired license. Please check your license status.");
|
|
753
800
|
}
|
|
754
801
|
const license2 = await licenseGuard.getLicenseByKey(licenseKey);
|
|
755
802
|
if (!license2) {
|
|
756
|
-
strapi.log.warn("
|
|
803
|
+
strapi.log.warn("[WARN] API access denied: License not found in database");
|
|
757
804
|
return policyContext.unauthorized("License not found. Please contact support.");
|
|
758
805
|
}
|
|
759
806
|
if (!license2.isActive) {
|
|
760
|
-
strapi.log.warn("
|
|
807
|
+
strapi.log.warn("[WARN] API access denied: License is inactive");
|
|
761
808
|
return policyContext.unauthorized("License is inactive. Please activate your license.");
|
|
762
809
|
}
|
|
763
810
|
if (license2.isExpired) {
|
|
764
|
-
strapi.log.warn("
|
|
811
|
+
strapi.log.warn("[WARN] API access denied: License has expired");
|
|
765
812
|
return policyContext.unauthorized("License has expired. Please renew your license.");
|
|
766
813
|
}
|
|
767
814
|
return true;
|
|
@@ -773,29 +820,29 @@ const licenseCheck = async (policyContext, config2, { strapi }) => {
|
|
|
773
820
|
const policies = {
|
|
774
821
|
"license-check": licenseCheck
|
|
775
822
|
};
|
|
823
|
+
const BOOKMARK_UID = "plugin::magic-mark.bookmark";
|
|
824
|
+
const ADMIN_USER_UID = "admin::user";
|
|
776
825
|
const bookmarkService = ({ strapi }) => ({
|
|
826
|
+
/**
|
|
827
|
+
* Find all bookmarks accessible to a user
|
|
828
|
+
* @param userId - The admin user's documentId
|
|
829
|
+
* @returns Array of accessible bookmarks
|
|
830
|
+
*/
|
|
777
831
|
async findAll(userId) {
|
|
778
832
|
try {
|
|
779
|
-
const user = await strapi.
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
sort: [
|
|
791
|
-
{ isPinned: "desc" },
|
|
792
|
-
{ order: "asc" }
|
|
793
|
-
],
|
|
794
|
-
populate: ["createdBy"]
|
|
795
|
-
}
|
|
796
|
-
);
|
|
833
|
+
const user = await strapi.documents(ADMIN_USER_UID).findOne({
|
|
834
|
+
documentId: userId,
|
|
835
|
+
populate: ["roles"]
|
|
836
|
+
});
|
|
837
|
+
const userRoleIds = user?.roles?.map((role) => role.documentId || role.id) || [];
|
|
838
|
+
const allBookmarks = await strapi.documents(BOOKMARK_UID).findMany({
|
|
839
|
+
sort: [
|
|
840
|
+
{ isPinned: "desc" },
|
|
841
|
+
{ order: "asc" }
|
|
842
|
+
]
|
|
843
|
+
});
|
|
797
844
|
const accessibleBookmarks = allBookmarks?.filter((bookmark) => {
|
|
798
|
-
if (bookmark.
|
|
845
|
+
if (bookmark.creatorId === userId) {
|
|
799
846
|
return true;
|
|
800
847
|
}
|
|
801
848
|
if (bookmark.isPublic) {
|
|
@@ -819,119 +866,140 @@ const bookmarkService = ({ strapi }) => ({
|
|
|
819
866
|
throw error;
|
|
820
867
|
}
|
|
821
868
|
},
|
|
869
|
+
/**
|
|
870
|
+
* Create a new bookmark
|
|
871
|
+
* @param name - Bookmark name
|
|
872
|
+
* @param path - URL path
|
|
873
|
+
* @param query - Query string
|
|
874
|
+
* @param emoji - Emoji icon
|
|
875
|
+
* @param description - Description
|
|
876
|
+
* @param userId - Creator's documentId
|
|
877
|
+
* @param sharedWithRoles - Array of role documentIds
|
|
878
|
+
* @param sharedWithUsers - Array of user documentIds
|
|
879
|
+
* @param isPublic - Public visibility
|
|
880
|
+
* @returns Created bookmark
|
|
881
|
+
*/
|
|
822
882
|
async create(name, path, query, emoji, description, userId, sharedWithRoles, sharedWithUsers, isPublic) {
|
|
823
883
|
try {
|
|
824
|
-
const bookmarks = await strapi.
|
|
825
|
-
"
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
limit: 1
|
|
829
|
-
}
|
|
830
|
-
);
|
|
884
|
+
const bookmarks = await strapi.documents(BOOKMARK_UID).findMany({
|
|
885
|
+
sort: [{ order: "desc" }],
|
|
886
|
+
limit: 1
|
|
887
|
+
});
|
|
831
888
|
const maxOrder = bookmarks && bookmarks.length > 0 ? bookmarks[0].order : 0;
|
|
832
|
-
const bookmark = await strapi.
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}
|
|
889
|
+
const bookmark = await strapi.documents(BOOKMARK_UID).create({
|
|
890
|
+
data: {
|
|
891
|
+
name,
|
|
892
|
+
path,
|
|
893
|
+
query: query || "",
|
|
894
|
+
emoji: emoji || "bookmark",
|
|
895
|
+
description,
|
|
896
|
+
isPinned: false,
|
|
897
|
+
order: (maxOrder || 0) + 1,
|
|
898
|
+
creatorId: userId,
|
|
899
|
+
// Store as string field, not relation
|
|
900
|
+
updaterId: userId,
|
|
901
|
+
sharedWithRoles: sharedWithRoles || [],
|
|
902
|
+
sharedWithUsers: sharedWithUsers || [],
|
|
903
|
+
isPublic: isPublic || false
|
|
848
904
|
}
|
|
849
|
-
);
|
|
905
|
+
});
|
|
850
906
|
return bookmark;
|
|
851
907
|
} catch (error) {
|
|
852
908
|
strapi.log.error("[magic-mark] Error creating bookmark:", error);
|
|
853
909
|
throw error;
|
|
854
910
|
}
|
|
855
911
|
},
|
|
856
|
-
|
|
912
|
+
/**
|
|
913
|
+
* Update an existing bookmark
|
|
914
|
+
* @param documentId - Bookmark's documentId
|
|
915
|
+
* @param data - Update data
|
|
916
|
+
* @param userId - Editor's documentId
|
|
917
|
+
* @returns Updated bookmark
|
|
918
|
+
*/
|
|
919
|
+
async update(documentId, data, userId) {
|
|
857
920
|
try {
|
|
858
|
-
const existingBookmark = await strapi.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
populate: ["createdBy"]
|
|
863
|
-
}
|
|
864
|
-
);
|
|
865
|
-
if (!existingBookmark || existingBookmark.createdBy?.id !== userId) {
|
|
921
|
+
const existingBookmark = await strapi.documents(BOOKMARK_UID).findOne({
|
|
922
|
+
documentId
|
|
923
|
+
});
|
|
924
|
+
if (!existingBookmark || existingBookmark.creatorId !== userId) {
|
|
866
925
|
throw new Error("Unauthorized: You can only edit your own bookmarks");
|
|
867
926
|
}
|
|
868
|
-
const bookmark = await strapi.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
updatedBy: userId
|
|
884
|
-
}
|
|
927
|
+
const bookmark = await strapi.documents(BOOKMARK_UID).update({
|
|
928
|
+
documentId,
|
|
929
|
+
data: {
|
|
930
|
+
name: data.name,
|
|
931
|
+
path: data.path,
|
|
932
|
+
query: data.query || "",
|
|
933
|
+
emoji: data.emoji || "bookmark",
|
|
934
|
+
description: data.description,
|
|
935
|
+
isPinned: data.isPinned,
|
|
936
|
+
order: data.order,
|
|
937
|
+
sharedWithRoles: data.sharedWithRoles,
|
|
938
|
+
sharedWithUsers: data.sharedWithUsers,
|
|
939
|
+
isPublic: data.isPublic,
|
|
940
|
+
updaterId: userId
|
|
941
|
+
// Store as string field
|
|
885
942
|
}
|
|
886
|
-
);
|
|
943
|
+
});
|
|
887
944
|
return bookmark;
|
|
888
945
|
} catch (error) {
|
|
889
946
|
strapi.log.error("[magic-mark] Error updating bookmark:", error);
|
|
890
947
|
throw error;
|
|
891
948
|
}
|
|
892
949
|
},
|
|
893
|
-
|
|
950
|
+
/**
|
|
951
|
+
* Delete a bookmark
|
|
952
|
+
* @param documentId - Bookmark's documentId
|
|
953
|
+
* @returns Deleted bookmark
|
|
954
|
+
*/
|
|
955
|
+
async delete(documentId) {
|
|
894
956
|
try {
|
|
895
|
-
return await strapi.
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
);
|
|
957
|
+
return await strapi.documents(BOOKMARK_UID).delete({
|
|
958
|
+
documentId
|
|
959
|
+
});
|
|
899
960
|
} catch (error) {
|
|
900
961
|
strapi.log.error("[magic-mark] Error deleting bookmark:", error);
|
|
901
962
|
throw error;
|
|
902
963
|
}
|
|
903
964
|
},
|
|
904
|
-
|
|
965
|
+
/**
|
|
966
|
+
* Pin or unpin a bookmark
|
|
967
|
+
* @param documentId - Bookmark's documentId
|
|
968
|
+
* @param isPinned - Pin status
|
|
969
|
+
* @param userId - Editor's documentId
|
|
970
|
+
* @returns Updated bookmark
|
|
971
|
+
*/
|
|
972
|
+
async pin(documentId, isPinned, userId) {
|
|
905
973
|
try {
|
|
906
|
-
const bookmark = await strapi.
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
isPinned,
|
|
912
|
-
updatedBy: userId
|
|
913
|
-
}
|
|
974
|
+
const bookmark = await strapi.documents(BOOKMARK_UID).update({
|
|
975
|
+
documentId,
|
|
976
|
+
data: {
|
|
977
|
+
isPinned,
|
|
978
|
+
updaterId: userId
|
|
914
979
|
}
|
|
915
|
-
);
|
|
980
|
+
});
|
|
916
981
|
return bookmark;
|
|
917
982
|
} catch (error) {
|
|
918
983
|
strapi.log.error("[magic-mark] Error pinning bookmark:", error);
|
|
919
984
|
throw error;
|
|
920
985
|
}
|
|
921
986
|
},
|
|
987
|
+
/**
|
|
988
|
+
* Reorder bookmarks
|
|
989
|
+
* @param bookmarkIds - Array of bookmark documentIds in new order
|
|
990
|
+
* @param userId - Editor's documentId
|
|
991
|
+
* @returns Updated bookmarks
|
|
992
|
+
*/
|
|
922
993
|
async reorder(bookmarkIds, userId) {
|
|
923
994
|
try {
|
|
924
995
|
const updates = bookmarkIds.map(
|
|
925
|
-
(
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
order: index2,
|
|
931
|
-
updatedBy: userId
|
|
932
|
-
}
|
|
996
|
+
(documentId, index2) => strapi.documents(BOOKMARK_UID).update({
|
|
997
|
+
documentId,
|
|
998
|
+
data: {
|
|
999
|
+
order: index2,
|
|
1000
|
+
updaterId: userId
|
|
933
1001
|
}
|
|
934
|
-
)
|
|
1002
|
+
})
|
|
935
1003
|
);
|
|
936
1004
|
return Promise.all(updates);
|
|
937
1005
|
} catch (error) {
|
|
@@ -939,6 +1007,11 @@ const bookmarkService = ({ strapi }) => ({
|
|
|
939
1007
|
throw error;
|
|
940
1008
|
}
|
|
941
1009
|
},
|
|
1010
|
+
/**
|
|
1011
|
+
* Validate URL format
|
|
1012
|
+
* @param url - URL to validate
|
|
1013
|
+
* @returns True if valid
|
|
1014
|
+
*/
|
|
942
1015
|
validateUrl(url) {
|
|
943
1016
|
try {
|
|
944
1017
|
new URL(url);
|
|
@@ -948,6 +1021,13 @@ const bookmarkService = ({ strapi }) => ({
|
|
|
948
1021
|
}
|
|
949
1022
|
}
|
|
950
1023
|
});
|
|
1024
|
+
let pluginVersion = "2.0.0";
|
|
1025
|
+
try {
|
|
1026
|
+
const pkgPath = join(__dirname, "../../../package.json");
|
|
1027
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1028
|
+
pluginVersion = pkg.version || "2.0.0";
|
|
1029
|
+
} catch (e) {
|
|
1030
|
+
}
|
|
951
1031
|
const LICENSE_SERVER_URL = "https://magicapi.fitlex.me";
|
|
952
1032
|
const licenseGuardService = ({ strapi }) => ({
|
|
953
1033
|
/**
|
|
@@ -1013,7 +1093,8 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1013
1093
|
* Get user agent (server context)
|
|
1014
1094
|
*/
|
|
1015
1095
|
getUserAgent() {
|
|
1016
|
-
|
|
1096
|
+
const strapiVersion = strapi.config.get("info.strapi") || "5.0.0";
|
|
1097
|
+
return `MagicMark/${pluginVersion} Strapi/${strapiVersion} Node/${process.version} ${os.platform()}/${os.release()}`;
|
|
1017
1098
|
},
|
|
1018
1099
|
/**
|
|
1019
1100
|
* Create a license
|
|
@@ -1044,14 +1125,14 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1044
1125
|
});
|
|
1045
1126
|
const data = await response.json();
|
|
1046
1127
|
if (data.success) {
|
|
1047
|
-
strapi.log.info("
|
|
1128
|
+
strapi.log.info("[SUCCESS] License created successfully:", data.data.licenseKey);
|
|
1048
1129
|
return data.data;
|
|
1049
1130
|
} else {
|
|
1050
|
-
strapi.log.error("
|
|
1131
|
+
strapi.log.error("[ERROR] License creation failed:", data);
|
|
1051
1132
|
return null;
|
|
1052
1133
|
}
|
|
1053
1134
|
} catch (error) {
|
|
1054
|
-
strapi.log.error("
|
|
1135
|
+
strapi.log.error("[ERROR] Error creating license:", error);
|
|
1055
1136
|
return null;
|
|
1056
1137
|
}
|
|
1057
1138
|
},
|
|
@@ -1080,7 +1161,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1080
1161
|
if (data.success) {
|
|
1081
1162
|
const isValid = data.data.isActive && !data.data.isExpired;
|
|
1082
1163
|
const statusInfo = data.data.isExpired ? "EXPIRED" : data.data.isActive ? "ACTIVE" : "INACTIVE";
|
|
1083
|
-
strapi.log.info(
|
|
1164
|
+
strapi.log.info(`[SUCCESS] License verified online: ${statusInfo} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1084
1165
|
if (isValid) {
|
|
1085
1166
|
const pluginStore = strapi.store({
|
|
1086
1167
|
type: "plugin",
|
|
@@ -1093,16 +1174,16 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1093
1174
|
data: data.data
|
|
1094
1175
|
};
|
|
1095
1176
|
} else {
|
|
1096
|
-
strapi.log.warn(
|
|
1177
|
+
strapi.log.warn(`[WARN] License verification failed: ${data.message || "Unknown error"} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1097
1178
|
return { valid: false, data: null };
|
|
1098
1179
|
}
|
|
1099
1180
|
} catch (error) {
|
|
1100
1181
|
if (allowGracePeriod) {
|
|
1101
|
-
strapi.log.warn(
|
|
1102
|
-
strapi.log.info(
|
|
1182
|
+
strapi.log.warn(`[WARN] Cannot verify license online: ${error.message} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1183
|
+
strapi.log.info(`[GRACE] Grace period active - accepting stored license key`);
|
|
1103
1184
|
return { valid: true, data: null, gracePeriod: true };
|
|
1104
1185
|
}
|
|
1105
|
-
strapi.log.error(
|
|
1186
|
+
strapi.log.error(`[ERROR] Error verifying license: ${error.message} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1106
1187
|
return { valid: false, data: null };
|
|
1107
1188
|
}
|
|
1108
1189
|
},
|
|
@@ -1125,10 +1206,10 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1125
1206
|
});
|
|
1126
1207
|
const data = await response.json();
|
|
1127
1208
|
if (data.success) {
|
|
1128
|
-
strapi.log.debug(
|
|
1209
|
+
strapi.log.debug(`[PING] License ping successful: ${data.data?.isActive ? "ACTIVE" : "INACTIVE"} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1129
1210
|
return data.data;
|
|
1130
1211
|
} else {
|
|
1131
|
-
strapi.log.debug(
|
|
1212
|
+
strapi.log.debug(`[WARN] License ping failed: ${data.message || "Unknown error"} (Key: ${licenseKey?.substring(0, 8)}...)`);
|
|
1132
1213
|
return null;
|
|
1133
1214
|
}
|
|
1134
1215
|
} catch (error) {
|
|
@@ -1149,7 +1230,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1149
1230
|
}
|
|
1150
1231
|
return null;
|
|
1151
1232
|
} catch (error) {
|
|
1152
|
-
strapi.log.error("
|
|
1233
|
+
strapi.log.error("[ERROR] Error fetching license by key:", error);
|
|
1153
1234
|
return null;
|
|
1154
1235
|
}
|
|
1155
1236
|
},
|
|
@@ -1166,7 +1247,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1166
1247
|
}
|
|
1167
1248
|
return null;
|
|
1168
1249
|
} catch (error) {
|
|
1169
|
-
strapi.log.error("
|
|
1250
|
+
strapi.log.error("[ERROR] Error fetching online stats:", error);
|
|
1170
1251
|
return null;
|
|
1171
1252
|
}
|
|
1172
1253
|
},
|
|
@@ -1179,7 +1260,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1179
1260
|
const pingInterval = setInterval(async () => {
|
|
1180
1261
|
await this.pingLicense(licenseKey);
|
|
1181
1262
|
}, intervalMs);
|
|
1182
|
-
strapi.log.info(
|
|
1263
|
+
strapi.log.info(`[PING] Started pinging license every ${intervalMinutes} minutes`);
|
|
1183
1264
|
return pingInterval;
|
|
1184
1265
|
},
|
|
1185
1266
|
/**
|
|
@@ -1188,7 +1269,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1188
1269
|
*/
|
|
1189
1270
|
async initialize() {
|
|
1190
1271
|
try {
|
|
1191
|
-
strapi.log.info("
|
|
1272
|
+
strapi.log.info("[LICENSE] Initializing License Guard...");
|
|
1192
1273
|
const pluginStore = strapi.store({
|
|
1193
1274
|
type: "plugin",
|
|
1194
1275
|
name: "magic-mark"
|
|
@@ -1204,29 +1285,29 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1204
1285
|
withinGracePeriod = hoursSinceValidation < gracePeriodHours;
|
|
1205
1286
|
}
|
|
1206
1287
|
strapi.log.info("──────────────────────────────────────────────────────────");
|
|
1207
|
-
strapi.log.info(
|
|
1288
|
+
strapi.log.info(`[STORE] Plugin Store Check:`);
|
|
1208
1289
|
if (licenseKey) {
|
|
1209
|
-
strapi.log.info(`
|
|
1210
|
-
strapi.log.info(`
|
|
1290
|
+
strapi.log.info(` [OK] License Key found: ${licenseKey}`);
|
|
1291
|
+
strapi.log.info(` [KEY] Key (short): ${licenseKey.substring(0, 8)}...`);
|
|
1211
1292
|
if (lastValidated) {
|
|
1212
1293
|
const lastValidatedDate = new Date(lastValidated);
|
|
1213
1294
|
const hoursAgo = Math.floor((now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60));
|
|
1214
|
-
strapi.log.info(`
|
|
1295
|
+
strapi.log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
|
|
1215
1296
|
} else {
|
|
1216
|
-
strapi.log.info(`
|
|
1297
|
+
strapi.log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
|
|
1217
1298
|
}
|
|
1218
1299
|
} else {
|
|
1219
|
-
strapi.log.info(`
|
|
1300
|
+
strapi.log.info(` [NONE] No license key stored`);
|
|
1220
1301
|
}
|
|
1221
1302
|
strapi.log.info("──────────────────────────────────────────────────────────");
|
|
1222
1303
|
if (licenseKey) {
|
|
1223
|
-
strapi.log.info("
|
|
1304
|
+
strapi.log.info("[VERIFY] Verifying stored license key...");
|
|
1224
1305
|
const verification = await this.verifyLicense(licenseKey, true);
|
|
1225
1306
|
if (verification.valid) {
|
|
1226
1307
|
if (verification.gracePeriod) {
|
|
1227
|
-
strapi.log.info("
|
|
1308
|
+
strapi.log.info("[SUCCESS] License accepted (offline mode / grace period)");
|
|
1228
1309
|
} else {
|
|
1229
|
-
strapi.log.info("
|
|
1310
|
+
strapi.log.info("[SUCCESS] License is valid and active");
|
|
1230
1311
|
}
|
|
1231
1312
|
const pingInterval = this.startPinging(licenseKey, 15);
|
|
1232
1313
|
strapi.licenseGuard = {
|
|
@@ -1236,17 +1317,17 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1236
1317
|
};
|
|
1237
1318
|
return { valid: true, data: verification.data };
|
|
1238
1319
|
} else {
|
|
1239
|
-
strapi.log.warn("
|
|
1320
|
+
strapi.log.warn("[WARN] Stored license is invalid or expired");
|
|
1240
1321
|
if (!withinGracePeriod) {
|
|
1241
1322
|
await pluginStore.delete({ key: "licenseKey" });
|
|
1242
1323
|
await pluginStore.delete({ key: "lastValidated" });
|
|
1243
1324
|
}
|
|
1244
1325
|
}
|
|
1245
1326
|
}
|
|
1246
|
-
strapi.log.warn("
|
|
1327
|
+
strapi.log.warn("[WARN] No valid license found. Plugin will run with limited functionality.");
|
|
1247
1328
|
return { valid: false, demo: true };
|
|
1248
1329
|
} catch (error) {
|
|
1249
|
-
strapi.log.error("
|
|
1330
|
+
strapi.log.error("[ERROR] Error initializing license guard:", error);
|
|
1250
1331
|
return { valid: false, error: error.message };
|
|
1251
1332
|
}
|
|
1252
1333
|
},
|
|
@@ -1255,7 +1336,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1255
1336
|
*/
|
|
1256
1337
|
async storeLicenseKey(licenseKey) {
|
|
1257
1338
|
try {
|
|
1258
|
-
strapi.log.info(
|
|
1339
|
+
strapi.log.info(`[STORE] Storing license key: ${licenseKey}`);
|
|
1259
1340
|
const pluginStore = strapi.store({
|
|
1260
1341
|
type: "plugin",
|
|
1261
1342
|
name: "magic-mark"
|
|
@@ -1264,14 +1345,14 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1264
1345
|
await pluginStore.set({ key: "lastValidated", value: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1265
1346
|
const stored = await pluginStore.get({ key: "licenseKey" });
|
|
1266
1347
|
if (stored === licenseKey) {
|
|
1267
|
-
strapi.log.info("
|
|
1348
|
+
strapi.log.info("[SUCCESS] License key stored and verified successfully");
|
|
1268
1349
|
return true;
|
|
1269
1350
|
} else {
|
|
1270
|
-
strapi.log.error("
|
|
1351
|
+
strapi.log.error("[ERROR] License key storage verification failed");
|
|
1271
1352
|
return false;
|
|
1272
1353
|
}
|
|
1273
1354
|
} catch (error) {
|
|
1274
|
-
strapi.log.error("
|
|
1355
|
+
strapi.log.error("[ERROR] Error storing license key:", error);
|
|
1275
1356
|
return false;
|
|
1276
1357
|
}
|
|
1277
1358
|
},
|
|
@@ -1282,7 +1363,7 @@ const licenseGuardService = ({ strapi }) => ({
|
|
|
1282
1363
|
const licenseGuard = strapi.licenseGuard;
|
|
1283
1364
|
if (licenseGuard && licenseGuard.pingInterval) {
|
|
1284
1365
|
clearInterval(licenseGuard.pingInterval);
|
|
1285
|
-
strapi.log.info("
|
|
1366
|
+
strapi.log.info("[STOP] License pinging stopped");
|
|
1286
1367
|
}
|
|
1287
1368
|
}
|
|
1288
1369
|
});
|