├── .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 |
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 |
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 |
20 |
21 |
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 |
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 | });
--------------------------------------------------------------------------------