adonisjs / attachment-lite Goto Github PK
View Code? Open in Web Editor NEWTurn any field on your Lucid models to an attachment data type
License: MIT License
Turn any field on your Lucid models to an attachment data type
License: MIT License
Many apps manage files that come from other sources than an HTTP request, for example an app might create invoices in a scheduled task, or process videos in a background job. And currently Attachment.fromFile()
requires a MultipartFileContract file to be passed in, which currently can only be obtained by using request.file or request.files
which of course are available only in HTTP requests, if we could pass a NodeJS Buffer, or create an object compatible with MultipartFileContract from a Buffer, this would be solved
Yes, currently it's possible to do this by creating the file manually using Adonis Drive and creating the attachment using Attachment.fromDbResponse
with a fake db response object.
Yes
File is not deleted after uploading to S3. The uploaded files are also stored in the temp folder.
1.0.4
Nodejs - v14.18.1
npm - 6.14.15
Use S3 as disk and upload a file. The same file will exist in the temp folder .
At the moment it is impossible to override the following column options on the attachment decorator: serialize, prepare and consume.
I've found the code where the options are configured here:
I think the column options should take priority in the spread so we may override them if we choose.
Ability to override serialize, prepare and consume options on the attachment() decorator for more advances serialization cases (ie. omit or not based on model $sideloaded values).
No it is impossible to use custom serialize, prepare and consume options on the attachment() decorator as of right now.
Absolutely. Easy change.
1.0.7 and 1.0.8
Node.js version = 18.12.0
npm version = 8.19.2
@attachment({ disk: 's3', folder: 'profiles', preComputeUrl: true })
public avatar?: AttachmentContract | null
The preComputeUrl is giving out the url like this - "https://endpoint/bucket,fileName".
The URL is missing "/" between the bucket name and fileName.
I am sorry if the format is wrong.
"@adonisjs/attachment-lite": "^1.0.4",
Nodejs - v14.18.1
npm - 6.14.15
I'm using with preComputedUrl on private s3 disk to get signed url. The problem is that when a new model is created, the pre-signed url will be saved into the model.
Because of the expiry on pre-signed url, the url is no longer valid on next access. Is there a way to refresh pre-signed url.
Is it intended behavior or am I doing wrong.
Thanks.
When a model contains the attachment
decorator the save
function of the model internally calls the saveWithAttachments
function of the decorator and returns undefined
instead of Promise<Model>
.
v1.0.7
Node.js: v18.15.0
npm: v9.5.0
Add the attachment
decorator to a model.
Sometimes you want to set disk/folder options for an attachment on the fly. For example, here I'm setting the folder option based on key
, refId
& entity
import { Attachment } from '@ioc:Adonis/Addons/AttachmentLite'
import { AuthContract } from '@ioc:Adonis/Addons/Auth'
import { TransactionClientContract } from '@ioc:Adonis/Lucid/Database'
import Entity from 'App/Models/System/Entity'
import Media from 'App/Models/System/Media'
import StoreMediaValidator from 'App/Validators/System/StoreMediaValidator'
import Env from '@ioc:Adonis/Core/Env'
export default class StoreMedia {
public static async handle(
{ file, key, refId, entity }: StoreMediaValidator['schema']['props'],
auth: AuthContract,
client?: TransactionClientContract
) {
const folder = `${Env.get('NODE_ENV')}/${entity}/${refId}/${key}`
return await Media.create(
{
file: Attachment.fromFile(file).setOptions({ folder }),
key,
refId,
entity: Entity[entity],
createdBy: auth.user?.id
},
{ client }
)
}
}
In this case the folder defaults to the one specified on the @attachment decorator in my Media model.
Yes, I tried Attachment.fromFile(file).setOptions({ folder }).save()
which uploads to the correct folder but I could not retrieve the correct path in order to persist it in the DB.
Yes, of course. Happy to take this on ๐
Currently we cannot set custom expire time for signed url with preCompute option. Is it possible to add expiresIn option when using pre computed url.
Not yet.
Yes.
I've noticed a persistent and unavoidable error when DB response is null
. In a typical usage of the addon, not all attachment column will return the expected format which is parse-able by the add-on. Some columns will contain null
values. The add-on current fails when null
values are encountered.
The issue can be traced to these lines:
attachment-lite/src/Attachment/index.ts
Lines 64 to 75 in 4f05e55
When attributes
is null
, the Array.forEach
call fails. A suggestion is for the add-on to provide a no-op
when null
is encountered.
1.0.1
Node: 14.18.2. NPM: 6.14.15
attachment-lite/src/Attachment/index.ts
Lines 64 to 75 in 4f05e55
The README states that I can use the computeUrl
function to compute URL on demand. This does not work however because the function only computes the URL when the preComputeUrl
config is set.
v1.0.7
Node.js: v18.15.0
npm: v9.5.0
DO NOT set the preComputeUrl
property on the decorator config and use the computeUrl
function.
The URL is not set on the attachment.
1.0.7
v20.5.1
import { Attachment } from '@ioc:Adonis/Addons/AttachmentLite'
class UsersController {
public store({ request }: HttpContextContract) {
const avatar = request.file('avatar')!
const user = new User()
user.avatar = Attachment.fromFile(avatar)
await user.save()
}
}
[07:43:22.223] ERROR (adonis/941667): existingFile.setOptions is not a function
err: {
"type": "TypeError",
"message": "existingFile.setOptions is not a function",
"stack":
TypeError: existingFile.setOptions is not a function
at persistAttachment (/xxx/adonis/node_modules/@adonisjs/attachment-lite/build/src/Attachment/decorator.js:45:26)
at /xxx/adonis/node_modules/@adonisjs/attachment-lite/build/src/Attachment/decorator.js:83:80
at Array.map (<anonymous>)
at Proxy.saveWithAttachments (/xxx/adonis/node_modules/@adonisjs/attachment-lite/build/src/Attachment/decorator.js:83:55)
at UserController.avatar (/xxx/adonis/app/Controllers/UserController.ts:128:23)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at Object.PreCompiler.runRouteHandler [as fn] (/xxx/adonis/node_modules/@adonisjs/http-server/build/src/Server/PreCompiler/index.js:47:31)
at AuthMiddleware.handle (/xxx/adonis/app/Middleware/Auth.ts:76:5)
at SilentAuthMiddleware.handle (/xxx/adonis/app/Middleware/SilentAuth.ts:19:5)
at Server.handleRequest (/xxx/adonis/node_modules/@adonisjs/http-server/build/src/Server/index.js:108:13)
"status": 500
}
Following the README:
[...] We recommend not enabling the preComputeUrl option when you need the URL for just one or two queries and not within the rest of your application. [...]
But, in file Attachment/index.ts on line 233, the computeUrl() mehtod return nothing if the options.preComputeUrl is undefined or false
attachment-lite/src/Attachment/index.ts
Lines 233 to 235 in 8144c36
1.0.7
node: v14.18.2
npm: 6.14.15
Same code of README
Would be nice to specify names/prefixes for uploaded images.
Something like this
data.avatar = Attachment.fromFile(avatar, {name: new Date().getTime() + '-avatar'} );
Whenever I make an attachment from an uploaded file the name is always undefined, which causes an error on getUrl()
and likely other methods. From what I can tell in the code the fromFile
method never sets the name?
1.0.7
v18.16.0 and 9.5.1
const att = Attachment.fromFile(someFile);
console.log(att.name); // undefined
console.log(att.getUrl()); // error
1.0.7
18.16.0, pnpm 8.2.0
Users often upload very large photos as avatars and we want to resize it and convert to webp to save storage space. However, Attachment
only created from the MultipartFileContract
that is directly from request
. Even I override the file with converted webp, it still store file info of previous PNG/JPG.
const tempFile = await file();
await sharp(avatar.tmpPath).webp().toFile(tempFile.path);
await rename(tempFile.path, avatar.tmpPath);
auth.user!.avatar = Attachment.fromFile(avatar);
Is here a good practice to do image conversion with Attachment? Thanks!
Hi there! I've been having trouble recently with using model factories because of how we can create Attachment objects.
I cannot create an Attachment object because:
I'm wondering if there's any other way to create an Attachment object? ๐ If not, you could guide me on what I could PR to help fix this issue?
Thank you.
Confusing for first time user to use the package since the documentation never mention anything about creating a column in migration for the model
It should mention to add a column in migration with the type json and example like the following
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
export default class UsersSchema extends BaseSchema {
protected tableName = 'users'
public async up() {
this.schema.createTable(this.tableName, (table) => {
table.uuid('id').primary()
table.string('email', 255).unique().notNullable()
table.string('password', 180).notNullable()
table.string('username', 32).unique().notNullable()
table.string('remember_me_token').nullable()
__table.json('avatar').nullable()__
table.string('description', 255).nullable()
/**
* Uses timestampz for PostgreSQL and DATETIME2 for MSSQL
*/
table.timestamp('created_at', { useTz: true }).notNullable()
table.timestamp('updated_at', { useTz: true }).notNullable()
})
}
public async down() {
this.schema.dropTable(this.tableName)
}
}
https://github.com/ndianabasi/adonis-responsive-attachment V 1.3.0
Node version: v16.11.0
Npm version: 8.0.0
When getting images from the databases, you can use Image.query()
or Database.from(Image.table)
.
When using Database.from(Image.table)
, your SGBD return usable timestamp, so it can help to use this method. But, with version V 1.3.0
of this packages, the image's url dosn't compute when using Database.from(Image.table)
as you can see below
Images models:
@responsiveAttachment({
folder: 'images',
preComputeUrls: true,
breakpoints: {
medium: 'off',
large: 'off',
thumbmail: 'off',
},
})
public data: ResponsiveAttachmentContract
Query to fetch an image
public async show({ params }: HttpContextContract) {
const image = await Image.findOrFail(params.id)
return image
}
Return this result:
{
"folder_id": 9,
"id": 1000,
"title": "IMG_7740.png",
"data": {
"name": "images/original_cl3od91bf000argxi5zmohrc5.png",
"size": 23187.75,
"hash": "cl3od91bf000argxi5zmohrc5",
"width": 3861,
"format": "png",
"height": 2574,
"extname": "png",
"mimeType": "image/png",
"breakpoints": {
"thumbnail": {
"name": "images/thumbnail_cl3od91bf000argxi5zmohrc5.png",
"hash": "cl3od91bf000argxi5zmohrc5",
"extname": "png",
"mimeType": "image/png",
"format": "png",
"width": 234,
"height": 156,
"size": 96.57,
"url": "/uploads/images/thumbnail_cl3od91bf000argxi5zmohrc5.png"
},
"small": {
"name": "images/small_cl3od91bf000argxi5zmohrc5.png",
"hash": "cl3od91bf000argxi5zmohrc5",
"extname": "png",
"mimeType": "image/png",
"format": "png",
"width": 500,
"height": 333,
"size": 428.04,
"url": "/uploads/images/small_cl3od91bf000argxi5zmohrc5.png"
}
},
"url": "/uploads/images/original_cl3od91bf000argxi5zmohrc5.png"
},
"raw": null,
"created_at": "2022-05-27T13:33:58.194+02:00",
"updated_at": "2022-05-27T13:33:58.194+02:00"
}
But if you're using this method to fetch from db:
public async show({ params }: HttpContextContract) {
const image = await Database.from(Image.table).where('id', params.id).first()
return image
}
The result is:
{
"folder_id": 9,
"id": 1000,
"title": "IMG_7740.png",
"data": {
"name": "images/original_cl3od91bf000argxi5zmohrc5.png",
"size": 23187.75,
"hash": "cl3od91bf000argxi5zmohrc5",
"width": 3861,
"format": "png",
"height": 2574,
"extname": "png",
"mimeType": "image/png",
"breakpoints": {
"thumbnail": {
"name": "images/thumbnail_cl3od91bf000argxi5zmohrc5.png",
"hash": "cl3od91bf000argxi5zmohrc5",
"extname": "png",
"mimeType": "image/png",
"format": "png",
"width": 234,
"height": 156,
"size": 96.57
},
"small": {
"name": "images/small_cl3od91bf000argxi5zmohrc5.png",
"hash": "cl3od91bf000argxi5zmohrc5",
"extname": "png",
"mimeType": "image/png",
"format": "png",
"width": 500,
"height": 333,
"size": 428.04
}
}
},
"raw": null,
"created_at": "2022-05-27T11:33:58.194Z",
"updated_at": "2022-05-27T11:33:58.194Z"
}
There is no URL, and the timestamp are TZ
I'm really sorry if this is normal, but, it worked on previous version 1.2.2
so i thought something happened since then
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.