@lenne.tech/nest-server 8.6.15 → 8.6.18
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/dist/config.env.js +54 -0
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/interfaces/cron-job-config.interface.d.ts +12 -0
- package/dist/core/common/interfaces/cron-job-config.interface.js +3 -0
- package/dist/core/common/interfaces/cron-job-config.interface.js.map +1 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +4 -0
- package/dist/core/common/services/core-cron-jobs.service.d.ts +15 -0
- package/dist/core/common/services/core-cron-jobs.service.js +54 -0
- package/dist/core/common/services/core-cron-jobs.service.js.map +1 -0
- package/dist/core/common/services/crud.service.d.ts +13 -2
- package/dist/core/common/services/crud.service.js +31 -5
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/types/falsy.type.d.ts +1 -0
- package/dist/core/common/types/falsy.type.js +3 -0
- package/dist/core/common/types/falsy.type.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/server/common/services/cron-jobs.service.d.ts +7 -0
- package/dist/server/common/services/cron-jobs.service.js +31 -0
- package/dist/server/common/services/cron-jobs.service.js.map +1 -0
- package/dist/server/server.module.js +4 -0
- package/dist/server/server.module.js.map +1 -1
- package/dist/test/test.helper.d.ts +2 -0
- package/dist/test/test.helper.js +38 -1
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -2
- package/src/config.env.ts +58 -0
- package/src/core/common/interfaces/cron-job-config.interface.ts +52 -0
- package/src/core/common/interfaces/server-options.interface.ts +9 -0
- package/src/core/common/services/core-cron-jobs.service.ts +101 -0
- package/src/core/common/services/crud.service.ts +54 -7
- package/src/core/common/types/falsy.type.ts +4 -0
- package/src/index.ts +3 -0
- package/src/server/common/services/cron-jobs.service.ts +26 -0
- package/src/server/server.module.ts +7 -0
- package/src/test/test.helper.ts +47 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "8.6.
|
|
3
|
+
"version": "8.6.18",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
"reinit": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i && npm run test:e2e && npm run build",
|
|
27
27
|
"reinit:force": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i --force && npm run test:e2e",
|
|
28
28
|
"reinit:legacy": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i --legacy-peer-deps && npm run test:e2e",
|
|
29
|
-
"start": "npm run start:
|
|
29
|
+
"start": "npm run start:local",
|
|
30
30
|
"stop": "./node_modules/.bin/pm2 delete nest",
|
|
31
31
|
"start:pm2": "./node_modules/.bin/grunt",
|
|
32
32
|
"start:prod": "./node_modules/.bin/grunt productive",
|
|
33
33
|
"start:nodemon": "ts-node -r tsconfig-paths/register src/main.ts",
|
|
34
34
|
"start:debug": "nodemon --config nodemon-debug.json",
|
|
35
35
|
"start:dev": "nodemon",
|
|
36
|
+
"start:local": "NODE_ENV=local nodemon",
|
|
36
37
|
"test": "NODE_ENV=local jest",
|
|
37
38
|
"test:cov": "NODE_ENV=local jest --coverage",
|
|
38
39
|
"test:debug": "NODE_ENV=local node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"@nestjs/mongoose": "9.1.1",
|
|
67
68
|
"@nestjs/passport": "8.2.2",
|
|
68
69
|
"@nestjs/platform-express": "8.4.7",
|
|
70
|
+
"@nestjs/schedule": "2.0.1",
|
|
69
71
|
"apollo-server-core": "3.9.0",
|
|
70
72
|
"apollo-server-express": "3.9.0",
|
|
71
73
|
"bcrypt": "5.0.1",
|
|
@@ -93,6 +95,7 @@
|
|
|
93
95
|
},
|
|
94
96
|
"devDependencies": {
|
|
95
97
|
"@nestjs/testing": "8.4.7",
|
|
98
|
+
"@types/cron": "2.0.0",
|
|
96
99
|
"@types/ejs": "3.1.1",
|
|
97
100
|
"@types/jest": "28.1.3",
|
|
98
101
|
"@types/lodash": "4.14.182",
|
package/src/config.env.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CronExpression } from '@nestjs/schedule';
|
|
1
2
|
import { join } from 'path';
|
|
2
3
|
import { IServerOptions } from './core/common/interfaces/server-options.interface';
|
|
3
4
|
|
|
@@ -5,6 +6,63 @@ import { IServerOptions } from './core/common/interfaces/server-options.interfac
|
|
|
5
6
|
* Configuration for the different environments
|
|
6
7
|
*/
|
|
7
8
|
const config: { [env: string]: IServerOptions } = {
|
|
9
|
+
// ===========================================================================
|
|
10
|
+
// Local environment
|
|
11
|
+
// ===========================================================================
|
|
12
|
+
local: {
|
|
13
|
+
cronJobs: {
|
|
14
|
+
sayHello: {
|
|
15
|
+
cronTime: CronExpression.EVERY_5_MINUTES,
|
|
16
|
+
timeZone: 'Europe/Berlin',
|
|
17
|
+
runOnInit: false,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
email: {
|
|
21
|
+
smtp: {
|
|
22
|
+
auth: {
|
|
23
|
+
user: 'rebeca68@ethereal.email',
|
|
24
|
+
pass: 'v5WUScAN98AzGbRjpc',
|
|
25
|
+
},
|
|
26
|
+
host: 'smtp.ethereal.email',
|
|
27
|
+
port: 587,
|
|
28
|
+
secure: false,
|
|
29
|
+
},
|
|
30
|
+
mailjet: {
|
|
31
|
+
api_key_public: 'MAILJET_API_KEY_PUBLIC',
|
|
32
|
+
api_key_private: 'MAILJET_API_KEY_PRIVATE',
|
|
33
|
+
},
|
|
34
|
+
defaultSender: {
|
|
35
|
+
email: 'rebeca68@ethereal.email',
|
|
36
|
+
name: 'Rebeca Sixtyeight',
|
|
37
|
+
},
|
|
38
|
+
verificationLink: 'http://localhost:4200/user/verification',
|
|
39
|
+
passwordResetLink: 'http://localhost:4200/user/password-reset',
|
|
40
|
+
},
|
|
41
|
+
env: 'local',
|
|
42
|
+
execAfterInit: 'npm run docs:bootstrap',
|
|
43
|
+
graphQl: {
|
|
44
|
+
driver: {
|
|
45
|
+
debug: true,
|
|
46
|
+
introspection: true,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
jwt: {
|
|
50
|
+
secret: 'SECRET_OR_PRIVATE_KEY_DEV',
|
|
51
|
+
},
|
|
52
|
+
mongoose: {
|
|
53
|
+
uri: 'mongodb://localhost/nest-server-dev',
|
|
54
|
+
},
|
|
55
|
+
port: 3000,
|
|
56
|
+
staticAssets: {
|
|
57
|
+
path: join(__dirname, '..', 'public'),
|
|
58
|
+
options: { prefix: '' },
|
|
59
|
+
},
|
|
60
|
+
templates: {
|
|
61
|
+
path: join(__dirname, 'templates'),
|
|
62
|
+
engine: 'ejs',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
|
|
8
66
|
// ===========================================================================
|
|
9
67
|
// Development environment
|
|
10
68
|
// ===========================================================================
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CronExpression } from '@nestjs/schedule';
|
|
2
|
+
import { CronCommand } from 'cron';
|
|
3
|
+
import { Falsy } from '../types/falsy.type';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Interface for cron job configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface CronJobConfig {
|
|
9
|
+
/**
|
|
10
|
+
* The context within which to execute the onTick method. This defaults to the cronjob itself allowing you to call
|
|
11
|
+
* `this.stop()`. However, if you change this you'll have access to the functions and values within your context
|
|
12
|
+
* object.
|
|
13
|
+
*/
|
|
14
|
+
context?: any;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The time to fire off your job. This can be in the form of cron syntax or a JS `Date` object.
|
|
18
|
+
*/
|
|
19
|
+
cronTime: CronExpression | string | Date | Falsy;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A function that will fire when the job is complete, when it is stopped.
|
|
23
|
+
*/
|
|
24
|
+
onComplete?: CronCommand | null;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This will immediately fire your `onTickfunction as soon as the requisit initialization has happened.
|
|
28
|
+
* This option is set to ``true``` by default.
|
|
29
|
+
*/
|
|
30
|
+
runOnInit?: boolean;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Specify the timezone for the execution. This will modify the actual time relative to your timezone.
|
|
34
|
+
* If the timezone is invalid, an error is thrown. Can be any string accepted by luxon's `DateTime.setZone()`
|
|
35
|
+
* (https://moment.github.io/luxon/api-docs/index.html#datetimesetzone).
|
|
36
|
+
*/
|
|
37
|
+
timeZone?: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* If you have code that keeps the event loop running and want to stop the node process when that finishes
|
|
41
|
+
* regardless of the state of your cronjob, you can do so making use of this parameter. This is off by default and
|
|
42
|
+
* cron will run as if it needs to control the event loop. For more information take a look at
|
|
43
|
+
* timers#timers_timeout_unref from the NodeJS docs.
|
|
44
|
+
*/
|
|
45
|
+
unrefTimeout?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* This allows you to specify the offset of your timezone rather than using the `timeZoneparam.
|
|
49
|
+
* Probably don't use both ``timeZone` andutcOffset`` together or weird things may happen.
|
|
50
|
+
*/
|
|
51
|
+
utcOffset?: string | number;
|
|
52
|
+
}
|
|
@@ -3,13 +3,22 @@ import { GqlModuleAsyncOptions } from '@nestjs/graphql';
|
|
|
3
3
|
import { JwtModuleOptions } from '@nestjs/jwt';
|
|
4
4
|
import { MongooseModuleOptions } from '@nestjs/mongoose';
|
|
5
5
|
import { ServeStaticOptions } from '@nestjs/platform-express/interfaces/serve-static-options.interface';
|
|
6
|
+
import { CronExpression } from '@nestjs/schedule';
|
|
6
7
|
import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
|
|
8
|
+
import { Falsy } from '../types/falsy.type';
|
|
9
|
+
import { CronJobConfig } from './cron-job-config.interface';
|
|
7
10
|
import { MailjetOptions } from './mailjet-options.interface';
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* Options for the server
|
|
11
14
|
*/
|
|
12
15
|
export interface IServerOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Cron jobs configuration object with the name of the cron job function as key
|
|
18
|
+
* and the cron expression or config as value
|
|
19
|
+
*/
|
|
20
|
+
cronJobs?: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>;
|
|
21
|
+
|
|
13
22
|
/**
|
|
14
23
|
* SMTP and template configuration for sending emails
|
|
15
24
|
*/
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CronExpression, SchedulerRegistry } from '@nestjs/schedule';
|
|
2
|
+
import { CronJob } from 'cron';
|
|
3
|
+
import { CronJobConfig } from '../interfaces/cron-job-config.interface';
|
|
4
|
+
import { Falsy } from '../types/falsy.type';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cron jobs service to extend
|
|
8
|
+
*/
|
|
9
|
+
export abstract class CoreCronJobs {
|
|
10
|
+
/**
|
|
11
|
+
* Config for cron jobs
|
|
12
|
+
*/
|
|
13
|
+
config: {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
log: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// ===================================================================================================================
|
|
19
|
+
// Initializations
|
|
20
|
+
// ===================================================================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Integrate services and init chron jobs
|
|
24
|
+
*/
|
|
25
|
+
protected constructor(
|
|
26
|
+
protected schedulerRegistry: SchedulerRegistry,
|
|
27
|
+
protected cronJobs: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>,
|
|
28
|
+
options?: { log?: boolean }
|
|
29
|
+
) {
|
|
30
|
+
this.config = {
|
|
31
|
+
log: true,
|
|
32
|
+
...options,
|
|
33
|
+
};
|
|
34
|
+
this.initCronJobs();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Init cron jobs
|
|
39
|
+
*/
|
|
40
|
+
protected initCronJobs() {
|
|
41
|
+
// Get cron jobs
|
|
42
|
+
if (!this.cronJobs) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Init cron jobs
|
|
47
|
+
for (const [name, CronExpressionOrConfig] of Object.entries(this.cronJobs)) {
|
|
48
|
+
// Check config
|
|
49
|
+
if (!CronExpressionOrConfig) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Prepare config
|
|
54
|
+
let config: CronExpression | string | Date | Falsy | CronJobConfig = CronExpressionOrConfig;
|
|
55
|
+
if (typeof config === 'string' || config instanceof Date) {
|
|
56
|
+
config = {
|
|
57
|
+
cronTime: config,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Set defaults
|
|
62
|
+
config = {
|
|
63
|
+
timeZone: 'Europe/Berlin',
|
|
64
|
+
runOnInit: true,
|
|
65
|
+
...config,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Check if cron job should be activated
|
|
69
|
+
if (!config?.cronTime) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// check if cron job exists
|
|
74
|
+
if (!this[name]) {
|
|
75
|
+
if (this.config.log) {
|
|
76
|
+
console.log('Missing cron job function ' + name);
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Init cron job
|
|
82
|
+
const job = new CronJob(
|
|
83
|
+
config.cronTime,
|
|
84
|
+
() => {
|
|
85
|
+
this[name]();
|
|
86
|
+
},
|
|
87
|
+
null,
|
|
88
|
+
true,
|
|
89
|
+
config.timeZone,
|
|
90
|
+
config.context,
|
|
91
|
+
config.runOnInit,
|
|
92
|
+
config.utcOffset,
|
|
93
|
+
config.unrefTimeout
|
|
94
|
+
);
|
|
95
|
+
this.schedulerRegistry.addCronJob(name, job);
|
|
96
|
+
if (this.config.log && this.schedulerRegistry.getCronJob(name)) {
|
|
97
|
+
console.log(`CronJob ${name} initialized with "${config.cronTime}"`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { NotFoundException } from '@nestjs/common';
|
|
2
|
+
import { FilterQuery, QueryOptions } from 'mongoose';
|
|
2
3
|
import { FilterArgs } from '../args/filter.args';
|
|
3
4
|
import { merge } from '../helpers/config.helper';
|
|
5
|
+
import { getStringIds } from '../helpers/db.helper';
|
|
4
6
|
import { convertFilterArgsToQuery } from '../helpers/filter.helper';
|
|
5
7
|
import { assignPlain } from '../helpers/input.helper';
|
|
6
8
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
@@ -12,7 +14,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
12
14
|
* Create item
|
|
13
15
|
*/
|
|
14
16
|
async create(input: any, serviceOptions?: ServiceOptions): Promise<T> {
|
|
15
|
-
merge({ prepareInput: { create: true } }, serviceOptions);
|
|
17
|
+
serviceOptions = merge({ prepareInput: { create: true } }, serviceOptions);
|
|
16
18
|
return this.process(
|
|
17
19
|
async (data) => {
|
|
18
20
|
const currentUserId = serviceOptions?.currentUser?.id;
|
|
@@ -36,16 +38,55 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
36
38
|
/**
|
|
37
39
|
* Get items via filter
|
|
38
40
|
*/
|
|
39
|
-
async find(
|
|
41
|
+
async find(
|
|
42
|
+
filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
43
|
+
serviceOptions?: ServiceOptions
|
|
44
|
+
): Promise<T[]> {
|
|
40
45
|
return this.process(
|
|
41
46
|
async (data) => {
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
// Prepare filter query
|
|
48
|
+
const filterQuery = { filterQuery: data?.input?.filterQuery, queryOptions: data?.input?.queryOptions };
|
|
49
|
+
if (data?.input instanceof FilterArgs) {
|
|
50
|
+
const converted = convertFilterArgsToQuery(data.input);
|
|
51
|
+
filterQuery.filterQuery = converted[0];
|
|
52
|
+
filterQuery.queryOptions = converted[1];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Find in DB
|
|
56
|
+
return this.mainDbModel.find(filterQuery.filterQuery, null, filterQuery.queryOptions).exec();
|
|
44
57
|
},
|
|
45
|
-
{ input:
|
|
58
|
+
{ input: filter, serviceOptions }
|
|
46
59
|
);
|
|
47
60
|
}
|
|
48
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Find and update
|
|
64
|
+
*/
|
|
65
|
+
async findAndUpdate(
|
|
66
|
+
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
67
|
+
update: any,
|
|
68
|
+
serviceOptions?: ServiceOptions
|
|
69
|
+
): Promise<T[]> {
|
|
70
|
+
const dbItems: T[] = await this.find(filter, serviceOptions);
|
|
71
|
+
if (!dbItems?.length) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const promises: Promise<T>[] = [];
|
|
75
|
+
for (const dbItem of dbItems) {
|
|
76
|
+
promises.push(
|
|
77
|
+
new Promise(async (resolve, reject) => {
|
|
78
|
+
try {
|
|
79
|
+
const item = await this.update(getStringIds(dbItem as any), update, serviceOptions);
|
|
80
|
+
resolve(item);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
reject(e);
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return await Promise.all(promises);
|
|
88
|
+
}
|
|
89
|
+
|
|
49
90
|
/**
|
|
50
91
|
* CRUD alias for get
|
|
51
92
|
*/
|
|
@@ -54,12 +95,18 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
54
95
|
/**
|
|
55
96
|
* CRUD alias for find
|
|
56
97
|
*/
|
|
57
|
-
async read(
|
|
98
|
+
async read(
|
|
99
|
+
filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
100
|
+
serviceOptions?: ServiceOptions
|
|
101
|
+
): Promise<T[]>;
|
|
58
102
|
|
|
59
103
|
/**
|
|
60
104
|
* CRUD alias for get or find
|
|
61
105
|
*/
|
|
62
|
-
async read(
|
|
106
|
+
async read(
|
|
107
|
+
input: string | FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
|
|
108
|
+
serviceOptions?: ServiceOptions
|
|
109
|
+
): Promise<T | T[]> {
|
|
63
110
|
if (typeof input === 'string') {
|
|
64
111
|
return this.get(input, serviceOptions);
|
|
65
112
|
} else {
|
package/src/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ export * from './core/common/inputs/single-filter.input';
|
|
|
34
34
|
export * from './core/common/inputs/sort.input';
|
|
35
35
|
export * from './core/common/interceptors/check-response.interceptor';
|
|
36
36
|
export * from './core/common/interfaces/core-persistence-model.interface';
|
|
37
|
+
export * from './core/common/interfaces/cron-job-config.interface';
|
|
37
38
|
export * from './core/common/interfaces/mailjet-options.interface';
|
|
38
39
|
export * from './core/common/interfaces/prepare-input-options.interface';
|
|
39
40
|
export * from './core/common/interfaces/prepare-output-options.interface';
|
|
@@ -48,12 +49,14 @@ export * from './core/common/scalars/any.scalar';
|
|
|
48
49
|
export * from './core/common/scalars/date.scalar';
|
|
49
50
|
export * from './core/common/scalars/json.scalar';
|
|
50
51
|
export * from './core/common/services/config.service';
|
|
52
|
+
export * from './core/common/services/core-cron-jobs.service';
|
|
51
53
|
export * from './core/common/services/crud.service';
|
|
52
54
|
export * from './core/common/services/email.service';
|
|
53
55
|
export * from './core/common/services/mailjet.service';
|
|
54
56
|
export * from './core/common/services/module.service';
|
|
55
57
|
export * from './core/common/services/template.service';
|
|
56
58
|
export * from './core/common/types/core-model-constructor.type';
|
|
59
|
+
export * from './core/common/types/falsy.type';
|
|
57
60
|
export * from './core/common/types/field-selection.type';
|
|
58
61
|
export * from './core/common/types/ids.type';
|
|
59
62
|
export * from './core/common/types/maybe-promise.type';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { SchedulerRegistry } from '@nestjs/schedule';
|
|
3
|
+
import envConfig from '../../../config.env';
|
|
4
|
+
import { CoreCronJobs } from '../../../core/common/services/core-cron-jobs.service';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class CronJobs extends CoreCronJobs {
|
|
8
|
+
// ===================================================================================================================
|
|
9
|
+
// Initializations
|
|
10
|
+
// ===================================================================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Init cron jobs
|
|
14
|
+
*/
|
|
15
|
+
constructor(protected schedulerRegistry: SchedulerRegistry) {
|
|
16
|
+
super(schedulerRegistry, envConfig.cronJobs, { log: true });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ===================================================================================================================
|
|
20
|
+
// Cron jobs
|
|
21
|
+
// ===================================================================================================================
|
|
22
|
+
|
|
23
|
+
protected sayHello() {
|
|
24
|
+
console.log('Hello :)');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
|
+
import { ScheduleModule } from '@nestjs/schedule';
|
|
2
3
|
import envConfig from '../config.env';
|
|
3
4
|
import { CoreModule } from '../core.module';
|
|
4
5
|
import { CoreAuthService } from '../core/modules/auth/services/core-auth.service';
|
|
6
|
+
import { CronJobs } from './common/services/cron-jobs.service';
|
|
5
7
|
import { AuthModule } from './modules/auth/auth.module';
|
|
6
8
|
import { FileModule } from './modules/file/file.module';
|
|
7
9
|
import { ServerController } from './server.controller';
|
|
@@ -18,6 +20,9 @@ import { ServerController } from './server.controller';
|
|
|
18
20
|
// Include CoreModule for standard processes
|
|
19
21
|
CoreModule.forRoot(CoreAuthService, AuthModule.forRoot(envConfig.jwt), envConfig),
|
|
20
22
|
|
|
23
|
+
// Include cron job handling
|
|
24
|
+
ScheduleModule.forRoot(),
|
|
25
|
+
|
|
21
26
|
// Include AuthModule for authorization handling,
|
|
22
27
|
// which will also include UserModule
|
|
23
28
|
AuthModule.forRoot(envConfig.jwt),
|
|
@@ -26,6 +31,8 @@ import { ServerController } from './server.controller';
|
|
|
26
31
|
FileModule,
|
|
27
32
|
],
|
|
28
33
|
|
|
34
|
+
providers: [CronJobs],
|
|
35
|
+
|
|
29
36
|
// Include REST controllers
|
|
30
37
|
controllers: [ServerController],
|
|
31
38
|
|
package/src/test/test.helper.ts
CHANGED
|
@@ -4,10 +4,12 @@ import * as fs from 'fs';
|
|
|
4
4
|
import { createClient } from 'graphql-ws';
|
|
5
5
|
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
|
6
6
|
import * as LightMyRequest from 'light-my-request';
|
|
7
|
+
import { Types } from 'mongoose';
|
|
7
8
|
import * as superagent from 'superagent';
|
|
8
9
|
import * as supertest from 'supertest';
|
|
9
10
|
import * as util from 'util';
|
|
10
11
|
import * as ws from 'ws';
|
|
12
|
+
import { getStringIds } from '../core/common/helpers/db.helper';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* GraphQL request type
|
|
@@ -98,6 +100,11 @@ export interface TestGraphQLOptions {
|
|
|
98
100
|
*/
|
|
99
101
|
logError?: boolean;
|
|
100
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Whether to prepare arguments (like dates)
|
|
105
|
+
*/
|
|
106
|
+
prepareArguments?: boolean;
|
|
107
|
+
|
|
101
108
|
/**
|
|
102
109
|
* Status Code = 400
|
|
103
110
|
*/
|
|
@@ -187,6 +194,7 @@ export class TestHelper {
|
|
|
187
194
|
statusCode: 200,
|
|
188
195
|
log: false,
|
|
189
196
|
logError: false,
|
|
197
|
+
prepareArguments: true,
|
|
190
198
|
...options,
|
|
191
199
|
};
|
|
192
200
|
|
|
@@ -233,7 +241,9 @@ export class TestHelper {
|
|
|
233
241
|
|
|
234
242
|
// Set arguments
|
|
235
243
|
if (graphql.arguments) {
|
|
236
|
-
queryObj[graphql.type][graphql.name].__args =
|
|
244
|
+
queryObj[graphql.type][graphql.name].__args = config.prepareArguments
|
|
245
|
+
? this.prepareArguments(graphql.arguments)
|
|
246
|
+
: graphql.arguments;
|
|
237
247
|
}
|
|
238
248
|
|
|
239
249
|
// Create request payload query
|
|
@@ -330,6 +340,39 @@ export class TestHelper {
|
|
|
330
340
|
return result;
|
|
331
341
|
}
|
|
332
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Prepare arguments
|
|
345
|
+
*/
|
|
346
|
+
prepareArguments(args: any, objects?: WeakMap<any, any>) {
|
|
347
|
+
if (!args) {
|
|
348
|
+
return args;
|
|
349
|
+
}
|
|
350
|
+
if (args instanceof Date) {
|
|
351
|
+
return args.toISOString();
|
|
352
|
+
}
|
|
353
|
+
if (args instanceof Types.ObjectId) {
|
|
354
|
+
return getStringIds(args);
|
|
355
|
+
}
|
|
356
|
+
if (!objects) {
|
|
357
|
+
objects = new WeakMap<any, any>();
|
|
358
|
+
}
|
|
359
|
+
if (typeof args === 'object' && objects.get(args)) {
|
|
360
|
+
return objects.get(args);
|
|
361
|
+
}
|
|
362
|
+
if (Array.isArray(args)) {
|
|
363
|
+
objects.set(args, args);
|
|
364
|
+
return args.map((item) => this.prepareArguments(item, objects));
|
|
365
|
+
}
|
|
366
|
+
if (typeof args === 'object') {
|
|
367
|
+
objects.set(args, args);
|
|
368
|
+
for (const [key, value] of Object.entries(args)) {
|
|
369
|
+
args[key] = this.prepareArguments(value, objects);
|
|
370
|
+
}
|
|
371
|
+
return args;
|
|
372
|
+
}
|
|
373
|
+
return args;
|
|
374
|
+
}
|
|
375
|
+
|
|
333
376
|
/**
|
|
334
377
|
* Prepare GraphQL fields for request
|
|
335
378
|
* @param fields
|
|
@@ -424,6 +467,9 @@ export class TestHelper {
|
|
|
424
467
|
}
|
|
425
468
|
|
|
426
469
|
// Response
|
|
470
|
+
if (log) {
|
|
471
|
+
console.log(requestConfig);
|
|
472
|
+
}
|
|
427
473
|
const response = await (variables ? request : request.send(requestConfig.payload));
|
|
428
474
|
return this.processResponse(response, statusCode, log, logError);
|
|
429
475
|
}
|