Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading simple local file gives: "no such file or directory, mkdir 'C:\\...\\api-fastify\\public\\files\\id()" ... "Resource: \"${this.resource.id()}\" does not have an id property" #83

Open
rw3iss opened this issue Jul 14, 2024 · 0 comments

Comments

@rw3iss
Copy link

rw3iss commented Jul 14, 2024

I'm trying to setup AdminJS on a simple fastify backend, using typeorm and postges. I have been having issues getting a file upload to work, suggesting there is no id property set on the resource.
Following the example app for a single file, the upload form seems to work, but when I save it the backend gives the error:

{
    "statusCode": 500,
    "code": "ENOENT",
    "error": "Internal Server Error",
    "message": "ENOENT: no such file or directory, mkdir 'C:\\Users\\rw3iss\\Sites\\api-fastify\\public\\files\\id() {\n        
        const idProperty = this.resource.properties().find(p => p.isId());\n        
        if (!idProperty) {\n           
            throw new Error(`Resource: \"${this.resource.id()}\" does not have an id property`);\n        
        }\n        
return this.params[idProperty.name()];\n    }'"
}

relevant package.json dependency versions are:

 "dependencies": {
        "@adminjs/fastify": "^4.1.3",
        "@adminjs/passwords": "^4.0.0",
        "@adminjs/typeorm": "^5.0.1",
        "@adminjs/upload": "^4.0.2",
        "@fastify/session": "^10.9.0",
        "adminjs": "^7.8.7",
        "connect-pg-simple": "^9.0.1",
        "fastify": "^4.28.1",
        "pg": "^8.12.0",
    }

The typeorm File entity is defined as:

import { BaseEntity, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';

@Entity({ name: 'files' })
export class File extends BaseEntity {

    @PrimaryGeneratedColumn()
    public id: number;

    @Column({ name: 'key', nullable: true, type: 'varchar' })
    public key: string;

    @Column({ nullable: true, type: 'varchar' })
    public bucket: string;

    @Column({ nullable: true, type: 'varchar' })
    public mime: string;

    @Column('int', { nullable: true })
    public size: number;

    @Column('varchar', { nullable: true })
    public comment: string;

    @CreateDateColumn({ name: 'created_at' })
    public createdAt: Date;

    @UpdateDateColumn({ name: 'updated_at' })
    public updatedAt: Date;

}

export interface IFile {
    id: number;
    key: string;
    bucket: string;
    mime: string;
    size: number;
    comment: string | null;
}

The AdminJS File resource:

import uploadFeature from '@adminjs/upload';
import { BaseRecord } from 'adminjs';
import { File } from './../file.entity';
import { CreateResourceResult } from './CreateResourceResult';

const localUploadProvider = {
    bucket: 'public/files',
    opts: {
        baseUrl: '/files',
    },
};

export const createFileResource = (componentLoader): CreateResourceResult<typeof File> => ({
    resource: File,
    options: {
        listProperties: ['id', 'key', 'bucket', 'path']
    },
    features: [
        uploadFeature({
            componentLoader,
            provider: {
                local: localUploadProvider
            },
            multiple: false,
            properties: {
                file: 'file',
                filename: 'filename',
                filePath: 'filePath',
                filesToDelete: 'filesToDelete',
                key: 'key',
                mimeType: 'mime',
                bucket: 'bucket',
                size: 'size'
            },
            validation: {
                mimeTypes: ['image/jpeg', 'image/png']
            },
            uploadPath: (record: BaseRecord, filename) => {
                console.log(`get upload path`, record.id, filename);
                return `${record.id}/${filename}`;
            }
        })
    ],
});

The AdminJS config/initialization is:

        const app = Fastify({ logger: config.debug });
        app.register(fastifyTypeorm, config.postgres);
        app.register(fastifyStatic, {
            root: path.join(import.meta.dirname, 'public'),
            prefix: '/',
        })

        const componentLoader = new ComponentLoader();
        const fileResource = createFileResource(componentLoader);

        const admin = new AdminJS({
            rootPath: '/admin',
            componentLoader,
            resources: [
                fileResource
            ]
        })
        admin.watch();

        await AdminJSFastify.buildAuthenticatedRouter(
            admin,
            {
                authenticate,
                cookiePassword: config.adminJs.cookieSecret,
                cookieName: config.adminJs.cookieSecret,
            },
            app,
            {
                store: sessionStore as any,
                saveUninitialized: true,
                secret: config.adminJs.cookieSecret,
                cookie: {
                    httpOnly: config.isProduction,
                    secure: config.isProduction
                },
            }
        )

Here's a screenshot of the upload page after saving:
Screenshot 2024-07-14 051254

In trying to debug I notice the adminjs library tries to assign the properties, but it seems the id property never has _isId: true, I only ever see it false for any property, even after the property decoration is finished and merged:

 PropertyDecorator {
  property: Property {
    _path: 'id',
    _type: 'string',
    _isId: false,
    _isSortable: true,
    _position: 1,
    column: ColumnMetadata {

I've tried to add the isId: true property to the File resource id property, but it still never shows _isId: true anywhere.

{
    resource: File,
    options: {
        listProperties: ['id', 'key', 'bucket', 'path'],
        properties: {
            id: {
                isId: true
            }
    }, ...

Any ideas? I don't know if this an issue in the typeorm adapter or the adminjs BaseAdapter not loading those properties as expected, or maybe my config is wrong. I have been trying to dig further into the adminjs and upload feature code to see why. Still working it out...

@rw3iss rw3iss changed the title Uploading simple local file gives: "no such file or directory, mkdir 'C:\\Users\\rw3iss\\Sites\\api-fastify\\public\\files\\id()" ... "Resource: \"${this.resource.id()}\" does not have an id property" Uploading simple local file gives: "no such file or directory, mkdir 'C:\\...\\api-fastify\\public\\files\\id()" ... "Resource: \"${this.resource.id()}\" does not have an id property" Jul 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant