mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
add create post graphql api and tests
This commit is contained in:
parent
12db8b6a7d
commit
9caad12f09
8 changed files with 117 additions and 9 deletions
|
|
@ -515,7 +515,6 @@ export type CreatePostError = {
|
|||
};
|
||||
|
||||
export enum CreatePostErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,6 @@ type CreatePostError {
|
|||
}
|
||||
|
||||
enum CreatePostErrorCode {
|
||||
BAD_REQUEST
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export const authTrx = async <T>(
|
|||
): Promise<T> => {
|
||||
let { uid, userRole } = options
|
||||
|
||||
// if uid and dbRole are not passed in, then get them from the claims
|
||||
// if uid and dbRole are not passed in, then get them from the http context
|
||||
if (!uid && !userRole) {
|
||||
const claims: Claims | undefined = httpContext.get('claims')
|
||||
uid = claims?.uid
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ import {
|
|||
webhookResolver,
|
||||
webhooksResolver,
|
||||
} from './index'
|
||||
import { postResolver, postsResolver } from './posts'
|
||||
import { createPostResolver, postResolver, postsResolver } from './posts'
|
||||
import {
|
||||
markEmailAsItemResolver,
|
||||
recentEmailsResolver,
|
||||
|
|
@ -318,6 +318,7 @@ export const functionResolvers = {
|
|||
createFolderPolicy: createFolderPolicyResolver,
|
||||
updateFolderPolicy: updateFolderPolicyResolver,
|
||||
deleteFolderPolicy: deleteFolderPolicyResolver,
|
||||
createPost: createPostResolver,
|
||||
},
|
||||
Query: {
|
||||
me: getMeUserResolver,
|
||||
|
|
@ -904,4 +905,5 @@ export const functionResolvers = {
|
|||
...resultResolveTypeResolver('DeleteFolderPolicy'),
|
||||
...resultResolveTypeResolver('Posts'),
|
||||
...resultResolveTypeResolver('Post'),
|
||||
...resultResolveTypeResolver('CreatePost'),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { Post } from '../../entity/post'
|
||||
import {
|
||||
CreatePostError,
|
||||
CreatePostErrorCode,
|
||||
CreatePostSuccess,
|
||||
MutationCreatePostArgs,
|
||||
PostEdge,
|
||||
PostErrorCode,
|
||||
PostResult,
|
||||
|
|
@ -10,10 +14,13 @@ import {
|
|||
ResolverFn,
|
||||
} from '../../generated/graphql'
|
||||
import {
|
||||
createPosts,
|
||||
createPublicPost,
|
||||
findPublicPostById,
|
||||
findPublicPostsByUserId,
|
||||
} from '../../services/post'
|
||||
import { Merge } from '../../util'
|
||||
import { authorized } from '../../utils/gql-utils'
|
||||
import { ResolverContext } from '../types'
|
||||
|
||||
type PartialPostEdge = Merge<
|
||||
|
|
@ -97,3 +104,34 @@ export const postResolver: ResolverFn<
|
|||
}
|
||||
}
|
||||
|
||||
export const createPostResolver = authorized<
|
||||
Merge<CreatePostSuccess, { post: Post }>,
|
||||
CreatePostError,
|
||||
MutationCreatePostArgs
|
||||
>(async (_, { input }, { uid, log }) => {
|
||||
const { title, content, highlightIds, libraryItemIds, thought, thumbnail } =
|
||||
input
|
||||
|
||||
const postToCreate = {
|
||||
userId: uid,
|
||||
title,
|
||||
content,
|
||||
highlightIds: highlightIds || undefined,
|
||||
libraryItemIds: libraryItemIds || undefined,
|
||||
thought: thought || undefined,
|
||||
thumbnail: thumbnail || undefined,
|
||||
}
|
||||
|
||||
const post = await createPublicPost(uid, postToCreate)
|
||||
if (!post) {
|
||||
log.error('Failed to create post', { postToCreate })
|
||||
|
||||
return {
|
||||
errorCodes: [CreatePostErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
post,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3354,8 +3354,8 @@ const schema = gql`
|
|||
}
|
||||
|
||||
input CreatePostInput {
|
||||
title: String!
|
||||
content: String!
|
||||
title: String! @sanitize(minLength: 1, maxLength: 255)
|
||||
content: String! @sanitize(minLength: 1)
|
||||
thumbnail: String
|
||||
libraryItemIds: [ID!]
|
||||
highlightIds: [ID!]
|
||||
|
|
@ -3374,7 +3374,6 @@ const schema = gql`
|
|||
|
||||
enum CreatePostErrorCode {
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
}
|
||||
|
||||
input UpdatePostInput {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { DeepPartial } from 'typeorm'
|
||||
import { Post } from '../entity/post'
|
||||
import { Profile } from '../entity/profile'
|
||||
import { authTrx, getRepository } from '../repository'
|
||||
|
||||
export const findPublicPostsByUserId = async (
|
||||
|
|
@ -26,6 +27,30 @@ export const findPublicPostsByUserId = async (
|
|||
return posts
|
||||
}
|
||||
|
||||
export const createPublicPost = async (
|
||||
userId: string,
|
||||
post: DeepPartial<Post>
|
||||
) => {
|
||||
return authTrx(
|
||||
async (trx) => {
|
||||
const newPost = await trx.getRepository(Post).save(post)
|
||||
|
||||
// Make user profile public when user creates a post
|
||||
await trx.getRepository(Profile).update(
|
||||
{ user: { id: userId } },
|
||||
{
|
||||
private: false,
|
||||
}
|
||||
)
|
||||
|
||||
return newPost
|
||||
},
|
||||
{
|
||||
uid: userId,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const createPosts = async (
|
||||
userId: string,
|
||||
posts: Array<DeepPartial<Post>>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import { expect } from 'chai'
|
||||
import { User } from '../../src/entity/user'
|
||||
import { createPosts, deletePosts } from '../../src/services/post'
|
||||
import { updateProfile } from '../../src/services/profile'
|
||||
import {
|
||||
createPosts,
|
||||
deletePosts,
|
||||
findPublicPostById,
|
||||
} from '../../src/services/post'
|
||||
import { findProfile, updateProfile } from '../../src/services/profile'
|
||||
import { deleteUser } from '../../src/services/user'
|
||||
import { createTestUser } from '../db'
|
||||
import { generateFakeUuid, graphqlRequest, loginAndGetAuthToken } from '../util'
|
||||
|
|
@ -242,4 +246,46 @@ describe('Post Resolvers', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('createPostResolver', () => {
|
||||
const mutation = `
|
||||
mutation CreatePost($input: CreatePostInput!) {
|
||||
createPost(input: $input) {
|
||||
... on CreatePostSuccess {
|
||||
post {
|
||||
id
|
||||
title
|
||||
content
|
||||
}
|
||||
}
|
||||
... on CreatePostError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
it('should create a post', async () => {
|
||||
const response = await graphqlRequest(mutation, authToken, {
|
||||
input: {
|
||||
title: 'Post',
|
||||
content: 'Content',
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.body.data.createPost.post.title).to.eql('Post')
|
||||
expect(response.body.data.createPost.post.content).to.eql('Content')
|
||||
|
||||
const postId = response.body.data.createPost.post.id as string
|
||||
|
||||
const post = await findPublicPostById(postId)
|
||||
expect(post).to.exist
|
||||
expect(post?.title).to.eql('Post')
|
||||
|
||||
const profile = await findProfile(loginUser)
|
||||
expect(profile?.private).to.be.false
|
||||
|
||||
await deletePosts(loginUser.id, [postId])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue