Skip to content

Commit

Permalink
✨ feat(uploads): install formidable
Browse files Browse the repository at this point in the history
  • Loading branch information
thrownullexception committed Nov 20, 2023
1 parent 3e1ee08 commit 187da28
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 61 deletions.
78 changes: 74 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
"@dashpress/bacteria": "^0.0.9",
"@tanstack/react-table": "^8.7.9",
"@types/cryptr": "^4.0.1",
"@types/formidable": "^3.4.5",
"@types/jsonwebtoken": "^8.5.8",
"@types/lodash": "^4.14.182",
"@types/microseconds": "^0.2.0",
"@types/multer": "^1.4.7",
"@types/nodemailer": "^6.4.6",
"@types/prismjs": "^1.26.0",
"@types/qs": "^6.9.7",
Expand All @@ -55,18 +55,17 @@
"execa": "^6.1.0",
"final-form": "^4.20.7",
"final-form-arrays": "^3.0.2",
"formidable": "^3.5.1",
"fs-extra": "^10.1.0",
"immer": "9.0.3",
"jsonwebtoken": "^8.5.1",
"knex": "^2.3.0",
"latest-version": "^7.0.0",
"lodash": "^4.17.21",
"microseconds": "^0.2.0",
"multer": "^1.4.5-lts.1",
"mustache": "^4.2.0",
"nanoid": "^4.0.0",
"next": "12.3.1",
"next-connect": "^0.13.0",
"nodemailer": "^6.8.0",
"path": "^0.12.7",
"polished": "^4.2.2",
Expand Down
2 changes: 1 addition & 1 deletion src/backend/actions/actions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class ActionsApiService implements IApplicationService {
await this._actionInstancesPersistenceService.setup();
}

// TODO: job queue
// TODO: job queue https://github.com/bee-queue/bee-queue
async runAction(
entity: string,
formAction: string,
Expand Down
2 changes: 2 additions & 0 deletions src/backend/lib/request/validations/implementations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { canUserValidationImpl as canUser } from "./can-user";
import { withPasswordValidationImpl as withPassword } from "./with-password";
import { authenticatedUserValidationImpl as authenticatedUser } from "./authenticated-user";
import { requestQueriesValidationImpl as requestQueries } from "./request-queries";
import { rawRequestValidationImpl as rawRequest } from "./raw-request";

import { ValidationImplType } from "./types";
import { PortalValidationImpl } from "./portal";
Expand All @@ -32,6 +33,7 @@ export const ValidationImpl: Record<
anyBody,
requestQuery,
canUser,
rawRequest,
requestQueries,
authenticatedUser,
configBody,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ValidationImplType } from "./types";

export const rawRequestValidationImpl: ValidationImplType<
Record<string, unknown>
> = async (req) => {
return req as unknown as Record<string, unknown>;
};
1 change: 1 addition & 0 deletions src/backend/lib/request/validations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type ValidationKeys = {
| "entity"
| "authenticatedUser"
| "configKey"
| "rawRequest"
| "paginationFilter"
| "canUser"
| "crudEnabled"
Expand Down
21 changes: 21 additions & 0 deletions src/backend/uploads/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const FORMIDABLE_ERRORS = {
aborted: 1002,
biggerThanMaxFileSize: 1016,
biggerThanTotalMaxFileSize: 1009,
cannotCreateDir: 1018,
filenameNotString: 1005,
malformedMultipart: 1012,
maxFieldsExceeded: 1007,
maxFieldsSizeExceeded: 1006,
maxFilesExceeded: 1015,
missingContentType: 1011,
missingMultipartBoundary: 1013,
missingPlugin: 1000,
noEmptyFiles: 1010,
noParser: 1003,
pluginFailed: 1017,
pluginFunction: 1001,
smallerThanMinFileSize: 1008,
uninitializedParser: 1004,
unknownTransferEncoding: 1014,
};
52 changes: 52 additions & 0 deletions src/backend/uploads/parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import formidable from "formidable";
import { mkdir, stat } from "fs/promises";
import { join } from "path";
import { sluggify } from "shared/lib/strings";
import { format } from "date-fns";
import { NextApiRequest } from "next";
import { nanoid } from "nanoid";

export async function parseForm(
req: NextApiRequest
): Promise<{ fields: formidable.Fields; files: formidable.Files }> {
const UPLOAD_CONFIG = {
entity: sluggify("posts"),
maxFileSize: 1024 * 1024 * 5,
fileType: "image",
rootDir: process.cwd(),
};

const uploadDir = join(
UPLOAD_CONFIG.rootDir || process.cwd(),
`/uploads/${UPLOAD_CONFIG.entity}/${format(Date.now(), "dd-MM-Y")}`
);

try {
await stat(uploadDir);
} catch (e: any) {
if (e.code === "ENOENT") {
await mkdir(uploadDir, { recursive: true });
} else {
throw e;
}
}

const form = formidable({
maxFiles: 1,
maxFileSize: UPLOAD_CONFIG.maxFileSize,
uploadDir,
filename: (_name, _ext, part) => {
return `${nanoid()}.${part.originalFilename.split(".").pop()}`;
},
filter: (part) => {
return (
part.name === "file" &&
(part.mimetype?.includes(UPLOAD_CONFIG.fileType) || false)
);
},
});

const [fields, files] = await form.parse(req);

return { fields, files };
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useState } from "react";
import { useDropzone } from "react-dropzone";
import axios, { AxiosProgressEvent } from "axios";
import { getRequestHeaders } from "frontend/lib/data/makeRequest";
import { ISharedFormInput } from "../_types";
import { generateClassNames, wrapLabelAndError } from "../_wrapForm";
import { Presentation } from "./Presentation";
Expand All @@ -9,7 +10,6 @@ interface IFormFileInput extends ISharedFormInput {
uploadUrl: string;
metadata?: Record<string, unknown>;
maxSize?: number;
requestHeaders?: Record<string, unknown>;
}

function FileInput({
Expand All @@ -19,7 +19,6 @@ function FileInput({
uploadUrl,
metadata,
maxSize,
requestHeaders,
}: IFormFileInput) {
const [progress, setProgress] = useState<number>(0);
const [error, setError] = useState<string>("");
Expand All @@ -43,7 +42,7 @@ function FileInput({
const { fileUrl } = (
await axios.post(uploadUrl, formData, {
headers: {
...requestHeaders,
...getRequestHeaders(),
"Content-Type": "multipart/form-data",
},
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
Expand All @@ -55,8 +54,11 @@ function FileInput({
})
).data;
input.onChange(fileUrl);
setError(null);
} catch (e) {
setError("Ooops, something wrong happened.");
setError(
e.response.data.message || "Ooops, something wrong happened."
);
}
setProgress(0);
});
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/lib/data/makeRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const pathWithBaseUrl = (path: string) => {
return (process.env.NEXT_PUBLIC_BASE_URL || "") + path;
};

const getRequestHeaders = () => {
export const getRequestHeaders = () => {
const authToken = getAuthToken();
const headers: Record<string, string> = {
"Content-Type": "application/json",
Expand Down
Loading

0 comments on commit 187da28

Please sign in to comment.