Skip to content

Using form.onPart() to validate file type/name and then form.parse to receive the file #617

@droddy

Description

@droddy

Should I be able to use form.onPart() along with form.parse() in order to

form.onPart(): test for valid file types and return validation message if that fails or continue on to...

form.parse(): parse the file if the validation in form.onPart() passes?

I can't seem to find the right way to do this.

CONTROLLER:

class {
  public initializeRoutes() {
    this.router.post(
      '/file',
      this.uploadFile,
    );
  }
  formidableOptions = {
    encoding: 'utf-8',
    keepExtensions: true,
    // 3 mb for news image and attachments. override otherwise
    maxFileSize: 3 * 1024 * 1024,
  };

  uploadFile = (req: Request, res: Response) => {
    const typeValidationMessage = 'Please choose a JPEG, GIF, PDF or DOC file.';

    const form = formidable(this.formidableOptions);

    form.onPart = (part: { filename: any; mime: any }) => {
      let isValid = true;
      if (part.filename || part.mime) {
        if (part.filename) {
          isValid =
            isValid && !AttachmentValidator.isInvalidFileName(part.filename);
        }

        if (part.mime) {
          isValid =
            isValid && !AttachmentValidator.isInvalidFileType(part.mime);
        }
        if (!isValid) {
          return res.status(400).json({ message: typeValidationMessage });
        }
      }
    };

    try {
      UploadService.upload(
        req,
        // onSuccess callback
        async (fileLocation: string, originalName: string) => {
          try {
            await C3DistributionService.sendAttachment(
              fileLocation,
              originalName,
            );
          } catch (error) {
            this.logger.error(error);
            return res.status(500).json({ message: error.message });
          } finally {
            // try catch swallow in case only the delete tmp file (unlinkSync) fails
            try {
              fs.unlinkSync(fileLocation);
            } catch (error) {
              this.logger.error(error);
            }
          }
          return res.status(201).send();
        },
        // onFail callback
        () => {
          return res.status(500).json({
            message: 'unexpected error from upload service callback run',
          });
        },
      );
    } catch (error) {
      this.logger.error(error);
      return res.status(500).json({ message: error.message });
    }
  };
}

SERVICE/formidable parse wrapper:

const formidableOptions = {
  encoding: 'utf-8',
  uploadDir: UPLOAD_DIR,
  keepExtensions: true,
  // 3 mb for news image and attachments. override otherwise
  maxFileSize: 3 * 1024 * 1024,
};

const UploadService = {
  upload: (req: Request, onSuccess?: Function, onFail?: Function): void => {
    ensureTmpFilePath();

    const form = formidable(formidableOptions);

    form.parse(req, (err: any, fields: any, files: { files: File }) => {
      if (err) {
        logger.error('formidable err: %j', err);
        if (onFail) {
          onFail();
        }
      } else if (onSuccess) {
        onSuccess(files.files.path, files.files.name);
      }
    });
  },
};

Originally posted by @droddy in #387 (comment)
EDIT: SYNTAX highlighting

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions