diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 0b0d76895..794da581a 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -22,7 +22,7 @@ const createAction = async ({user = {}, pubsub, loaders: {Comments}}, {item_id, } } - let action = await ActionsService.insertUserAction({ + let action = await ActionsService.create({ item_id, item_type, user_id: user.id, diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index 533032412..b32b8ed79 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -309,7 +309,7 @@ const createPublicComment = async (context, commentInput) => { // TODO: this is kind of fragile, we should refactor this to resolve // all these const's that we're using like 'COMMENTS', 'FLAG' to be // defined in a checkable schema. - await ActionsService.insertUserAction({ + await ActionsService.create({ item_id: comment.id, item_type: 'COMMENTS', action_type: 'FLAG', diff --git a/services/actions.js b/services/actions.js index 8ee50df61..d2c2350bd 100644 --- a/services/actions.js +++ b/services/actions.js @@ -58,7 +58,7 @@ module.exports = class ActionsService { * @param {String} action the new action to the item * @return {Promise} */ - static async insertUserAction(action) { + static async create(action) { // Actions are made unique by using a query that can be reproducable, i.e., // not containing user inputable values. diff --git a/services/comments.js b/services/comments.js index 88e44dc6e..07c822459 100644 --- a/services/comments.js +++ b/services/comments.js @@ -280,7 +280,7 @@ module.exports = class CommentsService { * @return {Promise} */ static addAction(item_id, user_id, action_type, metadata = {}) { - return ActionsService.insertUserAction({ + return ActionsService.create({ item_id, item_type: 'COMMENTS', user_id, @@ -301,7 +301,7 @@ const incrActionCounts = async (action, value) => { [`action_counts.${ACTION_TYPE}`]: value, }; - if (action.group_id !== null && action.group_id.length > 0) { + if (action.group_id && action.group_id.length > 0) { const GROUP_ID = sc(action.group_id.toLowerCase()); update[`action_counts.${ACTION_TYPE}_${GROUP_ID}`] = value; diff --git a/services/users.js b/services/users.js index 7ed55f712..64e4494a0 100644 --- a/services/users.js +++ b/services/users.js @@ -737,7 +737,7 @@ module.exports = class UsersService { * @return {Promise} */ static addAction(item_id, user_id, action_type, metadata) { - return ActionsService.insertUserAction({ + return ActionsService.create({ item_id, item_type: 'users', user_id, diff --git a/test/server/services/actions.js b/test/server/services/actions.js index 4d22dff6f..aef565908 100644 --- a/test/server/services/actions.js +++ b/test/server/services/actions.js @@ -1,36 +1,134 @@ const ActionModel = require('../../../models/action'); const ActionsService = require('../../../services/actions'); +const CommentModel = require('../../../models/comment'); -const expect = require('chai').expect; +const chai = require('chai'); +chai.use(require('chai-as-promised')); +const expect = chai.expect; + +const events = require('../../../services/events'); +const {ACTIONS_NEW, ACTIONS_DELETE} = require('../../../services/events/constants'); + +const sinon = require('sinon'); describe('services.ActionsService', () => { let mockActions = []; + let comment; - beforeEach(() => ActionModel.create([ - { - action_type: 'FLAG', - item_id: '123', - item_type: 'COMMENTS', - user_id: 'flagginguserid' - }, - { - action_type: 'FLAG', - item_id: '456', - item_type: 'COMMENTS' - }, - { - action_type: 'FLAG', - item_id: '123', - item_type: 'COMMENTS' - }, - { - action_type: 'LIKE', - item_id: '123', - item_type: 'COMMENTS' - } - ]).then((actions) => { - mockActions = actions; - })); + beforeEach(async () => { + comment = await CommentModel.create({ + body: 'comment 10', + asset_id: '123', + status_history: [], + parent_id: '', + author_id: '123', + id: '1' + }); + + mockActions = await ActionModel.create([ + { + action_type: 'FLAG', + item_id: comment.id, + item_type: 'COMMENTS', + user_id: 'flagginguserid' + }, + { + action_type: 'FLAG', + item_id: '456', + item_type: 'COMMENTS', + user_id: '1' + }, + { + action_type: 'FLAG', + item_id: comment.id, + item_type: 'COMMENTS', + user_id: '2' + }, + { + action_type: 'LIKE', + item_id: comment.id, + item_type: 'COMMENTS', + user_id: '3' + } + ]); + }); + + describe('#create', () => { + + it('creates an action', async () => { + const srcAction = { + action_type: 'LIKE', + item_type: 'COMMENTS', + item_id: comment.id, + }; + + const createdAction = await ActionsService.create(srcAction); + + expect(createdAction).is.not.null; + expect(createdAction).has.property('id'); + expect(createdAction).has.property('item_id', comment.id); + + const retrievedAction = await ActionModel.findOne({id: createdAction.id}); + + expect(retrievedAction).is.not.null; + expect(retrievedAction).has.property('id', createdAction.id); + expect(retrievedAction).has.property('item_id', comment.id); + }); + + it('fires the callback sucesfully', async () => { + const srcAction = { + action_type: 'LIKE', + item_type: 'COMMENTS', + item_id: comment.id, + }; + + const spy = sinon.spy(); + events.once(ACTIONS_NEW, spy); + + const createdAction = await ActionsService.create(srcAction); + + expect(createdAction).is.not.null; + expect(createdAction).has.property('id'); + expect(createdAction).has.property('item_id', comment.id); + + expect(spy).to.have.been.calledWith(createdAction); + + const retrievedComment = await CommentModel.findOne({id: comment.id}); + + expect(retrievedComment).to.have.property('action_counts'); + expect(retrievedComment.action_counts).to.have.property('like', 1); + }); + + }); + + describe('#delete', () => { + + it('deletes an action', async () => { + const deletedAction = await ActionsService.delete(mockActions[0]); + + expect(deletedAction).has.property('id', mockActions[0].id); + + const retrievedAction = await ActionModel.findOne({id: deletedAction.id}); + + expect(retrievedAction).is.null; + }); + + it('fires the callback sucesfully', async () => { + const spy = sinon.spy(); + events.once(ACTIONS_DELETE, spy); + + const deletedAction = await ActionsService.delete(mockActions[0]); + + expect(deletedAction).has.property('id', mockActions[0].id); + expect(spy).to.have.been.calledWith(deletedAction); + + const retrievedComment = await CommentModel.findOne({id: comment.id}); + + expect(retrievedComment).to.have.property('action_counts'); + expect(retrievedComment.action_counts).to.have.property('flag', -1); + }); + + }); describe('#findById()', () => { it('should find an action by id', () => { @@ -43,7 +141,7 @@ describe('services.ActionsService', () => { describe('#findByItemIdArray()', () => { it('should find an array of actions from an array of item_ids', () => { - return ActionsService.findByItemIdArray(['123', '456']).then((result) => { + return ActionsService.findByItemIdArray([comment.id, '456']).then((result) => { expect(result).to.have.length(4); }); }); @@ -52,14 +150,14 @@ describe('services.ActionsService', () => { describe('#getActionSummaries()', () => { it('should return properly formatted summaries from an array of item_ids', () => { return ActionsService - .getActionSummaries(['123', '789']) + .getActionSummaries([comment.id, '789']) .then((summaries) => { expect(summaries).to.have.length(2); expect(summaries).to.deep.include({ action_type: 'LIKE', count: 1, - item_id: '123', + item_id: comment.id, item_type: 'COMMENTS', current_user: null }); @@ -67,7 +165,7 @@ describe('services.ActionsService', () => { expect(summaries).to.deep.include({ action_type: 'FLAG', count: 2, - item_id: '123', + item_id: comment.id, item_type: 'COMMENTS', current_user: null }); @@ -76,15 +174,15 @@ describe('services.ActionsService', () => { it('should include a current user when one is passed', () => { return ActionsService - .getActionSummaries(['123'], 'flagginguserid') + .getActionSummaries([comment.id], 'flagginguserid') .then((summaries) => { expect(summaries).to.have.length(2); - let summary = summaries.find((s) => s.item_id === '123' && s.action_type === 'FLAG'); + let summary = summaries.find((s) => s.item_id === comment.id && s.action_type === 'FLAG'); expect(summary).to.not.be.undefined; expect(summary.current_user).to.not.be.null; - expect(summary.current_user).to.have.property('item_id', '123'); + expect(summary.current_user).to.have.property('item_id', comment.id); expect(summary.current_user).to.have.property('item_type', 'COMMENTS'); expect(summary.current_user).to.have.property('user_id', 'flagginguserid'); expect(summary.current_user).to.have.property('action_type', 'FLAG'); @@ -93,7 +191,7 @@ describe('services.ActionsService', () => { it('should not include a current user when one is passed for a user that doesn\'t have an action', () => { return ActionsService - .getActionSummaries(['123'], 'flagginguserid2') + .getActionSummaries([comment.id], 'flagginguserid2') .then((summaries) => { expect(summaries).to.have.length(2);