项目作者: ceejay-el

项目描述 :
NodeJS image upload to mongodb GridFS with multer
高级语言: JavaScript
项目地址: git://github.com/ceejay-el/image-repo.git
创建时间: 2020-09-19T11:21:55Z
项目社区:https://github.com/ceejay-el/image-repo

开源协议:

下载


image-repo

NodeJS image upload to Mongodb with multer.

Project Structure

Front-end

  • signup.html: contains html form for registering with any username and password.
  • login.html is the landing page. Gallery is private. User has to log in with their username and password
  • User uploads and views images from gallery.html

Server-side

  • app.js handles user authentication with md5 password encryption, as well as creating the storage engine and running the express app.

npm modules

  • express.js, a simple NodeJS framework with a robust set of features
  • mongoose a “MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.” Ok basically makes it easier to use the MongoDB in the express server, so that you don’t have to write all the MongoDB server code.
  • body-parser for parsing the html body data
  • multer for handling multipart/form-data from the html body.
  • multer-gridfs-storage which creates a mongodb connection automatically.
  • method-override to allow for the deleting function.
  • gridfs-stream to allow for easy streaming of files to and from mongodb GridFS
  • md5 for password encryption.
  • dotenv to keep our secret variables at, like the encryption key and the database uris, that, you know, have your database username and password!!

initialize engine for uploading and storing images

  • I created the engine in the engines.js. Also, saying “I created the engine” and “look it up in the engines file” are such cool things to say, so I’ll do it just because I can.
    ```
    // dependencies
    require(“dotenv”).config();
    const express = require(“express”);
    const multer = require(“multer”);
    const GridFsStorage = require(“multer-gridfs-storage”);
    const path = require(“path”);
    const util = require(“util”);

// create storage engine
const storage = new GridFsStorage({
url: process.env.GALLERYDBURI,
options: {useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true},
file: function(req, file){
const match = [“image/png”, “image/jpeg”];
if(match.indexOf(file.mimetype) === -1){
return {
filename: “file
“ + Date.now() + path.extname(file.originalname),
bucketname: “uploads”
};
}
}
});

// initialize GridFS stream and upload up to 5 images
const upload = multer({storage: storage}).array(“files”, 5);
const uploadFilesEngine = util.promisify(upload);

  1. - With the storage engine, you can now control the image uploads and export it to `app.js`. Remember to ask the user to upload at least one file. Or you write the function to accept only one file. In this case, the function accepts at least one file, and a maximum of 5 files. The `array()` functions sets the maximum number of images that can be uploaded. The first parameter is the name of the file `input` tag, in this case, `files`. The second parameter is the maximum number of images. If there's too many files, the `catch()` statement checks for that and alerts the user when they try to upload more than 5 images.

// handle image uploads
async function uploadImages(request, respond){
try {
await uploadFilesEngine(request, respond);

  1. console.log(request.files);
  2. if(request.files.length <= 0)
  3. return respond.send("Ay, select a file! At least ONE file!");
  4. else
  5. respond.send("Good work, now go grab yourself a biscuit or something");
  6. } catch (err) {
  7. console.log(err);
  8. if (err.code === "LIMIT_UNEXPECTED_FILE")
  9. return respond.send("Woah, calm down! How many fingers you got?");
  10. else
  11. return respond.send("Might I interest you in upload error? No? Ok.");
  12. }

}
module.exports = {
uploadFiles: uploadImages
};

  1. - Create the express app server: Require the necessary dependencies; initialize middleware; add the landing, signup and uploads `get` and `post` methods. To use the uploading function from `engines.js`, start by importing it:
  2. > `const engines = require("./engines");`
  3. - This would allow you to call the methods from `engines.js`. The post route, for example, uses the uploading function from engines. So:
  4. > `app.post("/upload", engines.uploadFiles);`
  5. - If you did everything right, you could load the html document from your browser. Side note, the best part about this is that I just found a new way to initialize the connect to the MongoDb server _and_ solved that incessant 'Deprecation warning: blah blah add {newUnifiedTopology: true}' bug!
  6. #### start user database server
  7. - First initialize user database and configure the User Database model.

async function connectUserdb(){
try {
await mongoose.connect(userdbURI, {useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true});
console.log(“connected to userdb!”);
} catch (err) {
console.log(err);
throw(err);
}
}

// configure user model
const userSchema = mongoose.Schema({
username: String,
password: String
});
const User = new mongoose.model(“User”, userSchema);

// initialize mongo userdb server
connectUserdb();

  1. - In `app.js` encrypt the password from the html document with md5 in the signup `post` route's callback function.

app.post(“/signup”, function(request, respond){
const newUser = new User({
username: request.body.username,
password: md5(request.body.password)
});
newUser.save(function(err){
if (err)
console.log(err)
else
respond.sendFile(__dirname + “/public/gallery.html”);
});
});

  1. - After you register with just your username and password (anything can do, it's not that serious. I just wanted to make a private-access project), you can log in and view the gallery. Of course, there's nothing to see there since you didn't add anything ><. But below are the pages that you should see.
  2. - PS. I hope the image markdown works.
  3. > ![Signup page](/screenshots/Picture1.png)
  4. > ![Login page](/screenshots/Picture2.png)
  5. * well would you look at that! It works!!
  6. #### login
  7. - `login.html` is the landing page. If you have your toy name and password in the database, you should be able to access `gallery.html`. The callback checks for the correct username and password in the database.
  8. - Remember, when you run the `md5` hashing function on the same string, the hash that is created will always be the same. This is what we look for in the callback. The user input from the html body is hashed and compared to the hash in the database. If they're the same, we have a successful login. If they're not, well, then _something mighty spooky going on._

app.post(“/“, function(request, respond){
const username = request.body.username;
const password = md5(request.body.password);

  1. User.findOne({username: username}, function(error, foundUser){
  2. if (error)
  3. console.log(error);
  4. else {
  5. if (foundUser){
  6. if (foundUser.password === password)
  7. respond.sendFile(__dirname + "/public/gallery.html");
  8. else
  9. respond.send("I feel a great disturbance in the force");
  10. }
  11. }
  12. });

});
```

Future of this project

  • The project could do with a little bit more work. Here’s what I have in mind
  1. Try to notify the user that the image has actually uploaded. At present, all that happens is show successful connection to database at the terminal and show data metrics in Atlas!! What’s up with that??!
  2. View engines. I think I need a view engine. And no, I won’t use ejs because it makes code look hideous.
  3. Yeah, I think that’s about it. I mean I have to move on to something else, right?
  • Ok bye, thank you for attending my TED talk, have a great day. Peace. Chuck out.