├── .gitignore ├── .DS_Store ├── db ├── .DS_Store ├── migrate │ ├── .DS_Store │ ├── 20150311074249-create-interest.js │ ├── 20150406225348-create-impression.js │ ├── 20150324151852-create-action-type.js │ ├── 20150324152508-create-user-action.js │ ├── 20150311074334-create-user-interest.js │ ├── 20150311074201-create-user.js │ └── 20150311051302-create-publisher.js └── database.json ├── Models ├── .DS_Store ├── userinterest.js ├── interest.js ├── useraction.js ├── actiontype.js ├── user.js ├── impression.js ├── publisher.js └── index.js ├── public ├── 382499.jpg └── stylesheets │ └── style.css ├── UMLs ├── getuserlocation.png ├── create_actiontype.png ├── delete_actiontype.png ├── publisher_signup1.png ├── publisher_signin_sequence_diagram.png └── publisher_edit_actiontype_sequence_diagram.png ├── .sequelizerc ├── views ├── partials │ ├── footer.ejs │ ├── head.ejs │ └── header.ejs ├── createAction.ejs ├── signin.ejs ├── profile.ejs ├── editAction.ejs └── homepage.ejs ├── lib ├── userLocation.js ├── createAction.js ├── viewActionType.js ├── localStrategy.js └── publisherAuth.js ├── sequelize-meta.json ├── README.md ├── auth.js ├── package.json ├── routes ├── users.js ├── useractions.js ├── adProposal.js ├── adRequest.js ├── actiontypes.js └── publishers.js ├── app.js └── test └── routes ├── publishers.js ├── users.js ├── useractions.js └── actiontypes.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/.DS_Store -------------------------------------------------------------------------------- /db/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/db/.DS_Store -------------------------------------------------------------------------------- /Models/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/Models/.DS_Store -------------------------------------------------------------------------------- /public/382499.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/public/382499.jpg -------------------------------------------------------------------------------- /db/migrate/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/db/migrate/.DS_Store -------------------------------------------------------------------------------- /UMLs/getuserlocation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/getuserlocation.png -------------------------------------------------------------------------------- /UMLs/create_actiontype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/create_actiontype.png -------------------------------------------------------------------------------- /UMLs/delete_actiontype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/delete_actiontype.png -------------------------------------------------------------------------------- /UMLs/publisher_signup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/publisher_signup1.png -------------------------------------------------------------------------------- /UMLs/publisher_signin_sequence_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/publisher_signin_sequence_diagram.png -------------------------------------------------------------------------------- /UMLs/publisher_edit_actiontype_sequence_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MennaDarwish/IAS/HEAD/UMLs/publisher_edit_actiontype_sequence_diagram.png -------------------------------------------------------------------------------- /.sequelizerc: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | 'config': path.resolve('db', 'database.json'), 5 | 'migrations-path': path.resolve('db', 'migrate') 6 | } -------------------------------------------------------------------------------- /views/partials/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /views/partials/head.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%= title %> - Intelligent Ad Server 3 | 4 | -------------------------------------------------------------------------------- /lib/userLocation.js: -------------------------------------------------------------------------------- 1 | var satelize = require('satelize'); 2 | 3 | exports.getUserLocation = function(IP) { 4 | satelize.satelize({ip:IP}, function(err, geoData) { 5 | var obj = JSON.parse(geoData);//wrap the data in js object 6 | var userLocation = obj; 7 | }); 8 | return userLocation; 9 | }; 10 | -------------------------------------------------------------------------------- /sequelize-meta.json: -------------------------------------------------------------------------------- 1 | [ 2 | "20150311051302-create-publisher.js", 3 | "20150311074201-create-user.js", 4 | "20150311074249-create-interest.js", 5 | "20150311074334-create-user-interest.js", 6 | "20150324151852-create-action-type.js", 7 | "20150324152508-create-user-action.js", 8 | "20150406225348-create-impression.js" 9 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IAS 2 | Intelligent Ad Server, 3 | 4 | The idea is basically implementing an intelligent api centric adserver that would allow different websites, to feed the ad server with data, and accordingly segment users and decide what ad is most relevant to the user. 5 | 6 | Following Code Conventions http://nodeguide.com/style.html -------------------------------------------------------------------------------- /Models/userinterest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var UserInterest = sequelize.define("UserInterest", { 4 | weight: DataTypes.INTEGER 5 | }, { 6 | classMethods: { 7 | associate: function(models) { 8 | 9 | 10 | } 11 | } 12 | }); 13 | return UserInterest; 14 | }; -------------------------------------------------------------------------------- /views/partials/header.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Models/interest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var Interest = sequelize.define("Interest", { 4 | title: DataTypes.STRING 5 | }, { 6 | classMethods: { 7 | associate: function(models) { 8 | Interest.belongsToMany(models.User, {through: models.UserInterest, foreignKey: 'interestId'}); 9 | } 10 | } 11 | }); 12 | return Interest; 13 | }; -------------------------------------------------------------------------------- /Models/useraction.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var UserAction = sequelize.define("UserAction",{}, { 4 | classMethods: { 5 | associate: function(models) { 6 | // associations can be defined here. 7 | UserAction.belongsTo(models.ActionType, {foreignKey:'actionTypeId' }); 8 | UserAction.belongsTo(models.User, {foreignKey:'userId' }); 9 | } 10 | } 11 | }); 12 | return UserAction; 13 | }; -------------------------------------------------------------------------------- /Models/actiontype.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var ActionType = sequelize.define("ActionType", { 4 | actionName: DataTypes.STRING, 5 | actionWeight: DataTypes.INTEGER 6 | }, { 7 | classMethods: { 8 | associate: function(models) { 9 | // associations can be defined here 10 | ActionType.belongsTo(models.Publisher, {foreignKey:'publisherId' }); 11 | } 12 | } 13 | }); 14 | return ActionType; 15 | }; -------------------------------------------------------------------------------- /lib/createAction.js: -------------------------------------------------------------------------------- 1 | var Actiontypes = require('../models/index.js').ActionType; 2 | var Publisher = require('../models/index.js').Publisher; 3 | var Q = require('q'); 4 | 5 | exports.createAction = function (name,weight,publisherId){ 6 | var action = { 7 | "actionName" : name, 8 | "actionWeight" : weight, 9 | "publisherId" : publisherId 10 | } 11 | Actiontypes.create(action) 12 | .then(function (createdAction) { 13 | console.log("Action: " + JSON.stringify(createdAction)); 14 | }); 15 | } -------------------------------------------------------------------------------- /lib/viewActionType.js: -------------------------------------------------------------------------------- 1 | var ActionType = require('../models/index.js').ActionType; 2 | var Publisher = require('../models/index.js').Publisher; 3 | var Q = require('q'); 4 | 5 | //Finding all the action types of a certain publisher to view them on their profile. 6 | exports.viewActionTypes = function(publisherID) { 7 | var deferred = Q.defer(); 8 | 9 | ActionType.findAll({where: {publisherId: publisherID} }).then(function(result) { 10 | deferred.resolve(result); 11 | }); 12 | return deferred.promise; 13 | }; -------------------------------------------------------------------------------- /Models/user.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var User = sequelize.define("User", { 4 | name: DataTypes.STRING, 5 | email: DataTypes.STRING, 6 | birthdate: DataTypes.DATE, 7 | gender: DataTypes.ENUM('male', 'female') 8 | }, { 9 | classMethods: { 10 | associate: function(models) { 11 | User.belongsTo(models.Publisher, {foreignKey:'publisherId' }); 12 | User.belongsToMany(models.Interest, {through: models.UserInterest, foreignKey: 'userId'}); 13 | } 14 | } 15 | }); 16 | return User; 17 | }; -------------------------------------------------------------------------------- /db/database.json: -------------------------------------------------------------------------------- 1 | { 2 | "development": { 3 | "username": "root", 4 | "password": null, 5 | "database": "adx_development", 6 | "host": "127.0.0.1", 7 | "dialect": "mysql" 8 | }, 9 | "test": { 10 | "username": "root", 11 | "password": null, 12 | "database": "adx_test", 13 | "host": "127.0.0.1", 14 | "logging": false, 15 | "dialect": "mysql" 16 | }, 17 | "production": { 18 | "username": "root", 19 | "password": null, 20 | "database": "database_production", 21 | "host": "127.0.0.1", 22 | "dialect": "mysql" 23 | } 24 | } -------------------------------------------------------------------------------- /auth.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var LocalStrategy = require('passport-localapikey').Strategy; 3 | var Publisher = require('./Models/index.js').Publisher; 4 | 5 | passport.use(new LocalStrategy( 6 | function(req, done) { 7 | process.nextTick(function() { 8 | Publisher.find({ 9 | where:{apikey: req} 10 | }).then(function(publisher) { 11 | if(!publisher) {return done(null, false, {message: 'Unknown apikey: '+ apikey});} 12 | return done(null, publisher); 13 | }); 14 | }); 15 | } 16 | )); 17 | 18 | module.exports = passport; -------------------------------------------------------------------------------- /Models/impression.js: -------------------------------------------------------------------------------- 1 | "use strict" ; 2 | module.exports = function(sequelize, DataTypes) { 3 | var Impression = sequelize.define("Impression", { 4 | width: DataTypes.INTEGER, 5 | height: DataTypes.INTEGER, 6 | redirectUrl: DataTypes.STRING, 7 | //imageUrl: DataTypes.STRING, 8 | }, { 9 | classMethods: { 10 | associate: function(models) { 11 | Impression.belongsTo(models.User, {foreignKey: 'userId'}); 12 | Impression.belongsTo(models.Publisher , {forgeinKey: 'publisherId'}); //check 13 | //Impression.belongsTo(model.Ad , {forgein: 'adId'}); 14 | } 15 | } 16 | }); 17 | return Impression; 18 | }; -------------------------------------------------------------------------------- /Models/publisher.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = function(sequelize, DataTypes) { 3 | var Publisher = sequelize.define("Publisher", { 4 | name: DataTypes.STRING, 5 | domain: DataTypes.STRING, 6 | email: DataTypes.STRING, 7 | channel: DataTypes.STRING, 8 | password: DataTypes.STRING, //password 9 | apikey: DataTypes.STRING 10 | }, { 11 | classMethods: { 12 | associate: function(models) { 13 | // associations can be defined here 14 | Publisher.hasMany(models.User, {foreignKey: 'publisherId'}) 15 | Publisher.hasMany(models.ActionType, {foreignKey: 'publisherId'}) 16 | } 17 | 18 | } 19 | }); 20 | return Publisher; 21 | }; 22 | -------------------------------------------------------------------------------- /db/migrate/20150311074249-create-interest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("Interests", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | title: { 12 | type: DataTypes.STRING 13 | }, 14 | createdAt: { 15 | allowNull: false, 16 | type: DataTypes.DATE 17 | }, 18 | updatedAt: { 19 | allowNull: false, 20 | type: DataTypes.DATE 21 | } 22 | }).done(done); 23 | }, 24 | down: function(migration, DataTypes, done) { 25 | migration.dropTable("Interests").done(done); 26 | } 27 | }; -------------------------------------------------------------------------------- /views/createAction.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% include ../views/partials/head %> 5 | 6 | 7 | 8 | 9 |
10 |
11 | 14 | 17 |
18 |
19 | 20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "adX", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "NODE_ENV=test mocha --recursive", 8 | "start": "node ./bin/www " 9 | }, 10 | "author": "", 11 | "style": "style.css", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bcryptjs": "^2.1.0", 15 | "body-parser": "^1.12.3", 16 | "cookie-parser": "^1.3.4", 17 | "ejs": "^1.0.0", 18 | "express": "^4.12.3", 19 | "express-session": "^1.11.1", 20 | "jade": "*", 21 | "morgan": "*", 22 | "mysql": "^2.5.5", 23 | "node-uuid": "*", 24 | "passport": "^0.2.1", 25 | "passport-local": "^1.0.0", 26 | "passport-localapikey": "0.0.3", 27 | "q": "^1.3.0", 28 | "satelize": "^0.1.1", 29 | "sequelize": "^2.0.4", 30 | "sequelize-cli": "^1.3.1" 31 | }, 32 | "devDependencies": { 33 | "mocha": "^2.2.1", 34 | "should": "^5.1.0", 35 | "supertest": "^0.15.0" 36 | } 37 | } -------------------------------------------------------------------------------- /Models/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var fs = require("fs"); 4 | var path = require("path"); 5 | var Sequelize = require("sequelize"); 6 | var basename = path.basename(module.filename); 7 | var env = process.env.NODE_ENV || "development"; 8 | var config = require(__dirname + '/../db/database.json')[env]; 9 | var sequelize = new Sequelize(config.database, config.username, config.password, config); 10 | var db = {}; 11 | 12 | fs 13 | .readdirSync(__dirname) 14 | .filter(function(file) { 15 | return (file.indexOf(".") !== 0) && (file !== basename); 16 | }) 17 | .forEach(function(file) { 18 | var model = sequelize["import"](path.join(__dirname, file)); 19 | db[model.name] = model; 20 | }); 21 | 22 | Object.keys(db).forEach(function(modelName) { 23 | if ("associate" in db[modelName]) { 24 | db[modelName].associate(db); 25 | } 26 | }); 27 | 28 | db.sequelize = sequelize; 29 | db.Sequelize = Sequelize; 30 | 31 | module.exports = db; -------------------------------------------------------------------------------- /views/signin.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% include ../views/partials/head %> 5 | 6 | 7 |
8 |
9 | 12 | 15 |
16 |
17 | 18 |
19 |
20 | 29 | 30 | -------------------------------------------------------------------------------- /views/profile.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% include ../views/partials/head %> 4 | 5 | 6 | 7 |
8 | <% include ../views/partials/header %> 9 |
10 | 11 |
12 |
13 |
14 |
15 |

<%= name %>

16 | 24 |
25 | 26 |
27 |
28 |
29 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /db/migrate/20150406225348-create-impression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | up: function(migration, DataTypes, done) { 5 | // add altering commands here, calling 'done' when finished 6 | migration.createTable("Impression",{ 7 | id: { 8 | allowNull: false, 9 | autoIncrement: true, 10 | primaryKey: true, 11 | type: DataTypes.INTEGER 12 | }, 13 | width: { 14 | type : DataTypes.INTEGER 15 | }, 16 | height: { 17 | type : DataTypes.INTEGER 18 | }, 19 | redirectUrl : { 20 | type : DataTypes.STRING 21 | }, 22 | createdAt: { 23 | allowNull: false, 24 | type: DataTypes.DATE 25 | }, 26 | updatedAt: { 27 | allowNull: false, 28 | type: DataTypes.DATE 29 | } 30 | }).done(done); 31 | 32 | }, 33 | 34 | down: function(migration, DataTypes, done) { 35 | migration.dropTable("Impression").done(done); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /db/migrate/20150324151852-create-action-type.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("ActionTypes", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | actionName: { 12 | type: DataTypes.STRING 13 | }, 14 | actionWeight: { 15 | type: DataTypes.INTEGER 16 | }, 17 | publisherId: { 18 | type: DataTypes.INTEGER, 19 | references: 'Publishers', 20 | referencesKey: 'id', 21 | allowNull: false 22 | }, 23 | createdAt: { 24 | allowNull: false, 25 | type: DataTypes.DATE 26 | }, 27 | updatedAt: { 28 | allowNull: false, 29 | type: DataTypes.DATE 30 | } 31 | }).done(done); 32 | }, 33 | down: function(migration, DataTypes, done) { 34 | migration.dropTable("ActionTypes").done(done); 35 | } 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /db/migrate/20150324152508-create-user-action.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("UserActions", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | actionTypeId: { 12 | type: DataTypes.INTEGER, 13 | references: 'ActionTypes', 14 | referencesKey: 'id', 15 | allowNull: false 16 | }, 17 | userId: { 18 | type: DataTypes.INTEGER, 19 | references: 'Users', 20 | referencesKey: 'id', 21 | allowNull: false 22 | }, 23 | createdAt: { 24 | allowNull: false, 25 | type: DataTypes.DATE 26 | }, 27 | updatedAt: { 28 | allowNull: false, 29 | type: DataTypes.DATE 30 | } 31 | }).done(done); 32 | }, 33 | down: function(migration, DataTypes, done) { 34 | migration.dropTable("UserActions").done(done); 35 | } 36 | }; -------------------------------------------------------------------------------- /db/migrate/20150311074334-create-user-interest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("UserInterests", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | weight: { 12 | type: DataTypes.INTEGER 13 | }, 14 | userId: { 15 | type: DataTypes.INTEGER, 16 | references: 'Users', 17 | referencesKey: 'id', 18 | allowNull: false 19 | }, 20 | interestId: { 21 | type: DataTypes.INTEGER, 22 | references: 'Interests', 23 | referencesKey: 'id', 24 | allowNull: false 25 | }, 26 | createdAt: { 27 | allowNull: false, 28 | type: DataTypes.DATE 29 | }, 30 | updatedAt: { 31 | allowNull: false, 32 | type: DataTypes.DATE 33 | } 34 | }).done(done); 35 | }, 36 | down: function(migration, DataTypes, done) { 37 | migration.dropTable("UserInterests").done(done); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /views/editAction.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% include ../views/partials/head %> 5 | 6 | 7 |
8 |
9 | 12 | 15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 | Destroy 24 | 25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /db/migrate/20150311074201-create-user.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("Users", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | name: { 12 | type: DataTypes.STRING 13 | }, 14 | gender: { 15 | type: DataTypes.ENUM('male', 'female') 16 | }, 17 | email: { 18 | type: DataTypes.STRING 19 | }, 20 | birthdate: { 21 | type: DataTypes.DATE 22 | }, 23 | publisherId: { 24 | type: DataTypes.INTEGER, 25 | references: 'Publishers', 26 | referencesKey: 'id', 27 | allowNull: false 28 | }, 29 | createdAt: { 30 | allowNull: false, 31 | type: DataTypes.DATE 32 | }, 33 | updatedAt: { 34 | allowNull: false, 35 | type: DataTypes.DATE 36 | } 37 | }).done(done); 38 | }, 39 | down: function(migration, DataTypes, done) { 40 | migration.dropTable("Users").done(done); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /db/migrate/20150311051302-create-publisher.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | up: function(migration, DataTypes, done) { 4 | migration.createTable("Publishers", { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: DataTypes.INTEGER 10 | }, 11 | name: { 12 | type: DataTypes.STRING 13 | }, 14 | domain: { 15 | type: DataTypes.STRING 16 | }, 17 | email: { 18 | type: DataTypes.STRING 19 | }, 20 | channel: { 21 | type: DataTypes.STRING 22 | }, 23 | password: { 24 | type: DataTypes.STRING 25 | }, 26 | apikey: { 27 | type: DataTypes.STRING 28 | }, 29 | createdAt: { 30 | allowNull: false, 31 | type: DataTypes.DATE 32 | }, 33 | updatedAt: { 34 | allowNull: false, 35 | type: DataTypes.DATE 36 | }, 37 | password: { 38 | type: DataTypes.STRING 39 | }, 40 | }).done(done); 41 | }, 42 | down: function(migration, DataTypes, done) { 43 | migration.dropTable("Publishers").done(done); 44 | } 45 | }; -------------------------------------------------------------------------------- /views/homepage.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% include ../views/partials/head %> 5 | 6 | 7 |
8 |
9 | 12 | 15 | 16 | 19 | 22 | 25 |
26 |
27 | 28 |
29 |
30 | 39 | 40 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var User = require('../Models/index').User; 3 | var bodyParser = require('body-parser'); 4 | var jsonParser = bodyParser.json(); 5 | var auth = require('../auth.js'); 6 | var router = express.Router(); 7 | 8 | var userBuilder = function(req, res, next) { 9 | var user = { 10 | name: req.body.name, 11 | email: req.body.email, 12 | birthdate: req.body.birthdate, 13 | gender: req.body.gender, 14 | publisherId: req.body.publisherId 15 | }; 16 | req.body.user = user; 17 | next(); 18 | } 19 | router.route('/') //authenticating using localapikey on requests coming from servers. 20 | .post(jsonParser, auth.authenticate('localapikey', { session: false }), userBuilder, auth.authenticate('localapikey', { session: false }), function(req, res) { 21 | var user = req.body.user; 22 | User.create(user).then( function(createdUser) { 23 | res.status(201).json({status: 'created', userId: createdUser.dataValues.id}); 24 | }, function(err) { 25 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 26 | }); 27 | }); 28 | 29 | router.route('/:id') 30 | .get(function(req, res) { 31 | User.find(req.params.id).then(function(user) { 32 | if(!user) return res.sendStatus(404); 33 | res.status(200).json(user.dataValues); 34 | },function(err) { 35 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 36 | }); 37 | }); 38 | 39 | module.exports = router; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var jade = require('jade'); 3 | var app = express(); 4 | var passport = require('passport'); 5 | var cookieParser = require('cookie-parser'); 6 | var session = require('express-session'); 7 | var bodyParser = require('body-parser'); 8 | //Routes 9 | var usersRoute = require('./routes/users'); 10 | var publishersRoute = require('./routes/publishers'); 11 | var actionTypesRoute = require('./routes/actiontypes'); 12 | var userActionsRoute = require('./routes/useractions'); 13 | var adRequest = require('./routes/adRequest'); 14 | var querystring = require('querystring'); 15 | 16 | app.use(bodyParser.urlencoded({extended : true})); 17 | app.use(cookieParser()); 18 | app.use(session({ 19 | secret: process.env.SESSION_SECRET || 'secret', 20 | resave: false, 21 | saveUninitialized: false 22 | })); 23 | app.use(passport.initialize()); 24 | app.use(passport.session()); 25 | 26 | var auth = require('./auth.js'); 27 | var morgan = require('morgan'); 28 | 29 | app.use(auth.initialize()); 30 | app.set('views', __dirname + '/views'); 31 | app.set('public',__dirname + '/public'); 32 | app.set('view engine', 'ejs'); 33 | app.use(morgan('dev')); 34 | app.use(express.static(__dirname + '/public')); 35 | app.use('/adRequest',adRequest); 36 | app.use('/users', usersRoute); 37 | app.use('/publishers', publishersRoute); 38 | app.use('/actiontypes', actionTypesRoute); 39 | app.use('/useractions', userActionsRoute); 40 | 41 | app.listen(3000); 42 | console.log("Listening on port 3000"); 43 | 44 | module.exports = app; -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=PT+Sans+Narrow); 2 | 3 | html { 4 | background: url(../382499.jpg); 5 | background-size: 1500px 700px; 6 | background-repeat: no-repeat; 7 | } 8 | 9 | 10 | *, 11 | *:before, 12 | *:after { 13 | box-sizing: border-box; 14 | } 15 | form { 16 | border: 1px solid #c6c7cc; 17 | border-radius: 5px; 18 | font: 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 19 | overflow: hidden; 20 | width: 240px; 21 | margin-left: 550px; 22 | margin-top: 200px; 23 | } 24 | fieldset { 25 | border: 0; 26 | margin: 0; 27 | padding: 0; 28 | } 29 | input { 30 | border-radius: 5px; 31 | font: 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 32 | margin: 0; 33 | } 34 | .account-info { 35 | padding: 20px 20px 0 20px; 36 | } 37 | .account-info label { 38 | color: #395870; 39 | display: block; 40 | font-weight: bold; 41 | margin-bottom: 20px; 42 | } 43 | .account-info input { 44 | background: #fff; 45 | border: 1px solid #c6c7cc; 46 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .1); 47 | color: #636466; 48 | padding: 6px; 49 | margin-top: 6px; 50 | width: 100%; 51 | } 52 | .account-action { 53 | background-color:rgba(240,240,242,0.5); 54 | 55 | border-top: 1px solid #c6c7cc; 56 | padding: 20px; 57 | } 58 | .account-action .btn { 59 | background: linear-gradient(#49708f, #293f50); 60 | border: 0; 61 | color: #fff; 62 | cursor: pointer; 63 | font-weight: bold; 64 | float: left; 65 | padding: 8px 16px; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /routes/useractions.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var jsonParser = bodyParser.json(); 4 | var router = express.Router(); 5 | var auth = require('../auth.js'); 6 | var UserAction = require('../models/index.js').UserAction; 7 | 8 | var UserActionBuilder = function(req, res, next){ 9 | var userAction = { 10 | userId: req.body.userId, 11 | actionTypeId: req.body.actionTypeId 12 | } 13 | req.body.userAction = userAction; 14 | next(); 15 | } 16 | 17 | router.route('/') //authenticating using localapikey on requests coming from servers. 18 | .post(jsonParser, auth.authenticate('localapikey', { session: false }), UserActionBuilder, function(req, res){ 19 | var userAction = req.body.userAction; 20 | UserAction.create(userAction).then(function(createdUserAction){ 21 | res.status(201).json({status: 'created', userActionId: createdUserAction.dataValues.id}); 22 | }, function(err){ 23 | res.status(404).json({status: 'ERROR', message: 'Something went wrong ' + err}); 24 | }); 25 | }); 26 | 27 | router.route('/:id') 28 | .get(function(req, res) { 29 | UserAction.find(req.params.id).then(function(userAction) { 30 | if(!userAction) return res.sendStatus(404); 31 | res.status(200).json(userAction.dataValues); 32 | },function(err) { 33 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 34 | }); 35 | }); 36 | 37 | router.route('/:id') 38 | .delete(function(req,res) { 39 | UserAction.find(req.params.id).then(function(toBeDeletedUserAction) { 40 | if(!toBeDeletedUserAction) return res.sendStatus(404); 41 | toBeDeletedUserAction.destroy(); 42 | res.status(200).json({status: 'deleted'}); 43 | }, function(err) { 44 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 45 | }); 46 | 47 | }); 48 | 49 | module.exports = router; -------------------------------------------------------------------------------- /lib/localStrategy.js: -------------------------------------------------------------------------------- 1 | //configuring local strategy 2 | var passport = require('passport'); 3 | var passportLocal = require('passport-local'); 4 | var publisherAuth = require('./publisherAuth.js'); 5 | var uuid = require('node-uuid'); 6 | var apikey = uuid.v4(); 7 | 8 | // Use the LocalStrategy within Passport to Register/"signup" publishers. 9 | passport.use('local-signup', new passportLocal( 10 | {passReqToCallback : true}, //allows us to pass back the request to the callback 11 | function(req, username, password, done) { 12 | publisherAuth.localReg(req.body.name,req.body.channel,req.body.domain,username, apikey ,password) 13 | .then(function (user) { 14 | if (user) { 15 | console.log('LOGGED IN AS: ' + user.email); 16 | req.session.success = 'You are successfully logged in ' + user.username + '!'; 17 | done(null, user); 18 | } 19 | if (!user) { 20 | console.log('COULD NOT LOG IN'); 21 | req.session.error = 'Could not log user in. Please try again.'; //inform user could not log them in 22 | done(null, user); 23 | } 24 | }) 25 | .fail(function (err){ 26 | console.log(err.body); 27 | }); 28 | } 29 | )); 30 | 31 | // Use the LocalStrategy within Passport to login publishers. 32 | passport.use('local-signin', new passportLocal( 33 | {passReqToCallback : true}, //allows us to pass back the request to the callback 34 | function(req, username, password, done) { 35 | publisherAuth.localsignin(username, password) 36 | .then(function (user) { 37 | if (user) { 38 | console.log('LOGGED IN AS: ' + user.dataValues.name); 39 | req.session.success = 'You are successfully logged in ' + user.dataValues.name + '!'; 40 | done(null, user); 41 | } 42 | if (!user) { 43 | console.log('COULD NOT LOG IN'); 44 | req.session.error = 'Could not log user in. Please try again.'; //inform user could not log them in 45 | done(null, user); 46 | } 47 | }) 48 | .fail(function (err){ 49 | console.log(err.body); 50 | }); 51 | } 52 | )); 53 | 54 | module.exports=passportLocal; -------------------------------------------------------------------------------- /lib/publisherAuth.js: -------------------------------------------------------------------------------- 1 | //Actually registering (signup) the publisher. 2 | var bcrypt = require('bcryptjs'); 3 | var Q = require('q'); // to return a promise 4 | var Publisher = require('../models/index.js').Publisher; 5 | 6 | exports.localReg = function (name,channel,domain,username,apikey,password) { 7 | 8 | var deferred = Q.defer(); 9 | var hash = bcrypt.hashSync(password, 8); 10 | var publisher = { 11 | "name": name, 12 | "channel": channel, 13 | "domain": domain, 14 | "email": username, 15 | "password": hash, 16 | "apikey": apikey 17 | } 18 | //check if username is already assigned in our database 19 | Publisher.find({ where: {email: username} }) 20 | .then(function (result) { //case in which user already exists in db 21 | if (result != null) {//username already exists 22 | console.log('username already exists'); 23 | deferred.resolve(false); 24 | } else { 25 | Publisher.create(publisher) 26 | .then(function (createdPublisher) { 27 | console.log('Publisher: ' + createdPublisher); 28 | deferred.resolve(createdPublisher); // return value if the promise 29 | }) 30 | .fail(function (err) { 31 | console.log('PUT FAIL:' + err.body); 32 | deferred.reject(new Error(err.body)); 33 | }); 34 | } 35 | }); 36 | return deferred.promise; 37 | }; 38 | 39 | 40 | //Checking if username exists and the passwrd is correct in order to sign in the publisher. 41 | exports.localsignin = function (username, password) { 42 | var deferred = Q.defer(); 43 | Publisher.find({ where: {email: username} }) 44 | .then(function (result){ 45 | if (result !== null) { 46 | console.log('result'); 47 | console.log(result); 48 | var hash = result.password; 49 | console.log(hash); 50 | console.log(bcrypt.compareSync(password, hash)); 51 | if (bcrypt.compareSync(password, hash)) { 52 | deferred.resolve(result); 53 | } else { 54 | console.log('PASSWORDS NOT MATCH'); 55 | deferred.resolve(false); 56 | } 57 | } else { 58 | console.log('COULD NOT FIND USER IN DB FOR SIGNIN'); 59 | deferred.resolve(false); 60 | } 61 | }); 62 | return deferred.promise; 63 | }; -------------------------------------------------------------------------------- /test/routes/publishers.js: -------------------------------------------------------------------------------- 1 | var request = require('supertest'); 2 | var app = require('../../app'); 3 | var db = require('../../models/index'); 4 | var should = require('should'); 5 | 6 | describe('Publishers Route', function() { 7 | 8 | describe('Creating new publishers', function(){ 9 | beforeEach(function(done) { 10 | //Destroy database before running each test 11 | 12 | db.sequelize.sync({force: true}).then(function() { 13 | done(); 14 | }).catch(function(err) { 15 | return done(err); 16 | }); 17 | }); 18 | 19 | it('Returns 201 status code', function(done){ 20 | 21 | request(app) 22 | .post('/publishers') 23 | .send('name=FooPublisher&email=publisher@example.com&domain=http://www.publisher.com&channel=Sports') 24 | .expect(201, done); 25 | }); 26 | 27 | it('Returns application/json format', function(done) { 28 | 29 | request(app) 30 | .post('/publishers') 31 | .send('name=FooPublisher&email=publisher@example.com&domain=http://www.publisher.com&channel=Sports') 32 | .expect('Content-Type', /application\/json/, done); 33 | 34 | }); 35 | 36 | it('Returns the id of the newly created publisher', function(done) { 37 | 38 | request(app) 39 | .post('/publishers') 40 | .send('name=FooPublisher&email=publisher@example.com&domain=http://www.publisher.com&channel=Sports') 41 | .expect(function(response) { 42 | response.body.publisherId.should.be.above(0).and.be.a.Number 43 | }).end(done); 44 | 45 | }); 46 | 47 | it('Returns status message "created"', function(done) { 48 | 49 | request(app) 50 | .post('/publishers') 51 | .send('name=FooPublisher&email=publisher@example.com&domain=http://www.publisher.com&channel=Sports') 52 | .expect(function(response){ 53 | response.body.status.should.be.equal('created'); 54 | }).end(done); 55 | 56 | }); 57 | 58 | it('Return apikey of the newly created publisher', function(done) { 59 | request(app) 60 | .post('/publishers') 61 | .send('name=FooPublisher&email=publisher@example.com&domain=http://www.publisher.com&channel=Sports') 62 | .expect(function(res) { 63 | res.body.apikey.should.exist; 64 | }).end(done); 65 | }); 66 | 67 | }); 68 | 69 | }); 70 | -------------------------------------------------------------------------------- /routes/adProposal.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var jsonParser = require('body-parser').json(); 4 | var http = require('http'); 5 | var Q = require('Q'); 6 | var User = require('../models/index').User; 7 | var loc = require('../lib').userLocation; 8 | 9 | /* 10 | * Author: Ahmed Adel 11 | * Publisher send an ad request for a specific user to the IAS, IAS fetch user 12 | interests, IAS sends the user interests to the DSP, the DSP decides which 13 | ad to send to the publisher, it sends this ad to the IAS, the iAS sends this ad to the publisher. 14 | * request, response 15 | */ 16 | 17 | router.route('/') 18 | .post(jsonParser, function(request, response){ 19 | 20 | var data = {}; 21 | var options = { 22 | host: 'localhost', 23 | port: 4000, 24 | path: '/placements', 25 | method: 'POST', 26 | headers: { 27 | 'Content-Type': 'application/json' 28 | } 29 | }; 30 | var userLocation = getUserLocation(request.body.userIP); 31 | 32 | data['width'] = request.body.width; 33 | data['height'] = request.body.height; 34 | 35 | if(userLocation['latitude']){ 36 | data['latitude'] = userLocation['latitude']; 37 | } 38 | else{ 39 | data['latitude'] = "N/A"; 40 | } 41 | if(userLocation['longitude']){ 42 | data['longitude'] = userLocation['longitude']; 43 | } 44 | else{ 45 | data['longitude'] = "N/A"; 46 | } 47 | if(userLocation['city']){ 48 | data['city'] = userLocation['city']; 49 | } 50 | else{ 51 | data['city'] = "N/A"; 52 | } 53 | if(userLocation['country']){ 54 | data['country'] = userLocation['country']; 55 | } 56 | else{ 57 | data['country'] = "N/A"; 58 | } 59 | 60 | User.find(request.body.userId).then(function(user) { 61 | return user.getInterests(); 62 | }).then(function(interests) { 63 | var titlesPromises = interests.map(function(interest) { 64 | var title = interest.dataValues.title; 65 | return Q(title); 66 | }); 67 | return Q.all(titlesPromises); 68 | }).then(function(interestsTitles) { 69 | data['tags'] = interestsTitles; 70 | var req = http.request(options, function(res) { 71 | res.pipe(response); 72 | }); 73 | var stringData = JSON.stringify({placement: data}); 74 | req.write(stringData); 75 | req.end(); 76 | }); 77 | }); 78 | 79 | module.exports = router; 80 | -------------------------------------------------------------------------------- /routes/adRequest.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var bodyParser = require('body-parser'); 4 | var Impression = require('../models/index.js').Impression; 5 | var http = require('http'); 6 | var auth = require('../auth.js'); 7 | var userLocation = require('../lib/userLocation.js'); 8 | 9 | router.route('/') //authenticating using localapikey on requests coming from servers. 10 | .post(bodyParser, auth.authenticate('localapikey', { session: false }), function(request, response){ //post request from publisher containing user and ad info 11 | var ip = request.header('x-forwarded-for') ; // ip address of the user 12 | var userLocation = userLocation.getUserLocation(ip); 13 | var width = request.body.width; 14 | var height = request.body.height; 15 | var UserId = request.body.userId; 16 | var PublisherId = request.body.publisherId; 17 | //request.on('finish', function(){ //when request is done sending, start forwarding to DSP 18 | var data = { //data that will be sent in the request to dsp 19 | width : width, 20 | userId : UserId, 21 | height : heigth, 22 | location: userLocation 23 | }; 24 | 25 | var options = { // request options 26 | //host: //DSP, 27 | //port: //DSP PORT NUMBER, 28 | path: '/', 29 | method: 'POST', 30 | headers: { 31 | 'Content-Type': 'application/x-www-form-urlencoded', 32 | 'Content-Length': Buffer.byteLength(data) 33 | } 34 | } 35 | // http request to send data to DSP 36 | var req = http.request(options, function(res) { 37 | var body; 38 | res.on('data', function (chunk) { //resp data is sent in the response from dsp 39 | body += chunk; 40 | var adId = chunk.adId; 41 | var price = chunk.price; 42 | var ad = chunk.ad; //save the response from the DSP in an object 43 | }); 44 | }); 45 | 46 | req.write(data); // send data to dsp 47 | req.end(); // end of the request 48 | 49 | var impression = { 50 | publisherId : PublisherId, 51 | userId : UserId, 52 | adId : adId 53 | } 54 | //Creating Impression 55 | Impression.create(impression).then(function(createdImpression){ 56 | res.status(201).json({status : 'created'}); 57 | }), function(err){ 58 | res.status(400).json({status: 'Error', message : 'Something went wrong ' + err}); 59 | }; 60 | //send the DSP's response back to the publisher 61 | response.send(body); 62 | }); 63 | 64 | module.exports = router; -------------------------------------------------------------------------------- /routes/actiontypes.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var urlEncoded = bodyParser.urlencoded({extended: false}); 4 | var jsonParser = bodyParser.json(); 5 | var router = express.Router(); 6 | var ActionType = require('../models/index.js').ActionType; 7 | var publishers = require('../routes/publishers.js'); 8 | var passport = require('passport'); 9 | 10 | var ActionTypeBuilder = function(req, res, next){ 11 | var actionType = { 12 | actionName: req.body.actionName, 13 | actionWeight: req.body.actionWeight, 14 | publisherId: req.user.id 15 | } 16 | req.body.actionType = actionType; 17 | next(); 18 | } 19 | //Creating an actiontype and rendering to publisher's profile after successfully creating it. 20 | router.route('/') 21 | .post(jsonParser, ActionTypeBuilder, function(req, res){ 22 | if (req.isAuthenticated()){ //checking if the publisher is authenticated 23 | var actionType = req.body.actionType; 24 | ActionType.create(actionType).then(function(createdActionType) { 25 | res.redirect('../publishers/profile'); //redirecting to the publisher's profile when it successfully created the action. 26 | }, function(err){ 27 | res.status(404).json({status: 'ERROR', message: 'Something went wrong '+ err}); 28 | }); 29 | } 30 | else { 31 | res.redirect('/publishers/homepage'); //redirecting to the homepage when it fails to create an action. 32 | } 33 | }); 34 | 35 | //Fetching a certain action type using its id as a queryparam, then rendering the view of editing this actiontype 36 | router.route('/:id') 37 | .get(function(req, res) { 38 | var id = req.params.id.substring(1); 39 | ActionType.find(id).then(function(actionType) { 40 | if(!actionType) return res.sendStatus(404); 41 | res.render ('editAction',{ 42 | title : 'Edit Action', 43 | actiontype : actionType 44 | }); 45 | },function(err) { 46 | res.status(404).json({status: 'ERROR', message: 'Something went wrong ' + err}); 47 | }); 48 | }); 49 | 50 | //Editing the action type by fetchiing it from the database using the id as a queryparam, then changing its values. 51 | router.route('/:id') 52 | .post(urlEncoded,function(req, res) { 53 | var id = req.params.id.substring(1); 54 | ActionType.find(id).then(function(oldActionType) { 55 | if(!oldActionType) return res.sendStatus(404); 56 | oldActionType.setDataValue('actionName', req.body.actionName); 57 | oldActionType.setDataValue('actionWeight', req.body.actionWeight); 58 | oldActionType.save(); 59 | res.redirect('../publishers/profile'); 60 | }, function(err) { 61 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 62 | }); 63 | }); 64 | 65 | //deleting an action type, and rendering to publisher's profile after successfully deleting it. 66 | router.route('/:id') 67 | .delete(urlEncoded, function(req,res) { 68 | var id = req.params.id.substring(1, 3); 69 | ActionType.find(id).then(function(toBeDeletedActionType) { 70 | if(!toBeDeletedActionType) return res.sendStatus(404); 71 | console.log(toBeDeletedActionType); 72 | toBeDeletedActionType.destroy(); 73 | res.redirect('../publishers/profile'); 74 | }, function(err) { 75 | res.status(400).json({status: 'ERROR', message: 'Something went wrong ' + err}); 76 | }); 77 | }); 78 | 79 | module.exports = router; -------------------------------------------------------------------------------- /test/routes/users.js: -------------------------------------------------------------------------------- 1 | var request = require('supertest'); 2 | var app = require('../../app'); 3 | var db = require('../../models/index'); 4 | var should = require('should'); 5 | var uuid = require('node-uuid'); 6 | var id = uuid.v4(); 7 | var secret = uuid.v4(); 8 | var publisher = { 9 | name: 'FOO', 10 | apikey: id + ':' + secret 11 | } 12 | 13 | var userData = { 14 | name: 'FooUser', 15 | email: 'user@example.com', 16 | birthdate: '1/1/1990', 17 | gender: 'male', 18 | publisherId: 1, 19 | apikey: publisher.apikey 20 | } 21 | describe('Users Route', function() { 22 | describe('Creating new users', function() { 23 | 24 | beforeEach(function(done) { 25 | //Destroy database before running each test. 26 | db.sequelize.sync({force: true}).then(function() { 27 | // Create publisher record which will be used in creating users. 28 | db.Publisher.create(publisher).then(function() { 29 | 30 | done(); 31 | }); 32 | }) 33 | 34 | }) 35 | 36 | 37 | 38 | it('Returns 201 status code', function(done){ 39 | 40 | request(app) 41 | .post('/users') 42 | .send(userData) 43 | .expect(201, done); 44 | }); 45 | 46 | it('Returns application/json format', function(done) { 47 | 48 | request(app) 49 | .post('/users') 50 | .send(userData) 51 | .expect('Content-Type', /application\/json/, done); 52 | 53 | }); 54 | 55 | it('Returns the id of the newly created user', function(done) { 56 | 57 | request(app) 58 | .post('/users') 59 | .send(userData) 60 | .expect(function(response) { 61 | response.body.userId.should.be.above(0).and.be.a.Number 62 | }).end(done); 63 | 64 | }); 65 | 66 | it('Returns status message "created"', function(done) { 67 | 68 | request(app) 69 | .post('/users') 70 | .send(userData) 71 | .expect(function(response){ 72 | response.body.status.should.be.equal('created'); 73 | }).end(done); 74 | 75 | }); 76 | 77 | }); 78 | 79 | describe('Fetching a user', function(done) { 80 | beforeEach(function(done) { 81 | // Sync database and create a user record 82 | 83 | db.sequelize.sync({force: true}).then(function() { 84 | // Create publisher record which will be used in creating users. 85 | db.Publisher.create({}).then(function() { 86 | db.User.create({name:'FetcherTester',publisherId:1}); 87 | done(); 88 | }); 89 | 90 | }); 91 | 92 | }); 93 | 94 | it('Returns status code 200 if the record was found', function(done){ 95 | request(app) 96 | .get('/users/1') 97 | .send("apikey="+ publisher.apikey) 98 | .expect(200, done); 99 | 100 | 101 | }); 102 | 103 | it('Returns status code 404 if the record was not found', function(done){ 104 | 105 | request(app) 106 | .get('/users/100') 107 | .expect(404, done); 108 | 109 | }); 110 | 111 | it('Returns application/json format', function(done){ 112 | 113 | request(app) 114 | .get('/users/1') 115 | .expect('Content-Type', /application\/json/, done); 116 | 117 | }); 118 | 119 | it('Returns the user record if found', function(done){ 120 | 121 | request(app) 122 | .get('/users/1') 123 | .expect(/FetcherTester/, done) // The name of the created user in beforeEach hook. 124 | 125 | }); 126 | 127 | }); 128 | 129 | }); -------------------------------------------------------------------------------- /test/routes/useractions.js: -------------------------------------------------------------------------------- 1 | var request = require('supertest'); 2 | var app = require('../../app'); 3 | var db = require('../../models/index'); 4 | var should = require('should'); 5 | 6 | describe('UserActions Route', function() { 7 | 8 | describe('Logging Actions to Users', function(){ 9 | 10 | beforeEach(function(done){ 11 | //Destroy the database before running each test. 12 | db.sequelize.sync({force: true}).then(function() { 13 | done(); 14 | }).catch(function(err) { 15 | return done(err); 16 | }); 17 | }); 18 | 19 | it('Returns 201 status code', function(done) { 20 | request(app) 21 | .post('/useractions') 22 | .send('userId=123&publisherId=456') 23 | .expect(201, done); 24 | }); 25 | 26 | it('Returns application/json format', function(done) { 27 | request(app) 28 | .post('/useractions') 29 | .send('userId=123&publisherId=456') 30 | .expect('Content-Type', /application\/json/, done); 31 | }); 32 | 33 | it('Returns the id of the UserAction', function(done) { 34 | // Id that will be returned is the ID of the UserAction pair! 35 | request(app) 36 | .post('/useractions') 37 | .send('userId=123&publisherId=456') 38 | .expect(function(response){ 39 | response.body.userActionId.should.be.above(0).and.be.a.Number 40 | }).end(done); 41 | }); 42 | 43 | it('Returns status message "created"', function(done) { 44 | request(app) 45 | .post('/useractions') 46 | .send('userId=123&publisherId=456') 47 | .expect(function(response){ 48 | response.body.status.should.be.equal('created'); 49 | }).end(done); 50 | }); 51 | }); 52 | describe('Fetching a user action', function(done) { 53 | beforeEach(function(done) { 54 | db.sequelize.sync({force: true}).then(function() { 55 | db.Publisher.create({}).then(function(publisher) { 56 | db.User.create({publisherId: publisher.dataValues.id}).then(function(user) { 57 | db.ActionType.create({publisherId: publisher.dataValues.id}).then(function(actionType) { 58 | db.UserAction.create({actionTypeId: actionType.dataValues.id, userId: user.dataValues.id}); 59 | done(); 60 | }); 61 | }); 62 | }); 63 | }); 64 | }); 65 | it('Returns status code 200 if the record was found', function(done) { 66 | request(app) 67 | .get('/useractions/1') 68 | .expect(200, done); 69 | }); 70 | it('Returns status code 404 if the record was not found', function(done) { 71 | request(app) 72 | .get('/useractions/30') 73 | .expect(404, done); 74 | }); 75 | }); 76 | 77 | describe('Deleting a user action', function(done) { 78 | beforeEach(function(done) { 79 | db.sequelize.sync({force: true}).then(function() { 80 | db.Publisher.create({}).then(function(publisher) { 81 | db.User.create({publisherId: publisher.dataValues.id}).then(function(user) { 82 | db.ActionType.create({publisherId: publisher.dataValues.id}).then(function(actionType) { 83 | db.UserAction.create({actionTypeId: actionType.dataValues.id, userId: user.dataValues.id}); 84 | done(); 85 | }); 86 | }); 87 | }); 88 | }); 89 | }); 90 | it('Returns status message "deleted" if record is found', function(done) { 91 | request(app) 92 | .delete('/useractions/1') 93 | .expect(function(response) { 94 | response.body.status.should.be.equal('deleted'); 95 | }).end(done); 96 | }); 97 | it('Returns status code 404 if the record was not found', function(done) { 98 | request(app) 99 | .delete('/useractions/30') 100 | .expect(404, done); 101 | }); 102 | }); 103 | }); -------------------------------------------------------------------------------- /routes/publishers.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var urlEncoded = bodyParser.urlencoded({ 4 | extended: false 5 | }); 6 | var uuid = require('node-uuid'); 7 | var auth = require('../auth.js'); 8 | var router = express.Router(); 9 | var id = uuid.v4(); 10 | var secret = uuid.v4(); 11 | var passport = require('passport'); 12 | var passportLocal = require('passport-local'); 13 | var publisherAuth = require('../lib/publisherAuth.js'); 14 | var localStrategy = require('../lib/localStrategy'); 15 | var actiontypes = require('../routes/actiontypes.js'); 16 | var Publisher = require('../Models/index.js').Publisher; 17 | var viewActionType = require('../lib/viewActionType.js'); 18 | 19 | var publisherBuilder = function(req, res, next) { 20 | var publisher = { 21 | name: req.body.name, 22 | domain: req.body.domain, 23 | email: req.body.email, 24 | channel: req.body.channel, 25 | apikey: id + ':' + secret 26 | }; 27 | req.body.publisher = publisher; 28 | next(); 29 | 30 | }; 31 | 32 | //passport session setup. 33 | passport.serializeUser(function(user, done) { 34 | console.log('serializing ' + user.name); 35 | done(null, user); 36 | }); 37 | 38 | passport.deserializeUser(function(obj, done) { 39 | console.log('deserializing ' + obj); 40 | done(null, obj); 41 | }); 42 | 43 | router.route('/') 44 | .post(urlEncoded, publisherBuilder, function(req, res) { 45 | var publisher = req.body.publisher; 46 | Publisher.create(publisher).then(function(createdPublisher) { 47 | res.status(201).json({ 48 | status: 'created', 49 | publisherId: createdPublisher.dataValues.id, 50 | apikey: createdPublisher.dataValues.apikey 51 | }); 52 | }, function(err) { 53 | res.status(404).json({ 54 | status: 'ERROR', 55 | message: 'Something went wrong ' + err 56 | }); 57 | }); 58 | }); 59 | 60 | //Creating a profile, and passing the publisher's name, and their action types to the view. 61 | router.route('/profile') 62 | .get(function(req, res) { 63 | if (req.isAuthenticated()) { 64 | viewActionType.viewActionTypes(req.user.id).then(function(result) { 65 | res.render('profile', { 66 | name: req.user.name, 67 | title: 'Publisher Profile', 68 | actiontypes: result 69 | }); 70 | }); 71 | } else { 72 | res.redirect('/publishers/signup'); 73 | } 74 | }); 75 | 76 | router.route('/createaction') 77 | .get(function(req, res) { 78 | res.render('createAction', { 79 | title: 'Create Action' 80 | }); 81 | }); 82 | 83 | //Rendering the sign in view on the route publishers/signin 84 | router.route('/signin') 85 | .get(function(req, res) { 86 | res.render('signin', { 87 | title: 'Publisher Sign In' 88 | }); 89 | }) 90 | //Signing in the publisher using passport's authentication 91 | .post(passport.authenticate('local-signin', { 92 | successRedirect: '/publishers/profile', 93 | failureRedirect: '/publishers/signin' 94 | })); 95 | 96 | //Logging out on the route publishers/logout 97 | router.route('/logout') 98 | .get(function(req, res) { 99 | req.logout(); 100 | res.redirect('/publishers/signup'); 101 | }); 102 | 103 | //rendering view homepage whenever the publisher wants to signup 104 | router.route('/signup') 105 | .get(function(req, res) { 106 | res.render('homepage.ejs', { 107 | title : 'Publisher Sign Up' 108 | }) 109 | }) //signing up using passport 110 | .post(passport.authenticate('local-signup', { 111 | successRedirect: '/publishers/profile', 112 | failureRedirect: '/publishers/signup' 113 | })); 114 | 115 | module.exports = router; -------------------------------------------------------------------------------- /test/routes/actiontypes.js: -------------------------------------------------------------------------------- 1 | var request = require('supertest'); 2 | var app = require('../../app'); 3 | var db = require('../../models/index'); 4 | var should = require('should'); 5 | 6 | describe('ActionTypes Route', function() { 7 | 8 | describe('Creating new action type', function(){ 9 | 10 | beforeEach(function(done){ 11 | //Destroy the database before running each test. 12 | db.sequelize.sync({force: true}).then(function() { 13 | done(); 14 | }).catch(function(err) { 15 | return done(err); 16 | }); 17 | }); 18 | 19 | it('Returns 201 status code', function(done) { 20 | request(app) 21 | .post('/actiontypes') 22 | .send('actionName=LIKE&actionWeight=5&publisherId=123') 23 | .expect(201, done); 24 | }); 25 | 26 | it('Returns application/json format', function(done) { 27 | request(app) 28 | .post('/actiontypes') 29 | .send('actionName=LIKE&actionWeight=5&publisherId=123') 30 | .expect('Content-Type', /application\/json/, done); 31 | }); 32 | 33 | it('Returns the id of the created action type', function(done) { 34 | request(app) 35 | .post('/actiontypes') 36 | .send('actionName=LIKE&actionWeight=5&publisherId=123') 37 | .expect(function(response){ 38 | response.body.actionTypeId.should.be.above(0).and.be.a.Number 39 | }).end(done); 40 | }); 41 | 42 | it('Returns status message "created"', function(done) { 43 | request(app) 44 | .post('/actiontypes') 45 | .send('actionName=LIKE&actionWeight=5&publisherId=123') 46 | .expect(function(response){ 47 | response.body.status.should.be.equal('created'); 48 | }).end(done); 49 | }); 50 | }); 51 | 52 | describe('Fetching an action type', function() { 53 | beforeEach(function(done) { 54 | db.sequelize.sync({force: true}).then(function() { 55 | db.Publisher.create({}).then(function() { 56 | db.ActionType.create({actionName: 'FetcherTester', publisherId:1}); 57 | done(); 58 | }); 59 | }); 60 | }); 61 | it('Returns status code 200 if the record was found', function(done) { 62 | request(app) 63 | .get('/actiontypes/1') 64 | .expect(200, done); 65 | }); 66 | it('Returns status code 404 if the record was not found', function(done) { 67 | request(app) 68 | .get('/actiontypes/30') 69 | .expect(404, done); 70 | }); 71 | }); 72 | describe('Updating an action type', function(){ 73 | beforeEach(function(done) { 74 | db.sequelize.sync({force: true}).then(function() { 75 | db.Publisher.create({}).then(function() { 76 | db.ActionType.create({actionName: 'UpdatingTester', publisherId:1}); 77 | done(); 78 | }); 79 | }); 80 | }); 81 | it('Returns status message "updated" if record is found', function(done) { 82 | request(app) 83 | .put('/actiontypes/1') 84 | .send('actionName=SHARE&actionWeight=4') 85 | .expect(function(response) { 86 | response.body.status.should.be.equal('updated'); 87 | }).end(done); 88 | }); 89 | it('Returns status code 404 if the record was not found', function(done) { 90 | request(app) 91 | .put('/actiontypes/30') 92 | .expect(404, done); 93 | }); 94 | }); 95 | describe('Deleting an action type', function() { 96 | beforeEach(function(done) { 97 | db.sequelize.sync({force: true}).then(function() { 98 | db.Publisher.create({}).then(function() { 99 | db.ActionType.create({actionName: 'UpdatingTester', publisherId:1}); 100 | done(); 101 | }); 102 | }); 103 | }); 104 | it('Returns status message "deleted" if record is found', function(done) { 105 | request(app) 106 | .delete('/actiontypes/1') 107 | .expect(function(response) { 108 | response.body.status.should.be.equal('deleted'); 109 | }).end(done); 110 | }); 111 | it('Returns status code 404 if the record was not found', function(done) { 112 | request(app) 113 | .delete('/actiontypes/30') 114 | .expect(404, done); 115 | }); 116 | }); 117 | }); --------------------------------------------------------------------------------