diff --git a/apis/collection/backend.js b/apis/collection/backend.js index 6fa7c150e1..bf39d8a642 100644 --- a/apis/collection/backend.js +++ b/apis/collection/backend.js @@ -1,5 +1,3 @@ -import ss from 'simple-statistics'; - ApiBackends = new Mongo.Collection('apiBackends'); // RegEx constants @@ -653,49 +651,28 @@ Schemas.ApiBackendsSchema = new SimpleSchema({ type: "hidden", label: false } - } -}); - -ApiBackends.attachSchema(Schemas.ApiBackendsSchema); - -ApiBackends.allow({ - insert: function () { - return true; - }, - update: function (userId, apiBackendDoc) { - // Save ID of API Backend - const apiBackendId = apiBackendDoc._id; - // Get API backend with ID - const apiBackend = ApiBackends.findOne(apiBackendId); - // Check if current user can edit API Backend - let currentUserCanEdit = apiBackend.currentUserCanEdit(); - - if (currentUserCanEdit) { - // User is allowed to perform action - return true; - } else { - // User is not allowded to perform action - return false; + }, + averageRating: { + type: Number, + decimal: true, + optional: true, + autoform: { + type: "hidden", + label: false } }, - remove: function (userId, apiBackendDoc) { - // Save ID of API Backend - const apiBackendId = apiBackendDoc._id; - // Get API backend with ID - const apiBackend = ApiBackends.findOne(apiBackendId); - // Check if current user can edit API Backend - let currentUserCanEdit = apiBackend.currentUserCanEdit(); - - if (currentUserCanEdit) { - // User is allowed to perform action - return true; - } else { - // User is not allowded to perform action - return false; + bookmarkCount: { + type: Number, + optional: true, + autoform: { + type: "hidden", + label: false } } }); +ApiBackends.attachSchema(Schemas.ApiBackendsSchema); + SimpleSchema.messages({ // RegEx messages regEx: [ @@ -705,80 +682,3 @@ SimpleSchema.messages({ // update password form "updatePassword_passwordsMismatch": "Passwords do not match" }); - -ApiBackends.helpers({ - 'getRating': function () { - // Get API Backend ID - apiBackendId = this._id; - - // Check if user is logged in - if (Meteor.userId()) { - // Check if user has rated API Backend - var userRating = ApiBackendRatings.findOne({ - userId: Meteor.userId(), - apiBackendId: apiBackendId - }); - - if (userRating) { - return userRating.rating; - } - } - - // Otherwise, get average rating - - // Fetch all ratings - var apiBackendRatings = ApiBackendRatings.find({ - apiBackendId: apiBackendId - }).fetch(); - - // If ratings exist - if (apiBackendRatings) { - // Create array containing only rating values - var apiBackendRatingsArray = _.map(apiBackendRatings, function (rating) { - // get only the rating value; omit User ID and API Backend ID fields - return rating.rating; - }); - - // Get the average (mean) value for API Backend ratings - var apiBackendRatingsAverage = ss.mean(apiBackendRatingsArray); - - return apiBackendRatingsAverage; - } - }, - currentUserCanEdit: function() { - // Get current userId - var userId = Meteor.userId(); - - // Check that user is logged in - if( userId ) { - // Check if user is API manager - var isManager = _.contains(this.managerIds, userId); - - if (isManager) { - return true; - } - - // Check if user is administrator - var isAdmin = Roles.userIsInRole(userId, ['admin']); - - if (isAdmin) { - return true; - } - } else { - // User is not logged in - return false; - } - }, - currentUserIsManager: function () { - // Get current User ID - var userId = Meteor.userId(); - - // Get Manager IDs array from API Backend document - var managerIds = this.managerIds; - - // Check if User ID is in Manager IDs array - var isManager = _.contains(managerIds, userId); - - return isManager; - } -}); diff --git a/apis/collection/helpers.js b/apis/collection/helpers.js new file mode 100644 index 0000000000..3bf2630fe1 --- /dev/null +++ b/apis/collection/helpers.js @@ -0,0 +1,114 @@ +import ss from 'simple-statistics'; + +ApiBackends.helpers({ + getAverageRating () { + // Fetch all ratings + var apiBackendRatings = ApiBackendRatings.find({ + apiBackendId: this._id + }).fetch(); + + // If ratings exist + if (apiBackendRatings) { + // Create array containing only rating values + var apiBackendRatingsArray = _.map(apiBackendRatings, function (rating) { + // get only the rating value; omit User ID and API Backend ID fields + return rating.rating; + }); + + // Get the average (mean) value for API Backend ratings + var apiBackendRatingsAverage = ss.mean(apiBackendRatingsArray); + + return apiBackendRatingsAverage; + } + }, + setAverageRating () { + // get average rating value + const averageRating = this.getAverageRating(); + + // Check if average rating calculation succeeds + if (averageRating) { + // Update the API Backend with average rating value + ApiBackends.update(this._id, {$set: {averageRating}}); + } + }, + getBookmarkCount () { + // Get API Backend ID + const apiBackendId = this._id; + + // Get count of API Bookmarks where API Backend ID is in API Backend IDs array + const apiBookmarkCount = ApiBookmarks.find({apiIds: apiBackendId}).count(); + + return apiBookmarkCount; + }, + setBookmarkCount () { + // get average rating value + const bookmarkCount = this.getBookmarkCount(); + + // Check if average rating calculation succeeds + if (bookmarkCount) { + // Update the API Backend with average rating value + ApiBackends.update(this._id, {$set: {bookmarkCount}}); + } else { + ApiBackends.update(this._id, {$unset: {bookmarkCount: ""}}) + } + }, + getRating () { + // Get API Backend ID + const apiBackendId = this._id; + + // Get current user ID + const userId = Meteor.userId(); + + // Check if user is logged in + if (Meteor.userId()) { + // Check if user has rated API Backend + var userRating = ApiBackendRatings.findOne({ + apiBackendId, + userId + }); + + if (userRating) { + return userRating.rating; + } + } + + // Otherwise, get average rating + return this.averageRating; + }, + currentUserCanEdit () { + // Get current userId + var userId = Meteor.userId(); + + // Check that user is logged in + if( userId ) { + // Check if user is API manager + var isManager = _.contains(this.managerIds, userId); + + if (isManager) { + return true; + } + + // Check if user is administrator + var isAdmin = Roles.userIsInRole(userId, ['admin']); + + if (isAdmin) { + return true; + } + } else { + // User is not logged in + return false; + } + }, + currentUserIsManager () { + // Get current User ID + var userId = Meteor.userId(); + + // Get Manager IDs array from API Backend document + var managerIds = this.managerIds; + + // Check if User ID is in Manager IDs array + var isManager = _.contains(managerIds, userId); + + return isManager; + } +}); diff --git a/apis/collection/permissions.js b/apis/collection/permissions.js new file mode 100644 index 0000000000..43cdace8b4 --- /dev/null +++ b/apis/collection/permissions.js @@ -0,0 +1,52 @@ +ApiBackends.allow({ + insert: function () { + return true; + }, + update: function (userId, apiBackendDoc) { + // Save ID of API Backend + const apiBackendId = apiBackendDoc._id; + // Get API backend with ID + const apiBackend = ApiBackends.findOne(apiBackendId); + // Check if current user can edit API Backend + let currentUserCanEdit = apiBackend.currentUserCanEdit(); + + if (currentUserCanEdit) { + // User is allowed to perform action + return true; + } else { + // User is not allowded to perform action + return false; + } + }, + remove: function (userId, apiBackendDoc) { + // Save ID of API Backend + const apiBackendId = apiBackendDoc._id; + // Get API backend with ID + const apiBackend = ApiBackends.findOne(apiBackendId); + // Check if current user can edit API Backend + let currentUserCanEdit = apiBackend.currentUserCanEdit(); + + if (currentUserCanEdit) { + // User is allowed to perform action + return true; + } else { + // User is not allowded to perform action + return false; + } + } +}); + +ApiBackends.deny({ + insert () { + // Don't allow user to set average rating or bookmark count fields + if (_.contains(fields, "averageRating") || _.contains(fields, "bookmarkCount")) { + return true; + } + }, + update () { + // Don't allow user to set average rating or bookmark count fields + if (_.contains(fields, "averageRating") || _.contains(fields, "bookmarkCount")) { + return true; + } + } +}); diff --git a/apis/server/methods/bookmarks.js b/apis/server/methods/bookmarks.js new file mode 100644 index 0000000000..dadd5799e7 --- /dev/null +++ b/apis/server/methods/bookmarks.js @@ -0,0 +1,19 @@ +Meteor.methods({ + setAllApiBackendBookmarkCounts () { + // Get all API Backends + const apiBackends = ApiBackends.find().fetch(); + + // Update the average rating value for each API Backend + apiBackends.forEach(function (apiBackend) { + // Set average rating value for current API Backend + apiBackend.setBookmarkCount(); + }); + }, + setApiBackendBookmarkCount (apiBackendId) { + // Get API Backend + const apiBackend = ApiBackends.findOne(apiBackendId); + + // Update the API Backend bookmark count + apiBackend.setBookmarkCount(); + } +}); diff --git a/apis/server/methods/ratings.js b/apis/server/methods/ratings.js new file mode 100644 index 0000000000..c33df1a8a9 --- /dev/null +++ b/apis/server/methods/ratings.js @@ -0,0 +1,19 @@ +Meteor.methods({ + setAllApiBackendAverageRatings () { + // Get all API Backends + const apiBackends = ApiBackends.find().fetch(); + + // Update the average rating value for each API Backend + apiBackends.forEach(function (apiBackend) { + // Set average rating value for current API Backend + apiBackend.setAverageRating(); + }); + }, + setApiBackendAverageRating (apiBackendId) { + // Get API Backend + const apiBackend = ApiBackends.findOne(apiBackendId); + + // Update the API Backend bookmark count + apiBackend.setAverageRating(); + } +}); diff --git a/apis/server/startup.js b/apis/server/startup.js new file mode 100644 index 0000000000..1f15cd9e2e --- /dev/null +++ b/apis/server/startup.js @@ -0,0 +1,7 @@ +Meteor.startup(function () { + // Make sure all API backends have bookmark counts + Meteor.call('setAllApiBackendBookmarkCounts'); + + // Make sure all API backends have average ratings + Meteor.call('setAllApiBackendAverageRatings'); +}); diff --git a/bookmarks/server/methods.js b/bookmarks/server/methods.js index f961c34a2c..56f67a0cfc 100644 --- a/bookmarks/server/methods.js +++ b/bookmarks/server/methods.js @@ -6,10 +6,10 @@ Meteor.methods({ // object to store currentUserId and the Api ID var userBookmarks = {userId: currentUserId, apiIds: apiBackendIds}; - + // If possible, get the bookmarks for current user. var existingUserBookmarks = ApiBookmarks.findOne({userId: currentUserId}); - + // Check if user has existing bookmarks if (existingUserBookmarks) { // Get an array of bookmark IDs @@ -31,14 +31,16 @@ Meteor.methods({ } // Updating current user apiBookmarks - ApiBookmarks.update({userId: currentUserId},{$set: {apiIds: apiIds} }); + ApiBookmarks.update({userId: currentUserId},{$set: { apiIds } }); } else { // Insert bookmark to database ApiBookmarks.insert(userBookmarks); } + // Update the API Backend bookmark count + Meteor.call("setApiBackendBookmarkCount", backendId); + return apiIds; } }); - diff --git a/catalogue/tabular.js b/catalogue/tabular.js index 6a35b61b8b..1e9e767e4e 100644 --- a/catalogue/tabular.js +++ b/catalogue/tabular.js @@ -17,9 +17,11 @@ TabularTables.ApiTable = new Tabular.Table({ }, {tmpl: Meteor.isClient && Template.favourite, title: "Bookmark"}, { - tmpl: Meteor.isClient && Template.apiBackendRating, - title: "Rating" - } + data: "averageRating", + tmpl: Meteor.isClient && Template.apiBackendRating, + title: "Rating" + }, + {data: "bookmarkCount", title: "Popularity"}, ], responsive: true, autoWidth: false diff --git a/ratings/client/rating.js b/ratings/client/rating.js index d4f0aeaf34..7b2acd8bdd 100644 --- a/ratings/client/rating.js +++ b/ratings/client/rating.js @@ -23,26 +23,29 @@ Template.apiBackendRating.rendered = function () { var instance = this; // Get API Backend ID from template instance - var apiBackend = instance.data; + var apiBackendId = instance.data._id; + + // get API Backend document + const apiBackend = ApiBackends.findOne(apiBackendId); instance.autorun(function () { // Make sure API Backend Rating subscription is ready if (instance.apiRatingSubscription.ready()) { // Check if user has previously rated API Backend var userRating = ApiBackendRatings.findOne({ - apiBackendId: apiBackend._id, + apiBackendId, userId: Meteor.userId() }); // Add the jQuery RateIt widget - $("#rating-" + apiBackend._id).rateit({ + $("#rating-" + apiBackendId).rateit({ max: 4, step: 1, resetable: false, // Only logged in user can rate readonly: Meteor.userId() ? false : true, // use previous rating, if exists - value: userRating ? userRating.rating : apiBackend.getRating() + value: userRating ? userRating.rating : apiBackend.averageRating }); } }); @@ -91,6 +94,9 @@ Template.apiBackendRating.events({ // Otherwise, create a new rating ApiBackendRatings.insert(apiBackendRating); } + + // Update the API Backend average rating + Meteor.call("setApiBackendAverageRating", apiBackendId); } });