diff --git a/server/README.md b/server/README.md deleted file mode 100644 index 252d542..0000000 --- a/server/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# votely-server - -## Setup - -Install dependencies by running `npm install`. - -To start the server, execute `npm run`. - -### Environment Variables - -You must set the following environment variables: - -- `AWS_BUCKET` - The name of the AWS bucket you want to upload images into. - -### AWS User - -Additionally, you should [set your AWS credentials][aws-credentials]. One easy way to do it is to set the following environment variables: - -- `AWS_ACCESS_KEY_ID` -- `AWS_SECRET_ACCESS_KEY` - -## Tests - -Tests are located in `./test`. To run tests, execute `npm test`. - - - - -[aws-credentials]: http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html diff --git a/server/app/controllers/account/create.js b/server/app/controllers/account/create.js deleted file mode 100644 index e6e876a..0000000 --- a/server/app/controllers/account/create.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -const accountModel = require('../../models/account'); -const authentication = require('../../lib/authentication'); -const traitModel = require('../../models/trait'); -const completedVotesModel = require('../../models/completedVotes'); -const traits = require('../../../bin/traits'); -const _ = require('lodash'); - -const create = function* create() { - const body = this.request.body; - const facebookId = body.facebookId; - const accessToken = body.access_token; - const DEFAULT_TRAITS = _.map(traits.defaultTraits, function(traitTemplate) { - return traitModel.newTrait(traitTemplate.id, traitTemplate.themes); - }); - try { - const acctOpts = yield { - defaultTraits: traitModel.addBulk(DEFAULT_TRAITS), - friends: accountModel.getFriends(facebookId, accessToken), - picture: accountModel.getPicture(facebookId, accessToken), - profile: accountModel.getProfile(facebookId, accessToken), - completedVotes: completedVotesModel.createForAcct(facebookId) - }; - yield [ - accountModel.addAcctToFriends(facebookId, acctOpts.friends), - accountModel.add({ - viewed: { - walkthrough: false, - dragText: false, - traitNote: false - }, - facebookId: facebookId, - traits: _.map(acctOpts.defaultTraits, 'id'), - friends: _.map(acctOpts.friends, 'id'), - accessToken: accessToken, - profilePicture: acctOpts.picture, - name: acctOpts.profile.name - }) - ]; - - yield authentication.login.call(this); - } catch (err) { - this.body = err.message; - this.status = 500; - console.error(err); - } -}; - -/** - * Exports. - */ - -module.exports = create; diff --git a/server/app/controllers/account/current.js b/server/app/controllers/account/current.js deleted file mode 100644 index ef88f00..0000000 --- a/server/app/controllers/account/current.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const accountModel = require('../../models/account'); -const _ = require('lodash'); - -const current = function* current() { - // const userId = _.get(this.session, 'passport.user'); - // const acct = yield accountModel.get(userId); - const acct = yield accountModel.getByFacebookId('mock_facebookId4'); - - if (!acct) { - this.status = 403; - } else { - this.status = 200; - this.body = acct; - } -}; - -module.exports = current; diff --git a/server/app/controllers/account/get.js b/server/app/controllers/account/get.js deleted file mode 100644 index 39f40e8..0000000 --- a/server/app/controllers/account/get.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -const accountModel = require('../../models/account'); -/** - * Find a photo by ID. - */ -const find = function* find() { - const id = this.params.id; - const account = yield accountModel.get(id); - if (!account) { - this.status = 404; - return; - } - - this.body = account; - this.status = 200; -}; - -/** - * Exports. - */ - -module.exports = find; diff --git a/server/app/controllers/account/index.js b/server/app/controllers/account/index.js deleted file mode 100644 index 844bf64..0000000 --- a/server/app/controllers/account/index.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const app = require('koa')(); -const router = require('koa-router')(); - -router.post('/', require('./create')); -router.post('/viewed', require('./viewed')); -router.get('/current', require('./current')); -router.get('/:id', require('./get')); - -app.use(router.routes()); -app.use(router.allowedMethods()); - -module.exports = app; diff --git a/server/app/controllers/account/viewed.js b/server/app/controllers/account/viewed.js deleted file mode 100644 index 809ade8..0000000 --- a/server/app/controllers/account/viewed.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -const accountModel = require('../../models/account'); -const viewComponents = require('../../models/schemas').viewComponents; -const _ = require('lodash'); - -const current = function* current() { - const body = this.request.body; - const acctId = body.id; - const component = body.component; - if(_.contains(viewComponents, component)) { - try { - yield accountModel.setComponentViewed(acctId, component); - this.body = 200; - } catch(e) { - console.error(e); - this.body = e.message; - this.status = 500; - } - } else { - this.status = 400; - this.body = 'Unknown component ' + component; - } -}; - -module.exports = current; diff --git a/server/app/controllers/feedback/create.js b/server/app/controllers/feedback/create.js deleted file mode 100644 index 8c41c52..0000000 --- a/server/app/controllers/feedback/create.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -const feedbackModel = require('../../models/feedback'); -const nodemailer = require('nodemailer'); - -if (!process.env.SUPPORT_EMAIL || !process.env.SUPPORT_PASSWORD) { - console.error('MISSING SUPPORT_EMAIL AND SUPPORT_PASSWORD, FEEDBACK WILL NOT SEND EMAILS'); -} - -const transporter = nodemailer.createTransport({ - service: 'gmail', - auth: { - user: process.env.SUPPORT_EMAIL, - pass: process.env.SUPPORT_PASSWORD - } -}); -const accountModel = require('../../models/account'); -/** - * upload a photo. Handles multipart uploads only. - */ -const create = function* create() { - try { - const body = this.request.body; - const text = body.feedbackText; - const facebookId = body.facebookId; - const email = body.email; - - const vals = yield [ - accountModel.getByFacebookId(facebookId), - feedbackModel.add({ - facebookId: facebookId, - text: text, - email: email - }) - ]; - - if (process.env.NODE_ENV !== 'test') { - const account = vals[0]; - transporter.sendMail({ - from: 'scottzhang235@gmail.com', - to: 'scottzhang235@gmail.com', - subject: 'I GOTZ APP FEEDBACK', - text: text + ' EMAIL: ' + email + ' USER OBJECT: ' + JSON.stringify(account) - }, function() { - console.log('node email cb arguments: ', arguments); - }); - } - - this.status = 200; - } catch (e) { - console.error('error sending feedback', e); - this.status = 500; - } -}; - -/** - * Exports. - */ - -module.exports = create; - diff --git a/server/app/controllers/feedback/index.js b/server/app/controllers/feedback/index.js deleted file mode 100644 index bf2fc06..0000000 --- a/server/app/controllers/feedback/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const app = require('koa')(); -const router = require('koa-router')(); - -router.post('/', require('./create')); - -app.use(router.routes()); -app.use(router.allowedMethods()); - -module.exports = app; diff --git a/server/app/controllers/trait/get.js b/server/app/controllers/trait/get.js deleted file mode 100644 index 6be45ad..0000000 --- a/server/app/controllers/trait/get.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -const traitModel = require('../../models/trait'); -const denormalizeTrait = require('../../services/denormalizeTrait'); - -const get = function* get() { - const id = this.params.id; - const trait = yield traitModel.get(id); - if (!trait) { - this.status = 404; - return; - } - - const denormalizedTrait = yield denormalizeTrait(trait); - this.body = denormalizedTrait; - this.status = 200; -}; - -/** - * Exports. - */ - -module.exports = get; diff --git a/server/app/controllers/trait/index.js b/server/app/controllers/trait/index.js deleted file mode 100644 index 810aba3..0000000 --- a/server/app/controllers/trait/index.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -const app = require('koa')(); -const router = require('koa-router')(); - -router.get('/query/:facebookId', require('./query')); -router.get('/:id', require('./get')); - -app.use(router.routes()); -app.use(router.allowedMethods()); - -module.exports = app; diff --git a/server/app/controllers/trait/query.js b/server/app/controllers/trait/query.js deleted file mode 100644 index ea1b39a..0000000 --- a/server/app/controllers/trait/query.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const traitModel = require('../../models/trait'); -const accountModel = require('../../models/account'); - -const query = function* query() { - const facebookId = this.params.facebookId; - const account = yield accountModel.getByFacebookId(facebookId); - - if (!account) { - this.status = 404; - this.body = 'No user found'; - return; - } - - const traits = yield traitModel.query({ - id: { $in: account.traits } - }); - - this.body = traits; - this.status = 200; -}; - -/** - * Exports. - */ - -module.exports = query; diff --git a/server/app/controllers/votes/index.js b/server/app/controllers/votes/index.js deleted file mode 100644 index 638e1fd..0000000 --- a/server/app/controllers/votes/index.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -const app = require('koa')(); -const router = require('koa-router')(); - -router.get('/:facebookId', require('./query')); -router.post('/:id', require('./submit')); - -app.use(router.routes()); -app.use(router.allowedMethods()); - -module.exports = app; diff --git a/server/app/controllers/votes/query.js b/server/app/controllers/votes/query.js deleted file mode 100644 index 4c04e4a..0000000 --- a/server/app/controllers/votes/query.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -const createVotes = require('../../services/createVotes'); -const denormalizeVotes = require('../../services/denormalizeVotes'); -const voteModel = require('../../models/vote'); -const _ = require('lodash'); - -const query = function* query() { - const facebookId = this.params.facebookId; - yield createVotes(facebookId); - const votes = yield voteModel.query({voterId: facebookId, selected: null}); - const denormalizedVotes = yield denormalizeVotes(votes); - - this.body = _.shuffle(denormalizedVotes); - this.status = 200; -}; - -/** - * Exports. - */ - -module.exports = query; diff --git a/server/app/controllers/votes/submit.js b/server/app/controllers/votes/submit.js deleted file mode 100644 index 9bba819..0000000 --- a/server/app/controllers/votes/submit.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict'; - -const voteModel = require('../../models/vote'); -const accountModel = require('../../models/account'); -const _ = require('lodash'); - -//Submitting a vote : -//Updates the vote obj to have a selected field -//Updates relevant trait according to each contestant - -const submit = function* submit() { - const body = this.request.body; - const voteId = this.params.id; - const selected = body.selected; - const score = body.score; - - try { - yield voteModel.submit(voteId, selected, score); - const vote = yield voteModel.get(voteId); - - yield [_.map(vote.contestants, function(fbId) { - return accountModel.incrementTraitByTemplateId(fbId, vote.traitTemplateId, fbId === selected, vote); - })]; - - this.status = 200; - } catch(err) { - console.error(err); - this.status = 500; - } -}; - -/** - * Exports. - */ - -module.exports = submit; diff --git a/server/app/db.js b/server/app/db.js deleted file mode 100644 index 84fb04b..0000000 --- a/server/app/db.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -const monk = require('monk'); -const semver = require('semver'); -const util = require('util'); -const q = require('q'); -const uuid = require('uuid'); -const co = require('co'); -function* validateMongoVersion(db) { - const EXPECTED_MONGO_VERSION = '3.0.x'; - - function promisifiedBuildInfo() { - const deferred = q.defer(); - db.admin().buildInfo( - function(err, res) { - if (err) return deferred.reject(err); - deferred.resolve(res); - }, - function(err) { - console.error('error checking mongo version', err); - deferred.reject(err); - } - ); - return deferred.promise; - } - - promisifiedBuildInfo().then(function(res) { - const version = res.version; - - if (!semver.satisfies(version, EXPECTED_MONGO_VERSION)) { - throw new Error(util.format( - 'Mongo version is %s, but Votally requires version %s. Exiting...', - version, EXPECTED_MONGO_VERSION - )); - } else { - return null; - } - }); -} - -module.exports = (function() { - const isTest = process.env.NODE_ENV === 'test'; - - var mongoUri = (function() { - return isTest ? 'localhost/qelf_test_' + uuid.v4() : (process.env.APP_HOST || 'localhost') + '/qelf'; - })(); - const db = monk(mongoUri, { - w: 1, - j: true, - native_parser: true, - poolSize: 25 - }); - - co(function* () { - yield validateMongoVersion(db.driver); - }); - - if (isTest) { - process.on('exit', function() { - db.driver.dropDatabase(mongoUri, function(err) { - if (err) return console.log(err); - }); - }); - } - - return db; -})(); diff --git a/server/app/index.js b/server/app/index.js deleted file mode 100644 index 21fea69..0000000 --- a/server/app/index.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const bodyParser = require('koa-bodyparser'); -const koa = require('koa'); -const route = require('koa-route'); -const mount = require('koa-mount'); -const logger = require('koa-logger'); -const cors = require('kcors'); -const authentication = require('./lib/authentication'); - -const app = koa(); - -/** - * Global middleware. - */ -app.use(bodyParser({ - formLimit: '10mb' -})); -app.use(cors({ - credentials: true -})); -app.use(logger()); -authentication.initialize(app); - -/** - * Routes. - */ -app.use(mount('/login', require('./login'))); -app.use(mount('/account', require('./controllers/account'))); -app.use(mount('/trait', require('./controllers/trait'))); -app.use(mount('/feedback', require('./controllers/feedback'))); -app.use(mount('/vote', require('./controllers/votes'))); -app.use(route.post('/logout', function *() { - this.session = null; - this.body = null; - this.status = 200; -})); -/** - * Exports. - */ - -module.exports = app; diff --git a/server/app/lib/authentication.js b/server/app/lib/authentication.js deleted file mode 100644 index dde6ac0..0000000 --- a/server/app/lib/authentication.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -const session = require('koa-session-store'); -const mongoStore = require('koa-session-mongo'); -const db = require('../db'); -const passport = require('koa-passport'); -const accountModel = require('../models/account'); -const FacebookStrategy = require('passport-facebook-token'); -const co = require('co'); - -passport.serializeUser(function(user, done) { - done(null, user.id); -}); - -passport.deserializeUser(function (id, done) { - co(function* () { - const user = yield accountModel.get(id); - done(null, user); - }); -}); - -passport.use(new FacebookStrategy({ - clientID: '201708533509741', //FACEBOOK_APP_ID - clientSecret: '2815fd63ddaf3161387ec1ef760b66a7', //FACEBOOK_APP_SECRET -}, function (accessToken, refreshToken, profile, done) { - co(function* () { - let account = yield accountModel.getByFacebookId(profile.id); - if (!account) { - console.log('No such account: ', profile); - return done(null, false); - } - if (account.accessToken !== accessToken) { - yield accountModel.updateById(account.id, { - accessToken: accessToken - }); - account = yield accountModel.getByFacebookId(profile.id); - } - - done(null, account); - }); -})); - -module.exports = { - initialize: function(app) { - app.keys = ['secrsset']; - app.use(session({ - cookie: { - maxAge: 1000000000, - httpOnly: false - }, - store: mongoStore.create({ - db: db.driver, - collection: 'sessions' - }) - })); - - app.use(passport.initialize()); - app.use(passport.session()); - }, - passport: passport, - isAuthenticated: function* (next) { - if (this.isAuthenticated()) { - yield next; - } else { - throw new Error('Authentication error'); - } - }, - login: function () { - const self = this; - return passport.authenticate('facebook-token', function* (err, user, info) { - if (err) throw err; - if (user === false) { - console.error('Authentication error: ', info); - self.status = 403; - } else { - self.status = 200; - self.body = user; - yield self.login(user); - } - }); - } -}; diff --git a/server/app/lib/aws.js b/server/app/lib/aws.js deleted file mode 100644 index 5839712..0000000 --- a/server/app/lib/aws.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const AWS = require('aws-sdk'); - -const AWS_CONFIG = { - accessKeyId: process.env.AWS_ACCESS_KEY, - secretAccessKey: process.env.AWS_SECRET, -}; - -AWS.config.update(AWS_CONFIG); -const s3 = new AWS.S3(); - -/** - * Upload a photo to S3. - * - * @param {stream.Readable} contents - * @param {string} key to save file as - * @return {Promise} - */ -const upload = function upload(contents, key) { - const params = { - Body: contents, - Bucket: process.env.AWS_BUCKET, - Key: key - }; - - return new Promise(function(resolve, reject) { - s3.upload(params, function(err, data) { - if (err) return reject(err); - resolve(data); - }); - }); -}; - -module.exports = { - upload: upload -}; diff --git a/server/app/lib/facebook.js b/server/app/lib/facebook.js deleted file mode 100644 index 3f6d059..0000000 --- a/server/app/lib/facebook.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const request = require('koa-request'); -const FB_API_HOST = 'graph.facebook.com/v2.5/'; -const _ = require('lodash'); - -const get = function* (fbId, access_token, route, opts) { - const qs = _.defaults({ - access_token: access_token - }, opts || {}); - const options = { - url: 'https://' + FB_API_HOST + fbId + (route ? '/' + route : ''), - qs: qs, - headers: { 'User-Agent': 'request' } - }; - - const response = yield request(options); - return JSON.parse(response.body); -}; - -const getFriends = function* getFriends(facebookId, access_token) { - const res = yield get(facebookId, access_token, 'friends'); - console.log(res.data); - return res.data; -}; - -const getPicture = function* getPicture(facebookId, access_token) { - const res = yield get(facebookId, access_token, 'picture', {type: 'large', redirect: false}); - return res.data.url; -}; - -const getProfile = function* getProfile(facebookId, access_token) { - const res = yield get(facebookId, access_token, ''); - return res; -}; - -module.exports = { - getPicture: getPicture, - getFriends: getFriends, - getProfile: getProfile -}; diff --git a/server/app/login.js b/server/app/login.js deleted file mode 100644 index 7303b68..0000000 --- a/server/app/login.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const app = require('koa')(); -const router = require('koa-router')(); -const authentication = require('./lib/authentication'); - -router.post('/', function* () { - yield authentication.login.call(this); -}); - -app.use(router.routes()); -app.use(router.allowedMethods()); - -module.exports = app; diff --git a/server/app/models/account.js b/server/app/models/account.js deleted file mode 100644 index 16ef14b..0000000 --- a/server/app/models/account.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('account'); -const facebook = require('../lib/facebook'); -const traitModel = require('./trait'); -const AccountSchema = require('./schemas').account; - -const modelCRUD = require('./concerns/modelCRUD')('account', collection, AccountSchema); -const getByFacebookId = function getByFacebookId(facebookId) { - return collection.findOne({facebookId: facebookId}); -}; -const getFriends = facebook.getFriends; -const getPicture = facebook.getPicture; -const getProfile = facebook.getProfile; - -const incrementTraitByTemplateId = function* (fbId, templateId, increment, vote) { - const acct = yield getByFacebookId(fbId); - const trait = yield traitModel.getFromArrByTemplateId(acct.traits, templateId); - - yield traitModel.incrementTrait(trait.id, increment, vote); -}; - -const setComponentViewed = function* setComponentViewed(id, component) { - var update = {}; - update['viewed.' + component] = true; - try { - yield modelCRUD.updateById(id, update); - } catch (e) { - console.error('error completing walkthrough', e); - throw e; - } -}; - -const add = function* add(toAdd) { - const existingUser = yield collection.findOne({ - facebookId: toAdd.facebookId - }); - - if (existingUser) { - this.status = 400; - throw new Error('attempting to add duplicate user', existingUser); - } - - const added = yield* modelCRUD.create(toAdd); - return added; -}; - -const addAcctToFriends = function(fbId, friends) { - return collection.update( - { friends: { $in: friends } }, - { $push: { friends: fbId } } - ); -}; - -module.exports = { - add: add, - get: modelCRUD.get, - query: modelCRUD.query, - getByFacebookId: getByFacebookId, - getFriends: getFriends, - getPicture: getPicture, - updateById: modelCRUD.updateById, - update: modelCRUD.update, - incrementTraitByTemplateId: incrementTraitByTemplateId, - getProfile: getProfile, - addAcctToFriends: addAcctToFriends, - setComponentViewed : setComponentViewed, - //FOR TESTING ONLY - clear: function* () { - yield collection.remove({}); - } -}; diff --git a/server/app/models/completedVotes.js b/server/app/models/completedVotes.js deleted file mode 100644 index 155b85c..0000000 --- a/server/app/models/completedVotes.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('completedVotes'); -const _ = require('lodash'); -const CompletedVotesSchema = require('./schemas').completedVotes; - -const modelCRUD = require('./concerns/modelCRUD')('completedVotes', collection, CompletedVotesSchema); -const push = function* push(facebookId, votes) { - const isVoteArr = _.isArray(votes); - const toPush = isVoteArr ? votes : [votes]; - if (_.isEmpty(toPush)) return; - - yield collection.update({facebookId: facebookId}, { - $push: { - complete: { $each: toPush } - } - }); -}; -const getByFacebookId = function getByFacebookId(facebookId) { - return collection.findOne({facebookId: facebookId}); -}; -const createForAcct = function* createForAcct(fbId) { - yield modelCRUD.create({ - facebookId: fbId, - complete: [] - }); -}; - -module.exports = { - add: modelCRUD.create, - push: push, - createForAcct: createForAcct, - getByFacebookId: getByFacebookId, - query: modelCRUD.query, - //FOR TESTING ONLY - clear: function* () { - yield collection.remove({}); - } -}; diff --git a/server/app/models/concerns/modelCRUD.js b/server/app/models/concerns/modelCRUD.js deleted file mode 100644 index 939b813..0000000 --- a/server/app/models/concerns/modelCRUD.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; - -const Joi = require('joi'); -const uuid = require('uuid'); -const _ = require('lodash'); - -function validate(obj, schema, collectionName) { - const validity = Joi.validate(obj, schema); - if (validity.error) { - console.log('Invalid ' + collectionName + ' object: ', JSON.stringify(obj)); - console.log('Error: ', validity.error); - throw validity.error; - } -} - -module.exports = function(collectionName, collection, schema) { - function bulkUpdate(ids, updateParams) { - return collection.update({id: {$in: ids}}, {$set: updateParams}, {multi: true}); - } - return { - bulkInsert: function* bulkInsert(toAdd) { - try { - const toAddWithIds = (function() { - return _.map(toAdd, function(v) { - const val = _.cloneDeep(v); - val.id = v.id || uuid.v4(); - return val; - }); - })(); - - _.each(toAddWithIds, function(v) { - validate(v, schema, collectionName); - }); - yield collection.insert(toAddWithIds); - return toAddWithIds; - } catch (err) { - console.error('error attempting to bulk insert ' + collectionName + ':', err); - } - }, - create: function* create(toAdd) { - try { - const existingId = toAdd.id; - toAdd.id = existingId || uuid.v4(); - - validate(toAdd, schema, collectionName); - if (existingId) { - const existingObj = yield collection.find({id: existingId}); - if (existingObj) throw new Error('attempted to add duplicate object'); - } - - yield collection.insert(toAdd); - return toAdd; - } catch (err) { - console.error('error attempting to create ' + collectionName + ':', err); - throw err; - } - }, - addOrUpdate: function addOrUpdate(obj) { - validate(obj, schema, collectionName); - return collection.update({id: obj.id}, obj, {upsert: true}); - }, - get: function get(id) { - return collection.findOne({id: id}); - }, - bulkUpdate: bulkUpdate, - updateById: function updateById(id, updateParams) { - return bulkUpdate([id], updateParams); - }, - update: function* update(query, updateParams) { - yield collection.update(query, {$set: updateParams}); - }, - query: function query(params) { - params = params || {}; - const optKeys = ['sort', 'limit', 'offset']; - const opts = _.pick(params, optKeys); - const filter = _.omit(params, optKeys); - - const q = collection.find(filter); - - if (opts.limit) { - q.limit(opts.limit); - } - - return q; - } - }; -}; diff --git a/server/app/models/feedback.js b/server/app/models/feedback.js deleted file mode 100644 index d073658..0000000 --- a/server/app/models/feedback.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('feedback'); -const FeedbackSchema = require('./schemas').feedback; - -const modelCRUD = require('./concerns/modelCRUD')('account', collection, FeedbackSchema); - -module.exports = { - add: modelCRUD.create -}; diff --git a/server/app/models/schemas/index.js b/server/app/models/schemas/index.js deleted file mode 100644 index 1be9bda..0000000 --- a/server/app/models/schemas/index.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -const Joi = require('joi'); -const _ = require('lodash'); - -const viewComponents = ['traitNote', 'dragText', 'walkthrough']; -const components = _.reduce(viewComponents, function(total, val) { - total[val] = Joi.boolean().required(); - return total; -}, {}); -const AccountSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - name: Joi.string().required(), - facebookId: Joi.string().required(), - accessToken: Joi.string().required(), - friends: Joi.array().items(Joi.string().description('facebookId of other account objects')).required(), - traits: Joi.array().items(Joi.string()).required().description('Array of strings that correspond to the id of trait objects'), - profilePicture: Joi.string().required().description('profile picture url'), - viewed: Joi.object().keys(components).required() -}); - -const VoteSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - traitTemplateId: Joi.string().required(), - contestants: Joi.array(Joi.string().description('facebookId of contestant').required()).required(), - comparison: Joi.string().required(), - selected: Joi.string().required().allow(null), - voterId: Joi.string().required(), - score: Joi.number().required().allow(null).description('Score between 0 - 100, representing % confidence of voter on their selection') -}); - -const CompletedVotesSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - complete: Joi.array().items(VoteSchema).required().description('an array of vote objects'), - facebookId: Joi.string().required() -}); - -const FeedbackSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - text: Joi.string().required(), - facebookId: Joi.string().required(), - email: Joi.string().required().allow('') -}); - -const TraitSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - templateId: Joi.string().required(), - themes: Joi.array().required().items(Joi.string()).description('An array of themes that the trait fits into'), - count: Joi.number().required(), - total: Joi.array().required().items(Joi.string()).description('An array of vote ids corresponding to completed votes') -}); - -const TraitTemplateSchema = Joi.object().keys({ - _id: Joi.string(), - id: Joi.string().required(), - comparisons: Joi.array().required().items(Joi.string().required()), - themes: Joi.array().required() -}); - -module.exports = { - account: AccountSchema, - completedVotes: CompletedVotesSchema, - feedback: FeedbackSchema, - trait: TraitSchema, - traitTemplate: TraitTemplateSchema, - vote: VoteSchema, - viewComponents: viewComponents -}; diff --git a/server/app/models/trait.js b/server/app/models/trait.js deleted file mode 100644 index 4f5348a..0000000 --- a/server/app/models/trait.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('trait'); -const _ = require('lodash'); -const TraitSchema = require('./schemas').trait; - -const modelCRUD = require('./concerns/modelCRUD')('trait', collection, TraitSchema); -const newTrait = function newTrait(templateId, themes) { - return { - templateId: templateId, - count: 0, - themes: themes || [], - total: [] - }; -}; - -const incrementTrait = function(id, incrementCount, vote) { - const update = _.merge({ $push: {total: vote.id } }, - (incrementCount ? {$inc: {count: 1}} : {}) - ); - - return collection.update({id: id}, update); -}; - -const getFromArrByTemplateId = function(traits, templateId) { - return collection.findOne({ - id: {$in: traits}, - templateId: templateId - }); -}; - -module.exports = { - get: modelCRUD.get, - add: modelCRUD.create, - update: modelCRUD.update, - newTrait: newTrait, - addBulk: modelCRUD.bulkInsert, - query: modelCRUD.query, - incrementTrait: incrementTrait, - getFromArrByTemplateId: getFromArrByTemplateId, - //FOR TESTING ONLY - clear: function* () { - yield collection.remove({}); - } -}; diff --git a/server/app/models/traitTemplate.js b/server/app/models/traitTemplate.js deleted file mode 100644 index 41f3bb2..0000000 --- a/server/app/models/traitTemplate.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('traitTemplate'); -const TraitTemplateSchema = require('./schemas').traitTemplate; - -const modelCRUD = require('./concerns/modelCRUD')('traitTemplate', collection, TraitTemplateSchema); - -module.exports = { - addOrUpdate: modelCRUD.addOrUpdate, - get: modelCRUD.get, - query: modelCRUD.query, - //FOR TESTING ONLY - clear: function* () { - yield collection.remove({}); - } -}; diff --git a/server/app/models/vote.js b/server/app/models/vote.js deleted file mode 100644 index ab3d9cb..0000000 --- a/server/app/models/vote.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const db = require('../db'); -const collection = db.get('vote'); -const VoteSchema = require('./schemas').vote; -const modelCRUD = require('./concerns/modelCRUD')('vote', collection, VoteSchema); - -const submit = function* submit(id, selected, score) { - yield modelCRUD.updateById(id, { - selected: selected, - score: score - }); -}; - -const newVote = function(fbId, comparison, contestants, traitTemplateId) { - return { - traitTemplateId: traitTemplateId, - voterId: fbId, - selected: null, - score: null, - comparison: comparison, - contestants: contestants - }; -}; - -module.exports = { - add: modelCRUD.create, - bulkAdd: modelCRUD.bulkInsert, - query: modelCRUD.query, - get: modelCRUD.get, - submit: submit, - newVote: newVote, - //FOR TESTING ONLY - clear: function* () { - yield collection.remove({}); - } -}; diff --git a/server/app/services/createVotes.js b/server/app/services/createVotes.js deleted file mode 100644 index 9d3ff95..0000000 --- a/server/app/services/createVotes.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; - -const voteModel = require('../models/vote'); -const accountModel = require('../models/account'); -const traitTemplateModel = require('../models/traitTemplate'); -const completedVotesModel = require('../models/completedVotes'); -const _ = require('lodash'); - -// returns a map describing created vote objects -// { -// trait : { -// userId1: { -// userId2: true, -// userId3: true -// }, -// userId4: { -// userId5: true -// } -// } -// } -function getCompletedMapByFriend(completedVotes) { - return _.reduce(completedVotes, function(total, vote) { - return _.set(total, vote.traitTemplateId + '.' + vote.contestants[0] + '.' + vote.contestants[1], true); - }, {}); -} - -function validateCombinationIsUnique(completedVoteMap, accountId, accountId2, traitTemplateId) { - return _.get(completedVoteMap, traitTemplateId + '.' + accountId + '.' + accountId2) || - _.get(completedVoteMap, traitTemplateId + '.' + accountId2 + '.' + accountId); -} - -function shuffleContestants(id1, id2) { - return Math.random() > 0.5 ? [id1, id2] : [id2, id1]; -} - -module.exports = function* (facebookId) { - const values = yield [accountModel.getByFacebookId(facebookId), traitTemplateModel.query({}), completedVotesModel.getByFacebookId(facebookId)]; - const account = values[0]; - const templates = values[1]; - const completedVotes = _.get(values[2], 'complete'); - const completedVoteMap = getCompletedMapByFriend(completedVotes); - - if (_.isEmpty(templates)) { - throw new Error('missing default traits, please run addTraits'); - } - - if (account.friends.length < 2) { - console.log('Not enough friends'); - return []; - } - - const TOTAL_POSSIBLE_VOTES = ((account.friends.length * ( account.friends.length - 1 )) / 2 ) * (templates.length); - if (completedVotes.length === TOTAL_POSSIBLE_VOTES) { - //don't need to create any more votes; - return []; - } - - const votes = _.reduce(account.friends, function(total, friendFBid1, key, coll) { - const unmatchedFBIds = coll.slice(key + 1); - const newVotes = _.map(unmatchedFBIds, function(friendFBid2) { - return _.map(templates, function(template) { - if (validateCombinationIsUnique(completedVoteMap, friendFBid1, friendFBid2, template.id)) return null; - const contestants = shuffleContestants(friendFBid2, friendFBid1); - return voteModel.newVote( - facebookId, - template.comparisons[Math.floor(Math.random() * template.comparisons.length)], - contestants, - template.id - ); - }); - }); - - return total.concat(newVotes); - }, []); - - const flattenedVotes = _.compact(_.flatten(votes)); - if (_.isEmpty(flattenedVotes)) return; - - const addedVotes = yield voteModel.bulkAdd(flattenedVotes); - yield completedVotesModel.push(facebookId, addedVotes); -}; diff --git a/server/app/services/denormalizeTrait.js b/server/app/services/denormalizeTrait.js deleted file mode 100644 index bce58d4..0000000 --- a/server/app/services/denormalizeTrait.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const voteModel = require('../models/vote'); -const traitTemplateModel = require('../models/traitTemplate'); - -module.exports = function* (trait) { - const voteIds = trait.total; - const traitTemplateId = trait.templateId; - - const vals = yield { - votes: voteModel.query({ - id: {$in: voteIds} - }), - traitTemplate: traitTemplateModel.get(traitTemplateId) - }; - - trait.total = vals.votes; - trait.template = vals.traitTemplate; - - return trait; -}; diff --git a/server/app/services/denormalizeVotes.js b/server/app/services/denormalizeVotes.js deleted file mode 100644 index a129ac1..0000000 --- a/server/app/services/denormalizeVotes.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const accountModel = require('../models/account'); -const _ = require('lodash'); - -module.exports = function* (votes) { - const contestantIds = _.uniq(_.flatten(_.map(votes, 'contestants'))); - const contestants = yield accountModel.query({ - facebookId: {$in: contestantIds} - }); - - return (function composeVotes() { - return _.map(votes, function(vote) { - const contestantIds = vote.contestants; - vote.contestants = [_.find(contestants, {facebookId: contestantIds[0]}), _.find(contestants, {facebookId: contestantIds[1]})]; - return vote; - }); - })(); -}; diff --git a/server/bin/addTraits.js b/server/bin/addTraits.js deleted file mode 100644 index 36e6499..0000000 --- a/server/bin/addTraits.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -const traits = require('./traits'); -const co = require('co'); - -function addDefaults() { - co(function* () { - yield traits.addDefault(); - }); -} - -addDefaults(); diff --git a/server/bin/initDev.js b/server/bin/initDev.js deleted file mode 100644 index ae5a2b0..0000000 --- a/server/bin/initDev.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; - -const accountModel = require('../app/models/account'); -const traitModel = require('../app/models/trait'); -const completedVotesModel = require('../app/models/completedVotes'); -const _ = require('lodash'); -const traits = require('./traits'); -const DEFAULT_TRAITS = _.map(traits.defaultTraits, function(trait) { - return traitModel.newTrait(trait.id, trait.themes); -}); -const users = ['mock_facebookId1', 'mock_facebookId2', 'mock_facebookId3', 'mock_facebookId4']; -const co = require('co'); -function getAllExcept(user) { - return _.filter(users, function(u) { - return u !== user; - }); -} -const user1 = { - facebookId: users[0], - name: 'Scott Zhang', - accessToken: 'mock_accessToken1', - friends: getAllExcept(users[0]), - profilePicture: 'https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xtp1/v/t1.0-9/12108274_10101564644192315_7334749882900604967_n.jpg?oh=e0fee8c71ce074b2ba8180193ae610bb&oe=56E3A4FB' -}; - -const user2 = { - facebookId: users[1], - name: 'Zach Pomerantz', - accessToken: 'mock_accessToken2', - friends: getAllExcept(users[1]), - profilePicture: 'https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xfa1/v/t1.0-9/1622790_2249316349597_120305514_n.jpg?oh=54347afaf810a3c18b31d52ad752d647&oe=56D65332' -}; - -const user3 = { - facebookId: users[2], - name: 'Adam D Richman', - accessToken: 'mock_accessToken3', - friends: getAllExcept(users[2]), - profilePicture: 'https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xaf1/v/t1.0-9/11389991_10153380756994173_3936534420190887871_n.jpg?oh=7414a2a09cb545c3c07d2f361474af7d&oe=56D91526' -}; - -const user4 = { - facebookId: users[3], - name: 'Sandra Picton Hollis', - accessToken: 'mock_accessToken4', - friends: getAllExcept(users[3]), - profilePicture: 'https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xtf1/v/t1.0-9/11222815_10101966010266737_978063582363883619_n.jpg?oh=1200337f37288c66fe78026ac4734257&oe=571A381D' -}; - -var mockUsers = [user1, user2, user3, user4]; -function addAcct(acct) { - co(function* () { - try { - yield traits.addDefault(); - const acctValues = yield [traitModel.addBulk(DEFAULT_TRAITS), completedVotesModel.createForAcct(acct.facebookId)]; - acct.traits = _.map(acctValues[0], 'id'); - yield* accountModel.add(acct); - } catch (e) { - console.error('error adding account', e); - } - }); -} -for (var i = 0; i < mockUsers.length; i++) { - try { - mockUsers[i].viewed = { - walkthrough: false, - dragText: false, - traitNote: false - }; - addAcct(mockUsers[i]); - } catch (err) { - console.error(err); - } -} diff --git a/server/bin/server b/server/bin/server deleted file mode 100755 index 7c272a0..0000000 --- a/server/bin/server +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -/** - * Module dependencies. - */ - -const app = require('../app'); - -/** - * Boot. - */ - -const port = process.env.PORT || 3000; -app.listen(port); diff --git a/server/bin/traits/index.js b/server/bin/traits/index.js deleted file mode 100644 index a5bd5fb..0000000 --- a/server/bin/traits/index.js +++ /dev/null @@ -1,262 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const traitTemplateModel = require('../../app/models/traitTemplate'); -//Rename -const THEMES = { - happiness: 'Traits that predict happiness (Kaufman @ UPenn)', - likeability: 'Traits that make you likeable (Norman Anderson)', - leadership: 'Traits measuring leadership potential (Cattell Leadership Potential Equation)', - friend: 'Traits of a good friend (Roberts-Griffin @ UPenn)' -}; - -//Trait names must fit into the sentence: "I scored really high in ___TRAIT___" -//Comparisons are meant to: -// 1. Be interesting to answer -// 2. Together, fully encompass the given trait -// 3. Concise -// 4. Has to be easy to answer ('Who is more inspiring' vs 'Who inspires you to be a better person?') - -const defaults = [ - { - id: 'Kindness', - comparisons: [ - 'Who is a more kind person?', - 'Who do you enjoy spending time with more?', - 'Who is more concerned about others?' - ], - themes: [THEMES.likeability] - }, - { - id: 'Thoughtfulness', - comparisons: [ - 'Who is a more thoughtful person?', - 'Who is more likely to remember your birthday?', - 'Who is more concerned about your well being?' //Hmm - ] - }, - { - id: 'Enthusiasm', - comparisons: [ - 'Who is a more enthusiastic person?', - 'Who is more energetic?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Intuitiveness', - comparisons: [ - 'Who has more intuition?', - 'Who is more likely to rely on their gut instinct?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Charisma', - comparisons: [ - 'Who is a more charismatic person?', - //'Who do you think ?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Emotional Stability', - comparisons: [ - 'Who is a more emotionally stable person?', - 'Who is more even-tempered?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Self Assurance', - comparisons: [ - 'Who is more confident?', - 'Who is more confident in their own decisions?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Positivity', - comparisons: [ - 'Who has a more positive attitude?', - 'Who is more likely to make the best out of a bad situation?' - ] - }, - { - id: 'Dominance', - comparisons: [ - 'Who has a more dominant personality?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Loving to Learn', - comparisons: [ - 'Who is a more curious person?', - 'Who is more likely to try out new things?', - 'Who likes to learn more?' //Hmm - ], - themes: [THEMES.happiness] - }, - { - id: 'Sincerity', - comparisons: [ - 'Who is a more sincere person?', - 'Who is less likely to talk about you behind your back?', - 'Who is more likely to tell you how they really feel rather than hold it in?' //HMMM - ], - themes: [THEMES.likeability] - }, - { - id: 'Honesty', - comparisons: [ - 'Who is a more honest person?', - 'Who is more likely to return excess change given to them by a cashier' - ], - themes: [THEMES.likeability, THEMES.leadership, THEMES.friend] - }, - { - id: 'Loyalty', - comparisons: [ - 'Who is a more loyal friend?', - 'During tough times, who\'s more likely to be there to support you?' - ], - themes: [THEMES.likeability] - }, - { - id: 'Gratitude', - comparisons: [ - 'Who is more grateful for things that happen?', - 'Who shows more gratitude for the things you do?' - ], - themes: [THEMES.happiness] - }, - { - id: 'Happiness', - comparisons: [ - 'Who is a happier person?' - ], - themes: [THEMES.happiness] - }, - { - id: 'Calmness', - comparisons: [ - 'Who is more calm?', - 'Who is more likely to keep their cool in a stressful situation?' - ] - }, - { - id: 'Trustworthiness', - comparisons: [ - 'Who do you trust more?' - ], - themes: [THEMES.likeability, THEMES.leadership, THEMES.friend] - }, - { - id: 'Social Boldness', - comparisons: [ - 'Who is more likely to put themselves out there?', - 'Who is less offended by criticism' - ], - themes: [THEMES.leadership] - }, - { - id: 'Inspiration', - comparisons: [ - 'Who is more inspiring?', - 'Who' - ] - }, - { - id: 'Patience', - comparisons: [ - 'Who is more patient?' - ] - }, - { - id: 'Likeability', - comparisons: [ - 'Who do you like more?' - ], - themes: [THEMES.likeability] - }, - { - id: 'Acceptance', - comparisons: [ - 'Who is more accepting of others?', - 'Who are you more comfortable being yourself around?', - ] - }, - { - id: 'Fun', - comparisons: [ - 'Who is more fun to hang out with?', - 'Who is more fun?' - ] - }, - { - id: 'Reliability', - comparisons: [ - 'Who is a more reliable person?', - 'Who keeps their promises more often?' - ] - }, - { - id: 'Integrity', - comparisons: [ - 'Who is more true to their word?', - 'Who has a stronger moral compass?' - ] - }, - { - id: 'Empathy', - comparisons: [ - 'Who is more able to see from your point of view?', - 'Who is more empathetic towards your point of view?' - ], - themes: [THEMES.likeability, THEMES.leadership] - }, - { - id: 'Conscientiousness', - comparisons: [ - 'Who has a higher standard for themselves and their work?', - 'Who is more organized and neat?', - 'Who is more self disciplined?' - ], - themes: [THEMES.leadership] - }, - { - id: 'Determination', - comparisons: [ - 'Who is a more determined person', - 'Who pushes themselves harder to succeed?' - ] - }, - { - id: 'Adaptability', - comparisons: [ - 'If time travelled to the 1800\'s, who do you think would adapt the most quickly?', - 'If woken up in a foreign country, who would be most likely to make it home unscathed?' - ] - }, - { - id: 'Supportive', - comparisons: [ - 'Who is a more supportive friend?', - 'Who are you more likely to turn to during hard times?' - ], - themes: [THEMES.friend] - } -]; - -module.exports = { - defaultTraits: defaults, - addDefault: function* () { - yield _.map(defaults, function(trait) { - if (!trait.themes) { - trait.themes = []; - } - return traitTemplateModel.addOrUpdate(trait); - }); - } -}; diff --git a/server/package.json b/server/package.json deleted file mode 100644 index 72bad36..0000000 --- a/server/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "server", - "version": "0.0.1", - "private": true, - "scripts": { - "start": "bin/server", - "test": "mocha" - }, - "dependencies": { - "async": "^1.5.0", - "aws-sdk": "2.1.49", - "co": "4.6.0", - "joi": "6.6.1", - "kcors": "1.0.1", - "koa": "1.1.2", - "koa-bodyparser": "2.0.1", - "koa-logger": "1.3.0", - "koa-mount": "1.3.0", - "koa-passport": "1.2.0", - "koa-request": "1.0.0", - "koa-route": "2.4.2", - "koa-router": "5.1.2", - "koa-session": "3.3.1", - "koa-session-mongo": "1.0.1", - "koa-session-store": "1.1.1", - "lodash": "3.10.1", - "mongodb": "1.4.39", - "monk": "1.0.1", - "nodemailer": "1.11.0", - "passport-facebook-token": "3.0.6", - "q": "1.4.1", - "semver": "5.0.1", - "uuid": "2.0.1" - }, - "devDependencies": { - "mocha": "2.3.0", - "nodemon": "1.4.1", - "proxyquire": "1.7.3", - "supertest": "1.1.0" - } -} diff --git a/server/test/.eslintrc b/server/test/.eslintrc deleted file mode 100644 index 93a0a95..0000000 --- a/server/test/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "env": { - "mocha": true, - "it": true - } -} diff --git a/server/test/account.js b/server/test/account.js deleted file mode 100644 index 674af9f..0000000 --- a/server/test/account.js +++ /dev/null @@ -1,108 +0,0 @@ -'use strict'; - -const agent = require('supertest').agent; -const app = require('./mockApp'); -const http = require('http'); -const uuid = require('uuid'); -const expect = require('expect.js'); -const testUtils = require('./testUtils'); -const completedVotesModel = require('../app/models/completedVotes'); -const co = require('co'); -const accountModel = require('../app/models/account'); - -describe('/account', function() { - beforeEach(testUtils.clearAll); - - let request; - let testUser; - beforeEach(function(done) { - request = agent(http.createServer(app.callback())); - const facebookId = uuid.v4(); - request - .post('/account') - .send({ - facebookId: facebookId, - access_token: 'test' - }) - .expect(200) - .end(function(err, res) { - if (err) throw err; - testUser = res.body; - done(); - }); - }); - - describe('POST /account', function() { - it('should create a new account', function(done) { - expect(testUser).to.be.ok(); - done(); - }); - it('should create a completed votes collection for given user', function(done) { - co(function* () { - const completedVotes = yield completedVotesModel.getByFacebookId(testUser.facebookId); - expect(completedVotes).to.be.ok(); - expect(completedVotes.complete).to.be.an('array'); - done(); - }).catch(function(err) { - console.log(err); - }); - }); - it('should 500 when missing required fields', function(done) { - request - .post('/account') - .expect(500, done); - }); - }); - //TODO - // describe('GET /current', function() { - // it('should create a new account', function(done) { - // expect(testUser).to.be.ok(); - // done(); - // }); - // }); - describe('GET /id', function() { - it('should get an account', function(done) { - request - .get('/account/' + testUser.id) - .expect(200) - .end(function(err, res) { - if (err) throw err; - const acct = res.body; - expect(acct.id).to.be(testUser.id); - done(); - }); - }); - }); - - describe('POST /viewed', function() { - it('should set viewed elements', function(done) { - request - .post('/account/viewed') - .send({ - id: testUser.id, - component: 'walkthrough' - }) - .expect(200) - .end(function(err) { - if (err) throw err; - co(function* () { - const acct = yield accountModel.get(testUser.id); - expect(acct.viewed.walkthrough).to.be(true); - done(); - }).catch(function(e) { - console.error(e); - throw e; - }); - }); - }); - it('should 400 when attempting to set non existant component', function(done) { - request - .post('/account/viewed') - .send({ - id: testUser.id, - component: 'made up' - }) - .expect(400, done); - }); - }); -}); diff --git a/server/test/createVotes.js b/server/test/createVotes.js deleted file mode 100644 index a184296..0000000 --- a/server/test/createVotes.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -const createVotes = require('../app/services/createVotes'); -const voteModel = require('../app/models/vote'); -const traitTemplateModel = require('../app/models/traitTemplate'); -const co = require('co'); -const expect = require('expect.js'); -const testUtils = require('./testUtils'); - -describe('createVotes', function() { - beforeEach(testUtils.clearAll); - - let MOCK_USER; - const traitTemplate = { - id: 'test', - comparisons: ['this is a comparison'], - themes: [] - }; - - beforeEach(function(cb) { - co(function* () { - yield traitTemplateModel.addOrUpdate(traitTemplate); - MOCK_USER = yield testUtils.createTestUser(null, null, { - friends: ['1', '2', '3', '4'] - }); - cb(); - }); - }); - - it('should add votes', function(done) { - const TEMPLATE_ID = traitTemplate.id; - co(function* () { - yield createVotes(MOCK_USER.facebookId); - const votes = yield voteModel.query({ - traitTemplateId: TEMPLATE_ID - }); - - const TOTAL_POSSIBLE_VOTES = ((MOCK_USER.friends.length * ( MOCK_USER.friends.length - 1 )) / 2 ); - expect(votes).to.be.an('array'); - expect(votes).to.have.length(TOTAL_POSSIBLE_VOTES); - done(); - }).catch(function(err) { - if (err) return console.log(err); - }); - }); -}); diff --git a/server/test/feedback.js b/server/test/feedback.js deleted file mode 100644 index 15d0428..0000000 --- a/server/test/feedback.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -const agent = require('supertest').agent; -const app = require('./mockApp'); -const http = require('http'); -const testUtils = require('./testUtils'); - -describe('/feedback', function() { - beforeEach(testUtils.clearAll); - let request; - - beforeEach(function () { - request = agent(http.createServer(app.callback())); - }); - - describe('POST /feedback', function() { - it('should create feedback', function(done) { - request - .post('/feedback') - .send({ - facebookId: 'test', - feedbackText: 'testFeedback', - email: '' - }) - .expect(200, done); - }); - }); -}); diff --git a/server/test/login.js b/server/test/login.js deleted file mode 100644 index 744f1a0..0000000 --- a/server/test/login.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -const agent = require('supertest').agent; -const app = require('./mockApp'); -const http = require('http'); -const uuid = require('uuid'); -const testUtils = require('./testUtils'); -const co = require('co'); -/** - * Tests. - */ - -describe('/login', function() { - beforeEach(testUtils.clearAll); - - let request; - let MOCK_USER; - beforeEach(function() { - request = agent(http.createServer(app.callback())); - }); - - beforeEach(function(done) { - co(function* () { - MOCK_USER = yield testUtils.createTestUser(); - done(); - }); - }); - - describe('POST /login', function() { - var facebookId = uuid.v4(); - it('should login an existing account', function(done) { - request - .post('/login') - .send({facebookId: facebookId}) - .expect(200, done); - }); - }); -}); diff --git a/server/test/mockApp.js b/server/test/mockApp.js deleted file mode 100644 index ec68613..0000000 --- a/server/test/mockApp.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const proxyquire = require('proxyquire'); -const accountModel = require('../app/models/account'); -const _ = require('lodash'); -const mockAuth = { - login: function* () { - const fbId = _.get(this, 'request.body.facebookId'); - if (fbId) { - this.body = yield accountModel.getByFacebookId(fbId); - } - this.status = 200; - } -}; -const app = proxyquire('../app', { - './controllers/account': proxyquire('../app/controllers/account', { - './create': proxyquire('../app/controllers/account/create', { - '../../lib/authentication': mockAuth, - '../../models/account': proxyquire('../app/models/account', { - '../lib/facebook': { - getPicture: function* () { - return 'test.jpeg'; - }, - getFriends: function* () { - return []; - }, - getProfile: function() { - return { - name: 'test' - }; - } - } - }) - }) - }), - './login': proxyquire('../app/login', { - './lib/authentication': mockAuth - }) -}); - -module.exports = app; diff --git a/server/test/testUtils.js b/server/test/testUtils.js deleted file mode 100644 index 95997c8..0000000 --- a/server/test/testUtils.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict' - -const accountModel = require('../app/models/account'); -const proxyquire = require('proxyquire'); -const createAccount = proxyquire('../app/controllers/account/create', { - '../../lib/authentication': { - login: function* () { - this.status = 200; - } - }, - '../../models/account': proxyquire('../app/models/account', { - '../lib/facebook': { - getPicture: function* () { - return 'test.jpeg'; - }, - getFriends: function* () { - return []; - }, - getProfile: function* () { - return { - name: 'test' - }; - } - } - }) -}); -const _ = require('lodash'); -const traitModel = require('../app/models/trait'); -const voteModel = require('../app/models/vote'); -const completedVotesModel = require('../app/models/completedVotes'); -const traitTemplateModel = require('../app/models/traitTemplate'); -const co = require('co'); - -module.exports = { - clearAll: function(cb) { - co(function* () { - yield accountModel.clear(); - yield traitModel.clear(); - yield traitTemplateModel.clear(); - yield voteModel.clear(); - yield completedVotesModel.clear(); - cb(); - }).catch(function(err) { console.log(err); }); - }, - createTestUser: function* (_facebookId, accessToken, opts) { - const facebookId = _facebookId || 'test'; - yield createAccount.call({ - request: { - body: { - facebookId: facebookId, - access_token: accessToken || 'test_token' - } - } - }); - - if (opts) { - yield accountModel.update({facebookId: facebookId}, opts); - } - - return yield accountModel.getByFacebookId(facebookId); - }, - createTrait: function* (templateId, overrides) { - var trait = traitModel.newTrait(templateId); - return yield traitModel.add(_.merge(trait, overrides || {})); - }, - createTraitTemplate: function(id, comparisons, themes) { - traitTemplateModel.addOrUpdate({ - id: id, - comparisons: comparisons, - themes: themes || [] - }); - } -}; diff --git a/server/test/traitImporting.js b/server/test/traitImporting.js deleted file mode 100644 index 26c997e..0000000 --- a/server/test/traitImporting.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -const traits = require('../bin/traits'); -const expect = require('expect.js'); -const co = require('co'); -const testUtils = require('./testUtils'); -const traitTemplateModel = require('../app/models/traitTemplate'); -const _ = require('lodash'); - -describe('Trait Importing', function() { - beforeEach(testUtils.clearAll); - it('should add all default traits', function(done) { - co(function *() { - yield traits.addDefault(); - const addedTraits = yield traitTemplateModel.query({ - id: { $in: _.map(traits.defaultTraits, 'id') } - }); - - expect(addedTraits).to.have.length(traits.defaultTraits.length); - done(); - }).catch(function(e) { - console.error('error adding traits', e); - }); - }); -}); diff --git a/server/test/traits.js b/server/test/traits.js deleted file mode 100644 index c57d7f9..0000000 --- a/server/test/traits.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -const agent = require('supertest').agent; -const app = require('./mockApp'); -const http = require('http'); -const _ = require('lodash'); -const expect = require('expect.js'); -const co = require('co'); -const testUtils = require('./testUtils'); -const voteModel = require('../app/models/vote'); -const Joi = require('joi'); -const voteSchema = require('../app/models/schemas').vote; - -describe('/trait', function() { - beforeEach(testUtils.clearAll); - - let request; - let MOCK_USER; - - beforeEach(function(done) { - co(function* () { - request = agent(http.createServer(app.callback())); - MOCK_USER = yield testUtils.createTestUser(); - done(); - }); - }); - - describe('GET /query', function() { - it('should get traits by user', function(done) { - request - .get('/trait/query/' + MOCK_USER.facebookId) - .expect(200) - .end(function(err, res) { - if (err) throw err; - var traits = res.body; - expect(_.map(traits, 'id')[0]).to.be(MOCK_USER.traits[0]); - expect(traits).to.have.length(MOCK_USER.traits.length); - done(); - }); - }); - }); - - describe('GET /get', function() { - //Add vote - let testTrait; - beforeEach(function(done) { - co(function* () { - const vote = yield voteModel.add(voteModel.newVote('testId', 'is this a test?', ['1', '2'], 'test')); - testTrait = yield testUtils.createTrait('test', { - total: [vote.id] - }); - done(); - }).catch(function(err) { - console.error(err); - }); - }); - - it('should get denormalized traits by id', function(done) { - request - .get('/trait/' + testTrait.id) - .expect(200) - .end(function(err, res) { - if (err) throw err; - const trait = res.body; - expect(trait.total).to.have.length(1); - - const validation = Joi.validate(_.first(trait.total), voteSchema); - if (validation.error) { - throw validation.error; - }; - - expect(trait).to.have.key('template'); - done(); - }); - }); - }); -}); diff --git a/server/test/votes.js b/server/test/votes.js deleted file mode 100644 index 15477bd..0000000 --- a/server/test/votes.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; - -const agent = require('supertest').agent; -const app = require('./mockApp'); -const http = require('http'); -const expect = require('expect.js'); -const createVotes = require('../app/services/createVotes'); -const voteModel = require('../app/models/vote'); -const completedVotesModel = require('../app/models/completedVotes'); -const traitModel = require('../app/models/trait'); -const testUtils = require('./testUtils'); -const co = require('co'); -const _ = require('lodash'); -const Joi = require('joi'); -const accountSchema = require('../app/models/schemas').account; - -describe('/vote', function() { - beforeEach(testUtils.clearAll); - let request; - let mockUser; - let friend1; - let friend2; - let trait1; - let trait2; - const id1 = 'friend1'; - const id2 = 'friend2'; - - beforeEach(function(cb) { - request = agent(http.createServer(app.callback())); - co(function* () { - const traitTemplateId = '1'; - const setup = yield { - mockUser: testUtils.createTestUser(null, null, { - friends: [id1, id2] - }), - trait1: testUtils.createTrait(traitTemplateId), - trait2: testUtils.createTrait(traitTemplateId), - template: testUtils.createTraitTemplate(traitTemplateId, ['comparison1']) - }; - mockUser = setup.mockUser; - trait1 = setup.trait1; - trait2 = setup.trait2; - - const setupFriends = yield [ - testUtils.createTestUser(id1, null, { - traits: [trait1.id] - }), - testUtils.createTestUser(id2, null, { - traits: [trait2.id] - }) - ]; - friend1 = setupFriends[0]; - friend2 = setupFriends[1]; - - cb(); - }).catch(function(err) { - console.error(err); - }); - }); - - describe('POST /vote/:id', function() { - let testVote; - beforeEach(function(cb) { - co(function* () { - yield createVotes(mockUser.facebookId); - const votes = yield voteModel.query({}); - testVote = votes[0]; - cb(); - }); - }); - it('should complete a vote', function(cb) { - request - .post('/vote/' + testVote.id) - .send({ - facebookId: mockUser.facebookId, - selected: id1, - score: 22 - }) - .expect(200) - .end(function(err) { - if (err) throw err; - co(function* () { - const winningTrait = yield traitModel.get(trait1.id); - const losingTrait = yield traitModel.get(trait2.id); - expect(winningTrait.count).to.be(1); - expect(losingTrait.count).to.be(0); - expect(losingTrait.total).to.be.an('array'); - expect(losingTrait.total).to.have.length(1); - - const completedVotes = yield completedVotesModel.getByFacebookId(mockUser.facebookId); - expect(completedVotes.complete).to.have.length(1); - expect(completedVotes.complete[0].id).to.be(testVote.id); - - cb(); - }).catch(function(err) { - console.log('error with should complete a vote', err); - throw err; - }); - }); - }); - }); - describe('GET /vote/:facebookId', function() { - it('should return an array of incomplete votes', function(cb) { - request - .get('/vote/' + mockUser.facebookId) - .expect(200) - .end(function(err, res) { - if (err) throw err; - const votes = res.body; - expect(votes).to.have.length(1); - expect(votes[0].contestants).to.have.length(2); - - cb(); - }); - }); - it('returned votes should be denomalized', function(cb) { - request - .get('/vote/' + mockUser.facebookId) - .expect(200) - .end(function(err, res) { - if (err) throw err; - const votes = res.body; - _.each(votes[0].contestants, function(acct) { - const validation = Joi.validate(acct, accountSchema); - expect(!validation.error).to.be.ok(); - }); - cb(); - }); - }); - }); -});