diff --git a/README.md b/README.md index 6edd221..4a3e7e3 100644 --- a/README.md +++ b/README.md @@ -1 +1,128 @@ -# collectivecar \ No newline at end of file +#ComunalCar app + + +**Backend:** + Nodejs + Express + MongoDB + +**Frontend:** + Angularjs + Materializecss + + +##Project Structure: +``` +comunalcar/ + server/ + controllers/ + userController.js + travelController.js + carController.js + askfortravelController.js + models/ + userModel.js + travelModel.js + carModel.js + needtravelModel.js + node_modules/ + config.js + server.js + package.js + README.md +``` + + +##To Do List: +**Backend:** +``` +-signup user --> done +-loggin user --> done +-update user profile --> done +-create new travel --> done +-update travel --> done +-delete travel --> done +-create offeringCar +-update offeringCar +-delete offeringCar +-create askingForTravel (needtravel) +-update askingForTravel +-delete askgingForTravel +-user joins a car +-user joins travel +``` + +**Frontend:** +``` +-signup user +-loggin user +-update user profile +-create new travel +-update travel +-delete travel +-create offeringCar +-update offeringCar +-delete offeringCar +-create askingForTravel +-update askingForTravel +-delete askgingForTravel +``` +-------------------- +####**PARA LA BASE DE DATOS** [para definir como queremos q esté estructurado, pensando en las funcionalidades que queremos tener]: + +**user**: +-username +-password +-description +-icon/avatar +-mail +-phone + +**travel**: (seria cuando un user publica un nuevo trayecto que va a hacer) +-title +-description +-owner (user q ha publicado el viaje) +-from +-to +-date +-description +-generateddate (cuando el user genera el aviso) +-seats (plazas de coche disponibles) + +**car**: (cuando un user tiene un coche disponible para hacer viajes que se necesiten) +-title +-description +-owner (user q ha publicado el viaje) +-zone (la zona por la que está) +-available (cuando el user esta disponible, marca que esta disponible, si unos dias no podrá, lo desactiva) +-generateddate +-seats (plazas de coche disponibles) + +**needtravel**: (cuando un user no dispone de coche y necesita hacer un travel) +-title +-description +-owner (user q ha publicado el asking travel) +-from +-to +-date (las fechas para cuando se necesita el viaje) +-generateddate (cuando el user genera el aviso) +-seats (plazas de coche necesarias) + +**collectivizedCar**: (los coches/furgos comunales) --> quizás esto no hace falta, solo usar 'offeringCar' normal con un añadido para notificar que es un coche colectivizado +-owner (user q publica el coche) +-title +-seats (plazas de coche disponibles) + +-------------------- + + + +####**OTRAS COSAS**: +lo de poner o no un mapa, de entrada no destinaria esfuerzos en eso. Para la primera versión de la aplicación no hace falta, solo añade confort visual, para ver el recorrido, pero de entrada para una app q pone en contacto personas para compartir coche, no es algo imprescindible quizás + + + +####**RESOURCES to use**: + + car icons [http://www.flaticon.com/packs/transportation-7](http://www.flaticon.com/packs/transportation-7) + + css para la app: matterializeCSS [http://materializecss.com/](http://materializecss.com/) + + avatars users: [http://www.flaticon.com/packs/animal-icon-collection](http://www.flaticon.com/packs/animal-icon-collection) diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..bf7525f --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,41 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history diff --git a/server/config.js b/server/config.js new file mode 100644 index 0000000..ee73326 --- /dev/null +++ b/server/config.js @@ -0,0 +1,7 @@ +module.exports = { + + 'secret': 'secretfortoken', + 'database': 'mongodb://localhost/comunalcar', + "port" : process.env.PORT || 3000 + +}; diff --git a/server/controllers/travelController.js b/server/controllers/travelController.js new file mode 100644 index 0000000..882e102 --- /dev/null +++ b/server/controllers/travelController.js @@ -0,0 +1,97 @@ +//File: controllers/travelController.js +var mongoose = require('mongoose'); +var travelModel = mongoose.model('travelModel'); + +var userModel = mongoose.model('userModel'); + +//GET +exports.findAllTravels = function(req, res) { + + travelModel.find(function(err, travels) { + if(err) res.send(500, err.message); + + res.status(200).jsonp(travels); + }); + + +}; + +//GET +exports.findById = function(req, res) { + travelModel.findById(req.params.id, function(err, travel) { + if(err) return res.send(500, err.message); + + console.log('GET /travel/' + req.params.id); + res.status(200).jsonp(travel); + }); +}; + +exports.findAllTravelsFromUsername = function(req, res) { + travelModel.find({ + authorname: req.params.userid + }, function(err, travels) { + + if (err) throw err; + + if (!travels) { + res.json({ success: false, message: 'no travels for user' }); + } else if (travels) { + console.log(travels); + // return the information including token as JSON + res.jsonp(travels); + + + } + + }); +}; + +exports.addTravel = function(req, res) { + console.log('POST new travel, content: ' + req.body.content); + console.log(req.body); + + var travel = new travelModel({ + title: req.body.title, + description: req.body.description, + owner: req.body.owner, + from: req.body.from, + to: req.body.to, + date: req.body.date, + generateddate: req.body.generateddate, + seats: req.body.seats + }); + + travel.save(function(err, travel) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(travel); + }); +}; + +//PUT +exports.updateTravel = function(req, res) { + ActivityModel.findById(req.params.id, function(err, tvshow) { + tvshow.title = req.body.petId; + tvshow.year = req.body.year; + tvshow.country = req.body.country; + tvshow.poster = req.body.poster; + tvshow.seasons = req.body.seasons; + tvshow.genre = req.body.genre; + tvshow.summary = req.body.summary; + + tvshow.save(function(err) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(tvshow); + }); + }); +}; + +//DELETE +exports.deleteTravel = function(req, res) { + ActivityModel.findById(req.params.id, function(err, activity) { + activity.remove(function(err) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(req.params.id); + console.log('DELETE /activities/' + req.params.id); + }) + }); +}; diff --git a/server/controllers/userController.js b/server/controllers/userController.js new file mode 100644 index 0000000..da36ca5 --- /dev/null +++ b/server/controllers/userController.js @@ -0,0 +1,139 @@ +//File: controllers/userController.js +var mongoose = require('mongoose'); +var userModel = mongoose.model('userModel'); + +/* */ +var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens +var express = require("express"); +var app = express(); +var config = require('../config'); // get our config file +app.set('superSecret', config.secret); // secret variable +/* */ + +//GET - Return all Users in the DB +exports.findAllUsers = function(req, res) { + userModel.find(function(err, users) { + if(err) res.send(500, err.message); + + console.log('GET /users'); + res.status(200).jsonp(users); + }); +}; + +//GET - Return a User with specified ID +exports.findById = function(req, res) { + userModel.findById(req.params.id, function(err, user) { + if(err) return res.send(500, err.message); + + console.log('GET /users/' + req.params.id); + res.status(200).jsonp(user); + }); +}; + +exports.findUserByUsername = function(req, res) { + userModel.find({ + username: req.params.username + }, function(err, user) { + + if (err) throw err; + + if (!user) { + res.json({ success: false, message: 'no user found' }); + } else if (user) { + console.log(user); + // return the information including token as JSON + res.jsonp(user); + + + } + + }); +}; + +//POST - Insert a new User in the DB +exports.addUser = function(req, res) { + console.log('POST new user, name: ' + req.body.username); + //console.log(req.body); + + var user = new userModel({ + username: req.body.username, + password: req.body.password, + description: req.body.description, + avatar: req.body.avatar, + mail: req.body.mail, + admin: req.body.admin + }); + + user.save(function(err, user) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(user); + }); +}; + +//PUT - Update a user already exists +exports.updateUser = function(req, res) { + userModel.findById(req.params.id, function(err, user) { + user.username = req.body.username; + user.password = req.body.password; + user.description = req.body.description; + user.avatar = req.body.avatar; + user.mail = req.body.mail; + user.admin = req.body.admin; + + user.save(function(err) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(user); + }); + }); +}; + +//DELETE - Delete a user with specified ID +exports.deleteUser = function(req, res) { + userModel.findById(req.params.id, function(err, user) { + user.remove(function(err) { + if(err) return res.send(500, err.message); + res.status(200).jsonp(req.params.id); + console.log('DELETE /users/' + req.params.id); + }) + }); +}; + + +//POST - auth user +exports.login = function(req, res) { + // find the user + userModel.findOne({ + username: req.body.username + }, function(err, user) { + + if (err) throw err; + + if (!user) { + res.json({ success: false, message: 'Authentication failed. User not found.' }); + } else if (user) { + + // check if password matches + if (user.password != req.body.password) { + res.json({ success: false, message: 'Authentication failed. Wrong password.' }); + } else { + + // if user is found and password is right + // create a token + var token = jwt.sign(user, app.get('superSecret'), { + //expiresInMinutes: 1440 // expires in 24 hours + expiresIn: '60m' + }); +console.log(user); + // return the information including token as JSON + res.json({ + success: true, + message: 'Enjoy your token!', + token: token, + avatar: user.avatar + }); + } + + } + + }); +}; diff --git a/server/models/carModel.js b/server/models/carModel.js new file mode 100644 index 0000000..883bef7 --- /dev/null +++ b/server/models/carModel.js @@ -0,0 +1,14 @@ +var mongoose = require('mongoose'), + Schema = mongoose.Schema; + + +var carSchema = new Schema({ + title: { type: String }, + description: { type: String }, + owner: { type: String }, + zone: { type: String }, + available: { type: Boolean }, + generateddate: { type: Date }, + seats: { type: Number } +}) +module.exports = mongoose.model('carModel', carSchema); diff --git a/server/models/needtravelModel.js b/server/models/needtravelModel.js new file mode 100644 index 0000000..5a95a09 --- /dev/null +++ b/server/models/needtravelModel.js @@ -0,0 +1,15 @@ +var mongoose = require('mongoose'), + Schema = mongoose.Schema; + + +var needtravelSchema = new Schema({ + title: { type: String }, + description: { type: String }, + owner: { type: String }, + from: { type: String }, + to: { type: String }, + date: { type: Date }, + generateddate: { type: Date }, + seats: { type: Number } +}) +module.exports = mongoose.model('needtravelModel', needtravelSchema); diff --git a/server/models/travelModel.js b/server/models/travelModel.js new file mode 100644 index 0000000..96fa635 --- /dev/null +++ b/server/models/travelModel.js @@ -0,0 +1,15 @@ +var mongoose = require('mongoose'), + Schema = mongoose.Schema; + + +var travelSchema = new Schema({ + title: { type: String }, + description: { type: String }, + owner: { type: String }, + from: { type: String }, + to: { type: String }, + date: { type: Date }, + generateddate: { type: Date }, + seats: { type: Number } +}) +module.exports = mongoose.model('travelModel', travelSchema); diff --git a/server/models/userModel.js b/server/models/userModel.js new file mode 100644 index 0000000..3fbd11e --- /dev/null +++ b/server/models/userModel.js @@ -0,0 +1,13 @@ +var mongoose = require('mongoose'), + Schema = mongoose.Schema; + + +var userSchema = new Schema({ + username: { type: String }, + password: { type: String }, + description: { type: String }, + avatar: { type: String }, + mail: { type: String }, + phone: { type: String } +}) +module.exports = mongoose.model('userModel', userSchema); diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..5c5da62 --- /dev/null +++ b/server/package.json @@ -0,0 +1,17 @@ +{ + "name": "comunalCar", + "version": "0.0.1", + "description": "comunalCar, carsharing", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "mongoose": "^4.5.6", + "express": "^4.7.1", + "method-override": "^2.1.2", + "body-parser": "^1.5.1", + "jsonwebtoken" : "latest", + "morgan" : "latest" + } +} diff --git a/server/server.js b/server/server.js new file mode 100755 index 0000000..2172541 --- /dev/null +++ b/server/server.js @@ -0,0 +1,123 @@ +var express = require("express"), + app = express(), + bodyParser = require("body-parser"), + methodOverride = require("method-override"), + mongoose = require('mongoose'); + + +var morgan = require('morgan'); +var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens +var config = require('./config'); // get our config file + + +// Connection to DB +mongoose.connect(config.database, function(err, res) { + if(err) throw err; + console.log('Connected to Database'); +}); +app.set('superSecret', config.secret); // secret variable + +// Middlewares +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); +app.use(methodOverride()); + +// use morgan to log requests to the console +app.use(morgan('dev')); + +// Import Models and controllers +var userMdl = require('./models/userModel')(app, mongoose); +var userCtrl = require('./controllers/userController'); + +var travelMdl = require('./models/travelModel')(app, mongoose); +var travelCtrl = require('./controllers/travelController'); + +/*// Example Route +var router = express.Router(); +router.get('/', function(req, res) { + res.send("Hello world!"); +}); +app.use(router);*/ +app.use(express.static(__dirname + '/web')); + + +//CORS +app.use(function(req, res, next) { + res.header("Access-Control-Allow-Origin", "*"); + res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + next(); +}); + +// API routes ------------------------------------------------------ +var apiRoutes = express.Router(); + +apiRoutes.route('/users') + .get(userCtrl.findAllUsers) + .post(userCtrl.addUser); +apiRoutes.route('/users/:id') + .get(userCtrl.findById); +apiRoutes.route('/users/byusername/:username') + .get(userCtrl.findUserByUsername); +apiRoutes.route('/travels/user/:userid') + .get(travelCtrl.findAllTravelsFromUsername); + +apiRoutes.route('/auth') + .post(userCtrl.login); + +apiRoutes.route('/travels') + .get(travelCtrl.findAllTravels); + +apiRoutes.route('/travels/:id') +.get(travelCtrl.findById) + +// route middleware to verify a token +apiRoutes.use(function(req, res, next) { + + // check header or url parameters or post parameters for token + var token = req.body.token || req.query.token || req.headers['x-access-token']; + + // decode token + if (token) { + + // verifies secret and checks exp + jwt.verify(token, app.get('superSecret'), function(err, decoded) { + if (err) { + return res.json({ success: false, message: 'Failed to authenticate token.' }); + } else { + // if everything is good, save to request for use in other routes + req.decoded = decoded; + next(); + } + }); + + } else { + + // if there is no token + // return an error + return res.status(403).send({ + success: false, + message: 'No token provided.' + }); + + } +}); + +apiRoutes.route('/users/:id') + .put(userCtrl.updateUser) + .delete(userCtrl.deleteUser); + +apiRoutes.route('/travels') + .post(travelCtrl.addTravel); + +apiRoutes.route('/travels/:id') + .put(travelCtrl.updateTravel) + .delete(travelCtrl.deleteTravel); + +app.use('/api', apiRoutes); +// end of API routes ------------------------------------- + +// Start server +app.listen(config.port, function() { + console.log("Node server running on http://localhost:3000"); +});