diff --git a/packages/medusa-js/package.json b/packages/medusa-js/package.json index 48fbaa13e6..8d3cf5c5cb 100644 --- a/packages/medusa-js/package.json +++ b/packages/medusa-js/package.json @@ -17,6 +17,7 @@ "dependencies": { "@medusajs/medusa": "^1.1.60", "axios": "^0.24.0", + "form-data": "^4.0.0", "retry-axios": "^2.6.0" }, "repository": { diff --git a/packages/medusa-js/src/request.ts b/packages/medusa-js/src/request.ts index 6aa92f3e88..a7a5502e35 100644 --- a/packages/medusa-js/src/request.ts +++ b/packages/medusa-js/src/request.ts @@ -102,12 +102,14 @@ class Client { * @param {object} userHeaders user supplied headers * @param {Types.RequestMethod} method request method * @param {string} path request path + * @param {object} customHeaders user supplied headers * @return {object} */ setHeaders( userHeaders: RequestOptions, method: RequestMethod, - path: string + path: string, + customHeaders: object = {} ): AxiosRequestHeaders { let defaultHeaders: object = { Accept: "application/json", @@ -126,7 +128,12 @@ class Client { defaultHeaders["Idempotency-Key"] = uuidv4() } - return Object.assign({}, defaultHeaders, this.normalizeHeaders(userHeaders)) + return Object.assign( + {}, + defaultHeaders, + this.normalizeHeaders(userHeaders), + customHeaders + ) } /** @@ -170,13 +177,15 @@ class Client { * @param {string} path request path * @param {object} payload request payload * @param {RequestOptions} options axios configuration + * @param {object} customHeaders custom request headers * @return {object} */ async request( method: RequestMethod, path: string, payload: object = {}, - options: RequestOptions = {} + options: RequestOptions = {}, + customHeaders: object = {} ): Promise { const reqOpts = { method, @@ -184,7 +193,7 @@ class Client { url: path, data: payload, json: true, - headers: this.setHeaders(options, method, path), + headers: this.setHeaders(options, method, path, customHeaders), } // e.g. data = { cart: { ... } }, response = { status, headers, ... } diff --git a/packages/medusa-js/src/resources/admin/index.ts b/packages/medusa-js/src/resources/admin/index.ts index b3f794d1e6..d2939b4033 100644 --- a/packages/medusa-js/src/resources/admin/index.ts +++ b/packages/medusa-js/src/resources/admin/index.ts @@ -19,6 +19,7 @@ import AdminStoresResource from "./store" import AdminShippingOptionsResource from "./shipping-options" import AdminRegionsResource from "./regions" import AdminNotificationsResource from "./notifications" +import AdminUploadsResource from "./uploads" class Admin extends BaseResource { public auth = new AdminAuthResource(this.client) @@ -41,6 +42,7 @@ class Admin extends BaseResource { public shippingOptions = new AdminShippingOptionsResource(this.client) public regions = new AdminRegionsResource(this.client) public notifications = new AdminNotificationsResource(this.client) + public uploads = new AdminUploadsResource(this.client) } export default Admin diff --git a/packages/medusa-js/src/resources/admin/uploads.ts b/packages/medusa-js/src/resources/admin/uploads.ts new file mode 100644 index 0000000000..2b24373259 --- /dev/null +++ b/packages/medusa-js/src/resources/admin/uploads.ts @@ -0,0 +1,21 @@ +import { AdminUploadRes, IAdminPostUploadsFile } from "@medusajs/medusa" +import { ResponsePromise } from "../../typings" +import BaseResource from "../base" +import FormData from "form-data" + +class AdminUploadsResource extends BaseResource { + private headers = { + "Content-Type": "multipart/form-data", + } + + create(file: IAdminPostUploadsFile): ResponsePromise { + const path = `/admin/uploads` + + const payload = new FormData() + payload.append("files", file) + + return this.client.request("POST", path, payload, {}, this.headers) + } +} + +export default AdminUploadsResource diff --git a/packages/medusa/src/api/index.js b/packages/medusa/src/api/index.js index 6fb37c139c..dcf2858dd8 100644 --- a/packages/medusa/src/api/index.js +++ b/packages/medusa/src/api/index.js @@ -33,7 +33,7 @@ export * from "./routes/admin/orders" export * from "./routes/admin/variants" export * from "./routes/admin/return-reasons" export * from "./routes/admin/swaps" -export * from "./routes/admin/store" +export * from "./routes/admin/uploads" export * from "./routes/admin/returns" export * from "./routes/admin/shipping-options" export * from "./routes/admin/regions" diff --git a/packages/medusa/src/api/routes/admin/uploads/create-upload.js b/packages/medusa/src/api/routes/admin/uploads/create-upload.js deleted file mode 100644 index f5f2340d13..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/create-upload.js +++ /dev/null @@ -1,21 +0,0 @@ -import fs from "fs" - -export default async (req, res) => { - try { - const fileService = req.scope.resolve("fileService") - - const result = await Promise.all( - req.files.map(async (f) => { - return fileService.upload(f).then((result) => { - fs.unlinkSync(f.path) - return result - }) - }) - ) - - res.status(200).json({ uploads: result }) - } catch (err) { - console.log(err) - throw err - } -} diff --git a/packages/medusa/src/api/routes/admin/uploads/create-upload.ts b/packages/medusa/src/api/routes/admin/uploads/create-upload.ts new file mode 100644 index 0000000000..86320c33db --- /dev/null +++ b/packages/medusa/src/api/routes/admin/uploads/create-upload.ts @@ -0,0 +1,43 @@ +import fs from "fs" + +/** + * @oas [post] / + * operationId: "PostUploads" + * summary: "Uploads an array of files" + * description: "Uploads an array of files to the specific fileservice that is installed in medusa." + * x-authenticated: true + * tags: + * - Uploads + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * uploads + */ +export default async (req, res) => { + try { + const fileService = req.scope.resolve("fileService") + + const result = await Promise.all( + req.files.map(async (f) => { + return fileService.upload(f).then((result) => { + fs.unlinkSync(f.path) + return result + }) + }) + ) + + res.status(200).json({ uploads: result }) + } catch (err) { + console.log(err) + throw err + } +} + +export class IAdminPostUploadsFile { + originalName: string + path: string +} diff --git a/packages/medusa/src/api/routes/admin/uploads/delete-upload.js b/packages/medusa/src/api/routes/admin/uploads/delete-upload.js deleted file mode 100644 index fcc07651a2..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/delete-upload.js +++ /dev/null @@ -1,12 +0,0 @@ -export default async (req, res) => { - try { - const fileService = req.scope.resolve("fileService") - - await fileService.delete(req.body.file) - - res.status(200).send("Deleted image") - } catch (err) { - console.log(err) - throw err - } -} diff --git a/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts b/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts new file mode 100644 index 0000000000..52e65c2ded --- /dev/null +++ b/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts @@ -0,0 +1,24 @@ +/** + * [delete] /uploads + * operationId: "AdminDeleteUpload" + * summary: "Removes an uploaded file" + * description: "Removes an uploaded file using the installed fileservice" + * x-authenticated: true + * tags: + * - Uploads + * responses: + * 200: + * description: OK + */ +export default async (req, res) => { + try { + const fileService = req.scope.resolve("fileService") + + await fileService.delete(req.body.file) + + res.status(200).send({ id: "", object: "file", deleted: true }) + } catch (err) { + console.log(err) + throw err + } +} diff --git a/packages/medusa/src/api/routes/admin/uploads/index.js b/packages/medusa/src/api/routes/admin/uploads/index.ts similarity index 52% rename from packages/medusa/src/api/routes/admin/uploads/index.js rename to packages/medusa/src/api/routes/admin/uploads/index.ts index 706818f65b..6dddd85ec1 100644 --- a/packages/medusa/src/api/routes/admin/uploads/index.js +++ b/packages/medusa/src/api/routes/admin/uploads/index.ts @@ -1,5 +1,6 @@ import { Router } from "express" import multer from "multer" +import { DeleteResponse } from "../../../../types/common" import middlewares from "../../../middlewares" @@ -15,7 +16,17 @@ export default (app) => { middlewares.wrap(require("./create-upload").default) ) - route.post("/delete", middlewares.wrap(require("./delete-upload").default)) + // removed on purpose + // route.post("/delete", middlewares.wrap(require("./delete-upload").default)) return app } + +export type AdminUploadRes = { + uploads: any[] +} + +export type AdminDeleteUploadRes = DeleteResponse + +export * from "./create-upload" +// export * from "./delete-upload"