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

Incorrect operation of upload property in avatar field configuration in next-admin library #480

Open
joriksp opened this issue Oct 30, 2024 · 10 comments

Comments

@joriksp
Copy link

joriksp commented Oct 30, 2024

Problem description

When using the upload property in the avatar field configuration in the User model, a problem occurs: instead of the expected string returned from the upload handler, the actual file itself is sent in the user change form. This leads to incorrect data processing on the server and can cause errors when saving data.

Steps for playback

  1. Configure the User model with the avatar field as shown in the example:
import { upload } from "@/lib/fileStorage";
import type { NextAdminOptions } from "@premieroctet/next-admin";

const options: NextAdminOptions = {
  model: {
     User: {
        edit: {
           fields: {
              avatar: {
                 format: "file",
                 required: true,
                 handler: {
                    upload: async (buffer, { name, type }) => {
                          const uploadedFile = await upload(
                             new File([buffer], name)
                          );
                          return uploadedFile.url || "";
                       },
                 },
              },
           },
        },
     },
  }
}

export default options;
  1. Try to change the user by uploading a file for the avatar field.
  2. Pay attention to the data sent to the server.

Expected behavior

When uploading a file, the value returned from the upload handler (in this case, the file name) should be sent for the avatar field, not the file itself.

Actual behavior

The file itself is sent to the server, not the file name, which causes problems with data processing.
{58481F4E-24CF-44FA-9742-6001B9E6ECE7}

More info

Next-admin library version: 6.1.6.
Nextjs version: 14.2.16.
Operating system: Windows 11
Browser: Chrome 130.0.6723.71.

@joriksp joriksp changed the title Feedback for “Model configuration” Incorrect operation of upload property in avatar field configuration in next-admin library Oct 30, 2024
@no-need-to-be-anonymous
Copy link

I have the same issue. Also, I cannot see any logs in the upload fn.

Next-admin library version: 6.1.6.
Nextjs version: 14.2.16.
Operating system: MacOS Sonoma 14.0
Browser: Chrome 130.0.6723.70

@cregourd
Copy link
Collaborator

cregourd commented Nov 4, 2024

Hi,

The upload function runs on the server side. You need to use it to process the uploading file and return a string (URL) that will be stored in your database and used to find the file when you display the form of the object.

When a form containing a file object is submitted, the client sends file data and information to the server, it catches this information and passes it to the upload function.

I don't quite understand your request, can you please give more details about your request to see if I'm missing something ?

@joriksp
Copy link
Author

joriksp commented Nov 4, 2024

This is a sample NextAdminOptions code from my project:

const options: NextAdminOptions = {
   model: {
      User: {
         edit: {
            fields: {
               avatar: {
                  format: "file",
                  required: true,
                  handler: {
                     upload: async (buffer, { name, type }) => {
                        const uploadedFile = await upload(
                           new File([buffer], name)
                        );
                        return uploadedFile.url || "";
                     },
                  },
               },
            },
         },
      },
};

Here, a function inside handler.upload with the same name takes in a File and returns an object with a download reference. Here is its code:

export const upload = async (file: File) => {
   const formData = new FormData();
   formData.append("file", file);

   try {
      const response = await fetch(`${fsHost}/upload`, {
         method: "POST",
         body: formData,
      });

      if (!response.ok) {
         return {
            success: false,
            message: `Request failed, ${response.status}`,
         };
      }

      const data: UploadedFile = await response.json();

      return data;
   } catch (error) {
      return {
         success: false,
         message: `Request failed, ${error}`,
      };
   }
};

if you add any debugging (console.log('example')) to handler.upload, it will not be displayed in the console

@cregourd
Copy link
Collaborator

cregourd commented Nov 8, 2024

Hi @joriksp,
To optimize performance and reduce computation, the form submits only dirty fields, if you don't modify or add a file, the function handler.upload won't run due to unmodified data. Perhaps this behavior explains why you don't see the log. It's not actually an issue but a default behavior
I hope this explains your issue, if not, please let us know

@joriksp
Copy link
Author

joriksp commented Nov 12, 2024

Hello, the problem is a bit of a misnomer. After selecting an image when I want to save new data the following error appears:

{8CC2B1AD-9650-4015-B83D-04571064DA62}

@cregourd
Copy link
Collaborator

What's the return type of your handler.upload function? This return type is passed to Prisma in your field, which appears to be named image.

This error means that you are trying to submit the output of your upload function without passing through handler.upload.

@jpalomino10
Copy link

@joriksp I had the same problem in my case was that I didn`t add the options on app/api/admin/[[...nextadmin]]/route.ts by default come commented

import { prisma } from "@/prisma";
import schema from "@/prisma/json-schema/json-schema.json";
import { createHandler } from "@premieroctet/next-admin/appHandler";
 
const { run } = createHandler({
  apiBasePath: "/api/admin",
  prisma,
  schema,
  /*options*/
});
 
export { run as DELETE, run as GET, run as POST };

@joriksp
Copy link
Author

joriksp commented Nov 13, 2024

What's the return type of your handler.upload function? This return type is passed to Prisma in your field, which appears to be named image.

This error means that you are trying to submit the output of your upload function without passing through handler.upload.

handler: {
                    upload: async (buffer, { name, type }) => {
                          const uploadedFile = await upload(
                             new File([buffer], name)
                          );
                          return uploadedFile.url || "";
                       },
                 },

It returns string (url)

@cregourd
Copy link
Collaborator

cregourd commented Nov 13, 2024

@joriksp I had the same problem in my case was that I didn`t add the options on app/api/admin/[[...nextadmin]]/route.ts by default come commented

import { prisma } from "@/prisma";
import schema from "@/prisma/json-schema/json-schema.json";
import { createHandler } from "@premieroctet/next-admin/appHandler";
 
const { run } = createHandler({
  apiBasePath: "/api/admin",
  prisma,
  schema,
  /*options*/
});
 
export { run as DELETE, run as GET, run as POST };

Indeed, thanks for the precision
If you are using options, which it seems you are, you need to pass the options to the createHandler function param. If you don't, any server-side function you add to the options file (such as handler.upload) will not be executed. In the example this part is commented because the options are optional, in your case you need to put options in there.

@joriksp please let me know if you have in the same case

@cregourd
Copy link
Collaborator

Also, to avoid other problems, we recommend putting options in the createHandler function params from the moment you use any options, even if it does not appear to be server-side execution.

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

4 participants