From 81071eacd6361f5f8f080db7918454a9ec7861be Mon Sep 17 00:00:00 2001 From: gaba Date: Sat, 10 Dec 2016 14:00:46 -1000 Subject: [PATCH 1/8] It adds a status field and change the name of the closedAt and closedMessage to record changes from the status from closed to open too. --- models/asset.js | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/models/asset.js b/models/asset.js index 3c68b7c13..c1fc59dc3 100644 --- a/models/asset.js +++ b/models/asset.js @@ -5,6 +5,12 @@ const Setting = require('./setting'); const uuid = require('uuid'); +// ASSET_STATUSES is the list of statuses that are permitted for the asset status. +const ASSET_STATUS = [ + 'open', + 'closed' +]; + const AssetSchema = new Schema({ id: { type: String, @@ -29,14 +35,15 @@ const AssetSchema = new Schema({ type: Schema.Types.Mixed, default: null }, - closedAt: { + status: { + type: String, + default: 'open' + }, + statusChangedAt: { type: Date, default: null }, - closedMessage: { - type: String, - default: null - }, + statusClosedMessage: String, title: String, description: String, image: String, @@ -68,9 +75,27 @@ AssetSchema.index({ * Returns true if the asset is closed, false else. */ AssetSchema.virtual('isClosed').get(function() { - return this.closedAt && this.closedAt.getTime() <= new Date().getTime(); + return (this.status === 'closed') && this.statusChangedAt && this.statusChangedAt.getTime() <= new Date().getTime(); }); +/** + * Close or Open the asset. + */ +AssetSchema.statics.changeOpenStatus = (id, status, closedMessage = '') => { + // Check to see if the user role is in the allowable set of roles. + if (ASSET_STATUS.indexOf(status) === -1) { + // Asset status is not supported! Error out here. + return Promise.reject(new Error(`status ${status} is not supported`)); + } + return Asset.update({id}, { + $set: { + status: status, + statusChangedAt: new Date().getTime(), + statusClosedMessage: closedMessage + } + }); +}; + /** * Finds an asset by its id. * @param {String} id identifier of the asset (uuid). From 5e21102c2fb9573ec9bb650555da1cd6ea02a971 Mon Sep 17 00:00:00 2001 From: gaba Date: Sat, 10 Dec 2016 14:01:24 -1000 Subject: [PATCH 2/8] Fix routes and tests for asset status change. --- routes/api/asset/index.js | 4 ++-- routes/api/comments/index.js | 2 +- tests/routes/api/comments/index.js | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index 2ddc3ea23..ebdcf038d 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -90,9 +90,9 @@ router.put('/:asset_id/settings', (req, res, next) => { }); router.put('/:asset_id/status', (req, res, next) => { - // Update the asset status + Asset - .update({id: req.params.asset_id}, {status: req.query.status}) + .changeOpenStatus(req.params.asset_id, req.query.status, req.query.closedMessage) .then(() => res.status(204).end()) .catch((err) => next(err)); }); diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index 168b89fc3..fad9083cc 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -89,7 +89,7 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { if (asset.isClosed) { // They have, ensure that we send back an error. - return Promise.reject(new Error(`asset has commenting closed because: ${asset.closedMessage}`)); + return Promise.reject(new Error(`asset has commenting closed because: ${asset.statusClosedMessage}`)); } return asset; diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index b3e4e2675..4787e4d58 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -199,8 +199,9 @@ describe('/api/v1/comments', () => { it('shouldn\'t create a comment when the asset has expired commenting', () => { return Asset.create({ - closedAt: new Date().setDate(0), - closedMessage: 'tests said expired!' + status: 'closed', + statusChangedAt: new Date().setDate(0), + statusClosedMessage: 'tests said expired!' }) .then((asset) => { return chai.request(app) From 3b131ce315b3d74f81508a4161c7c1166e4995eb Mon Sep 17 00:00:00 2001 From: gaba Date: Mon, 12 Dec 2016 13:02:39 -0800 Subject: [PATCH 3/8] Removes status field for Asset. Now closedAt and closedMessage are in the settings field. --- client/coral-framework/actions/config.js | 21 ++++++----- models/asset.js | 44 +++--------------------- routes/api/asset/index.js | 18 ++++++---- routes/api/comments/index.js | 3 +- tests/routes/api/comments/index.js | 10 ++++-- 5 files changed, 36 insertions(+), 60 deletions(-) diff --git a/client/coral-framework/actions/config.js b/client/coral-framework/actions/config.js index f85e609eb..eb03d63ed 100644 --- a/client/coral-framework/actions/config.js +++ b/client/coral-framework/actions/config.js @@ -6,14 +6,6 @@ import I18n from 'coral-framework/modules/i18n/i18n'; import translations from './../translations'; const lang = new I18n(translations); -export const updateOpenStatus = status => (dispatch, getState) => { - const assetId = getState().items.get('assets') - .keySeq() - .toArray()[0]; - return coralApi(`/asset/${assetId}/status?status=${status}`, {method: 'PUT'}) - .then(() => dispatch({type: status === 'open' ? actions.OPEN_COMMENTS : actions.CLOSE_COMMENTS})); -}; - const updateConfigRequest = () => ({type: actions.UPDATE_CONFIG_REQUEST}); const updateConfigSuccess = config => ({type: actions.UPDATE_CONFIG_SUCCESS, config}); const updateConfigFailure = () => ({type: actions.UPDATE_CONFIG_FAILURE}); @@ -31,3 +23,16 @@ export const updateConfiguration = newConfig => (dispatch, getState) => { }) .catch(error => dispatch(updateConfigFailure(error))); }; + +const openStream = () => ({type: actions.OPEN_COMMENTS}); +const closeStream = () => ({type: actions.CLOSE_COMMENTS}); + +export const updateOpenStatus = status => dispatch => { + if (status === 'open') { + dispatch(openStream()); + dispatch(updateConfiguration({closedAt: null})); + } else { + dispatch(closeStream()); + dispatch(updateConfiguration({closedAt: Date.getTime()})); + } +}; diff --git a/models/asset.js b/models/asset.js index c1fc59dc3..09a9f49e8 100644 --- a/models/asset.js +++ b/models/asset.js @@ -5,12 +5,6 @@ const Setting = require('./setting'); const uuid = require('uuid'); -// ASSET_STATUSES is the list of statuses that are permitted for the asset status. -const ASSET_STATUS = [ - 'open', - 'closed' -]; - const AssetSchema = new Schema({ id: { type: String, @@ -35,15 +29,6 @@ const AssetSchema = new Schema({ type: Schema.Types.Mixed, default: null }, - status: { - type: String, - default: 'open' - }, - statusChangedAt: { - type: Date, - default: null - }, - statusClosedMessage: String, title: String, description: String, image: String, @@ -71,31 +56,6 @@ AssetSchema.index({ background: true }); -/** - * Returns true if the asset is closed, false else. - */ -AssetSchema.virtual('isClosed').get(function() { - return (this.status === 'closed') && this.statusChangedAt && this.statusChangedAt.getTime() <= new Date().getTime(); -}); - -/** - * Close or Open the asset. - */ -AssetSchema.statics.changeOpenStatus = (id, status, closedMessage = '') => { - // Check to see if the user role is in the allowable set of roles. - if (ASSET_STATUS.indexOf(status) === -1) { - // Asset status is not supported! Error out here. - return Promise.reject(new Error(`status ${status} is not supported`)); - } - return Asset.update({id}, { - $set: { - status: status, - statusChangedAt: new Date().getTime(), - statusClosedMessage: closedMessage - } - }); -}; - /** * Finds an asset by its id. * @param {String} id identifier of the asset (uuid). @@ -108,6 +68,10 @@ AssetSchema.statics.findById = (id) => Asset.findOne({id}); */ AssetSchema.statics.findByUrl = (url) => Asset.findOne({url}); +AssetSchema.virtual('isClosed').get(function() { + return this.settings && this.settings.closedAt && this.settings.closedAt <= new Date().getTime(); +}); + /** * Retrieves the settings given an asset query and rectifies it against the * global settings. diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index ebdcf038d..f61851f0c 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -89,12 +89,16 @@ router.put('/:asset_id/settings', (req, res, next) => { .catch((err) => next(err)); }); -router.put('/:asset_id/status', (req, res, next) => { - - Asset - .changeOpenStatus(req.params.asset_id, req.query.status, req.query.closedMessage) - .then(() => res.status(204).end()) - .catch((err) => next(err)); -}); +// router.put('/:asset_id/status', (req, res, next) => { +// Asset +// .findOneAndUpdate(req.params.asset_id, { +// $set: { +// closedAt: req.query.closedAt, +// closedMessage: req.query.closedMessage +// } +// }) +// .then(() => res.status(204).end()) +// .catch((err) => next(err)); +// }); module.exports = router; diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index fad9083cc..bf741ed2d 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -87,9 +87,8 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { // Check to see if the asset has closed commenting... if (asset.isClosed) { - // They have, ensure that we send back an error. - return Promise.reject(new Error(`asset has commenting closed because: ${asset.statusClosedMessage}`)); + return Promise.reject(new Error(`asset has commenting closed because: ${asset.settings.closedMessage}`)); } return asset; diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index 4787e4d58..0f6e8442e 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -160,6 +160,9 @@ describe('/api/v1/comments', () => { .then((res) => { expect(res).to.have.status(201); expect(res.body).to.have.property('id'); + }) + .catch((err) => { + expect(err).to.be.null; }); }); @@ -199,9 +202,10 @@ describe('/api/v1/comments', () => { it('shouldn\'t create a comment when the asset has expired commenting', () => { return Asset.create({ - status: 'closed', - statusChangedAt: new Date().setDate(0), - statusClosedMessage: 'tests said expired!' + settings: { + closedAt: new Date().setDate(0), + closedMessage: 'tests said expired!' + } }) .then((asset) => { return chai.request(app) From 0648b2b1c81ff0a434ec89e6c8c2fa22af570554 Mon Sep 17 00:00:00 2001 From: gaba Date: Mon, 12 Dec 2016 15:38:28 -0800 Subject: [PATCH 4/8] More tests. --- client/coral-framework/actions/config.js | 18 ++++++++++++-- models/asset.js | 10 +++++++- routes/api/asset/index.js | 27 ++++++++++++--------- routes/api/comments/index.js | 2 +- tests/routes/api/assets/index.js | 31 +++++++++++++++++++++++- tests/routes/api/comments/index.js | 6 ++--- 6 files changed, 74 insertions(+), 20 deletions(-) diff --git a/client/coral-framework/actions/config.js b/client/coral-framework/actions/config.js index eb03d63ed..7850577dc 100644 --- a/client/coral-framework/actions/config.js +++ b/client/coral-framework/actions/config.js @@ -24,15 +24,29 @@ export const updateConfiguration = newConfig => (dispatch, getState) => { .catch(error => dispatch(updateConfigFailure(error))); }; +export const updateOpenStream = newConfig => (dispatch, getState) => { + const assetId = getState().items.get('assets') + .keySeq() + .toArray()[0]; + + dispatch(updateConfigRequest()); + coralApi(`/asset/${assetId}/status`, {method: 'PUT', body: newConfig}) + .then(() => { + dispatch(addNotification('success', lang.t('successUpdateSettings'))); + dispatch(updateConfigSuccess(newConfig)); + }) + .catch(error => dispatch(updateConfigFailure(error))); +}; + const openStream = () => ({type: actions.OPEN_COMMENTS}); const closeStream = () => ({type: actions.CLOSE_COMMENTS}); export const updateOpenStatus = status => dispatch => { if (status === 'open') { dispatch(openStream()); - dispatch(updateConfiguration({closedAt: null})); + dispatch(updateOpenStream({closedAt: null})); } else { dispatch(closeStream()); - dispatch(updateConfiguration({closedAt: Date.getTime()})); + dispatch(updateOpenStream({closedAt: Date.now(), closedMessage: ''})); } }; diff --git a/models/asset.js b/models/asset.js index 09a9f49e8..ed1bf98d0 100644 --- a/models/asset.js +++ b/models/asset.js @@ -29,6 +29,14 @@ const AssetSchema = new Schema({ type: Schema.Types.Mixed, default: null }, + closedAt: { + type: Date, + default: null + }, + closedMessage: { + type: String, + default: null + }, title: String, description: String, image: String, @@ -69,7 +77,7 @@ AssetSchema.statics.findById = (id) => Asset.findOne({id}); AssetSchema.statics.findByUrl = (url) => Asset.findOne({url}); AssetSchema.virtual('isClosed').get(function() { - return this.settings && this.settings.closedAt && this.settings.closedAt <= new Date().getTime(); + return this.closedAt && this.closedAt.getTime() <= new Date().getTime(); }); /** diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index f61851f0c..6723d3671 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -89,16 +89,21 @@ router.put('/:asset_id/settings', (req, res, next) => { .catch((err) => next(err)); }); -// router.put('/:asset_id/status', (req, res, next) => { -// Asset -// .findOneAndUpdate(req.params.asset_id, { -// $set: { -// closedAt: req.query.closedAt, -// closedMessage: req.query.closedMessage -// } -// }) -// .then(() => res.status(204).end()) -// .catch((err) => next(err)); -// }); +router.put('/:asset_id/status', (req, res, next) => { + const id = req.params.asset_id; + const { + closedAt = null, + closedMessage = null + } = req.query; + Asset + .update(id, { + closedAt: closedAt, + closedMessage: closedMessage + }) + .then((asset) => { + res.status(201).json(asset); + }) + .catch((err) => next(err)); +}); module.exports = router; diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index bf741ed2d..b54717c78 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -88,7 +88,7 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { // Check to see if the asset has closed commenting... if (asset.isClosed) { // They have, ensure that we send back an error. - return Promise.reject(new Error(`asset has commenting closed because: ${asset.settings.closedMessage}`)); + return Promise.reject(new Error(`asset has commenting closed because: ${asset.closedMessage}`)); } return asset; diff --git a/tests/routes/api/assets/index.js b/tests/routes/api/assets/index.js index c56e5b1ba..817f5b181 100644 --- a/tests/routes/api/assets/index.js +++ b/tests/routes/api/assets/index.js @@ -17,7 +17,8 @@ describe('/api/v1/assets', () => { { url: 'https://coralproject.net/news/asset1', title: 'Asset 1', - description: 'term1' + description: 'term1', + id: '1' }, { url: 'https://coralproject.net/news/asset2', @@ -82,4 +83,32 @@ describe('/api/v1/assets', () => { }); + describe('#put', () => { + it('should close the asset', function() { + + const asset = Asset.findByUrl('http://test.com') + .then((asset) => { + expect(asset).to.have.property('closedAt') + .and.to.equal(null); + }); + + const today = Date.now(); + return chai.request(app) + .put(`/api/v1/asset/${asset.id}/status`) + .set(passport.inject({roles: ['admin']})) + .send({closedAt: today}) + .then((res) => { + expect(res).to.have.status(201); + + Asset.findByUrl('http://test.com') + .then((asset) => { + expect(asset).to.have.property('isClosed') + .and.to.equal(true); + expect(asset).to.have.property('closedAt') + .and.to.not.equal(null); + }); + }); + }); + }); + }); diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index 0f6e8442e..59d840e1b 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -202,10 +202,8 @@ describe('/api/v1/comments', () => { it('shouldn\'t create a comment when the asset has expired commenting', () => { return Asset.create({ - settings: { - closedAt: new Date().setDate(0), - closedMessage: 'tests said expired!' - } + closedAt: new Date().setDate(0), + closedMessage: 'tests said expired!' }) .then((asset) => { return chai.request(app) From 475c84dfbc5b806fb598710bd6b4b5c52c52537e Mon Sep 17 00:00:00 2001 From: gaba Date: Mon, 12 Dec 2016 22:18:11 -0800 Subject: [PATCH 5/8] Fix date comparision and change article for asset. --- client/coral-framework/actions/config.js | 9 +++++---- client/coral-framework/reducers/config.js | 2 +- models/asset.js | 2 +- routes/api/asset/index.js | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/client/coral-framework/actions/config.js b/client/coral-framework/actions/config.js index 7850577dc..c2d4083b7 100644 --- a/client/coral-framework/actions/config.js +++ b/client/coral-framework/actions/config.js @@ -24,16 +24,17 @@ export const updateConfiguration = newConfig => (dispatch, getState) => { .catch(error => dispatch(updateConfigFailure(error))); }; -export const updateOpenStream = newConfig => (dispatch, getState) => { +export const updateOpenStream = closedBody => (dispatch, getState) => { const assetId = getState().items.get('assets') .keySeq() .toArray()[0]; dispatch(updateConfigRequest()); - coralApi(`/asset/${assetId}/status`, {method: 'PUT', body: newConfig}) + + coralApi(`/asset/${assetId}/status`, {method: 'PUT', body: closedBody}) .then(() => { dispatch(addNotification('success', lang.t('successUpdateSettings'))); - dispatch(updateConfigSuccess(newConfig)); + dispatch(updateConfigSuccess(closedBody)); }) .catch(error => dispatch(updateConfigFailure(error))); }; @@ -47,6 +48,6 @@ export const updateOpenStatus = status => dispatch => { dispatch(updateOpenStream({closedAt: null})); } else { dispatch(closeStream()); - dispatch(updateOpenStream({closedAt: Date.now(), closedMessage: ''})); + dispatch(updateOpenStream({closedAt: new Date().getTime(), closedMessage: ''})); } }; diff --git a/client/coral-framework/reducers/config.js b/client/coral-framework/reducers/config.js index 8266fbfa1..362608d6d 100644 --- a/client/coral-framework/reducers/config.js +++ b/client/coral-framework/reducers/config.js @@ -22,7 +22,7 @@ export default (state = initialState, action) => { return state .set('status', 'closed'); case actions.ADD_ITEM: - return action.item_type === 'assets' ? state.set('status', action.item.status) : state; + return action.item_type === 'assets' ? state.set('status', (action.item && action.item.closedAt && new Date(action.item.closedAt).getTime() <= new Date().getTime()) ? 'closed' : 'open') : state; default: return state; } diff --git a/models/asset.js b/models/asset.js index ed1bf98d0..f3d0bae91 100644 --- a/models/asset.js +++ b/models/asset.js @@ -19,7 +19,7 @@ const AssetSchema = new Schema({ }, type: { type: String, - default: 'article' + default: 'assets' }, scraped: { type: Date, diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index 6723d3671..32961416d 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -94,7 +94,7 @@ router.put('/:asset_id/status', (req, res, next) => { const { closedAt = null, closedMessage = null - } = req.query; + } = req.body; Asset .update(id, { closedAt: closedAt, From 9043ae9f2014772113f9eeb96fa23412c5599e5d Mon Sep 17 00:00:00 2001 From: gaba Date: Mon, 12 Dec 2016 22:19:09 -0800 Subject: [PATCH 6/8] We are using asset and not article. --- client/coral-configure/translations.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-configure/translations.json b/client/coral-configure/translations.json index e597c9c9a..5aa7f72b6 100644 --- a/client/coral-configure/translations.json +++ b/client/coral-configure/translations.json @@ -3,7 +3,7 @@ "configureCommentStream": { "apply": "Apply", "title": "Configure Comment Stream", - "description": "As an admin you may customize the settings for the comment stream for this article", + "description": "As an admin you may customize the settings for the comment stream for this asset", "enablePremod": "Enable Premoderation", "enablePremodDescription": "Moderators must approve any comment before its published.", "enablePremodLinks": "Pre-Moderate Comments Containing Links", From 61128e9c06d807d2c3700c1bd5eb6f9362e594a4 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 13 Dec 2016 11:28:19 -0700 Subject: [PATCH 7/8] Updated docs, services, tests. --- app.js | 4 +- bin/cli-assets | 2 +- bin/cli-jobs | 4 +- bin/cli-serve | 2 +- bin/cli-settings | 2 +- bin/cli-users | 2 +- architecture.png => docs/architecture.png | Bin architecture.xml => docs/architecture.xml | 0 data-model.png => docs/data-model.png | Bin data-model.xml => docs/data-model.xml | 0 .../moderation-flow-post.png | Bin .../moderation-flow-pre.png | Bin .../moderation-flow.xml | 0 swagger.yaml => docs/swagger.yaml | 0 models/action.js | 2 +- models/asset.js | 5 ++- models/comment.js | 2 +- models/setting.js | 4 +- models/user.js | 2 +- package.json | 37 +++++++++++------ pree2e.sh | 2 - routes/api/asset/index.js | 20 ++++++--- routes/api/auth/index.js | 2 +- routes/api/index.js | 2 +- scripts/pree2e.sh | 7 ++++ cache.js => services/cache.js | 0 kue.js => services/kue.js | 0 mongoose.js => services/mongoose.js | 0 passport.js => services/passport.js | 2 +- redis.js => services/redis.js | 0 services/scraper.js | 2 +- tests/mongoose.js | 2 +- tests/routes/api/assets/index.js | 38 +++++++++--------- tests/routes/api/comments/index.js | 3 -- tests/utils/e2e-mongoose.js | 2 +- 35 files changed, 87 insertions(+), 63 deletions(-) rename architecture.png => docs/architecture.png (100%) rename architecture.xml => docs/architecture.xml (100%) rename data-model.png => docs/data-model.png (100%) rename data-model.xml => docs/data-model.xml (100%) rename moderation-flow-post.png => docs/moderation-flow-post.png (100%) rename moderation-flow-pre.png => docs/moderation-flow-pre.png (100%) rename moderation-flow.xml => docs/moderation-flow.xml (100%) rename swagger.yaml => docs/swagger.yaml (100%) delete mode 100755 pree2e.sh create mode 100755 scripts/pree2e.sh rename cache.js => services/cache.js (100%) rename kue.js => services/kue.js (100%) rename mongoose.js => services/mongoose.js (100%) rename passport.js => services/passport.js (98%) rename redis.js => services/redis.js (100%) diff --git a/app.js b/app.js index fe392932b..15a7a5442 100644 --- a/app.js +++ b/app.js @@ -3,10 +3,10 @@ const bodyParser = require('body-parser'); const morgan = require('morgan'); const path = require('path'); const helmet = require('helmet'); -const passport = require('./passport'); +const passport = require('./services/passport'); const session = require('express-session'); const RedisStore = require('connect-redis')(session); -const redis = require('./redis'); +const redis = require('./services/redis'); const app = express(); diff --git a/bin/cli-assets b/bin/cli-assets index 9ab36685a..4b0d65c2a 100755 --- a/bin/cli-assets +++ b/bin/cli-assets @@ -15,7 +15,7 @@ const pkg = require('../package.json'); const parseDuration = require('parse-duration'); const Table = require('cli-table'); const Asset = require('../models/asset'); -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const scraper = require('../services/scraper'); const util = require('../util'); diff --git a/bin/cli-jobs b/bin/cli-jobs index bc320d14b..91a0a6e59 100755 --- a/bin/cli-jobs +++ b/bin/cli-jobs @@ -13,8 +13,8 @@ process.env.DEBUG = process.env.TALK_DEBUG; const program = require('commander'); const scraper = require('../services/scraper'); const util = require('../util'); -const mongoose = require('../mongoose'); -const kue = require('../kue'); +const mongoose = require('../services/mongoose'); +const kue = require('../services/kue'); util.onshutdown([ () => mongoose.disconnect() diff --git a/bin/cli-serve b/bin/cli-serve index dd682f5ad..c22920eaa 100755 --- a/bin/cli-serve +++ b/bin/cli-serve @@ -11,7 +11,7 @@ const debug = require('debug')('talk:server'); const http = require('http'); const init = require('../init'); const scraper = require('../services/scraper'); -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const util = require('../util'); /** diff --git a/bin/cli-settings b/bin/cli-settings index e7ba30151..e38249199 100755 --- a/bin/cli-settings +++ b/bin/cli-settings @@ -11,7 +11,7 @@ process.env.DEBUG = process.env.TALK_DEBUG; */ const program = require('commander'); -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const Setting = require('../models/setting'); const util = require('../util'); diff --git a/bin/cli-users b/bin/cli-users index adfe3bf23..e212a477f 100755 --- a/bin/cli-users +++ b/bin/cli-users @@ -14,7 +14,7 @@ const program = require('commander'); const pkg = require('../package.json'); const prompt = require('prompt'); const User = require('../models/user'); -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const util = require('../util'); const Table = require('cli-table'); diff --git a/architecture.png b/docs/architecture.png similarity index 100% rename from architecture.png rename to docs/architecture.png diff --git a/architecture.xml b/docs/architecture.xml similarity index 100% rename from architecture.xml rename to docs/architecture.xml diff --git a/ data-model.png b/docs/data-model.png similarity index 100% rename from data-model.png rename to docs/data-model.png diff --git a/ data-model.xml b/docs/data-model.xml similarity index 100% rename from data-model.xml rename to docs/data-model.xml diff --git a/moderation-flow-post.png b/docs/moderation-flow-post.png similarity index 100% rename from moderation-flow-post.png rename to docs/moderation-flow-post.png diff --git a/moderation-flow-pre.png b/docs/moderation-flow-pre.png similarity index 100% rename from moderation-flow-pre.png rename to docs/moderation-flow-pre.png diff --git a/moderation-flow.xml b/docs/moderation-flow.xml similarity index 100% rename from moderation-flow.xml rename to docs/moderation-flow.xml diff --git a/swagger.yaml b/docs/swagger.yaml similarity index 100% rename from swagger.yaml rename to docs/swagger.yaml diff --git a/models/action.js b/models/action.js index ed18e48c5..45f828226 100644 --- a/models/action.js +++ b/models/action.js @@ -1,4 +1,4 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const uuid = require('uuid'); const _ = require('lodash'); const Schema = mongoose.Schema; diff --git a/models/asset.js b/models/asset.js index f3d0bae91..09c06a09d 100644 --- a/models/asset.js +++ b/models/asset.js @@ -1,4 +1,4 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const Schema = mongoose.Schema; const Setting = require('./setting'); @@ -76,6 +76,9 @@ AssetSchema.statics.findById = (id) => Asset.findOne({id}); */ AssetSchema.statics.findByUrl = (url) => Asset.findOne({url}); +/** + * Returns true if the asset is closed, false else. + */ AssetSchema.virtual('isClosed').get(function() { return this.closedAt && this.closedAt.getTime() <= new Date().getTime(); }); diff --git a/models/comment.js b/models/comment.js index 9cfee2ee7..b3b3bc52f 100644 --- a/models/comment.js +++ b/models/comment.js @@ -1,4 +1,4 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const Schema = mongoose.Schema; const _ = require('lodash'); const uuid = require('uuid'); diff --git a/models/setting.js b/models/setting.js index 687c28959..967b5fd7e 100644 --- a/models/setting.js +++ b/models/setting.js @@ -1,7 +1,7 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const Schema = mongoose.Schema; const _ = require('lodash'); -const cache = require('../cache'); +const cache = require('../services/cache'); /** * SettingSchema manages application settings that get used on front and backend. diff --git a/models/user.js b/models/user.js index 857eb1260..216345cbd 100644 --- a/models/user.js +++ b/models/user.js @@ -1,4 +1,4 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); const uuid = require('uuid'); const _ = require('lodash'); const bcrypt = require('bcrypt'); diff --git a/package.json b/package.json index c54bd6723..53af9910b 100644 --- a/package.json +++ b/package.json @@ -5,21 +5,26 @@ "main": "app.js", "scripts": { "start": "./bin/cli serve --jobs", - "build": "NODE_ENV=production webpack --config webpack.config.js --bail", - "build-watch": "NODE_ENV=development webpack --config webpack.config.dev.js --watch", - "lint": "eslint bin/* .", - "lint-fix": "eslint . --fix", - "test": "NODE_ENV=test mocha --compilers js:babel-core/register --recursive tests", - "test-watch": "NODE_ENV=test mocha --compilers js:babel-core/register --recursive -w tests", - "pree2e": "NODE_ENV=test ./pree2e.sh", - "e2e": "NODE_ENV=test node_modules/.bin/nightwatch", + "build": "NODE_ENV=production ./node_modules/.bin/webpack --config webpack.config.js --bail", + "build-watch": "NODE_ENV=development ./node_modules/.bin/webpack --config webpack.config.dev.js --watch", + "lint": "./node_modules/.bin/eslint bin/* .", + "lint-fix": "./node_modules/.bin/eslint bin/* . --fix", + "test": "NODE_ENV=test ./node_modules/.bin/mocha --compilers js:babel-core/register --recursive tests", + "test-watch": "NODE_ENV=test ./node_modules/.bin/mocha --compilers js:babel-core/register --recursive -w tests", + "pree2e": "NODE_ENV=test ./scripts/pree2e.sh", + "e2e": "NODE_ENV=test ./node_modules/.bin/nightwatch", "embed-start": "NODE_ENV=development npm run build && ./bin/cli serve --jobs" }, "config": { "pre-git": { "commit-msg": [], - "pre-commit": ["npm run lint", "npm test"], - "pre-push": ["npm test"], + "pre-commit": [ + "npm run lint", + "npm test" + ], + "pre-push": [ + "npm test" + ], "post-commit": [], "post-merge": [] } @@ -28,7 +33,12 @@ "type": "git", "url": "git+https://github.com/coralproject/talk.git" }, - "keywords": ["talk", "coral", "coralproject", "ask"], + "keywords": [ + "talk", + "coral", + "coralproject", + "ask" + ], "author": "", "license": "Apache-2.0", "bugs": { @@ -59,7 +69,6 @@ "passport-facebook": "^2.1.1", "passport-local": "^1.0.0", "prompt": "^1.0.0", - "react-linkify": "^0.1.3", "redis": "^2.6.3", "uuid": "^2.0.3" }, @@ -84,9 +93,10 @@ "copy-webpack-plugin": "^4.0.0", "css-loader": "^0.25.0", "dialog-polyfill": "^0.4.4", - "eslint": "^3.9.1", + "eslint": "^3.12.1", "eslint-config-postcss": "^2.0.2", "eslint-config-standard": "^6.2.1", + "eslint-module-utils": "^2.0.0", "eslint-plugin-flowtype": "^2.25.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-mocha": "^4.7.0", @@ -113,6 +123,7 @@ "pym.js": "^1.1.1", "react": "15.3.2", "react-dom": "15.3.2", + "react-linkify": "^0.1.3", "react-mdl": "^1.7.2", "react-mdl-selectfield": "^0.2.0", "react-onclickoutside": "^5.7.1", diff --git a/pree2e.sh b/pree2e.sh deleted file mode 100755 index 8857e5745..000000000 --- a/pree2e.sh +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/selenium-standalone/bin/selenium-standalone install -npm start & diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index 32961416d..26da92279 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -90,20 +90,28 @@ router.put('/:asset_id/settings', (req, res, next) => { }); router.put('/:asset_id/status', (req, res, next) => { + const id = req.params.asset_id; + const { closedAt = null, closedMessage = null } = req.body; + Asset - .update(id, { - closedAt: closedAt, - closedMessage: closedMessage + .update({id}, { + $set: { + closedAt, + closedMessage + } }) - .then((asset) => { - res.status(201).json(asset); + .then(() => { + + res.status(204).json(); }) - .catch((err) => next(err)); + .catch((err) => { + next(err); + }); }); module.exports = router; diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index 369e5ec77..bcbfcc27e 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -1,5 +1,5 @@ const express = require('express'); -const passport = require('../../../passport'); +const passport = require('../../../services/passport'); const authorization = require('../../../middleware/authorization'); const router = express.Router(); diff --git a/routes/api/index.js b/routes/api/index.js index 7863b0cd0..6a7f6ff10 100644 --- a/routes/api/index.js +++ b/routes/api/index.js @@ -19,6 +19,6 @@ router.use('/stream', require('./stream')); router.use('/users', require('./users')); // Bind the kue handler to the /kue path. -router.use('/kue', authorization.needed('admin'), require('../../kue').kue.app); +router.use('/kue', authorization.needed('admin'), require('../../services/kue').kue.app); module.exports = router; diff --git a/scripts/pree2e.sh b/scripts/pree2e.sh new file mode 100755 index 000000000..dc3266dd2 --- /dev/null +++ b/scripts/pree2e.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# install selenium +../node_modules/selenium-standalone/bin/selenium-standalone install + +# start the app server +npm start & diff --git a/cache.js b/services/cache.js similarity index 100% rename from cache.js rename to services/cache.js diff --git a/kue.js b/services/kue.js similarity index 100% rename from kue.js rename to services/kue.js diff --git a/mongoose.js b/services/mongoose.js similarity index 100% rename from mongoose.js rename to services/mongoose.js diff --git a/passport.js b/services/passport.js similarity index 98% rename from passport.js rename to services/passport.js index 2e084eafd..f709970dc 100644 --- a/passport.js +++ b/services/passport.js @@ -1,5 +1,5 @@ const passport = require('passport'); -const User = require('./models/user'); +const User = require('../models/user'); const LocalStrategy = require('passport-local').Strategy; const FacebookStrategy = require('passport-facebook').Strategy; diff --git a/redis.js b/services/redis.js similarity index 100% rename from redis.js rename to services/redis.js diff --git a/services/scraper.js b/services/scraper.js index 10e0e4aa8..c75a12750 100644 --- a/services/scraper.js +++ b/services/scraper.js @@ -1,4 +1,4 @@ -const kue = require('../kue'); +const kue = require('./kue'); const debug = require('debug')('talk:services:scraper'); const Asset = require('../models/asset'); const JOB_NAME = 'scraper'; diff --git a/tests/mongoose.js b/tests/mongoose.js index 74a0b04f7..7544072ec 100644 --- a/tests/mongoose.js +++ b/tests/mongoose.js @@ -1,4 +1,4 @@ -const mongoose = require('../mongoose'); +const mongoose = require('../services/mongoose'); beforeEach(function (done) { function clearDB() { diff --git a/tests/routes/api/assets/index.js b/tests/routes/api/assets/index.js index 817f5b181..64e820722 100644 --- a/tests/routes/api/assets/index.js +++ b/tests/routes/api/assets/index.js @@ -86,27 +86,27 @@ describe('/api/v1/assets', () => { describe('#put', () => { it('should close the asset', function() { - const asset = Asset.findByUrl('http://test.com') - .then((asset) => { - expect(asset).to.have.property('closedAt') - .and.to.equal(null); - }); - const today = Date.now(); - return chai.request(app) - .put(`/api/v1/asset/${asset.id}/status`) - .set(passport.inject({roles: ['admin']})) - .send({closedAt: today}) - .then((res) => { - expect(res).to.have.status(201); - Asset.findByUrl('http://test.com') - .then((asset) => { - expect(asset).to.have.property('isClosed') - .and.to.equal(true); - expect(asset).to.have.property('closedAt') - .and.to.not.equal(null); - }); + return Asset.findOrCreateByUrl('http://test.com') + .then((asset) => { + expect(asset).to.have.property('isClosed', null); + expect(asset).to.have.property('closedAt', null); + + return chai.request(app) + .put(`/api/v1/asset/${asset.id}/status`) + .set(passport.inject({roles: ['admin']})) + .send({closedAt: today}); + }) + .then((res) => { + + expect(res).to.have.status(204); + + return Asset.findByUrl('http://test.com'); + }) + .then((asset) => { + expect(asset).to.have.property('isClosed', true); + expect(asset).to.have.property('closedAt').and.to.not.equal(null); }); }); }); diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index 59d840e1b..b3e4e2675 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -160,9 +160,6 @@ describe('/api/v1/comments', () => { .then((res) => { expect(res).to.have.status(201); expect(res.body).to.have.property('id'); - }) - .catch((err) => { - expect(err).to.be.null; }); }); diff --git a/tests/utils/e2e-mongoose.js b/tests/utils/e2e-mongoose.js index 1bb7e695b..0b630c0e3 100644 --- a/tests/utils/e2e-mongoose.js +++ b/tests/utils/e2e-mongoose.js @@ -1,4 +1,4 @@ -const mongoose = require('../../mongoose'); +const mongoose = require('../../services/mongoose'); // Ensure the NODE_ENV is set to 'test', // this is helpful when you would like to change behavior when testing. From 387e20309accacfb8ec26f4c4bfe2ea822457cb5 Mon Sep 17 00:00:00 2001 From: gaba Date: Tue, 13 Dec 2016 10:42:30 -0800 Subject: [PATCH 8/8] We already have the default for closedMessage to be null in the model. Removing the passing of a blank closedMEssage. --- client/coral-framework/actions/config.js | 2 +- routes/api/asset/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/coral-framework/actions/config.js b/client/coral-framework/actions/config.js index c2d4083b7..c88138534 100644 --- a/client/coral-framework/actions/config.js +++ b/client/coral-framework/actions/config.js @@ -48,6 +48,6 @@ export const updateOpenStatus = status => dispatch => { dispatch(updateOpenStream({closedAt: null})); } else { dispatch(closeStream()); - dispatch(updateOpenStream({closedAt: new Date().getTime(), closedMessage: ''})); + dispatch(updateOpenStream({closedAt: new Date().getTime()})); } }; diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js index 26da92279..5aa9b8cc6 100644 --- a/routes/api/asset/index.js +++ b/routes/api/asset/index.js @@ -94,8 +94,8 @@ router.put('/:asset_id/status', (req, res, next) => { const id = req.params.asset_id; const { - closedAt = null, - closedMessage = null + closedAt, + closedMessage } = req.body; Asset