add update post graphql api and tests
This commit is contained in:
@ -20,10 +20,10 @@ export class Post {
|
||||
user!: User
|
||||
|
||||
@Column('uuid', { array: true, nullable: true })
|
||||
libraryItemIds?: string[]
|
||||
libraryItemIds?: string[] | null
|
||||
|
||||
@Column('uuid', { array: true, nullable: true })
|
||||
highlightIds?: string[]
|
||||
highlightIds?: string[] | null
|
||||
|
||||
@Column('text')
|
||||
title!: string
|
||||
@ -32,10 +32,10 @@ export class Post {
|
||||
content!: string
|
||||
|
||||
@Column('text', { nullable: true })
|
||||
thumbnail?: string
|
||||
thumbnail?: string | null
|
||||
|
||||
@Column('text', { nullable: true })
|
||||
thought?: string
|
||||
thought?: string | null
|
||||
|
||||
@Column('timestamptz')
|
||||
createdAt!: Date
|
||||
|
||||
@ -151,7 +151,12 @@ import {
|
||||
webhookResolver,
|
||||
webhooksResolver,
|
||||
} from './index'
|
||||
import { createPostResolver, postResolver, postsResolver } from './posts'
|
||||
import {
|
||||
createPostResolver,
|
||||
postResolver,
|
||||
postsResolver,
|
||||
updatePostResolver,
|
||||
} from './posts'
|
||||
import {
|
||||
markEmailAsItemResolver,
|
||||
recentEmailsResolver,
|
||||
@ -319,6 +324,7 @@ export const functionResolvers = {
|
||||
updateFolderPolicy: updateFolderPolicyResolver,
|
||||
deleteFolderPolicy: deleteFolderPolicyResolver,
|
||||
createPost: createPostResolver,
|
||||
updatePost: updatePostResolver,
|
||||
},
|
||||
Query: {
|
||||
me: getMeUserResolver,
|
||||
@ -906,4 +912,5 @@ export const functionResolvers = {
|
||||
...resultResolveTypeResolver('Posts'),
|
||||
...resultResolveTypeResolver('Post'),
|
||||
...resultResolveTypeResolver('CreatePost'),
|
||||
...resultResolveTypeResolver('UpdatePost'),
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
CreatePostErrorCode,
|
||||
CreatePostSuccess,
|
||||
MutationCreatePostArgs,
|
||||
MutationUpdatePostArgs,
|
||||
PostEdge,
|
||||
PostErrorCode,
|
||||
PostResult,
|
||||
@ -12,12 +13,15 @@ import {
|
||||
QueryPostArgs,
|
||||
QueryPostsArgs,
|
||||
ResolverFn,
|
||||
UpdatePostError,
|
||||
UpdatePostErrorCode,
|
||||
UpdatePostSuccess,
|
||||
} from '../../generated/graphql'
|
||||
import {
|
||||
createPosts,
|
||||
createPublicPost,
|
||||
findPublicPostById,
|
||||
findPublicPostsByUserId,
|
||||
updatePost,
|
||||
} from '../../services/post'
|
||||
import { Merge } from '../../util'
|
||||
import { authorized } from '../../utils/gql-utils'
|
||||
@ -135,3 +139,57 @@ export const createPostResolver = authorized<
|
||||
post,
|
||||
}
|
||||
})
|
||||
|
||||
export const updatePostResolver = authorized<
|
||||
Merge<UpdatePostSuccess, { post?: Post }>,
|
||||
UpdatePostError,
|
||||
MutationUpdatePostArgs
|
||||
>(async (_, { input }, { uid, log }) => {
|
||||
const {
|
||||
id,
|
||||
title,
|
||||
content,
|
||||
highlightIds,
|
||||
libraryItemIds,
|
||||
thought,
|
||||
thumbnail,
|
||||
} = input
|
||||
|
||||
if (!id || title === null || content === null) {
|
||||
log.error('Invalid args', { id })
|
||||
|
||||
return {
|
||||
errorCodes: [UpdatePostErrorCode.BadRequest],
|
||||
}
|
||||
}
|
||||
|
||||
const result = await updatePost(uid, id, {
|
||||
title,
|
||||
content,
|
||||
highlightIds,
|
||||
libraryItemIds,
|
||||
thought,
|
||||
thumbnail,
|
||||
})
|
||||
|
||||
if (!result.affected) {
|
||||
log.error('Failed to update post', { id })
|
||||
|
||||
return {
|
||||
errorCodes: [UpdatePostErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
const post = await findPublicPostById(id)
|
||||
if (!post) {
|
||||
log.error('Post not found', { id })
|
||||
|
||||
return {
|
||||
errorCodes: [UpdatePostErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
post,
|
||||
}
|
||||
})
|
||||
|
||||
@ -3378,8 +3378,8 @@ const schema = gql`
|
||||
|
||||
input UpdatePostInput {
|
||||
id: ID!
|
||||
title: String
|
||||
content: String
|
||||
title: String @sanitize(minLength: 1, maxLength: 255)
|
||||
content: String @sanitize(minLength: 1)
|
||||
thumbnail: String
|
||||
libraryItemIds: [ID!]
|
||||
highlightIds: [ID!]
|
||||
|
||||
@ -81,3 +81,13 @@ export const findPublicPostById = async (id: string) => {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const updatePost = async (
|
||||
userId: string,
|
||||
postId: string,
|
||||
post: Partial<Post>
|
||||
) => {
|
||||
return authTrx(async (trx) => trx.getRepository(Post).update(postId, post), {
|
||||
uid: userId,
|
||||
})
|
||||
}
|
||||
|
||||
@ -288,4 +288,99 @@ describe('Post Resolvers', () => {
|
||||
await deletePosts(loginUser.id, [postId])
|
||||
})
|
||||
})
|
||||
|
||||
describe('updatePostResolver', () => {
|
||||
const mutation = `
|
||||
mutation UpdatePost($input: UpdatePostInput!) {
|
||||
updatePost(input: $input) {
|
||||
... on UpdatePostSuccess {
|
||||
post {
|
||||
id
|
||||
title
|
||||
content
|
||||
}
|
||||
}
|
||||
... on UpdatePostError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
let postId: string
|
||||
|
||||
before(async () => {
|
||||
const post = {
|
||||
title: 'Post',
|
||||
content: 'Content',
|
||||
user: loginUser,
|
||||
}
|
||||
const newPost = await createPosts(loginUser.id, [post])
|
||||
|
||||
postId = newPost[0].id
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
await deletePosts(loginUser.id, [postId])
|
||||
})
|
||||
|
||||
it('should return an error if the args are invalid', async () => {
|
||||
const response = await graphqlRequest(mutation, authToken, {
|
||||
input: {
|
||||
id: postId,
|
||||
title: null,
|
||||
content: null,
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.body.data.updatePost.errorCodes).to.eql(['BAD_REQUEST'])
|
||||
})
|
||||
|
||||
it('should return an error if the post is not found', async () => {
|
||||
const response = await graphqlRequest(mutation, authToken, {
|
||||
input: {
|
||||
id: generateFakeUuid(),
|
||||
title: 'Post',
|
||||
content: 'Content',
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.body.data.updatePost.errorCodes).to.eql(['UNAUTHORIZED'])
|
||||
})
|
||||
|
||||
it('should return an error if the user is not the owner of the post', async () => {
|
||||
const notOwner = await createTestUser('notOwner')
|
||||
const notOwnerToken = await loginAndGetAuthToken(notOwner.email)
|
||||
|
||||
const response = await graphqlRequest(mutation, notOwnerToken, {
|
||||
input: {
|
||||
id: postId,
|
||||
title: 'Post',
|
||||
content: 'Content',
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.body.data.updatePost.errorCodes).to.eql(['UNAUTHORIZED'])
|
||||
|
||||
await deleteUser(notOwner.id)
|
||||
})
|
||||
|
||||
it('should update the post', async () => {
|
||||
const response = await graphqlRequest(mutation, authToken, {
|
||||
input: {
|
||||
id: postId,
|
||||
title: 'Updated Post',
|
||||
content: 'Updated Content',
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.body.data.updatePost.post.title).to.eql('Updated Post')
|
||||
expect(response.body.data.updatePost.post.content).to.eql(
|
||||
'Updated Content'
|
||||
)
|
||||
|
||||
const post = await findPublicPostById(postId)
|
||||
expect(post?.title).to.eql('Updated Post')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user