Skip to content

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

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions