Merge branch 'next' into next-readmore

This commit is contained in:
Kiwi
2018-09-27 13:43:41 +02:00
committed by GitHub
6 changed files with 164 additions and 24 deletions
@@ -6,6 +6,7 @@ const Asset: GQLAssetTypeResolver<Asset> = {
ctx.loaders.Comments.forAsset(asset.id, input),
// TODO: implement this.
isClosed: () => false,
commentCounts: asset => asset.comment_counts,
};
export default Asset;
@@ -0,0 +1,14 @@
import {
GQLCOMMENT_STATUS,
GQLCommentCountsTypeResolver,
} from "talk-server/graph/tenant/schema/__generated__/types";
import { CommentStatusCounts } from "talk-server/models/asset";
const CommentCounts: GQLCommentCountsTypeResolver<CommentStatusCounts> = {
totalVisible: commentCounts =>
commentCounts[GQLCOMMENT_STATUS.ACCEPTED] +
commentCounts[GQLCOMMENT_STATUS.NONE],
statuses: commentCounts => commentCounts,
};
export default CommentCounts;
@@ -4,6 +4,7 @@ import { GQLResolver } from "talk-server/graph/tenant/schema/__generated__/types
import Asset from "./asset";
import AuthIntegrations from "./auth_integrations";
import Comment from "./comment";
import CommentCounts from "./comment_counts";
import Mutation from "./mutation";
import Profile from "./profile";
import Query from "./query";
@@ -12,6 +13,7 @@ const Resolvers: GQLResolver = {
Asset,
AuthIntegrations,
Comment,
CommentCounts,
Cursor,
Mutation,
Profile,
@@ -265,7 +265,7 @@ type KarmaThreshold {
type KarmaThresholds {
"""
flag represents karma settings in relation to how well a User's flagging
ability aligns with the moderation decicions made by moderators.
ability aligns with the moderation decisions made by moderators.
"""
flag: KarmaThreshold!
@@ -284,7 +284,7 @@ type Karma {
"""
karmaThresholds contains the currently set thresholds for triggering Trust
beheviour.
behavior.
"""
thresholds: KarmaThresholds!
}
@@ -741,6 +741,50 @@ type CommentsConnection {
pageInfo: PageInfo!
}
################################################################################
## CommentCounts
################################################################################
type CommentStatusCounts {
"""
The comment is not PREMOD, but was not applied a moderation status by a
moderator.
"""
NONE: Int!
"""
The comment has been accepted by a moderator.
"""
ACCEPTED: Int!
"""
The comment has been rejected by a moderator.
"""
REJECTED: Int!
"""
The comment was created while the asset's premoderation option was on, and
new comments that haven't been moderated yet are referred to as
"premoderated" or "premod" comments.
"""
PREMOD: Int!
"""
SYSTEM_WITHHELD represents a comment that was withheld by the system because
it was flagged by an internal process for further review.
"""
SYSTEM_WITHHELD: Int!
}
type CommentCounts {
"""
totalVisible will return the count of all visible Comments.
"""
totalVisible: Int!
statuses: CommentStatusCounts! @auth(roles: [ADMIN, MODERATOR])
}
################################################################################
## Asset
################################################################################
@@ -795,6 +839,11 @@ type Asset {
"""
isClosed: Boolean!
"""
commentCounts stores all the counts of Comments that are left on the Comment.
"""
commentCounts: CommentCounts!
"""
createdAt is the date that the Asset was created at.
"""
@@ -1119,7 +1168,7 @@ input SettingsKarmaThresholdInput {
input SettingsKarmaThresholdsInput {
"""
flag represents karma settings in relation to how well a User's flagging
ability aligns with the moderation decicions made by moderators.
ability aligns with the moderation decisions made by moderators.
"""
flag: SettingsKarmaThresholdInput
@@ -1138,7 +1187,7 @@ input SettingsKarmaInput {
"""
karmaThresholds contains the currently set thresholds for triggering Trust
beheviour.
behavior.
"""
thresholds: SettingsKarmaThresholdsInput
}
+73 -16
View File
@@ -1,9 +1,9 @@
import { defaults } from "lodash";
import { Db } from "mongodb";
import uuid from "uuid";
import { Omit } from "talk-common/types";
import { dotize } from "talk-common/utils/dotize";
import { GQLCOMMENT_STATUS } from "talk-server/graph/tenant/schema/__generated__/types";
import { ModerationSettings } from "talk-server/models/settings";
import { TenantResource } from "talk-server/models/tenant";
@@ -11,12 +11,24 @@ function collection(db: Db) {
return db.collection<Readonly<Asset>>("assets");
}
// TODO: (wyattjoh) write a test to verify that this set of counts is always in sync with GQLCOMMENT_STATUS.
export interface CommentStatusCounts {
[GQLCOMMENT_STATUS.ACCEPTED]: number;
[GQLCOMMENT_STATUS.NONE]: number;
[GQLCOMMENT_STATUS.PREMOD]: number;
[GQLCOMMENT_STATUS.REJECTED]: number;
[GQLCOMMENT_STATUS.SYSTEM_WITHHELD]: number;
}
export interface Asset extends TenantResource {
readonly id: string;
url: string;
scraped?: Date;
closedAt?: Date;
closedMessage?: string;
created_at: Date;
modified_date?: Date;
title?: string;
description?: string;
image?: string;
@@ -24,11 +36,15 @@ export interface Asset extends TenantResource {
subsection?: string;
author?: string;
publication_date?: Date;
modified_date?: Date;
created_at: Date;
/**
* settings provides a point where the settings can be overriden for a
* comment_counts stores the different counts for each comment on the Asset
* according to their statuses.
*/
comment_counts: CommentStatusCounts;
/**
* settings provides a point where the settings can be overridden for a
* specific Asset.
*/
settings?: Partial<ModerationSettings>;
@@ -51,23 +67,22 @@ export async function upsertAsset(
// Create the asset, optionally sourcing the id from the input, additionally
// porting in the tenant_id.
const update: { $setOnInsert: Asset } = {
$setOnInsert: defaults(
{
url,
tenant_id: tenantID,
created_at: now,
},
{ id },
{
id: uuid.v4(),
}
),
$setOnInsert: {
id: id ? id : uuid.v4(),
url,
tenant_id: tenantID,
created_at: now,
comment_counts: createEmptyCommentCounts(),
},
};
// Perform the find and update operation to try and find and or create the
// asset.
const { value: asset } = await collection(db).findOneAndUpdate(
{ url },
{
url,
tenant_id: tenantID,
},
update,
{
// Create the object if it doesn't already exist.
@@ -89,6 +104,48 @@ export async function upsertAsset(
return asset;
}
/**
* updateCommentStatusCount increments the number of status counts for the
* given Asset ID.
*
* @param mongo the database handle
* @param tenantID the tenant that the Asset is on.
* @param id the ID of the Asset.
* @param commentStatusCounts the update document that contains a positive or
* negative number of comments to increment on the given Asset.
*/
export async function updateCommentStatusCount(
mongo: Db,
tenantID: string,
id: string,
commentStatusCounts: Partial<CommentStatusCounts>
) {
const { value: asset } = await collection(mongo).findOneAndUpdate(
{
id,
tenant_id: tenantID,
},
// Update all the specific comment status counts that are associated with
// each of the counts.
{ $inc: dotize({ comment_counts: commentStatusCounts }) },
// False to return the updated document instead of the original
// document.
{ returnOriginal: false }
);
return asset;
}
function createEmptyCommentCounts(): CommentStatusCounts {
return {
[GQLCOMMENT_STATUS.ACCEPTED]: 0,
[GQLCOMMENT_STATUS.NONE]: 0,
[GQLCOMMENT_STATUS.PREMOD]: 0,
[GQLCOMMENT_STATUS.REJECTED]: 0,
[GQLCOMMENT_STATUS.SYSTEM_WITHHELD]: 0,
};
}
export interface FindOrCreateAssetInput {
id?: string;
url?: string;
+21 -4
View File
@@ -1,7 +1,10 @@
import { Db } from "mongodb";
import { Omit } from "talk-common/types";
import { retrieveAsset } from "talk-server/models/asset";
import {
retrieveAsset,
updateCommentStatusCount,
} from "talk-server/models/asset";
import {
createComment,
CreateCommentInput,
@@ -84,6 +87,11 @@ export async function create(
);
}
// Increment the status count for the particular status on the Asset.
await updateCommentStatusCount(mongo, tenant.id, asset.id, {
[status]: 1,
});
return comment;
}
@@ -100,7 +108,7 @@ export async function edit(
req?: Request
) {
// Get the comment that we're editing.
let comment = await retrieveComment(mongo, tenant.id, input.id);
const comment = await retrieveComment(mongo, tenant.id, input.id);
if (!comment) {
// TODO: replace to match error returned by the models/comments.ts
throw new Error("comment not found");
@@ -124,7 +132,7 @@ export async function edit(
// TODO: (wyattjoh) use the actions somehow.
comment = await editComment(mongo, tenant.id, {
const editedComment = await editComment(mongo, tenant.id, {
id: input.id,
author_id: author.id,
body: input.body,
@@ -139,5 +147,14 @@ export async function edit(
),
});
return comment;
if (comment.status !== editedComment.status) {
// Increment the status count for the particular status on the Asset, and
// decrement the status on the comment's previous status.
await updateCommentStatusCount(mongo, tenant.id, asset.id, {
[comment.status]: -1,
[editedComment.status]: 1,
});
}
return editedComment;
}