@drax/media-back 3.50.0 → 3.51.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.
@@ -1,7 +1,6 @@
1
1
  import FileServiceFactory from "../factory/services/FileServiceFactory.js";
2
2
  import { AbstractFastifyController } from "@drax/crud-back";
3
3
  import FilePermissions from "../permissions/FilePermissions.js";
4
- import { StoreManager } from "@drax/common-back";
5
4
  class FileController extends AbstractFastifyController {
6
5
  constructor() {
7
6
  super(FileServiceFactory.instance, FilePermissions);
@@ -24,15 +23,6 @@ class FileController extends AbstractFastifyController {
24
23
  };
25
24
  return payload;
26
25
  }
27
- async postDelete(request, item) {
28
- try {
29
- await StoreManager.deleteFilepath(item.relativePath);
30
- }
31
- catch (error) {
32
- console.error(error);
33
- }
34
- return item;
35
- }
36
26
  }
37
27
  export default FileController;
38
28
  export { FileController };
@@ -51,6 +51,29 @@ class MediaController extends CommonController {
51
51
  this.handleError(e, reply);
52
52
  }
53
53
  }
54
+ async deleteFile(request, reply) {
55
+ try {
56
+ request.rbac.assertPermission(MediaPermissions.DeleteFile);
57
+ const dir = request.params.dir;
58
+ const year = request.params.year;
59
+ const month = request.params.month;
60
+ const filename = request.params.filename;
61
+ const deleteMetadata = request.query?.deleteMetadata === undefined
62
+ ? undefined
63
+ : !["false", "0", "no"].includes(String(request.query.deleteMetadata).toLowerCase());
64
+ const result = await this.mediaService.deleteFile({
65
+ dir,
66
+ year,
67
+ month,
68
+ filename,
69
+ deleteMetadata,
70
+ });
71
+ return reply.send(result);
72
+ }
73
+ catch (e) {
74
+ this.handleError(e, reply);
75
+ }
76
+ }
54
77
  }
55
78
  export default MediaController;
56
79
  export { MediaController };
@@ -1,6 +1,7 @@
1
1
  var MediaPermissions;
2
2
  (function (MediaPermissions) {
3
3
  MediaPermissions["UploadFile"] = "file:upload";
4
+ MediaPermissions["DeleteFile"] = "file:delete";
4
5
  })(MediaPermissions || (MediaPermissions = {}));
5
6
  export default MediaPermissions;
6
7
  export { MediaPermissions };
@@ -11,6 +11,19 @@ async function MediaRoutes(fastify, options) {
11
11
  tags: ['Media'],
12
12
  }
13
13
  }, (req, rep) => controller.downloadFile(req, rep));
14
+ fastify.delete('/api/file/:dir/:year/:month/:filename', {
15
+ schema: {
16
+ tags: ['Media'],
17
+ querystring: {
18
+ type: 'object',
19
+ properties: {
20
+ deleteMetadata: {
21
+ type: 'boolean',
22
+ },
23
+ },
24
+ },
25
+ }
26
+ }, (req, rep) => controller.deleteFile(req, rep));
14
27
  }
15
28
  export default MediaRoutes;
16
29
  export { MediaRoutes };
@@ -1,8 +1,20 @@
1
1
  import { AbstractService } from "@drax/crud-back";
2
+ import { StoreManager } from "@drax/common-back";
2
3
  class FileService extends AbstractService {
3
4
  constructor(FileRepository, baseSchema, fullSchema) {
4
5
  super(FileRepository, baseSchema, fullSchema);
5
6
  this._validateOutput = true;
7
+ this.onDeleted = async (id, item) => {
8
+ if (!item?.relativePath) {
9
+ return;
10
+ }
11
+ try {
12
+ await StoreManager.deleteFilepath(item.relativePath);
13
+ }
14
+ catch (error) {
15
+ console.error(error);
16
+ }
17
+ };
6
18
  }
7
19
  async registerUploadedFile(data) {
8
20
  return await this.create(data);
@@ -118,6 +118,71 @@ class MediaService {
118
118
  absolutePath,
119
119
  };
120
120
  }
121
+ async deleteFile(params) {
122
+ const { dir, year, month, filename, deleteMetadata = true } = params;
123
+ this.assertDir(dir);
124
+ this.assertYear(year);
125
+ this.assertMonth(month);
126
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
127
+ const relativePath = join(fileDir, filename);
128
+ const absolutePath = resolve(process.cwd(), relativePath);
129
+ let metadataDeleted = false;
130
+ if (deleteMetadata && this.isMetadataEnabled()) {
131
+ const file = await FileServiceFactory.instance.findOneBy("relativePath", relativePath);
132
+ if (file) {
133
+ await FileServiceFactory.instance.delete(file._id);
134
+ metadataDeleted = true;
135
+ return {
136
+ dir,
137
+ year,
138
+ month,
139
+ filename,
140
+ fileDir,
141
+ relativePath,
142
+ absolutePath,
143
+ deleted: true,
144
+ metadataDeleted,
145
+ };
146
+ }
147
+ }
148
+ await StoreManager.deleteFilepath(relativePath);
149
+ return {
150
+ dir,
151
+ year,
152
+ month,
153
+ filename,
154
+ fileDir,
155
+ relativePath,
156
+ absolutePath,
157
+ deleted: true,
158
+ metadataDeleted,
159
+ };
160
+ }
161
+ async deleteFileByRelativePath(params) {
162
+ const { relativePath, deleteMetadata = true } = params;
163
+ const absolutePath = resolve(process.cwd(), relativePath);
164
+ let metadataDeleted = false;
165
+ if (deleteMetadata && this.isMetadataEnabled()) {
166
+ const file = await FileServiceFactory.instance.findOneBy("relativePath", relativePath);
167
+ if (file) {
168
+ await FileServiceFactory.instance.delete(file._id);
169
+ metadataDeleted = true;
170
+ return {
171
+ relativePath,
172
+ absolutePath,
173
+ deleted: true,
174
+ metadataDeleted,
175
+ };
176
+ }
177
+ }
178
+ await StoreManager.deleteFilepath(relativePath);
179
+ return {
180
+ relativePath,
181
+ absolutePath,
182
+ deleted: true,
183
+ metadataDeleted,
184
+ };
185
+ }
121
186
  }
122
187
  export default MediaService;
123
188
  export { MediaService, };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.50.0",
6
+ "version": "3.51.0",
7
7
  "description": "Media files",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "license": "ISC",
22
22
  "dependencies": {
23
23
  "@drax/common-back": "^3.28.0",
24
- "@drax/identity-back": "^3.50.0"
24
+ "@drax/identity-back": "^3.51.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@fastify/multipart": "^9.0.3",
@@ -39,5 +39,5 @@
39
39
  "tsc-alias": "^1.8.10",
40
40
  "typescript": "^5.4.5"
41
41
  },
42
- "gitHead": "1f7040e46eafd8ed45dcdec95d3c1ba41e567e75"
42
+ "gitHead": "62e011454676e3e1d5977be0fcfedba6bd568624"
43
43
  }
@@ -2,7 +2,6 @@ import FileServiceFactory from "../factory/services/FileServiceFactory.js";
2
2
  import {AbstractFastifyController, CustomRequest} from "@drax/crud-back";
3
3
  import FilePermissions from "../permissions/FilePermissions.js";
4
4
  import type {IFile, IFileBase} from "../interfaces/IFile";
5
- import {StoreManager} from "@drax/common-back";
6
5
 
7
6
  class FileController extends AbstractFastifyController<IFile, IFileBase, IFileBase> {
8
7
 
@@ -33,15 +32,6 @@ class FileController extends AbstractFastifyController<IFile, IFileBase, IFileBa
33
32
 
34
33
  return payload
35
34
  }
36
-
37
- async postDelete(request: CustomRequest, item:IFile){
38
- try {
39
- await StoreManager.deleteFilepath(item.relativePath)
40
- } catch (error) {
41
- console.error(error)
42
- }
43
- return item
44
- }
45
35
  }
46
36
 
47
37
  export default FileController;
@@ -64,6 +64,32 @@ class MediaController extends CommonController {
64
64
 
65
65
  }
66
66
 
67
+ async deleteFile(request: any, reply: any) {
68
+ try {
69
+ request.rbac.assertPermission(MediaPermissions.DeleteFile)
70
+
71
+ const dir = request.params.dir
72
+ const year = request.params.year
73
+ const month = request.params.month
74
+ const filename = request.params.filename
75
+ const deleteMetadata = request.query?.deleteMetadata === undefined
76
+ ? undefined
77
+ : !["false", "0", "no"].includes(String(request.query.deleteMetadata).toLowerCase())
78
+
79
+ const result = await this.mediaService.deleteFile({
80
+ dir,
81
+ year,
82
+ month,
83
+ filename,
84
+ deleteMetadata,
85
+ })
86
+
87
+ return reply.send(result)
88
+ } catch (e) {
89
+ this.handleError(e, reply)
90
+ }
91
+ }
92
+
67
93
 
68
94
  }
69
95
 
package/src/index.ts CHANGED
@@ -18,6 +18,10 @@ import type {
18
18
  IMediaSaveFileResult,
19
19
  IMediaGetFileParams,
20
20
  IMediaGetFileResult,
21
+ IMediaDeleteFileParams,
22
+ IMediaDeleteFileResult,
23
+ IMediaDeleteFileByRelativePathParams,
24
+ IMediaDeleteFileByRelativePathResult,
21
25
  } from "./services/MediaService.js";
22
26
 
23
27
  export type {
@@ -29,6 +33,10 @@ export type {
29
33
  IMediaSaveFileResult,
30
34
  IMediaGetFileParams,
31
35
  IMediaGetFileResult,
36
+ IMediaDeleteFileParams,
37
+ IMediaDeleteFileResult,
38
+ IMediaDeleteFileByRelativePathParams,
39
+ IMediaDeleteFileByRelativePathResult,
32
40
  }
33
41
 
34
42
  export {
@@ -1,6 +1,7 @@
1
1
  enum MediaPermissions {
2
2
 
3
3
  UploadFile = "file:upload",
4
+ DeleteFile = "file:delete",
4
5
 
5
6
  }
6
7
 
@@ -17,6 +17,20 @@ async function MediaRoutes(fastify, options) {
17
17
  }
18
18
  }, (req,rep) => controller.downloadFile(req,rep) )
19
19
 
20
+ fastify.delete('/api/file/:dir/:year/:month/:filename', {
21
+ schema: {
22
+ tags: ['Media'],
23
+ querystring: {
24
+ type: 'object',
25
+ properties: {
26
+ deleteMetadata: {
27
+ type: 'boolean',
28
+ },
29
+ },
30
+ },
31
+ }
32
+ }, (req,rep) => controller.deleteFile(req,rep) )
33
+
20
34
 
21
35
  }
22
36
 
@@ -3,14 +3,25 @@ import type{IFileRepository} from "../interfaces/IFileRepository.js";
3
3
  import type {IFileBase, IFile} from "../interfaces/IFile.js";
4
4
  import {AbstractService} from "@drax/crud-back";
5
5
  import type {ZodObject, ZodRawShape} from "zod";
6
+ import {StoreManager} from "@drax/common-back";
6
7
 
7
8
  class FileService extends AbstractService<IFile, IFileBase, IFileBase> {
8
9
 
9
-
10
10
  constructor(FileRepository: IFileRepository, baseSchema?: ZodObject<ZodRawShape>, fullSchema?: ZodObject<ZodRawShape>) {
11
11
  super(FileRepository, baseSchema, fullSchema);
12
12
 
13
13
  this._validateOutput = true
14
+ this.onDeleted = async (id: string, item?: IFile | null): Promise<void> => {
15
+ if (!item?.relativePath) {
16
+ return;
17
+ }
18
+
19
+ try {
20
+ await StoreManager.deleteFilepath(item.relativePath);
21
+ } catch (error) {
22
+ console.error(error);
23
+ }
24
+ }
14
25
 
15
26
  }
16
27
 
@@ -49,6 +49,38 @@ interface IMediaGetFileResult {
49
49
  absolutePath: string;
50
50
  }
51
51
 
52
+ interface IMediaDeleteFileParams {
53
+ dir: string;
54
+ year: string;
55
+ month: string;
56
+ filename: string;
57
+ deleteMetadata?: boolean;
58
+ }
59
+
60
+ interface IMediaDeleteFileResult {
61
+ dir: string;
62
+ year: string;
63
+ month: string;
64
+ filename: string;
65
+ fileDir: string;
66
+ relativePath: string;
67
+ absolutePath: string;
68
+ deleted: boolean;
69
+ metadataDeleted: boolean;
70
+ }
71
+
72
+ interface IMediaDeleteFileByRelativePathParams {
73
+ relativePath: string;
74
+ deleteMetadata?: boolean;
75
+ }
76
+
77
+ interface IMediaDeleteFileByRelativePathResult {
78
+ relativePath: string;
79
+ absolutePath: string;
80
+ deleted: boolean;
81
+ metadataDeleted: boolean;
82
+ }
83
+
52
84
  class MediaService {
53
85
  protected getBaseFileDir(): string {
54
86
  return DraxConfig.getOrLoad(CommonConfig.FileDir) || "files";
@@ -183,6 +215,83 @@ class MediaService {
183
215
  absolutePath,
184
216
  };
185
217
  }
218
+
219
+ async deleteFile(params: IMediaDeleteFileParams): Promise<IMediaDeleteFileResult> {
220
+ const {dir, year, month, filename, deleteMetadata = true} = params;
221
+
222
+ this.assertDir(dir);
223
+ this.assertYear(year);
224
+ this.assertMonth(month);
225
+
226
+ const fileDir = join(this.getBaseFileDir(), dir, year, month);
227
+ const relativePath = join(fileDir, filename);
228
+ const absolutePath = resolve(process.cwd(), relativePath);
229
+ let metadataDeleted = false;
230
+
231
+ if (deleteMetadata && this.isMetadataEnabled()) {
232
+ const file = await FileServiceFactory.instance.findOneBy("relativePath", relativePath);
233
+ if (file) {
234
+ await FileServiceFactory.instance.delete(file._id);
235
+ metadataDeleted = true;
236
+
237
+ return {
238
+ dir,
239
+ year,
240
+ month,
241
+ filename,
242
+ fileDir,
243
+ relativePath,
244
+ absolutePath,
245
+ deleted: true,
246
+ metadataDeleted,
247
+ };
248
+ }
249
+ }
250
+
251
+ await StoreManager.deleteFilepath(relativePath);
252
+
253
+ return {
254
+ dir,
255
+ year,
256
+ month,
257
+ filename,
258
+ fileDir,
259
+ relativePath,
260
+ absolutePath,
261
+ deleted: true,
262
+ metadataDeleted,
263
+ };
264
+ }
265
+
266
+ async deleteFileByRelativePath(params: IMediaDeleteFileByRelativePathParams): Promise<IMediaDeleteFileByRelativePathResult> {
267
+ const {relativePath, deleteMetadata = true} = params;
268
+ const absolutePath = resolve(process.cwd(), relativePath);
269
+ let metadataDeleted = false;
270
+
271
+ if (deleteMetadata && this.isMetadataEnabled()) {
272
+ const file = await FileServiceFactory.instance.findOneBy("relativePath", relativePath);
273
+ if (file) {
274
+ await FileServiceFactory.instance.delete(file._id);
275
+ metadataDeleted = true;
276
+
277
+ return {
278
+ relativePath,
279
+ absolutePath,
280
+ deleted: true,
281
+ metadataDeleted,
282
+ };
283
+ }
284
+ }
285
+
286
+ await StoreManager.deleteFilepath(relativePath);
287
+
288
+ return {
289
+ relativePath,
290
+ absolutePath,
291
+ deleted: true,
292
+ metadataDeleted,
293
+ };
294
+ }
186
295
  }
187
296
 
188
297
  export default MediaService;
@@ -195,4 +304,8 @@ export type {
195
304
  IMediaSaveFileResult,
196
305
  IMediaGetFileParams,
197
306
  IMediaGetFileResult,
307
+ IMediaDeleteFileParams,
308
+ IMediaDeleteFileResult,
309
+ IMediaDeleteFileByRelativePathParams,
310
+ IMediaDeleteFileByRelativePathResult,
198
311
  };