strapi-plugin-magic-link-v5 4.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/.eslintignore +1 -0
- package/.github/workflows/semantic-release.yml +27 -0
- package/README.md +318 -0
- package/admin/jsconfig.json +10 -0
- package/admin/src/components/Initializer/index.jsx +20 -0
- package/admin/src/components/Initializer.jsx +18 -0
- package/admin/src/components/LazyComponentLoader.jsx +27 -0
- package/admin/src/components/PluginIcon/index.jsx +6 -0
- package/admin/src/components/PluginIcon.jsx +5 -0
- package/admin/src/index.js +101 -0
- package/admin/src/pages/App/index.jsx +50 -0
- package/admin/src/pages/App.jsx +15 -0
- package/admin/src/pages/HomePage/index.js +2 -0
- package/admin/src/pages/HomePage/index.jsx +228 -0
- package/admin/src/pages/HomePage.jsx +655 -0
- package/admin/src/pages/Settings/index.jsx +1289 -0
- package/admin/src/pages/Settings/utils/api.js +13 -0
- package/admin/src/pages/Settings/utils/index.js +5 -0
- package/admin/src/pages/Settings/utils/layout.js +100 -0
- package/admin/src/pages/Settings/utils/schema.js +18 -0
- package/admin/src/pages/Tokens/index.jsx +2250 -0
- package/admin/src/permissions.js +7 -0
- package/admin/src/pluginId.js +3 -0
- package/admin/src/routes.js +40 -0
- package/admin/src/translations/de.json +188 -0
- package/admin/src/translations/en.json +189 -0
- package/admin/src/utils/getRequestURL.js +5 -0
- package/admin/src/utils/getTrad.js +17 -0
- package/admin/src/utils/getTranslation.js +3 -0
- package/admin/src/utils/index.js +4 -0
- package/build.js +75 -0
- package/package.json +59 -0
- package/server/bootstrap.js +127 -0
- package/server/controllers/settings.js +122 -0
- package/server/jsconfig.json +10 -0
- package/server/services/store.js +35 -0
- package/server/src/bootstrap.js +110 -0
- package/server/src/config/index.js +6 -0
- package/server/src/content-types/index.js +7 -0
- package/server/src/content-types/token/index.js +5 -0
- package/server/src/content-types/token/schema.json +47 -0
- package/server/src/controllers/auth.js +211 -0
- package/server/src/controllers/controller.js +213 -0
- package/server/src/controllers/index.js +16 -0
- package/server/src/controllers/jwt.js +261 -0
- package/server/src/controllers/tokens.js +654 -0
- package/server/src/destroy.js +5 -0
- package/server/src/index.js +33 -0
- package/server/src/middlewares/index.js +3 -0
- package/server/src/policies/index.js +3 -0
- package/server/src/register.js +5 -0
- package/server/src/routes/admin.js +160 -0
- package/server/src/routes/content-api.js +27 -0
- package/server/src/routes/index.js +9 -0
- package/server/src/services/index.js +11 -0
- package/server/src/services/magic-link.js +356 -0
- package/server/src/services/service.js +13 -0
- package/server/utils/index.js +14 -0
- package/strapi-admin.js +82 -0
- package/strapi-server.js +4 -0
- package/vite.config.js +36 -0
package/.eslintignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dist
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Semantic Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
packages: write
|
|
14
|
+
issues: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v3
|
|
17
|
+
- uses: actions/setup-node@v3
|
|
18
|
+
with:
|
|
19
|
+
node-version: 20
|
|
20
|
+
registry-url: https://registry.npmjs.org/
|
|
21
|
+
- run: yarn install
|
|
22
|
+
- run: yarn build
|
|
23
|
+
- run: yarn semantic-release
|
|
24
|
+
env:
|
|
25
|
+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
26
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
27
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Magic Link - Passwordless Authentication for Strapi
|
|
2
|
+
|
|
3
|
+
A secure passwordless authentication solution for Strapi, allowing users to log in via email links without requiring passwords.
|
|
4
|
+
|
|
5
|
+
## Core Features
|
|
6
|
+
|
|
7
|
+
- **Passwordless Authentication**: Login via secure email links
|
|
8
|
+
- **Token Management**: Admin dashboard for managing and monitoring tokens
|
|
9
|
+
- **JWT Session Tracking**: Monitor and manage active sessions
|
|
10
|
+
- **Security Features**: IP banning, token expiration controls
|
|
11
|
+
- **Admin Interface**: Statistics dashboard and configuration options
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Using npm
|
|
17
|
+
npm install magic-link
|
|
18
|
+
|
|
19
|
+
# Using yarn
|
|
20
|
+
yarn add magic-link
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
After installation, restart your Strapi server and the plugin will be available in the admin panel.
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
### Email User with Login Link
|
|
28
|
+
|
|
29
|
+
1. **Request Process**:
|
|
30
|
+
|
|
31
|
+
- User requests a login link by entering their email
|
|
32
|
+
- System generates a secure token and sends an email
|
|
33
|
+
- Email contains a magic link with the token
|
|
34
|
+
|
|
35
|
+
2. **Token Details**:
|
|
36
|
+
- Cryptographically secure random tokens
|
|
37
|
+
- Configurable expiration time
|
|
38
|
+
- Option for one-time use or reusable tokens
|
|
39
|
+
- Tracks IP address and user agent information
|
|
40
|
+
|
|
41
|
+
### Login with Token
|
|
42
|
+
|
|
43
|
+
1. **Authentication Process**:
|
|
44
|
+
|
|
45
|
+
- User clicks the link in their email
|
|
46
|
+
- System verifies the token is valid and not expired
|
|
47
|
+
- User is automatically authenticated
|
|
48
|
+
- JWT token is generated for the session
|
|
49
|
+
|
|
50
|
+
2. **Security Measures**:
|
|
51
|
+
- IP address validation (optional)
|
|
52
|
+
- Token expiration
|
|
53
|
+
- One-time use tokens (configurable)
|
|
54
|
+
- Automatic blocking after failed attempts
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Configure the plugin through **Settings > Magic Link** in the Strapi admin panel:
|
|
59
|
+
|
|
60
|
+
### General Settings
|
|
61
|
+
|
|
62
|
+
- **Enable Magic Link**: Turn the feature on/off
|
|
63
|
+
- **Create New Users**: Automatically create users if they don't exist
|
|
64
|
+
- **Token Stays Valid**: Configure one-time use or reusable tokens
|
|
65
|
+
- **Expiration Period**: Set how long tokens remain valid
|
|
66
|
+
- **Token Length**: Configure the security level of tokens
|
|
67
|
+
|
|
68
|
+
### Authentication Settings
|
|
69
|
+
|
|
70
|
+
- **Default Role**: Select which user role is assigned to new users
|
|
71
|
+
- **JWT Token Expiration**: Define how long JWT tokens remain valid (e.g., 30d, 24h)
|
|
72
|
+
- **Store Login Info**: Enable tracking of user agents and IP addresses
|
|
73
|
+
- **Remember Me**: Allow users to stay logged in for extended periods
|
|
74
|
+
|
|
75
|
+
### Email Settings
|
|
76
|
+
|
|
77
|
+
- **Sender Information**: Configure the email sender details (name, email)
|
|
78
|
+
- **Reply-To Address**: Set a reply-to email address for support inquiries
|
|
79
|
+
- **Email Subject**: Customize the subject line of the magic link emails
|
|
80
|
+
- **Email Templates**: Customize HTML and text templates
|
|
81
|
+
- **Email Designer Integration**: Use with Email Designer 5 if installed
|
|
82
|
+
|
|
83
|
+
## Dashboard & Admin Interface
|
|
84
|
+
|
|
85
|
+
Magic Link provides a comprehensive admin interface with several key sections:
|
|
86
|
+
|
|
87
|
+
### Dashboard Overview
|
|
88
|
+
|
|
89
|
+
- **Security Score**: Dynamic score (0-100) showing your current security configuration
|
|
90
|
+
- **Active Tokens**: Count and management of currently active tokens
|
|
91
|
+
- **Token Usage**: Metrics on token creation and usage patterns
|
|
92
|
+
- **Users Using Magic Link**: Number of unique users authenticating via magic links
|
|
93
|
+
- **Tokens About to Expire**: Warning system for tokens expiring soon
|
|
94
|
+
|
|
95
|
+
### Token Management
|
|
96
|
+
|
|
97
|
+
- **Token List View**: Sortable and filterable list of all tokens
|
|
98
|
+
- **Token Status Indicators**: Visual indicators showing token status (active, expired, used)
|
|
99
|
+
- **Token Details**: Inspect complete token information including:
|
|
100
|
+
- Creation and expiration dates
|
|
101
|
+
- IP address and user agent information
|
|
102
|
+
- Usage history and context data
|
|
103
|
+
- **Bulk Actions**: Select multiple tokens for batch operations
|
|
104
|
+
- **Search & Filter**: Find tokens by email, status, or creation date
|
|
105
|
+
- **Token Operations**:
|
|
106
|
+
- Block/deactivate tokens
|
|
107
|
+
- Extend token expiration
|
|
108
|
+
- Delete tokens
|
|
109
|
+
|
|
110
|
+
### JWT Session Management
|
|
111
|
+
|
|
112
|
+
- **Active Sessions**: Monitor all active JWT sessions across your application
|
|
113
|
+
- **Session Revocation**: Ability to revoke any active session immediately
|
|
114
|
+
- **Session Details**: View complete session information including:
|
|
115
|
+
- User details
|
|
116
|
+
- Creation and expiration time
|
|
117
|
+
- Last activity
|
|
118
|
+
- IP address and device information
|
|
119
|
+
|
|
120
|
+
### Security Features
|
|
121
|
+
|
|
122
|
+
- **IP Ban Management**: View and manage banned IP addresses
|
|
123
|
+
- **IP Ban Controls**: Ban suspicious IPs and view associated tokens
|
|
124
|
+
- **Security Audit**: Track login attempts and security events
|
|
125
|
+
- **System Status**: Monitor the health of the plugin and its dependencies
|
|
126
|
+
|
|
127
|
+
### Token Creation Interface
|
|
128
|
+
|
|
129
|
+
- **Manual Token Creation**: Generate tokens for specific users
|
|
130
|
+
- **Email Control**: Option to send or not send the email with the token
|
|
131
|
+
- **Context Injection**: Add custom JSON context data to tokens
|
|
132
|
+
- **Email Validation**: Verify email existence before token creation
|
|
133
|
+
|
|
134
|
+
## Admin Features
|
|
135
|
+
|
|
136
|
+
### Token Management
|
|
137
|
+
|
|
138
|
+
- View all active/inactive tokens
|
|
139
|
+
- Block or activate individual tokens
|
|
140
|
+
- Delete expired tokens
|
|
141
|
+
- See token usage statistics
|
|
142
|
+
|
|
143
|
+
### Security Dashboard
|
|
144
|
+
|
|
145
|
+
- Security score based on your configuration
|
|
146
|
+
- IP banning for suspicious activity
|
|
147
|
+
- JWT session monitoring and management
|
|
148
|
+
- Token expiration warnings
|
|
149
|
+
|
|
150
|
+
## API Endpoints
|
|
151
|
+
|
|
152
|
+
- `POST /api/magic-link/send` - Generate and send a magic link
|
|
153
|
+
- `GET /api/magic-link/login?loginToken=xxx` - Authenticate with token
|
|
154
|
+
- `GET /api/magic-link/tokens` - List tokens (admin only)
|
|
155
|
+
- `GET /api/magic-link/jwt-sessions` - List active sessions (admin only)
|
|
156
|
+
- `POST /api/magic-link/tokens/:id/block` - Block a specific token
|
|
157
|
+
- `POST /api/magic-link/ban-ip` - Ban an IP address
|
|
158
|
+
|
|
159
|
+
## Frontend Implementation
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Request a magic link
|
|
163
|
+
const requestLogin = async (email) => {
|
|
164
|
+
try {
|
|
165
|
+
await axios.post("/api/magic-link/send", { email });
|
|
166
|
+
// Show success message
|
|
167
|
+
} catch (error) {
|
|
168
|
+
// Handle error
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Verify token on the callback page
|
|
173
|
+
const verifyToken = async () => {
|
|
174
|
+
const token = new URLSearchParams(window.location.search).get("loginToken");
|
|
175
|
+
if (token) {
|
|
176
|
+
try {
|
|
177
|
+
const response = await axios.get(
|
|
178
|
+
`/api/magic-link/login?loginToken=${token}`
|
|
179
|
+
);
|
|
180
|
+
// Store JWT and redirect user
|
|
181
|
+
localStorage.setItem("token", response.data.jwt);
|
|
182
|
+
window.location.href = "/dashboard";
|
|
183
|
+
} catch (error) {
|
|
184
|
+
// Handle invalid token
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Context Data
|
|
191
|
+
|
|
192
|
+
You can include additional context when sending a magic link:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
await axios.post("/api/magic-link/send", {
|
|
196
|
+
email: "user@example.com",
|
|
197
|
+
context: {
|
|
198
|
+
redirectUrl: "/dashboard",
|
|
199
|
+
source: "registration",
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Security Best Practices
|
|
205
|
+
|
|
206
|
+
- Set reasonable token expiration times
|
|
207
|
+
- Use one-time tokens for sensitive operations
|
|
208
|
+
- Regularly monitor the security dashboard
|
|
209
|
+
- Ban suspicious IP addresses promptly
|
|
210
|
+
|
|
211
|
+
## Troubleshooting
|
|
212
|
+
|
|
213
|
+
| Issue | Solution |
|
|
214
|
+
| ---------------------- | ---------------------------------------------- |
|
|
215
|
+
| Emails not sending | Check your Strapi email provider configuration |
|
|
216
|
+
| Token validation fails | Verify token expiration settings |
|
|
217
|
+
| User not found errors | Check "Create New Users" setting |
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
[MIT](LICENSE)
|
|
222
|
+
|
|
223
|
+
## Development & Contributing
|
|
224
|
+
|
|
225
|
+
### Release Process
|
|
226
|
+
|
|
227
|
+
This project uses [semantic-release](https://github.com/semantic-release/semantic-release) to automate version management and package publishing.
|
|
228
|
+
|
|
229
|
+
To create a new release:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
npx semantic-release
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
This will automatically:
|
|
236
|
+
|
|
237
|
+
1. Analyze commit messages since the last release
|
|
238
|
+
2. Determine the appropriate version bump (major, minor, or patch)
|
|
239
|
+
3. Generate release notes
|
|
240
|
+
4. Update the version in package.json
|
|
241
|
+
5. Create a new Git tag
|
|
242
|
+
6. Publish the package to npm
|
|
243
|
+
|
|
244
|
+
### Commit Guidelines
|
|
245
|
+
|
|
246
|
+
To ensure semantic-release can properly determine the next version number, please follow these commit message conventions:
|
|
247
|
+
|
|
248
|
+
#### Commit Message Format
|
|
249
|
+
|
|
250
|
+
Each commit message consists of a **header**, an optional **body**, and an optional **footer**:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
<type>(<scope>): <subject>
|
|
254
|
+
<BLANK LINE>
|
|
255
|
+
<body>
|
|
256
|
+
<BLANK LINE>
|
|
257
|
+
<footer>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The **header** is mandatory and must conform to the following format:
|
|
261
|
+
|
|
262
|
+
- **type**: What type of change this commit is making. Must be one of:
|
|
263
|
+
|
|
264
|
+
- `feat`: A new feature (triggers a minor release)
|
|
265
|
+
- `fix`: A bug fix (triggers a patch release)
|
|
266
|
+
- `docs`: Documentation changes only
|
|
267
|
+
- `style`: Changes that don't affect code functionality (formatting, etc.)
|
|
268
|
+
- `refactor`: Code changes that neither fix a bug nor add a feature
|
|
269
|
+
- `perf`: Performance improvements
|
|
270
|
+
- `test`: Adding or updating tests
|
|
271
|
+
- `chore`: Changes to build process or auxiliary tools
|
|
272
|
+
- `ci`: Changes to CI configuration files and scripts
|
|
273
|
+
|
|
274
|
+
- **scope**: Optional, can be anything specifying the place of the commit change (e.g., `admin`, `api`, `auth`)
|
|
275
|
+
|
|
276
|
+
- **subject**: Brief description of the change
|
|
277
|
+
|
|
278
|
+
#### Breaking Changes
|
|
279
|
+
|
|
280
|
+
For breaking changes, add `BREAKING CHANGE:` in the footer of the commit message or append a `!` after the type/scope:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
feat(api)!: completely restructure API endpoints
|
|
284
|
+
|
|
285
|
+
BREAKING CHANGE: The API endpoints have been completely restructured.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
This will trigger a major version bump.
|
|
289
|
+
|
|
290
|
+
#### Examples
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
feat(auth): add support for multiple roles
|
|
294
|
+
|
|
295
|
+
fix(email): correct template rendering issue
|
|
296
|
+
|
|
297
|
+
docs: update API documentation
|
|
298
|
+
|
|
299
|
+
chore(deps): update dependencies
|
|
300
|
+
|
|
301
|
+
fix!: critical security vulnerability in token validation
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Branching Strategy
|
|
305
|
+
|
|
306
|
+
- `main`: Production-ready code
|
|
307
|
+
- `develop`: Integration branch for features
|
|
308
|
+
- `feature/*`: New features
|
|
309
|
+
- `fix/*`: Bug fixes
|
|
310
|
+
- `docs/*`: Documentation changes
|
|
311
|
+
|
|
312
|
+
When creating PRs, always merge feature branches into `develop` first. The `develop` branch is periodically merged into `main` for releases.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Support
|
|
317
|
+
|
|
318
|
+
If you encounter issues or have questions, please check the admin documentation or open an issue.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import pluginId from '../../pluginId';
|
|
4
|
+
|
|
5
|
+
const Initializer = ({ setPlugin }) => {
|
|
6
|
+
const ref = useRef();
|
|
7
|
+
ref.current = setPlugin;
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
ref.current(pluginId);
|
|
11
|
+
}, []);
|
|
12
|
+
|
|
13
|
+
return null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
Initializer.propTypes = {
|
|
17
|
+
setPlugin: PropTypes.func.isRequired,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default Initializer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PLUGIN_ID } from '../pluginId';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @type {import('react').FC<{ setPlugin: (id: string) => void }>}
|
|
7
|
+
*/
|
|
8
|
+
const Initializer = ({ setPlugin }) => {
|
|
9
|
+
const ref = useRef(setPlugin);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
ref.current(PLUGIN_ID);
|
|
13
|
+
}, []);
|
|
14
|
+
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { Initializer };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// This helper ensures the component module structure that Strapi v5 expects
|
|
4
|
+
// for lazy-loaded components
|
|
5
|
+
const LazyComponentLoader = (importComponent) => {
|
|
6
|
+
return React.lazy(() => {
|
|
7
|
+
return importComponent().then(module => {
|
|
8
|
+
// If the module has a default export, use it
|
|
9
|
+
if (module.default) {
|
|
10
|
+
return { default: module.default };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Otherwise, use the named export if available
|
|
14
|
+
const firstExport = Object.keys(module)[0];
|
|
15
|
+
if (firstExport && module[firstExport]) {
|
|
16
|
+
return { default: module[firstExport] };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If no suitable export is found, return a fallback component
|
|
20
|
+
return {
|
|
21
|
+
default: () => <div>Component loading error</div>
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default LazyComponentLoader;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { prefixPluginTranslations } from '@strapi/strapi/admin';
|
|
2
|
+
import pluginPkg from '../../package.json';
|
|
3
|
+
import pluginId from './pluginId';
|
|
4
|
+
import Initializer from './components/Initializer';
|
|
5
|
+
import PluginIcon from './components/PluginIcon';
|
|
6
|
+
import pluginPermissions from './permissions';
|
|
7
|
+
import getTrad from './utils/getTrad';
|
|
8
|
+
|
|
9
|
+
const name = pluginPkg.strapi.name;
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
register(app) {
|
|
13
|
+
app.addMenuLink({
|
|
14
|
+
to: `/plugins/${pluginId}`,
|
|
15
|
+
icon: PluginIcon,
|
|
16
|
+
intlLabel: {
|
|
17
|
+
id: `${pluginId}.plugin.name`,
|
|
18
|
+
defaultMessage: name,
|
|
19
|
+
},
|
|
20
|
+
Component: () => import('./pages/HomePage').then(module => ({
|
|
21
|
+
default: module.default
|
|
22
|
+
}))
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.addMenuLink({
|
|
26
|
+
to: `/plugins/${pluginId}/tokens`,
|
|
27
|
+
icon: PluginIcon,
|
|
28
|
+
intlLabel: {
|
|
29
|
+
id: getTrad('tokens.title'),
|
|
30
|
+
defaultMessage: 'Magic Link Tokens',
|
|
31
|
+
},
|
|
32
|
+
Component: () => import('./pages/Tokens').then(module => ({
|
|
33
|
+
default: module.default
|
|
34
|
+
}))
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
app.createSettingSection(
|
|
38
|
+
{
|
|
39
|
+
id: pluginId,
|
|
40
|
+
intlLabel: {
|
|
41
|
+
id: getTrad('Header.Settings'),
|
|
42
|
+
defaultMessage: 'Magic Link',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
[
|
|
46
|
+
{
|
|
47
|
+
intlLabel: {
|
|
48
|
+
id: getTrad('Form.title.Settings'),
|
|
49
|
+
defaultMessage: 'Settings',
|
|
50
|
+
},
|
|
51
|
+
id: 'magic-link-settings',
|
|
52
|
+
to: `/settings/${pluginId}`,
|
|
53
|
+
Component: () => import('./pages/Settings').then(module => ({
|
|
54
|
+
default: module.default
|
|
55
|
+
})),
|
|
56
|
+
permissions: pluginPermissions.readSettings,
|
|
57
|
+
},
|
|
58
|
+
]
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
app.registerPlugin({
|
|
62
|
+
id: pluginId,
|
|
63
|
+
initializer: Initializer,
|
|
64
|
+
isReady: false,
|
|
65
|
+
name,
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
bootstrap() {
|
|
70
|
+
// Nothing to do here
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
async registerTrads({ locales }) {
|
|
74
|
+
const importedTrads = await Promise.all(
|
|
75
|
+
locales.map(locale => {
|
|
76
|
+
try {
|
|
77
|
+
return import(`./translations/${locale}.json`)
|
|
78
|
+
.then(({ default: data }) => {
|
|
79
|
+
return {
|
|
80
|
+
data: prefixPluginTranslations(data, pluginId),
|
|
81
|
+
locale,
|
|
82
|
+
};
|
|
83
|
+
})
|
|
84
|
+
.catch(() => {
|
|
85
|
+
return {
|
|
86
|
+
data: {},
|
|
87
|
+
locale,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
data: {},
|
|
93
|
+
locale,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return Promise.resolve(importedTrads);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Main, Box, Typography } from '@strapi/design-system';
|
|
3
|
+
import pluginId from '../../pluginId';
|
|
4
|
+
import HomePage from '../HomePage';
|
|
5
|
+
import TokensPage from '../Tokens';
|
|
6
|
+
|
|
7
|
+
const App = () => {
|
|
8
|
+
console.log("Magic Link App-Root-Komponente wird geladen");
|
|
9
|
+
|
|
10
|
+
// Ermittle den aktuellen Pfad, um zu sehen, welche Route angezeigt werden soll
|
|
11
|
+
const currentPath = window.location.pathname;
|
|
12
|
+
console.log("Aktueller Pfad:", currentPath);
|
|
13
|
+
console.log("Plugin ID:", pluginId);
|
|
14
|
+
|
|
15
|
+
// Einfachere Bedingungen, die nur prüfen, ob der Pfad bestimmte Segmente enthält
|
|
16
|
+
const isTokensPage = currentPath.includes(`/plugins/${pluginId}/tokens`) ||
|
|
17
|
+
currentPath.includes(`/plugins/magic-link/tokens`);
|
|
18
|
+
const isHomePage = (currentPath.includes(`/plugins/${pluginId}`) ||
|
|
19
|
+
currentPath.includes(`/plugins/magic-link`)) && !isTokensPage;
|
|
20
|
+
|
|
21
|
+
console.log("isTokensPage:", isTokensPage);
|
|
22
|
+
console.log("isHomePage:", isHomePage);
|
|
23
|
+
|
|
24
|
+
let content;
|
|
25
|
+
if (isTokensPage) {
|
|
26
|
+
console.log("Zeige TokensPage an");
|
|
27
|
+
content = <TokensPage />;
|
|
28
|
+
} else if (isHomePage) {
|
|
29
|
+
console.log("Zeige HomePage an");
|
|
30
|
+
content = <HomePage />;
|
|
31
|
+
} else {
|
|
32
|
+
console.log("Zeige 404 Seite an");
|
|
33
|
+
content = (
|
|
34
|
+
<Box padding={8} background="neutral100">
|
|
35
|
+
<Typography variant="alpha">
|
|
36
|
+
404 - Route nicht gefunden: {currentPath}
|
|
37
|
+
</Typography>
|
|
38
|
+
</Box>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Main>
|
|
44
|
+
{content}
|
|
45
|
+
</Main>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { App };
|
|
50
|
+
export default App;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Page } from '@strapi/strapi/admin';
|
|
2
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import { HomePage } from './HomePage';
|
|
5
|
+
|
|
6
|
+
const App = () => {
|
|
7
|
+
return (
|
|
8
|
+
<Routes>
|
|
9
|
+
<Route index element={<HomePage />} />
|
|
10
|
+
<Route path="*" element={<Page.Error />} />
|
|
11
|
+
</Routes>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { App };
|