alexis-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/libalexis.iml +8 -0
- package/.idea/modules.xml +8 -0
- package/.idea/php.xml +19 -0
- package/bin/alexis.js +56 -0
- package/commands/make-auth.js +308 -0
- package/commands/make-crud.js +276 -0
- package/commands/make-entity.js +97 -0
- package/commands/make-migration.js +13 -0
- package/commands/make-module.js +174 -0
- package/commands/make-swagger.js +439 -0
- package/commands/migrate.js +15 -0
- package/package.json +15 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="inheritedJdk" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
</module>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/libalexis.iml" filepath="$PROJECT_DIR$/.idea/libalexis.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
package/.idea/php.xml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="MessDetectorOptionsConfiguration">
|
|
4
|
+
<option name="transferred" value="true" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="PHPCSFixerOptionsConfiguration">
|
|
7
|
+
<option name="transferred" value="true" />
|
|
8
|
+
</component>
|
|
9
|
+
<component name="PHPCodeSnifferOptionsConfiguration">
|
|
10
|
+
<option name="highlightLevel" value="WARNING" />
|
|
11
|
+
<option name="transferred" value="true" />
|
|
12
|
+
</component>
|
|
13
|
+
<component name="PhpStanOptionsConfiguration">
|
|
14
|
+
<option name="transferred" value="true" />
|
|
15
|
+
</component>
|
|
16
|
+
<component name="PsalmOptionsConfiguration">
|
|
17
|
+
<option name="transferred" value="true" />
|
|
18
|
+
</component>
|
|
19
|
+
</project>
|
package/bin/alexis.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const makeEntity = require('../commands/make-entity');
|
|
4
|
+
const makeMigration = require('../commands/make-migration');
|
|
5
|
+
const migrate = require('../commands/migrate');
|
|
6
|
+
const makeModule = require('../commands/make-module');
|
|
7
|
+
const makeAuth = require('../commands/make-auth');
|
|
8
|
+
const makeCrud = require('../commands/make-crud');
|
|
9
|
+
const makeSwagger = require('../commands/make-swagger');
|
|
10
|
+
|
|
11
|
+
const [, , command, subcommand, name] = process.argv;
|
|
12
|
+
|
|
13
|
+
(async () => {
|
|
14
|
+
switch (`${command}:${subcommand}`) {
|
|
15
|
+
case 'make:entity':
|
|
16
|
+
await makeEntity(name);
|
|
17
|
+
break;
|
|
18
|
+
|
|
19
|
+
case 'make:migration':
|
|
20
|
+
makeMigration(name);
|
|
21
|
+
break;
|
|
22
|
+
|
|
23
|
+
case 'migrate:undefined':
|
|
24
|
+
migrate.run();
|
|
25
|
+
break;
|
|
26
|
+
|
|
27
|
+
case 'migrate:rollback':
|
|
28
|
+
migrate.rollback();
|
|
29
|
+
break;
|
|
30
|
+
|
|
31
|
+
case 'make:module':
|
|
32
|
+
makeModule(name);
|
|
33
|
+
break;
|
|
34
|
+
case 'make:auth':
|
|
35
|
+
makeAuth();
|
|
36
|
+
break;
|
|
37
|
+
case 'make:crud':
|
|
38
|
+
makeCrud(name);
|
|
39
|
+
break;
|
|
40
|
+
case 'make:swagger':
|
|
41
|
+
makeSwagger();
|
|
42
|
+
break;
|
|
43
|
+
default:
|
|
44
|
+
console.log(`
|
|
45
|
+
❓ Available commands:
|
|
46
|
+
|
|
47
|
+
alexis make entity <Name>
|
|
48
|
+
alexis make migration <name>
|
|
49
|
+
alexis migrate
|
|
50
|
+
alexis migrate rollback
|
|
51
|
+
alexis make module <name>
|
|
52
|
+
alexis make swagger
|
|
53
|
+
alexis make crud <name>
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
module.exports = () => {
|
|
5
|
+
console.log('🔐 Generating Auth system...');
|
|
6
|
+
|
|
7
|
+
/* =========================
|
|
8
|
+
1. USER ENTITY
|
|
9
|
+
========================= */
|
|
10
|
+
|
|
11
|
+
const entityDir = path.join(__dirname, '../../src/entities');
|
|
12
|
+
const userEntityPath = path.join(entityDir, 'User.entity.js');
|
|
13
|
+
|
|
14
|
+
if (!fs.existsSync(entityDir)) {
|
|
15
|
+
fs.mkdirSync(entityDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(userEntityPath)) {
|
|
19
|
+
const userEntity = `
|
|
20
|
+
const { EntitySchema } = require('typeorm');
|
|
21
|
+
|
|
22
|
+
module.exports = new EntitySchema({
|
|
23
|
+
name: 'User',
|
|
24
|
+
tableName: 'users',
|
|
25
|
+
columns: {
|
|
26
|
+
id: { type: Number, primary: true, generated: true },
|
|
27
|
+
email: { type: String, unique: true },
|
|
28
|
+
password: { type: String },
|
|
29
|
+
createdAt: { type: 'timestamp', createDate: true }
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
`.trim();
|
|
33
|
+
|
|
34
|
+
fs.writeFileSync(userEntityPath, userEntity + '\n');
|
|
35
|
+
console.log('✅ User entity created');
|
|
36
|
+
} else {
|
|
37
|
+
console.log('ℹ️ User entity already exists');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* =========================
|
|
41
|
+
2. AUTH MODULE
|
|
42
|
+
========================= */
|
|
43
|
+
|
|
44
|
+
const authDir = path.join(__dirname, '../../src/modules/v1/auth');
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(authDir)) {
|
|
47
|
+
fs.mkdirSync(authDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Controller
|
|
51
|
+
fs.writeFileSync(
|
|
52
|
+
path.join(authDir, 'auth.controller.js'),
|
|
53
|
+
`
|
|
54
|
+
const authService = require('./auth.service');
|
|
55
|
+
|
|
56
|
+
exports.register = async (req, res, next) => {
|
|
57
|
+
try {
|
|
58
|
+
const user = await authService.register(req.body);
|
|
59
|
+
res.status(201).json(user);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
next(err);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
exports.login = async (req, res, next) => {
|
|
66
|
+
try {
|
|
67
|
+
const token = await authService.login(req.body);
|
|
68
|
+
res.json({ token });
|
|
69
|
+
} catch (err) {
|
|
70
|
+
next(err);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
exports.profile = (req, res) => {
|
|
75
|
+
res.json(req.user);
|
|
76
|
+
};
|
|
77
|
+
`.trim() + '\n'
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Service
|
|
81
|
+
fs.writeFileSync(
|
|
82
|
+
path.join(authDir, 'auth.service.js'),
|
|
83
|
+
`
|
|
84
|
+
const bcrypt = require('bcrypt');
|
|
85
|
+
const jwt = require('jsonwebtoken');
|
|
86
|
+
const AppDataSource = require('../../../config/orm');
|
|
87
|
+
const User = require('../../../entities/User.entity');
|
|
88
|
+
const { JWT_SECRET } = require('../../../config/jwt');
|
|
89
|
+
|
|
90
|
+
exports.register = async ({ email, password }) => {
|
|
91
|
+
const repo = AppDataSource.getRepository(User);
|
|
92
|
+
|
|
93
|
+
if (await repo.findOneBy({ email })) {
|
|
94
|
+
throw new Error('User exists');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const hash = await bcrypt.hash(password, 10);
|
|
98
|
+
const user = repo.create({ email, password: hash });
|
|
99
|
+
await repo.save(user);
|
|
100
|
+
|
|
101
|
+
return { id: user.id, email: user.email };
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
exports.login = async ({ email, password }) => {
|
|
105
|
+
const repo = AppDataSource.getRepository(User);
|
|
106
|
+
const user = await repo.findOneBy({ email });
|
|
107
|
+
|
|
108
|
+
if (!user || !(await bcrypt.compare(password, user.password))) {
|
|
109
|
+
throw new Error('Invalid credentials');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return jwt.sign(
|
|
113
|
+
{ id: user.id, email: user.email },
|
|
114
|
+
JWT_SECRET,
|
|
115
|
+
{ expiresIn: '1h' }
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
`.trim() + '\n'
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Routes (Swagger inclus)
|
|
122
|
+
fs.writeFileSync(
|
|
123
|
+
path.join(authDir, 'auth.routes.js'),
|
|
124
|
+
`
|
|
125
|
+
const express = require('express');
|
|
126
|
+
const router = express.Router();
|
|
127
|
+
const controller = require('./auth.controller');
|
|
128
|
+
const authMiddleware = require('../../../middlewares/auth.middleware');
|
|
129
|
+
const rateLimit = require('express-rate-limit');
|
|
130
|
+
|
|
131
|
+
const loginLimiter = rateLimit({
|
|
132
|
+
windowMs: 15 * 60 * 1000, // 15 min
|
|
133
|
+
max: 5,
|
|
134
|
+
message: { message: "Trop de tentatives de login. Réessayez dans 15 minutes." },
|
|
135
|
+
standardHeaders: true,
|
|
136
|
+
legacyHeaders: false
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @swagger
|
|
142
|
+
* /auth/register:
|
|
143
|
+
* post:
|
|
144
|
+
* summary: Crée un nouvel utilisateur
|
|
145
|
+
* tags: [Auth]
|
|
146
|
+
* requestBody:
|
|
147
|
+
* required: true
|
|
148
|
+
* content:
|
|
149
|
+
* application/json:
|
|
150
|
+
* schema:
|
|
151
|
+
* type: object
|
|
152
|
+
* required:
|
|
153
|
+
* - email
|
|
154
|
+
* - password
|
|
155
|
+
* properties:
|
|
156
|
+
* email:
|
|
157
|
+
* type: string
|
|
158
|
+
* example: test@test.com
|
|
159
|
+
* password:
|
|
160
|
+
* type: string
|
|
161
|
+
* example: 123456
|
|
162
|
+
* responses:
|
|
163
|
+
* 201:
|
|
164
|
+
* description: Utilisateur créé
|
|
165
|
+
*/
|
|
166
|
+
router.post('/register', controller.register);
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @swagger
|
|
170
|
+
* /auth/login:
|
|
171
|
+
* post:
|
|
172
|
+
* summary: Connexion utilisateur
|
|
173
|
+
* tags: [Auth]
|
|
174
|
+
* requestBody:
|
|
175
|
+
* required: true
|
|
176
|
+
* content:
|
|
177
|
+
* application/json:
|
|
178
|
+
* schema:
|
|
179
|
+
* type: object
|
|
180
|
+
* required:
|
|
181
|
+
* - email
|
|
182
|
+
* - password
|
|
183
|
+
* properties:
|
|
184
|
+
* email:
|
|
185
|
+
* type: string
|
|
186
|
+
* example: test@test.com
|
|
187
|
+
* password:
|
|
188
|
+
* type: string
|
|
189
|
+
* example: 123456
|
|
190
|
+
* responses:
|
|
191
|
+
* 200:
|
|
192
|
+
* description: Token JWT
|
|
193
|
+
*/
|
|
194
|
+
router.post('/login', controller.login);
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @swagger
|
|
198
|
+
* /auth/profile:
|
|
199
|
+
* get:
|
|
200
|
+
* summary: Récupère le profil de l'utilisateur connecté
|
|
201
|
+
* tags: [Auth]
|
|
202
|
+
* security:
|
|
203
|
+
* - bearerAuth: []
|
|
204
|
+
* responses:
|
|
205
|
+
* 200:
|
|
206
|
+
* description: Profil utilisateur
|
|
207
|
+
*/
|
|
208
|
+
router.get('/profile', authMiddleware, controller.profile);
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
module.exports = router;
|
|
212
|
+
`.trim() + '\n'
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
/* =========================
|
|
216
|
+
3. AUTH MIDDLEWARE
|
|
217
|
+
========================= */
|
|
218
|
+
|
|
219
|
+
const middlewareDir = path.join(__dirname, '../../src/middlewares');
|
|
220
|
+
const middlewarePath = path.join(middlewareDir, 'auth.middleware.js');
|
|
221
|
+
|
|
222
|
+
if (!fs.existsSync(middlewareDir)) {
|
|
223
|
+
fs.mkdirSync(middlewareDir, { recursive: true });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!fs.existsSync(middlewarePath)) {
|
|
227
|
+
fs.writeFileSync(
|
|
228
|
+
middlewarePath,
|
|
229
|
+
`
|
|
230
|
+
const jwt = require('jsonwebtoken');
|
|
231
|
+
const { JWT_SECRET } = require('../config/jwt');
|
|
232
|
+
|
|
233
|
+
module.exports = (req, res, next) => {
|
|
234
|
+
const token = req.headers.authorization?.split(' ')[1];
|
|
235
|
+
if (!token) return res.status(401).json({ message: 'No token' });
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
req.user = jwt.verify(token, JWT_SECRET);
|
|
239
|
+
next();
|
|
240
|
+
} catch {
|
|
241
|
+
res.status(401).json({ message: 'Invalid token' });
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
`.trim() + '\n'
|
|
245
|
+
);
|
|
246
|
+
console.log('✅ Auth middleware created');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* =========================
|
|
250
|
+
4. JWT CONFIG
|
|
251
|
+
========================= */
|
|
252
|
+
|
|
253
|
+
const jwtConfigPath = path.join(__dirname, '../../src/config/jwt.js');
|
|
254
|
+
|
|
255
|
+
if (!fs.existsSync(jwtConfigPath)) {
|
|
256
|
+
fs.writeFileSync(
|
|
257
|
+
jwtConfigPath,
|
|
258
|
+
`module.exports = {
|
|
259
|
+
JWT_SECRET: process.env.JWT_SECRET || 'change-me'
|
|
260
|
+
};
|
|
261
|
+
`.trim() + '\n'
|
|
262
|
+
);
|
|
263
|
+
console.log('✅ JWT config created');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
console.log('\n🎉 Auth system ready');
|
|
267
|
+
console.log('➡️ Next steps:');
|
|
268
|
+
console.log(' alexis make migration create-users');
|
|
269
|
+
console.log(' alexis migrate');
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/* =========================
|
|
273
|
+
5. AUTO-REGISTER AUTH ROUTE
|
|
274
|
+
========================= */
|
|
275
|
+
|
|
276
|
+
const routesIndexPath = path.join(
|
|
277
|
+
__dirname,
|
|
278
|
+
'../../src/routes/v1/index.js'
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
if (!fs.existsSync(routesIndexPath)) {
|
|
282
|
+
console.warn('⚠️ routes/v1/index.js not found, skipping auth route registration');
|
|
283
|
+
} else {
|
|
284
|
+
let indexContent = fs.readFileSync(routesIndexPath, 'utf8');
|
|
285
|
+
|
|
286
|
+
const importLine =
|
|
287
|
+
`const authRoutes = require('../../../src/modules/v1/auth/auth.routes');`;
|
|
288
|
+
const routeLine =
|
|
289
|
+
`router.use('/auth', authRoutes);`;
|
|
290
|
+
|
|
291
|
+
if (!indexContent.includes(importLine)) {
|
|
292
|
+
indexContent = indexContent.replace(
|
|
293
|
+
'// AUTO-IMPORTS (do not remove)',
|
|
294
|
+
`// AUTO-IMPORTS (do not remove)\n${importLine}`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (!indexContent.includes(routeLine)) {
|
|
299
|
+
indexContent = indexContent.replace(
|
|
300
|
+
'// AUTO-ROUTES (do not remove)',
|
|
301
|
+
`// AUTO-ROUTES (do not remove)\n${routeLine}`
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
fs.writeFileSync(routesIndexPath, indexContent);
|
|
306
|
+
console.log('🔗 Auth routes registered in routes/v1/index.js');
|
|
307
|
+
}
|
|
308
|
+
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
module.exports = (entityName) => {
|
|
5
|
+
if (!entityName) {
|
|
6
|
+
console.error('❌ Usage: alexis make crud <Entity>');
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const moduleName = entityName.toLowerCase();
|
|
11
|
+
const EntityName =
|
|
12
|
+
entityName.charAt(0).toUpperCase() + entityName.slice(1);
|
|
13
|
+
|
|
14
|
+
// 🔎 Vérifier l'Entity
|
|
15
|
+
const entityPath = path.join(
|
|
16
|
+
__dirname,
|
|
17
|
+
'../../src/entities',
|
|
18
|
+
`${EntityName}.entity.js`
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(entityPath)) {
|
|
22
|
+
console.error(`❌ Entity "${EntityName}" not found`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 📁 Module
|
|
27
|
+
const moduleDir = path.join(
|
|
28
|
+
__dirname,
|
|
29
|
+
'../../src/modules/v1',
|
|
30
|
+
moduleName
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (fs.existsSync(moduleDir)) {
|
|
34
|
+
console.error(`❌ Module "${moduleName}" already exists`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fs.mkdirSync(moduleDir, { recursive: true });
|
|
39
|
+
|
|
40
|
+
/* ======================
|
|
41
|
+
SERVICE
|
|
42
|
+
====================== */
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
path.join(moduleDir, `${moduleName}.service.js`),
|
|
45
|
+
`
|
|
46
|
+
const AppDataSource = require('../../../config/orm');
|
|
47
|
+
const ${EntityName} = require('../../../entities/${EntityName}.entity');
|
|
48
|
+
|
|
49
|
+
const repo = () => AppDataSource.getRepository(${EntityName});
|
|
50
|
+
|
|
51
|
+
exports.findAll = () => repo().find();
|
|
52
|
+
|
|
53
|
+
exports.findOne = (id) =>
|
|
54
|
+
repo().findOneBy({ id: Number(id) });
|
|
55
|
+
|
|
56
|
+
exports.create = (data) => repo().save(repo().create(data));
|
|
57
|
+
|
|
58
|
+
exports.update = async (id, data) => {
|
|
59
|
+
await repo().update(id, data);
|
|
60
|
+
return exports.findOne(id);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
exports.remove = (id) =>
|
|
64
|
+
repo().delete(id);
|
|
65
|
+
`.trim() + '\n'
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
/* ======================
|
|
69
|
+
CONTROLLER
|
|
70
|
+
====================== */
|
|
71
|
+
fs.writeFileSync(
|
|
72
|
+
path.join(moduleDir, `${moduleName}.controller.js`),
|
|
73
|
+
`
|
|
74
|
+
const service = require('./${moduleName}.service');
|
|
75
|
+
|
|
76
|
+
exports.findAll = async (req, res, next) => {
|
|
77
|
+
try {
|
|
78
|
+
res.json(await service.findAll());
|
|
79
|
+
} catch (e) {
|
|
80
|
+
next(e);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
exports.findOne = async (req, res, next) => {
|
|
85
|
+
try {
|
|
86
|
+
res.json(await service.findOne(req.params.id));
|
|
87
|
+
} catch (e) {
|
|
88
|
+
next(e);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
exports.create = async (req, res, next) => {
|
|
93
|
+
try {
|
|
94
|
+
res.status(201).json(await service.create(req.body));
|
|
95
|
+
} catch (e) {
|
|
96
|
+
next(e);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
exports.update = async (req, res, next) => {
|
|
101
|
+
try {
|
|
102
|
+
res.json(await service.update(req.params.id, req.body));
|
|
103
|
+
} catch (e) {
|
|
104
|
+
next(e);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
exports.remove = async (req, res, next) => {
|
|
109
|
+
try {
|
|
110
|
+
await service.remove(req.params.id);
|
|
111
|
+
res.status(204).end();
|
|
112
|
+
} catch (e) {
|
|
113
|
+
next(e);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
`.trim() + '\n'
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
/* ======================
|
|
120
|
+
ROUTES + SWAGGER
|
|
121
|
+
====================== */
|
|
122
|
+
fs.writeFileSync(
|
|
123
|
+
path.join(moduleDir, `${moduleName}.routes.js`),
|
|
124
|
+
`
|
|
125
|
+
/**
|
|
126
|
+
* @swagger
|
|
127
|
+
* tags:
|
|
128
|
+
* name: ${EntityName}
|
|
129
|
+
* description: CRUD ${EntityName}
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
const express = require('express');
|
|
133
|
+
const router = express.Router();
|
|
134
|
+
const controller = require('./${moduleName}.controller');
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @swagger
|
|
138
|
+
* /${moduleName}:
|
|
139
|
+
* get:
|
|
140
|
+
* summary: Get all ${EntityName}
|
|
141
|
+
* tags: [${EntityName}]
|
|
142
|
+
* security:
|
|
143
|
+
* - bearerAuth: []
|
|
144
|
+
* responses:
|
|
145
|
+
* 200:
|
|
146
|
+
* description: List of ${EntityName}
|
|
147
|
+
*/
|
|
148
|
+
router.get('/', controller.findAll);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @swagger
|
|
152
|
+
* /${moduleName}/{id}:
|
|
153
|
+
* get:
|
|
154
|
+
* summary: Get a ${EntityName} by id
|
|
155
|
+
* tags: [${EntityName}]
|
|
156
|
+
* security:
|
|
157
|
+
* - bearerAuth: []
|
|
158
|
+
* parameters:
|
|
159
|
+
* - in: path
|
|
160
|
+
* name: id
|
|
161
|
+
* required: true
|
|
162
|
+
* schema:
|
|
163
|
+
* type: integer
|
|
164
|
+
* responses:
|
|
165
|
+
* 200:
|
|
166
|
+
* description: ${EntityName} found
|
|
167
|
+
* 404:
|
|
168
|
+
* description: ${EntityName} not found
|
|
169
|
+
*/
|
|
170
|
+
router.get('/:id', controller.findOne);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @swagger
|
|
174
|
+
* /${moduleName}:
|
|
175
|
+
* post:
|
|
176
|
+
* summary: Create a ${EntityName}
|
|
177
|
+
* tags: [${EntityName}]
|
|
178
|
+
* security:
|
|
179
|
+
* - bearerAuth: []
|
|
180
|
+
* requestBody:
|
|
181
|
+
* required: true
|
|
182
|
+
* content:
|
|
183
|
+
* application/json:
|
|
184
|
+
* schema:
|
|
185
|
+
* type: object
|
|
186
|
+
* responses:
|
|
187
|
+
* 201:
|
|
188
|
+
* description: ${EntityName} created
|
|
189
|
+
*/
|
|
190
|
+
router.post('/', controller.create);
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @swagger
|
|
194
|
+
* /${moduleName}/{id}:
|
|
195
|
+
* put:
|
|
196
|
+
* summary: Update a ${EntityName}
|
|
197
|
+
* tags: [${EntityName}]
|
|
198
|
+
* security:
|
|
199
|
+
* - bearerAuth: []
|
|
200
|
+
* parameters:
|
|
201
|
+
* - in: path
|
|
202
|
+
* name: id
|
|
203
|
+
* required: true
|
|
204
|
+
* schema:
|
|
205
|
+
* type: integer
|
|
206
|
+
* requestBody:
|
|
207
|
+
* required: true
|
|
208
|
+
* content:
|
|
209
|
+
* application/json:
|
|
210
|
+
* schema:
|
|
211
|
+
* type: object
|
|
212
|
+
* responses:
|
|
213
|
+
* 200:
|
|
214
|
+
* description: ${EntityName} updated
|
|
215
|
+
*/
|
|
216
|
+
router.put('/:id', controller.update);
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @swagger
|
|
220
|
+
* /${moduleName}/{id}:
|
|
221
|
+
* delete:
|
|
222
|
+
* summary: Delete a ${EntityName}
|
|
223
|
+
* tags: [${EntityName}]
|
|
224
|
+
* security:
|
|
225
|
+
* - bearerAuth: []
|
|
226
|
+
* parameters:
|
|
227
|
+
* - in: path
|
|
228
|
+
* name: id
|
|
229
|
+
* required: true
|
|
230
|
+
* schema:
|
|
231
|
+
* type: integer
|
|
232
|
+
* responses:
|
|
233
|
+
* 204:
|
|
234
|
+
* description: ${EntityName} deleted
|
|
235
|
+
*/
|
|
236
|
+
router.delete('/:id', controller.remove);
|
|
237
|
+
|
|
238
|
+
module.exports = router;
|
|
239
|
+
`.trim() + '\n'
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
console.log(`✅ CRUD module "${moduleName}" created`);
|
|
243
|
+
|
|
244
|
+
/* ======================
|
|
245
|
+
AUTO-REGISTER ROUTE
|
|
246
|
+
====================== */
|
|
247
|
+
const routesIndexPath = path.join(
|
|
248
|
+
__dirname,
|
|
249
|
+
'../../src/routes/v1/index.js'
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
let index = fs.readFileSync(routesIndexPath, 'utf8');
|
|
253
|
+
|
|
254
|
+
const importLine =
|
|
255
|
+
`const ${moduleName}Routes = require('../../../src/modules/v1/${moduleName}/${moduleName}.routes');`;
|
|
256
|
+
const routeLine =
|
|
257
|
+
`router.use('/${moduleName}', ${moduleName}Routes);`;
|
|
258
|
+
|
|
259
|
+
if (!index.includes(importLine)) {
|
|
260
|
+
index = index.replace(
|
|
261
|
+
'// AUTO-IMPORTS (do not remove)',
|
|
262
|
+
`// AUTO-IMPORTS (do not remove)\n${importLine}`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!index.includes(routeLine)) {
|
|
267
|
+
index = index.replace(
|
|
268
|
+
'// AUTO-ROUTES (do not remove)',
|
|
269
|
+
`// AUTO-ROUTES (do not remove)\n${routeLine}`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fs.writeFileSync(routesIndexPath, index);
|
|
274
|
+
|
|
275
|
+
console.log(`🔗 Route "/${moduleName}" registered`);
|
|
276
|
+
};
|