Created like-post and follow-user routes, changed file names

This commit is contained in:
Hackntosh 2023-07-25 10:57:23 -03:00
parent b6be9d6755
commit 11d74d846b
33 changed files with 280 additions and 41 deletions

View file

@ -19,8 +19,8 @@ An open-source social media.
- Able to choose a profile picture✅
- Probably gonna use LocalStack to mock Amazon S3✅
- Image compression ✅
- Following/unfollowing features
- Like posts
- Following/unfollowing features
- Like posts
- Probably pinned posts
- Authentication ✅
- Add more verification (like, if the password is too short) ✅

View file

@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "Like" (
"id" TEXT NOT NULL,
"postId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Like_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Like" ADD CONSTRAINT "Like_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Like" ADD CONSTRAINT "Like_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,22 @@
-- CreateTable
CREATE TABLE "Follower" (
"id" TEXT NOT NULL,
"followerId" TEXT NOT NULL,
CONSTRAINT "Follower_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Following" (
"id" TEXT NOT NULL,
"followingId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Following_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Follower" ADD CONSTRAINT "Follower_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Following" ADD CONSTRAINT "Following_followingId_fkey" FOREIGN KEY ("followingId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,32 @@
/*
Warnings:
- You are about to drop the `Follower` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `Following` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "Follower" DROP CONSTRAINT "Follower_followerId_fkey";
-- DropForeignKey
ALTER TABLE "Following" DROP CONSTRAINT "Following_followingId_fkey";
-- DropTable
DROP TABLE "Follower";
-- DropTable
DROP TABLE "Following";
-- CreateTable
CREATE TABLE "Follows" (
"followerId" TEXT NOT NULL,
"followingId" TEXT NOT NULL,
CONSTRAINT "Follows_pkey" PRIMARY KEY ("followerId","followingId")
);
-- AddForeignKey
ALTER TABLE "Follows" ADD CONSTRAINT "Follows_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Follows" ADD CONSTRAINT "Follows_followingId_fkey" FOREIGN KEY ("followingId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -1,6 +1,3 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
@ -18,6 +15,9 @@ model User {
password String
posts Post[]
profileImage String?
likedPosts Like[]
followers Follows[] @relation("following")
following Follows[] @relation("follower")
createdAt DateTime @default(now())
}
@ -26,6 +26,24 @@ model Post {
content String
authorId String
author User @relation(fields: [authorId], references: [id])
likes Like[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
}
model Like {
id String @id @default(uuid())
postId String
post Post @relation(fields: [postId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}
model Follows {
follower User @relation("follower", fields: [followerId], references: [id])
followerId String
following User @relation("following", fields: [followingId], references: [id])
followingId String
@@id([followerId, followingId])
}

View file

@ -3,10 +3,10 @@
import { Router } from 'express'
// Controllers
import postCreateController from './posts/post-create'
import postDeleteController from './posts/post-delete'
import postInfoController from './posts/post-info'
import postUpdateController from './posts/post-update'
import postCreateController from './posts/create'
import postDeleteController from './posts/delete'
import postInfoController from './posts/get-info'
import postUpdateController from './posts/update'
// Middlewares
import ensureAuthenticated from '../middlewares/ensure-authenticated'

View file

@ -3,12 +3,14 @@
import { Router } from 'express'
// Controllers
import userAuthController from './users/user-auth'
import userDeleteController from './users/user-delete'
import userInfoController from './users/user-info'
import userSignupController from './users/user-signup'
import userUpdateController from './users/user-update'
import userUploadPictureController from './users/user-upload-picture'
import userAuthController from './users/auth'
import userDeleteController from './users/delete'
import userFollowController from './users/follow-user'
import userInfoController from './users/get-info'
import userLikePostController from './users/like-post'
import userSignupController from './users/signup'
import userUpdateController from './users/update'
import userUploadPictureController from './users/upload-picture'
// Middlewares
import ensureAuthenticated from '../middlewares/ensure-authenticated'
@ -23,5 +25,7 @@ usersRouter.get('/info', userInfoController)
usersRouter.post('/signup', userSignupController)
usersRouter.put('/update', ensureAuthenticated, userUpdateController)
usersRouter.put('/profile-picture/upload', ensureAuthenticated, uploadFile, userUploadPictureController)
usersRouter.post('/like-post', ensureAuthenticated, userLikePostController)
usersRouter.post('/follow-user', ensureAuthenticated, userFollowController)
export default usersRouter

View file

@ -0,0 +1,18 @@
import { user } from '../../services'
import type { Request, Response } from 'express'
import { badRequest } from '../../lib/http-errors'
async function userFollowController (req: Request, res: Response): Promise<void> {
const userId = req.user?.id ?? ''
const { userToFollow } = req.body
const result = await user.follow(userId, userToFollow)
if (result instanceof Error) {
return badRequest(res, result.message)
}
res.json(result)
}
export default userFollowController

View file

@ -0,0 +1,18 @@
import { user } from '../../services'
import type { Request, Response } from 'express'
import { badRequest } from '../../lib/http-errors'
async function userLikePostController (req: Request, res: Response): Promise<void> {
const userId = req.user?.id ?? ''
const { postId } = req.body
const result = await user.likePost(postId, userId)
if (result instanceof Error) {
return badRequest(res, result.message)
}
res.json(result)
}
export default userLikePostController

View file

@ -1,14 +1,16 @@
import userAuthService from './users/user-auth'
import userDeleteService from './users/user-delete'
import userInfoService from './users/user-info'
import userSignupService from './users/user-signup'
import userUpdateService from './users/user-update'
import userUploadPictureService from './users/user-upload-picture'
import userAuthService from './users/auth'
import userDeleteService from './users/delete'
import userFollowService from './users/follow-user'
import userInfoService from './users/get-info'
import userLikePostService from './users/like-post'
import userSignupService from './users/signup'
import userUpdateService from './users/update'
import userUploadPictureService from './users/upload-picture'
import postCreateService from './posts/post-create'
import postDeleteService from './posts/post-delete'
import postInfoService from './posts/post-info'
import postUpdateService from './posts/post-update'
import postCreateService from './posts/create'
import postDeleteService from './posts/delete'
import postInfoService from './posts/get-info'
import postUpdateService from './posts/update'
// User services
const user = {
@ -17,7 +19,9 @@ const user = {
info: userInfoService,
signup: userSignupService,
update: userUpdateService,
uploadPicture: userUploadPictureService
uploadPicture: userUploadPictureService,
likePost: userLikePostService,
follow: userFollowService
}
// Post services

View file

@ -15,7 +15,8 @@ async function postInfoService (id: string): Promise<Object | Error> {
displayName: true,
username: true
}
}
},
likes: true
}
})

View file

View file

@ -10,7 +10,7 @@ async function userAuthService (email: string, password: string): Promise<Object
})
if (user == null) {
return new Error('User does not exists')
return new Error('Invalid email or password')
}
if (email === undefined || password === undefined) {

View file

@ -0,0 +1,55 @@
import prisma from '../../clients/prisma-client'
async function userFollowService (userId: string, followingUsername: string): Promise<Object | Error> {
if (userId === undefined || followingUsername === undefined) {
return new Error('Missing fields')
}
const user = await prisma.user.findFirst({
where: {
username: followingUsername
}
})
if (user === null) {
return new Error('User not found')
}
const userToFollow = await prisma.user.findFirst({
where: {
id: userId
}
})
if (userToFollow === null) {
return new Error('User to follow not found')
}
const alreadyFollow = await prisma.follows.findFirst({
where: {
followerId: user.id,
followingId: userToFollow.id
}
})
if (alreadyFollow !== null) {
await prisma.follows.deleteMany({
where: {
followerId: user.id,
followingId: userToFollow.id
}
})
return {}
}
const follow = await prisma.follows.create({
data: {
followerId: user.id,
followingId: userToFollow.id
}
})
return follow
}
export default userFollowService

View file

@ -17,6 +17,11 @@ async function userInfoService (username: string): Promise<Object> {
createdAt: true,
updatedAt: true
}
},
likedPosts: {
select: {
postId: true
}
}
}
})

View file

@ -0,0 +1,55 @@
import prisma from '../../clients/prisma-client'
async function userLikePostService (postId: string, userId: string): Promise<Object | Error> {
if (postId === undefined || userId === undefined) {
return new Error('Missing fields')
}
const post = await prisma.post.findFirst({
where: {
id: postId
}
})
if (post === null) {
return new Error('Post not found')
}
const user = await prisma.user.findFirst({
where: {
id: userId
}
})
if (user === null) {
return new Error('User not found')
}
const alreadyLiked = await prisma.like.findFirst({
where: {
postId: post.id,
userId: user.id
}
})
if (alreadyLiked !== null) {
await prisma.like.deleteMany({
where: {
postId: post.id,
userId: user.id
}
})
return {}
}
const like = await prisma.like.create({
data: {
postId: post.id,
userId: user.id
}
})
return like
}
export default userLikePostService

View file

@ -8,6 +8,9 @@ async function userUpdateService ({ id, email, displayName, username }: userPayl
return new Error('User not found')
}
// Check if the provided email or username is different from the current user's data
// if they are different, additional queries are made to check if the new email or username is already in use.
if (email !== undefined && email.trim() !== user.email) {
const existingUser = await prisma.user.findFirst({ where: { email } })
if ((existingUser != null) && existingUser.email !== user.email) {

View file

@ -15,18 +15,7 @@ async function userUploadPictureService (authorId: string, url: string): Promise
profileImage: url
},
select: {
profileImage: true,
displayName: true,
username: true,
createdAt: true,
posts: {
select: {
id: true,
content: true,
createdAt: true,
updatedAt: true
}
}
profileImage: true
}
})