From d0df0e39009691f79dc1540cc839ba70b41d8e60 Mon Sep 17 00:00:00 2001 From: walter Date: Mon, 30 Nov 2015 23:16:01 -0800 Subject: [PATCH 1/4] added authentication --- README.md | 28 ----------- walter_nicholas/lib/basic_http_auth.js | 18 +++++++ walter_nicholas/lib/eat_auth.js | 33 ++++++++++++ walter_nicholas/lib/handle_error.js | 4 ++ walter_nicholas/models/user.js | 29 +++++++++++ walter_nicholas/package.json | 4 ++ walter_nicholas/routes/task_routes.js | 58 +++++++++++++++++++++ walter_nicholas/routes/tasks_routes.js | 70 -------------------------- walter_nicholas/routes/user_routes.js | 69 +++++++++++++++++++++++++ walter_nicholas/server.js | 7 ++- 10 files changed, 220 insertions(+), 100 deletions(-) delete mode 100644 README.md create mode 100644 walter_nicholas/lib/basic_http_auth.js create mode 100644 walter_nicholas/lib/eat_auth.js create mode 100644 walter_nicholas/lib/handle_error.js create mode 100644 walter_nicholas/models/user.js create mode 100644 walter_nicholas/routes/task_routes.js delete mode 100644 walter_nicholas/routes/tasks_routes.js create mode 100644 walter_nicholas/routes/user_routes.js diff --git a/README.md b/README.md deleted file mode 100644 index 5e09c5c..0000000 --- a/README.md +++ /dev/null @@ -1,28 +0,0 @@ -Mongo Backed REST API -========================== -To complete this assignment: - * fork this repository (the sub module for this specific assignment) - * clone down your fork - * place all of your work in a folder that is your full name, use `_`s instead of spaces - * push back up to your fork - * create a pull request back to the original repo - * submit a link to the PR in canvas - -Assignment Description --------------------------- -Create a single resource rest API with Express that's backed by Mongo. - -I'm leaving this pretty open to interpretation. I want you to write this from scratch, don't just copy and paste code from class or previous projects. - -Add a feature of Mongoose that we didn't use class, such as data validation. - -Also, implement a non CRUD resource (meaning that it doesn't use the full GET/POST/PUT/PATCH/DELETE interface). - - - -Rubric - - * Use of Express: 3pts - * Use of Mongo: 3pts - * Tests: 2pts - * Project Organization: 2pts diff --git a/walter_nicholas/lib/basic_http_auth.js b/walter_nicholas/lib/basic_http_auth.js new file mode 100644 index 0000000..92987fe --- /dev/null +++ b/walter_nicholas/lib/basic_http_auth.js @@ -0,0 +1,18 @@ +module.exports = function(req, res, next) { + try { + var authString = req.headers.authorization; + var basicString = authString.split(' ')[1]; + var basicBuffer = new Buffer(basicString, 'base64'); + var authArray = basicBuffer.toString().split(':'); + req.auth = { + username: authArray[0], + password: authArray[1] + }; + // debugger; + next(); + } catch(e) { + // debugger; + console.log(e); + return res.status(401).json({msg: 'nope cat 4 u'}); + } +}; diff --git a/walter_nicholas/lib/eat_auth.js b/walter_nicholas/lib/eat_auth.js new file mode 100644 index 0000000..a7f9fe4 --- /dev/null +++ b/walter_nicholas/lib/eat_auth.js @@ -0,0 +1,33 @@ +var eat = require('eat'); +var User = require(__dirname + '/../models/user'); + +module.exports = exports = function(req, res, next) { + var token = req.headers.token || (req.body)? req.body.token : ''; + if (!token) { + console.log('no token'); + return res.status(401).json({msg: 'no token'}); + } + + eat.decode(token, process.env.APP_SECRET, function(err, decoded) { + if (err) { + console.log(err); + return res.status(401).json({msg: 'eat cat say nope (1)'}); + } + + User.findOne({_id: decoded.id}, function(err, user) { + if (err) { + console.log(err); + return res.status(401).json({msg: 'eat cat say nope (2)'}); + } + + if (!user) { + console.log(err); + return res.status(401).json({msg: 'eat cat say nope (3)'}); + + } + + req.user = user; + next(); + }); + }); +}; diff --git a/walter_nicholas/lib/handle_error.js b/walter_nicholas/lib/handle_error.js new file mode 100644 index 0000000..fb84c51 --- /dev/null +++ b/walter_nicholas/lib/handle_error.js @@ -0,0 +1,4 @@ +module.exports = function(err, res) { + console.log(err); + res.status(500).json({msg: 'server error.'}); +}; \ No newline at end of file diff --git a/walter_nicholas/models/user.js b/walter_nicholas/models/user.js new file mode 100644 index 0000000..b0fd324 --- /dev/null +++ b/walter_nicholas/models/user.js @@ -0,0 +1,29 @@ +var mongoose = require('mongoose'); +var bcrypt = require('bcrypt'); +var eat = require('eat'); + +var userSchema = new mongoose.Schema({ + username: String, + auth: { + basic: { + username: String, + password: String + } + } +}); + +userSchema.methods.hashPassword = function(password) { + var hash = this.auth.basic.password = bcrypt.hashSync(password, 8); + return hash; +}; + +userSchema.methods.checkPassword = function(password) { + return bcrypt.compareSync(password, this.auth.basic.password); +}; + +userSchema.methods.generateToken = function(cb) { + var id = this._id; + eat.encode({id: id}, process.env.APP_SECRET, cb); +}; + +module.exports = mongoose.model('User', userSchema); \ No newline at end of file diff --git a/walter_nicholas/package.json b/walter_nicholas/package.json index 4ca581f..06fb06e 100644 --- a/walter_nicholas/package.json +++ b/walter_nicholas/package.json @@ -14,8 +14,12 @@ "mongoose": "^4.2.5" }, "devDependencies": { + "bcrypt": "^0.8.5", + "body-parser": "^1.14.1", "chai": "^3.4.1", "chai-http": "^1.0.0", + "eat": "^0.1.1", + "express": "^4.13.3", "mocha": "^2.3.3" } } diff --git a/walter_nicholas/routes/task_routes.js b/walter_nicholas/routes/task_routes.js new file mode 100644 index 0000000..4df6ed3 --- /dev/null +++ b/walter_nicholas/routes/task_routes.js @@ -0,0 +1,58 @@ +var express = require('express'); +var bodyParser = require('body-parser').json(); +var handleError = require(__dirname + '/../lib/handle_error'); +var Task = require(__dirname + '/../models/task'); +var taskRouter = module.exports = exports = express.Router(); +var eatAuth = require(__dirname + '/../lib/eat_auth'); + +taskRouter.get('/tasks', function (req, res) { + Task.find({}, function (err, data) { + if (err) return handleError(err, res); + + res.json(data); + }); +}); + +taskRouter.get('/tasks/priority/:num', function (req, res) { + Task.find({priority : { $lt: (parseInt(req.params.num) + 1)}}, function(err, data) { //finds all tasks with priority less than or equal to route specified by :num + if (err) return handleError(err, res); + + res.json(data); + }); +}); + +taskRouter.get('/tasks/location/:loc', function (req, res) { + Task.find({location : req.params.loc}, function(err, data) { + if (err) return handleError(err, res); + + res.json(data); + }); +}); + +taskRouter.post('/tasks', bodyParser, function (req, res) { + var newTask = new Task(req.body); + newTask.save(function(err, data) { + if (err) return handleError(err, res); + + res.json(data); + }); +}); + +taskRouter.put('/tasks/:id', bodyParser, function (req, res) { + var taskData = req.body; + delete taskData._id; + Task.update({_id: req.params.id}, taskData, function (err) { + if (err) return handleError(err, res); + + res.json({msg: 'Task modified.'}); + }); +}); + +taskRouter.delete('/tasks/:id', bodyParser, eatAuth, function (req, res) { + Task.remove({_id: req.params.id}, function (err) { + if (err) return handleError(err, res); + + res.json({msg: 'eat auth success!'}); + }); +}); + diff --git a/walter_nicholas/routes/tasks_routes.js b/walter_nicholas/routes/tasks_routes.js deleted file mode 100644 index 33a3ecf..0000000 --- a/walter_nicholas/routes/tasks_routes.js +++ /dev/null @@ -1,70 +0,0 @@ -var express = require('express'); -var bodyParser = require('body-parser'); - -var Task = require(__dirname + '/../models/task'); -var tasksRouter = express.Router(); -module.exports = exports = tasksRouter; - -tasksRouter.get('/tasks', function(req, res) { - Task.find({}, function(err, data) { - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json(data); - }); -}); - -tasksRouter.get('/tasks/priority/:num', function(req, res) { - Task.find({priority : { $lt: (parseInt(req.params.num) + 1)}}, function(err, data) { //finds all tasks with priority less than or equal to route specified by :num - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json(data); - }); -}); - -tasksRouter.get('/tasks/location/:loc', function(req, res) { - Task.find({location : req.params.loc}, function(err, data) { - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json(data); - }); -}); - -tasksRouter.post('/tasks', bodyParser.json(), function(req, res) { - var newTask = new Task(req.body); - newTask.save(function(err, data) { - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json(data); - }); -}); - -tasksRouter.put('/tasks/:id', bodyParser.json(), function(req, res) { - var taskData = req.body; - delete taskData._id; - Task.update({_id: req.params.id}, taskData, function(err) { - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json({msg: 'Task modified.'}); - }); -}); - -tasksRouter.delete('/tasks/:id', function(req, res) { - Task.remove({_id: req.params.id}, function(err) { - if (err) return function(err, res) { - res.status(500).json({msg: 'Server error.'}); - }; - - res.json({msg: 'Task deleted.'}); - }); -}); - diff --git a/walter_nicholas/routes/user_routes.js b/walter_nicholas/routes/user_routes.js new file mode 100644 index 0000000..3177866 --- /dev/null +++ b/walter_nicholas/routes/user_routes.js @@ -0,0 +1,69 @@ +var express = require('express'); +var bodyParser = require('body-parser').json(); +var handleError = require(__dirname + '/../lib/handle_error'); +var basicHttp = require(__dirname + '/../lib/basic_http_auth') +var User = require(__dirname + '/../models/user'); + +var userRouter = module.exports = exports = express.Router(); + +userRouter.post('/signup', bodyParser, function (req, res) { + + User.findOne({'username': req.body.username}, function (err, user) { + if(err) { + console.log('error finding user'); + return res.status(401).json({msg: 'signup cat say some sort of error'}); + } + + if(!user) { //only creates new user after it determines there is no user with that name already in db + var user = new User(); + user.auth.basic.username = req.body.username; + user.username = req.body.username; + user.hashPassword(req.body.password); + + user.save(function(err, data) { + if(err) return handleError(err, res); + + user.generateToken(function(err, token) { + if(err) return handleError(err, res); + + res.json({token: token}); + }); + }); + } else { + console.log('user already exists'); + return res.status(401).json({msg: 'signup cat says user by that name already exists.'}); + } + }); +}); + +userRouter.get('/signin', basicHttp, function (req, res) { + if(!(req.auth.username && req.auth.password)) { + console.log('no username/password provided'); + return res.status(401).json({msg: 'cat say gib username and password rigt now'}); + } + + User.findOne({'auth.basic.username': req.auth.username}, function (err, user) { + if(err) { + console.log('error finding user'); + return res.status(401).json({msg: 'cat say some sort of error finding user'}); + } + + if(!user) { + console.log('no user found'); + return res.status(401).json({msg: 'cat say no user found by that name'}); + } + + if(!user.checkPassword(req.auth.password)) { + console.log('wrong password'); + return res.status(401).json({msg: 'cat say wrong password'}); + } + + user.generateToken(function (err, token) { + if(err) return handleError(err, res); + + res.json({token: token}); + }); + }); +}); + + diff --git a/walter_nicholas/server.js b/walter_nicholas/server.js index f0a16f2..b9a8fb9 100644 --- a/walter_nicholas/server.js +++ b/walter_nicholas/server.js @@ -1,10 +1,13 @@ var mongoose = require('mongoose'); var app = require('express')(); -var tasksRouter = require(__dirname + '/routes/tasks_routes'); +var userRouter = require(__dirname + '/routes/user_routes'); +var taskRouter = require(__dirname + '/routes/task_routes'); +process.env.APP_SECRET = process.env.APP_SECRET || 'changethislaterforsomereason'; mongoose.connect(process.env.MONGOLAB_URI || 'mongodb://localhost/tasks_db_dev'); -app.use('/api', tasksRouter); +app.use('/api', userRouter); +app.use('/api', taskRouter); app.listen(3000, function() { console.log('server up'); From 77b9f240e9fadf291cebbc489b291e2cdaab9230 Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 2 Dec 2015 12:44:47 -0800 Subject: [PATCH 2/4] initial commit --- walter_nicholas/app/index.html | 18 +++++++++++++++++ walter_nicholas/app/js/entry.js | 6 ++++++ .../js/tasks/controllers/tasks_controller.js | 15 ++++++++++++++ walter_nicholas/app/js/tasks/tasks.js | 3 +++ walter_nicholas/gulpfile.js | 20 +++++++++++++++++++ walter_nicholas/package.json | 5 ++++- walter_nicholas/server.js | 7 +++++++ 7 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 walter_nicholas/app/index.html create mode 100644 walter_nicholas/app/js/entry.js create mode 100644 walter_nicholas/app/js/tasks/controllers/tasks_controller.js create mode 100644 walter_nicholas/app/js/tasks/tasks.js create mode 100644 walter_nicholas/gulpfile.js diff --git a/walter_nicholas/app/index.html b/walter_nicholas/app/index.html new file mode 100644 index 0000000..0b3fe05 --- /dev/null +++ b/walter_nicholas/app/index.html @@ -0,0 +1,18 @@ + + + + + Task Finder + + +

Task Finder

+
+
    +
  • + {{task.description}} +
  • +
+
+ + + \ No newline at end of file diff --git a/walter_nicholas/app/js/entry.js b/walter_nicholas/app/js/entry.js new file mode 100644 index 0000000..cd2e689 --- /dev/null +++ b/walter_nicholas/app/js/entry.js @@ -0,0 +1,6 @@ +require('angular/angular'); +var angular = window.angular; + +var taskApp = angular.module('taskApp', []); +// require('./controllers/controllers')(taskApp); +require('./tasks/tasks')(taskApp); diff --git a/walter_nicholas/app/js/tasks/controllers/tasks_controller.js b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js new file mode 100644 index 0000000..4ece073 --- /dev/null +++ b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js @@ -0,0 +1,15 @@ +module.exports = function(app) { + app.controller('tasksController', ['$scope', '$http', function($scope, $http) { + $scope.tasks = []; + + $scope.retrieveTasks = function() { + $http.get('/api/tasks') + .then(function(res) { + $scope.tasks = res.data; + }, function(err) { + console.log(err.data); + }); + }; + + }]); +}; \ No newline at end of file diff --git a/walter_nicholas/app/js/tasks/tasks.js b/walter_nicholas/app/js/tasks/tasks.js new file mode 100644 index 0000000..bc6c1a0 --- /dev/null +++ b/walter_nicholas/app/js/tasks/tasks.js @@ -0,0 +1,3 @@ +module.exports = function(app) { + require('./controllers/tasks_controller')(app); +}; diff --git a/walter_nicholas/gulpfile.js b/walter_nicholas/gulpfile.js new file mode 100644 index 0000000..9458331 --- /dev/null +++ b/walter_nicholas/gulpfile.js @@ -0,0 +1,20 @@ +var gulp = require('gulp'); +var webpack = require('webpack-stream'); + +gulp.task('static:dev', function() { + gulp.src('app/**/*.html') + .pipe(gulp.dest('build/')); +}); + +gulp.task('webpack:dev', function() { + return gulp.src('app/js/entry.js') + .pipe(webpack({ + output: { + filename: 'bundle.js' + } + })) + .pipe(gulp.dest('build/')); +}); + +gulp.task('build:dev', ['webpack:dev', 'static:dev']); +gulp.task('default', ['build:dev']); diff --git a/walter_nicholas/package.json b/walter_nicholas/package.json index 06fb06e..9fad8b8 100644 --- a/walter_nicholas/package.json +++ b/walter_nicholas/package.json @@ -14,12 +14,15 @@ "mongoose": "^4.2.5" }, "devDependencies": { + "angular": "^1.4.8", "bcrypt": "^0.8.5", "body-parser": "^1.14.1", "chai": "^3.4.1", "chai-http": "^1.0.0", "eat": "^0.1.1", "express": "^4.13.3", - "mocha": "^2.3.3" + "gulp": "^3.9.0", + "mocha": "^2.3.3", + "webpack-stream": "^2.2.0" } } diff --git a/walter_nicholas/server.js b/walter_nicholas/server.js index b9a8fb9..ed6272f 100644 --- a/walter_nicholas/server.js +++ b/walter_nicholas/server.js @@ -1,4 +1,6 @@ var mongoose = require('mongoose'); +var fs = require('fs'); +var express = require('express'); var app = require('express')(); var userRouter = require(__dirname + '/routes/user_routes'); var taskRouter = require(__dirname + '/routes/task_routes'); @@ -9,6 +11,11 @@ mongoose.connect(process.env.MONGOLAB_URI || 'mongodb://localhost/tasks_db_dev') app.use('/api', userRouter); app.use('/api', taskRouter); +app.use(express.static('build')); +app.get('/', function (req, res) { + res.send((fs.readFileSync(__dirname + '/build/index.html')).toString()); +}); + app.listen(3000, function() { console.log('server up'); }); From f034611a7730a3505124514f15a98eb7d66c03fe Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 2 Dec 2015 15:42:12 -0800 Subject: [PATCH 3/4] finished adding CRUD --- walter_nicholas/app/css/base.css | 25 ++++++++ walter_nicholas/app/index.html | 63 +++++++++++++++++-- .../js/tasks/controllers/tasks_controller.js | 56 +++++++++++++++++ walter_nicholas/gulpfile.js | 7 ++- walter_nicholas/models/task.js | 3 +- walter_nicholas/package.json | 6 ++ walter_nicholas/routes/task_routes.js | 20 +++++- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 walter_nicholas/app/css/base.css diff --git a/walter_nicholas/app/css/base.css b/walter_nicholas/app/css/base.css new file mode 100644 index 0000000..d72c046 --- /dev/null +++ b/walter_nicholas/app/css/base.css @@ -0,0 +1,25 @@ +body { + background: lightgrey; +} + +td { + border: 1px solid black; + width: 200px; + height: 40px; + font-size: 1.3em; + background: white; + text-align: center; +} + +.deleteTasksButton, .updateButton { + width: 200px; + height: 40px; + font-size: 1.2em; +} + +.deleteTasksButton { + color: red; +} + +#taskTable { +} \ No newline at end of file diff --git a/walter_nicholas/app/index.html b/walter_nicholas/app/index.html index 0b3fe05..6b9e9dd 100644 --- a/walter_nicholas/app/index.html +++ b/walter_nicholas/app/index.html @@ -1,18 +1,69 @@ + Task Finder -

Task Finder

+

Task Finder

-
    -
  • - {{task.description}} -
  • -
+
+ + +
+ + +
+ +
+

New Task:

+ + + + + + + + + + + +
+ +

+ + + + + + + + +
Description Location Priority Completed Delete Tasks
{{task.description}} {{task.location}} {{task.priority}}
+
+ \ No newline at end of file diff --git a/walter_nicholas/app/js/tasks/controllers/tasks_controller.js b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js index 4ece073..1a67ce9 100644 --- a/walter_nicholas/app/js/tasks/controllers/tasks_controller.js +++ b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js @@ -1,6 +1,40 @@ module.exports = function(app) { app.controller('tasksController', ['$scope', '$http', function($scope, $http) { $scope.tasks = []; + var defaults = {location: 'work', priority: 1}; + $scope.newTask = Object.create(defaults); + + $scope.showTasksByPriority = function() { + var priority = $('select[id="priority"]').val(); + + $http.get('/api/tasks/priority/' + priority) + .then(function(res) { + $scope.tasks = res.data; + }, function(err) { + console.log(err.data); + }); + }; + + $scope.showTasksByCompletion = function() { + var status = $('select[id="completionStatus"]').val(); + + $http.get('/api/tasks/completed/' + status) + .then(function(res) { + $scope.tasks = res.data; + }, function(err) { + console.log(err.data); + }); + }; + + $scope.createTask = function(task) { + $http.post('/api/tasks', task) + .then(function(res) { + $scope.tasks.push(res.data); + $scope.newTask = Object.create(defaults); + }, function(err) { + console.log(err.data) + }); + }; $scope.retrieveTasks = function() { $http.get('/api/tasks') @@ -11,5 +45,27 @@ module.exports = function(app) { }); }; + $scope.updateTask = function(task) { + if(task.completed) task.completed = false; + else task.completed = true; + $http.put('/api/tasks/' + task._id, task) + .then(function(res) { + console.log('task completion status updated.'); + }, function(err) { + console.log(err.data); + }); + }; + + $scope.deleteTask = function(task) { + $scope.tasks.splice($scope.tasks.indexOf(task), 1); + $http.delete('/api/tasks/' + task._id) + .then(function(res) { + console.log('task deleted'); + }, function(err) { + console.log(err.data); + $scope.retrieveTasks(); + }); + }; + }]); }; \ No newline at end of file diff --git a/walter_nicholas/gulpfile.js b/walter_nicholas/gulpfile.js index 9458331..ffa9417 100644 --- a/walter_nicholas/gulpfile.js +++ b/walter_nicholas/gulpfile.js @@ -6,6 +6,11 @@ gulp.task('static:dev', function() { .pipe(gulp.dest('build/')); }); +gulp.task('cssFiles:dev', function() { + gulp.src('app/css/*.css') + .pipe(gulp.dest('build/css/')); +}); + gulp.task('webpack:dev', function() { return gulp.src('app/js/entry.js') .pipe(webpack({ @@ -16,5 +21,5 @@ gulp.task('webpack:dev', function() { .pipe(gulp.dest('build/')); }); -gulp.task('build:dev', ['webpack:dev', 'static:dev']); +gulp.task('build:dev', ['webpack:dev', 'static:dev', 'cssFiles:dev']); gulp.task('default', ['build:dev']); diff --git a/walter_nicholas/models/task.js b/walter_nicholas/models/task.js index fc5a3f1..3f56952 100644 --- a/walter_nicholas/models/task.js +++ b/walter_nicholas/models/task.js @@ -4,8 +4,7 @@ var taskSchema = new mongoose.Schema({ description: String, location: {type: String, default: 'work'}, deadline: Date, - priority: {type: Number, min: 0, max: 5}, - requiresCollab: {type: Boolean, default: false}, + priority: {type: Number, min: 1, max: 5, default: 1}, completed: {type: Boolean, default: false} }); diff --git a/walter_nicholas/package.json b/walter_nicholas/package.json index 9fad8b8..8842af4 100644 --- a/walter_nicholas/package.json +++ b/walter_nicholas/package.json @@ -15,6 +15,7 @@ }, "devDependencies": { "angular": "^1.4.8", + "angular-mocks": "^1.4.8", "bcrypt": "^0.8.5", "body-parser": "^1.14.1", "chai": "^3.4.1", @@ -22,7 +23,12 @@ "eat": "^0.1.1", "express": "^4.13.3", "gulp": "^3.9.0", + "jasmine-core": "^2.3.4", + "karma": "^0.13.15", + "karma-jasmine": "^0.3.6", + "karma-phantomjs-launcher": "^0.2.1", "mocha": "^2.3.3", + "phantomjs": "^1.9.19", "webpack-stream": "^2.2.0" } } diff --git a/walter_nicholas/routes/task_routes.js b/walter_nicholas/routes/task_routes.js index 4df6ed3..f75a946 100644 --- a/walter_nicholas/routes/task_routes.js +++ b/walter_nicholas/routes/task_routes.js @@ -21,6 +21,14 @@ taskRouter.get('/tasks/priority/:num', function (req, res) { }); }); +taskRouter.get('/tasks/completed/:status', function (req, res) { + Task.find({completed : req.params.status}, function(err, data) { + if (err) return handleError(err, res); + + res.json(data); + }); +}); + taskRouter.get('/tasks/location/:loc', function (req, res) { Task.find({location : req.params.loc}, function(err, data) { if (err) return handleError(err, res); @@ -48,11 +56,19 @@ taskRouter.put('/tasks/:id', bodyParser, function (req, res) { }); }); -taskRouter.delete('/tasks/:id', bodyParser, eatAuth, function (req, res) { +taskRouter.delete('/tasks/:id', function (req, res) { Task.remove({_id: req.params.id}, function (err) { if (err) return handleError(err, res); - res.json({msg: 'eat auth success!'}); + res.json({msg: 'Task deleted.'}); }); }); +// taskRouter.delete('/tasks/:id', bodyParser, eatAuth, function (req, res) { +// Task.remove({_id: req.params.id}, function (err) { +// if (err) return handleError(err, res); + +// res.json({msg: 'eat auth success!'}); +// }); +// }); + From 9f1d16262899a00cd3623cca16878e89c380b477 Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 11 Dec 2015 11:57:25 -0800 Subject: [PATCH 4/4] added advanced Sass --- walter_nicholas/app/index.html | 54 +++++++---- .../js/tasks/controllers/tasks_controller.js | 91 +++++++++++++++++-- walter_nicholas/app/scss/_base.scss | 43 +++++++++ walter_nicholas/app/scss/_layout.scss | 54 +++++++++++ walter_nicholas/app/scss/_state.scss | 5 + walter_nicholas/app/scss/application.scss | 3 + walter_nicholas/gulpfile.js | 13 ++- walter_nicholas/lib/eat_auth.js | 1 + walter_nicholas/package.json | 5 +- walter_nicholas/routes/task_routes.js | 8 +- 10 files changed, 247 insertions(+), 30 deletions(-) create mode 100644 walter_nicholas/app/scss/_base.scss create mode 100644 walter_nicholas/app/scss/_layout.scss create mode 100644 walter_nicholas/app/scss/_state.scss create mode 100644 walter_nicholas/app/scss/application.scss diff --git a/walter_nicholas/app/index.html b/walter_nicholas/app/index.html index 6b9e9dd..961af6a 100644 --- a/walter_nicholas/app/index.html +++ b/walter_nicholas/app/index.html @@ -1,31 +1,49 @@ - + Task Finder -

Task Finder

+

Task Finder

-
- -
+ + + +
+
+ + +
+ + +
+
+ +

New Task:

@@ -46,7 +64,7 @@

New Task:

- +

diff --git a/walter_nicholas/app/js/tasks/controllers/tasks_controller.js b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js index 1a67ce9..b3d9d8d 100644 --- a/walter_nicholas/app/js/tasks/controllers/tasks_controller.js +++ b/walter_nicholas/app/js/tasks/controllers/tasks_controller.js @@ -3,6 +3,69 @@ module.exports = function(app) { $scope.tasks = []; var defaults = {location: 'work', priority: 1}; $scope.newTask = Object.create(defaults); + $scope.token = false; + $scope.username = ''; + + $scope.signUp = function() { + $scope.username = $('input[id="newUsername"]').val(); + var password = $('input[id="newPassword"]').val(); + var repeated = $('input[id="repeated"]').val(); + if(!($scope.username != '' && password != '' && repeated != '')) alert('Fill out all fields'); + else if(repeated != password) alert('password != repeated'); + else { + var newUser = {"username": $scope.username, "password": password}; + + var successCb = function(res) { + if(res.data.token) $scope.token = res.data.token; + }; + var errorCb = function(err) { + console.log(err.data.msg); + alert(err.data.msg); + }; + + var req = { + method: 'POST', + url:'/api/signup', + data: newUser + }; + + $http(req).then(successCb, errorCb); + } + }; + + // $scope.signIn = function() { + // $scope.username = $('input[id="username"]').val(); + // var password = $('input[id="password"]').val(); + // if(!($scope.username != '' && password != '')) alert('Fill out all fields.'); + // else { + + // var successCb = function(res) { + // if(res.data.token) $scope.token = res.data.token; + // }; + + // var errorCb = function(err) { + // console.log(err.data) + // }; + + // var user = $scope.username; + // var req = { + // method: 'GET', + // url: '/api/signin' + // headers: {"Authorization": "Basic " + btoa(user + ":" + password)} + // }; + + // $http(req).then(successCb, errorCb); + + // var newUser = {"username": $scope.username, "password": password}; + // $http.post('/api/signup', newUser) + // .then(function(res) { + // if(res.data.token) $scope.token = res.data.token; + // }, function(err) { + // console.log(err.data) + // }); + // } + // }; + $scope.showTasksByPriority = function() { var priority = $('select[id="priority"]').val(); @@ -57,14 +120,28 @@ module.exports = function(app) { }; $scope.deleteTask = function(task) { - $scope.tasks.splice($scope.tasks.indexOf(task), 1); - $http.delete('/api/tasks/' + task._id) - .then(function(res) { - console.log('task deleted'); - }, function(err) { - console.log(err.data); + if(!($scope.token)) alert('Must be logged in to delete tasks.'); + else { + $scope.tasks.splice($scope.tasks.indexOf(task), 1); + + var successCb = function(res) { + console.log('task deleted.') + }; + + var errorCb = function(err) { + console.log(err.data.msg); $scope.retrieveTasks(); - }); + }; + + var req = { + method: 'POST', + url:'/api/tasks/delete/' + task._id, + data: {token: $scope.token} + }; + + $http(req).then(successCb, errorCb); + + } }; }]); diff --git a/walter_nicholas/app/scss/_base.scss b/walter_nicholas/app/scss/_base.scss new file mode 100644 index 0000000..74e2bbb --- /dev/null +++ b/walter_nicholas/app/scss/_base.scss @@ -0,0 +1,43 @@ +$a-variable-height: 40px; + +@mixin center { + text-align: center; + margin-left: auto; + margin-right: auto; +} + +@mixin container($bg, $radius, $height, $width) { + text-align: center; + background: $bg; + border: 1px solid black; + border-radius: $radius; + height: $height; + width: $width; + margin: 12px; +} + +@mixin border($radius) { + border: 1px solid black; + border-radius: $radius; +} + +body { + background: cornsilk; +} + +h1 { + font-size: 3em; +} + +h2 { + font-size: 2em; +} + +td { + @include border(3px); + width: 200px; + height: $a-variable-height; + font-size: 1.3em; + background: white; + text-align: center; +} diff --git a/walter_nicholas/app/scss/_layout.scss b/walter_nicholas/app/scss/_layout.scss new file mode 100644 index 0000000..054cd11 --- /dev/null +++ b/walter_nicholas/app/scss/_layout.scss @@ -0,0 +1,54 @@ +#taskTable { + @include center; +} + +.title { + @include container(lime, 3px, 70px, 270px); + @include center; +} + +.formContainer { + @include container(lime, 3px, 170px, 540px); + padding: 10px; + text-align: center; + @include center; +} + +.sortButtonsContainer { + @include container(yellow, 3px, 125px, 430px); + @include center; + + + button { + margin: 3px; + padding: 4px; + font-size: 1.1em; + } + select { + font-size: 1.1em; + padding: 4px; + } +} + +.deleteTasksButton, .updateButton { + width: 200px; + height: $a-variable-height; + font-size: 1.2em; +} + +.deleteTasksButton { + color: darkred; +} + +.login { + @include container(salmon, 10px, 200px, 250px); + position: absolute; + right: 6px; + top: 6px; + padding: 3px; + + input { + margin: 3px; + } +} + diff --git a/walter_nicholas/app/scss/_state.scss b/walter_nicholas/app/scss/_state.scss new file mode 100644 index 0000000..5e83670 --- /dev/null +++ b/walter_nicholas/app/scss/_state.scss @@ -0,0 +1,5 @@ +.loggedIn { + height: $a-variable-height; + font-size: 1.4em; + text-align: center; +} \ No newline at end of file diff --git a/walter_nicholas/app/scss/application.scss b/walter_nicholas/app/scss/application.scss new file mode 100644 index 0000000..ac111de --- /dev/null +++ b/walter_nicholas/app/scss/application.scss @@ -0,0 +1,3 @@ +@import "base"; +@import "layout"; +@import "state"; \ No newline at end of file diff --git a/walter_nicholas/gulpfile.js b/walter_nicholas/gulpfile.js index ffa9417..1147cb5 100644 --- a/walter_nicholas/gulpfile.js +++ b/walter_nicholas/gulpfile.js @@ -1,5 +1,8 @@ var gulp = require('gulp'); var webpack = require('webpack-stream'); +var sass = require('gulp-sass'); +var minifyCSS = require('gulp-minify-css'); +var sourcemaps = require('gulp-sourcemaps'); gulp.task('static:dev', function() { gulp.src('app/**/*.html') @@ -7,10 +10,18 @@ gulp.task('static:dev', function() { }); gulp.task('cssFiles:dev', function() { - gulp.src('app/css/*.css') + gulp.src('app/scss/**/*.scss') + .pipe(sourcemaps.init()) + .pipe(sass()) + .pipe(minifyCSS()) + .pipe(sourcemaps.write()) .pipe(gulp.dest('build/css/')); }); +gulp.task('css:watch', function () { + gulp.watch('app/css/**/*.css', ['css:dev']); +}); + gulp.task('webpack:dev', function() { return gulp.src('app/js/entry.js') .pipe(webpack({ diff --git a/walter_nicholas/lib/eat_auth.js b/walter_nicholas/lib/eat_auth.js index a7f9fe4..efe00c8 100644 --- a/walter_nicholas/lib/eat_auth.js +++ b/walter_nicholas/lib/eat_auth.js @@ -3,6 +3,7 @@ var User = require(__dirname + '/../models/user'); module.exports = exports = function(req, res, next) { var token = req.headers.token || (req.body)? req.body.token : ''; + if (!token) { console.log('no token'); return res.status(401).json({msg: 'no token'}); diff --git a/walter_nicholas/package.json b/walter_nicholas/package.json index 8842af4..894f7ac 100644 --- a/walter_nicholas/package.json +++ b/walter_nicholas/package.json @@ -23,12 +23,15 @@ "eat": "^0.1.1", "express": "^4.13.3", "gulp": "^3.9.0", + "gulp-minify-css": "^1.2.2", + "gulp-sass": "^2.1.0", + "gulp-sourcemaps": "^1.6.0", "jasmine-core": "^2.3.4", "karma": "^0.13.15", "karma-jasmine": "^0.3.6", "karma-phantomjs-launcher": "^0.2.1", "mocha": "^2.3.3", "phantomjs": "^1.9.19", - "webpack-stream": "^2.2.0" + "webpack-stream": "^2.3.0" } } diff --git a/walter_nicholas/routes/task_routes.js b/walter_nicholas/routes/task_routes.js index f75a946..b6ee87b 100644 --- a/walter_nicholas/routes/task_routes.js +++ b/walter_nicholas/routes/task_routes.js @@ -56,15 +56,17 @@ taskRouter.put('/tasks/:id', bodyParser, function (req, res) { }); }); -taskRouter.delete('/tasks/:id', function (req, res) { +//had to use post instead of delete because angular's $http delete cannot send an object with the request, +//and we need to send an object with token to authenticate +taskRouter.post('/tasks/delete/:id', bodyParser, eatAuth, function (req, res) { Task.remove({_id: req.params.id}, function (err) { if (err) return handleError(err, res); - res.json({msg: 'Task deleted.'}); + res.json({msg: 'eat auth success!'}); }); }); -// taskRouter.delete('/tasks/:id', bodyParser, eatAuth, function (req, res) { +// taskRouter.delete('/tasks/delete/:id', bodyParser, eatAuth, function (req, res) { // Task.remove({_id: req.params.id}, function (err) { // if (err) return handleError(err, res);