strapi-plugin-magic-link-v5 4.0.15 → 4.0.17
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/admin/src/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pluginPkg from '../../package.json';
|
|
2
2
|
import pluginId from './pluginId';
|
|
3
3
|
import { Initializer } from './components/Initializer';
|
|
4
|
-
import {
|
|
4
|
+
import { Faders, Key } from '@strapi/icons';
|
|
5
5
|
import pluginPermissions from './permissions';
|
|
6
6
|
import getTrad from './utils/getTrad';
|
|
7
7
|
|
|
@@ -11,10 +11,10 @@ export default {
|
|
|
11
11
|
register(app) {
|
|
12
12
|
app.addMenuLink({
|
|
13
13
|
to: `/plugins/${pluginId}`,
|
|
14
|
-
icon:
|
|
14
|
+
icon: Faders,
|
|
15
15
|
intlLabel: {
|
|
16
16
|
id: `${pluginId}.plugin.name`,
|
|
17
|
-
defaultMessage:
|
|
17
|
+
defaultMessage: 'Magic Link Dashboard',
|
|
18
18
|
},
|
|
19
19
|
Component: () => import('./pages/HomePage').then(module => ({
|
|
20
20
|
default: module.default
|
|
@@ -23,7 +23,7 @@ export default {
|
|
|
23
23
|
|
|
24
24
|
app.addMenuLink({
|
|
25
25
|
to: `/plugins/${pluginId}/tokens`,
|
|
26
|
-
icon:
|
|
26
|
+
icon: Key,
|
|
27
27
|
intlLabel: {
|
|
28
28
|
id: getTrad('tokens.title'),
|
|
29
29
|
defaultMessage: 'Magic Link Tokens',
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
Modal,
|
|
23
23
|
Field,
|
|
24
24
|
useField,
|
|
25
|
+
Grid,
|
|
25
26
|
} from '@strapi/design-system';
|
|
26
27
|
import { useFetchClient, useNotification, useFetchClient as useFetchClientHelper } from '@strapi/strapi/admin';
|
|
27
28
|
import {
|
|
@@ -178,19 +179,22 @@ const TokensPage = () => {
|
|
|
178
179
|
// Finde Benutzer anhand der E-Mail
|
|
179
180
|
const findUserByEmail = async (email) => {
|
|
180
181
|
try {
|
|
181
|
-
|
|
182
|
+
// Verwende die Plugin-eigene Route statt der geschützten API
|
|
183
|
+
const response = await get('/magic-link/validate-email', {
|
|
182
184
|
params: { email }
|
|
183
185
|
});
|
|
184
186
|
|
|
185
|
-
if (response && response.data) {
|
|
187
|
+
if (response && response.data && response.data.exists) {
|
|
186
188
|
return {
|
|
187
189
|
id: response.data.id,
|
|
188
|
-
documentId: response.data.documentId
|
|
190
|
+
documentId: response.data.documentId || response.data.id
|
|
189
191
|
};
|
|
190
192
|
}
|
|
191
193
|
return null;
|
|
192
194
|
} catch (error) {
|
|
193
|
-
console.error("Fehler beim
|
|
195
|
+
console.error("Fehler beim Validieren der E-Mail:", error);
|
|
196
|
+
// Nur Log-Ausgabe, kein Fehlerwerfen oder Benachrichtigung
|
|
197
|
+
// Toggle-Notification wird von der aufrufenden Funktion gehandhabt
|
|
194
198
|
return null;
|
|
195
199
|
}
|
|
196
200
|
};
|
|
@@ -235,27 +239,61 @@ const TokensPage = () => {
|
|
|
235
239
|
setEmailValidationStatus(null);
|
|
236
240
|
|
|
237
241
|
try {
|
|
238
|
-
// Prüfe
|
|
239
|
-
const
|
|
242
|
+
// Prüfe zuerst die Plugin-Einstellungen
|
|
243
|
+
const settingsResponse = await get('/magic-link/settings');
|
|
240
244
|
|
|
241
|
-
//
|
|
242
|
-
|
|
245
|
+
// Berücksichtige verschiedene Antwortstrukturen:
|
|
246
|
+
// 1. Direkte Einstellungen: settingsResponse.data
|
|
247
|
+
// 2. Verschachtelte Einstellungen: settingsResponse.data.settings
|
|
248
|
+
// 3. Zusätzliche Struktur: settingsResponse.data.data oder settingsResponse.data.data.settings
|
|
249
|
+
const rawSettings = settingsResponse.data || {};
|
|
250
|
+
let settings = { ...rawSettings };
|
|
251
|
+
|
|
252
|
+
// Entpacke verschachtelte Strukturen
|
|
253
|
+
if (settings.settings) settings = { ...settings, ...settings.settings };
|
|
254
|
+
if (settings.data) {
|
|
255
|
+
settings = { ...settings, ...settings.data };
|
|
256
|
+
if (settings.data.settings) settings = { ...settings, ...settings.data.settings };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Debug-Ausgaben
|
|
260
|
+
console.log('Rohe API-Antwort:', settingsResponse);
|
|
261
|
+
console.log('Verarbeitete Einstellungen:', settings);
|
|
262
|
+
console.log('createUserIfNotExists Wert:', settings.createUserIfNotExists);
|
|
263
|
+
console.log('Typ von createUserIfNotExists:', typeof settings.createUserIfNotExists);
|
|
264
|
+
|
|
265
|
+
// Prüfe auf mehrere Arten ob die Benutzererstelling aktiviert ist
|
|
266
|
+
// 1. Boolean-Wert direkt
|
|
267
|
+
// 2. String-Wert "true"
|
|
268
|
+
// 3. Objekt mit type="boolean" und value=true
|
|
269
|
+
const canCreateUser =
|
|
270
|
+
(typeof settings.createUserIfNotExists === 'boolean' && settings.createUserIfNotExists) ||
|
|
271
|
+
(typeof settings.createUserIfNotExists === 'string' && settings.createUserIfNotExists === 'true') ||
|
|
272
|
+
(settings.createUserIfNotExists?.type === 'boolean' && settings.createUserIfNotExists.value) ||
|
|
273
|
+
(typeof settings.create_new_user === 'boolean' && settings.create_new_user) ||
|
|
274
|
+
(typeof settings.create_new_user === 'string' && settings.create_new_user === 'true') ||
|
|
275
|
+
(settings.create_new_user?.type === 'boolean' && settings.create_new_user.value);
|
|
276
|
+
|
|
277
|
+
console.log('canCreateUser berechnet:', canCreateUser);
|
|
278
|
+
|
|
279
|
+
// Wenn automatische Benutzererstellung aktiviert ist, brauchen wir nicht zu prüfen,
|
|
280
|
+
// ob der Benutzer existiert - wir können immer einen Token erstellen
|
|
281
|
+
if (canCreateUser) {
|
|
243
282
|
setEmailValidationStatus({
|
|
244
283
|
valid: true,
|
|
245
|
-
message: '
|
|
284
|
+
message: 'Token kann erstellt werden. Benutzer wird bei Bedarf automatisch erstellt.'
|
|
246
285
|
});
|
|
247
286
|
return true;
|
|
248
287
|
}
|
|
249
|
-
|
|
250
|
-
// Wenn der Benutzer nicht existiert, müssen wir die Plugin-Einstellungen prüfen
|
|
251
|
-
const settingsResponse = await get('/magic-link/settings');
|
|
252
|
-
const settings = settingsResponse.data || {};
|
|
253
288
|
|
|
254
|
-
//
|
|
255
|
-
|
|
289
|
+
// Rest der Funktion bleibt gleich
|
|
290
|
+
const user = await findUserByEmail(email);
|
|
291
|
+
|
|
292
|
+
// Wenn der Benutzer existiert, ist alles in Ordnung
|
|
293
|
+
if (user) {
|
|
256
294
|
setEmailValidationStatus({
|
|
257
295
|
valid: true,
|
|
258
|
-
message: '
|
|
296
|
+
message: 'Benutzer gefunden. Token kann erstellt werden.'
|
|
259
297
|
});
|
|
260
298
|
return true;
|
|
261
299
|
} else {
|
|
@@ -634,6 +672,13 @@ const TokensPage = () => {
|
|
|
634
672
|
// Validiere zuerst die E-Mail
|
|
635
673
|
const isValid = await validateEmail(emailToCreate);
|
|
636
674
|
if (!isValid) {
|
|
675
|
+
// Zeige die Validierungsfehlermeldung, falls vorhanden
|
|
676
|
+
if (emailValidationStatus && emailValidationStatus.message) {
|
|
677
|
+
toggleNotification({
|
|
678
|
+
type: 'warning',
|
|
679
|
+
message: emailValidationStatus.message
|
|
680
|
+
});
|
|
681
|
+
}
|
|
637
682
|
return; // Beende die Funktion, wenn die E-Mail nicht gültig ist
|
|
638
683
|
}
|
|
639
684
|
|
|
@@ -675,9 +720,14 @@ const TokensPage = () => {
|
|
|
675
720
|
fetchTokens(); // Token-Liste aktualisieren
|
|
676
721
|
} catch (error) {
|
|
677
722
|
console.error('Fehler beim Erstellen des Tokens:', error);
|
|
723
|
+
// Zeige die spezifische Fehlermeldung vom Backend an
|
|
724
|
+
const errorMessage = error.response?.data?.error?.message ||
|
|
725
|
+
error.response?.data?.message ||
|
|
726
|
+
'Fehler beim Erstellen des Tokens';
|
|
678
727
|
toggleNotification({
|
|
679
728
|
type: 'danger',
|
|
680
|
-
message: error.response?.data?.message || 'Fehler beim Erstellen des Tokens',
|
|
729
|
+
// message: error.response?.data?.message || 'Fehler beim Erstellen des Tokens',
|
|
730
|
+
message: errorMessage,
|
|
681
731
|
});
|
|
682
732
|
} finally {
|
|
683
733
|
setIsCreating(false);
|
|
@@ -1900,7 +1950,7 @@ const TokensPage = () => {
|
|
|
1900
1950
|
value={emailToCreate}
|
|
1901
1951
|
required
|
|
1902
1952
|
aria-label="E-Mail-Adresse"
|
|
1903
|
-
error={emailValidationStatus && !emailValidationStatus.valid}
|
|
1953
|
+
error={emailValidationStatus && !emailValidationStatus.valid ? emailValidationStatus.message : undefined}
|
|
1904
1954
|
/>
|
|
1905
1955
|
{emailValidationStatus && emailValidationStatus.message && (
|
|
1906
1956
|
<Field.Hint>{emailValidationStatus.message}</Field.Hint>
|
|
@@ -1989,6 +2039,7 @@ const TokensPage = () => {
|
|
|
1989
2039
|
<Modal.Title>Token Details</Modal.Title>
|
|
1990
2040
|
</Modal.Header>
|
|
1991
2041
|
<Modal.Body>
|
|
2042
|
+
{/* Fallback auf Flex-Layout, da Grid Probleme verursacht */}
|
|
1992
2043
|
<Box background="neutral100" padding={4} hasRadius style={{ marginBottom: '24px' }}>
|
|
1993
2044
|
<Typography variant="beta" textColor="primary600" style={{ marginBottom: '12px' }}>
|
|
1994
2045
|
Allgemeine Informationen
|
|
@@ -2135,34 +2186,32 @@ const TokensPage = () => {
|
|
|
2135
2186
|
</Box>
|
|
2136
2187
|
)}
|
|
2137
2188
|
|
|
2138
|
-
{
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
</Typography>
|
|
2189
|
+
{selectedToken.context && Object.keys(selectedToken.context).length > 0 && (
|
|
2190
|
+
<Box background="neutral100" padding={4} hasRadius>
|
|
2191
|
+
<Typography variant="beta" textColor="primary600" style={{ marginBottom: '12px' }}>
|
|
2192
|
+
Context Daten
|
|
2193
|
+
</Typography>
|
|
2194
|
+
<Box padding={3} background="neutral0" hasRadius shadow="filterShadow">
|
|
2195
|
+
<Typography variant="delta" fontWeight="bold" textColor="neutral800">Context JSON</Typography>
|
|
2196
|
+
<Box
|
|
2197
|
+
background="neutral150"
|
|
2198
|
+
padding={3}
|
|
2199
|
+
hasRadius
|
|
2200
|
+
style={{
|
|
2201
|
+
wordBreak: 'break-all',
|
|
2202
|
+
maxHeight: '200px',
|
|
2203
|
+
overflow: 'auto'
|
|
2204
|
+
}}
|
|
2205
|
+
>
|
|
2206
|
+
<Typography variant="pi" fontFamily="monospace">
|
|
2207
|
+
{typeof selectedToken.context === 'object'
|
|
2208
|
+
? JSON.stringify(selectedToken.context, null, 2)
|
|
2209
|
+
: selectedToken.context
|
|
2210
|
+
}
|
|
2211
|
+
</Typography>
|
|
2212
|
+
</Box>
|
|
2163
2213
|
</Box>
|
|
2164
2214
|
</Box>
|
|
2165
|
-
</Box>
|
|
2166
2215
|
)}
|
|
2167
2216
|
</Modal.Body>
|
|
2168
2217
|
<Modal.Footer>
|
package/package.json
CHANGED
|
@@ -68,14 +68,17 @@ module.exports = {
|
|
|
68
68
|
const { body } = ctx.request;
|
|
69
69
|
|
|
70
70
|
try {
|
|
71
|
-
//
|
|
72
|
-
|
|
71
|
+
// Extrahiere die tatsächlichen Einstellungen, prüfe ob sie direkt im Body oder in body.settings liegen
|
|
72
|
+
let settingsToProcess = body.settings ? { ...body.settings } : { ...body };
|
|
73
73
|
|
|
74
|
-
// Entferne verschachtelte settings
|
|
75
|
-
if (
|
|
76
|
-
|
|
74
|
+
// Entferne vorsichtshalber nochmals verschachtelte settings
|
|
75
|
+
if (settingsToProcess.settings) {
|
|
76
|
+
delete settingsToProcess.settings;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// Stelle sicher, dass alle Boolean-Werte korrekt formatiert sind
|
|
80
|
+
const processedBody = { ...settingsToProcess };
|
|
81
|
+
|
|
79
82
|
// Verarbeite alle Eigenschaften, die als Boolean behandelt werden sollten
|
|
80
83
|
const booleanFields = [
|
|
81
84
|
'enabled', 'createUserIfNotExists', 'stays_valid', 'verify_email',
|
|
@@ -97,19 +97,40 @@ module.exports = {
|
|
|
97
97
|
|
|
98
98
|
const settings = await pluginStore.get({ key: 'settings' });
|
|
99
99
|
|
|
100
|
+
// --- DEBUG LOGGING START ---
|
|
101
|
+
strapi.log.info('[MagicLink Controller - create function] Loaded settings from store:', settings);
|
|
102
|
+
// --- DEBUG LOGGING END ---
|
|
103
|
+
|
|
100
104
|
// Find the user
|
|
101
105
|
let user = await strapi.db.query('plugin::users-permissions.user').findOne({
|
|
102
106
|
where: { email },
|
|
103
107
|
select: ['id', 'username', 'email'],
|
|
104
108
|
});
|
|
105
109
|
|
|
106
|
-
//
|
|
107
|
-
|
|
110
|
+
// --- DEBUG LOGGING START ---
|
|
111
|
+
strapi.log.info(`[MagicLink Controller - create function] Checking user existence for: ${email}`);
|
|
112
|
+
strapi.log.info(`[MagicLink Controller - create function] User found: ${!!user}`);
|
|
113
|
+
strapi.log.info(`[MagicLink Controller - create function] Value of createUserIfNotExists from settings: ${settings.createUserIfNotExists}`);
|
|
114
|
+
strapi.log.info(`[MagicLink Controller - create function] Value of create_new_user from settings: ${settings.create_new_user}`);
|
|
115
|
+
// --- DEBUG LOGGING END ---
|
|
116
|
+
|
|
117
|
+
// Verwende den richtigen Einstellungsnamen: createUserIfNotExists anstatt create_new_user
|
|
118
|
+
// Prüfe sowohl auf den neuen als auch auf den alten Namen für Abwärtskompatibilität
|
|
119
|
+
const canCreateUser = settings.createUserIfNotExists || settings.create_new_user;
|
|
120
|
+
|
|
121
|
+
// If user doesn't exist and automatic creation is not enabled, return error
|
|
122
|
+
if (!user && !canCreateUser) {
|
|
123
|
+
// --- DEBUG LOGGING START ---
|
|
124
|
+
strapi.log.warn(`[MagicLink Controller - create function] User does not exist AND canCreateUser is false. Returning Bad Request.`);
|
|
125
|
+
// --- DEBUG LOGGING END ---
|
|
108
126
|
return ctx.badRequest('User does not exist and automatic user creation is disabled');
|
|
109
127
|
}
|
|
110
128
|
|
|
111
129
|
// If user doesn't exist, create a new one
|
|
112
|
-
if (!user &&
|
|
130
|
+
if (!user && canCreateUser) {
|
|
131
|
+
// --- DEBUG LOGGING START ---
|
|
132
|
+
strapi.log.info(`[MagicLink Controller - create function] User does not exist BUT canCreateUser is true. Attempting to create user...`);
|
|
133
|
+
// --- DEBUG LOGGING END ---
|
|
113
134
|
// Generate a random username based on the email
|
|
114
135
|
const username = email.split('@')[0] + Math.floor(Math.random() * 10000);
|
|
115
136
|
|
|
@@ -426,22 +447,60 @@ module.exports = {
|
|
|
426
447
|
return ctx.badRequest('Email is required');
|
|
427
448
|
}
|
|
428
449
|
|
|
429
|
-
//
|
|
450
|
+
// Überprüfe, ob die Plugin-Einstellungen das Erstellen neuer Benutzer erlauben
|
|
451
|
+
const pluginStore = strapi.store({
|
|
452
|
+
environment: '',
|
|
453
|
+
type: 'plugin',
|
|
454
|
+
name: 'magic-link',
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
const settings = await pluginStore.get({ key: 'settings' });
|
|
458
|
+
|
|
459
|
+
// Find the user - Entferne UUID aus der Abfrage, damit es in Strapi v5 funktioniert
|
|
430
460
|
const user = await strapi.db.query('plugin::users-permissions.user').findOne({
|
|
431
461
|
where: { email },
|
|
432
|
-
select: ['id', 'username', 'email', 'confirmed', 'blocked', 'documentId'
|
|
462
|
+
select: ['id', 'username', 'email', 'confirmed', 'blocked', 'documentId'],
|
|
433
463
|
});
|
|
434
464
|
|
|
435
465
|
if (!user) {
|
|
436
|
-
|
|
466
|
+
// Mit createUserIfNotExists-Option kann die API weiterhin true zurückgeben
|
|
467
|
+
if (settings && settings.createUserIfNotExists) {
|
|
468
|
+
return {
|
|
469
|
+
exists: false,
|
|
470
|
+
canBeCreated: true,
|
|
471
|
+
autoCreationEnabled: true
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
exists: false,
|
|
477
|
+
canBeCreated: false,
|
|
478
|
+
autoCreationEnabled: false
|
|
479
|
+
};
|
|
437
480
|
}
|
|
438
481
|
|
|
439
|
-
|
|
482
|
+
// Sicheres Benutzerobjekt ohne sensible Daten
|
|
483
|
+
return {
|
|
484
|
+
id: user.id,
|
|
485
|
+
username: user.username,
|
|
486
|
+
email: user.email,
|
|
487
|
+
documentId: user.documentId || null,
|
|
488
|
+
exists: true
|
|
489
|
+
};
|
|
440
490
|
} catch (error) {
|
|
491
|
+
console.error("Error finding user by email:", error);
|
|
441
492
|
ctx.throw(500, error);
|
|
442
493
|
}
|
|
443
494
|
},
|
|
444
495
|
|
|
496
|
+
/**
|
|
497
|
+
* Validiert eine E-Mail (Alias für Frontend-Aufrufe)
|
|
498
|
+
* @param {Object} ctx - The request context
|
|
499
|
+
*/
|
|
500
|
+
async validateEmail(ctx) {
|
|
501
|
+
return this.findUserByEmail(ctx);
|
|
502
|
+
},
|
|
503
|
+
|
|
445
504
|
/**
|
|
446
505
|
* Ban an IP address
|
|
447
506
|
* @param {Object} ctx - The request context
|
|
@@ -589,7 +648,8 @@ module.exports = {
|
|
|
589
648
|
let configPoints = 0;
|
|
590
649
|
|
|
591
650
|
// Ist das Auto-Create-User Feature deaktiviert? (sicherer)
|
|
592
|
-
|
|
651
|
+
// Prüfe sowohl auf den neuen als auch auf den alten Namen für Abwärtskompatibilität
|
|
652
|
+
if (settings.createUserIfNotExists === false && settings.create_new_user === false) configPoints += 10;
|
|
593
653
|
|
|
594
654
|
// Ist das Email-Send Feature aktiviert? (sicherer)
|
|
595
655
|
if (settings.enabled === true) configPoints += 5;
|
|
@@ -62,16 +62,31 @@ module.exports = ({ strapi }) => ({
|
|
|
62
62
|
async user(email, username) {
|
|
63
63
|
const settings = await this.settings();
|
|
64
64
|
const createUserIfNotExists = settings.createUserIfNotExists;
|
|
65
|
+
|
|
66
|
+
// --- DEBUG LOGGING START ---
|
|
67
|
+
strapi.log.info(`[MagicLink Service - user function] Checking user: ${email || username}`);
|
|
68
|
+
strapi.log.info(`[MagicLink Service - user function] createUserIfNotExists setting value: ${createUserIfNotExists} (Type: ${typeof createUserIfNotExists})`);
|
|
69
|
+
// --- DEBUG LOGGING END ---
|
|
65
70
|
|
|
66
71
|
const user = await strapi.query('plugin::users-permissions.user').findOne({
|
|
67
72
|
where: email ? { email } : { username },
|
|
68
73
|
});
|
|
74
|
+
|
|
75
|
+
// --- DEBUG LOGGING START ---
|
|
76
|
+
strapi.log.info(`[MagicLink Service - user function] User found: ${!!user}`);
|
|
77
|
+
// --- DEBUG LOGGING END ---
|
|
69
78
|
|
|
70
79
|
if (!user && !createUserIfNotExists) {
|
|
71
|
-
|
|
80
|
+
// --- DEBUG LOGGING START ---
|
|
81
|
+
strapi.log.warn(`[MagicLink Service - user function] User not found AND createUserIfNotExists is false. Throwing error.`);
|
|
82
|
+
// --- DEBUG LOGGING END ---
|
|
83
|
+
throw new Error('User not found and auto-creation disabled.'); // Slightly more specific error
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
if (!user && createUserIfNotExists) {
|
|
87
|
+
// --- DEBUG LOGGING START ---
|
|
88
|
+
strapi.log.info(`[MagicLink Service - user function] User not found BUT createUserIfNotExists is true. Creating user...`);
|
|
89
|
+
// --- DEBUG LOGGING END ---
|
|
75
90
|
const newUser = await this.createUser({
|
|
76
91
|
email,
|
|
77
92
|
username: username || email.split('@')[0],
|