-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8e9fddd
commit 115b155
Showing
11 changed files
with
395 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { Request, Response } from 'express'; | ||
import { FollowService } from '../services/follow.service'; | ||
import asyncHandler from 'express-async-handler'; | ||
import i18next from 'i18next'; | ||
import { isAuthenticated } from '../middlewares/auth.middleware'; | ||
|
||
const { t } = i18next; | ||
const followService = new FollowService(); | ||
|
||
// Follow a user | ||
export const followUser = [ | ||
isAuthenticated, | ||
asyncHandler(async (req: Request, res: Response) => { | ||
const followerId = req.session.user?.id || 0; | ||
const followedId = parseInt(req.params.userId, 10); | ||
|
||
try { | ||
await followService.followUser(followerId, followedId); | ||
req.flash('flashMessage', t('message.followSuccess')); | ||
res.redirect(`/users/${followedId}`); | ||
} catch (error) { | ||
console.error(error); | ||
const err = error as Error; | ||
req.flash('flashMessage', err.message); | ||
res.redirect(`/users/${followedId}`); | ||
} | ||
}), | ||
]; | ||
|
||
// Unfollow a user | ||
export const unfollowUser = [ | ||
isAuthenticated, | ||
asyncHandler(async (req: Request, res: Response) => { | ||
const followerId = req.session.user?.id || 0; | ||
const followedId = parseInt(req.params.userId, 10); | ||
|
||
try { | ||
await followService.unfollowUser(followerId, followedId); | ||
req.flash('flashMessage', t('message.unfollowSuccess')); | ||
res.redirect(`/users/${followedId}`); | ||
} catch (error) { | ||
console.error(error); | ||
res.redirect(`/users/${followedId}`); | ||
} | ||
}), | ||
]; | ||
|
||
// Get followers of a user | ||
export const getFollowers = asyncHandler(async (req: Request, res: Response) => { | ||
const userId = parseInt(req.params.userId, 10); | ||
|
||
try { | ||
const followers = await followService.getFollowers(userId); | ||
res.render('user/followers', { | ||
followers, | ||
title: t('title.followers'), | ||
flashMessage: req.flash('flashMessage'), | ||
}); | ||
} catch (error) { | ||
console.error(error); | ||
res.status(500).send(t('error.serverError')); | ||
} | ||
}); | ||
|
||
// Get following users of a user | ||
export const getFollowing = asyncHandler(async (req: Request, res: Response) => { | ||
const userId = parseInt(req.params.userId, 10); | ||
|
||
try { | ||
const following = await followService.getFollowing(userId); | ||
res.render('user/following', { | ||
following, | ||
title: t('title.following'), | ||
flashMessage: req.flash('flashMessage'), | ||
}); | ||
} catch (error) { | ||
console.error(error); | ||
res.status(500).send(t('error.serverError')); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// routes/follow.routes.ts | ||
|
||
import express from 'express'; | ||
import { | ||
followUser, | ||
unfollowUser, | ||
getFollowers, | ||
getFollowing, | ||
} from '../controllers/follow.controller'; | ||
|
||
const router = express.Router(); | ||
|
||
// Follow a user | ||
router.post('/follow/:userId', followUser); | ||
|
||
// Unfollow a user | ||
router.post('/unfollow/:userId', unfollowUser); | ||
|
||
// Get followers of a user | ||
router.get('/:userId/followers', getFollowers); | ||
|
||
// Get following users of a user | ||
router.get('/:userId/following', getFollowing); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { AppDataSource } from '../config/data-source'; | ||
import { User } from '../entities/user.entity'; | ||
|
||
export class FollowService { | ||
private userRepository = AppDataSource.getRepository(User); | ||
|
||
async followUser(followerId: number, followedId: number): Promise<void> { | ||
if (followerId === followedId) { | ||
throw new Error('You cannot follow yourself'); | ||
} | ||
|
||
const follower = await this.userRepository.findOne({ | ||
where: { userId: followerId }, | ||
relations: ['following'], | ||
}); | ||
|
||
const followed = await this.userRepository.findOne({ | ||
where: { userId: followedId }, | ||
}); | ||
|
||
if (!follower || !followed) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
if (follower.following.some(user => user.userId === followedId)) { | ||
throw new Error('You are already following this user'); | ||
} | ||
|
||
follower.following.push(followed); | ||
await this.userRepository.save(follower); | ||
} | ||
|
||
async unfollowUser(followerId: number, followedId: number): Promise<void> { | ||
if (followerId === followedId) { | ||
throw new Error('You cannot unfollow yourself'); | ||
} | ||
|
||
const follower = await this.userRepository.findOne({ | ||
where: { userId: followerId }, | ||
relations: ['following'], | ||
}); | ||
|
||
if (!follower) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
follower.following = follower.following.filter(user => user.userId !== followedId); | ||
await this.userRepository.save(follower); | ||
} | ||
|
||
async getFollowers(userId: number): Promise<User[]> { | ||
const user = await this.userRepository.findOne({ | ||
where: { userId }, | ||
relations: ['followers'], | ||
}); | ||
|
||
if (!user) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
return user.followers; | ||
} | ||
|
||
async getFollowing(userId: number): Promise<User[]> { | ||
const user = await this.userRepository.findOne({ | ||
where: { userId }, | ||
relations: ['following'], | ||
select: { | ||
following: { | ||
userId: true, | ||
username: true, | ||
} | ||
} | ||
}); | ||
|
||
if (!user) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
return user.following; | ||
} | ||
|
||
async isFollowing(followerId: number, followedId: number): Promise<boolean> { | ||
const follower = await this.userRepository.findOne({ | ||
where: { userId: followerId }, | ||
relations: ['following'], | ||
}); | ||
|
||
if (!follower) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
return follower.following.some(user => user.userId === followedId); | ||
} | ||
} |
Oops, something went wrong.