Files
forkmessager/apps/server/src/routes/friends.ts
Халимов Рустам b4b4b8e0d3 Original
2026-03-10 21:11:59 +03:00

259 lines
8.8 KiB
TypeScript

import { Router } from 'express';
import { prisma } from '../db';
import { AuthRequest } from '../middleware/auth';
import { USER_SELECT } from '../shared';
const router = Router();
// ─── Get accepted friends list ───────────────────────────────────────
router.get('/', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const friendships = await prisma.friendship.findMany({
where: {
status: 'accepted',
OR: [{ userId }, { friendId: userId }],
},
include: {
user: { select: USER_SELECT },
friend: { select: USER_SELECT },
},
});
const friends = friendships.map(f => ({
...(f.userId === userId ? f.friend : f.user),
friendshipId: f.id,
}));
res.json(friends);
} catch (error) {
console.error('Get friends error:', error);
res.status(500).json({ error: 'Ошибка получения друзей' });
}
});
// ─── Get incoming friend requests ────────────────────────────────────
router.get('/requests', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const requests = await prisma.friendship.findMany({
where: { friendId: userId, status: 'pending' },
include: {
user: { select: USER_SELECT },
},
orderBy: { createdAt: 'desc' },
});
res.json(requests.map(r => ({ id: r.id, user: r.user, createdAt: r.createdAt })));
} catch (error) {
console.error('Get friend requests error:', error);
res.status(500).json({ error: 'Ошибка получения заявок' });
}
});
// ─── Get outgoing friend requests ────────────────────────────────────
router.get('/outgoing', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const requests = await prisma.friendship.findMany({
where: { userId, status: 'pending' },
include: {
friend: { select: USER_SELECT },
},
orderBy: { createdAt: 'desc' },
});
res.json(requests.map(r => ({ id: r.id, user: r.friend, createdAt: r.createdAt })));
} catch (error) {
console.error('Get outgoing requests error:', error);
res.status(500).json({ error: 'Ошибка получения заявок' });
}
});
// ─── Get friendship status with a user ───────────────────────────────
router.get('/status/:userId', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const targetId = String(req.params.userId);
if (userId === targetId) {
res.json({ status: 'self' });
return;
}
const friendship = await prisma.friendship.findFirst({
where: {
OR: [
{ userId, friendId: targetId },
{ userId: targetId, friendId: userId },
],
},
});
if (!friendship) {
res.json({ status: 'none', friendshipId: null });
return;
}
// Determine who sent the request to show correct action
const direction = friendship.userId === userId ? 'outgoing' : 'incoming';
res.json({ status: friendship.status, friendshipId: friendship.id, direction });
} catch (error) {
console.error('Get friend status error:', error);
res.status(500).json({ error: 'Ошибка получения статуса' });
}
});
// ─── Send friend request ─────────────────────────────────────────────
router.post('/request', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const { friendId } = req.body;
if (!friendId || typeof friendId !== 'string') {
res.status(400).json({ error: 'ID пользователя обязателен' });
return;
}
if (userId === friendId) {
res.status(400).json({ error: 'Нельзя добавить себя в друзья' });
return;
}
// Check if target user exists
const targetUser = await prisma.user.findUnique({ where: { id: friendId } });
if (!targetUser) {
res.status(404).json({ error: 'Пользователь не найден' });
return;
}
// Check for existing friendship in either direction
const existing = await prisma.friendship.findFirst({
where: {
OR: [
{ userId, friendId },
{ userId: friendId, friendId: userId },
],
},
});
if (existing) {
if (existing.status === 'accepted') {
res.status(400).json({ error: 'Уже в друзьях' });
return;
}
if (existing.status === 'pending') {
// If they already sent us a request, auto-accept
if (existing.userId === friendId) {
const updated = await prisma.friendship.update({
where: { id: existing.id },
data: { status: 'accepted' },
include: { user: { select: USER_SELECT }, friend: { select: USER_SELECT } },
});
res.json({ status: 'accepted', friendship: updated });
return;
}
res.status(400).json({ error: 'Заявка уже отправлена' });
return;
}
if (existing.status === 'declined') {
// Allow re-sending if previously declined — keep existing direction to avoid @@unique conflict
const updated = await prisma.friendship.update({
where: { id: existing.id },
data: { status: 'pending' },
});
res.json({ status: 'pending', friendship: updated });
return;
}
}
const friendship = await prisma.friendship.create({
data: { userId, friendId },
include: { user: { select: USER_SELECT }, friend: { select: USER_SELECT } },
});
res.json({ status: 'pending', friendship });
} catch (error) {
console.error('Send friend request error:', error);
res.status(500).json({ error: 'Ошибка отправки заявки' });
}
});
// ─── Accept friend request ───────────────────────────────────────────
router.post('/:id/accept', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const friendshipId = String(req.params.id);
const friendship = await prisma.friendship.findUnique({ where: { id: friendshipId } });
if (!friendship || friendship.friendId !== userId || friendship.status !== 'pending') {
res.status(404).json({ error: 'Заявка не найдена' });
return;
}
const updated = await prisma.friendship.update({
where: { id: friendshipId },
data: { status: 'accepted' },
include: { user: { select: USER_SELECT }, friend: { select: USER_SELECT } },
});
res.json(updated);
} catch (error) {
console.error('Accept friend request error:', error);
res.status(500).json({ error: 'Ошибка принятия заявки' });
}
});
// ─── Decline friend request ──────────────────────────────────────────
router.post('/:id/decline', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const friendshipId = String(req.params.id);
const friendship = await prisma.friendship.findUnique({ where: { id: friendshipId } });
if (!friendship || friendship.friendId !== userId || friendship.status !== 'pending') {
res.status(404).json({ error: 'Заявка не найдена' });
return;
}
await prisma.friendship.update({
where: { id: friendshipId },
data: { status: 'declined' },
});
res.json({ success: true });
} catch (error) {
console.error('Decline friend request error:', error);
res.status(500).json({ error: 'Ошибка отклонения заявки' });
}
});
// ─── Remove friend ───────────────────────────────────────────────────
router.delete('/:id', async (req: AuthRequest, res) => {
try {
const userId = req.userId!;
const friendshipId = String(req.params.id);
const friendship = await prisma.friendship.findUnique({ where: { id: friendshipId } });
if (!friendship || (friendship.userId !== userId && friendship.friendId !== userId)) {
res.status(404).json({ error: 'Дружба не найдена' });
return;
}
await prisma.friendship.delete({ where: { id: friendshipId } });
res.json({ success: true });
} catch (error) {
console.error('Remove friend error:', error);
res.status(500).json({ error: 'Ошибка удаления друга' });
}
});
export default router;