@jrmc/adonis-attachment 3.1.0 → 3.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.
Files changed (45) hide show
  1. package/README.md +4 -0
  2. package/build/src/adapters/meta.d.ts +3 -0
  3. package/build/src/adapters/meta.js +40 -0
  4. package/build/src/attachment_manager.d.ts +5 -5
  5. package/build/src/attachment_manager.js +39 -27
  6. package/build/src/attachments/attachment.js +9 -2
  7. package/build/src/decorators/attachment.js +25 -0
  8. package/build/src/errors.d.ts +15 -15
  9. package/build/src/mixins/attachmentable.d.ts +5 -314
  10. package/build/src/mixins/attachmentable.js +10 -88
  11. package/build/src/types/converter.d.ts +22 -1
  12. package/build/src/types/input.d.ts +5 -0
  13. package/build/src/utils/helpers.d.ts +0 -7
  14. package/build/src/utils/helpers.js +4 -26
  15. package/build/src/utils/hooks.d.ts +11 -0
  16. package/build/src/utils/hooks.js +92 -0
  17. package/package.json +18 -16
  18. package/build/bin/test.d.ts +0 -1
  19. package/build/bin/test.js +0 -34
  20. package/build/tests/attachment-manager.spec.d.ts +0 -7
  21. package/build/tests/attachment-manager.spec.js +0 -234
  22. package/build/tests/attachment.spec.d.ts +0 -7
  23. package/build/tests/attachment.spec.js +0 -16
  24. package/build/tests/commands.spec.d.ts +0 -7
  25. package/build/tests/commands.spec.js +0 -58
  26. package/build/tests/fixtures/converters/image_converter.d.ts +0 -12
  27. package/build/tests/fixtures/converters/image_converter.js +0 -12
  28. package/build/tests/fixtures/factories/user.d.ts +0 -8
  29. package/build/tests/fixtures/factories/user.js +0 -19
  30. package/build/tests/fixtures/factories/user_with_variants.d.ts +0 -8
  31. package/build/tests/fixtures/factories/user_with_variants.js +0 -19
  32. package/build/tests/fixtures/migrations/create_users_table.d.ts +0 -12
  33. package/build/tests/fixtures/migrations/create_users_table.js +0 -23
  34. package/build/tests/fixtures/models/user.d.ts +0 -466
  35. package/build/tests/fixtures/models/user.js +0 -36
  36. package/build/tests/fixtures/models/user_with_variants.d.ts +0 -465
  37. package/build/tests/fixtures/models/user_with_variants.js +0 -33
  38. package/build/tests/helpers/app.d.ts +0 -29
  39. package/build/tests/helpers/app.js +0 -104
  40. package/build/tests/helpers/index.d.ts +0 -7
  41. package/build/tests/helpers/index.js +0 -7
  42. package/build/tests/options.spec.d.ts +0 -7
  43. package/build/tests/options.spec.js +0 -126
  44. package/build/tests/variants.spec.d.ts +0 -7
  45. package/build/tests/variants.spec.js +0 -21
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @jrmc/adonis-attachment
3
+ *
4
+ * @license MIT
5
+ * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
+ */
7
+ import { persistAttachment, commit, rollback, generateVariants, preComputeUrl, } from '../utils/actions.js';
8
+ import { clone, getAttachmentAttributeNames, getDirtyAttachmentAttributeNames, } from '../utils/helpers.js';
9
+ import { defaultStateAttributeMixin } from '../utils/default_values.js';
10
+ // @afterFind()
11
+ export const afterFindHook = async (instance) => {
12
+ const modelInstance = instance;
13
+ const attachmentAttributeNames = getAttachmentAttributeNames(modelInstance);
14
+ await Promise.all(attachmentAttributeNames.map((attributeName) => {
15
+ return preComputeUrl(modelInstance, attributeName);
16
+ }));
17
+ };
18
+ // @afterFetch()
19
+ // @afterPaginate()
20
+ export const afterFetchHook = async (instance) => {
21
+ const modelInstances = instance;
22
+ await Promise.all(modelInstances.map((row) => afterFindHook(row)));
23
+ };
24
+ // @beforeSave()
25
+ export const beforeSaveHook = async (instance) => {
26
+ const modelInstance = instance;
27
+ const attachmentAttributeNames = getDirtyAttachmentAttributeNames(modelInstance);
28
+ /**
29
+ * Empty previous $attachments
30
+ */
31
+ modelInstance.$attachments = clone(defaultStateAttributeMixin);
32
+ /**
33
+ * Set attributes Attachment type modified
34
+ */
35
+ attachmentAttributeNames.forEach((attributeName) => modelInstance.$attachments.attributesModified.push(attributeName));
36
+ /**
37
+ * Persist attachments before saving the model to the database. This
38
+ * way if file saving fails we will not write anything to the
39
+ * database
40
+ */
41
+ await Promise.all(attachmentAttributeNames.map((attributeName) => persistAttachment(modelInstance, attributeName)));
42
+ try {
43
+ if (modelInstance.$trx) {
44
+ modelInstance.$trx.after('commit', () => commit(modelInstance));
45
+ modelInstance.$trx.after('rollback', () => rollback(modelInstance));
46
+ }
47
+ else {
48
+ await commit(modelInstance);
49
+ }
50
+ }
51
+ catch (error) {
52
+ await rollback(modelInstance);
53
+ throw error;
54
+ }
55
+ };
56
+ // @afterSave()
57
+ export const afterSaveHook = async (instance) => {
58
+ const modelInstance = instance;
59
+ const attachmentAttributeNames = getAttachmentAttributeNames(modelInstance);
60
+ /**
61
+ * For all properties Attachment
62
+ * Launch async generation variants
63
+ */
64
+ await Promise.all(attachmentAttributeNames.map((attributeName) => {
65
+ if (modelInstance.$attachments.attributesModified.includes(attributeName)) {
66
+ return generateVariants(modelInstance, attributeName);
67
+ }
68
+ }));
69
+ };
70
+ // @beforeDelete()
71
+ export const beforeDeleteHook = async (instance) => {
72
+ const modelInstance = instance;
73
+ const attachmentAttributeNames = getAttachmentAttributeNames(modelInstance);
74
+ /**
75
+ * Mark all attachments for deletion
76
+ */
77
+ attachmentAttributeNames.map((attributeName) => {
78
+ if (modelInstance.$attributes[attributeName]) {
79
+ modelInstance.$attachments.detached.push(modelInstance.$attributes[attributeName]);
80
+ }
81
+ });
82
+ /**
83
+ * If model is using transaction, then wait for the transaction
84
+ * to settle
85
+ */
86
+ if (modelInstance.$trx) {
87
+ modelInstance.$trx.after('commit', () => commit(modelInstance));
88
+ }
89
+ else {
90
+ await commit(modelInstance);
91
+ }
92
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrmc/adonis-attachment",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "type": "module",
5
5
  "description": "Turn any field on your Lucid model to an attachment data type",
6
6
  "engines": {
@@ -64,28 +64,30 @@
64
64
  "./attachment_provider": "./build/providers/attachment_provider.js"
65
65
  },
66
66
  "dependencies": {
67
- "@poppinss/defer": "^1.1.0",
68
- "exifreader": "^4.25.0",
69
- "file-type": "^19.6.0"
67
+ "@poppinss/defer": "^1.1.1",
68
+ "exifreader": "^4.26.0",
69
+ "file-type": "^19.6.0",
70
+ "mime-types": "^2.1.35"
70
71
  },
71
72
  "devDependencies": {
72
73
  "@adonisjs/assembler": "^7.8.2",
73
- "@adonisjs/core": "^6.17.0",
74
+ "@adonisjs/core": "^6.17.1",
74
75
  "@adonisjs/drive": "^3.2.0",
75
- "@adonisjs/lucid": "^21.5.1",
76
+ "@adonisjs/lucid": "^21.6.0",
76
77
  "@adonisjs/prettier-config": "^1.4.0",
77
78
  "@adonisjs/tsconfig": "^1.4.0",
78
- "@japa/assert": "^3.0.0",
79
- "@japa/expect-type": "^2.0.2",
80
- "@japa/file-system": "^2.3.0",
81
- "@japa/plugin-adonisjs": "^3.0.1",
82
- "@japa/runner": "^3.1.4",
83
- "@poppinss/utils": "^6.8.3",
84
- "@swc/core": "^1.10.1",
79
+ "@japa/assert": "^4.0.1",
80
+ "@japa/expect-type": "^2.0.3",
81
+ "@japa/file-system": "^2.3.2",
82
+ "@japa/plugin-adonisjs": "^4.0.0",
83
+ "@japa/runner": "^4.1.0",
84
+ "@poppinss/utils": "^6.9.2",
85
+ "@swc/core": "^1.10.7",
85
86
  "@types/luxon": "^3.4.2",
86
- "@types/node": "^22.10.2",
87
+ "@types/mime-types": "^2.1.4",
88
+ "@types/node": "^22.10.7",
87
89
  "@types/sinon": "^17.0.3",
88
- "better-sqlite3": "^11.7.0",
90
+ "better-sqlite3": "^11.8.0",
89
91
  "c8": "^10.1.3",
90
92
  "copyfiles": "^2.4.1",
91
93
  "del-cli": "^6.0.0",
@@ -93,7 +95,7 @@
93
95
  "luxon": "^3.5.0",
94
96
  "prettier": "^3.4.2",
95
97
  "ts-node": "^10.9.2",
96
- "typescript": "^5.7.2",
98
+ "typescript": "^5.7.3",
97
99
  "vitepress": "^1.5.0"
98
100
  },
99
101
  "peerDependencies": {
@@ -1 +0,0 @@
1
- export {};
package/build/bin/test.js DELETED
@@ -1,34 +0,0 @@
1
- import { assert } from '@japa/assert';
2
- import { expectTypeOf } from '@japa/expect-type';
3
- import { processCLIArgs, configure, run } from '@japa/runner';
4
- import { createApp, initializeDatabase } from '../tests/helpers/app.js';
5
- import { fileSystem } from '@japa/file-system';
6
- import app from '@adonisjs/core/services/app';
7
- import { BASE_URL } from '../tests/helpers/index.js';
8
- let testApp;
9
- processCLIArgs(process.argv.slice(2));
10
- configure({
11
- files: ['tests/**/*.spec.ts'],
12
- plugins: [assert(), fileSystem({ basePath: BASE_URL }), expectTypeOf()],
13
- setup: [
14
- async () => {
15
- testApp = await createApp();
16
- await initializeDatabase(testApp);
17
- },
18
- ],
19
- teardown: [
20
- async () => {
21
- await app.terminate();
22
- await testApp.terminate();
23
- },
24
- ],
25
- });
26
- /*
27
- |--------------------------------------------------------------------------
28
- | Run tests
29
- |--------------------------------------------------------------------------
30
- |
31
- | The following "run" method is required to execute all the tests.
32
- |
33
- */
34
- run();
@@ -1,7 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- export {};
@@ -1,234 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import https from 'node:https';
8
- import { readFile } from 'node:fs/promises';
9
- import { test } from '@japa/runner';
10
- import app from '@adonisjs/core/services/app';
11
- import drive from '@adonisjs/drive/services/main';
12
- import { MultipartFileFactory } from '@adonisjs/core/factories/bodyparser';
13
- import { UserFactory } from './fixtures/factories/user.js';
14
- import { attachmentManager } from '../index.js';
15
- test.group('attachment-manager', () => {
16
- test('save method - should result in noop when attachment is created from db response', async ({ assert, }) => {
17
- const attachmentManager = await app.container.make('jrmc.attachment');
18
- const attachment = attachmentManager.createFromDbResponse(JSON.stringify({
19
- size: 1440,
20
- name: 'foo123.jpg',
21
- originalName: 'foo.jpg',
22
- extname: 'jpg',
23
- mimeType: 'image/jpg',
24
- }));
25
- assert.equal(attachment?.originalName, 'foo.jpg');
26
- });
27
- test('Attachment - should be null when db response is null', async ({ assert }) => {
28
- const attachmentManager = await app.container.make('jrmc.attachment');
29
- const attachment = attachmentManager.createFromDbResponse(null);
30
- assert.isNull(attachment);
31
- });
32
- test('Attachment path default is uploads', async ({ assert }) => {
33
- const attachmentManager = await app.container.make('jrmc.attachment');
34
- const attachment = attachmentManager.createFromDbResponse(JSON.stringify({
35
- size: 1440,
36
- name: 'foo.jpg',
37
- extname: 'jpg',
38
- mimeType: 'image/jpg',
39
- }));
40
- assert.equal(attachment?.path, 'uploads/foo.jpg');
41
- });
42
- test('Attachment path - should be custom', async ({ assert }) => {
43
- const attachmentManager = await app.container.make('jrmc.attachment');
44
- const attachment = attachmentManager.createFromDbResponse(JSON.stringify({
45
- size: 1440,
46
- name: 'foo.jpg',
47
- extname: 'jpg',
48
- mimeType: 'image/jpg',
49
- }));
50
- attachment?.setOptions({ folder: 'avatar' });
51
- assert.equal(attachment?.path, 'avatar/foo.jpg');
52
- });
53
- test('Attachment get url', async ({ assert, cleanup }) => {
54
- drive.fake('fs');
55
- cleanup(() => drive.restore('fs'));
56
- const attachmentManager = await app.container.make('jrmc.attachment');
57
- const attachment = attachmentManager.createFromDbResponse(JSON.stringify({
58
- size: 1440,
59
- name: 'foo.jpg',
60
- extname: 'jpg',
61
- mimeType: 'image/jpg',
62
- }));
63
- attachment?.setOptions({ folder: 'avatars' });
64
- const url = await attachment?.getUrl();
65
- const signedUrl = await attachment?.getSignedUrl();
66
- assert.match(url, /\/drive\/fakes\/avatars\/foo\.jpg/);
67
- assert.match(signedUrl, /\/drive\/fakes\/signed\/avatars\/foo\.jpg/);
68
- });
69
- test('Precompute file url', async ({ assert, cleanup }) => {
70
- drive.fake('fs');
71
- cleanup(() => drive.restore('fs'));
72
- const attachmentManager = await app.container.make('jrmc.attachment');
73
- const attachment = attachmentManager.createFromDbResponse(JSON.stringify({
74
- size: 1440,
75
- name: 'foo.jpg',
76
- extname: 'jpg',
77
- mimeType: 'image/jpg',
78
- }));
79
- attachment?.setOptions({ preComputeUrl: true, folder: 'avatars' });
80
- await attachmentManager.preComputeUrl(attachment);
81
- assert.match(attachment?.url, /\/drive\/fakes\/avatars\/foo\.jpg/);
82
- });
83
- test('with base64 (prefix)', async ({ assert }) => {
84
- const avatar = await attachmentManager.createFromBase64('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=', 'avatar.png');
85
- const user = await UserFactory.merge({ avatar }).create();
86
- const data = await user.serialize();
87
- assert.deepEqual(data.avatar, {
88
- extname: 'png',
89
- meta: {
90
- dimension: {
91
- height: 24,
92
- width: 24,
93
- },
94
- host: 'www.inkscape.org',
95
- },
96
- mimeType: 'image/png',
97
- name: data.avatar.name,
98
- originalName: 'avatar.png',
99
- size: 965,
100
- });
101
- });
102
- test('with base64 (no prefix)', async ({ assert }) => {
103
- const avatar = await attachmentManager.createFromBase64('iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=', 'avatar.png');
104
- const user = await UserFactory.merge({ avatar }).create();
105
- const data = await user.serialize();
106
- assert.deepEqual(data.avatar, {
107
- extname: 'png',
108
- meta: {
109
- dimension: {
110
- height: 24,
111
- width: 24,
112
- },
113
- host: 'www.inkscape.org',
114
- },
115
- mimeType: 'image/png',
116
- name: data.avatar.name,
117
- originalName: 'avatar.png',
118
- size: 965,
119
- });
120
- });
121
- test('with buffer', async ({ assert }) => {
122
- const buffer = await readFile(app.makePath('../fixtures/images/img.jpg'));
123
- const avatar = await attachmentManager.createFromBuffer(buffer, 'avatar.jpg');
124
- const user = await UserFactory.merge({ avatar }).create();
125
- const data = await user.serialize();
126
- assert.deepEqual(data.avatar, {
127
- extname: 'jpg',
128
- meta: {
129
- dimension: {
130
- height: 1313,
131
- width: 1920,
132
- },
133
- },
134
- mimeType: 'image/jpeg',
135
- name: data.avatar.name,
136
- originalName: 'avatar.jpg',
137
- size: 122851,
138
- });
139
- });
140
- test('with file', async ({ assert }) => {
141
- const file = new MultipartFileFactory()
142
- .merge({
143
- size: 4000000,
144
- extname: 'jpg',
145
- type: 'image',
146
- subtype: 'jpeg',
147
- })
148
- .create();
149
- file.tmpPath = app.makePath('../fixtures/images/img.jpg');
150
- const avatar = await attachmentManager.createFromFile(file);
151
- const user = await UserFactory.merge({ avatar }).create();
152
- const data = await user.serialize();
153
- assert.deepEqual(data.avatar, {
154
- extname: 'jpg',
155
- meta: {
156
- dimension: {
157
- height: 1313,
158
- width: 1920,
159
- },
160
- },
161
- mimeType: 'image/jpeg',
162
- name: data.avatar.name,
163
- originalName: 'file.jpg',
164
- size: 4000000,
165
- });
166
- });
167
- test('with path', async ({ assert }) => {
168
- const path = app.makePath('../fixtures/images/img.jpg');
169
- const avatar = await attachmentManager.createFromPath(path, 'file.jpg');
170
- const user = await UserFactory.merge({ avatar }).create();
171
- const data = await user.serialize();
172
- assert.deepEqual(data.avatar, {
173
- extname: 'jpg',
174
- meta: {
175
- dimension: {
176
- height: 1313,
177
- width: 1920,
178
- },
179
- },
180
- mimeType: 'image/jpeg',
181
- name: data.avatar.name,
182
- originalName: 'file.jpg',
183
- size: 83,
184
- });
185
- });
186
- test('with url', async ({ assert }) => {
187
- const url = new URL('https://raw.githubusercontent.com/batosai/adonis-attachment/refs/heads/develop/tests/fixtures/images/img.jpg');
188
- const avatar = await attachmentManager.createFromUrl(url, 'file.jpg');
189
- const user = await UserFactory.merge({ avatar }).create();
190
- const data = await user.serialize();
191
- assert.deepEqual(data.avatar, {
192
- extname: 'jpg',
193
- meta: {
194
- dimension: {
195
- height: 1313,
196
- width: 1920,
197
- },
198
- },
199
- mimeType: 'image/jpeg',
200
- name: data.avatar.name,
201
- originalName: 'file.jpg',
202
- size: 31,
203
- });
204
- });
205
- test('with stream', async ({ assert }) => {
206
- async function downloadImageStream(input) {
207
- return await new Promise((resolve) => {
208
- https.get(input, (response) => {
209
- if (response.statusCode === 200) {
210
- resolve(response);
211
- }
212
- });
213
- });
214
- }
215
- const url = new URL('https://raw.githubusercontent.com/batosai/adonis-attachment/refs/heads/develop/tests/fixtures/images/img.jpg');
216
- const stream = await downloadImageStream(url);
217
- const avatar = await attachmentManager.createFromStream(stream, 'file.jpg');
218
- const user = await UserFactory.merge({ avatar }).create();
219
- const data = await user.serialize();
220
- assert.deepEqual(data.avatar, {
221
- extname: 'jpg',
222
- meta: {
223
- dimension: {
224
- height: 1313,
225
- width: 1920,
226
- },
227
- },
228
- mimeType: 'image/jpeg',
229
- name: data.avatar.name,
230
- originalName: 'file.jpg',
231
- size: 31,
232
- });
233
- });
234
- });
@@ -1,7 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- export {};
@@ -1,16 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { test } from '@japa/runner';
8
- import { UserFactory } from './fixtures/factories/user.js';
9
- test.group('attachment', () => {
10
- test('delete', async ({ assert }) => {
11
- const user = await UserFactory.create();
12
- user.avatar = null;
13
- await user.save();
14
- assert.isNull(user.avatar);
15
- });
16
- });
@@ -1,7 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- export {};
@@ -1,58 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { test } from '@japa/runner';
8
- import Configure from '@adonisjs/core/commands/configure';
9
- import { IgnitorFactory } from '@adonisjs/core/factories';
10
- import MakeConverter from '../commands/make/converter.js';
11
- import { BASE_URL } from './helpers/index.js';
12
- async function setupFakeAdonisProject(fs) {
13
- await Promise.all([
14
- fs.create('.env', ''),
15
- fs.createJson('tsconfig.json', {}),
16
- fs.create('adonisrc.ts', `export default defineConfig({})`),
17
- ]);
18
- }
19
- async function setupApp() {
20
- const ignitor = new IgnitorFactory()
21
- .withCoreProviders()
22
- .withCoreConfig()
23
- .create(BASE_URL, {
24
- importer: (filePath) => {
25
- if (filePath.startsWith('./') || filePath.startsWith('../')) {
26
- return import(new URL(filePath, BASE_URL).href);
27
- }
28
- return import(filePath);
29
- },
30
- });
31
- const app = ignitor.createApp('web');
32
- await app.init();
33
- await app.boot();
34
- const ace = await app.container.make('ace');
35
- ace.ui.switchMode('raw');
36
- return { ace, app };
37
- }
38
- test.group('configure', (group) => {
39
- group.tap((t) => t.timeout(20_000));
40
- group.each.setup(async ({ context }) => setupFakeAdonisProject(context.fs));
41
- test('add provider, config file, and command', async ({ assert }) => {
42
- const { ace } = await setupApp();
43
- const command = await ace.create(Configure, ['../../configure.js']);
44
- await command.exec();
45
- command.assertSucceeded();
46
- await assert.fileExists('config/attachment.ts');
47
- await assert.fileExists('adonisrc.ts');
48
- await assert.fileContains('adonisrc.ts', '@jrmc/adonis-attachment/attachment_provider');
49
- await assert.fileContains('adonisrc.ts', '@jrmc/adonis-attachment/commands');
50
- });
51
- test('create converter', async ({ assert }) => {
52
- const { ace } = await setupApp();
53
- const command = await ace.create(MakeConverter, ['thumb']);
54
- await command.exec();
55
- command.assertSucceeded();
56
- await assert.fileExists('app/converters/thumb_converter.ts');
57
- });
58
- });
@@ -1,12 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import type { ConverterAttributes } from '../../../src/types/converter.js';
8
- import type { Input } from '../../../src/types/input.js';
9
- import Converter from '../../../src/converters/converter.js';
10
- export default class ImageConverter extends Converter {
11
- handle({ input }: ConverterAttributes): Promise<Input>;
12
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import Converter from '../../../src/converters/converter.js';
8
- export default class ImageConverter extends Converter {
9
- async handle({ input }) {
10
- return input;
11
- }
12
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import User from '../models/user.js';
8
- export declare const UserFactory: import("@adonisjs/lucid/types/factory").FactoryBuilderQueryContract<typeof User, import("@adonisjs/lucid/types/factory").FactoryModelContract<typeof User>>;
@@ -1,19 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { readFile } from 'node:fs/promises';
8
- import User from '../models/user.js';
9
- import Factory from '@adonisjs/lucid/factories';
10
- import app from '@adonisjs/core/services/app';
11
- export const UserFactory = Factory.define(User, async ({ faker }) => {
12
- const attachmentManager = await app.container.make('jrmc.attachment');
13
- const buffer = await readFile(app.makePath('../fixtures/images/img.jpg'));
14
- const avatar = await attachmentManager.createFromBuffer(buffer, 'avatar.jpg');
15
- return {
16
- name: faker.person.lastName(),
17
- avatar,
18
- };
19
- }).build();
@@ -1,8 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import User from '../models/user_with_variants.js';
8
- export declare const UserFactory: import("@adonisjs/lucid/types/factory").FactoryBuilderQueryContract<typeof User, import("@adonisjs/lucid/types/factory").FactoryModelContract<typeof User>>;
@@ -1,19 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { readFile } from 'node:fs/promises';
8
- import User from '../models/user_with_variants.js';
9
- import Factory from '@adonisjs/lucid/factories';
10
- import app from '@adonisjs/core/services/app';
11
- export const UserFactory = Factory.define(User, async ({ faker }) => {
12
- const attachmentManager = await app.container.make('jrmc.attachment');
13
- const buffer = await readFile(app.makePath('../fixtures/images/img.jpg'));
14
- const avatar = await attachmentManager.createFromBuffer(buffer, 'avatar.jpg');
15
- return {
16
- name: faker.person.lastName(),
17
- avatar,
18
- };
19
- }).build();
@@ -1,12 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { BaseSchema } from '@adonisjs/lucid/schema';
8
- export default class extends BaseSchema {
9
- protected tableName: string;
10
- up(): Promise<void>;
11
- down(): Promise<void>;
12
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * @jrmc/adonis-attachment
3
- *
4
- * @license MIT
5
- * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
6
- */
7
- import { BaseSchema } from '@adonisjs/lucid/schema';
8
- export default class extends BaseSchema {
9
- tableName = 'users';
10
- async up() {
11
- this.schema.createTable(this.tableName, (table) => {
12
- table.increments('id');
13
- table.string('name');
14
- table.json('avatar');
15
- table.json('avatar_2');
16
- table.timestamp('created_at');
17
- table.timestamp('updated_at');
18
- });
19
- }
20
- async down() {
21
- this.schema.dropTable(this.tableName);
22
- }
23
- }