like and unlike post

This commit is contained in:
Guillaume Dorce 2022-08-25 18:03:06 +02:00
parent 9e5dc4a740
commit 001cce5374
8 changed files with 180 additions and 2 deletions

View File

@ -17,6 +17,7 @@ model User {
password String
posts Post[]
role Role @default(USER)
likes Like[]
}
enum Role {
@ -32,4 +33,14 @@ model Post {
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
likes Int @default(0)
likedBy Like[]
}
model Like {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}

View File

@ -3,6 +3,8 @@ import getPosts from './getPosts';
import postPost from './newPost';
import putPost from './editPost';
import deletePost from './deletePost';
import likePost from './likePost';
import unlikePost from './unlikePost';
const posts = Router();
@ -10,5 +12,7 @@ posts.get('/', getPosts);
posts.post('/new', postPost);
posts.put('/edit/:id', putPost);
posts.delete('/delete/:id', deletePost);
posts.put('/like/:id', likePost);
posts.put('/unlike/:id', unlikePost);
export default posts;

16
src/api/posts/likePost.ts Normal file
View File

@ -0,0 +1,16 @@
import { likePost } from '@/controller/PostController';
import { Request, Response } from 'express';
export default async (req: Request, res: Response) => {
try {
const id = parseInt(req.params.id);
const userId = 1; // hardcoded for now, use userId from token
const likedPost = await likePost(id, userId);
if (likedPost instanceof Error) {
return res.status(403).send(likedPost.message);
}
return res.status(200).send({ message: 'Post liked' });
} catch (error) {
return res.status(500).send(error);
}
};

View File

@ -0,0 +1,18 @@
import { unlikePost } from '@/controller/PostController';
import { Request, Response } from 'express';
export default async (req: Request, res: Response) => {
try {
const postId = parseInt(req.params.id);
const userId = 1; // hardcoded for now, use userId from token
const likedPost = await unlikePost(postId, userId);
if (likedPost instanceof Error) {
return res.status(403).send(likedPost.message);
}
return res.status(200).send({ message: 'Post unliked' });
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
};

View File

@ -1,4 +1,4 @@
import { PrismaClient, Post as PrismaPost, User } from '@prisma/client';
import { PrismaClient, Post as PrismaPost, Like } from '@prisma/client';
import { Post } from '@/models/PostModel';
const prisma = new PrismaClient();
@ -15,6 +15,9 @@ const getPostById = async (id: number): Promise<PrismaPost | null> => {
where: {
id,
},
include: {
likedBy: true,
},
});
return post;
};
@ -23,6 +26,7 @@ const getAllPosts = async (): Promise<PrismaPost[]> => {
const posts = prisma.post.findMany({
include: {
author: true,
likedBy: true,
},
});
return (await posts).map((post) => {
@ -90,4 +94,100 @@ const deletePost = async (id: number, userId: number): Promise<PrismaPost | Erro
});
};
export { getAllPosts, createPost, editPost, getPostById, deletePost };
const unlikePost = async (postId: number, userId: number): Promise<Like | Error> => {
const post = await prisma.post.findUnique({
where: {
id: postId,
},
include: {
likedBy: true,
},
});
if (post === null) {
return new Error('Post not found');
}
const user = await prisma.user.findUnique({
where: {
id: userId,
},
include: {
likes: true,
},
});
if (user === null) {
return new Error('User not found');
}
const like = post.likedBy.find((likes) => likes.postId === postId && likes.userId === userId);
if (like === undefined) {
return new Error('Post not liked');
}
await prisma.post.update({
where: {
id: postId,
},
data: {
likes: {
decrement: 1,
},
},
});
return prisma.like.delete({
where: {
id: like.id,
},
});
};
const likePost = async (id: number, userId: number): Promise<PrismaPost | Error> => {
const post = await prisma.post.findUnique({
where: {
id,
},
include: {
likedBy: true,
},
});
if (post === null) {
return new Error('Post not found');
}
// if (post.authorId === userId) {
// return new Error('User cannot like their own post');
// }
if (post.likedBy.some((like) => like.userId === userId)) {
return new Error('Post already liked');
}
const newLike = await prisma.like.create({
data: {
post: {
connect: {
id,
},
},
user: {
connect: {
id: userId,
},
},
},
});
return prisma.post.update({
where: {
id,
},
data: {
likedBy: {
connect: {
id: newLike.id,
},
},
likes: {
increment: 1,
},
},
});
};
export { getAllPosts, createPost, editPost, getPostById, deletePost, likePost, unlikePost };

21
src/models/LikeModel.ts Normal file
View File

@ -0,0 +1,21 @@
import { z } from 'zod';
import { User } from './UserModel';
import { Post } from './PostModel';
interface Like {
id?: number | undefined;
userId: number;
user: User;
postId: number;
post: Post;
}
const Like: z.ZodType<Like> = z.object({
id: z.number().optional(),
userId: z.number(),
user: User,
postId: z.number(),
post: Post,
});
export { Like };

View File

@ -1,10 +1,13 @@
import { z } from 'zod';
import { Like } from './LikeModel';
interface Post {
id?: number | undefined;
content?: string | undefined;
image?: string | undefined;
authorId: number;
likes?: number | undefined;
likedBy?: Like[] | undefined;
}
const Post: z.ZodType<Post> = z.object({
@ -12,6 +15,8 @@ const Post: z.ZodType<Post> = z.object({
content: z.string().optional(),
image: z.string().optional(),
authorId: z.number(),
likes: z.number().optional(),
likedBy: z.array(Like).optional(),
});
export { Post };

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { Post } from './PostModel';
import { Like } from './LikeModel';
interface User {
id?: number | undefined;
@ -9,6 +10,7 @@ interface User {
lastName: string;
role?: string | undefined;
posts?: Post[] | undefined;
likes?: Like[] | undefined;
}
const User: z.ZodType<User> = z.object({
@ -19,6 +21,7 @@ const User: z.ZodType<User> = z.object({
lastName: z.string(),
role: z.string().optional(),
posts: z.array(Post).optional(),
likes: z.array(Like).optional(),
});
export { User };