@lenne.tech/nest-server 11.1.14 → 11.2.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/dist/core/common/helpers/gridfs.helper.d.ts +42 -0
- package/dist/core/common/helpers/gridfs.helper.js +107 -0
- package/dist/core/common/helpers/gridfs.helper.js.map +1 -0
- package/dist/core/common/services/brevo.service.d.ts +1 -0
- package/dist/core/common/services/brevo.service.js +19 -18
- package/dist/core/common/services/brevo.service.js.map +1 -1
- package/dist/core/common/services/crud.service.js +1 -1
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/modules/file/core-file.controller.d.ts +2 -1
- package/dist/core/modules/file/core-file.controller.js +1 -1
- package/dist/core/modules/file/core-file.controller.js.map +1 -1
- package/dist/core/modules/file/core-file.service.d.ts +7 -7
- package/dist/core/modules/file/core-file.service.js +28 -51
- package/dist/core/modules/file/core-file.service.js.map +1 -1
- package/dist/core/modules/file/interfaces/file-upload.interface.d.ts +1 -1
- package/dist/core/modules/user/core-user.service.js +2 -3
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/file/file-info.model.d.ts +7 -3
- package/dist/server/modules/file/file.controller.d.ts +6 -4
- package/dist/server/modules/file/file.controller.js +15 -4
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/file/file.resolver.js +1 -1
- package/dist/server/modules/file/file.resolver.js.map +1 -1
- package/dist/server/modules/file/multer-config.service.d.ts +0 -2
- package/dist/server/modules/file/multer-config.service.js +3 -22
- package/dist/server/modules/file/multer-config.service.js.map +1 -1
- package/dist/server/modules/user/user.model.d.ts +7 -3
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/graphql-upload.d.ts +25 -0
- package/package.json +21 -23
- package/src/core/common/helpers/gridfs.helper.ts +227 -0
- package/src/core/common/services/brevo.service.ts +20 -18
- package/src/core/common/services/crud.service.ts +3 -3
- package/src/core/modules/file/core-file.controller.ts +3 -2
- package/src/core/modules/file/core-file.service.ts +49 -60
- package/src/core/modules/file/interfaces/file-upload.interface.ts +2 -1
- package/src/core/modules/user/core-user.service.ts +3 -3
- package/src/index.ts +1 -0
- package/src/server/modules/file/file.controller.ts +25 -7
- package/src/server/modules/file/file.resolver.ts +1 -2
- package/src/server/modules/file/multer-config.service.ts +6 -21
- package/src/types/graphql-upload.d.ts +25 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for graphql-upload
|
|
3
|
+
* graphql-upload uses deep imports, so we declare types for the specific modules
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module 'graphql-upload/graphqlUploadExpress.js' {
|
|
7
|
+
import { RequestHandler } from 'express';
|
|
8
|
+
|
|
9
|
+
interface GraphQLUploadOptions {
|
|
10
|
+
maxFiles?: number;
|
|
11
|
+
maxFileSize?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function graphqlUploadExpress(options?: GraphQLUploadOptions): RequestHandler;
|
|
15
|
+
|
|
16
|
+
export = graphqlUploadExpress;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module 'graphql-upload/GraphQLUpload.js' {
|
|
20
|
+
import { GraphQLScalarType } from 'graphql';
|
|
21
|
+
|
|
22
|
+
const GraphQLUpload: GraphQLScalarType;
|
|
23
|
+
|
|
24
|
+
export = GraphQLUpload;
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.2.0",
|
|
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",
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"homepage": "https://github.com/lenneTech/nest-server",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "rimraf dist && nest build",
|
|
17
|
+
"build": "rimraf dist && nest build && npm run build:copy-types && npm run build:add-type-references",
|
|
18
|
+
"build:copy-types": "mkdir -p dist/types && cp src/types/*.d.ts dist/types/",
|
|
19
|
+
"build:add-type-references": "node scripts/add-type-references.js",
|
|
18
20
|
"build:pack": "npm pack && echo 'use file:/ROOT_PATH_TO_TGZ_FILE to integrate the package'",
|
|
19
21
|
"build:dev": "npm run build && yalc push --private",
|
|
20
22
|
"docs": "npm run docs:ci && open http://127.0.0.1:8080/ && open ./public/index.html && compodoc -p tsconfig.json -s ",
|
|
@@ -65,15 +67,13 @@
|
|
|
65
67
|
"node": ">= 20"
|
|
66
68
|
},
|
|
67
69
|
"dependencies": {
|
|
68
|
-
"@apollo/gateway": "2.11.
|
|
69
|
-
"@getbrevo/brevo": "
|
|
70
|
-
"@lenne.tech/mongoose-gridfs": "1.4.2",
|
|
71
|
-
"@lenne.tech/multer-gridfs-storage": "5.0.8",
|
|
70
|
+
"@apollo/gateway": "2.11.3",
|
|
71
|
+
"@getbrevo/brevo": "3.0.1",
|
|
72
72
|
"@nestjs/apollo": "13.1.0",
|
|
73
73
|
"@nestjs/common": "11.1.6",
|
|
74
74
|
"@nestjs/core": "11.1.6",
|
|
75
75
|
"@nestjs/graphql": "13.1.0",
|
|
76
|
-
"@nestjs/jwt": "11.0.
|
|
76
|
+
"@nestjs/jwt": "11.0.1",
|
|
77
77
|
"@nestjs/mongoose": "11.0.3",
|
|
78
78
|
"@nestjs/passport": "11.0.5",
|
|
79
79
|
"@nestjs/platform-express": "11.1.6",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@nestjs/terminus": "11.0.0",
|
|
83
83
|
"apollo-server-core": "3.13.0",
|
|
84
84
|
"apollo-server-express": "3.13.0",
|
|
85
|
-
"bcrypt": "
|
|
85
|
+
"bcrypt": "6.0.0",
|
|
86
86
|
"class-transformer": "0.5.1",
|
|
87
87
|
"class-validator": "0.14.2",
|
|
88
88
|
"compression": "1.8.1",
|
|
@@ -98,8 +98,8 @@
|
|
|
98
98
|
"light-my-request": "6.6.0",
|
|
99
99
|
"lodash": "4.17.21",
|
|
100
100
|
"mongodb": "6.20.0",
|
|
101
|
-
"mongoose": "
|
|
102
|
-
"multer": "
|
|
101
|
+
"mongoose": "8.19.1",
|
|
102
|
+
"multer": "2.0.2",
|
|
103
103
|
"node-mailjet": "6.0.9",
|
|
104
104
|
"nodemailer": "7.0.9",
|
|
105
105
|
"nodemon": "3.1.10",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"@compodoc/compodoc": "1.1.31",
|
|
117
117
|
"@lenne.tech/eslint-config-ts": "2.1.3",
|
|
118
118
|
"@nestjs/cli": "11.0.10",
|
|
119
|
-
"@nestjs/schematics": "11.0.
|
|
119
|
+
"@nestjs/schematics": "11.0.9",
|
|
120
120
|
"@nestjs/testing": "11.1.6",
|
|
121
121
|
"@swc/cli": "0.7.8",
|
|
122
122
|
"@swc/core": "1.13.5",
|
|
@@ -125,11 +125,11 @@
|
|
|
125
125
|
"@types/cookie-parser": "1.4.9",
|
|
126
126
|
"@types/ejs": "3.1.5",
|
|
127
127
|
"@types/express": "4.17.21",
|
|
128
|
-
"@types/jest": "
|
|
128
|
+
"@types/jest": "30.0.0",
|
|
129
129
|
"@types/lodash": "4.17.20",
|
|
130
|
-
"@types/multer": "
|
|
131
|
-
"@types/node": "
|
|
132
|
-
"@types/nodemailer": "
|
|
130
|
+
"@types/multer": "2.0.0",
|
|
131
|
+
"@types/node": "24.7.1",
|
|
132
|
+
"@types/nodemailer": "7.0.2",
|
|
133
133
|
"@types/passport": "1.0.17",
|
|
134
134
|
"@types/supertest": "6.0.3",
|
|
135
135
|
"@typescript-eslint/eslint-plugin": "8.46.0",
|
|
@@ -145,28 +145,26 @@
|
|
|
145
145
|
"grunt-contrib-watch": "1.1.0",
|
|
146
146
|
"grunt-sync": "0.8.2",
|
|
147
147
|
"husky": "9.1.7",
|
|
148
|
-
"jest": "
|
|
148
|
+
"jest": "30.2.0",
|
|
149
149
|
"npm-watch": "0.13.0",
|
|
150
150
|
"pm2": "6.0.13",
|
|
151
151
|
"prettier": "3.6.2",
|
|
152
152
|
"pretty-quick": "4.2.2",
|
|
153
153
|
"supertest": "7.1.4",
|
|
154
|
-
"ts-jest": "29.4.
|
|
154
|
+
"ts-jest": "29.4.5",
|
|
155
155
|
"ts-loader": "9.5.4",
|
|
156
|
-
"ts-morph": "
|
|
156
|
+
"ts-morph": "27.0.0",
|
|
157
157
|
"ts-node": "10.9.2",
|
|
158
158
|
"tsconfig-paths": "4.2.0",
|
|
159
|
-
"typescript": "5.
|
|
159
|
+
"typescript": "5.9.3",
|
|
160
160
|
"yalc": "1.0.0-pre.53"
|
|
161
161
|
},
|
|
162
162
|
"overrides": {
|
|
163
|
-
"multer-gridfs-storage": {
|
|
164
|
-
"multer": "$multer"
|
|
165
|
-
},
|
|
166
163
|
"@lykmapipo/common": {
|
|
167
164
|
"flat": "5.0.2",
|
|
168
165
|
"mime": "2.6.0"
|
|
169
|
-
}
|
|
166
|
+
},
|
|
167
|
+
"ts-morph": "27.0.0"
|
|
170
168
|
},
|
|
171
169
|
"jest": {
|
|
172
170
|
"collectCoverage": true,
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { mongo, Types } from 'mongoose';
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
|
|
4
|
+
// Use Mongoose's MongoDB types to avoid BSON version conflicts
|
|
5
|
+
const ObjectId = Types.ObjectId;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* GridFS File Info interface matching the structure from GridFS
|
|
9
|
+
* This is the normalized structure with contentType at root level
|
|
10
|
+
*/
|
|
11
|
+
export interface GridFSFileInfo {
|
|
12
|
+
_id: Types.ObjectId;
|
|
13
|
+
chunkSize: number;
|
|
14
|
+
/**
|
|
15
|
+
* Content type of the file
|
|
16
|
+
* Note: Stored in metadata.contentType in MongoDB, normalized to root level by helper
|
|
17
|
+
*/
|
|
18
|
+
contentType?: string;
|
|
19
|
+
filename: string;
|
|
20
|
+
length: number;
|
|
21
|
+
metadata?: Record<string, any> & { contentType?: string };
|
|
22
|
+
uploadDate: Date;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Options for reading files from GridFS
|
|
27
|
+
*/
|
|
28
|
+
export interface GridFSReadOptions {
|
|
29
|
+
_id?: string | Types.ObjectId;
|
|
30
|
+
filename?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for writing files to GridFS
|
|
34
|
+
*/
|
|
35
|
+
export interface GridFSWriteOptions {
|
|
36
|
+
contentType?: string;
|
|
37
|
+
filename: string;
|
|
38
|
+
metadata?: Record<string, any>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type GridFSBucket = mongo.GridFSBucket;
|
|
42
|
+
|
|
43
|
+
type GridFSBucketReadStream = mongo.GridFSBucketReadStream;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Raw GridFS file structure as returned by MongoDB
|
|
47
|
+
* This is the internal structure before normalization
|
|
48
|
+
*/
|
|
49
|
+
interface RawGridFSFile {
|
|
50
|
+
_id: Types.ObjectId;
|
|
51
|
+
chunkSize: number;
|
|
52
|
+
filename: string;
|
|
53
|
+
length: number;
|
|
54
|
+
metadata?: Record<string, any> & { contentType?: string };
|
|
55
|
+
uploadDate: Date;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Helper class for GridFS operations using native MongoDB driver
|
|
60
|
+
* Provides Promise-based API for all GridFS operations
|
|
61
|
+
*/
|
|
62
|
+
export class GridFSHelper {
|
|
63
|
+
/**
|
|
64
|
+
* Normalize file info to ensure contentType is accessible at root level
|
|
65
|
+
* MongoDB stores contentType in metadata, but our API expects it at root
|
|
66
|
+
*/
|
|
67
|
+
private static normalizeFileInfo(fileInfo: RawGridFSFile): GridFSFileInfo {
|
|
68
|
+
return {
|
|
69
|
+
...fileInfo,
|
|
70
|
+
contentType: fileInfo.metadata?.contentType,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Write a file to GridFS from a stream
|
|
76
|
+
*/
|
|
77
|
+
static writeFileFromStream(
|
|
78
|
+
bucket: GridFSBucket,
|
|
79
|
+
stream: Readable,
|
|
80
|
+
options: GridFSWriteOptions,
|
|
81
|
+
): Promise<GridFSFileInfo> {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
// Store contentType in metadata to avoid deprecation warning
|
|
84
|
+
const metadata = { ...options.metadata };
|
|
85
|
+
if (options.contentType) {
|
|
86
|
+
metadata.contentType = options.contentType;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const uploadStream = bucket.openUploadStream(options.filename, {
|
|
90
|
+
metadata,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
uploadStream.on('error', (error) => {
|
|
94
|
+
reject(error);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
uploadStream.on('finish', () => {
|
|
98
|
+
// Fetch the file info after upload completes
|
|
99
|
+
bucket
|
|
100
|
+
.find({ _id: uploadStream.id })
|
|
101
|
+
.toArray()
|
|
102
|
+
.then((files) => {
|
|
103
|
+
if (files && files.length > 0) {
|
|
104
|
+
resolve(GridFSHelper.normalizeFileInfo(files[0]));
|
|
105
|
+
} else {
|
|
106
|
+
reject(new Error('File uploaded but metadata not found'));
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
.catch(reject);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
stream.pipe(uploadStream);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Read a file from GridFS to a buffer
|
|
118
|
+
*/
|
|
119
|
+
static readFileToBuffer(bucket: GridFSBucket, options: GridFSReadOptions): Promise<Buffer> {
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
const chunks: Buffer[] = [];
|
|
122
|
+
let downloadStream: GridFSBucketReadStream;
|
|
123
|
+
|
|
124
|
+
if (options._id) {
|
|
125
|
+
const objectId = typeof options._id === 'string' ? new ObjectId(options._id) : options._id;
|
|
126
|
+
downloadStream = bucket.openDownloadStream(objectId);
|
|
127
|
+
} else if (options.filename) {
|
|
128
|
+
downloadStream = bucket.openDownloadStreamByName(options.filename);
|
|
129
|
+
} else {
|
|
130
|
+
return reject(new Error('Either _id or filename must be provided'));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
downloadStream.on('data', (chunk) => {
|
|
134
|
+
chunks.push(chunk);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
downloadStream.on('error', (error) => {
|
|
138
|
+
reject(error);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
downloadStream.on('end', () => {
|
|
142
|
+
resolve(Buffer.concat(chunks));
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Find file metadata by ID
|
|
149
|
+
*/
|
|
150
|
+
static async findFileById(bucket: GridFSBucket, id: string | Types.ObjectId): Promise<GridFSFileInfo | null> {
|
|
151
|
+
const objectId = typeof id === 'string' ? new ObjectId(id) : id;
|
|
152
|
+
const files = await bucket.find({ _id: objectId }).toArray();
|
|
153
|
+
return files.length > 0 ? GridFSHelper.normalizeFileInfo(files[0]) : null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Find file metadata by filename
|
|
158
|
+
*/
|
|
159
|
+
static async findFileByName(bucket: GridFSBucket, filename: string): Promise<GridFSFileInfo | null> {
|
|
160
|
+
const files = await bucket.find({ filename }).toArray();
|
|
161
|
+
return files.length > 0 ? GridFSHelper.normalizeFileInfo(files[0]) : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Find files with filter and options
|
|
166
|
+
*/
|
|
167
|
+
static async findFiles(bucket: GridFSBucket, filter: any = {}, options: any = {}): Promise<GridFSFileInfo[]> {
|
|
168
|
+
const files = await bucket.find(filter, options).toArray();
|
|
169
|
+
return files.map(file => GridFSHelper.normalizeFileInfo(file));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Delete a file from GridFS
|
|
174
|
+
*/
|
|
175
|
+
static async deleteFile(bucket: GridFSBucket, id: string | Types.ObjectId): Promise<void> {
|
|
176
|
+
const objectId = typeof id === 'string' ? new ObjectId(id) : id;
|
|
177
|
+
await bucket.delete(objectId);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Open download stream by ID
|
|
182
|
+
*/
|
|
183
|
+
static openDownloadStream(bucket: GridFSBucket, id: string | Types.ObjectId): GridFSBucketReadStream {
|
|
184
|
+
const objectId = typeof id === 'string' ? new ObjectId(id) : id;
|
|
185
|
+
return bucket.openDownloadStream(objectId);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Open download stream by name
|
|
190
|
+
*/
|
|
191
|
+
static openDownloadStreamByName(bucket: GridFSBucket, filename: string): GridFSBucketReadStream {
|
|
192
|
+
return bucket.openDownloadStreamByName(filename);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Open upload stream
|
|
197
|
+
*/
|
|
198
|
+
static openUploadStream(
|
|
199
|
+
bucket: GridFSBucket,
|
|
200
|
+
filename: string,
|
|
201
|
+
options?: { contentType?: string },
|
|
202
|
+
): mongo.GridFSBucketWriteStream {
|
|
203
|
+
// Store contentType in metadata to avoid deprecation warning
|
|
204
|
+
if (options?.contentType) {
|
|
205
|
+
const metadata = { contentType: options.contentType };
|
|
206
|
+
return bucket.openUploadStream(filename, { metadata });
|
|
207
|
+
}
|
|
208
|
+
return bucket.openUploadStream(filename, options);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Open upload stream with specific ID
|
|
213
|
+
*/
|
|
214
|
+
static openUploadStreamWithId(
|
|
215
|
+
bucket: GridFSBucket,
|
|
216
|
+
id: Types.ObjectId,
|
|
217
|
+
filename: string,
|
|
218
|
+
options?: { contentType?: string },
|
|
219
|
+
): mongo.GridFSBucketWriteStream {
|
|
220
|
+
// Store contentType in metadata to avoid deprecation warning
|
|
221
|
+
if (options?.contentType) {
|
|
222
|
+
const metadata = { contentType: options.contentType };
|
|
223
|
+
return bucket.openUploadStreamWithId(id, filename, { metadata });
|
|
224
|
+
}
|
|
225
|
+
return bucket.openUploadStreamWithId(id, filename, options);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SendSmtpEmail, TransactionalEmailsApi, TransactionalEmailsApiApiKeys } from '@getbrevo/brevo';
|
|
2
2
|
import { Injectable } from '@nestjs/common';
|
|
3
3
|
|
|
4
4
|
import { ConfigService } from './config.service';
|
|
@@ -9,15 +9,15 @@ import { ConfigService } from './config.service';
|
|
|
9
9
|
@Injectable()
|
|
10
10
|
export class BrevoService {
|
|
11
11
|
brevoConfig: ConfigService['configFastButReadOnly']['brevo'];
|
|
12
|
+
private apiInstance: TransactionalEmailsApi;
|
|
12
13
|
|
|
13
14
|
constructor(protected configService: ConfigService) {
|
|
14
|
-
const defaultClient = brevo.ApiClient.instance;
|
|
15
|
-
const apiKey = defaultClient.authentications['api-key'];
|
|
16
15
|
this.brevoConfig = configService.configFastButReadOnly.brevo;
|
|
17
16
|
if (!this.brevoConfig) {
|
|
18
17
|
throw new Error('Brevo configuration not set!');
|
|
19
18
|
}
|
|
20
|
-
|
|
19
|
+
this.apiInstance = new TransactionalEmailsApi();
|
|
20
|
+
this.apiInstance.setApiKey(TransactionalEmailsApiApiKeys.apiKey, this.brevoConfig.apiKey);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -37,14 +37,15 @@ export class BrevoService {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Prepare data
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const sendSmtpEmail: SendSmtpEmail = {
|
|
41
|
+
params,
|
|
42
|
+
templateId,
|
|
43
|
+
to: [{ email: to }],
|
|
44
|
+
};
|
|
45
45
|
|
|
46
46
|
// Send email
|
|
47
|
-
|
|
47
|
+
const result = await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
48
|
+
return result.body;
|
|
48
49
|
} catch (error) {
|
|
49
50
|
console.error(error);
|
|
50
51
|
}
|
|
@@ -75,16 +76,17 @@ export class BrevoService {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
// Prepare data
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
const sendSmtpEmail: SendSmtpEmail = {
|
|
80
|
+
htmlContent: html,
|
|
81
|
+
params: options?.params,
|
|
82
|
+
sender: this.brevoConfig.sender,
|
|
83
|
+
subject,
|
|
84
|
+
to: [{ email: to }],
|
|
85
|
+
};
|
|
85
86
|
|
|
86
87
|
// Send email
|
|
87
|
-
|
|
88
|
+
const result = await this.apiInstance.sendTransacEmail(sendSmtpEmail);
|
|
89
|
+
return result.body;
|
|
88
90
|
} catch (error) {
|
|
89
91
|
console.error(error);
|
|
90
92
|
}
|
|
@@ -105,7 +105,7 @@ export abstract class CrudService<
|
|
|
105
105
|
* Get distinct values of a property
|
|
106
106
|
*/
|
|
107
107
|
distinct(property: string): Promise<string[]> {
|
|
108
|
-
return this.mainDbModel.distinct(property)
|
|
108
|
+
return this.mainDbModel.distinct(property).exec() as Promise<string[]>;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/**
|
|
@@ -178,7 +178,7 @@ export abstract class CrudService<
|
|
|
178
178
|
find = find.collation(collation);
|
|
179
179
|
}
|
|
180
180
|
if (serviceOptions?.select) {
|
|
181
|
-
find = find.select(serviceOptions.select);
|
|
181
|
+
find = find.select(serviceOptions.select) as any;
|
|
182
182
|
}
|
|
183
183
|
return find.exec();
|
|
184
184
|
},
|
|
@@ -401,7 +401,7 @@ export abstract class CrudService<
|
|
|
401
401
|
find = find.collation(collation);
|
|
402
402
|
}
|
|
403
403
|
if (serviceOptions?.select) {
|
|
404
|
-
find = find.select(serviceOptions.select);
|
|
404
|
+
find = find.select(serviceOptions.select) as any;
|
|
405
405
|
}
|
|
406
406
|
return find.exec();
|
|
407
407
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BadRequestException, Controller, Get, NotFoundException, Param, Res } from '@nestjs/common';
|
|
2
|
+
import { Response } from 'express';
|
|
2
3
|
|
|
3
4
|
import { Roles } from '../../common/decorators/roles.decorator';
|
|
4
5
|
import { RoleEnum } from '../../common/enums/role.enum';
|
|
@@ -20,7 +21,7 @@ export abstract class CoreFileController {
|
|
|
20
21
|
*/
|
|
21
22
|
@Get(':filename')
|
|
22
23
|
@Roles(RoleEnum.S_EVERYONE)
|
|
23
|
-
async getFile(@Param('filename') filename: string, @Res() res) {
|
|
24
|
+
async getFile(@Param('filename') filename: string, @Res() res: Response) {
|
|
24
25
|
if (!filename) {
|
|
25
26
|
throw new BadRequestException('Missing filename for download');
|
|
26
27
|
}
|
|
@@ -30,7 +31,7 @@ export abstract class CoreFileController {
|
|
|
30
31
|
throw new NotFoundException('File not found');
|
|
31
32
|
}
|
|
32
33
|
const filestream = await this.fileService.getFileStream(file.id);
|
|
33
|
-
res.header('Content-Type', file.contentType);
|
|
34
|
+
res.header('Content-Type', file.contentType || 'application/octet-stream');
|
|
34
35
|
res.header('Content-Disposition', `attachment; filename=${file.filename}`);
|
|
35
36
|
return filestream.pipe(res);
|
|
36
37
|
}
|