@jrmc/adonis-attachment 5.0.0-beta.3 → 5.0.0-beta.6

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.
Files changed (82) hide show
  1. package/build/providers/attachment_provider.d.ts.map +1 -1
  2. package/build/providers/attachment_provider.js +9 -1
  3. package/build/services/regenerate_service.js +3 -3
  4. package/build/src/adapters/lock.d.ts +9 -0
  5. package/build/src/adapters/lock.d.ts.map +1 -0
  6. package/build/src/adapters/lock.js +21 -0
  7. package/build/src/adapters/poppler.js +0 -1
  8. package/build/src/attachment_manager.d.ts +7 -3
  9. package/build/src/attachment_manager.d.ts.map +1 -1
  10. package/build/src/attachment_manager.js +15 -50
  11. package/build/src/attachments/attachment.d.ts +9 -4
  12. package/build/src/attachments/attachment.d.ts.map +1 -1
  13. package/build/src/attachments/attachment.js +53 -9
  14. package/build/src/attachments/attachment_base.d.ts +11 -2
  15. package/build/src/attachments/attachment_base.d.ts.map +1 -1
  16. package/build/src/attachments/attachment_base.js +60 -3
  17. package/build/src/controllers/attachments_controller.d.ts.map +1 -1
  18. package/build/src/controllers/attachments_controller.js +21 -12
  19. package/build/src/services/attachment/attachment_detachment_service.d.ts +19 -0
  20. package/build/src/services/attachment/attachment_detachment_service.d.ts.map +1 -0
  21. package/build/src/services/attachment/attachment_detachment_service.js +66 -0
  22. package/build/src/services/attachment/attachment_persister_service.d.ts +22 -0
  23. package/build/src/services/attachment/attachment_persister_service.d.ts.map +1 -0
  24. package/build/src/services/attachment/attachment_persister_service.js +95 -0
  25. package/build/src/services/attachment/attachment_recorder_service.d.ts +68 -0
  26. package/build/src/services/attachment/attachment_recorder_service.d.ts.map +1 -0
  27. package/build/src/services/attachment/attachment_recorder_service.js +121 -0
  28. package/build/src/services/attachment/attachment_transaction_service.d.ts +26 -0
  29. package/build/src/services/attachment/attachment_transaction_service.d.ts.map +1 -0
  30. package/build/src/services/attachment/attachment_transaction_service.js +46 -0
  31. package/build/src/services/attachment/attachment_utils.d.ts +35 -0
  32. package/build/src/services/attachment/attachment_utils.d.ts.map +1 -0
  33. package/build/src/services/attachment/attachment_utils.js +71 -0
  34. package/build/src/services/attachment/attachment_variant_service.d.ts +17 -0
  35. package/build/src/services/attachment/attachment_variant_service.d.ts.map +1 -0
  36. package/build/src/services/attachment/attachment_variant_service.js +72 -0
  37. package/build/src/services/attachment/index.d.ts +15 -0
  38. package/build/src/services/attachment/index.d.ts.map +1 -0
  39. package/build/src/services/attachment/index.js +15 -0
  40. package/build/src/services/attachment_service.d.ts +8 -0
  41. package/build/src/services/attachment_service.d.ts.map +1 -0
  42. package/build/src/services/attachment_service.js +7 -0
  43. package/build/src/services/variant/{variant_generator.d.ts → variant_generator_service.d.ts} +8 -2
  44. package/build/src/services/variant/variant_generator_service.d.ts.map +1 -0
  45. package/build/src/services/variant/{variant_generator.js → variant_generator_service.js} +7 -1
  46. package/build/src/services/variant/{variant_persister.d.ts → variant_persister_service.d.ts} +8 -2
  47. package/build/src/services/variant/variant_persister_service.d.ts.map +1 -0
  48. package/build/src/services/variant/{variant_persister.js → variant_persister_service.js} +7 -1
  49. package/build/src/services/variant/{variant_purger.d.ts → variant_purger_service.d.ts} +7 -1
  50. package/build/src/services/variant/variant_purger_service.d.ts.map +1 -0
  51. package/build/src/services/variant/{variant_purger.js → variant_purger_service.js} +6 -0
  52. package/build/src/services/variant_service.d.ts +6 -0
  53. package/build/src/services/variant_service.d.ts.map +1 -1
  54. package/build/src/services/variant_service.js +13 -7
  55. package/build/src/types/attachment.d.ts +12 -3
  56. package/build/src/types/attachment.d.ts.map +1 -1
  57. package/build/src/types/config.d.ts +2 -1
  58. package/build/src/types/config.d.ts.map +1 -1
  59. package/build/src/types/index.d.ts +6 -0
  60. package/build/src/types/index.d.ts.map +1 -1
  61. package/build/src/types/index.js +6 -0
  62. package/build/src/types/lock.d.ts +14 -0
  63. package/build/src/types/lock.d.ts.map +1 -0
  64. package/build/src/types/lock.js +7 -0
  65. package/build/src/types/metadata.d.ts +6 -0
  66. package/build/src/types/metadata.d.ts.map +1 -1
  67. package/build/src/types/metadata.js +6 -0
  68. package/build/src/types/regenerate.d.ts +6 -0
  69. package/build/src/types/regenerate.d.ts.map +1 -1
  70. package/build/src/types/regenerate.js +6 -0
  71. package/build/src/types/service.d.ts +7 -1
  72. package/build/src/types/service.d.ts.map +1 -1
  73. package/build/src/types/service.js +6 -0
  74. package/build/src/utils/hooks.js +5 -5
  75. package/build/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +32 -23
  77. package/build/src/services/record_with_attachment.d.ts +0 -33
  78. package/build/src/services/record_with_attachment.d.ts.map +0 -1
  79. package/build/src/services/record_with_attachment.js +0 -316
  80. package/build/src/services/variant/variant_generator.d.ts.map +0 -1
  81. package/build/src/services/variant/variant_persister.d.ts.map +0 -1
  82. package/build/src/services/variant/variant_purger.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"attachment_provider.d.ts","sourceRoot":"","sources":["../../providers/attachment_provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAIhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAiB,iBAAiB;QAChC,iBAAiB,EAAE,iBAAiB,CAAA;KACrC;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,KAAK,CAAA;KACzC;CACF;AAED,MAAM,CAAC,OAAO,OAAO,kBAAkB;;IAGzB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,QAAQ;IAqBF,IAAI;CAQX"}
1
+ {"version":3,"file":"attachment_provider.d.ts","sourceRoot":"","sources":["../../providers/attachment_provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAM/D,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAiB,iBAAiB;QAChC,iBAAiB,EAAE,iBAAiB,CAAA;KACrC;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,KAAK,CAAA;KACzC;CACF;AAED,MAAM,CAAC,OAAO,OAAO,kBAAkB;;IAGzB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,QAAQ;IA4BF,IAAI;CAQX"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { configProvider } from '@adonisjs/core';
8
8
  import { RuntimeException } from '@poppinss/utils';
9
+ import { verrou } from '../src/adapters/lock.js';
9
10
  export default class AttachmentProvider {
10
11
  app;
11
12
  #manager = null;
@@ -18,7 +19,14 @@ export default class AttachmentProvider {
18
19
  const attachmentConfig = this.app.config.get('attachment');
19
20
  const config = await configProvider.resolve(this.app, attachmentConfig);
20
21
  const drive = await this.app.container.make('drive.manager');
21
- const lock = await this.app.container.make('lock.manager');
22
+ let lock;
23
+ try {
24
+ const lockManager = await this.app.container.make('lock.manager');
25
+ lock = verrou(lockManager);
26
+ }
27
+ catch (error) {
28
+ lock = verrou();
29
+ }
22
30
  if (!config) {
23
31
  throw new RuntimeException('Invalid config exported from "config/attachment.ts" file. Make sure to use the defineConfig method');
24
32
  }
@@ -1,4 +1,4 @@
1
- import RecordWithAttachment from '../src/services/record_with_attachment.js';
1
+ import { AttachmentRecordService } from '../src/services/attachment/index.js';
2
2
  export default class RegenerateService {
3
3
  #Model;
4
4
  #row;
@@ -15,13 +15,13 @@ export default class RegenerateService {
15
15
  }
16
16
  async run() {
17
17
  if (this.#row) {
18
- const record = new RecordWithAttachment(this.#row);
18
+ const record = new AttachmentRecordService(this.#row);
19
19
  return record.regenerateVariants(this.#options);
20
20
  }
21
21
  else if (this.#Model) {
22
22
  const entities = await this.#Model.all();
23
23
  return Promise.all(entities.map(async (entity) => {
24
- const record = new RecordWithAttachment(entity);
24
+ const record = new AttachmentRecordService(entity);
25
25
  return record.regenerateVariants(this.#options);
26
26
  }));
27
27
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @jrmc/adonis-attachment
3
+ *
4
+ * @license MIT
5
+ * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
+ */
7
+ import type { LockService } from '../types/lock.js';
8
+ export declare const verrou: (lock?: LockService) => LockService;
9
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../../src/adapters/lock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAKnD,eAAO,MAAM,MAAM,UAAW,WAAW,KAAG,WAW3C,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @jrmc/adonis-attachment
3
+ *
4
+ * @license MIT
5
+ * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
+ */
7
+ import { Verrou } from '@verrou/core';
8
+ import { memoryStore } from '@verrou/core/drivers/memory';
9
+ export const verrou = (lock) => {
10
+ if (lock) {
11
+ return lock;
12
+ }
13
+ else {
14
+ return new Verrou({
15
+ default: 'memory',
16
+ stores: {
17
+ memory: { driver: memoryStore() }
18
+ }
19
+ });
20
+ }
21
+ };
@@ -85,7 +85,6 @@ export default class Poppler {
85
85
  if (metadata['creationdate']) {
86
86
  const dateStr = metadata['creationdate'];
87
87
  const date = DateTime.fromFormat(dateStr, 'EEE MMM dd HH:mm:ss yyyy z', { zone: 'UTC' });
88
- console.log('Parsed date:', date.toISO());
89
88
  if (date.isValid) {
90
89
  creationDate = date.toFormat('yyyy-MM-dd\'T\'HH:mm:ss');
91
90
  }
@@ -5,8 +5,8 @@
5
5
  * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
6
  */
7
7
  import type { DriveService, SignedURLOptions } from '@adonisjs/drive/types';
8
- import type { LockService } from '@adonisjs/lock/types';
9
8
  import type { MultipartFile } from '@adonisjs/core/bodyparser';
9
+ import type { LockService } from './types/lock.js';
10
10
  import type { AttachmentAttributes, AttachmentBase, Attachment as AttachmentType } from './types/attachment.js';
11
11
  import type { ResolvedAttachmentConfig } from './define_config.js';
12
12
  import { DeferQueue } from '@poppinss/defer';
@@ -14,7 +14,6 @@ import Converter from './converters/converter.js';
14
14
  export declare class AttachmentManager<KnownConverters extends Record<string, Converter>> {
15
15
  #private;
16
16
  queue: DeferQueue;
17
- lock: LockService;
18
17
  constructor(config: ResolvedAttachmentConfig<KnownConverters>, drive: DriveService, lock: LockService);
19
18
  createFromDbResponse(response?: string | JSON): AttachmentType | null;
20
19
  createFromFile(input: MultipartFile): Promise<AttachmentType>;
@@ -25,6 +24,10 @@ export declare class AttachmentManager<KnownConverters extends Record<string, Co
25
24
  getVariant(variantName: string): import("./types/attachment.js").Variant | null;
26
25
  getUrl(variantName?: string): Promise<string>;
27
26
  getSignedUrl(variantNameOrOptions?: string | SignedURLOptions, signedUrlOptions?: SignedURLOptions): Promise<string>;
27
+ preComputeUrl(): Promise<void>;
28
+ moveFileForDelete(): Promise<void>;
29
+ rollbackMoveFileForDelete(): Promise<void>;
30
+ remove(): Promise<void>;
28
31
  toObject(): AttachmentAttributes;
29
32
  })[]>;
30
33
  createFromPath(input: string, name?: string): Promise<AttachmentType>;
@@ -32,11 +35,12 @@ export declare class AttachmentManager<KnownConverters extends Record<string, Co
32
35
  createFromBase64(input: string, name?: string): Promise<AttachmentType>;
33
36
  createFromUrl(input: URL, name?: string): Promise<AttachmentType>;
34
37
  createFromStream(stream: NodeJS.ReadableStream, name?: string): Promise<AttachmentType>;
35
- getConverter(key: string): Promise<void | Converter>;
36
38
  computeUrl(attachment: AttachmentType | AttachmentBase, signedUrlOptions?: SignedURLOptions): Promise<void>;
37
39
  preComputeUrl(attachment: AttachmentType): Promise<void>;
38
40
  write(attachment: AttachmentBase): Promise<void>;
39
41
  remove(attachment: AttachmentBase): Promise<void>;
42
+ get lock(): LockService;
40
43
  getConfig(): ResolvedAttachmentConfig<KnownConverters>;
44
+ getConverter(key: string): Promise<void | Converter>;
41
45
  }
42
46
  //# sourceMappingURL=attachment_manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachment_manager.d.ts","sourceRoot":"","sources":["../../src/attachment_manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACd,UAAU,IAAI,cAAc,EAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,SAAS,MAAM,2BAA2B,CAAA;AAQjD,qBAAa,iBAAiB,CAAC,eAAe,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC;;IAC9E,KAAK,aAAA;IAGL,IAAI,EAAE,WAAW,CAAA;gBAEL,MAAM,EAAE,wBAAwB,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;IAUrG,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAiBvC,cAAc,CAAC,KAAK,EAAE,aAAa;IAgBnC,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE;;;;;;;;;IAIvC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAiB3C,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAgB7C,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAW7C,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM;IAMvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,EAAE,MAAM;IAM7D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAMpD,UAAU,CACd,UAAU,EAAE,cAAc,GAAG,cAAc,EAC3C,gBAAgB,CAAC,EAAE,gBAAgB;IAY/B,aAAa,CAAC,UAAU,EAAE,cAAc;IAgBxC,KAAK,CAAC,UAAU,EAAE,cAAc;IAgBhC,MAAM,CAAC,UAAU,EAAE,cAAc;IAuBvC,SAAS;CAqBV"}
1
+ {"version":3,"file":"attachment_manager.d.ts","sourceRoot":"","sources":["../../src/attachment_manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACd,UAAU,IAAI,cAAc,EAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,SAAS,MAAM,2BAA2B,CAAA;AAQjD,qBAAa,iBAAiB,CAAC,eAAe,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC;;IAC9E,KAAK,aAAA;gBAKO,MAAM,EAAE,wBAAwB,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW;IAUrG,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAiBvC,cAAc,CAAC,KAAK,EAAE,aAAa;IAgBnC,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE;;;;;;;;;;;;;IAIvC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAiB3C,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAgB7C,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAW7C,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM;IAMvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,EAAE,MAAM;IAM7D,UAAU,CACd,UAAU,EAAE,cAAc,GAAG,cAAc,EAC3C,gBAAgB,CAAC,EAAE,gBAAgB;IAK/B,aAAa,CAAC,UAAU,EAAE,cAAc;IAIxC,KAAK,CAAC,UAAU,EAAE,cAAc;IAUhC,MAAM,CAAC,UAAU,EAAE,cAAc;IAMvC,IAAI,IAAI,gBAEP;IAED,SAAS;IAIH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;CAuB3D"}
@@ -17,10 +17,10 @@ export class AttachmentManager {
17
17
  queue;
18
18
  #config;
19
19
  #drive;
20
- lock;
20
+ #lock;
21
21
  constructor(config, drive, lock) {
22
22
  this.#drive = drive;
23
- this.lock = lock;
23
+ this.#lock = lock;
24
24
  this.#config = config;
25
25
  const concurrency = this.#config.queue?.concurrency || 1;
26
26
  this.queue = new DeferQueue({ concurrency });
@@ -96,71 +96,36 @@ export class AttachmentManager {
96
96
  const tmpPath = await streamToTempFile(stream);
97
97
  return this.createFromPath(tmpPath, name || path.basename(tmpPath));
98
98
  }
99
- async getConverter(key) {
100
- if (this.#config.converters) {
101
- return this.#config.converters[key];
102
- }
103
- }
104
99
  async computeUrl(attachment, signedUrlOptions) {
105
- const disk = attachment.getDisk();
106
- const fileVisibility = await disk.getVisibility(attachment.path);
107
- if (fileVisibility === 'private') {
108
- attachment.url = await attachment.getSignedUrl(signedUrlOptions);
109
- }
110
- else {
111
- attachment.url = await attachment.getUrl();
112
- }
100
+ await attachment.computeUrl(signedUrlOptions);
113
101
  }
114
102
  async preComputeUrl(attachment) {
115
- if (attachment.options?.preComputeUrl === false) {
116
- return;
117
- }
118
- await this.computeUrl(attachment);
119
- if (attachment instanceof Attachment && attachment.variants) {
120
- for (const key in attachment.variants) {
121
- if (Object.prototype.hasOwnProperty.call(attachment.variants, key)) {
122
- await this.computeUrl(attachment.variants[key]);
123
- }
124
- }
125
- }
103
+ await attachment.preComputeUrl();
126
104
  }
127
105
  async write(attachment) {
128
- const destinationPath = attachment.path;
129
106
  if (attachment.options?.meta) {
130
107
  attachment.meta = await ExifAdapter.exif(attachment.input, this.#config);
131
108
  }
132
109
  else {
133
110
  attachment.meta = undefined;
134
111
  }
135
- if (Buffer.isBuffer(attachment.input)) {
136
- await attachment.getDisk().put(destinationPath, attachment.input);
137
- }
138
- else if (attachment.input) {
139
- await attachment.getDisk().copyFromFs(attachment.input, destinationPath);
140
- }
112
+ await attachment.put();
141
113
  }
142
114
  async remove(attachment) {
143
- if (attachment.path) {
144
- await attachment.getDisk().delete(attachment.path);
145
- if (attachment instanceof Attachment) {
146
- if (attachment.variants) {
147
- const variantPath = attachment.variants[0].folder;
148
- await attachment.getDisk().deleteAll(variantPath); // not compatible Minio, necessary for fs as not to leave an empty directory
149
- for (const key in attachment.variants) {
150
- if (Object.prototype.hasOwnProperty.call(attachment.variants, key)) {
151
- await attachment.getDisk().delete(attachment.variants[key].path);
152
- }
153
- }
154
- }
155
- }
156
- }
157
- if (attachment.originalPath) {
158
- await attachment.getDisk().delete(attachment.originalPath);
159
- }
115
+ await attachment.remove();
116
+ }
117
+ // getters
118
+ get lock() {
119
+ return this.#lock;
160
120
  }
161
121
  getConfig() {
162
122
  return this.#config;
163
123
  }
124
+ async getConverter(key) {
125
+ if (this.#config.converters) {
126
+ return this.#config.converters[key];
127
+ }
128
+ }
164
129
  // private methods
165
130
  #configureAttachment(attachment) {
166
131
  if (this.#config.meta !== undefined) {
@@ -9,14 +9,11 @@ import type { AttachmentAttributes, Attachment as AttachmentInterface, LucidOpti
9
9
  import type { Input } from '../types/input.js';
10
10
  import { AttachmentBase } from './attachment_base.js';
11
11
  import { Variant } from './variant_attachment.js';
12
+ import { LucidRow } from '@adonisjs/lucid/types/model';
12
13
  export declare class Attachment extends AttachmentBase implements AttachmentInterface {
13
14
  originalName: string;
14
15
  variants?: Variant[];
15
16
  constructor(drive: DriveService, attributes: AttachmentAttributes, input?: Input);
16
- /**
17
- * Getters
18
- */
19
- get name(): string;
20
17
  /**
21
18
  * Methods
22
19
  */
@@ -25,6 +22,14 @@ export declare class Attachment extends AttachmentBase implements AttachmentInte
25
22
  getUrl(variantName?: string): Promise<string>;
26
23
  getSignedUrl(variantNameOrOptions?: string | SignedURLOptions, signedUrlOptions?: SignedURLOptions): Promise<string>;
27
24
  setOptions(options: LucidOptions): this;
25
+ /**
26
+ * Actions
27
+ */
28
+ preComputeUrl(): Promise<void>;
29
+ makeName(record?: LucidRow, attributeName?: string): Promise<this>;
30
+ moveFileForDelete(): Promise<void>;
31
+ rollbackMoveFileForDelete(): Promise<void>;
32
+ remove(): Promise<void>;
28
33
  /**
29
34
  *
30
35
  */
@@ -1 +1 @@
1
- {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../../src/attachments/attachment.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,IAAI,mBAAmB,EACjC,YAAY,EACb,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAGjD,qBAAa,UAAW,SAAQ,cAAe,YAAW,mBAAmB;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;gBAER,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,KAAK;IAehF;;OAEG;IAEH,IAAI,IAAI,WAMP;IAED;;OAEG;IAEG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBhE,UAAU,CAAC,WAAW,EAAE,MAAM;IAIxB,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM;IAe3B,YAAY,CAChB,oBAAoB,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAChD,gBAAgB,CAAC,EAAE,gBAAgB;IAyBrC,UAAU,CAAC,OAAO,EAAE,YAAY;IAkBhC;;OAEG;IAEH,QAAQ,IAAI,oBAAoB;IAUhC,MAAM,IAAI,MAAM;CAsCjB"}
1
+ {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../../src/attachments/attachment.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,IAAI,mBAAmB,EACjC,YAAY,EACb,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAEtD,qBAAa,UAAW,SAAQ,cAAe,YAAW,mBAAmB;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;gBAER,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,KAAK;IAehF;;OAEG;IAEG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBhE,UAAU,CAAC,WAAW,EAAE,MAAM;IAIxB,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM;IAe3B,YAAY,CAChB,oBAAoB,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAChD,gBAAgB,CAAC,EAAE,gBAAgB;IAyBrC,UAAU,CAAC,OAAO,EAAE,YAAY;IAkBhC;;OAEG;IAEG,aAAa;IAiBb,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM;IAIlD,iBAAiB;IAWjB,yBAAyB;IAWzB,MAAM;IAkBZ;;OAEG;IAEH,QAAQ,IAAI,oBAAoB;IAUhC,MAAM,IAAI,MAAM;CAsCjB"}
@@ -22,15 +22,6 @@ export class Attachment extends AttachmentBase {
22
22
  });
23
23
  }
24
24
  }
25
- /**
26
- * Getters
27
- */
28
- get name() {
29
- if (this.options && this.options.rename === false) {
30
- return this.originalName;
31
- }
32
- return super.name;
33
- }
34
25
  /**
35
26
  * Methods
36
27
  */
@@ -107,6 +98,59 @@ export class Attachment extends AttachmentBase {
107
98
  }
108
99
  return this;
109
100
  }
101
+ /**
102
+ * Actions
103
+ */
104
+ async preComputeUrl() {
105
+ if (this.options?.preComputeUrl === false) {
106
+ return;
107
+ }
108
+ await this.computeUrl();
109
+ if (this.variants) {
110
+ for (const key in this.variants) {
111
+ if (Object.prototype.hasOwnProperty.call(this.variants, key)) {
112
+ await this.computeUrl(this.variants[key]);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ async makeName(record, attributeName) {
118
+ return super.makeName(record, attributeName, this.originalName);
119
+ }
120
+ async moveFileForDelete() {
121
+ if (this.options && this.options.rename !== true) {
122
+ const originalPath = this.path;
123
+ this.name = `${this.name}.trash`;
124
+ const trashPath = this.path;
125
+ this.originalPath = trashPath;
126
+ await this.getDisk().move(originalPath, trashPath);
127
+ }
128
+ }
129
+ async rollbackMoveFileForDelete() {
130
+ if (this.options && this.options.rename !== true) {
131
+ const trashPath = this.path;
132
+ this.name = this.name.replace('.trash', '');
133
+ const originalPath = this.path;
134
+ this.originalPath = originalPath;
135
+ await this.getDisk().move(trashPath, originalPath);
136
+ }
137
+ }
138
+ async remove() {
139
+ await super.remove();
140
+ if (this.variants) {
141
+ const variantPath = this.variants[0].folder;
142
+ try {
143
+ await this.getDisk().deleteAll(variantPath); // not compatible Minio, necessary for fs as not to leave an empty directory
144
+ }
145
+ catch (error) {
146
+ for (const key in this.variants) {
147
+ if (Object.prototype.hasOwnProperty.call(this.variants, key)) {
148
+ this.variants[key].remove();
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
110
154
  /**
111
155
  *
112
156
  */
@@ -21,9 +21,10 @@ export declare class AttachmentBase implements AttachmentBaseInterface {
21
21
  options: LucidOptions;
22
22
  constructor(drive: DriveService, attributes: AttachmentBaseAttributes, input?: Input);
23
23
  /**
24
- * Getters
24
+ * Getters / Setters
25
25
  */
26
26
  get name(): string;
27
+ set name(name: string);
27
28
  get folder(): string | undefined;
28
29
  get path(): string;
29
30
  /**
@@ -38,7 +39,15 @@ export declare class AttachmentBase implements AttachmentBaseInterface {
38
39
  getKeyId(): string | undefined;
39
40
  setKeyId(keyId: string): this;
40
41
  setOptions(options: LucidOptions): this;
41
- makeFolder(record?: LucidRow): this;
42
+ /**
43
+ * Actions
44
+ */
45
+ computeUrl(signedUrlOptions?: SignedURLOptions): Promise<void>;
46
+ preComputeUrl(): Promise<void>;
47
+ makeName(record?: LucidRow, attributeName?: string, originalName?: string): Promise<this>;
48
+ makeFolder(record?: LucidRow): Promise<this>;
49
+ put(): Promise<void>;
50
+ remove(): Promise<void>;
42
51
  /**
43
52
  *
44
53
  */
@@ -1 +1 @@
1
- {"version":3,"file":"attachment_base.d.ts","sourceRoot":"","sources":["../../../src/attachments/attachment_base.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,cAAc,IAAI,uBAAuB,EAC1C,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAOpD,qBAAa,cAAe,YAAW,uBAAuB;;IAC5D,KAAK,EAAE,YAAY,CAAA;IAEnB,KAAK,CAAC,EAAE,KAAK,CAAA;IAMb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ,OAAO,EAAE,YAAY,CAAA;gBAET,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,wBAAwB,EAAE,KAAK,CAAC,EAAE,KAAK;IAsBpF;;OAEG;IAEH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAW/B;IAED,IAAI,IAAI,IAAI,MAAM,CAMjB;IAED;;OAEG;IAEH,OAAO;IAIP,QAAQ;IAIF,SAAS;IAKf,SAAS;IAIT,MAAM;IAIN,YAAY,CAAC,gBAAgB,CAAC,EAAE,gBAAgB;IAIhD,QAAQ;IAIR,QAAQ,CAAC,KAAK,EAAE,MAAM;IAKtB,UAAU,CAAC,OAAO,EAAE,YAAY;IAQhC,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ;IAwB5B;;OAEG;IAEH,QAAQ,IAAI,wBAAwB;IAYpC,MAAM,IAAI,MAAM;CAUjB"}
1
+ {"version":3,"file":"attachment_base.d.ts","sourceRoot":"","sources":["../../../src/attachments/attachment_base.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,cAAc,IAAI,uBAAuB,EAC1C,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAOpD,qBAAa,cAAe,YAAW,uBAAuB;;IAC5D,KAAK,EAAE,YAAY,CAAA;IAEnB,KAAK,CAAC,EAAE,KAAK,CAAA;IAMb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ,OAAO,EAAE,YAAY,CAAA;gBAET,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,wBAAwB,EAAE,KAAK,CAAC,EAAE,KAAK;IAsBpF;;OAEG;IAEH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAEpB;IAED,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAW/B;IAED,IAAI,IAAI,IAAI,MAAM,CAMjB;IAED;;OAEG;IAEH,OAAO;IAIP,QAAQ;IAIF,SAAS;IAKf,SAAS;IAIT,MAAM;IAIN,YAAY,CAAC,gBAAgB,CAAC,EAAE,gBAAgB;IAIhD,QAAQ;IAIR,QAAQ,CAAC,KAAK,EAAE,MAAM;IAKtB,UAAU,CAAC,OAAO,EAAE,YAAY;IAQhC;;OAEG;IAEG,UAAU,CAAC,gBAAgB,CAAC,EAAE,gBAAgB;IAW9C,aAAa;IAQb,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IAwBzE,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ;IAwB5B,GAAG;IAQH,MAAM;IASZ;;OAEG;IAEH,QAAQ,IAAI,wBAAwB;IAYpC,MAAM,IAAI,MAAM;CAUjB"}
@@ -41,11 +41,14 @@ export class AttachmentBase {
41
41
  this.drive = drive;
42
42
  }
43
43
  /**
44
- * Getters
44
+ * Getters / Setters
45
45
  */
46
46
  get name() {
47
47
  return this.#name;
48
48
  }
49
+ set name(name) {
50
+ this.#name = name;
51
+ }
49
52
  get folder() {
50
53
  if (this.#folder) {
51
54
  return this.#folder;
@@ -99,9 +102,49 @@ export class AttachmentBase {
99
102
  };
100
103
  return this;
101
104
  }
102
- makeFolder(record) {
105
+ /**
106
+ * Actions
107
+ */
108
+ async computeUrl(signedUrlOptions) {
109
+ const disk = this.getDisk();
110
+ const fileVisibility = await disk.getVisibility(this.path);
111
+ if (fileVisibility === 'private') {
112
+ this.url = await this.getSignedUrl(signedUrlOptions);
113
+ }
114
+ else {
115
+ this.url = await this.getUrl();
116
+ }
117
+ }
118
+ async preComputeUrl() {
119
+ if (this.options?.preComputeUrl === false) {
120
+ return;
121
+ }
122
+ await this.computeUrl();
123
+ }
124
+ async makeName(record, attributeName, originalName) {
125
+ if (typeof this.options.rename === 'function' && record) {
126
+ this.#name = (await this.options.rename(record, attributeName, originalName));
127
+ }
128
+ else if (originalName && this.options.rename === false) {
129
+ this.#name = originalName;
130
+ }
131
+ if (this.#name && record) {
132
+ const parameters = extractPathParameters(this.#name);
133
+ if (parameters) {
134
+ parameters.forEach((parameter) => {
135
+ const attribute = record.$attributes[parameter];
136
+ if (typeof attribute === 'string') {
137
+ const name = string.slug(string.noCase(string.escapeHTML(attribute.toLowerCase())));
138
+ this.#name = this.#name?.replace(`:${parameter}`, name);
139
+ }
140
+ });
141
+ }
142
+ }
143
+ return this;
144
+ }
145
+ async makeFolder(record) {
103
146
  if (typeof this.options.folder === 'function' && record) {
104
- this.#folder = this.options.folder(record);
147
+ this.#folder = (await this.options.folder(record));
105
148
  }
106
149
  else if (this.options.folder) {
107
150
  this.#folder = this.options.folder;
@@ -120,6 +163,20 @@ export class AttachmentBase {
120
163
  }
121
164
  return this;
122
165
  }
166
+ async put() {
167
+ if (Buffer.isBuffer(this.input)) {
168
+ await this.getDisk().put(this.path, this.input);
169
+ }
170
+ else if (this.input) {
171
+ await this.getDisk().copyFromFs(this.input, this.path);
172
+ }
173
+ }
174
+ async remove() {
175
+ await this.getDisk().delete(this.path);
176
+ if (this.originalPath) {
177
+ await this.getDisk().delete(this.originalPath);
178
+ }
179
+ }
123
180
  /**
124
181
  *
125
182
  */
@@ -1 +1 @@
1
- {"version":3,"file":"attachments_controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/attachments_controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAoBtD,MAAM,CAAC,OAAO,OAAO,qBAAqB;IAElC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,WAAW;CAgGhD"}
1
+ {"version":3,"file":"attachments_controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/attachments_controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAoBtD,MAAM,CAAC,OAAO,OAAO,qBAAqB;IAElC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,WAAW;CA0GhD"}
@@ -3,8 +3,8 @@ import { Readable } from 'node:stream';
3
3
  import encryption from '@adonisjs/core/services/encryption';
4
4
  import db from '@adonisjs/lucid/services/db';
5
5
  import { attachmentManager } from '@jrmc/adonis-attachment';
6
- import VariantGenerator from '../services/variant/variant_generator.js';
7
- import VariantPersister from '../services/variant/variant_persister.js';
6
+ import VariantGeneratorService from '../services/variant/variant_generator_service.js';
7
+ import VariantPersisterService from '../services/variant/variant_persister_service.js';
8
8
  export default class AttachmentsController {
9
9
  async handle({ request, response }) {
10
10
  const { key } = request.params();
@@ -56,37 +56,46 @@ export default class AttachmentsController {
56
56
  */
57
57
  if (!variant && format) {
58
58
  const converter = (await attachmentManager.getConverter(format));
59
- variant = await (new VariantGenerator()).generateVariant({
59
+ variant = await (new VariantGeneratorService()).generateVariant({
60
60
  key: format,
61
61
  attachment: currentAttachment,
62
62
  converter
63
63
  });
64
64
  if (variant) {
65
- const variantPersister = new VariantPersister({
65
+ const variantPersister = new VariantPersisterService({
66
66
  id: data.id,
67
67
  modelTable: data.model,
68
68
  attributeName: data.attribute,
69
69
  multiple
70
70
  });
71
- await variantPersister.persist({ attachments: attachments ?? [currentAttachment], variants: [variant] });
71
+ const attachmentsOrCurrent = attachments.length ? attachments : [currentAttachment];
72
+ await variantPersister.persist({ attachments: attachmentsOrCurrent, variants: [variant] });
72
73
  }
73
74
  }
74
75
  /*
75
76
  * 5. Get the stream
76
77
  */
77
- let file;
78
+ let stream;
78
79
  let mimeType;
79
80
  if (variant) {
80
- file = await variant.getStream();
81
+ stream = await variant.getStream();
81
82
  mimeType = variant.mimeType;
82
83
  }
83
- else {
84
- file = await currentAttachment.getStream();
84
+ else if (currentAttachment) {
85
+ stream = await currentAttachment.getStream();
85
86
  mimeType = currentAttachment.mimeType;
86
87
  }
87
- const readable = Readable.from(file);
88
- response.header('Content-Type', mimeType);
89
- response.stream(readable);
88
+ /*
89
+ * 6. Return the stream
90
+ */
91
+ if (stream && mimeType) {
92
+ const readable = Readable.from(stream);
93
+ response.header('Content-Type', mimeType);
94
+ response.stream(readable);
95
+ }
96
+ else {
97
+ return response.notFound();
98
+ }
90
99
  });
91
100
  }
92
101
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @jrmc/adonis-attachment
3
+ *
4
+ * @license MIT
5
+ * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
+ */
7
+ import type { RecordWithAttachment as RecordWithAttachmentImplementation } from '../../types/service.js';
8
+ export declare class AttachmentDetachmentService {
9
+ #private;
10
+ /**
11
+ * Detach dirty attachments (mark for deletion)
12
+ */
13
+ detach(record: RecordWithAttachmentImplementation): Promise<void>;
14
+ /**
15
+ * Detach all attachments (mark all for deletion)
16
+ */
17
+ detachAll(record: RecordWithAttachmentImplementation): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=attachment_detachment_service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment_detachment_service.d.ts","sourceRoot":"","sources":["../../../../src/services/attachment/attachment_detachment_service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,oBAAoB,IAAI,kCAAkC,EAAE,MAAM,wBAAwB,CAAA;AAIxG,qBAAa,2BAA2B;;IACtC;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,kCAAkC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCvE;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,kCAAkC,GAAG,OAAO,CAAC,IAAI,CAAC;CA+B3E"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @jrmc/adonis-attachment
3
+ *
4
+ * @license MIT
5
+ * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
+ */
7
+ import { AttachmentUtils } from './attachment_utils.js';
8
+ export class AttachmentDetachmentService {
9
+ /**
10
+ * Detach dirty attachments (mark for deletion)
11
+ */
12
+ async detach(record) {
13
+ const attachmentAttributeNames = AttachmentUtils.getDirtyAttributeNamesOfAttachment(record.row);
14
+ await Promise.allSettled(attachmentAttributeNames.map(async (name) => {
15
+ let attachments = [];
16
+ const options = AttachmentUtils.getOptionsByAttributeName(record.row, name);
17
+ if (record.row.$dirty[name] === null) {
18
+ attachments = AttachmentUtils.getOriginalAttachmentsByAttributeName(record.row, name);
19
+ }
20
+ else {
21
+ const originalAttachments = AttachmentUtils.getOriginalAttachmentsByAttributeName(record.row, name);
22
+ const newAttachments = AttachmentUtils.getAttachmentsByAttributeName(record.row, name);
23
+ /**
24
+ * Clean Attachments changed
25
+ */
26
+ for (let i = 0; i < originalAttachments.length; i++) {
27
+ if (newAttachments.includes(originalAttachments[i])) {
28
+ continue;
29
+ }
30
+ /**
31
+ * If there was an existing file, then we must get rid of it
32
+ */
33
+ if (originalAttachments[i]) {
34
+ originalAttachments[i].setOptions(options);
35
+ attachments.push(originalAttachments[i]);
36
+ }
37
+ }
38
+ }
39
+ await this.#moveForDeletion(attachments);
40
+ await this.#markForDeletion(attachments, record);
41
+ }));
42
+ }
43
+ /**
44
+ * Detach all attachments (mark all for deletion)
45
+ */
46
+ async detachAll(record) {
47
+ const attachmentAttributeNames = AttachmentUtils.getAttributeNamesOfAttachment(record.row);
48
+ await Promise.allSettled(attachmentAttributeNames.map((name) => {
49
+ const options = AttachmentUtils.getOptionsByAttributeName(record.row, name);
50
+ const attachments = AttachmentUtils.getAttachmentsByAttributeName(record.row, name);
51
+ for (let i = 0; i < attachments.length; i++) {
52
+ attachments[i].setOptions(options);
53
+ }
54
+ this.#markForDeletion(attachments, record);
55
+ }));
56
+ }
57
+ /**
58
+ * Mark attachments for deletion by adding them to detached array
59
+ */
60
+ async #markForDeletion(attachments, record) {
61
+ await Promise.allSettled(attachments.map((attachment) => record.row.$attachments.detached.push(attachment)));
62
+ }
63
+ async #moveForDeletion(attachments) {
64
+ await Promise.allSettled(attachments.map((attachment) => attachment.moveFileForDelete()));
65
+ }
66
+ }