create-sip 1.3.1 → 1.3.2

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/expressapi/op DELETED
@@ -1,530 +0,0 @@
1
- import yargs from 'yargs';
2
- import { hideBin } from 'yargs/helpers';
3
- import replace from 'replace';
4
- import fse from 'fs-extra';
5
- import fsp from 'fs/promises';
6
- import { generateApiKey } from 'generate-api-key';
7
- import bcrypt from 'bcryptjs';
8
- import path from 'path';
9
- import { read } from 'read';
10
-
11
- yargs(hideBin(process.argv))
12
- .version()
13
- .strict()
14
- .usage('Használat: node op <command> [name]')
15
- .help()
16
- .demandCommand(2, 'Not enough arguments!')
17
- .command('make:model <name>',
18
- 'Generates a new Sequelize model',
19
- (yargs) => {
20
- return yargs
21
- .positional('name', {
22
- type: 'string',
23
- description: 'Name of the model'
24
- })
25
- },
26
- async (argv) => {
27
- const { name } = argv;
28
- await copyModel(name);
29
- }
30
- )
31
- .command('make:controller <name>',
32
- 'Generates a new controller',
33
- (yargs) => {
34
- return yargs
35
- .positional('name', {
36
- type: 'string',
37
- description: 'Name of the controller'
38
- })
39
- },
40
- async (argv) => {
41
- const { name } = argv;
42
- await copyController(name);
43
- }
44
- )
45
- .command('key:generate',
46
- 'Generates a new API key',
47
- (yargs) => {
48
- return yargs
49
- },
50
- async (argv) => {
51
- startGenerateKey();
52
- }
53
- )
54
- .command('conf:generate',
55
- 'Generate a new config file: .env',
56
- (yargs) => {
57
- return yargs
58
- },
59
- async (argv) => {
60
- startGenerateConf();
61
- }
62
- )
63
- .command('testconf:generate',
64
- 'Generate a new config file: .env.test',
65
- (yargs) => {
66
- return yargs
67
- },
68
- async (argv) => {
69
- startGenerateTestConf();
70
- }
71
- )
72
- .command('admin:generate',
73
- 'Generates a new admin user in database table: users',
74
- (yargs) => {
75
- return yargs
76
- },
77
- async (argv) => {
78
- startGenerateAdmin();
79
- }
80
- )
81
- .command('db:import <model> <filePath> [sep]',
82
- `Import CSV or JSON file to database table
83
-
84
- Examples:
85
- node op db:import thing somethings.json
86
- node op db:import thing somethings.csv
87
- node op db:import thing somethings.csv ,
88
- node op db:import thing somethings.csv :
89
- node op db:import thing somethings.csv ";"
90
-
91
- In CSV file the field names must match the model fields.
92
- `,
93
- (yargs) => {
94
- return yargs
95
- .positional('model', {
96
- type: 'string',
97
- description: 'Name of the model'
98
- })
99
- .positional('filePath', {
100
- type: 'string',
101
- description: 'Path to the file'
102
- })
103
- .positional('sep', {
104
- type: 'string',
105
- description: 'Separator for the CSV file'
106
- })
107
- },
108
- async (argv) => {
109
- const { model, filePath, sep } = argv;
110
- await runImportData(model, filePath, sep);
111
- }
112
- )
113
- .command('make:migration <name>',
114
- 'Generates a new migration file',
115
- (yargs) => {
116
- return yargs
117
- .positional('name', {
118
- type: 'string',
119
- description: 'Name of the migration'
120
- })
121
- },
122
- async (argv) => {
123
- const { name } = argv;
124
- await createMigration(name);
125
- }
126
- )
127
- .command('migration:run [migrationName]',
128
- 'Runs migrations',
129
- (yargs) => {
130
- return yargs
131
- .positional('migrationName', {
132
- type: 'string',
133
- description: 'Name of the migration'
134
- })
135
- },
136
- async (argv) => {
137
- const { migrationName } = argv;
138
- await startMigrations(migrationName);
139
- }
140
- )
141
- .command('migration:rollback',
142
- 'Rolls back migrations',
143
- (yargs) => {
144
- return yargs
145
- .options({
146
- step: {
147
- type: 'number',
148
- description: 'Number of migrations to rollback',
149
- default: 1
150
- }
151
- })
152
- },
153
- async (argv) => {
154
- const { step } = argv;
155
- await rollbackMigrations(step);
156
- }
157
- )
158
- .command('migration:fresh',
159
- 'Rolls back all migrations',
160
- (yargs) => {
161
- return yargs
162
- },
163
- async (argv) => {
164
- await freshMigrations();
165
- }
166
- )
167
- .command('migration:reset',
168
- 'Rolls back all migrations',
169
- (yargs) => {
170
- return yargs
171
- },
172
- async (argv) => {
173
- await resetMigrations();
174
- }
175
- )
176
- .parse();
177
-
178
- async function copyController(className) {
179
- const lowerName = className.toLowerCase()
180
-
181
- const src = 'templates/controllerTemplate.js'
182
- const dest = `app/controllers/${lowerName}Controller.js`
183
-
184
- if(await startCheckIfFileExists(dest)) {
185
- process.exit(1);
186
- }
187
-
188
- await fse.copy(src, dest)
189
-
190
- replace({
191
- regex: 'Thing',
192
- replacement: capitalizeFirstLetter(className),
193
- paths: [dest]
194
- })
195
- replace({
196
- regex: 'thing',
197
- replacement: className,
198
- paths: [dest]
199
- })
200
- replace({
201
- regex: 'things',
202
- replacement: className + 's',
203
- paths: [dest]
204
- })
205
- }
206
-
207
- async function copyModel(className) {
208
- const lowerName = className.toLowerCase()
209
- const src = 'templates/modelTemplate.js'
210
- const dest = `app/models/${lowerName}.js`
211
-
212
- if(await startCheckIfFileExists(dest)) {
213
- process.exit(1);
214
- }
215
-
216
- await fse.copy(src, dest)
217
-
218
- replace({
219
- regex: 'Thing',
220
- replacement: capitalizeFirstLetter(className),
221
- paths: [dest]
222
- })
223
- replace({
224
- regex: 'thing',
225
- replacement: className,
226
- paths: [dest]
227
- })
228
- }
229
-
230
- async function checkIfFileExists(filePath) {
231
- return await fsp.access(filePath)
232
- .then(() => true)
233
- .catch(() => false);
234
- }
235
-
236
- async function startCheckIfFileExists(filePath) {
237
- return await checkIfFileExists(filePath)
238
- .then(exists => {
239
- if (exists) {
240
- console.log(`The file ${filePath} exists!`);
241
- return true;
242
- } else {
243
- return false;
244
- }
245
- })
246
- .catch(error => console.log(error));
247
- }
248
-
249
- function capitalizeFirstLetter(word) {
250
- return word.charAt(0).toUpperCase() + word.slice(1);
251
- }
252
-
253
- async function startGenerateKey() {
254
- try {
255
- const envFile = '.env'
256
- let content = await fse.readFile(envFile, 'utf8')
257
- const key = generateApiKey({method: 'bytes', length: 32})
258
-
259
- const regex = /^APP_KEY *=.*$/m
260
- if(regex.test(content)) {
261
- content = content.replace(regex, `APP_KEY=${key}`)
262
- }else {
263
- if(content.trim() !== '') {
264
- content += `\nAPP_KEY=${key}\n`
265
- }else {
266
- content = `APP_KEY=${key}\n`
267
- }
268
- }
269
- fse.writeFile(envFile, content, 'utf8')
270
- } catch (error) {
271
- console.error(error)
272
- }
273
- }
274
-
275
- async function startGenerateConf() {
276
- const content = `
277
- APP_PORT=8000
278
- APP_KEY=
279
- APP_LOG=console.log
280
-
281
- DB_DIALECT=sqlite
282
- DB_HOST=127.0.0.1
283
- DB_NAME=
284
- DB_USER=
285
- DB_PASS=
286
- DB_PATH=:memory:
287
- `
288
- const destinationFileName = '.env'
289
- if(await startCheckIfFileExists(destinationFileName)) {
290
- process.exit(1);
291
- }
292
-
293
- await fse.writeFile(destinationFileName, content, 'utf8')
294
- }
295
-
296
- async function startGenerateTestConf() {
297
- const content = `
298
- APP_PORT=8000
299
- APP_KEY=my_secret_key
300
- APP_LOG=console.log
301
-
302
- DB_DIALECT=sqlite
303
- DB_PATH=:memory:
304
- `
305
- const destinationFileName = '.env.test'
306
- if(await startCheckIfFileExists(destinationFileName)) {
307
- process.exit(1);
308
- }
309
-
310
- await fse.writeFile(destinationFileName, content, 'utf8')
311
- }
312
-
313
- async function inputPassword() {
314
- const password = await read({
315
- prompt: 'Password: ',
316
- silent: true,
317
- replace: '*'
318
- })
319
- return password
320
- }
321
-
322
- async function startGenerateAdmin() {
323
- try {
324
- const { default: User } = await import('./app/models/user.js')
325
- await User.sync()
326
-
327
- await import('dotenv').then((dotenv) => dotenv.config())
328
- const isMemoryDb = process.env.DB_PATH === ':memory:';
329
- if(isMemoryDb) {
330
- console.log('Admin cannot be created in memory db!')
331
- return;
332
- }
333
-
334
- const isUserExist = await User.findOne({ where: { name: 'admin' } })
335
- if (isUserExist) {
336
- console.log('Admin already exists!')
337
- return;
338
- }
339
- const password = await inputPassword()
340
- const hashedPassword = await bcrypt.hash(password, 10);
341
- await User.create({
342
- name: 'admin',
343
- email: 'admin',
344
- password: hashedPassword
345
- })
346
- console.log('Admin created!')
347
- } catch (error) {
348
- console.error('Error creating admin!')
349
- console.error(error)
350
- }
351
- }
352
-
353
- const importFromJson = async (model, filePath) => {
354
- try {
355
- const data = JSON.parse(await fsp.readFile(filePath, 'utf8'))
356
- await model.bulkCreate(data)
357
- console.log(`Data imported successfully! ${model.name}`)
358
- } catch (error) {
359
- console.error(error)
360
- }
361
- }
362
-
363
- const importFromCsv = async (model, filePath, sep) => {
364
- try {
365
- const data = await fsp.readFile(filePath, 'utf8')
366
- const clearData = data.replace(/"/g, '').trim()
367
- const rows = clearData.split('\n')
368
- const headerColumns = rows.shift().split(sep)
369
-
370
- const dataToInsert = rows.map(row => {
371
- const columns = row.split(sep).map(item => {
372
- const number = Number(item)
373
- return Number.isNaN(number) ? `${item}` : number
374
- })
375
- return headerColumns.reduce((obj, header, index) => {
376
- obj[header] = columns[index]
377
- return obj
378
- }, {})
379
- })
380
-
381
- await model.bulkCreate(dataToInsert)
382
- console.log(`Data imported successfully! ${model.name}`)
383
- } catch (error) {
384
- console.error(error)
385
- }
386
- }
387
-
388
- async function runImportData(model, filePath, sep=',') {
389
-
390
- if(!filePath || !model) {
391
- console.log('Usage: node db:import <modelName> <filePath> [sep]')
392
- process.exit(1)
393
- }
394
-
395
- try {
396
- await import(`./app/models/${model}.js`)
397
- } catch (error) {
398
- console.log(`The ${model} model file does not exist!`)
399
- process.exit(1)
400
- }
401
-
402
- try {
403
- await fsp.stat(filePath)
404
- } catch (error) {
405
- if (error.code === 'ENOENT') {
406
- console.log(`The file ${filePath} does not exist!`)
407
- process.exit(1)
408
- } else {
409
- console.error(error)
410
- process.exit(1)
411
- }
412
- }
413
-
414
- const modelInstance = await import(`./app/models/${model}.js`)
415
- const modelObject = modelInstance.default
416
-
417
- const ext = path.extname(filePath).toLowerCase()
418
- if(ext !== '.json' && ext !== '.csv') {
419
- console.log('The file must have .json or .csv extension!')
420
- process.exit(1)
421
- }
422
- const { default: sequelize } = await import('./app/database/database.js')
423
- try {
424
- await sequelize.sync({ force: true })
425
- await sequelize.authenticate()
426
- if(ext === '.csv') {
427
- await importFromCsv(modelObject, filePath, sep)
428
- }else {
429
- await importFromJson(modelObject, filePath)
430
- }
431
- } catch (error) {
432
- console.error(error)
433
- }
434
-
435
- }
436
-
437
- async function createMigration(name) {
438
- console.log('Create a new migration...', name)
439
-
440
- const lowerName = name.toLowerCase()
441
- const date = new Date()
442
- const year = date.getFullYear()
443
- const month = String(date.getMonth() + 1).padStart(2, '0')
444
- const day = String(date.getDate()).padStart(2, '0')
445
- const hours = String(date.getHours()).padStart(2, '0')
446
- const minutes = String(date.getMinutes()).padStart(2, '0')
447
- const seconds = String(date.getSeconds()).padStart(2, '0')
448
- const timestamp = `${year}_${month}_${day}_${hours}${minutes}${seconds}`
449
-
450
- const migrationName = `${timestamp}_${lowerName}`
451
-
452
- const src = 'templates/migrationTemplate.js'
453
- const dest = `database/migrations/${migrationName}.js`
454
-
455
- if(await startCheckIfFileExists(dest)) {
456
- process.exit(1);
457
- }
458
-
459
- await fse.copy(src, dest)
460
-
461
- replace({
462
- regex: 'thing',
463
- replacement: name,
464
- paths: [dest]
465
- })
466
-
467
- }
468
-
469
- async function getUmzug() {
470
- const { default: sequelize } = await import('./app/database/database.js')
471
- const { Umzug, SequelizeStorage } = await import('umzug')
472
-
473
- const umzug = new Umzug({
474
- migrations: { glob: './database/migrations/*.js' },
475
- context: sequelize.getQueryInterface(),
476
- storage: new SequelizeStorage({ sequelize }),
477
- logger: console
478
- })
479
-
480
- return umzug
481
- }
482
-
483
- async function startMigrations(name) {
484
- if(name) {
485
- await runOneMigration(name)
486
- } else {
487
- await runMigrations()
488
- }
489
- }
490
-
491
- async function runOneMigration(name) {
492
- console.log('Run one migration...', name)
493
-
494
- if(!name.endsWith('.js')) {
495
- name += '.js'
496
- }
497
-
498
- const migrationPath = `database/migrations/${name}`
499
- if(!await startCheckIfFileExists(migrationPath)) {
500
- console.log(`The migration file ${migrationPath} not already exists.`)
501
- process.exit(1)
502
- }
503
-
504
- const umzug = await getUmzug()
505
- await umzug.up()
506
- }
507
-
508
- async function runMigrations() {
509
- console.log('Run migrations...')
510
- const umzug = await getUmzug()
511
- await umzug.up()
512
- }
513
-
514
- async function resetMigrations() {
515
- console.log('Reset migrations...')
516
- const umzug = await getUmzug()
517
- await umzug.down({ to: 0 })
518
- }
519
-
520
- async function freshMigrations() {
521
- console.log('Fresh migrations...')
522
- await resetMigrations()
523
- await runMigrations()
524
- }
525
-
526
- async function rollbackMigrations(step = 1) {
527
- console.log('Rollback migrations...')
528
- const umzug = await getUmzug()
529
- await umzug.down({ step: step })
530
- }