├── config.js ├── public └── app │ ├── directives │ └── reverse.js │ ├── app.js │ ├── services │ ├── userService.js │ ├── storyService.js │ └── authService.js │ ├── views │ ├── pages │ │ ├── allStories.html │ │ ├── login.html │ │ ├── signup.html │ │ └── home.html │ └── index.html │ ├── controllers │ ├── userCtrl.js │ ├── storyCtrl.js │ └── mainCtrl.js │ └── app.routes.js ├── app ├── models │ ├── story.js │ └── user.js └── routes │ └── api.js ├── package.json └── server.js /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | "database": "mongodb://root:abc123@ds045031.mongolab.com:45031/userstory", 4 | "port": process.env.PORT || 3000, 5 | "secretKey": "YourSecretKey" 6 | 7 | } -------------------------------------------------------------------------------- /public/app/directives/reverse.js: -------------------------------------------------------------------------------- 1 | angular.module('reverseDirective', []) 2 | 3 | .filter('reverse', function() { 4 | 5 | return function(items) { 6 | return items.slice().reverse(); 7 | } 8 | 9 | }); -------------------------------------------------------------------------------- /public/app/app.js: -------------------------------------------------------------------------------- 1 | angular.module('MyApp', ['appRoutes', 'mainCtrl', 'authService', 'userCtrl', 'userService', 'storyService', 'storyCtrl', 'reverseDirective']) 2 | 3 | .config(function($httpProvider) { 4 | 5 | $httpProvider.interceptors.push('AuthInterceptor'); 6 | 7 | 8 | }) -------------------------------------------------------------------------------- /app/models/story.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | 3 | var Schema = mongoose.Schema; 4 | 5 | 6 | var StorySchema = new Schema({ 7 | 8 | creator: { type: Schema.Types.ObjectId, ref: 'User' }, 9 | content: String, 10 | created: { type: Date, defauly: Date.now} 11 | 12 | }); 13 | 14 | module.exports = mongoose.model('Story', StorySchema); -------------------------------------------------------------------------------- /public/app/services/userService.js: -------------------------------------------------------------------------------- 1 | angular.module('userService', []) 2 | 3 | 4 | .factory('User', function($http) { 5 | 6 | var userFactory = {}; 7 | 8 | userFactory.create = function(userData) { 9 | return $http.post('/api/signup', userData); 10 | } 11 | 12 | userFactory.all = function() { 13 | return $http.get('/api/users'); 14 | } 15 | 16 | 17 | 18 | return userFactory; 19 | 20 | }); -------------------------------------------------------------------------------- /public/app/views/pages/allStories.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 |
8 | 9 |
10 |
11 | 12 | 13 |
14 |
Your Stories
15 |
16 |

{{ each.content }}

17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 | 26 | 27 |
28 | 29 | 30 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "userStory", 3 | "version": "0.0.0", 4 | "description": "This is a user Story app", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Johnny", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bcrypt-nodejs": "0.0.3", 13 | "body-parser": "^1.12.0", 14 | "express": "^4.11.2", 15 | "jsonwebtoken": "^3.2.2", 16 | "mongoose": "^3.8.23", 17 | "morgan": "^1.5.1", 18 | "socket.io": "^1.3.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/app/views/pages/login.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |

Login

6 | 7 |
8 | Username: 9 | 10 | Password: 11 | 12 | 13 |
14 |
15 | 16 |
17 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /public/app/controllers/userCtrl.js: -------------------------------------------------------------------------------- 1 | angular.module('userCtrl', ['userService']) 2 | 3 | 4 | .controller('UserController', function(User) { 5 | 6 | 7 | var vm = this; 8 | 9 | 10 | User.all() 11 | .success(function(data) { 12 | vm.users = data; 13 | }) 14 | 15 | 16 | }) 17 | 18 | 19 | .controller('UserCreateController', function(User, $location, $window) { 20 | 21 | var vm = this; 22 | 23 | vm.signupUser = function() { 24 | vm.message = ''; 25 | 26 | User.create(vm.userData) 27 | .then(function(response) { 28 | vm.userData = {}; 29 | vm.message = response.data.message; 30 | 31 | $window.localStorage.setItem('token', response.data.token); 32 | $location.path('/'); 33 | }) 34 | } 35 | 36 | }) -------------------------------------------------------------------------------- /public/app/views/pages/signup.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Signup!

5 |
6 | Name: 7 | Username: 8 | Password: 9 | 10 |
11 |
12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /public/app/app.routes.js: -------------------------------------------------------------------------------- 1 | angular.module('appRoutes', ['ngRoute']) 2 | 3 | 4 | .config(function($routeProvider, $locationProvider) { 5 | 6 | $routeProvider 7 | 8 | .when('/', { 9 | templateUrl: 'app/views/pages/home.html', 10 | controller: 'MainController', 11 | controllerAs: 'main' 12 | }) 13 | .when('/login', { 14 | templateUrl: 'app/views/pages/login.html' 15 | }) 16 | .when('/signup', { 17 | templateUrl: 'app/views/pages/signup.html' 18 | }) 19 | 20 | .when('/allStories', { 21 | templateUrl: 'app/views/pages/allStories.html', 22 | controller: 'AllStoriesController', 23 | controllerAs: 'story', 24 | resolve: { 25 | stories: function(Story) { 26 | return Story.allStories(); 27 | } 28 | } 29 | 30 | }) 31 | 32 | $locationProvider.html5Mode(true); 33 | 34 | }) -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | 3 | var Schema = mongoose.Schema; 4 | var bcrypt = require('bcrypt-nodejs'); 5 | 6 | var UserSchema = new Schema({ 7 | 8 | name: String, 9 | username: { type: String, required: true, index: { unique: true }}, 10 | password: { type: String, required: true, select: false} 11 | 12 | }); 13 | 14 | UserSchema.pre('save', function(next) { 15 | 16 | var user = this; 17 | 18 | if(!user.isModified('password')) return next(); 19 | 20 | bcrypt.hash(user.password, null, null, function(err, hash) { 21 | if(err) return next(err); 22 | 23 | user.password = hash; 24 | next(); 25 | 26 | }); 27 | }); 28 | 29 | UserSchema.methods.comparePassword = function(password) { 30 | 31 | var user = this; 32 | 33 | return bcrypt.compareSync(password, user.password); 34 | } 35 | 36 | module.exports = mongoose.model('User', UserSchema); -------------------------------------------------------------------------------- /public/app/controllers/storyCtrl.js: -------------------------------------------------------------------------------- 1 | angular.module('storyCtrl', ['storyService']) 2 | 3 | 4 | .controller('StoryController', function(Story, socketio) { 5 | 6 | 7 | var vm = this; 8 | 9 | Story.all() 10 | .success(function(data) { 11 | vm.stories = data; 12 | }); 13 | 14 | 15 | vm.createStory = function() { 16 | 17 | vm.processing = true; 18 | 19 | 20 | vm.message = ''; 21 | Story.create(vm.storyData) 22 | .success(function(data) { 23 | vm.processing = false; 24 | //clear up the form 25 | vm.storyData = {}; 26 | 27 | vm.message = data.message; 28 | 29 | 30 | }); 31 | 32 | }; 33 | 34 | socketio.on('story', function(data) { 35 | vm.stories.push(data); 36 | }) 37 | 38 | }) 39 | 40 | .controller('AllStoriesController', function(stories, socketio) { 41 | 42 | var vm = this; 43 | 44 | vm.stories = stories.data; 45 | 46 | socketio.on('story', function(data) { 47 | vm.stories.push(data); 48 | }); 49 | 50 | 51 | 52 | }); -------------------------------------------------------------------------------- /public/app/controllers/mainCtrl.js: -------------------------------------------------------------------------------- 1 | angular.module('mainCtrl', []) 2 | 3 | 4 | .controller('MainController', function($rootScope, $location, Auth) { 5 | 6 | var vm = this; 7 | 8 | 9 | vm.loggedIn = Auth.isLoggedIn(); 10 | 11 | $rootScope.$on('$routeChangeStart', function() { 12 | 13 | vm.loggedIn = Auth.isLoggedIn(); 14 | 15 | Auth.getUser() 16 | .then(function(data) { 17 | vm.user = data.data; 18 | }); 19 | }); 20 | 21 | 22 | vm.doLogin = function() { 23 | 24 | vm.processing = true; 25 | 26 | vm.error = ''; 27 | 28 | Auth.login(vm.loginData.username, vm.loginData.password) 29 | .success(function(data) { 30 | vm.processing = false; 31 | 32 | Auth.getUser() 33 | .then(function(data) { 34 | vm.user = data.data; 35 | }); 36 | 37 | if(data.success) 38 | $location.path('/'); 39 | else 40 | vm.error = data.message; 41 | 42 | }); 43 | } 44 | 45 | 46 | vm.doLogout = function() { 47 | Auth.logout(); 48 | $location.path('/logout'); 49 | } 50 | 51 | 52 | }); -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var morgan = require('morgan'); 4 | var config = require('./config'); 5 | var mongoose = require('mongoose'); 6 | var app = express(); 7 | 8 | var http = require('http').Server(app); 9 | var io = require('socket.io')(http); 10 | 11 | 12 | mongoose.connect(config.database, function(err) { 13 | if(err) { 14 | console.log(err); 15 | } else { 16 | console.log('Connected to the database'); 17 | } 18 | }); 19 | 20 | app.use(bodyParser.urlencoded({ extended: true })); 21 | app.use(bodyParser.json()); 22 | 23 | 24 | 25 | app.use(morgan('dev')); 26 | 27 | app.use(express.static(__dirname + '/public')); 28 | 29 | var api = require('./app/routes/api')(app, express, io); 30 | app.use('/api', api); 31 | 32 | 33 | app.get('*', function(req, res) { 34 | res.sendFile(__dirname + '/public/app/views/index.html'); 35 | }); 36 | 37 | http.listen(config.port, function(err) { 38 | if(err) { 39 | console.log(err); 40 | } else { 41 | console.log("Listening on port 3000"); 42 | } 43 | }); -------------------------------------------------------------------------------- /public/app/services/storyService.js: -------------------------------------------------------------------------------- 1 | angular.module('storyService', []) 2 | 3 | 4 | .factory('Story', function($http) { 5 | 6 | 7 | var storyFactory = {}; 8 | 9 | storyFactory.allStories = function() { 10 | return $http.get('/api/all_stories'); 11 | } 12 | 13 | storyFactory.all = function() { 14 | return $http.get('/api/'); 15 | } 16 | 17 | storyFactory.create = function(storyData) { 18 | return $http.post('/api/', storyData); 19 | } 20 | 21 | 22 | 23 | 24 | return storyFactory; 25 | 26 | 27 | }) 28 | 29 | .factory('socketio', function($rootScope) { 30 | 31 | var socket = io.connect(); 32 | return { 33 | 34 | on: function(eventName, callback) { 35 | socket.on(eventName, function() { 36 | var args = arguments; 37 | $rootScope.$apply(function() { 38 | callback.apply(socket, args); 39 | }); 40 | }); 41 | }, 42 | 43 | emit: function(eventName, data, callback) { 44 | socket.emit(eventName, data, function() { 45 | var args = arguments; 46 | $rootScope.apply(function() { 47 | if(callback) { 48 | callback.apply(socket, args); 49 | } 50 | }); 51 | }); 52 | } 53 | 54 | }; 55 | 56 | }); -------------------------------------------------------------------------------- /public/app/views/pages/home.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |

If you have balls Sign up!

6 |
7 | 8 |
9 |

Login to write your story

10 | Login 11 |
12 |
13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 |
25 |
26 |
Write your Story
27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 | 36 |
37 |
Your Stories
38 |
39 |

{{ each.content }}

40 |
41 |
42 | 43 |
44 |
45 | 46 | 47 |
48 | 49 | 50 |
51 | 52 | 53 |
-------------------------------------------------------------------------------- /public/app/services/authService.js: -------------------------------------------------------------------------------- 1 | angular.module('authService', []) 2 | 3 | 4 | 5 | .factory('Auth', function($http, $q, AuthToken) { 6 | 7 | 8 | var authFactory = {}; 9 | 10 | 11 | authFactory.login = function(username, password) { 12 | 13 | return $http.post('/api/login', { 14 | username: username, 15 | password: password 16 | }) 17 | .success(function(data) { 18 | AuthToken.setToken(data.token); 19 | return data; 20 | }) 21 | } 22 | 23 | authFactory.logout = function() { 24 | AuthToken.setToken(); 25 | } 26 | 27 | authFactory.isLoggedIn = function() { 28 | if(AuthToken.getToken()) 29 | return true; 30 | else 31 | return false; 32 | } 33 | 34 | authFactory.getUser = function() { 35 | if(AuthToken.getToken()) 36 | return $http.get('/api/me'); 37 | else 38 | return $q.reject({ message: "User has no token"}); 39 | 40 | } 41 | 42 | 43 | return authFactory; 44 | 45 | }) 46 | 47 | 48 | .factory('AuthToken', function($window) { 49 | 50 | var authTokenFactory = {}; 51 | 52 | authTokenFactory.getToken = function() { 53 | return $window.localStorage.getItem('token'); 54 | } 55 | 56 | authTokenFactory.setToken = function(token) { 57 | 58 | if(token) 59 | $window.localStorage.setItem('token', token); 60 | else 61 | $window.localStorage.removeItem('token'); 62 | 63 | } 64 | 65 | return authTokenFactory; 66 | 67 | }) 68 | 69 | 70 | .factory('AuthInterceptor', function($q, $location, AuthToken) { 71 | 72 | var interceptorFactory = {}; 73 | 74 | 75 | interceptorFactory.request = function(config) { 76 | 77 | var token = AuthToken.getToken(); 78 | 79 | if(token) { 80 | 81 | config.headers['x-access-token'] = token; 82 | 83 | } 84 | 85 | return config; 86 | 87 | }; 88 | 89 | 90 | 91 | 92 | return interceptorFactory; 93 | }); 94 | 95 | 96 | -------------------------------------------------------------------------------- /public/app/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | User Story 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 52 | 53 | 54 |
55 | 56 | 57 |
58 | 59 |
60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /app/routes/api.js: -------------------------------------------------------------------------------- 1 | var User = require('../models/user'); 2 | var Story = require('../models/story'); 3 | var config = require('../../config'); 4 | 5 | var secretKey = config.secretKey; 6 | 7 | var jsonwebtoken = require('jsonwebtoken'); 8 | 9 | function createToken(user) { 10 | 11 | var token = jsonwebtoken.sign({ 12 | id: user._id, 13 | name: user.name, 14 | username: user.username 15 | }, secretKey, { 16 | expirtesInMinute: 1440 17 | }); 18 | 19 | 20 | return token; 21 | 22 | } 23 | 24 | module.exports = function(app, express, io) { 25 | 26 | 27 | var api = express.Router(); 28 | 29 | api.get('/all_stories', function(req, res) { 30 | 31 | Story.find({}, function(err, stories) { 32 | if(err) { 33 | res.send(err); 34 | return; 35 | } 36 | res.json(stories); 37 | }); 38 | }); 39 | 40 | api.post('/signup', function(req, res) { 41 | 42 | var user = new User({ 43 | name: req.body.name, 44 | username: req.body.username, 45 | password: req.body.password 46 | }); 47 | var token = createToken(user); 48 | user.save(function(err) { 49 | if(err) { 50 | res.send(err); 51 | return; 52 | } 53 | 54 | res.json({ 55 | success: true, 56 | message: 'User has been created!', 57 | token: token 58 | }); 59 | }); 60 | }); 61 | 62 | 63 | api.get('/users', function(req, res) { 64 | 65 | User.find({}, function(err, users) { 66 | if(err) { 67 | res.send(err); 68 | return; 69 | } 70 | 71 | res.json(users); 72 | 73 | }); 74 | }); 75 | 76 | api.post('/login', function(req, res) { 77 | 78 | User.findOne({ 79 | username: req.body.username 80 | }).select('name username password').exec(function(err, user) { 81 | 82 | if(err) throw err; 83 | 84 | if(!user) { 85 | 86 | res.send({ message: "User doenst exist"}); 87 | } else if(user){ 88 | 89 | var validPassword = user.comparePassword(req.body.password); 90 | 91 | if(!validPassword) { 92 | res.send({ message: "Invalid Password"}); 93 | } else { 94 | 95 | ///// token 96 | var token = createToken(user); 97 | 98 | res.json({ 99 | success: true, 100 | message: "Successfuly login!", 101 | token: token 102 | }); 103 | } 104 | } 105 | }); 106 | }); 107 | 108 | api.use(function(req, res, next) { 109 | 110 | 111 | console.log("Somebody just came to our app!"); 112 | 113 | var token = req.body.token || req.param('token') || req.headers['x-access-token']; 114 | 115 | // check if token exist 116 | if(token) { 117 | 118 | jsonwebtoken.verify(token, secretKey, function(err, decoded) { 119 | 120 | if(err) { 121 | res.status(403).send({ success: false, message: "Failed to authenticate user"}); 122 | 123 | } else { 124 | 125 | // 126 | req.decoded = decoded; 127 | next(); 128 | } 129 | }); 130 | } else { 131 | res.status(403).send({ success: false, message: "No Token Provided"}); 132 | } 133 | 134 | }); 135 | 136 | 137 | 138 | // Destination B // provide a legitimate token 139 | 140 | api.route('/') 141 | 142 | .post(function(req, res) { 143 | 144 | var story = new Story({ 145 | creator: req.decoded.id, 146 | content: req.body.content, 147 | 148 | }); 149 | 150 | story.save(function(err, newStory) { 151 | if(err) { 152 | res.send(err); 153 | return 154 | } 155 | io.emit('story', newStory) 156 | res.json({message: "New Story Created!"}); 157 | }); 158 | }) 159 | 160 | 161 | .get(function(req, res) { 162 | 163 | Story.find({ creator: req.decoded.id }, function(err, stories) { 164 | 165 | if(err) { 166 | res.send(err); 167 | return; 168 | } 169 | 170 | res.send(stories); 171 | }); 172 | }); 173 | 174 | api.get('/me', function(req, res) { 175 | res.send(req.decoded); 176 | }); 177 | 178 | 179 | 180 | 181 | return api; 182 | 183 | 184 | } --------------------------------------------------------------------------------