From f2ba4018fc1605f3089c0df1e3e5b95a172a557f Mon Sep 17 00:00:00 2001 From: Edin Skeja Date: Wed, 8 Dec 2021 10:04:47 +0100 Subject: [PATCH] medusa-file-minio (#883) * A first commit for medusa-file-minio * Cleanup and remove unnecessary env vars * Update packages * Small fix big letter --- .eslintignore | 1 + .../how-to/uploading-images-to-minio.md | 53 +++++++++++++ packages/medusa-file-minio/.babelrc | 13 ++++ packages/medusa-file-minio/.gitignore | 16 ++++ packages/medusa-file-minio/.npmignore | 9 +++ packages/medusa-file-minio/README.md | 14 ++++ packages/medusa-file-minio/index.js | 1 + packages/medusa-file-minio/package.json | 46 +++++++++++ .../medusa-file-minio/src/services/minio.js | 76 +++++++++++++++++++ 9 files changed, 229 insertions(+) create mode 100644 docs/content/how-to/uploading-images-to-minio.md create mode 100644 packages/medusa-file-minio/.babelrc create mode 100644 packages/medusa-file-minio/.gitignore create mode 100644 packages/medusa-file-minio/.npmignore create mode 100644 packages/medusa-file-minio/README.md create mode 100644 packages/medusa-file-minio/index.js create mode 100644 packages/medusa-file-minio/package.json create mode 100644 packages/medusa-file-minio/src/services/minio.js diff --git a/.eslintignore b/.eslintignore index 123b29bdf4..48204cf49f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -58,6 +58,7 @@ /packages/medusa-cli /packages/medusa-core-utils /packages/medusa-dev-cli +/packages/medusa-file-minio /packages/medusa-file-s3 /packages/medusa-file-spaces /packages/medusa-fulfillment-manual diff --git a/docs/content/how-to/uploading-images-to-minio.md b/docs/content/how-to/uploading-images-to-minio.md new file mode 100644 index 0000000000..269bdb23dc --- /dev/null +++ b/docs/content/how-to/uploading-images-to-minio.md @@ -0,0 +1,53 @@ +# Uploading images to MinIO + +In order to work with images in Medusa, you need a file service plugin responsible for hosting. Following this guide will allow you to upload images to MinIO bucket. + +### Before you start + +At this point, you should have an instance of our store engine running. If not, we have a [full guide](https://docs.medusa-commerce.com/tutorial/set-up-your-development-environment) for setting up your local environment. + +### Set up up AWS + +#### Create an MinIO bucket + +In the MinIO console create a new bucket, then click into that bucket and change the `Access Policy` to `public`. + +Be aware, that this will allow for anyone to acces your bucket. Avoid storing sensitive data. + +#### Generate access keys + +Navigate to users and perform the following steps: + +- Enter new `Access Key` and `Secret Key` +- Select readwrite policy +- Submit the details + +### Installation + +First, install the plugin using your preferred package manager: + +``` +yarn add medusa-file-minio +``` + +Then configure your `medusa-config.js` to include the plugin alongside the required options: + +```=javascript +{ + resolve: `medusa-file-minio`, + options: { + endpoint: "minio.server.com", + bucket: "test", + access_key_id: "YOUR-ACCESS-KEY", + secret_access_key: "YOUR-SECRET-KEY", + }, +}, +``` + +The two access keys in the options are the ones created in the previous section. + +> Make sure to use an environment variable for the secret key in a live environment. + +### Try it out + +Finally, run your Medusa server alongside our admin system to try out your new file service. Upon editing or creating products, you can now upload thumbnails and images, that are stored in an MiniO server. diff --git a/packages/medusa-file-minio/.babelrc b/packages/medusa-file-minio/.babelrc new file mode 100644 index 0000000000..4d2dfe8f09 --- /dev/null +++ b/packages/medusa-file-minio/.babelrc @@ -0,0 +1,13 @@ +{ + "plugins": [ + "@babel/plugin-proposal-class-properties", + "@babel/plugin-transform-instanceof", + "@babel/plugin-transform-classes" + ], + "presets": ["@babel/preset-env"], + "env": { + "test": { + "plugins": ["@babel/plugin-transform-runtime"] + } + } +} diff --git a/packages/medusa-file-minio/.gitignore b/packages/medusa-file-minio/.gitignore new file mode 100644 index 0000000000..2ca7f03256 --- /dev/null +++ b/packages/medusa-file-minio/.gitignore @@ -0,0 +1,16 @@ +/lib +node_modules +.DS_store +.env* +/*.js +!index.js +yarn.lock + +/dist + +/api +/services +/models +/subscribers +/__mocks__ + diff --git a/packages/medusa-file-minio/.npmignore b/packages/medusa-file-minio/.npmignore new file mode 100644 index 0000000000..486581be18 --- /dev/null +++ b/packages/medusa-file-minio/.npmignore @@ -0,0 +1,9 @@ +/lib +node_modules +.DS_store +.env* +/*.js +!index.js +yarn.lock + + diff --git a/packages/medusa-file-minio/README.md b/packages/medusa-file-minio/README.md new file mode 100644 index 0000000000..3ce9cae6c0 --- /dev/null +++ b/packages/medusa-file-minio/README.md @@ -0,0 +1,14 @@ +# medusa-file-minio + +Upload files to a MinIO server. + +## Options + +``` + endpoint: [endpoint of your MinIO server], + bucket: [name of your bucket], + access_key_id: [access-key], + secret_access_key: [secret-access-key], +``` + +Follow [this guide](https://docs.medusa-commerce.com/how-to/uploading-images-to-minio) to configure the plugin. diff --git a/packages/medusa-file-minio/index.js b/packages/medusa-file-minio/index.js new file mode 100644 index 0000000000..172f1ae6a4 --- /dev/null +++ b/packages/medusa-file-minio/index.js @@ -0,0 +1 @@ +// noop diff --git a/packages/medusa-file-minio/package.json b/packages/medusa-file-minio/package.json new file mode 100644 index 0000000000..60fbe6edb2 --- /dev/null +++ b/packages/medusa-file-minio/package.json @@ -0,0 +1,46 @@ +{ + "name": "medusa-file-minio", + "version": "1.0.0", + "description": "MinIO server file connector for Medusa", + "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/medusa-file-minio" + }, + "author": "Edin Skeja", + "license": "MIT", + "devDependencies": { + "@babel/cli": "^7.16.0", + "@babel/core": "^7.16.0", + "@babel/node": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-transform-instanceof": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/register": "^7.16.0", + "@babel/runtime": "^7.16.3", + "client-sessions": "^0.8.0", + "cross-env": "^5.2.1", + "eslint": "^6.8.0", + "jest": "^25.5.2" + }, + "scripts": { + "build": "babel src -d .", + "prepare": "cross-env NODE_ENV=production npm run build", + "watch": "babel -w src --out-dir . --ignore **/__tests__", + "test": "jest" + }, + "peerDependencies": { + "medusa-interfaces": "1.x" + }, + "dependencies": { + "@babel/plugin-transform-classes": "^7.16.0", + "aws-sdk": "^2.1043.0", + "body-parser": "^1.19.0", + "express": "^4.17.1", + "medusa-core-utils": "^1.1.30", + "medusa-test-utils": "^1.1.33" + }, + "gitHead": "7770046479c361f375842a8605b15e5d7bc24624" +} diff --git a/packages/medusa-file-minio/src/services/minio.js b/packages/medusa-file-minio/src/services/minio.js new file mode 100644 index 0000000000..1f06a4b237 --- /dev/null +++ b/packages/medusa-file-minio/src/services/minio.js @@ -0,0 +1,76 @@ +import fs from "fs" +import aws from "aws-sdk" +import { FileService } from "medusa-interfaces" + +class MinioService extends FileService { + constructor({}, options) { + super() + + this.bucket_ = options.bucket + this.accessKeyId_ = options.access_key_id + this.secretAccessKey_ = options.secret_access_key + this.endpoint_ = options.endpoint + this.s3ForcePathStyle_ = true + this.signatureVersion_ = "v4" + } + + upload(file) { + aws.config.setPromisesDependency() + aws.config.update({ + accessKeyId: this.accessKeyId_, + secretAccessKey: this.secretAccessKey_, + endpoint: this.endpoint_, + s3ForcePathStyle: this.s3ForcePathStyle_, + signatureVersion: this.signatureVersion_, + }) + + const s3 = new aws.S3() + const params = { + ACL: "public-read", + Bucket: this.bucket_, + Body: fs.createReadStream(file.path), + Key: `${file.originalname}`, + } + + return new Promise((resolve, reject) => { + s3.upload(params, (err, data) => { + console.log(data, err) + if (err) { + reject(err) + return + } + + resolve({ url: data.Location }) + }) + }) + } + + delete(file) { + aws.config.setPromisesDependency() + aws.config.update({ + accessKeyId: this.accessKeyId_, + secretAccessKey: this.secretAccessKey_, + endpoint: this.endpoint_, + s3ForcePathStyle: this.s3ForcePathStyle_, + signatureVersion: this.signatureVersion_, + }) + + const s3 = new aws.S3() + const params = { + Bucket: this.bucket_, + Key: `${file}`, + } + + return new Promise((resolve, reject) => { + s3.deleteObject(params, (err, data) => { + if (err) { + reject(err) + return + } + resolve(data) + }) + }) + } +} + +export default MinioService