backend-scaffold-cli 1.2.0 → 1.4.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/bin/cli.js +157 -5
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -37,6 +37,12 @@ program
|
|
|
37
37
|
message: 'Include rate limiting?',
|
|
38
38
|
default: true
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
type: 'confirm',
|
|
42
|
+
name: 'useFileUpload',
|
|
43
|
+
message: 'Include file upload support (multer)?',
|
|
44
|
+
default: true
|
|
45
|
+
},
|
|
40
46
|
{
|
|
41
47
|
type: 'confirm',
|
|
42
48
|
name: 'installDeps',
|
|
@@ -61,10 +67,13 @@ program
|
|
|
61
67
|
console.log(chalk.blue(`Creating project in ${projectPath}\n`));
|
|
62
68
|
fs.ensureDirSync(projectPath);
|
|
63
69
|
|
|
64
|
-
createFolderStructure(projectPath);
|
|
70
|
+
createFolderStructure(projectPath, answers);
|
|
65
71
|
createConfigFiles(projectPath, answers);
|
|
66
72
|
createMiddlewareFiles(projectPath, answers);
|
|
67
73
|
createRouteFiles(projectPath, answers);
|
|
74
|
+
if (answers.useAuth) {
|
|
75
|
+
createUserModel(projectPath);
|
|
76
|
+
}
|
|
68
77
|
|
|
69
78
|
console.log(chalk.cyan(' Initializing git repository...'));
|
|
70
79
|
execSync('git init', { cwd: projectPath });
|
|
@@ -91,7 +100,7 @@ program.parse();
|
|
|
91
100
|
|
|
92
101
|
|
|
93
102
|
|
|
94
|
-
const createFolderStructure = (projectPath) => {
|
|
103
|
+
const createFolderStructure = (projectPath, answers) => {
|
|
95
104
|
const folders = [
|
|
96
105
|
'src/config',
|
|
97
106
|
'src/middleware',
|
|
@@ -102,12 +111,15 @@ const createFolderStructure = (projectPath) => {
|
|
|
102
111
|
'src/validation'
|
|
103
112
|
];
|
|
104
113
|
|
|
114
|
+
if (answers.useFileUpload) {
|
|
115
|
+
folders.push('uploads');
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
folders.forEach(folder => {
|
|
106
119
|
fs.ensureDirSync(path.join(projectPath, folder));
|
|
107
120
|
});
|
|
108
121
|
|
|
109
122
|
console.log(chalk.green(' Folder structure created'));
|
|
110
|
-
|
|
111
123
|
}
|
|
112
124
|
|
|
113
125
|
|
|
@@ -133,9 +145,10 @@ const createConfigFiles = (projectPath, answers) => {
|
|
|
133
145
|
mongoose: '^7.0.0',
|
|
134
146
|
dotenv: '^16.0.3',
|
|
135
147
|
cors: '^2.8.5',
|
|
136
|
-
...(answers.useAuth && { jsonwebtoken: '^9.0.0' }),
|
|
148
|
+
...(answers.useAuth && { jsonwebtoken: '^9.0.0' , bcryptjs: '^2.4.3'}),
|
|
137
149
|
...(answers.useValidation && { joi: '^17.9.0' }),
|
|
138
150
|
...(answers.useRateLimit && { 'express-rate-limit': '^6.7.0' }),
|
|
151
|
+
...(answers.useFileUpload && { multer: '^2.0.0' }),
|
|
139
152
|
|
|
140
153
|
},
|
|
141
154
|
devDependencies: {
|
|
@@ -182,7 +195,6 @@ LOG_LEVEL=debug
|
|
|
182
195
|
|
|
183
196
|
|
|
184
197
|
|
|
185
|
-
|
|
186
198
|
const gitignore = `node_modules/
|
|
187
199
|
.env
|
|
188
200
|
.env.local
|
|
@@ -195,10 +207,14 @@ npm-debug.log*
|
|
|
195
207
|
yarn-debug.log*
|
|
196
208
|
.idea/
|
|
197
209
|
.vscode/
|
|
210
|
+
${answers.useFileUpload ? 'uploads/*\n!uploads/.gitkeep' : ''}
|
|
198
211
|
`;
|
|
199
212
|
|
|
200
213
|
fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
|
|
201
214
|
|
|
215
|
+
if(answers.useFileUpload){
|
|
216
|
+
fs.writeFileSync(path.join(projectPath, 'uploads/.gitkeep'), '');
|
|
217
|
+
}
|
|
202
218
|
console.log(chalk.green(' Config files created'));
|
|
203
219
|
|
|
204
220
|
|
|
@@ -309,6 +325,57 @@ module.exports=limiter;
|
|
|
309
325
|
|
|
310
326
|
|
|
311
327
|
|
|
328
|
+
if(answers.useFileUpload){
|
|
329
|
+
const multerMiddleware= ` const multer = require('multer');
|
|
330
|
+
const path = require('path');
|
|
331
|
+
|
|
332
|
+
// Set storage engine
|
|
333
|
+
const storage = multer.diskStorage({
|
|
334
|
+
destination: function (req,file ,cb){
|
|
335
|
+
cb(null, 'uploads/');
|
|
336
|
+
},
|
|
337
|
+
filename: function (req, file, cb) {
|
|
338
|
+
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random()*1E9);
|
|
339
|
+
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
//file filter
|
|
346
|
+
const fileFilter = (req, file, cb) =>{
|
|
347
|
+
const allowedTypes = /jpeg|jpg|png|gif/;
|
|
348
|
+
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
|
|
349
|
+
const mimetype = allowedTypes.test(file.mimetype);
|
|
350
|
+
|
|
351
|
+
if(extname && mimetype){
|
|
352
|
+
return cb(null,true);
|
|
353
|
+
}else{
|
|
354
|
+
cb(new Error('Error: Images Only!'));
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const upload = multer({
|
|
359
|
+
storage: storage,
|
|
360
|
+
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB limit
|
|
361
|
+
fileFilter: fileFilter
|
|
362
|
+
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
module.exports = upload;
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
`;
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
fs.writeFileSync(
|
|
372
|
+
path.join(projectPath, 'src/middleware/upload.js'),
|
|
373
|
+
multerMiddleware
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
312
379
|
|
|
313
380
|
|
|
314
381
|
|
|
@@ -387,6 +454,7 @@ const createRouteFiles = (projectPath, answers) => {
|
|
|
387
454
|
const routes = `const express = require('express');
|
|
388
455
|
const router = express.Router();
|
|
389
456
|
${answers.useAuth ? "const authenticateToken = require('../middleware/auth');" : ''}
|
|
457
|
+
${answers.useFileUpload ? "const upload = require('../middleware/upload');" : ''}
|
|
390
458
|
|
|
391
459
|
// Public routes
|
|
392
460
|
router.get('/health', (req, res) => {
|
|
@@ -400,6 +468,28 @@ router.get('/protected', authenticateToken, (req, res) => {
|
|
|
400
468
|
});
|
|
401
469
|
` : ''}
|
|
402
470
|
|
|
471
|
+
${answers.useFileUpload ? `
|
|
472
|
+
// File upload route
|
|
473
|
+
router.post('/upload', upload.single('file'), (req,res) =>{
|
|
474
|
+
if(!req.file){
|
|
475
|
+
return res.status(400).json({
|
|
476
|
+
success: false,
|
|
477
|
+
message: 'No file uploaded'
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
res.json({
|
|
481
|
+
success: true,
|
|
482
|
+
message: 'File uploaded successfully',
|
|
483
|
+
file: req.file
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
`: ''}
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
403
493
|
module.exports = router;
|
|
404
494
|
`;
|
|
405
495
|
fs.writeFileSync(
|
|
@@ -513,3 +603,65 @@ process.on('unhandledRejection', (err) => {
|
|
|
513
603
|
|
|
514
604
|
console.log(chalk.green('Route and config files created'));
|
|
515
605
|
}
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
function createUserModel(projectPath) {
|
|
612
|
+
const userModel = `const mongoose = require('mongoose');
|
|
613
|
+
const bcrypt = require('bcryptjs');
|
|
614
|
+
|
|
615
|
+
const userSchema = new mongoose.Schema(
|
|
616
|
+
{
|
|
617
|
+
name:{
|
|
618
|
+
type: String,
|
|
619
|
+
required: [true, 'Name is required'],
|
|
620
|
+
trim: true,
|
|
621
|
+
},
|
|
622
|
+
email: {
|
|
623
|
+
type: String,
|
|
624
|
+
required: [true, 'Email is required'],
|
|
625
|
+
unique: true,
|
|
626
|
+
lowercase: true,
|
|
627
|
+
trim: true,
|
|
628
|
+
match: [/.+@.+\\..+/, 'Please fill a valid email address'],
|
|
629
|
+
},
|
|
630
|
+
password: {
|
|
631
|
+
type: String,
|
|
632
|
+
required: [true, 'Password is required'],
|
|
633
|
+
minlength: [6, 'Password must be at least 6 characters long'],
|
|
634
|
+
select: false
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
{ timestamps: true }
|
|
638
|
+
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
//hash password before saving
|
|
643
|
+
userSchema.pre('save', async function (next) {
|
|
644
|
+
if (!this.isModified('password')) {
|
|
645
|
+
return next();
|
|
646
|
+
}
|
|
647
|
+
this.password = await bcrypt.hash(this.password,10);
|
|
648
|
+
next();
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
//compare password method
|
|
653
|
+
userSchema.methods.comparePassword = async function(candidatePassword) {
|
|
654
|
+
return await bcrypt.compare(candidatePassword, this.password);
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
module.exports = mongoose.model('User', userSchema);
|
|
658
|
+
|
|
659
|
+
`;
|
|
660
|
+
|
|
661
|
+
fs.writeFileSync(
|
|
662
|
+
path.join(projectPath, 'src/models/User.js'),
|
|
663
|
+
userModel
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
console.log(chalk.green('User model created'));
|
|
667
|
+
}
|