From aee151685928f576d196670ef2eb2bbb136a7a4b Mon Sep 17 00:00:00 2001 From: gary Date: Fri, 12 Jan 2024 21:56:32 +0800 Subject: [PATCH] feat(comment): hide most of info in archived/banned comments --- schema.graphql | 4 +- src/definitions/schema.d.ts | 8 ++-- src/mutations/comment/deleteComment.ts | 6 +-- src/queries/comment/author.ts | 17 +++++-- src/queries/comment/content.ts | 2 +- src/queries/comment/createdAt.ts | 21 +++++++++ src/queries/comment/downvotes.ts | 6 +-- src/queries/comment/fromDonator.ts | 41 ++++++++++------- src/queries/comment/index.ts | 2 + src/queries/comment/replyTo.ts | 17 +++++-- src/queries/comment/upvotes.ts | 17 +++++-- src/types/__test__/2/comment.test.ts | 64 ++++++++++++++++++++++++++ src/types/comment.ts | 4 +- 13 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/queries/comment/createdAt.ts diff --git a/schema.graphql b/schema.graphql index 5f6ee9065..802ef6617 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1364,7 +1364,7 @@ type Comment implements Node { content: String """Author of this comment.""" - author: User! + author: User """This value determines this comment is pinned or not.""" pinned: Boolean! @@ -1392,7 +1392,7 @@ type Comment implements Node { remark: String """Current comment belongs to which Node.""" - node: Node! + node: Node } type CommentConnection implements Connection { diff --git a/src/definitions/schema.d.ts b/src/definitions/schema.d.ts index 3c5b9b6ce..42acc7345 100644 --- a/src/definitions/schema.d.ts +++ b/src/definitions/schema.d.ts @@ -888,7 +888,7 @@ export type GQLCollectionEdge = { export type GQLComment = GQLNode & { __typename?: 'Comment' /** Author of this comment. */ - author: GQLUser + author?: Maybe /** Descendant comments of this comment. */ comments: GQLCommentConnection /** Content of this comment. */ @@ -907,7 +907,7 @@ export type GQLComment = GQLNode & { /** The value determines current user's vote. */ myVote?: Maybe /** Current comment belongs to which Node. */ - node: GQLNode + node?: Maybe /** Parent comment of this comment. */ parentComment?: Maybe /** This value determines this comment is pinned or not. */ @@ -6056,7 +6056,7 @@ export type GQLCommentResolvers< ContextType = Context, ParentType extends GQLResolversParentTypes['Comment'] = GQLResolversParentTypes['Comment'] > = ResolversObject<{ - author?: Resolver + author?: Resolver, ParentType, ContextType> comments?: Resolver< GQLResolversTypes['CommentConnection'], ParentType, @@ -6073,7 +6073,7 @@ export type GQLCommentResolvers< fromDonator?: Resolver id?: Resolver myVote?: Resolver, ParentType, ContextType> - node?: Resolver + node?: Resolver, ParentType, ContextType> parentComment?: Resolver< Maybe, ParentType, diff --git a/src/mutations/comment/deleteComment.ts b/src/mutations/comment/deleteComment.ts index cff841458..50f37c5f8 100644 --- a/src/mutations/comment/deleteComment.ts +++ b/src/mutations/comment/deleteComment.ts @@ -1,4 +1,4 @@ -import type { GQLMutationResolvers } from 'definitions' +import type { GQLMutationResolvers, Article } from 'definitions' import { CACHE_KEYWORD, @@ -31,10 +31,10 @@ const resolver: GQLMutationResolvers['deleteComment'] = async ( const comment = await commentService.loadById(dbId) // check target - let article: any + let article: Article | undefined let circle: any if (comment.type === COMMENT_TYPE.article) { - article = await articleService.dataloader.load(comment.targetId) + article = await articleService.loadById(comment.targetId) } else { circle = await atomService.circleIdLoader.load(comment.targetId) } diff --git a/src/queries/comment/author.ts b/src/queries/comment/author.ts index 5b34cd743..5dbb7efd2 100644 --- a/src/queries/comment/author.ts +++ b/src/queries/comment/author.ts @@ -1,9 +1,20 @@ import type { GQLCommentResolvers } from 'definitions' +import { COMMENT_STATE } from 'common/enums' + const resolver: GQLCommentResolvers['author'] = ( - { authorId }, + { authorId, state }, _, - { dataSources: { userService } } -) => userService.loadById(authorId) + { viewer, dataSources: { userService } } +) => { + const isActive = state === COMMENT_STATE.active + const isCollapsed = state === COMMENT_STATE.collapsed + const isAdmin = viewer.hasRole('admin') + if (isActive || isCollapsed || isAdmin) { + return userService.loadById(authorId) + } else { + return null + } +} export default resolver diff --git a/src/queries/comment/content.ts b/src/queries/comment/content.ts index eeb9de9f9..fc5103c7c 100644 --- a/src/queries/comment/content.ts +++ b/src/queries/comment/content.ts @@ -8,7 +8,7 @@ const resolver: GQLCommentResolvers['content'] = ( { viewer } ) => { const isActive = state === COMMENT_STATE.active - const isCollapsed = state === 'collapsed' + const isCollapsed = state === COMMENT_STATE.collapsed const isAdmin = viewer.hasRole('admin') if (isActive || isCollapsed || isAdmin) { diff --git a/src/queries/comment/createdAt.ts b/src/queries/comment/createdAt.ts new file mode 100644 index 000000000..fdc5a7d8b --- /dev/null +++ b/src/queries/comment/createdAt.ts @@ -0,0 +1,21 @@ +import type { GQLCommentResolvers } from 'definitions' + +import { COMMENT_STATE } from 'common/enums' + +const resolver: GQLCommentResolvers['createdAt'] = ( + { createdAt, state }, + _, + { viewer } +) => { + const isActive = state === COMMENT_STATE.active + const isCollapsed = state === COMMENT_STATE.collapsed + const isAdmin = viewer.hasRole('admin') + if (isActive || isCollapsed || isAdmin) { + return createdAt + } else { + // invalid date + return new Date(0) + } +} + +export default resolver diff --git a/src/queries/comment/downvotes.ts b/src/queries/comment/downvotes.ts index fb9033bcd..2e70f6cf0 100644 --- a/src/queries/comment/downvotes.ts +++ b/src/queries/comment/downvotes.ts @@ -1,9 +1,5 @@ import type { GQLCommentResolvers } from 'definitions' -const resolver: GQLCommentResolvers['downvotes'] = ( - { id }, - _, - { dataSources: { commentService } } -) => 0 +const resolver: GQLCommentResolvers['downvotes'] = () => 0 export default resolver diff --git a/src/queries/comment/fromDonator.ts b/src/queries/comment/fromDonator.ts index fcd421b16..628c83520 100644 --- a/src/queries/comment/fromDonator.ts +++ b/src/queries/comment/fromDonator.ts @@ -2,36 +2,43 @@ import type { GQLCommentResolvers } from 'definitions' import { COMMENT_TYPE, + COMMENT_STATE, TRANSACTION_PURPOSE, TRANSACTION_STATE, TRANSACTION_TARGET_TYPE, } from 'common/enums' const resolver: GQLCommentResolvers['fromDonator'] = async ( - { authorId, targetId, type }, + { authorId, targetId, type, state }, _, - { dataSources: { atomService, articleService } } + { viewer, dataSources: { atomService, articleService } } ) => { if (!targetId || type !== COMMENT_TYPE.article) { return false } - const { id: entityTypeId } = await articleService.baseFindEntityTypeId( - TRANSACTION_TARGET_TYPE.article - ) + const isActive = state === COMMENT_STATE.active + const isCollapsed = state === COMMENT_STATE.collapsed + const isAdmin = viewer.hasRole('admin') + if (isActive || isCollapsed || isAdmin) { + const { id: entityTypeId } = await articleService.baseFindEntityTypeId( + TRANSACTION_TARGET_TYPE.article + ) + const record = await atomService.findFirst({ + table: 'transaction', + where: { + targetId, + targetType: entityTypeId, + senderId: authorId, + state: TRANSACTION_STATE.succeeded, + purpose: TRANSACTION_PURPOSE.donation, + }, + }) - const record = await atomService.findFirst({ - table: 'transaction', - where: { - targetId, - targetType: entityTypeId, - senderId: authorId, - state: TRANSACTION_STATE.succeeded, - purpose: TRANSACTION_PURPOSE.donation, - }, - }) - - return !!record + return !!record + } else { + return false + } } export default resolver diff --git a/src/queries/comment/index.ts b/src/queries/comment/index.ts index 84c2f38b4..c02fd2519 100644 --- a/src/queries/comment/index.ts +++ b/src/queries/comment/index.ts @@ -18,6 +18,7 @@ import circleDiscussionThreadCount from './circle/discussionThreadCount' import circlePinnedBroadcast from './circle/pinnedBroadcast' import comments from './comments' import content from './content' +import createdAt from './createdAt' import downvotes from './downvotes' import fromDonator from './fromDonator' import myVote from './myVote' @@ -53,6 +54,7 @@ export default { fromDonator, type: ({ type }: { type: string }) => COMMENT_TYPES_REVERSED[type], node, + createdAt, }, Circle: { broadcast: circleBroadcast, diff --git a/src/queries/comment/replyTo.ts b/src/queries/comment/replyTo.ts index e8b5752c6..6d502a758 100644 --- a/src/queries/comment/replyTo.ts +++ b/src/queries/comment/replyTo.ts @@ -1,9 +1,20 @@ import type { GQLCommentResolvers } from 'definitions' +import { COMMENT_STATE } from 'common/enums' + const resolver: GQLCommentResolvers['replyTo'] = ( - { replyTo }, + { replyTo, state }, _, - { dataSources: { commentService } } -) => (replyTo ? commentService.loadById(replyTo) : null) + { viewer, dataSources: { commentService } } +) => { + const isActive = state === COMMENT_STATE.active + const isCollapsed = state === COMMENT_STATE.collapsed + const isAdmin = viewer.hasRole('admin') + if (isActive || isCollapsed || isAdmin) { + return replyTo ? commentService.loadById(replyTo) : null + } else { + return null + } +} export default resolver diff --git a/src/queries/comment/upvotes.ts b/src/queries/comment/upvotes.ts index 1a10fc0b9..9706db1ec 100644 --- a/src/queries/comment/upvotes.ts +++ b/src/queries/comment/upvotes.ts @@ -1,9 +1,20 @@ import type { GQLCommentResolvers } from 'definitions' +import { COMMENT_STATE } from 'common/enums' + const resolver: GQLCommentResolvers['upvotes'] = ( - { id, upvotes }: any, + { id, state }, _, - { dataSources: { commentService } } -) => parseInt(upvotes, 10) || commentService.countUpVote(id) + { viewer, dataSources: { commentService } } +) => { + const isActive = state === COMMENT_STATE.active + const isCollapsed = state === COMMENT_STATE.collapsed + const isAdmin = viewer.hasRole('admin') + if (isActive || isCollapsed || isAdmin) { + return commentService.countUpVote(id) + } else { + return 0 + } +} export default resolver diff --git a/src/types/__test__/2/comment.test.ts b/src/types/__test__/2/comment.test.ts index d5b93eb91..347a7fc64 100644 --- a/src/types/__test__/2/comment.test.ts +++ b/src/types/__test__/2/comment.test.ts @@ -79,8 +79,20 @@ const GET_COMMENT = /* GraphQL */ ` query ($input: NodeInput!) { node(input: $input) { ... on Comment { + state + type + createdAt + content + author { + id + } + pinned upvotes downvotes + myVote + replyTo { + id + } } } } @@ -116,6 +128,58 @@ const getCommentVotes = async (commentId: string) => { return data && data.node } +describe('query comment', () => { + test('query comment by id', async () => { + const server = await testClient({ connections }) + const { + data: { node }, + errors, + } = await server.executeOperation({ + query: GET_COMMENT, + variables: { + input: { id: COMMENT_ID }, + }, + }) + expect(node.state).toBe('active') + expect(node.type).toBe('article') + expect(node.createdAt.toString()).not.toBe(new Date(0).toString()) + expect(node.content).not.toBe('') + expect(node.author).not.toBeNull() + expect(errors).toBeUndefined() + }) + test('query archived comment', async () => { + await connections + .knex('comment') + .where({ id: 1 }) + .update({ state: 'archived' }) + const server = await testClient({ connections }) + const { + data: { node }, + errors, + } = await server.executeOperation({ + query: GET_COMMENT, + variables: { + input: { id: COMMENT_ID }, + }, + }) + expect(node.state).toBe('archived') + expect(node.type).toBe('article') + expect(node.createdAt.toString()).toBe(new Date(0).toString()) + expect(node.content).toBe('') + expect(node.author).toBeNull() + expect(node.pinned).toBe(false) + expect(node.upvotes).toBe(0) + expect(node.downvotes).toBe(0) + expect(node.replyTo).toBeNull() + expect(errors).toBeUndefined() + + await connections + .knex('comment') + .where({ id: 1 }) + .update({ state: 'active' }) + }) +}) + describe('query comment list on article', () => { test('query comments by author', async () => { const authorId = toGlobalId({ type: NODE_TYPES.User, id: 2 }) diff --git a/src/types/comment.ts b/src/types/comment.ts index 2485a7b38..f35c5fa20 100644 --- a/src/types/comment.ts +++ b/src/types/comment.ts @@ -53,7 +53,7 @@ export default /* GraphQL */ ` content: String "Author of this comment." - author: User! @logCache(type: "${NODE_TYPES.User}") + author: User @logCache(type: "${NODE_TYPES.User}") "This value determines this comment is pinned or not." pinned: Boolean! @@ -82,7 +82,7 @@ export default /* GraphQL */ ` remark: String @auth(mode: "${AUTH_MODE.admin}") "Current comment belongs to which Node." - node: Node! @logCache(type: "${NODE_TYPES.Node}") + node: Node @logCache(type: "${NODE_TYPES.Node}") } extend type Article {