From 1137fca3b4d5b6f059ae10cb757eed5f61da0e25 Mon Sep 17 00:00:00 2001 From: gaba Date: Tue, 18 Apr 2017 14:03:26 -0700 Subject: [PATCH] Adds Tag Model that will be apply to different models. --- graph/resolvers/tag.js | 0 models/comment.js | 22 ------ models/tag.js | 64 +++++++++++++++++ models/user.js | 6 +- services/comments.js | 67 ++++-------------- services/mongoose.js | 1 + services/tags.js | 72 ++++++++++++++++++++ test/server/graph/mutations/addCommentTag.js | 8 ++- 8 files changed, 162 insertions(+), 78 deletions(-) create mode 100644 graph/resolvers/tag.js create mode 100644 models/tag.js create mode 100644 services/tags.js diff --git a/graph/resolvers/tag.js b/graph/resolvers/tag.js new file mode 100644 index 000000000..e69de29bb diff --git a/models/comment.js b/models/comment.js index 0984a0832..09f592eca 100644 --- a/models/comment.js +++ b/models/comment.js @@ -30,27 +30,6 @@ const StatusSchema = new Schema({ _id: false }); -/** - * The Mongo schema for a Comment Tag. - * @type {Schema} - */ -const TagSchema = new Schema({ - name: String, - - // The User ID of the user that assigned the status. - assigned_by: { - type: String, - default: null - }, - - created_at: { - type: Date, - default: Date - } -}, { - _id: false -}); - /** * The Mongo schema for a Comment. * @type {Schema} @@ -74,7 +53,6 @@ const CommentSchema = new Schema({ enum: STATUSES, default: 'NONE' }, - tags: [TagSchema], parent_id: String, // Additional metadata stored on the field. diff --git a/models/tag.js b/models/tag.js new file mode 100644 index 000000000..6991f3abb --- /dev/null +++ b/models/tag.js @@ -0,0 +1,64 @@ +const mongoose = require('../services/mongoose'); +const uuid = require('uuid'); +const Schema = mongoose.Schema; + +// in settings +// --> decide who can apply them (self, role, anyone) and + +// Who can see the tag (self, by role, anyone) +const PRIVACY_TYPES = [ + 'ADMIN', + 'SELF', + 'PUBLIC' +]; + +// The type of item that the tag is apply on. +const ITEM_TYPES = [ + 'ASSETS', + 'COMMENTS', + 'USERS' +]; + +/** + * The Mongo schema for a Comment Tag. + * @type {Schema} + */ +const TagSchema = new Schema({ + id: { + type: String, + default: uuid.v4, + unique: true + }, + + name: { + type: String, + unique: true + }, + + item_type: { + type: String, + enum: ITEM_TYPES + }, + + item_id: String, + + // The User ID of the user that assigned the status. + assigned_by: { + type: String, + default: null + }, + + privacy_type: { + type: String, + enum: PRIVACY_TYPES + }, + + // Additional metadata stored on the field. + metadata: Schema.Types.Mixed +}, { + _id: false +}); + +const Tag = mongoose.model('Tag', TagSchema); + +module.exports = Tag; diff --git a/models/user.js b/models/user.js index 2663410a7..fdd3ed74a 100644 --- a/models/user.js +++ b/models/user.js @@ -185,7 +185,9 @@ const USER_GRAPH_OPERATIONS = [ 'mutation:suspendUser', 'mutation:setCommentStatus', 'mutation:addCommentTag', - 'mutation:removeCommentTag' + 'mutation:removeCommentTag', + 'mutation:addUserTag', + 'mutation:removeUserTag' ]; /** @@ -207,7 +209,7 @@ UserSchema.method('can', function(...actions) { // {add,remove}CommentTag - requires admin and/or moderator role const userCanModifyTags = user => ['ADMIN', 'MODERATOR'].some(r => user.hasRoles(r)); - if (actions.some(a => ['mutation:removeCommentTag', 'mutation:addCommentTag'].includes(a)) && ! userCanModifyTags(this)) { + if (actions.some(a => ['mutation:removeCommentTag', 'mutation:addCommentTag', 'mutation:removeUserTag', 'mutation: addUserTag'].includes(a)) && ! userCanModifyTags(this)) { return false; } diff --git a/services/comments.js b/services/comments.js index 75b53873a..a7f483d2c 100644 --- a/services/comments.js +++ b/services/comments.js @@ -3,10 +3,8 @@ const CommentModel = require('../models/comment'); const ActionModel = require('../models/action'); const ActionsService = require('./actions'); -const ALLOWED_TAGS = [ - {name: 'STAFF'}, - {name: 'BEST'}, -]; +const TagModel = require('../models/tag'); +const TagsService = require('./tags'); const STATUSES = [ 'ACCEPTED', @@ -53,37 +51,14 @@ module.exports = class CommentsService { */ static addTag(id, name, assigned_by) { - if (ALLOWED_TAGS.find((t) => t.name === name) == null) { - return Promise.reject(new Error('tag not allowed')); - } + return TagsService.insertCommentTag({ + name, + item_id: id, + item_type: 'COMMENTS', + user_id: assigned_by, + }); - const filter = { - id, - 'tags.name': {$ne: name}, - }; - const update = { - $push: {tags: { - name, - assigned_by, - created_at: new Date() - }} - }; - return CommentModel.update(filter, update) - .then(({nModified}) => { - switch (nModified) { - case 0: - - // either the tag was already there, or the comment doesn't exist with that id... - throw new Error('Could not add tag to comment. Either the comment doesn\'t exist or the tag is already present.'); - case 1: - - // tag added - return; - default: - - // this should never happen because no multi parameter and unique index on id - } - }); + // Add the ID to the comment } /** @@ -93,25 +68,11 @@ module.exports = class CommentsService { * @param {String} name the name of the tag to add */ static removeTag(id, name) { - const filter = { - id, - 'tags.name': name, - }; - const update = {$pull: {tags: {name}}}; - return CommentModel.update(filter, update) - .then(({nModified}) => { - switch (nModified) { - case 0: - throw new Error('Could not remove tag from comment. Either the comment doesn\'t exist or the tag is not present'); - case 1: - - // tag removed - return; - default: - - // this should never happen because no multi parameter and unique index on id - } - }); + return TagModel.remove({ + item_type: 'COMMENTS', + item_id: id, + name + }); } /** diff --git a/services/mongoose.js b/services/mongoose.js index c7092326f..206075239 100644 --- a/services/mongoose.js +++ b/services/mongoose.js @@ -65,4 +65,5 @@ require('../models/action'); require('../models/asset'); require('../models/comment'); require('../models/setting'); +require('../models/tag'); require('../models/user'); diff --git a/services/tags.js b/services/tags.js new file mode 100644 index 000000000..caeb4e761 --- /dev/null +++ b/services/tags.js @@ -0,0 +1,72 @@ +const TagModel = require('../models/tag'); + +const ALLOWED_COMMENT_TAGS = [ + {name: 'STAFF'}, + {name: 'BEST'}, +]; + +module.exports = class TagsService { + + /** + * Finds an action by the id. + * @param {String} id identifier of the tag (uuid) + */ + static findById(id) { + return TagModel.findOne({id}); + } + + /** + * Add a tag. + * @param {string} name the actual tag + * @param {String} item_id identifier of the comment (uuid) + * @param {String} item_type type of the object being tag (COMMENTS) + * @param {String} user_id user id that assigned the tag (uuid) + * @param {String} privacy_type visibility of the tag on the comment + * @return {Promise} + */ + static insertCommentTag(tag) { + + if (ALLOWED_COMMENT_TAGS.find((t) => t.name === tag.name) == null) { + return Promise.reject(new Error('tag not allowed')); + } + + // Tags are made unique by using a query that can be reproducable, i.e., + // not containing user inputable values. + let query = { + name: tag.name, + item_id: tag.item_id, + item_type: tag.item_type, + assigned_by: tag.user_id, + privacy_type: tag.privacy_type + }; + + // Create/Update the tag. + return TagModel.findOneAndUpdate(query, tag, { + + // Ensure that if it's new, we return the new object created. + new: true, + + // Perform an upsert in the event that this doesn't exist. + upsert: true, + + // Set the default values if not provided based on the mongoose models. + setDefaultsOnInsert: true + }) + .then(({nModified}) => { + switch (nModified) { + case 0: + + // either the tag was already there, or the comment doesn't exist with that id... + throw new Error('Could not add tag to comment. Either the comment doesn\'t exist or the tag is already present.'); + case 1: + + // tag added + return; + default: + + // this should never happen because no multi parameter and unique index on id + } + }); + } + +}; diff --git a/test/server/graph/mutations/addCommentTag.js b/test/server/graph/mutations/addCommentTag.js index 018e96631..fbb7fe8a8 100644 --- a/test/server/graph/mutations/addCommentTag.js +++ b/test/server/graph/mutations/addCommentTag.js @@ -4,6 +4,7 @@ const {graphql} = require('graphql'); const schema = require('../../../../graph/schema'); const Context = require('../../../../graph/context'); const UserModel = require('../../../../models/user'); +const TagModel = require('../../../../models/tag'); const SettingsService = require('../../../../services/settings'); const CommentsService = require('../../../../services/comments'); @@ -37,7 +38,12 @@ describe('graph.mutations.addCommentTag', () => { console.error(response.errors); } expect(response.errors).to.be.empty; - expect(response.data.addCommentTag.comment.tags).to.deep.equal([{name: 'BEST'}]); + TagModel.find({ + item_id: response.data.addCommentTag.comment.id, + name: 'BEST' + }).then((tags) => { + expect(tags).to.have.length(1); + }); }); describe('users who cant add tags', () => {