diff --git a/server/.babelrc b/server/.babelrc new file mode 100644 index 0000000..5e7caa1 --- /dev/null +++ b/server/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["latest"] +} diff --git a/server/.eslintignore b/server/.eslintignore new file mode 100644 index 0000000..2174542 --- /dev/null +++ b/server/.eslintignore @@ -0,0 +1,3 @@ +dist +node_modules +import diff --git a/server/.eslintrc b/server/.eslintrc new file mode 100644 index 0000000..9518d59 --- /dev/null +++ b/server/.eslintrc @@ -0,0 +1,15 @@ +{ + "plugins": ["ava"], + "extends": ["airbnb-base", "plugin:ava/recommended"], + "parser": "babel-eslint", + "rules": { + "indent": ["error", 4], + "new-cap": "off", + "array-callback-return": "off", + "no-underscore-dangle": ["error", { "allow": ["_id"] }] + }, + "env": { + "node": true, + "es6": true + } +} diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..1521c8b --- /dev/null +++ b/server/.gitignore @@ -0,0 +1 @@ +dist diff --git a/server/controllers/auth.js b/server/controllers/auth.js deleted file mode 100644 index 1c354f6..0000000 --- a/server/controllers/auth.js +++ /dev/null @@ -1,31 +0,0 @@ -var passport = require('passport'); -var BasicStrategy = require('passport-http').BasicStrategy; -var User = require('../models/User'); - -passport.use(new BasicStrategy( - function(username, password, callback){ - User.findOne({ username: username }, function(err, user){ - if (err) { - return callback(err); - } - if (!user) { - return callback(null, false); - } - user.verifyPassword(password, function(err, isMatch){ - if (err) { - return callback(err); - } - if (!isMatch) { - return callback(null, false); - } - return callback(null, user); - }); - }); - } -)); - -exports.isAuthenticated = passport.authenticate('basic', {session: false}); - -exports.login = function(req, res) { - res.send(); -}; diff --git a/server/controllers/event.js b/server/controllers/event.js deleted file mode 100644 index 9437697..0000000 --- a/server/controllers/event.js +++ /dev/null @@ -1,109 +0,0 @@ -var Event = require('../models/Event'); -var _ = require('lodash'); -var moment = require('moment'); - -// POST /api/events -exports.postEvents = function(req, res){ - var evnt = new Event(req.body); - - evnt.save(function(err){ - if (err) - res.send(err); - - res.json({message: 'Event added.', data: evnt}); - }) -} - -// GET /api/events -exports.getEvents = function(req, res){ - var time = moment().subtract(6, 'hours').valueOf(); - var findEvents = Event.find().where('startAt').gt(time); - - if (req.query.published === 'all') { - findEvents - .exec(function(err, events) { - if(err) - res.send(err); - res.json(events); - }); - } - else { - findEvents - .where('isPublished').equals(true) - .exec(function(err, events) { - if(err) - res.send(err); - res.json(events); - }); - } - -}; - -// GET /api/events/:event_id -exports.getEvent = function(req, res){ - Event.findById(req.params.event_id, function(err, evnt){ - if(err) - res.send(err); - res.json(evnt); - }); -}; - -// PUT /api/events/:event_id -exports.putEvent = function(req, res){ - Event.update({_id:req.params.event_id}, - req.body, - function(err, raw){ - if (err) - res.send(err); - - res.json({message: 'Event updated.'}); - }); -}; - -// DELETE /api/events/:event_id -exports.deleteEvent = function(req, res){ - Event.remove({_id: req.params.event_id}, - function(err){ - if (err) - res.send(err); - res.json({message: 'Event removed.'}); - }); -}; - -// GET /api/v1/events -exports.oldEvents = function(req, res) { - var time = new Date().getTime(); - Event.find() - .where('startAt').gt(time) - .exec(function(err, events) { - if(err) - res.send(err); - var events_old = - _.map(events, function(evt) { - return { - "eventID": evt._id, - "title": evt.title, - "startAt": evt.startAt, - "placeName": evt.venue.name, - "address": evt.venue.address, - "latitude": evt.venue.latitude, - "longitude": evt.venue.longitude, - "ageLimit": evt.ageLimit, - "price": evt.price, - "categoryID": evt.category, - "descriptions": [{ - "language":"nb", - "text": Boolean(evt.description) ? evt.description.replace(/\s+/g, " ") - : "" - }], - "isRecommended": evt.isPromoted || false, - "imageURL": evt.imageUrl, - "eventURL": evt.eventUrl - }; - }); - res.json({ - "events": events_old - }); - }); - -} diff --git a/server/controllers/image.js b/server/controllers/image.js deleted file mode 100644 index 05c1361..0000000 --- a/server/controllers/image.js +++ /dev/null @@ -1,36 +0,0 @@ -var path = require('path'), - fs = require('fs'); - im = require('imagemagick-stream'); - -var FOLDERNAME = './uploads/' - -function genFilename() { - var n1 = Math.floor(Math.random() * 1e15); - var n2 = Math.floor(Math.random() * 1e15); - return n1.toString() + '_' + n2.toString(); -} - -exports.postImage = function(req, res){ - var fstream; - req.pipe(req.busboy); - req.busboy.on('file', function(fieldname, file, filename) { - var fname = genFilename() + path.extname(filename); - fstream = fs.createWriteStream(path.resolve(FOLDERNAME + - fname)); - var resize = im().resize('x350').quality('80'); - file.pipe(resize).pipe(fstream); - fstream.on('close', function() { - var port = req.app.settings.port || ''; - var url = path.join(req.get('host'), - req.originalUrl, fname); - url = req.protocol + '://' + url; - res.json({url: url}); - }); - }); -}; - -exports.getImage = function(req, res){ - var p = path.resolve(FOLDERNAME); - p += '/' + req.params['0']; - res.sendFile(p); -}; diff --git a/server/controllers/user.js b/server/controllers/user.js deleted file mode 100644 index 7395312..0000000 --- a/server/controllers/user.js +++ /dev/null @@ -1,54 +0,0 @@ -var User = require('../models/User'); - -// POST /api/users -exports.postUser = function(req, res){ - var user = new User({ - username: req.body.username, - password: req.body.password, - }); - user.save(function(err){ - if (err) - res.send(err); - - res.json({message: 'New user added.'}); - }); -}; - -// GET /api/users/ -exports.getUsers = function(req, res){ - User.find(function(err, users){ - if (err) - res.send(err); - - res.json(users); - }); -}; - -// GET /api/users/:user_id -exports.getUser = function(req, res){ - User.findById(req.params.user_id, function(err, users){ - if (err) - res.send(err); - res.json(users); - }); -}; - -// PUT /api/users/:user_id -exports.putUser = function(req, res){ - User.update({_id:req.params.user_id}, - function(err, raw){ - if (err) - res.send(err); - res.json({message: 'Event updated.'}); - }); -}; - -// DELETE /api/users/:user_id -exports.deleteUser = function(req, res){ - User.remove({_id: req.params.user_id}, - function(err){ - if (err) - res.send(err); - res.json({message: 'Event removed.'}); - }); -}; diff --git a/server/controllers/venue.js b/server/controllers/venue.js deleted file mode 100644 index b75795d..0000000 --- a/server/controllers/venue.js +++ /dev/null @@ -1,54 +0,0 @@ -var Venue = require('../models/Venue') - -// POST /api/venues -exports.postVenues = function(req, res){ - var venue = new Venue(req.body); - - venue.save(function(err){ - if (err) - res.send(err); - - res.json({message: 'Venue added.', data: venue}); - }) -} - -// GET /api/venues -exports.getVenues = function(req, res){ - Venue.find(function(err, venues){ - if (err) - res.send(err); - - res.json(venues); - }); -}; - -// GET /api/venues/:venue_id -exports.getVenue = function(req, res){ - Venue.findById(req.params.venue_id, function(err, venue){ - if(err) - res.send(err); - res.json(venue); - }); -}; - -// PUT /api/venues/:venue_id -exports.putVenue = function(req, res){ - Venue.update({_id:req.params.venue_id}, - req.body, - function(err, raw){ - if (err) - res.send(err); - - res.json({message: 'Venue updated.'}); - }); -}; - -// DELETE /api/venues/:venue_id -exports.deleteVenue = function(req, res){ - Venue.remove({_id: req.params.venue_id}, - function(err){ - if (err) - res.send(err); - res.json({message: 'Venue removed.'}); - }); -}; diff --git a/server/models/Event.js b/server/models/Event.js deleted file mode 100644 index 7dbabd0..0000000 --- a/server/models/Event.js +++ /dev/null @@ -1,26 +0,0 @@ -var mongoose = require('mongoose'); - - -var EventSchema = new mongoose.Schema({ - title: {type: String, trim: true}, - externalId: Number, - description: {type: String, trim: true}, - startAt: Date, - endAt: Date, - venue: { - name: {type: String, trim: true}, - address: {type: String, trim: true}, - longitude: Number, - latitude: Number - }, - ageLimit: Number, - price: Number, - category: {type: String, trim: true}, - tags: [String], - imageUrl: {type: String, trim: true}, - eventUrl: {type: String, trim: true}, - isPromoted: {type: Boolean, default: false}, - isPublished: {type: Boolean, default: false} -}, {timestamps: true}) - -module.exports = mongoose.model('Event', EventSchema); diff --git a/server/models/User.js b/server/models/User.js deleted file mode 100644 index 356f0af..0000000 --- a/server/models/User.js +++ /dev/null @@ -1,51 +0,0 @@ -var mongoose = require('mongoose'); -var bcrypt = require('bcrypt-nodejs'); - -var UserSchema = new mongoose.Schema({ - username: { - type: String, - unique: true, - required: true - }, - password: { - type: String, - required: true - }, - /*type: String*/ // What is this for? -}); - -/** - * Runs before a user is saved. This function - * takes care of hashing and salting the password. - */ -UserSchema.pre('save', function(callback){ - var user = this; - if (!user.isModified('password')) - return callback(); - - bcrypt.genSalt(5, function(err, salt) { - if (err) - return callback(err); - - bcrypt.hash(user.password, salt, null, function(err, hash){ - if (err) - return callback(err); - user.password = hash; - callback(); - }); - }); -}); - -/** - * Verifies the password (duh). - */ -UserSchema.methods.verifyPassword = function(password, callback){ - bcrypt.compare(password, this.password, function(err, isMatch){ - if (err) { - return callback(err); - } - callback(null, isMatch); - }, null) -}; - -module.exports = mongoose.model('User', UserSchema); diff --git a/server/models/Venue.js b/server/models/Venue.js deleted file mode 100644 index 222e7e2..0000000 --- a/server/models/Venue.js +++ /dev/null @@ -1,11 +0,0 @@ -var mongoose = require('mongoose'); - - -var VenueSchema = new mongoose.Schema({ - name: {type: String, trim: true}, - address: {type: String, trim: true}, - latitude: Number, - longitude: Number -}) - -module.exports = mongoose.model('Venue', VenueSchema); diff --git a/server/models/fixtures.js b/server/models/fixtures.js deleted file mode 100644 index 1eafe55..0000000 --- a/server/models/fixtures.js +++ /dev/null @@ -1,17 +0,0 @@ -var User = require('../models/User'); - -exports.addTestUsers = function() { - if(process.env.NODE_ENV === 'development') { - User.find(function(err, users) { - if(err || users.length === 0) { // add test user if users is empty - var user = new User({ - username: 'test', - password: 'test', - role: 'admin' - }); - user.save(); - console.log("Added test user!"); - } - }) - } -}; diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..3dc4dba --- /dev/null +++ b/server/package.json @@ -0,0 +1,75 @@ +{ + "name": "Barteguiden-Server", + "version": "0.0.5", + "description": "Barteguiden server", + "main": "src/server.js", + "dependencies": { + "body-parser": "~1.13.0", + "busboy": "~0.2.9", + "connect-busboy": "~0.0.2", + "cors": "~2.7.1", + "cron": "~1.0.9", + "csv": "~0.3.5", + "express": "~4.13.0", + "facebook-node-sdk": "0.2.0", + "imagemagick-stream": "~2.0.0", + "jsdom": "~7.0.0", + "lodash": "~3.10.1", + "moment": "~2.10.6", + "mongoose": "4.1.3", + "mongoose-bcrypt": "^1.4.2", + "object-mapper": "~2.1.0", + "passport": "~0.3.0", + "passport-http": "~0.3.0", + "q": "~1.4.1", + "request": "~2.61.0", + "xml2js": "~0.4.10", + "xtend": "~4.0.0" + }, + "devDependencies": { + "ava": "^0.16.0", + "babel-cli": "^6.14.0", + "babel-core": "^6.14.0", + "babel-eslint": "^6.1.2", + "babel-preset-latest": "^6.14.0", + "eslint": "^3.5.0", + "eslint-config-airbnb-base": "^7.1.0", + "eslint-plugin-ava": "^3.0.0", + "eslint-plugin-import": "^1.15.0", + "nodemon": "^1.10.2", + "supertest": "^2.0.0", + "supertest-as-promised": "^4.0.0" + }, + "engines": { + "node": ">=5.0.0" + }, + "scripts": { + "start": "nodemon src/server.js --exec babel-node", + "build": "rm -rf dist/ && babel . --out-dir dist", + "lint": "eslint .", + "test": "ava" + }, + "ava": { + "require": [ + "babel-register" + ], + "babel": "inherit" + }, + "private": true, + "author": "Studentmediene i Trondheim AS", + "contributors": [ + { + "name": "martinhath" + }, + { + "name": "andybb" + }, + { + "name": "EirikRogno" + }, + { + "name": "AnnaKastet" + } + ], + "license": "Apache-2.0" +} diff --git a/server/router.js b/server/router.js deleted file mode 100644 index bb3c649..0000000 --- a/server/router.js +++ /dev/null @@ -1,50 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var eventController = require('./controllers/event'); -var userController = require('./controllers/user'); -var authController = require('./controllers/auth'); -var imageController = require('./controllers/image'); -var venueController = require('./controllers/venue'); -var auth = authController.isAuthenticated; - -router.route('/events') - .post(auth, eventController.postEvents) - .get(eventController.getEvents); - -router.route('/events/:event_id') - .get(eventController.getEvent) - .put(auth, eventController.putEvent) - .delete(auth, eventController.deleteEvent); - -router.route('/v1/events') - .get(eventController.oldEvents); - -router.route('/users') - .post(auth, userController.postUser) - .get(auth, userController.getUsers); - -router.route('/users/:user_id') - .put(auth, userController.putUser) - .get(auth, userController.getUser) - .delete(auth, userController.deleteUser); - -router.route('/images') - .post(auth, imageController.postImage); - -router.route('/images/*') - .get(imageController.getImage); - -router.route('/venues') - .post(venueController.postVenues) - .get(venueController.getVenues); - -router.route('/venues/:venue_id') - .get(venueController.getVenue) - .put(venueController.putVenue) - .delete(venueController.deleteVenue); - -router.route('/login', userController.getUser) - .get(auth, authController.login); - -module.exports = router; - diff --git a/server/server.js b/server/server.js deleted file mode 100644 index 138f282..0000000 --- a/server/server.js +++ /dev/null @@ -1,31 +0,0 @@ -var mongoose = require('mongoose'); -var bodyParser = require('body-parser'); -var express = require('express'); -var app = express(); -var router = require('./router.js'); -var passport = require('passport'); -var cors = require('cors') -var busboy = require('connect-busboy'); -var jobs = require('./import/jobs'); -var fixtures = require('./models/fixtures.js'); - -var WHITELIST = [ - 'http://localhost:9000', - /\.barteguiden\.no$/ -]; - -app.use(bodyParser.json()); -app.use(busboy()); -app.use(passport.initialize()); -app.use(cors({origin: WHITELIST})); - -port = process.env.PORT || 4004; -mongoose.connect('mongodb://127.0.0.1:27018/eventdb'); - -app.use('/api', router); - -app.listen(port, function() { - console.log("Serving on port " + port); - jobs.start(); - fixtures.addTestUsers(); -}); diff --git a/server/src/controllers/auth.js b/server/src/controllers/auth.js new file mode 100644 index 0000000..85390ce --- /dev/null +++ b/server/src/controllers/auth.js @@ -0,0 +1,32 @@ +import passport from 'passport'; +import { BasicStrategy } from 'passport-http'; +import User from '../models/User'; + +passport.use(new BasicStrategy( + (username, password, callback) => { + User.findOne({ username }, (findErr, user) => { + if (findErr) { + return callback(findErr); + } + if (!user) { + return callback(null, false); + } + user.verifyPassword(password, (verErr, isMatch) => { + if (verErr) { + return callback(verErr); + } + if (!isMatch) { + return callback(null, false); + } + return callback(null, user); + }); + return callback('Something went wrong'); + }); + } +)); + +export const isAuthenticated = passport.authenticate('basic', { session: false }); + +export const login = (req, res) => { + res.send(); +}; diff --git a/server/src/controllers/event.js b/server/src/controllers/event.js new file mode 100644 index 0000000..0da7ef5 --- /dev/null +++ b/server/src/controllers/event.js @@ -0,0 +1,109 @@ +import _ from 'lodash'; +import moment from 'moment'; +import Event from '../models/Event'; + +// POST /api/events +export const postEvents = (req, res) => { + const evnt = new Event(req.body); + + evnt.save((err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Event added.', data: evnt }); + }); +}; + +// GET /api/events +export const getEvents = (req, res) => { + const time = moment().subtract(6, 'hours').valueOf(); + const findEvents = Event.find().where('startAt').gt(time); + + if (req.query.published === 'all') { + findEvents + .exec((err, events) => { + if (err) { + res.send(err); + } + res.json(events); + }); + } else { + findEvents + .where('isPublished').equals(true) + .exec((err, events) => { + if (err) { + res.send(err); + } + res.json(events); + }); + } +}; + +// GET /api/events/:event_id +export const getEvent = (req, res) => { + Event.findById(req.params.event_id, (err, evnt) => { + if (err) { + res.send(err); + } + res.json(evnt); + }); +}; + +// PUT /api/events/:event_id +export const putEvent = (req, res) => { + Event.update({ _id: req.params.event_id }, + req.body, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Event updated.' }); + }); +}; + +// DELETE /api/events/:event_id +export const deleteEvent = (req, res) => { + Event.remove({ _id: req.params.event_id }, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Event removed.' }); + }); +}; + +// GET /api/v1/events +export const oldEvents = (req, res) => { + const time = new Date().getTime(); + Event.find() + .where('startAt').gt(time) + .exec((err, events) => { + if (err) { + res.send(err); + } + const eventsOld = + _.map(events, evt => ({ + eventID: evt._id, + title: evt.title, + startAt: evt.startAt, + placeName: evt.venue.name, + address: evt.venue.address, + latitude: evt.venue.latitude, + longitude: evt.venue.longitude, + ageLimit: evt.ageLimit, + price: evt.price, + categoryID: evt.category, + descriptions: [{ + language: 'nb', + text: evt.description ? evt.description.replace(/\s+/g, ' ') + : '', + }], + isRecommended: evt.isPromoted || false, + imageURL: evt.imageUrl, + eventURL: evt.eventUrl, + })); + res.json({ + events: eventsOld, + }); + }); +}; diff --git a/server/src/controllers/image.js b/server/src/controllers/image.js new file mode 100644 index 0000000..3e02d4f --- /dev/null +++ b/server/src/controllers/image.js @@ -0,0 +1,35 @@ +import path from 'path'; +import fs from 'fs'; +import im from 'imagemagick-stream'; + +const FOLDERNAME = './uploads/'; + +const genFilename = () => { + const n1 = Math.floor(Math.random() * 1e15); + const n2 = Math.floor(Math.random() * 1e15); + return `${n1.toString()}_${n2.toString()}`; +}; + +export const postImage = (req, res) => { + let fstream; + req.pipe(req.busboy); + req.busboy.on('file', (fieldname, file, filename) => { + const fname = genFilename() + path.extname(filename); + fstream = fs.createWriteStream(path.resolve(FOLDERNAME + + fname)); + const resize = im().resize('x350').quality('80'); + file.pipe(resize).pipe(fstream); + fstream.on('close', () => { + let url = path.join(req.get('host'), + req.originalUrl, fname); + url = `${req.protocol}://${url}`; + res.json({ url }); + }); + }); +}; + +export const getImage = (req, res) => { + let p = path.resolve(FOLDERNAME); + p += `/${req.params['0']}`; + res.sendFile(p); +}; diff --git a/server/src/controllers/user.js b/server/src/controllers/user.js new file mode 100644 index 0000000..c817f21 --- /dev/null +++ b/server/src/controllers/user.js @@ -0,0 +1,57 @@ +import User from '../models/User'; + +// POST /api/users +export const postUser = (req, res) => { + const user = new User({ + username: req.body.username, + password: req.body.password, + }); + user.save((err) => { + if (err) { + res.send(err); + } + res.json({ message: 'New user added.' }); + }); +}; + +// GET /api/users/ +export const getUsers = (req, res) => { + User.find((err, users) => { + if (err) { + res.send(err); + } + res.json(users); + }); +}; + +// GET /api/users/:user_id +export const getUser = (req, res) => { + User.findById(req.params.user_id, (err, users) => { + if (err) { + res.send(err); + } + res.json(users); + }); +}; + +// PUT /api/users/:user_id +export const putUser = (req, res) => { + User.update({ _id: req.params.user_id }, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Event updated.' }); + }); +}; + +// DELETE /api/users/:user_id +export const deleteUser = (req, res) => { + User.remove({ _id: req.params.user_id }, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Event removed.' }); + }); +}; diff --git a/server/src/controllers/venue.js b/server/src/controllers/venue.js new file mode 100644 index 0000000..d456fb2 --- /dev/null +++ b/server/src/controllers/venue.js @@ -0,0 +1,56 @@ +import Venue from '../models/Venue'; + +// POST /api/venues +export const postVenues = (req, res) => { + const venue = new Venue(req.body); + + venue.save((err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Venue added.', data: venue }); + }); +}; + +// GET /api/venues +export const getVenues = (req, res) => { + Venue.find((err, venues) => { + if (err) { + res.send(err); + } + res.json(venues); + }); +}; + +// GET /api/venues/:venue_id +export const getVenue = (req, res) => { + Venue.findById(req.params.venue_id, (err, venue) => { + if (err) { + res.send(err); + } + res.json(venue); + }); +}; + +// PUT /api/venues/:venue_id +export const putVenue = (req, res) => { + Venue.update({ _id: req.params.venue_id }, + req.body, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Venue updated.' }); + }); +}; + +// DELETE /api/venues/:venue_id +export const deleteVenue = (req, res) => { + Venue.remove({ _id: req.params.venue_id }, + (err) => { + if (err) { + res.send(err); + } + res.json({ message: 'Venue removed.' }); + }); +}; diff --git a/server/import/import_scripts/category_mapping.js b/server/src/import/import_scripts/category_mapping.js similarity index 100% rename from server/import/import_scripts/category_mapping.js rename to server/src/import/import_scripts/category_mapping.js diff --git a/server/import/import_scripts/facebook.js b/server/src/import/import_scripts/facebook.js similarity index 100% rename from server/import/import_scripts/facebook.js rename to server/src/import/import_scripts/facebook.js diff --git a/server/import/import_scripts/google_drive.js b/server/src/import/import_scripts/google_drive.js similarity index 100% rename from server/import/import_scripts/google_drive.js rename to server/src/import/import_scripts/google_drive.js diff --git a/server/import/import_scripts/samfundet.js b/server/src/import/import_scripts/samfundet.js similarity index 100% rename from server/import/import_scripts/samfundet.js rename to server/src/import/import_scripts/samfundet.js diff --git a/server/import/import_scripts/trdevents.js b/server/src/import/import_scripts/trdevents.js similarity index 100% rename from server/import/import_scripts/trdevents.js rename to server/src/import/import_scripts/trdevents.js diff --git a/server/import/import_scripts/uka.js b/server/src/import/import_scripts/uka.js similarity index 100% rename from server/import/import_scripts/uka.js rename to server/src/import/import_scripts/uka.js diff --git a/server/import/jobs.js b/server/src/import/jobs.js similarity index 100% rename from server/import/jobs.js rename to server/src/import/jobs.js diff --git a/server/import/server_sync.js b/server/src/import/server_sync.js similarity index 100% rename from server/import/server_sync.js rename to server/src/import/server_sync.js diff --git a/server/src/models/Event.js b/server/src/models/Event.js new file mode 100644 index 0000000..f4007c8 --- /dev/null +++ b/server/src/models/Event.js @@ -0,0 +1,25 @@ +import mongoose from 'mongoose'; + +const EventSchema = new mongoose.Schema({ + title: { type: String, trim: true }, + externalId: Number, + description: { type: String, trim: true }, + startAt: Date, + endAt: Date, + venue: { + name: { type: String, trim: true }, + address: { type: String, trim: true }, + longitude: Number, + latitude: Number, + }, + ageLimit: Number, + price: Number, + category: { type: String, trim: true }, + tags: [String], + imageUrl: { type: String, trim: true }, + eventUrl: { type: String, trim: true }, + isPromoted: { type: Boolean, default: false }, + isPublished: { type: Boolean, default: false }, +}, { timestamps: true }); + +export default mongoose.model('Event', EventSchema); diff --git a/server/src/models/User.js b/server/src/models/User.js new file mode 100644 index 0000000..7fbcd14 --- /dev/null +++ b/server/src/models/User.js @@ -0,0 +1,19 @@ +import mongoose from 'mongoose'; +import mongooseBcrypt from 'mongoose-bcrypt'; + +const UserSchema = new mongoose.Schema({ + username: { + type: String, + unique: true, + required: true, + }, + password: { + type: String, + required: true, + bcrypt: true, + }, +}); + +UserSchema.plugin(mongooseBcrypt); + +export default mongoose.model('User', UserSchema); diff --git a/server/src/models/Venue.js b/server/src/models/Venue.js new file mode 100644 index 0000000..77a0cb5 --- /dev/null +++ b/server/src/models/Venue.js @@ -0,0 +1,10 @@ +import mongoose from 'mongoose'; + +const VenueSchema = new mongoose.Schema({ + name: { type: String, trim: true }, + address: { type: String, trim: true }, + latitude: Number, + longitude: Number, +}); + +export default mongoose.model('Venue', VenueSchema); diff --git a/server/src/models/fixtures.js b/server/src/models/fixtures.js new file mode 100644 index 0000000..37ccdbd --- /dev/null +++ b/server/src/models/fixtures.js @@ -0,0 +1,18 @@ +/* eslint-disable import/prefer-default-export */ +import User from '../models/User'; + +export function addTestUsers() { + if (process.env.NODE_ENV === 'development') { + User.find((err, users) => { + if (err || users.length === 0) { // add test user if users is empty + const user = new User({ + username: 'test', + password: 'test', + role: 'admin', + }); + user.save(); + console.log('Added test user!'); + } + }); + } +} diff --git a/server/src/router.js b/server/src/router.js new file mode 100644 index 0000000..b6fa85f --- /dev/null +++ b/server/src/router.js @@ -0,0 +1,53 @@ +import express from 'express'; +import { postEvents, getEvent, getEvents, + putEvent, deleteEvent, oldEvents } from './controllers/event'; +import { postUser, getUser, putUser, deleteUser, getUsers } from './controllers/user'; +import { isAuthenticated, login } from './controllers/auth'; +import { postImage, getImage } from './controllers/image'; +import { postVenues, getVenues, getVenue, + putVenue, deleteVenue } from './controllers/venue'; + +const auth = isAuthenticated; +const router = express.Router(); + + +router.route('/events') + .post(auth, postEvents) + .get(getEvents); + +router.route('/events/:event_id') + .get(getEvent) + .put(auth, putEvent) + .delete(auth, deleteEvent); + +router.route('/v1/events') + .get(oldEvents); + +router.route('/users') + .post(auth, postUser) + .get(auth, getUsers); + +router.route('/users/:user_id') + .put(auth, putUser) + .get(auth, getUser) + .delete(auth, deleteUser); + +router.route('/images') + .post(auth, postImage); + +router.route('/images/*') + .get(getImage); + +router.route('/venues') + .post(postVenues) + .get(getVenues); + +router.route('/venues/:venue_id') + .get(getVenue) + .put(putVenue) + .delete(deleteVenue); + +router.route('/login', getUser) + .get(auth, login); + +export default router; diff --git a/server/src/server.js b/server/src/server.js new file mode 100644 index 0000000..dc0c573 --- /dev/null +++ b/server/src/server.js @@ -0,0 +1,34 @@ +import mongoose from 'mongoose'; +import bodyParser from 'body-parser'; +import express from 'express'; +import passport from 'passport'; +import cors from 'cors'; +import busboy from 'connect-busboy'; +import router from './router.js'; +import jobs from './import/jobs'; +import { addTestUsers } from './models/fixtures.js'; + +const app = express(); + +const WHITELIST = [ + 'http://localhost:9000', + /\.barteguiden\.no$/, +]; + +app.use(bodyParser.json()); +app.use(busboy()); +app.use(passport.initialize()); +app.use(cors({ origin: WHITELIST })); + +const port = process.env.PORT || 4004; +mongoose.connect('mongodb://127.0.0.1:27018/eventdb'); + +app.use('/api', router); + +app.listen(port, () => { + console.log(`Serving on port ${port}`); + jobs.start(); + addTestUsers(); +}); + +export default app; diff --git a/server/test/example.test.js b/server/test/example.test.js new file mode 100644 index 0000000..582b873 --- /dev/null +++ b/server/test/example.test.js @@ -0,0 +1,12 @@ +/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */ +import test from 'ava'; +import request from 'supertest-as-promised'; +import app from '../src/server.js'; + +test('Can get events', (t) => { + request(app).get('/api/events') + .expect(200) + .then((res) => { + t.is(Array.isArray(res.body), true); + }); +});