Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(comment): hide most of info in archived/banned comments #3757

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -1392,7 +1392,7 @@ type Comment implements Node {
remark: String

"""Current comment belongs to which Node."""
node: Node!
node: Node
}

type CommentConnection implements Connection {
Expand Down
8 changes: 4 additions & 4 deletions src/definitions/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ export type GQLCollectionEdge = {
export type GQLComment = GQLNode & {
__typename?: 'Comment'
/** Author of this comment. */
author: GQLUser
author?: Maybe<GQLUser>
/** Descendant comments of this comment. */
comments: GQLCommentConnection
/** Content of this comment. */
Expand All @@ -907,7 +907,7 @@ export type GQLComment = GQLNode & {
/** The value determines current user's vote. */
myVote?: Maybe<GQLVote>
/** Current comment belongs to which Node. */
node: GQLNode
node?: Maybe<GQLNode>
/** Parent comment of this comment. */
parentComment?: Maybe<GQLComment>
/** This value determines this comment is pinned or not. */
Expand Down Expand Up @@ -6056,7 +6056,7 @@ export type GQLCommentResolvers<
ContextType = Context,
ParentType extends GQLResolversParentTypes['Comment'] = GQLResolversParentTypes['Comment']
> = ResolversObject<{
author?: Resolver<GQLResolversTypes['User'], ParentType, ContextType>
author?: Resolver<Maybe<GQLResolversTypes['User']>, ParentType, ContextType>
comments?: Resolver<
GQLResolversTypes['CommentConnection'],
ParentType,
Expand All @@ -6073,7 +6073,7 @@ export type GQLCommentResolvers<
fromDonator?: Resolver<GQLResolversTypes['Boolean'], ParentType, ContextType>
id?: Resolver<GQLResolversTypes['ID'], ParentType, ContextType>
myVote?: Resolver<Maybe<GQLResolversTypes['Vote']>, ParentType, ContextType>
node?: Resolver<GQLResolversTypes['Node'], ParentType, ContextType>
node?: Resolver<Maybe<GQLResolversTypes['Node']>, ParentType, ContextType>
parentComment?: Resolver<
Maybe<GQLResolversTypes['Comment']>,
ParentType,
Expand Down
6 changes: 3 additions & 3 deletions src/mutations/comment/deleteComment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { GQLMutationResolvers } from 'definitions'
import type { GQLMutationResolvers, Article } from 'definitions'

import {
CACHE_KEYWORD,
Expand Down Expand Up @@ -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)
}
Expand Down
17 changes: 14 additions & 3 deletions src/queries/comment/author.ts
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/queries/comment/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
21 changes: 21 additions & 0 deletions src/queries/comment/createdAt.ts
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should return null instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createdAt: DateTime!
can not return null here without update schema

}
}

export default resolver
6 changes: 1 addition & 5 deletions src/queries/comment/downvotes.ts
Original file line number Diff line number Diff line change
@@ -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
41 changes: 24 additions & 17 deletions src/queries/comment/fromDonator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,43 @@

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')

Check warning on line 22 in src/queries/comment/fromDonator.ts

View check run for this annotation

Codecov / codecov/patch

src/queries/comment/fromDonator.ts#L20-L22

Added lines #L20 - L22 were not covered by tests
if (isActive || isCollapsed || isAdmin) {
const { id: entityTypeId } = await articleService.baseFindEntityTypeId(

Check warning on line 24 in src/queries/comment/fromDonator.ts

View check run for this annotation

Codecov / codecov/patch

src/queries/comment/fromDonator.ts#L24

Added line #L24 was not covered by tests
TRANSACTION_TARGET_TYPE.article
)
const record = await atomService.findFirst({

Check warning on line 27 in src/queries/comment/fromDonator.ts

View check run for this annotation

Codecov / codecov/patch

src/queries/comment/fromDonator.ts#L27

Added line #L27 was not covered by tests
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

Check warning on line 40 in src/queries/comment/fromDonator.ts

View check run for this annotation

Codecov / codecov/patch

src/queries/comment/fromDonator.ts#L38-L40

Added lines #L38 - L40 were not covered by tests
}
}

export default resolver
2 changes: 2 additions & 0 deletions src/queries/comment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -53,6 +54,7 @@ export default {
fromDonator,
type: ({ type }: { type: string }) => COMMENT_TYPES_REVERSED[type],
node,
createdAt,
},
Circle: {
broadcast: circleBroadcast,
Expand Down
17 changes: 14 additions & 3 deletions src/queries/comment/replyTo.ts
Original file line number Diff line number Diff line change
@@ -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
17 changes: 14 additions & 3 deletions src/queries/comment/upvotes.ts
Original file line number Diff line number Diff line change
@@ -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
64 changes: 64 additions & 0 deletions src/types/__test__/2/comment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
}
Expand Down Expand Up @@ -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 })
Expand Down
4 changes: 2 additions & 2 deletions src/types/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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 {
Expand Down
Loading