From 588d5b377e3d0a7b25cc995e637cf2202bb9f717 Mon Sep 17 00:00:00 2001 From: Rasit <12167194+durmusrasit@users.noreply.github.com> Date: Tue, 8 Aug 2023 00:04:04 +0300 Subject: [PATCH] feat(apps/gql): add post upvote mutations (#605) # Description Created create and remove mutations for post upvotes. Also ensured that postID and userID are unique with one block attribute (@@unique) in the psima schema. Closes #554 Closes #556 --- apps/gql/features/pano/index.ts | 2 + apps/gql/features/pano/postUpvote.ts | 35 ++++++++++ apps/gql/loaders/pano.ts | 10 ++- apps/gql/schema/resolvers/index.ts | 28 ++++++++ apps/gql/schema/schema.graphql | 21 ++++++ apps/gql/schema/types.generated.ts | 98 ++++++++++++++++++++++++++++ db/prisma/schema.prisma | 1 + 7 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 apps/gql/features/pano/postUpvote.ts diff --git a/apps/gql/features/pano/index.ts b/apps/gql/features/pano/index.ts index f8a16f03..cc649038 100644 --- a/apps/gql/features/pano/index.ts +++ b/apps/gql/features/pano/index.ts @@ -1,10 +1,12 @@ import { createPanoCommentActions } from "~/features/pano/comment"; import { createPanoPostActions } from "~/features/pano/post"; import { type Clients } from "~/clients"; +import { createPostUpvoteActions } from "./postUpvote"; export function createPanoActions(clients: Clients) { return { post: createPanoPostActions(clients), comment: createPanoCommentActions(clients), + postUpvote: createPostUpvoteActions(clients), }; } diff --git a/apps/gql/features/pano/postUpvote.ts b/apps/gql/features/pano/postUpvote.ts new file mode 100644 index 00000000..29e0af17 --- /dev/null +++ b/apps/gql/features/pano/postUpvote.ts @@ -0,0 +1,35 @@ +import { type Clients } from "~/clients"; + +interface CreatePostUpvoteArgs { + postID: string; + userID: string; +} + +interface RemovePostUpvoteArgs { + postID: string; + userID: string; +} + +export function createPostUpvoteActions({ prisma }: Clients) { + const create = (args: CreatePostUpvoteArgs) => { + return prisma.upvote.create({ + data: { + post: { connect: { id: args.postID } }, + owner: { connect: { id: args.userID } }, + }, + }); + }; + + const remove = (args: RemovePostUpvoteArgs) => { + return prisma.upvote.delete({ + where: { + postID_userID: { + postID: args.postID, + userID: args.userID, + }, + }, + }); + }; + + return { create, remove }; +} diff --git a/apps/gql/loaders/pano.ts b/apps/gql/loaders/pano.ts index 7c24d6c9..9e2c85f6 100644 --- a/apps/gql/loaders/pano.ts +++ b/apps/gql/loaders/pano.ts @@ -4,7 +4,7 @@ import { createPrismaLoader, } from "@kampus/gql-utils"; import { type Connection } from "@kampus/gql-utils/connection"; -import { type Comment, type Post } from "@kampus/prisma"; +import { type Comment, type Post, type Upvote } from "@kampus/prisma"; import { type Clients } from "~/clients"; import { @@ -12,6 +12,7 @@ import { type PanoCommentConnection, type PanoPost, type PanoPostConnection, + type PostUpvote, } from "~/schema/types.generated"; export type PanoLoaders = ReturnType; @@ -142,3 +143,10 @@ export const transformPanoCommentConnection = (connection: Connection) totalCount: connection.totalCount, } satisfies PanoCommentConnection; }; + +export const transformPostUpvote = (upvote: Upvote) => { + return { + ...upvote, + __typename: "PostUpvote", + } satisfies PostUpvote; +}; diff --git a/apps/gql/schema/resolvers/index.ts b/apps/gql/schema/resolvers/index.ts index b90ebe94..60938be3 100644 --- a/apps/gql/schema/resolvers/index.ts +++ b/apps/gql/schema/resolvers/index.ts @@ -13,6 +13,7 @@ import { transformPanoCommentConnection, transformPanoPost, transformPanoPostConnection, + transformPostUpvote, } from "~/loaders/pano"; import { transformSozlukTerm, transformSozlukTermsConnection } from "~/loaders/sozluk"; import { transformUser } from "~/loaders/user"; @@ -244,6 +245,9 @@ export const resolvers = { CreatePanoCommentPayload: {}, // union UpdatePanoCommentPayload: {}, // union RemovePanoCommentPayload: {}, // union + CreatePostUpvotePayload: {}, // union + RemovePostUpvotePayload: {}, // union + UserError: {}, // interface InvalidInput: errorFieldsResolver, @@ -347,5 +351,29 @@ export const resolvers = { return transformPanoComment(await actions.pano.comment.remove(id.value)); }, + createPostUpvote: async (_, { input }, { actions, pasaport: { session } }) => { + if (!session?.user?.id) { + return NotAuthorized(); + } + + return transformPostUpvote( + await actions.pano.postUpvote.create({ + postID: input.postID, + userID: session.user.id, + }) + ); + }, + removePostUpvote: async (_, { input }, { actions, pasaport: { session } }) => { + if (!session?.user?.id) { + return NotAuthorized(); + } + + return transformPostUpvote( + await actions.pano.postUpvote.remove({ + postID: input.postID, + userID: session.user.id, + }) + ); + }, }, } satisfies Resolvers; diff --git a/apps/gql/schema/schema.graphql b/apps/gql/schema/schema.graphql index 8b141a6a..b177d87b 100644 --- a/apps/gql/schema/schema.graphql +++ b/apps/gql/schema/schema.graphql @@ -158,6 +158,12 @@ type PanoCommentEdge { node: PanoComment } +type PostUpvote { + id: ID! + postID: String! + userID: String! +} + type Mutation { createPanoPost(input: CreatePanoPostInput!): CreatePanoPostPayload updatePanoPost(input: UpdatePanoPostInput!): UpdatePanoPostPayload @@ -166,6 +172,9 @@ type Mutation { createPanoComment(input: CreatePanoCommentInput!): CreatePanoCommentPayload updatePanoComment(input: UpdatePanoCommentInput!): UpdatePanoCommentPayload removePanoComment(input: RemovePanoCommentInput!): RemovePanoCommentPayload + + createPostUpvote(input: CreatePostUpvoteInput!): CreatePostUpvotePayload + removePostUpvote(input: RemovePostUpvoteInput!): RemovePostUpvotePayload } input CreatePanoPostInput { @@ -211,3 +220,15 @@ union RemovePanoCommentPayload = PanoComment | NotAuthorized | InvalidInput input RemovePanoCommentInput { id: ID! } + +input CreatePostUpvoteInput { + postID: String! +} + +union CreatePostUpvotePayload = PostUpvote | NotAuthorized | InvalidInput + +input RemovePostUpvoteInput { + postID: String! +} + +union RemovePostUpvotePayload = PostUpvote | NotAuthorized | InvalidInput diff --git a/apps/gql/schema/types.generated.ts b/apps/gql/schema/types.generated.ts index 1ce30fc0..7bae5748 100644 --- a/apps/gql/schema/types.generated.ts +++ b/apps/gql/schema/types.generated.ts @@ -46,6 +46,12 @@ export type CreatePanoPostInput = { export type CreatePanoPostPayload = InvalidInput | NotAuthorized | PanoPost; +export type CreatePostUpvoteInput = { + postID: Scalars["String"]["input"]; +}; + +export type CreatePostUpvotePayload = InvalidInput | NotAuthorized | PostUpvote; + export type InvalidInput = UserError & { __typename?: "InvalidInput"; message: Scalars["String"]["output"]; @@ -55,8 +61,10 @@ export type Mutation = { __typename?: "Mutation"; createPanoComment: Maybe; createPanoPost: Maybe; + createPostUpvote: Maybe; removePanoComment: Maybe; removePanoPost: Maybe; + removePostUpvote: Maybe; updatePanoComment: Maybe; updatePanoPost: Maybe; }; @@ -69,6 +77,10 @@ export type MutationCreatePanoPostArgs = { input: CreatePanoPostInput; }; +export type MutationCreatePostUpvoteArgs = { + input: CreatePostUpvoteInput; +}; + export type MutationRemovePanoCommentArgs = { input: RemovePanoCommentInput; }; @@ -77,6 +89,10 @@ export type MutationRemovePanoPostArgs = { input: RemovePanoPostInput; }; +export type MutationRemovePostUpvoteArgs = { + input: RemovePostUpvoteInput; +}; + export type MutationUpdatePanoCommentArgs = { input: UpdatePanoCommentInput; }; @@ -187,6 +203,13 @@ export type PanoQueryPostsArgs = { ids: Array; }; +export type PostUpvote = { + __typename?: "PostUpvote"; + id: Scalars["ID"]["output"]; + postID: Scalars["String"]["output"]; + userID: Scalars["String"]["output"]; +}; + export type Query = { __typename?: "Query"; node: Maybe; @@ -217,6 +240,12 @@ export type RemovePanoPostInput = { export type RemovePanoPostPayload = InvalidInput | NotAuthorized | PanoPost; +export type RemovePostUpvoteInput = { + postID: Scalars["String"]["input"]; +}; + +export type RemovePostUpvotePayload = InvalidInput | NotAuthorized | PostUpvote; + export type SozlukQuery = { __typename?: "SozlukQuery"; term: Maybe; @@ -408,6 +437,10 @@ export type ResolversUnionTypes> = Resol | (InvalidInput & { __typename: "InvalidInput" }) | (NotAuthorized & { __typename: "NotAuthorized" }) | (PanoPost & { __typename: "PanoPost" }); + CreatePostUpvotePayload: + | (InvalidInput & { __typename: "InvalidInput" }) + | (NotAuthorized & { __typename: "NotAuthorized" }) + | (PostUpvote & { __typename: "PostUpvote" }); RemovePanoCommentPayload: | (InvalidInput & { __typename: "InvalidInput" }) | (NotAuthorized & { __typename: "NotAuthorized" }) @@ -416,6 +449,10 @@ export type ResolversUnionTypes> = Resol | (InvalidInput & { __typename: "InvalidInput" }) | (NotAuthorized & { __typename: "NotAuthorized" }) | (PanoPost & { __typename: "PanoPost" }); + RemovePostUpvotePayload: + | (InvalidInput & { __typename: "InvalidInput" }) + | (NotAuthorized & { __typename: "NotAuthorized" }) + | (PostUpvote & { __typename: "PostUpvote" }); UpdatePanoCommentPayload: | (InvalidInput & { __typename: "InvalidInput" }) | (NotAuthorized & { __typename: "NotAuthorized" }) @@ -451,6 +488,10 @@ export type ResolversTypes = ResolversObject<{ CreatePanoPostPayload: ResolverTypeWrapper< ResolversUnionTypes["CreatePanoPostPayload"] >; + CreatePostUpvoteInput: CreatePostUpvoteInput; + CreatePostUpvotePayload: ResolverTypeWrapper< + ResolversUnionTypes["CreatePostUpvotePayload"] + >; Date: ResolverTypeWrapper; DateTime: ResolverTypeWrapper; ID: ResolverTypeWrapper; @@ -468,6 +509,7 @@ export type ResolversTypes = ResolversObject<{ PanoPostEdge: ResolverTypeWrapper; PanoPostFilter: PanoPostFilter; PanoQuery: ResolverTypeWrapper; + PostUpvote: ResolverTypeWrapper; Query: ResolverTypeWrapper<{}>; RemovePanoCommentInput: RemovePanoCommentInput; RemovePanoCommentPayload: ResolverTypeWrapper< @@ -477,6 +519,10 @@ export type ResolversTypes = ResolversObject<{ RemovePanoPostPayload: ResolverTypeWrapper< ResolversUnionTypes["RemovePanoPostPayload"] >; + RemovePostUpvoteInput: RemovePostUpvoteInput; + RemovePostUpvotePayload: ResolverTypeWrapper< + ResolversUnionTypes["RemovePostUpvotePayload"] + >; SozlukQuery: ResolverTypeWrapper; SozlukTerm: ResolverTypeWrapper; SozlukTermBody: ResolverTypeWrapper; @@ -504,6 +550,8 @@ export type ResolversParentTypes = ResolversObject<{ CreatePanoCommentPayload: ResolversUnionTypes["CreatePanoCommentPayload"]; CreatePanoPostInput: CreatePanoPostInput; CreatePanoPostPayload: ResolversUnionTypes["CreatePanoPostPayload"]; + CreatePostUpvoteInput: CreatePostUpvoteInput; + CreatePostUpvotePayload: ResolversUnionTypes["CreatePostUpvotePayload"]; Date: Scalars["Date"]["output"]; DateTime: Scalars["DateTime"]["output"]; ID: Scalars["ID"]["output"]; @@ -520,11 +568,14 @@ export type ResolversParentTypes = ResolversObject<{ PanoPostConnection: PanoPostConnection; PanoPostEdge: PanoPostEdge; PanoQuery: PanoQuery; + PostUpvote: PostUpvote; Query: {}; RemovePanoCommentInput: RemovePanoCommentInput; RemovePanoCommentPayload: ResolversUnionTypes["RemovePanoCommentPayload"]; RemovePanoPostInput: RemovePanoPostInput; RemovePanoPostPayload: ResolversUnionTypes["RemovePanoPostPayload"]; + RemovePostUpvoteInput: RemovePostUpvoteInput; + RemovePostUpvotePayload: ResolversUnionTypes["RemovePostUpvotePayload"]; SozlukQuery: SozlukQuery; SozlukTerm: SozlukTerm; SozlukTermBody: SozlukTermBody; @@ -569,6 +620,17 @@ export type CreatePanoPostPayloadResolvers< >; }>; +export type CreatePostUpvotePayloadResolvers< + ContextType = KampusGQLContext, + ParentType extends ResolversParentTypes["CreatePostUpvotePayload"] = ResolversParentTypes["CreatePostUpvotePayload"] +> = ResolversObject<{ + __resolveType?: TypeResolveFn< + "InvalidInput" | "NotAuthorized" | "PostUpvote", + ParentType, + ContextType + >; +}>; + export interface DateScalarConfig extends GraphQLScalarTypeConfig { name: "Date"; } @@ -602,6 +664,12 @@ export type MutationResolvers< ContextType, RequireFields >; + createPostUpvote: Resolver< + Maybe, + ParentType, + ContextType, + RequireFields + >; removePanoComment: Resolver< Maybe, ParentType, @@ -614,6 +682,12 @@ export type MutationResolvers< ContextType, RequireFields >; + removePostUpvote: Resolver< + Maybe, + ParentType, + ContextType, + RequireFields + >; updatePanoComment: Resolver< Maybe, ParentType, @@ -760,6 +834,16 @@ export type PanoQueryResolvers< __isTypeOf?: IsTypeOfResolverFn; }>; +export type PostUpvoteResolvers< + ContextType = KampusGQLContext, + ParentType extends ResolversParentTypes["PostUpvote"] = ResolversParentTypes["PostUpvote"] +> = ResolversObject<{ + id: Resolver; + postID: Resolver; + userID: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type QueryResolvers< ContextType = KampusGQLContext, ParentType extends ResolversParentTypes["Query"] = ResolversParentTypes["Query"] @@ -798,6 +882,17 @@ export type RemovePanoPostPayloadResolvers< >; }>; +export type RemovePostUpvotePayloadResolvers< + ContextType = KampusGQLContext, + ParentType extends ResolversParentTypes["RemovePostUpvotePayload"] = ResolversParentTypes["RemovePostUpvotePayload"] +> = ResolversObject<{ + __resolveType?: TypeResolveFn< + "InvalidInput" | "NotAuthorized" | "PostUpvote", + ParentType, + ContextType + >; +}>; + export type SozlukQueryResolvers< ContextType = KampusGQLContext, ParentType extends ResolversParentTypes["SozlukQuery"] = ResolversParentTypes["SozlukQuery"] @@ -920,6 +1015,7 @@ export type Resolvers = ResolversObject<{ Actor: ActorResolvers; CreatePanoCommentPayload: CreatePanoCommentPayloadResolvers; CreatePanoPostPayload: CreatePanoPostPayloadResolvers; + CreatePostUpvotePayload: CreatePostUpvotePayloadResolvers; Date: GraphQLScalarType; DateTime: GraphQLScalarType; InvalidInput: InvalidInputResolvers; @@ -934,9 +1030,11 @@ export type Resolvers = ResolversObject<{ PanoPostConnection: PanoPostConnectionResolvers; PanoPostEdge: PanoPostEdgeResolvers; PanoQuery: PanoQueryResolvers; + PostUpvote: PostUpvoteResolvers; Query: QueryResolvers; RemovePanoCommentPayload: RemovePanoCommentPayloadResolvers; RemovePanoPostPayload: RemovePanoPostPayloadResolvers; + RemovePostUpvotePayload: RemovePostUpvotePayloadResolvers; SozlukQuery: SozlukQueryResolvers; SozlukTerm: SozlukTermResolvers; SozlukTermBody: SozlukTermBodyResolvers; diff --git a/db/prisma/schema.prisma b/db/prisma/schema.prisma index d20e5f07..a5a4b9be 100644 --- a/db/prisma/schema.prisma +++ b/db/prisma/schema.prisma @@ -25,6 +25,7 @@ model Upvote { updatedAt DateTime @updatedAt deletedAt DateTime? + @@unique([postID, userID]) @@index([postID]) @@index([userID]) }