├── .buildignore ├── .gitattributes ├── client ├── robots.txt ├── app │ ├── admin │ │ ├── admin.css │ │ ├── admin.js │ │ ├── admin.controller.js │ │ └── admin.html │ ├── home │ │ ├── home.js │ │ ├── home.controller.js │ │ ├── home.html │ │ └── home.css │ ├── invite │ │ ├── invite.js │ │ ├── invite.controller.js │ │ └── invite.html │ ├── main │ │ ├── main.js │ │ ├── main.controller.spec.js │ │ ├── main.scss │ │ ├── main.html │ │ ├── main.controller.js │ │ └── main.css │ ├── rssFeed │ │ ├── rssFeed.html │ │ └── rssFeed.controller.js │ ├── s3Upload │ │ ├── s3Upload.html │ │ └── s3Upload.controller.js │ ├── account │ │ ├── settings │ │ │ ├── settings.controller.js │ │ │ └── settings.html │ │ ├── forgotpassword │ │ │ ├── forgotpassword.controller.js │ │ │ └── forgotpassword.html │ │ ├── account.js │ │ ├── login │ │ │ ├── login.controller.js │ │ │ ├── login.css │ │ │ └── login.html │ │ └── signup │ │ │ ├── signup.controller.js │ │ │ └── signup.html │ ├── app.css │ └── app.js ├── snapSuccess.png ├── assets │ └── images │ │ ├── Thumbs.db │ │ ├── features.png │ │ ├── team-sid.png │ │ ├── Snapit-logoi.png │ │ ├── header-base.png │ │ ├── snapit-logo.png │ │ ├── team-vinaya.png │ │ ├── team-vincent.png │ │ ├── header-mobile.png │ │ ├── header-overlay.png │ │ ├── snap-anything.png │ │ ├── team-jennifer.png │ │ └── track-anything.png ├── chrome_extension │ ├── Thumbs.db │ ├── icon_128.png │ ├── icon_16.png │ ├── icon_48.png │ ├── manifest.json │ └── main.js ├── components │ ├── socket │ │ ├── socket.mock.js │ │ └── socket.service.js │ ├── mongoose-error │ │ └── mongoose-error.directive.js │ ├── auth │ │ ├── user.service.js │ │ ├── imageService.js │ │ └── auth.service.js │ ├── modal │ │ ├── modal.css │ │ ├── modal.html │ │ └── modal.service.js │ ├── navbar │ │ ├── navbar.controller.js │ │ ├── navbar.css │ │ └── navbar.html │ └── angulargrid │ │ └── angulargrid.js ├── .jshintrc ├── favicon.ico └── index.html ├── .bowerrc ├── screenshots ├── Thumbs.db ├── homepage.png ├── website.png └── Snapit-logo-blue.png ├── server ├── api │ ├── thing │ │ ├── snapSuccess.png │ │ ├── thing.model.js │ │ ├── index.js │ │ ├── thing.socket.js │ │ ├── thing.spec.js │ │ └── thing.controller.js │ └── user │ │ ├── index.js │ │ ├── user.model.spec.js │ │ ├── user.model.js │ │ └── user.controller.js ├── getConfig.js ├── .jshintrc-spec ├── config │ ├── environment │ │ ├── test.js │ │ ├── development.js │ │ ├── production.js │ │ ├── local.env.js │ │ └── index.js │ ├── seed.js │ ├── local.env.sample.js │ ├── socketio.js │ └── express.js ├── .jshintrc ├── components │ └── errors │ │ └── index.js ├── auth │ ├── twitter │ │ ├── index.js │ │ └── passport.js │ ├── facebook │ │ ├── index.js │ │ └── passport.js │ ├── index.js │ ├── local │ │ ├── index.js │ │ └── passport.js │ └── auth.service.js ├── invite.js ├── forgotpassword.js ├── app.js ├── routes.js └── views │ └── 404.html ├── .gitignore ├── .travis.yml ├── e2e └── main │ ├── main.po.js │ └── main.spec.js ├── .editorconfig ├── bower.json ├── .yo-rc.json ├── protractor.conf.js ├── README.md ├── karma.conf.js ├── PRESS-RELEASE.md ├── package.json ├── CONTRIBUTING.md └── Gruntfile.js /.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /client/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "client/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /client/app/admin/admin.css: -------------------------------------------------------------------------------- 1 | .trash { color:rgb(209, 91, 71); } 2 | -------------------------------------------------------------------------------- /client/snapSuccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/snapSuccess.png -------------------------------------------------------------------------------- /screenshots/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/screenshots/Thumbs.db -------------------------------------------------------------------------------- /screenshots/homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/screenshots/homepage.png -------------------------------------------------------------------------------- /screenshots/website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/screenshots/website.png -------------------------------------------------------------------------------- /client/assets/images/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/Thumbs.db -------------------------------------------------------------------------------- /screenshots/Snapit-logo-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/screenshots/Snapit-logo-blue.png -------------------------------------------------------------------------------- /server/api/thing/snapSuccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/server/api/thing/snapSuccess.png -------------------------------------------------------------------------------- /client/assets/images/features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/features.png -------------------------------------------------------------------------------- /client/assets/images/team-sid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/team-sid.png -------------------------------------------------------------------------------- /client/chrome_extension/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/chrome_extension/Thumbs.db -------------------------------------------------------------------------------- /client/assets/images/Snapit-logoi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/Snapit-logoi.png -------------------------------------------------------------------------------- /client/assets/images/header-base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/header-base.png -------------------------------------------------------------------------------- /client/assets/images/snapit-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/snapit-logo.png -------------------------------------------------------------------------------- /client/assets/images/team-vinaya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/team-vinaya.png -------------------------------------------------------------------------------- /client/assets/images/team-vincent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/team-vincent.png -------------------------------------------------------------------------------- /client/chrome_extension/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/chrome_extension/icon_128.png -------------------------------------------------------------------------------- /client/chrome_extension/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/chrome_extension/icon_16.png -------------------------------------------------------------------------------- /client/chrome_extension/icon_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/chrome_extension/icon_48.png -------------------------------------------------------------------------------- /client/assets/images/header-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/header-mobile.png -------------------------------------------------------------------------------- /client/assets/images/header-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/header-overlay.png -------------------------------------------------------------------------------- /client/assets/images/snap-anything.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/snap-anything.png -------------------------------------------------------------------------------- /client/assets/images/team-jennifer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/team-jennifer.png -------------------------------------------------------------------------------- /client/assets/images/track-anything.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ratracegrad/SnapIt/HEAD/client/assets/images/track-anything.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | .tmp 4 | .idea 5 | client/bower_components 6 | dist 7 | /server/config/local.env.js 8 | .floo 9 | .fooignore 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.11' 5 | before_script: 6 | - npm install -g bower grunt-cli 7 | - bower install 8 | services: mongodb -------------------------------------------------------------------------------- /server/getConfig.js: -------------------------------------------------------------------------------- 1 | var config = require('./config/environment'); 2 | 3 | module.exports = function (req, res) { 4 | var configKeys = config.keys; 5 | var json = JSON.stringify(configKeys); 6 | res.end(json); 7 | }; -------------------------------------------------------------------------------- /server/.jshintrc-spec: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ".jshintrc", 3 | "globals": { 4 | "describe": true, 5 | "it": true, 6 | "before": true, 7 | "beforeEach": true, 8 | "after": true, 9 | "afterEach": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /server/config/environment/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Test specific configuration 4 | // =========================== 5 | module.exports = { 6 | // MongoDB connection options 7 | mongo: { 8 | uri: 'mongodb://localhost/snapit-test' 9 | } 10 | }; -------------------------------------------------------------------------------- /client/app/home/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .config(['$stateProvider', function ($stateProvider) { 5 | $stateProvider 6 | .state('home', { 7 | url: '/', 8 | templateUrl: 'app/home/home.html', 9 | controller: 'HomeCtrl' 10 | }); 11 | }]); -------------------------------------------------------------------------------- /server/config/seed.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Populate DB with sample data on server start 3 | * to disable, edit config/environment/index.js, and set `seedDB: false` 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Thing = require('../api/thing/thing.model'); 9 | var User = require('../api/user/user.model'); 10 | 11 | -------------------------------------------------------------------------------- /client/app/admin/admin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .config(function ($stateProvider) { 5 | $stateProvider 6 | .state('admin', { 7 | url: '/admin', 8 | templateUrl: 'app/admin/admin.html', 9 | controller: 'AdminCtrl' 10 | }); 11 | }); -------------------------------------------------------------------------------- /client/app/home/home.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('HomeCtrl', ['$scope', 'Auth', '$location', function($scope, Auth, $location) { 5 | $scope.title = 'HomePage'; 6 | 7 | if (Auth.isLoggedIn()){ 8 | $location.path('/main'); 9 | } 10 | 11 | }]); -------------------------------------------------------------------------------- /client/app/invite/invite.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .config(function ($stateProvider) { 5 | $stateProvider 6 | .state('invite', { 7 | url: '/invite', 8 | templateUrl: 'app/invite/invite.html', 9 | controller: 'InviteCtrl' 10 | }); 11 | }); -------------------------------------------------------------------------------- /server/config/environment/development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Development specific configuration 4 | // ================================== 5 | module.exports = { 6 | // MongoDB connection options 7 | mongo: { 8 | uri: 'mongodb://localhost/snapit-dev' 9 | }, 10 | 11 | seedDB: true 12 | }; 13 | -------------------------------------------------------------------------------- /server/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "eqeqeq": true, 6 | "immed": true, 7 | "latedef": "nofunc", 8 | "newcap": true, 9 | "noarg": true, 10 | "regexp": true, 11 | "undef": true, 12 | "smarttabs": true, 13 | "asi": true, 14 | "debug": true 15 | } 16 | -------------------------------------------------------------------------------- /client/app/main/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .config(function ($stateProvider) { 5 | $stateProvider 6 | .state('main', { 7 | url: '/main', 8 | templateUrl: 'app/main/main.html', 9 | controller: 'MainCtrl', 10 | authenticate: true 11 | }); 12 | }); -------------------------------------------------------------------------------- /client/components/socket/socket.mock.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('socketMock', []) 4 | .factory('socket', function() { 5 | return { 6 | socket: { 7 | connect: function() {}, 8 | on: function() {}, 9 | emit: function() {}, 10 | receive: function() {} 11 | }, 12 | 13 | syncUpdates: function() {}, 14 | unsyncUpdates: function() {} 15 | }; 16 | }); -------------------------------------------------------------------------------- /server/api/thing/thing.model.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mongoose = require('mongoose'), 4 | Schema = mongoose.Schema; 5 | 6 | var ThingSchema = new Schema({ 7 | media: String, 8 | url: String, 9 | title: String, 10 | description: String, 11 | email: String, 12 | mediaType: String, 13 | createTime: Number, 14 | createDate: Date, 15 | upVotes: Number 16 | }); 17 | 18 | module.exports = mongoose.model('Thing', ThingSchema); -------------------------------------------------------------------------------- /e2e/main/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | this.heroEl = element(by.css('.hero-unit')); 10 | this.h1El = this.heroEl.element(by.css('h1')); 11 | this.imgEl = this.heroEl.element(by.css('img')); 12 | }; 13 | 14 | module.exports = new MainPage(); 15 | 16 | -------------------------------------------------------------------------------- /server/components/errors/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error responses 3 | */ 4 | 5 | 'use strict'; 6 | 7 | module.exports[404] = function pageNotFound(req, res) { 8 | var viewFilePath = '404'; 9 | var statusCode = 404; 10 | var result = { 11 | status: statusCode 12 | }; 13 | 14 | res.status(result.status); 15 | res.render(viewFilePath, function (err) { 16 | if (err) { return res.json(result, result.status); } 17 | 18 | res.render(viewFilePath); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /client/components/mongoose-error/mongoose-error.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Removes server error when user updates input 5 | */ 6 | angular.module('snapItApp') 7 | .directive('mongooseError', function () { 8 | return { 9 | restrict: 'A', 10 | require: 'ngModel', 11 | link: function(scope, element, attrs, ngModel) { 12 | element.on('keydown', function() { 13 | return ngModel.$setValidity('mongoose', true); 14 | }); 15 | } 16 | }; 17 | }); -------------------------------------------------------------------------------- /e2e/main/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Main View', function() { 4 | var page; 5 | 6 | beforeEach(function() { 7 | browser.get('/'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | it('should include jumbotron with correct data', function() { 12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); 13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); 14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /client/app/admin/admin.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('AdminCtrl', function ($scope, $http, Auth, User) { 5 | 6 | // Use the User $resource to fetch all users 7 | $scope.users = User.query(); 8 | 9 | $scope.delete = function(user) { 10 | User.remove({ id: user._id }); 11 | angular.forEach($scope.users, function(u, i) { 12 | if (u === user) { 13 | $scope.users.splice(i, 1); 14 | } 15 | }); 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /client/chrome_extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SnapIt", 3 | "version": "1.0", 4 | "manifest_version": 2, 5 | "description": "SnapIt on any web item", 6 | "browser_action": { 7 | "default_icon": "icon_48.png" 8 | }, 9 | "icons": { 10 | "128": "icon_128.png", 11 | "16": "icon_16.png", 12 | "48": "icon_48.png" 13 | }, 14 | "permissions": [ "cookies","","tabs", "contextMenus", "http://*/*", "https://*/*" ], 15 | "background": { "scripts": ["main.js"] } 16 | } 17 | -------------------------------------------------------------------------------- /client/components/auth/user.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .factory('User', function ($resource) { 5 | return $resource('/api/users/:id/:controller', { 6 | id: '@_id' 7 | }, 8 | { 9 | changePassword: { 10 | method: 'PUT', 11 | params: { 12 | controller:'password' 13 | } 14 | }, 15 | get: { 16 | method: 'GET', 17 | params: { 18 | id:'me' 19 | } 20 | } 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /client/app/rssFeed/rssFeed.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
Enter url to follow
5 | 6 | 7 |

{{ successMessage }}

8 |
9 |
-------------------------------------------------------------------------------- /server/auth/twitter/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router 10 | .get('/', passport.authenticate('twitter', { 11 | failureRedirect: '/signup', 12 | session: false 13 | })) 14 | 15 | .get('/callback', passport.authenticate('twitter', { 16 | failureRedirect: '/signup', 17 | session: false 18 | }), auth.setTokenCookie); 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /client/app/admin/admin.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

The delete user and user index api routes are restricted to users with the 'admin' role.

5 | 12 |
-------------------------------------------------------------------------------- /server/api/thing/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var controller = require('./thing.controller'); 5 | 6 | var router = express.Router(); 7 | 8 | router.get('/', controller.create); 9 | router.get('/getItems', controller.index); 10 | router.get('/:id', controller.show); 11 | router.post('/', controller.create); 12 | router.put('/:id', controller.update); 13 | router.patch('/:id', controller.update); 14 | router.post('/addFeeds', controller.createRss); 15 | router.delete('/:id', controller.destroy); 16 | 17 | module.exports = router; 18 | -------------------------------------------------------------------------------- /server/api/thing/thing.socket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Broadcast updates to client when the model changes 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var thing = require('./thing.model'); 8 | 9 | exports.register = function(socket) { 10 | thing.schema.post('save', function (doc) { 11 | onSave(socket, doc); 12 | }); 13 | thing.schema.post('remove', function (doc) { 14 | onRemove(socket, doc); 15 | }); 16 | } 17 | 18 | function onSave(socket, doc, cb) { 19 | socket.emit('thing:save', doc); 20 | } 21 | 22 | function onRemove(socket, doc, cb) { 23 | socket.emit('thing:remove', doc); 24 | } -------------------------------------------------------------------------------- /client/components/modal/modal.css: -------------------------------------------------------------------------------- 1 | .modal-primary .modal-header, 2 | .modal-info .modal-header, 3 | .modal-success .modal-header, 4 | .modal-warning .modal-header, 5 | .modal-danger .modal-header { 6 | color: #fff; 7 | border-radius: 5px 5px 0 0; 8 | } 9 | .modal-primary .modal-header { 10 | background: #428bca; 11 | } 12 | .modal-info .modal-header { 13 | background: #5bc0de; 14 | } 15 | .modal-success .modal-header { 16 | background: #5cb85c; 17 | } 18 | .modal-warning .modal-header { 19 | background: #f0ad4e; 20 | } 21 | .modal-danger .modal-header { 22 | background: #d9534f; 23 | } -------------------------------------------------------------------------------- /client/components/modal/modal.html: -------------------------------------------------------------------------------- 1 | 5 | 9 | -------------------------------------------------------------------------------- /server/api/thing/thing.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('should'); 4 | var app = require('../../app'); 5 | var request = require('supertest'); 6 | 7 | describe('GET /api/things', function() { 8 | 9 | // it('should respond with JSON array', function(done) { 10 | // request(app) 11 | // .get('/api/things') 12 | // .expect(200) 13 | // .expect('Content-Type', /json/) 14 | // .end(function(err, res) { 15 | // if (err) return done(err); 16 | // res.body.should.be.instanceof(Array); 17 | // done(); 18 | // }); 19 | // }); 20 | }); 21 | -------------------------------------------------------------------------------- /server/auth/facebook/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router 10 | .get('/', passport.authenticate('facebook', { 11 | scope: ['email', 'user_about_me'], 12 | failureRedirect: '/signup', 13 | session: false 14 | })) 15 | 16 | .get('/callback', passport.authenticate('facebook', { 17 | successRedirect: '/main', 18 | failureRedirect: '/signup', 19 | session: false 20 | }), auth.setTokenCookie); 21 | 22 | 23 | module.exports = router; -------------------------------------------------------------------------------- /server/auth/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var config = require('../config/environment'); 6 | var User = require('../api/user/user.model'); 7 | 8 | // Passport Configuration 9 | require('./local/passport').setup(User, config); 10 | require('./facebook/passport').setup(User, config); 11 | require('./twitter/passport').setup(User, config); 12 | 13 | var router = express.Router(); 14 | 15 | router.use('/local', require('./local')); 16 | router.use('/facebook', require('./facebook')); 17 | router.use('/twitter', require('./twitter')); 18 | 19 | module.exports = router; -------------------------------------------------------------------------------- /client/components/navbar/navbar.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('NavbarCtrl', function ($scope, $location, Auth) { 5 | $scope.menu = [{ 6 | 'title': 'Home', 7 | 'link': '/' 8 | }]; 9 | 10 | $scope.isCollapsed = true; 11 | $scope.isLoggedIn = Auth.isLoggedIn; 12 | $scope.isAdmin = Auth.isAdmin; 13 | $scope.getCurrentUser = Auth.getCurrentUser; 14 | 15 | $scope.logout = function() { 16 | Auth.logout(); 17 | $location.path('/login'); 18 | }; 19 | 20 | $scope.isActive = function(route) { 21 | return route === $location.path(); 22 | }; 23 | }); -------------------------------------------------------------------------------- /server/auth/local/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router.post('/', function(req, res, next) { 10 | passport.authenticate('local', function (err, user, info) { 11 | var error = err || info; 12 | if (error) return res.json(401, error); 13 | if (!user) return res.json(404, {message: 'Something went wrong, please try again.'}); 14 | 15 | var token = auth.signToken(user._id, user.role); 16 | res.json({token: token}); 17 | })(req, res, next) 18 | }); 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /server/config/local.env.sample.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Use local.env.js for environment variables that grunt will set when the server starts locally. 4 | // Use for your api keys, secrets, etc. This file should not be tracked by git. 5 | // 6 | // You will need to set these on the server you deploy to. 7 | 8 | module.exports = { 9 | DOMAIN: 'http://localhost:9000', 10 | SESSION_SECRET: 'snapit-secret', 11 | 12 | FACEBOOK_ID: 'app-id', 13 | FACEBOOK_SECRET: 'secret', 14 | 15 | TWITTER_ID: 'app-id', 16 | TWITTER_SECRET: 'secret', 17 | 18 | // Control debug level for modules using visionmedia/debug 19 | DEBUG: '' 20 | }; 21 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SnapIt", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": ">=1.2.*", 6 | "json3": "~3.3.1", 7 | "es5-shim": "~3.0.1", 8 | "jquery": "~1.11.0", 9 | "bootstrap": "~3.1.1", 10 | "angular-resource": ">=1.2.*", 11 | "angular-cookies": ">=1.2.*", 12 | "angular-sanitize": ">=1.2.*", 13 | "angular-bootstrap": "~0.11.0", 14 | "font-awesome": ">=4.1.0", 15 | "lodash": "~2.4.1", 16 | "aws-sdk":"~2.1.33", 17 | "toastr":"2.1.1", 18 | "angular-socket-io": "~0.6.0", 19 | "angular-ui-router": "~0.2.10" 20 | }, 21 | "devDependencies": { 22 | "angular-mocks": ">=1.2.*", 23 | "angular-scenario": ">=1.2.*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/config/environment/production.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Production specific configuration 4 | // ================================= 5 | module.exports = { 6 | // Server IP 7 | ip: process.env.OPENSHIFT_NODEJS_IP || 8 | process.env.IP || 9 | undefined, 10 | 11 | // Server port 12 | port: process.env.OPENSHIFT_NODEJS_PORT || 13 | process.env.PORT || 14 | 8080, 15 | 16 | // MongoDB connection options 17 | mongo: { 18 | uri: process.env.MONGOLAB_URI || 19 | process.env.MONGOHQ_URL || 20 | process.env.OPENSHIFT_MONGODB_DB_URL+process.env.OPENSHIFT_APP_NAME || 21 | 'mongodb://localhost/snapit' 22 | } 23 | }; -------------------------------------------------------------------------------- /client/app/s3Upload/s3Upload.html: -------------------------------------------------------------------------------- 1 | 2 |
Upload File
3 | 4 |
5 | 6 | 7 |
8 |
9 | {{ uploadProgress == 0 ? '' : uploadProgress + '%' }} 10 |
11 |
12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /client/app/account/settings/settings.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('SettingsCtrl', function ($scope, User, Auth) { 5 | $scope.errors = {}; 6 | 7 | $scope.changePassword = function(form) { 8 | $scope.submitted = true; 9 | if(form.$valid) { 10 | Auth.changePassword( $scope.user.oldPassword, $scope.user.newPassword ) 11 | .then( function() { 12 | $scope.message = 'Password successfully changed.'; 13 | }) 14 | .catch( function() { 15 | form.password.$setValidity('mongoose', false); 16 | $scope.errors.other = 'Incorrect password'; 17 | $scope.message = ''; 18 | }); 19 | } 20 | }; 21 | }); 22 | -------------------------------------------------------------------------------- /client/app/invite/invite.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('InviteCtrl', function ($scope, $http) { 5 | $scope.errors = {}; 6 | 7 | $scope.invite = function(form) { 8 | $scope.submitted = true; 9 | if(form.$valid) { 10 | $http.post('http://localhost:9000/invite/?inviteeEmail='+$scope.inviteeEmail+'&username=' + 'test') // need to replace test with user's name 11 | .then( function() { 12 | $scope.message = 'Invite Sent.'; 13 | }); 14 | // .catch( function() { 15 | // form.password.$setValidity('mongoose', false); 16 | // $scope.errors.other = 'Incorrect password'; 17 | // $scope.message = ''; 18 | // }); 19 | } 20 | }; 21 | }); -------------------------------------------------------------------------------- /server/api/user/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var controller = require('./user.controller'); 5 | var config = require('../../config/environment'); 6 | var auth = require('../../auth/auth.service'); 7 | 8 | var router = express.Router(); 9 | 10 | router.get('/', auth.hasRole('admin'), controller.index); 11 | router.delete('/:id', auth.hasRole('admin'), controller.destroy); 12 | router.get('/me', auth.isAuthenticated(), controller.me); 13 | router.put('/:id/password', auth.isAuthenticated(), controller.changePassword); 14 | router.get('/:id', auth.isAuthenticated(), controller.show); 15 | router.post('/me', controller.me); 16 | router.post('/', controller.create); 17 | router.post('/addUrl', controller.addUrl); 18 | 19 | module.exports = router; 20 | -------------------------------------------------------------------------------- /client/app/account/forgotpassword/forgotpassword.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('ForgotPasswordCtrl', function ($scope, $http) { 5 | $scope.errors = {}; 6 | 7 | $scope.reset = function(form) { 8 | $scope.submitted = true; 9 | if(form.$valid) { 10 | $http.post('http://localhost:9000/forgotpassword/?email=' + $scope.user.email) 11 | .then( function() { 12 | $scope.message = 'An email with your new password has been sent to your email address.'; 13 | }); 14 | // .catch( function() { 15 | // form.password.$setValidity('mongoose', false); 16 | // $scope.errors.other = 'Incorrect password'; 17 | // $scope.message = ''; 18 | // }); 19 | } 20 | }; 21 | }); -------------------------------------------------------------------------------- /client/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "jQuery": true, 23 | "angular": true, 24 | "console": true, 25 | "$": true, 26 | "_": true, 27 | "moment": true, 28 | "describe": true, 29 | "beforeEach": true, 30 | "module": true, 31 | "inject": true, 32 | "it": true, 33 | "expect": true, 34 | "browser": true, 35 | "element": true, 36 | "by": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /server/config/environment/local.env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Use local.env.js for environment variables that grunt will set when the server starts locally. 4 | // Use for your api keys, secrets, etc. This file should not be tracked by git. 5 | // 6 | // You will need to set these on the server you deploy to. 7 | 8 | module.exports = { 9 | DOMAIN: 'http://localhost:9000', 10 | SESSION_SECRET: 'snapit-secret', 11 | 12 | FACEBOOK_ID: 'app-id', 13 | FACEBOOK_SECRET: 'secret', 14 | 15 | TWITTER_ID: 'app-id', 16 | TWITTER_SECRET: 'secret', 17 | 18 | keys:{ 19 | access: 'AKIAINZITVNGQBZ7GPHA', 20 | secret: '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', 21 | bucket: 'vini-snapit', 22 | region: 'us-west-2' 23 | }, 24 | // Control debug level for modules using visionmedia/debug 25 | DEBUG: '' 26 | }; 27 | -------------------------------------------------------------------------------- /server/auth/local/passport.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var LocalStrategy = require('passport-local').Strategy; 3 | 4 | exports.setup = function (User, config) { 5 | passport.use(new LocalStrategy({ 6 | usernameField: 'email', 7 | passwordField: 'password' // this is the virtual field on the model 8 | }, 9 | function(email, password, done) { 10 | User.findOne({ 11 | email: email.toLowerCase() 12 | }, function(err, user) { 13 | if (err) return done(err); 14 | 15 | if (!user) { 16 | return done(null, false, { message: 'This email is not registered.' }); 17 | } 18 | if (!user.authenticate(password)) { 19 | return done(null, false, { message: 'This password is not correct.' }); 20 | } 21 | return done(null, user); 22 | }); 23 | } 24 | )); 25 | }; -------------------------------------------------------------------------------- /client/app/account/account.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .config(function ($stateProvider) { 5 | $stateProvider 6 | .state('login', { 7 | url: '/login', 8 | templateUrl: 'app/account/login/login.html', 9 | controller: 'LoginCtrl' 10 | }) 11 | .state('signup', { 12 | url: '/signup', 13 | templateUrl: 'app/account/signup/signup.html', 14 | controller: 'SignupCtrl' 15 | }) 16 | .state('settings', { 17 | url: '/settings', 18 | templateUrl: 'app/account/settings/settings.html', 19 | controller: 'SettingsCtrl', 20 | authenticate: true 21 | }) 22 | .state('forgotpassword', { 23 | url: '/forgotpassword', 24 | templateUrl: 'app/account/forgotpassword/forgotpassword.html', 25 | controller: 'ForgotPasswordCtrl' 26 | }); 27 | }); -------------------------------------------------------------------------------- /client/app/invite/invite.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |

Invite a friend

7 |
8 |
9 |
10 | 11 |
12 | 13 | 14 | 16 |

17 | {{ errors.other }} 18 |

19 |
20 | 21 |

{{ message }}

22 | 23 | 24 |
25 |
26 |
27 |
-------------------------------------------------------------------------------- /client/components/auth/imageService.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .factory('getPics', function imageService($location, $rootScope, $http) { 5 | // .factory('getPics', function imageService($location, $rootScope, $http, User, $cookieStore, $q) { 6 | // var currentUser = {}; 7 | //.service('imageService',['$q','$http',function($q,$http){ 8 | var pics = []; 9 | var url = 'https://api.flickr.com/services/feeds/photos_public.gne?format=json&jsoncallback=JSON_CALLBACK'; 10 | $http.jsonp(url).success( 11 | function (data) { 12 | data.items.forEach(function (obj) { 13 | var desc = obj.description, 14 | width = desc.match(/width="(.*?)"/)[1], 15 | height = desc.match(/height="(.*?)"/)[1]; 16 | 17 | obj.actualHeight = height; 18 | obj.actualWidth = width; 19 | }); 20 | pics = data.items; 21 | }); 22 | 23 | return { pics:pics}; 24 | 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /client/app/account/forgotpassword/forgotpassword.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

Reset Password

5 | 6 |
7 | 8 |
9 | 10 | 11 | 13 |

14 | {{ errors.other }} 15 |

16 |
17 | 18 |

{{ message }}

19 | 20 | 21 |
22 | 23 |
-------------------------------------------------------------------------------- /server/invite.js: -------------------------------------------------------------------------------- 1 | var nodemailer = require('nodemailer'); 2 | 3 | var transporter = nodemailer.createTransport({ 4 | service: 'Gmail', 5 | auth: { 6 | user: 'swordanchorthesis@gmail.com', 7 | pass: 'hackreactor1' 8 | } 9 | }); 10 | 11 | 12 | exports.invite = function(req, res) { 13 | // setup e-mail 14 | var mailOptions = { 15 | from: 'SnapIt Team ', // sender address 16 | to: req.query.inviteeEmail, 17 | subject: req.query.username + ' wants you to join them on SnapIt!', // Subject line 18 | html: 'Get started now with SnapIt; we make the internet better' // html body 19 | }; 20 | 21 | transporter.sendMail(mailOptions, function(error, info){ 22 | if(error){ 23 | console.log(error); 24 | }else{ 25 | console.log('Message sent: ' + info.response); 26 | } 27 | }); 28 | 29 | res.end(); 30 | }; -------------------------------------------------------------------------------- /client/components/navbar/navbar.css: -------------------------------------------------------------------------------- 1 | .navbar-custom-internal { 2 | background-color: #083858; 3 | left: 0; 4 | //position: absolute; 5 | top: 0; 6 | //width: 100%; 7 | z-index: 1; 8 | } 9 | .navbar-custom-internal a { 10 | color: #fff; 11 | } 12 | .navbar-custom-internal .navbar-logo { 13 | width: 140px; 14 | } 15 | .navbar-brandi { 16 | float: left; 17 | padding: 0 15px; 18 | font-size: 18px; 19 | line-height: 20px; 20 | height: 50px; 21 | } 22 | 23 | .navbar-custom-internal .navbar-nav>li>a, 24 | .navbar-custom-internal .navbar-nav>li>p { 25 | color: white; 26 | -webkit-transition: color 0.5s; 27 | transition: color 0.5s; 28 | line-height: 20px; 29 | } 30 | .navbar-custom-internal .navbar-nav>li>a:hover { 31 | -webkit-border-radius: 4px; 32 | -moz-border-radius: 4px; 33 | -ms-border-radius: 4px; 34 | text-decoration: none; 35 | background-color: transparent; 36 | color: white; 37 | line-height: 20px; 38 | border: 1px solid white; 39 | } -------------------------------------------------------------------------------- /client/app/main/main.controller.spec.js: -------------------------------------------------------------------------------- 1 | // 'use strict'; 2 | 3 | // describe('Controller: MainCtrl', function () { 4 | 5 | // // load the controller's module 6 | // // beforeEach(module('snapItApp')); 7 | // // beforeEach(module('socketMock')); 8 | 9 | // // var MainCtrl, 10 | // // scope, 11 | // // $httpBackend; 12 | 13 | // // // Initialize the controller and a mock scope 14 | // // beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { 15 | // // $httpBackend = _$httpBackend_; 16 | // // $httpBackend.expectGET('/api/things') 17 | // // .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']); 18 | 19 | // // scope = $rootScope.$new(); 20 | // // MainCtrl = $controller('MainCtrl', { 21 | // // $scope: scope 22 | // // }); 23 | // // })); 24 | 25 | // // it('should attach a list of things to the scope', function () { 26 | // // $httpBackend.flush(); 27 | // // expect(scope.awesomeThings.length).toBe(4); 28 | // // }); 29 | // // }); 30 | -------------------------------------------------------------------------------- /server/forgotpassword.js: -------------------------------------------------------------------------------- 1 | var nodemailer = require('nodemailer'); 2 | var user = require('./api/user/user.controller.js') 3 | 4 | var transporter = nodemailer.createTransport({ 5 | service: 'Gmail', 6 | auth: { 7 | user: 'swordanchorthesis@gmail.com', 8 | pass: 'hackreactor1' 9 | } 10 | }); 11 | 12 | 13 | exports.reset = function(req, res) { 14 | // setup e-mail 15 | var newPass = user.resetPassword(req.query.email); 16 | 17 | var mailOptions = { 18 | from: 'SnapIt Team ', // sender address 19 | to: req.query.email, 20 | subject: 'New SnapIt password.', // Subject line 21 | html: 'Your new password is ' + newPass + '. Login here.' // html body 22 | }; 23 | 24 | transporter.sendMail(mailOptions, function(error, info){ 25 | if(error){ 26 | console.log(error); 27 | }else{ 28 | console.log('Message sent: ' + info.response); 29 | } 30 | }); 31 | 32 | res.end(); 33 | }; -------------------------------------------------------------------------------- /server/auth/twitter/passport.js: -------------------------------------------------------------------------------- 1 | exports.setup = function (User, config) { 2 | var passport = require('passport'); 3 | var TwitterStrategy = require('passport-twitter').Strategy; 4 | 5 | passport.use(new TwitterStrategy({ 6 | consumerKey: config.twitter.clientID, 7 | consumerSecret: config.twitter.clientSecret, 8 | callbackURL: config.twitter.callbackURL 9 | }, 10 | function(token, tokenSecret, profile, done) { 11 | User.findOne({ 12 | 'twitter.id_str': profile.id 13 | }, function(err, user) { 14 | if (err) { 15 | return done(err); 16 | } 17 | if (!user) { 18 | user = new User({ 19 | name: profile.displayName, 20 | username: profile.username, 21 | role: 'user', 22 | provider: 'twitter', 23 | twitter: profile._json 24 | }); 25 | user.save(function(err) { 26 | if (err) return done(err); 27 | return done(err, user); 28 | }); 29 | } else { 30 | return done(err, user); 31 | } 32 | }); 33 | } 34 | )); 35 | }; -------------------------------------------------------------------------------- /client/app/account/login/login.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('LoginCtrl', function ($scope, Auth, $location, $window) { 5 | if (Auth.isLoggedIn()){ 6 | $location.path('/main'); 7 | } 8 | 9 | $scope.user = {}; 10 | $scope.errors = {}; 11 | 12 | $scope.login = function(form) { 13 | $scope.submitted = true; 14 | 15 | if(form.$valid) { 16 | Auth.login({ 17 | email: $scope.user.email, 18 | password: $scope.user.password 19 | }) 20 | .then( function() { 21 | // Logged in, redirect to home 22 | $location.path('/main'); 23 | }) 24 | .catch( function(err) { 25 | $scope.errors.other = err.message; 26 | }); 27 | } 28 | }; 29 | 30 | 31 | // $scope.isActive = function(route) { 32 | // return route === $location.path(); 33 | // // $location.path('/forgotpassword'); 34 | // }; 35 | 36 | $scope.loginOauth = function(provider) { 37 | $window.location.href = '/auth/' + provider; 38 | }; 39 | }); 40 | -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main application file 3 | */ 4 | 5 | 'use strict'; 6 | 7 | // Set default node environment to development 8 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'; 9 | 10 | var express = require('express'); 11 | var mongoose = require('mongoose'); 12 | var config = require('./config/environment'); 13 | 14 | // Connect to database 15 | mongoose.connect(config.mongo.uri, config.mongo.options); 16 | 17 | // Populate DB with sample data 18 | if(config.seedDB) { require('./config/seed'); } 19 | 20 | // Setup server 21 | var app = express(); 22 | var server = require('http').createServer(app); 23 | var socketio = require('socket.io')(server, { 24 | serveClient: (config.env === 'production') ? false : true, 25 | path: '/socket.io-client' 26 | }); 27 | require('./config/socketio')(socketio); 28 | require('./config/express')(app); 29 | require('./routes')(app); 30 | 31 | // Start server 32 | server.listen(config.port, config.ip, function () { 33 | console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); 34 | }); 35 | 36 | // Expose app 37 | exports = module.exports = app; -------------------------------------------------------------------------------- /server/auth/facebook/passport.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var FacebookStrategy = require('passport-facebook').Strategy; 3 | 4 | exports.setup = function (User, config) { 5 | passport.use(new FacebookStrategy({ 6 | clientID: config.facebook.clientID, 7 | clientSecret: config.facebook.clientSecret, 8 | callbackURL: config.facebook.callbackURL 9 | }, 10 | function(accessToken, refreshToken, profile, done) { 11 | User.findOne({ 12 | 'facebook.id': profile.id 13 | }, 14 | function(err, user) { 15 | if (err) { 16 | return done(err); 17 | } 18 | if (!user) { 19 | user = new User({ 20 | name: profile.displayName, 21 | email: profile.emails[0].value, 22 | role: 'user', 23 | username: profile.username, 24 | provider: 'facebook', 25 | facebook: profile._json 26 | }); 27 | user.save(function(err) { 28 | if (err) done(err); 29 | return done(err, user); 30 | }); 31 | } else { 32 | return done(err, user); 33 | } 34 | }) 35 | } 36 | )); 37 | }; -------------------------------------------------------------------------------- /client/app/account/signup/signup.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('snapItApp') 4 | .controller('SignupCtrl', function ($scope, Auth, $location, $window) { 5 | $scope.user = {}; 6 | $scope.errors = {}; 7 | 8 | if (Auth.isLoggedIn()){ 9 | $location.path('/main'); 10 | } 11 | 12 | $scope.register = function(form) { 13 | $scope.submitted = true; 14 | 15 | if(form.$valid) { 16 | Auth.createUser({ 17 | name: $scope.user.name, 18 | email: $scope.user.email, 19 | password: $scope.user.password 20 | }) 21 | .then( function() { 22 | // Account created, redirect to home 23 | $location.path('/main'); 24 | }) 25 | .catch( function(err) { 26 | err = err.data; 27 | $scope.errors = {}; 28 | 29 | // Update validity of form fields that match the mongoose errors 30 | angular.forEach(err.errors, function(error, field) { 31 | form[field].$setValidity('mongoose', false); 32 | $scope.errors[field] = error.message; 33 | }); 34 | }); 35 | } 36 | }; 37 | 38 | $scope.loginOauth = function(provider) { 39 | $window.location.href = '/auth/' + provider; 40 | }; 41 | }); 42 | -------------------------------------------------------------------------------- /server/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main application routes 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var errors = require('./components/errors'); 8 | var auth = require('./auth/auth.service'); 9 | 10 | module.exports = function(app) { 11 | 12 | // Insert routes below 13 | app.use('/api/things', require('./api/thing')); 14 | app.use('/api/users', require('./api/user')); 15 | 16 | app.use('/auth', require('./auth')); 17 | 18 | app.post('/forgotpassword', require('./forgotpassword').reset); 19 | app.post('/invite', require('./invite').invite); 20 | 21 | app.use('/successfullsnap', function(req, res){ 22 | res.sendfile(__dirname + '/api/thing/snapSuccess.png'); 23 | res.end(); 24 | }) 25 | 26 | app.use('/main', function(req, res, next){ 27 | if (auth.isAuthenticated() !== true){ 28 | res.redirect('/login') 29 | } 30 | else { 31 | next(); 32 | } 33 | }); 34 | 35 | app.use('/getAwsKeys', require("./getConfig.js")); 36 | 37 | // All undefined asset or api routes should return a 404 38 | app.route('/:url(api|auth|components|app|bower_components|assets)/*') 39 | .get(errors[404]); 40 | 41 | // All other routes should redirect to the index.html 42 | app.route('/*') 43 | .get(function(req, res) { 44 | res.sendfile(app.get('appPath') + '/index.html'); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-angular-fullstack": { 3 | "insertRoutes": true, 4 | "registerRoutesFile": "server/routes.js", 5 | "routesNeedle": "// Insert routes below", 6 | "routesBase": "/api/", 7 | "pluralizeRoutes": true, 8 | "insertSockets": true, 9 | "registerSocketsFile": "server/config/socketio.js", 10 | "socketsNeedle": "// Insert sockets below", 11 | "filters": { 12 | "js": true, 13 | "html": true, 14 | "css": true, 15 | "uirouter": true, 16 | "bootstrap": true, 17 | "uibootstrap": true, 18 | "socketio": true, 19 | "mongoose": true, 20 | "auth": true, 21 | "oauth": true, 22 | "facebookAuth": true, 23 | "twitterAuth": true 24 | } 25 | }, 26 | "generator-ng-component": { 27 | "routeDirectory": "client/app/", 28 | "directiveDirectory": "client/app/", 29 | "filterDirectory": "client/app/", 30 | "serviceDirectory": "client/app/", 31 | "basePath": "client", 32 | "moduleName": "", 33 | "filters": [ 34 | "uirouter" 35 | ], 36 | "extensions": [ 37 | "js", 38 | "html", 39 | "css" 40 | ], 41 | "directiveSimpleTemplates": "", 42 | "directiveComplexTemplates": "", 43 | "filterTemplates": "", 44 | "serviceTemplates": "", 45 | "factoryTemplates": "", 46 | "controllerTemplates": "", 47 | "decoratorTemplates": "", 48 | "providerTemplates": "", 49 | "routeTemplates": "" 50 | } 51 | } -------------------------------------------------------------------------------- /client/app/account/settings/settings.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |

Change Password

7 |
8 |
9 |
10 | 11 |
12 | 13 | 14 | 16 |

17 | {{ errors.other }} 18 |

19 |
20 | 21 |
22 | 23 | 24 | 27 |

29 | Password must be at least 3 characters. 30 |

31 |
32 | 33 |

{{ message }}

34 | 35 | 36 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /client/app/account/login/login.css: -------------------------------------------------------------------------------- 1 | .btn-facebook { 2 | color: #fff; 3 | background-color: #3B5998; 4 | border-color: #133783; 5 | } 6 | 7 | .btn-twitter { 8 | color: #fff; 9 | background-color: #2daddc; 10 | border-color: #0271bf; 11 | } 12 | 13 | .btn-github { 14 | color: #fff; 15 | background-color: #fafafa; 16 | border-color: #ccc; 17 | } 18 | 19 | // Colors 20 | // -------------------------------------------------- 21 | 22 | $btnText: #fff; 23 | $btnTextAlt: #000; 24 | 25 | .col-centered{ 26 | float: none; 27 | margin: 0 auto; 28 | } 29 | .signinForm { 30 | width: 340px; 31 | margin: 0 auto; 32 | border: 1px solid #bdbdbd; 33 | box-shadow: 0 1px 1px 0 grey; 34 | border-radius: 8px 8px; 35 | } 36 | .input { 37 | margin: 15px 0; 38 | vertical-align: baseline; 39 | } 40 | .snapit-logo { 41 | width: 200px; 42 | margin: 0 auto; 43 | } 44 | .login-button { 45 | background-color: #083858; 46 | border: 1px solid #ccc; 47 | border-radius: 8px; 48 | color: #fff; 49 | } 50 | .login-button a { 51 | color: inherit; 52 | text-decoration: none; 53 | background-color: transparent; 54 | } 55 | .login-button:hover { 56 | background-color: #ccc; 57 | color: #083858; 58 | } 59 | .panel-login { 60 | //border-radius: 8px; 61 | } 62 | .panelintro { 63 | border: 2px solid #083858; 64 | border-radius: 8px; 65 | } 66 | .panel, .panel-heading { 67 | border-bottom: 0; 68 | } 69 | .labeltext { 70 | color: #083858; 71 | } -------------------------------------------------------------------------------- /client/app/app.css: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Bootstrap Fonts 4 | */ 5 | 6 | @font-face { 7 | font-family: 'Glyphicons Halflings'; 8 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot'); 9 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), 10 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), 11 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), 12 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 13 | } 14 | 15 | /** 16 | *Font Awesome Fonts 17 | */ 18 | 19 | @font-face { 20 | font-family: 'FontAwesome'; 21 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0'); 22 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), 23 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), 24 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), 25 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); 26 | font-weight: normal; 27 | font-style: normal; 28 | } 29 | 30 | /** 31 | * App-wide Styles 32 | */ 33 | 34 | .browsehappy { 35 | margin: 0.2em 0; 36 | background: #ccc; 37 | color: #000; 38 | padding: 0.2em 0; 39 | } 40 | -------------------------------------------------------------------------------- /client/components/navbar/navbar.html: -------------------------------------------------------------------------------- 1 |