We are going to create a photo sharing service where the user is able to upload pictures and like them.
We will be using a simple MVC, so our file structure will be:
/controllers
/users.js
/photos.js
/likes.js
/models
/users.js # this will be half-mocked up since there's no time
# or we'll use auth0 if possible
/views
/index.pug
/layout.pug
/login.pug
/photo.pug
/public
/images
/1.jpg
/2.jpg
...
/style.css
/.env
/.gitignore
/app.js
/package.json
/routes.js
The user will be able to login (actually no, we will fake this)
For this, first we set up our app.js:
require('dotenv').config();
var express = require('express');
var bodyparser = require('body-parser');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.once('open', function(){
var app = express();
app.set('view engine', 'pug');
app.use(express.static('public'));
app.use(bodyparser.urlencoded({ extended: false }));
app.use(require('./routes'));
app.listen(process.env.PORT || 3000);
});
In routes.js:
var express = require('express');
var router = express.Router();
var controllers = require('auto-load')('controllers');
router.get('/', controllers.photos.index);
module.exports = router;
Let's mock the data:
module.exports.index = function(req, res){
res.render('index', {
photos: [
'/images/1.jpg',
'/images/2.jpg',
'/images/3.jpg',
'/images/4.jpg',
'/images/5.jpg'
]
});
}
Install the dependencies
npm install formidable cloudinary --save
Then in our controllers/photos.js:
var formidable = require('formidable');
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: process.env.cloud,
api_key: process.env.key,
api_secret: process.env.secret
});
exports.upload = function(req, res, next){
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
if (err) next(err);
cloudinary.uploader.upload(files.image.path, function(result) {
// Let's force https in the image:
var image = result.url.replace('http://', 'https://');
res.redirect('/');
});
});
});
Our layout.pug:
doctype html
html
head
title= title
link(rel="stylesheet" href="https://cdn.jsdelivr.net/picnicss/6.0.0/plugins.min.css")
link(rel='stylesheet', href='style.css')
block head
body
block content
script.
document.addEventListener("DOMContentLoaded", function() {
[].forEach.call(document.querySelectorAll('.dropimage'), function(img){
img.onchange = function(e){
var inputfile = this, reader = new FileReader();
reader.onloadend = function(){
inputfile.style['background-image'] = 'url('+reader.result+')';
}
reader.readAsDataURL(e.target.files[0]);
}
});
});
In index.pug:
extends layout
block content
h1= name
div.flex.one.two-500.five-900
each photo in photos
div.photo
img(src=photo)
button.like Like
form(action="/photos" method="POST" enctype="multipart/form-data")
div.flex.two
div
label.dropimage
input(type="file" name="image" title="Drop image or click me")
div
label Title:
input(name="title" placeholder="Title")
label Nickname:
input(name="nick" placeholder="Nickname")
input(type="submit" value="Upload")
In our style.css:
body {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
img {
width: 100%;
}
New photos.js:
var models = require('auto-load')('models');
var formidable = require('formidable');
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: process.env.cloud,
api_key: process.env.key,
api_secret: process.env.secret
});
module.exports.index = function(req, res){
models.photos.find({}, function(err, images){
res.render('index', { photos: images });
});
}
module.exports.upload = function(req, res, next){
var form = new formidable.IncomingForm();
function redirect(err){
if (err) next(err);
res.redirect('/');
}
function parseForm(err, fields, files) {
if (err) next(err);
cloudinary.uploader.upload(files.image.path, function (result) {
// Let's force https in the image:
var url = result.url.replace('http://', 'https://');
var Photo = new models.photos({
url: url,
title: fields.title,
nickname: fields.nick,
});
Photo.save(redirect);
});
}
form.parse(req, parseForm);
}
The model.js:
var mongoose = require('mongoose');
var photosSchema = mongoose.Schema({
title: { type: String, required: true },
nickname: { type: String, unique: true, required: true },
url: { type: String, required: true },
likes: [{ type: String }]
});
module.exports = mongoose.model('Photos', photosSchema);
Auth
We will follow Auth0 tutorial.