Merge branch 'master' into fix-permalink

This commit is contained in:
David Jay
2017-02-28 18:07:31 -05:00
committed by GitHub
25 changed files with 575 additions and 207 deletions
+34 -13
View File
@@ -39,7 +39,14 @@ const getCountsByAssetID = (context, asset_ids) => {
/**
* Returns the comment count for all comments that are public based on their
* parent ids.
* @param {Object} context graph context
* @param {Object}
graph context
* @param {Array<String>} parent_ids the ids of parents for which there are
* comments that we want to get
*/
@@ -271,19 +278,33 @@ const genRecentComments = (_, ids) => {
};
/**
* genComments returns the comments by the id's specified that are considered
* public comments (i.e., accepted or not rejected).
* genComments returns the comments by the id's. Only admins can see non-public comments.
* @param {Object} context graph context
* @param {Array<String>} ids the comment id's to fetch
* @return {Promise} resolves to the comments
*/
const genComments = (context, ids) => {
return CommentModel.find({
id: {
$in: ids
},
status: {
$in: ['NONE', 'ACCEPTED']
}
})
.then(util.singleJoinBy(ids, 'id'));
const genComments = ({user}, ids) => {
let comments
if (user && user.hasRoles('ADMIN')) {
comments = CommentModel.find({
id: {
$in: ids
}
});
} else {
comments = CommentModel.find({
id: {
$in: ids
},
status: {
$in: ['NONE', 'ACCEPTED']
}
});
return comments.then(util.singleJoinBy(ids, 'id'));
*/
const genCommentsByID = (context, ids) => {
};
/**
+96 -34
View File
@@ -2,10 +2,12 @@ const _ = require('lodash');
const DataLoader = require('dataloader');
const {objectCacheKeyFn} = require('./util');
const CommentModel = require('../../models/comment');
const ActionModel = require('../../models/action');
const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => {
/**
* Returns a list of assets with action metadata included on the models.
*/
const getAssetMetrics = ({loaders: {Metrics, Assets, Comments}}, {from, to, sort, limit}) => {
let commentMetrics = {};
let assetMetrics = [];
@@ -14,6 +16,10 @@ const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => {
.then((actionSummaries) => {
commentMetrics = actionSummaries.reduce((acc, {item_id, action_type, count}) => {
if (action_type !== sort) {
return acc;
}
if (!(item_id in acc)) {
acc[item_id] = [];
}
@@ -24,10 +30,10 @@ const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => {
}, {});
// Collect just the comment id's.
let commentIDs = _.uniq(actionSummaries.map((as) => as.item_id));
let commentIDs = Object.keys(commentMetrics);
// Find those comments.
return Metrics.getSpecificComments.loadMany(commentIDs);
return Comments.get.loadMany(commentIDs);
})
.then((comments) => {
@@ -44,29 +50,24 @@ const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => {
}));
return {action_summaries, id: asset_id};
});
})
.filter((asset) => {
let contextActionSummary = asset.action_summaries.find((({action_type}) => action_type === sort));
if (contextActionSummary === null) {
return false;
}
return true;
})
// Sort these metrics by the predefined sort order. This will ensure that
// if the action summary does not exist on the object, that it is less
// prefered over the one that does have it.
assetMetrics.sort((a, b) => {
.sort((a, b) => {
let aActionSummary = a.action_summaries.find((({action_type}) => action_type === sort));
let bActionSummary = b.action_summaries.find((({action_type}) => action_type === sort));
// If either a or b don't have this action type, then one of them will
// automatically win.
if (aActionSummary == null || bActionSummary == null) {
if (bActionSummary != null) {
return 1;
}
if (aActionSummary != null) {
return -1;
}
return 0;
}
// Both of them had an actionCount, hence we can determine that we could
// compare the actual values directly.
return bActionSummary.actionCount - aActionSummary.actionCount;
@@ -99,6 +100,75 @@ const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => {
});
};
/**
* Returns a list of comments that are retrieved based on most activity within
* the indicated time range.
*/
const getCommentMetrics = ({loaders: {Metrics, Comments}}, {from, to, sort, limit}) => {
let commentActionSummaries = {};
return Metrics.getRecentActions.load({from, to})
.then((actionSummaries) => {
actionSummaries.sort((a, b) => {
let aActionSummary = a.action_type === sort ? a : null;
let bActionSummary = b.action_type === sort ? b : null;
// If either a or b don't have this action type, then one of them will
// automatically win.
if (aActionSummary == null || bActionSummary == null) {
if (bActionSummary != null) {
return 1;
}
if (aActionSummary != null) {
return -1;
}
return 0;
}
// Both of them had an actionCount, hence we can determine that we could
// compare the actual values directly.
return bActionSummary.count - aActionSummary.count;
});
commentActionSummaries = _.groupBy(actionSummaries, 'item_id');
// Grab the comment id's for comment where they have at least one of the
// actions being sorted by.
let commentIDs = Object.keys(commentActionSummaries).filter((item_id) => {
let contextActionSummary = commentActionSummaries[item_id].find(({action_type}) => action_type === sort);
if (contextActionSummary == null) {
return false;
}
return true;
});
// Only keep the top `limit`.
commentIDs = commentIDs.slice(0, limit);
// If there are no comment's to get, then just continue with an empty
// array.
if (commentIDs.length === 0) {
return [];
}
// Find those comments, this is the final stage, so let's get all the
// fields.
return Comments.get.loadMany(commentIDs);
})
.then((comments) => comments.map((comment) => {
// Add in the action summaries genrerated.
comment.action_summaries = commentActionSummaries[comment.id];
return comment;
}));
};
const getRecentActions = (context, {from, to}) => {
return ActionModel.aggregate([
@@ -131,25 +201,17 @@ const getRecentActions = (context, {from, to}) => {
]);
};
const getSpecificComments = (context, ids) => {
return CommentModel.find({
id: {
$in: ids
}
})
.select({
id: 1,
asset_id: 1
});
};
module.exports = (context) => ({
Metrics: {
getSpecificComments: new DataLoader((ids) => getSpecificComments(context, ids)),
getRecentActions: new DataLoader(([{from, to}]) => getRecentActions(context, {from, to}).then((as) => [as]), {
batch: false,
cacheKeyFn: objectCacheKeyFn('from', 'to')
}),
get: ({from, to, sort, limit}) => getMetrics(context, {from, to, sort, limit})
Assets: {
get: ({from, to, sort, limit}) => getAssetMetrics(context, {from, to, sort, limit})
},
Comments: {
get: ({from, to, sort, limit}) => getCommentMetrics(context, {from, to, sort, limit})
}
}
});
+5 -1
View File
@@ -32,7 +32,11 @@ const Comment = {
return null;
},
action_summaries({id}, _, {loaders: {Actions}}) {
action_summaries({id, action_summaries}, _, {loaders: {Actions}}) {
if (action_summaries) {
return action_summaries;
}
return Actions.getSummariesByItemID.load(id);
},
asset({asset_id}, _, {loaders: {Assets}}) {
+10 -2
View File
@@ -58,12 +58,20 @@ const RootQuery = {
return Comments.getCountByQuery({statuses, asset_id, parent_id});
},
metrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics}}) {
assetMetrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics: {Assets}}}) {
if (user == null || !user.hasRoles('ADMIN')) {
return null;
}
return Metrics.get({from, to, sort, limit});
return Assets.get({from, to, sort, limit});
},
commentMetrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics: {Comments}}}) {
if (user == null || !user.hasRoles('ADMIN')) {
return null;
}
return Comments.get({from, to, sort, limit});
},
// This returns the current user, ensure that if we aren't logged in, we
+7 -3
View File
@@ -500,9 +500,13 @@ type RootQuery {
# role.
me: User
# Metrics related to user actions are saturated into the assets returned. The
# sort will affect if it will allow
metrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset]
# Asset metrics related to user actions are saturated into the assets
# returned.
assetMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset!]
# Comment metrics related to user actions are saturated into the comments
# returned.
commentMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Comment!]
}
################################################################################