mirror of
https://github.com/wassname/talk.git
synced 2026-08-19 12:40:16 +08:00
Merge branch 'next' into next-respect
This commit is contained in:
@@ -3,6 +3,7 @@ import DataLoader from "dataloader";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import {
|
||||
AssetToCommentsArgs,
|
||||
CommentToParentsArgs,
|
||||
CommentToRepliesArgs,
|
||||
GQLActionPresence,
|
||||
GQLCOMMENT_SORT,
|
||||
@@ -12,10 +13,30 @@ import {
|
||||
retrieveManyUserActionPresence,
|
||||
} from "talk-server/models/action";
|
||||
import {
|
||||
Comment,
|
||||
retrieveCommentAssetConnection,
|
||||
retrieveCommentParentsConnection,
|
||||
retrieveCommentRepliesConnection,
|
||||
retrieveManyComments,
|
||||
} from "talk-server/models/comment";
|
||||
import { Connection } from "talk-server/models/connection";
|
||||
|
||||
/**
|
||||
* primeCommentsFromConnection will prime a given context with the comments
|
||||
* retrieved via a connection.
|
||||
*
|
||||
* @param ctx graph context to use to prime the loaders.
|
||||
*/
|
||||
const primeCommentsFromConnection = (ctx: Context) => (
|
||||
connection: Readonly<Connection<Readonly<Comment>>>
|
||||
) => {
|
||||
// For each of the edges, prime the comment loader.
|
||||
connection.edges.forEach(({ node }) => {
|
||||
ctx.loaders.Comments.comment.prime(node.id, node);
|
||||
});
|
||||
|
||||
return connection;
|
||||
};
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
comment: new DataLoader((ids: string[]) =>
|
||||
@@ -45,7 +66,7 @@ export default (ctx: Context) => ({
|
||||
first,
|
||||
orderBy,
|
||||
after,
|
||||
}),
|
||||
}).then(primeCommentsFromConnection(ctx)),
|
||||
forParent: (
|
||||
assetID: string,
|
||||
parentID: string,
|
||||
@@ -66,5 +87,11 @@ export default (ctx: Context) => ({
|
||||
orderBy,
|
||||
after,
|
||||
}
|
||||
),
|
||||
).then(primeCommentsFromConnection(ctx)),
|
||||
parents: (comment: Comment, { last = 1, before }: CommentToParentsArgs) =>
|
||||
retrieveCommentParentsConnection(ctx.mongo, ctx.tenant.id, comment, {
|
||||
last,
|
||||
// The cursor passed here is always going to be a number.
|
||||
before: before as number,
|
||||
}).then(primeCommentsFromConnection(ctx)),
|
||||
});
|
||||
|
||||
@@ -2,8 +2,17 @@ import DataLoader from "dataloader";
|
||||
import Context from "talk-server/graph/tenant/context";
|
||||
import { retrieveManyUsers, User } from "talk-server/models/user";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
user: new DataLoader<string, User | null>(ids =>
|
||||
export default (ctx: Context) => {
|
||||
const user = new DataLoader<string, User | null>(ids =>
|
||||
retrieveManyUsers(ctx.mongo, ctx.tenant.id, ids)
|
||||
),
|
||||
});
|
||||
);
|
||||
|
||||
if (ctx.user) {
|
||||
// Prime the current logged in user in the dataloader cache.
|
||||
user.prime(ctx.user.id, ctx.user);
|
||||
}
|
||||
|
||||
return {
|
||||
user,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { GQLCommentTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { getRequestedFields } from "talk-server/graph/tenant/resolvers/util";
|
||||
import {
|
||||
GQLComment,
|
||||
GQLCommentTypeResolver,
|
||||
} from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { decodeActionCounts } from "talk-server/models/action";
|
||||
import { Comment } from "talk-server/models/comment";
|
||||
import { createConnection } from "talk-server/models/connection";
|
||||
|
||||
const Comment: GQLCommentTypeResolver<Comment> = {
|
||||
editing: (comment, input, ctx) => ({
|
||||
@@ -17,12 +22,68 @@ const Comment: GQLCommentTypeResolver<Comment> = {
|
||||
author: (comment, input, ctx) =>
|
||||
ctx.loaders.Users.user.load(comment.author_id),
|
||||
replies: (comment, input, ctx) =>
|
||||
ctx.loaders.Comments.forParent(comment.asset_id, comment.id, input),
|
||||
comment.reply_count > 0
|
||||
? ctx.loaders.Comments.forParent(comment.asset_id, comment.id, input)
|
||||
: createConnection(),
|
||||
actionCounts: comment => decodeActionCounts(comment.action_counts),
|
||||
myActionPresence: (comment, input, ctx) =>
|
||||
ctx.user
|
||||
? ctx.loaders.Comments.retrieveMyActionPresence.load(comment.id)
|
||||
: null,
|
||||
parentCount: comment =>
|
||||
comment.parent_id ? comment.grandparent_ids.length + 1 : 0,
|
||||
depth: comment =>
|
||||
comment.parent_id ? comment.grandparent_ids.length + 1 : 0,
|
||||
replyCount: comment => comment.reply_count,
|
||||
rootParent: (comment, input, ctx, info) => {
|
||||
// If there isn't a parent, then return nothing!
|
||||
if (!comment.parent_id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// rootParentID is the root parent id for a given comment.
|
||||
const rootParentID =
|
||||
comment.grandparent_ids.length > 0
|
||||
? comment.grandparent_ids[0]
|
||||
: comment.parent_id;
|
||||
|
||||
// Get the field names of the fields being requested, if it's only the ID,
|
||||
// we have that, so no need to make a database request.
|
||||
const fields = getRequestedFields<GQLComment>(info);
|
||||
if (fields.length === 1 && fields[0] === "id") {
|
||||
return {
|
||||
id: rootParentID,
|
||||
};
|
||||
}
|
||||
|
||||
// We want more than the ID! Get the comment!
|
||||
// TODO: (wyattjoh) if the parent and the parents (containing the parent) are requested, the parent comment is retrieved from the database twice. Investigate ways of reducing i/o.
|
||||
return ctx.loaders.Comments.comment.load(rootParentID);
|
||||
},
|
||||
parent: (comment, input, ctx, info) => {
|
||||
// If there isn't a parent, then return nothing!
|
||||
if (!comment.parent_id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the field names of the fields being requested, if it's only the ID,
|
||||
// we have that, so no need to make a database request.
|
||||
const fields = getRequestedFields<GQLComment>(info);
|
||||
if (fields.length === 1 && fields[0] === "id") {
|
||||
return {
|
||||
id: comment.parent_id,
|
||||
};
|
||||
}
|
||||
|
||||
// We want more than the ID! Get the comment!
|
||||
// TODO: (wyattjoh) if the parent and the parents (containing the parent) are requested, the parent comment is retrieved from the database twice. Investigate ways of reducing i/o.
|
||||
return ctx.loaders.Comments.comment.load(comment.parent_id);
|
||||
},
|
||||
parents: (comment, input, ctx) =>
|
||||
// Some resolver optimization.
|
||||
comment.parent_id
|
||||
? ctx.loaders.Comments.parents(comment, input)
|
||||
: createConnection(),
|
||||
};
|
||||
|
||||
export default Comment;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { GraphQLResolveInfo } from "graphql";
|
||||
import graphqlFields from "graphql-fields";
|
||||
import { pull } from "lodash";
|
||||
|
||||
/**
|
||||
* getRequestedFields returns the fields in an array that are being queried for.
|
||||
*
|
||||
* @param info query information
|
||||
*/
|
||||
export function getRequestedFields<T>(info: GraphQLResolveInfo) {
|
||||
return pull(Object.keys(graphqlFields<T>(info)), "__typename");
|
||||
}
|
||||
@@ -447,6 +447,27 @@ type Karma {
|
||||
thresholds: KarmaThresholds!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## CharCount
|
||||
################################################################################
|
||||
|
||||
type CharCount {
|
||||
"""
|
||||
enabled when true, enables the character count moderation phase.
|
||||
"""
|
||||
enabled: Boolean!
|
||||
|
||||
"""
|
||||
min is the smallest length of a Comment that may be posted.
|
||||
"""
|
||||
min: Int
|
||||
|
||||
"""
|
||||
max is the largest length of a Comment that may be posted.
|
||||
"""
|
||||
max: Int
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Email
|
||||
################################################################################
|
||||
@@ -589,14 +610,9 @@ type Settings {
|
||||
editCommentWindowLength: Int!
|
||||
|
||||
"""
|
||||
charCountEnable is true when the character count restriction is enabled.
|
||||
charCount stores the character count moderation settings.
|
||||
"""
|
||||
charCountEnable: Boolean!
|
||||
|
||||
"""
|
||||
charCount is the maximum number of characters a comment may be.
|
||||
"""
|
||||
charCount: Int
|
||||
charCount: CharCount!
|
||||
|
||||
"""
|
||||
organizationName is the name of the organization.
|
||||
@@ -807,11 +823,22 @@ type Comment {
|
||||
"""
|
||||
status: COMMENT_STATUS!
|
||||
|
||||
"""
|
||||
parentCount is the number of direct parents for this Comment. Currently this
|
||||
value is the same as depth.
|
||||
"""
|
||||
parentCount: Int!
|
||||
|
||||
"""
|
||||
depth is the number of levels that a given comment is deep.
|
||||
"""
|
||||
depth: Int!
|
||||
|
||||
"""
|
||||
replyCount is the number of replies. Only direct replies to this Comment
|
||||
are counted. Deleted comments are included in this count.
|
||||
"""
|
||||
replyCount: Int
|
||||
replyCount: Int!
|
||||
|
||||
"""
|
||||
replies will return the replies to this Comment.
|
||||
@@ -820,7 +847,24 @@ type Comment {
|
||||
first: Int = 10
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
): CommentsConnection
|
||||
): CommentsConnection!
|
||||
|
||||
"""
|
||||
parent is the immediate parent of a given comment.
|
||||
"""
|
||||
parent: Comment
|
||||
|
||||
"""
|
||||
rootParent is the highest level parent Comment. This Comment would have been
|
||||
left on the Asset itself.
|
||||
"""
|
||||
rootParent: Comment
|
||||
|
||||
"""
|
||||
parents returns a CommentsConnection that allows accessing direct parents of
|
||||
the given Comment.
|
||||
"""
|
||||
parents(last: Int = 1, before: Cursor): CommentsConnection!
|
||||
|
||||
"""
|
||||
editing returns details about the edit status of a Comment.
|
||||
@@ -997,11 +1041,6 @@ type Query {
|
||||
"""
|
||||
comment(id: ID!): Comment
|
||||
|
||||
"""
|
||||
assets returns a AssetsConnection.
|
||||
"""
|
||||
assets(cursor: Cursor, limit: Int = 10): AssetsConnection
|
||||
|
||||
"""
|
||||
asset is the Asset specified by its ID/URL.
|
||||
"""
|
||||
@@ -1304,6 +1343,23 @@ input SettingsKarmaInput {
|
||||
thresholds: SettingsKarmaThresholdsInput
|
||||
}
|
||||
|
||||
input SettingsCharCountInput {
|
||||
"""
|
||||
enabled when true, enables the character count moderation phase.
|
||||
"""
|
||||
enabled: Boolean
|
||||
|
||||
"""
|
||||
min is the smallest length of a Comment that may be posted.
|
||||
"""
|
||||
min: Int
|
||||
|
||||
"""
|
||||
max is the largest length of a Comment that may be posted.
|
||||
"""
|
||||
max: Int
|
||||
}
|
||||
|
||||
"""
|
||||
SettingsInput is the partial type of the Settings type for performing mutations.
|
||||
"""
|
||||
@@ -1395,16 +1451,6 @@ input SettingsInput {
|
||||
"""
|
||||
editCommentWindowLength: Int
|
||||
|
||||
"""
|
||||
charCountEnable is true when the character count restriction is enabled.
|
||||
"""
|
||||
charCountEnable: Boolean
|
||||
|
||||
"""
|
||||
charCount is the maximum number of characters a comment may be.
|
||||
"""
|
||||
charCount: Int
|
||||
|
||||
"""
|
||||
organizationName is the name of the organization.
|
||||
"""
|
||||
@@ -1440,6 +1486,11 @@ input SettingsInput {
|
||||
handled.
|
||||
"""
|
||||
karma: SettingsKarmaInput
|
||||
|
||||
"""
|
||||
charCount stores the character count moderation settings.
|
||||
"""
|
||||
charCount: SettingsCharCountInput
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user