mirror of
https://github.com/wassname/talk.git
synced 2026-07-08 17:21:05 +08:00
Merge branch 'next' into next-readmore
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user