Skip to content

Commit

Permalink
Merge pull request #23 from azeddine-hmd/dev
Browse files Browse the repository at this point in the history
complete friend request feature with sockets data sync
  • Loading branch information
azeddine-hmd authored Dec 26, 2023
2 parents 68f7517 + fb98fe1 commit 88e67a6
Show file tree
Hide file tree
Showing 38 changed files with 665 additions and 311 deletions.
148 changes: 75 additions & 73 deletions backend/prisma/seed.ts
Original file line number Diff line number Diff line change
@@ -1,97 +1,100 @@
import { PrismaClient, UserStatus } from '@prisma/client'
import { PrismaClient, UserStatus } from '@prisma/client';

const prisma = new PrismaClient()
const prisma = new PrismaClient();

async function fakeUsers() {
await prisma.user.createMany({
data: [
{
username: "test1",
email: "test1@test.com",
displayName: "test1",
id: 1,
username: 'test1',
email: 'test1@test.com',
displayName: 'test1',
active: true,
status: UserStatus.OFFLINE,
password: "$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy",
password:
'$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy',
dateOfBirth: new Date(),
},
{
username: "test2",
email: "test2@test.com",
displayName: "test2",
id: 2,
username: 'test2',
email: 'test2@test.com',
displayName: 'test2',
active: true,
status: UserStatus.OFFLINE,
password: "$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy",
password:
'$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy',
dateOfBirth: new Date(),
},
{
username: "test3",
email: "test3@test.com",
displayName: "test3",
id: 3,
username: 'test3',
email: 'test3@test.com',
displayName: 'test3',
active: true,
status: UserStatus.OFFLINE,
password: "$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy",
password:
'$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy',
dateOfBirth: new Date(),
},
{
username: "test4",
email: "test4@test.com",
displayName: "test4",
id: 4,
username: 'test4',
email: 'test4@test.com',
displayName: 'test4',
active: true,
status: UserStatus.OFFLINE,
password: "$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy",
password:
'$2b$10$dQSMKR7ywUMr0/WNz8EFoOQ8VTUwuGAvsBgijQyYtPgLOMyiyGTRy',
dateOfBirth: new Date(),
},
]
})
await prisma.file.createMany({
data: [
{
filename: 'test1-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=1',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test1' } },
},
{
filename: 'test2-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=2',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test2' } },
},
{
filename: 'test3-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=3',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test3' } },
},
{
filename: 'test4-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=4',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test4' } },
},
{
filename: 'test5-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=5',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test5' } },
},
],
});
await prisma.file.create({
data: {
filename: 'test1-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=1',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test1' } },
},
});
await prisma.file.create({
data: {
filename: 'test2-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=2',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test2' } },
},
});
await prisma.file.create({
data: {
filename: 'test3-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=3',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test3' } },
},
});
await prisma.file.create({
data: {
filename: 'test4-avatar',
fieldname: 'avatar',
filePath: 'wefwefA',
url: 'https://i.pravatar.cc/150?img=4',
mimeType: 'image/jpg',
fileSize: 5000,
uploadedBy: { connect: { username: 'test4' } },
},
});
}

async function main() {
Expand All @@ -100,11 +103,10 @@ async function main() {

main()
.then(async () => {
await prisma.$disconnect()
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})

console.error(e);
await prisma.$disconnect();
process.exit(1);
});
6 changes: 3 additions & 3 deletions backend/src/api/auth/auth-controller.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { plainToClass } from 'class-transformer';
import { Request, Response } from 'express';
import { RegisterDto } from './dto/register-dto';
import { RegisterDto } from './types/dto/register-dto';
import { validate } from 'class-validator';
import * as authService from './auth-service';
import { VerifyEmailDto } from './dto/verify-email';
import { LoginDto } from './dto/login-dto';
import { VerifyEmailDto } from './types/dto/verify-email';
import { LoginDto } from './types/dto/login-dto';
import { defaultCookieOptions } from '../../config';
import * as profileService from '../users/services/profile-service';

Expand Down
7 changes: 6 additions & 1 deletion backend/src/api/auth/auth-service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { RegisterDto } from './dto/register-dto';
import { CodeOperation, User } from '@prisma/client';
import { randomUUID } from 'crypto';
import { comparePassword, hashPassword } from '../../utils/password';
import { prisma, signJwt } from '../../config';
import { sendVerificationMail } from '../../utils/send-mail';
import { HttpError } from '../../utils/error';
import { RegisterDto } from './types/dto/register-dto';

export async function registerUser(registerDto: RegisterDto): Promise<User> {
const hashedPassword = await hashPassword(registerDto.password);
const birth = registerDto.dateOfBirth;
const oldUser = await prisma.user.findFirst({
where: { username: registerDto.username },
});
if (oldUser && !oldUser.active)
await prisma.user.delete({ where: { id: oldUser.id } });
const user = await prisma.user.create({
data: {
displayName: registerDto.displayName,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions backend/src/api/sockets/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export const io = new Server(server, {

io.adapter(createAdapter(pool));

(async () => {
await prisma.userSockets.deleteMany({});
await prisma.user.updateMany({
where: {},
data: { status: UserStatus.OFFLINE },
});
})();
require('./middlewares');

const onConnection = listenerWrapper(async (socket) => {
Expand Down
27 changes: 13 additions & 14 deletions backend/src/api/sockets/users-handler.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import { Socket } from 'socket.io';
import * as profileService from '../users/services/profile-service';
import { listenerWrapper } from '../../utils/listener-wrapper';
import { mapToPrivateProfile, mapToPublicProfile } from '../users/users-mapper';

module.exports = (io: Socket, socket: Socket) => {
const profile = async () => {
console.log('recieving listener for event:', 'profile');
const { profile, avatar } = await profileService.getProfile(socket.user.id);
const profile = await profileService.getProfile(socket.user.id);

socket.emit('profile', {
id: profile.id,
username: profile.username,
displayName: profile.displayName,
avatar: avatar.url,
status: profile.status.toLowerCase(),
...mapToPrivateProfile(profile),
});
};

const relation = async () => {
console.log('recieving listener for event:', 'relation');
const blockedUsersprofile = await profileService.getBlockedUsersProfile(
socket.user.id
);
const friendsProfile = await profileService.getFriendsProfile(
socket.user.id
);
const id = socket.user.id;
const friends = await profileService.getFriendsProfile(id);
const blocked = await profileService.getBlockedUsersProfile(id);
const { acceptFR, sentFR } = await profileService.getPendingFRProfile(id);

socket.emit('relation', {
friends: friendsProfile,
blocked: blockedUsersprofile,
friends: friends.map((profile) => mapToPublicProfile(profile)),
blocked: blocked.map((profile) => mapToPublicProfile(profile)),
sentFR: sentFR.map((profile) => mapToPublicProfile(profile)),
acceptFR: acceptFR.map((profile) => mapToPublicProfile(profile)),
});
};

Expand Down
21 changes: 5 additions & 16 deletions backend/src/api/users/controllers/profile-controller.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
import { Request, Response } from 'express';
import * as profileService from '../services/profile-service';
import { File, User } from '@prisma/client';
import { HttpError } from '../../../utils/error';

function mapToProfileResponse(user: User, avatar?: File) {
return {
email: user.email,
username: user.username,
displayName: user.displayName,
dateOfBirth: user.dateOfBirth,
status: user.status.toLowerCase(),
avatar: avatar ? avatar.url : '',
};
}
import { mapToPrivateProfile, mapToPublicProfile } from '../users-mapper';

export async function myProfile(req: Request, res: Response) {
const { profile, avatar } = await profileService.getProfile(req.user.id);
res.status(200).send(mapToProfileResponse(profile, avatar));
const profile = await profileService.getProfile(req.user.id);
res.status(200).send(mapToPrivateProfile(profile));
}

export async function otherProfile(req: Request, res: Response) {
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
const { profile, avatar } = await profileService.getProfile(id);
res.status(200).send(mapToProfileResponse(profile, avatar));
const profile = await profileService.getProfile(id);
res.status(200).send(mapToPublicProfile(profile));
}

export async function uploadAvatar(req: Request, res: Response) {
Expand Down
33 changes: 27 additions & 6 deletions backend/src/api/users/controllers/relationship-controller.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,66 @@
import { Request, Response } from 'express';
import * as relationshipService from '../services/relationship-service';
import { HttpError } from '../../../utils/error';
import { mapToPublicProfile } from '../users-mapper';

export async function sendFriendRequest(req: Request, res: Response) {
if (!req.params.username)
throw new HttpError(400, 'Invalid recipient username');
const recipientUsername = req.params.username;
if (!recipientUsername || recipientUsername === '')
throw new HttpError(400, 'Invalid recipient username');
const recipientProfile = await relationshipService.sendFriendRequest(
req.user,
recipientUsername
);
res.status(201).send(mapToPublicProfile(recipientProfile));
}

export async function cancelFriendRequest(req: Request, res: Response) {
if (!req.params.username)
throw new HttpError(400, 'Invalid recipient username');
const recipientUsername = req.params.username;
if (!recipientUsername || recipientUsername === '')
throw new HttpError(400, 'Invalid recipient username');
await relationshipService.sendFriendRequest(req.user, recipientUsername);
await relationshipService.cancelFriendRequest(req.user, recipientUsername);
res.status(204).send();
}

export async function acceptFriendRequest(req: Request, res: Response) {
const id = parseInt(req.query.id.toString());
if (!req.params.id) throw new HttpError(400, 'Invalid Id');
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
await relationshipService.acceptFriendRequest(req.user, id);
res.status(204).send();
}

export async function rejectFriendRequest(req: Request, res: Response) {
const id = parseInt(req.query.id.toString());
if (!req.params.id) throw new HttpError(400, 'Invalid Id');
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
await relationshipService.rejectFriendRequest(req.user, id);
res.status(204).send();
}

export async function removeFriend(req: Request, res: Response) {
const id = parseInt(req.query.id.toString());
if (!req.params.id) throw new HttpError(400, 'Invalid Id');
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
await relationshipService.removeFriend(req.user, id);
res.status(204).send();
}

export async function blockUser(req: Request, res: Response) {
const id = parseInt(req.query.id.toString());
if (!req.params.id) throw new HttpError(400, 'Invalid Id');
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
await relationshipService.blockUser(req.user, id);
res.status(204).send();
}

export async function unblockUser(req: Request, res: Response) {
const id = parseInt(req.query.id.toString());
if (!req.params.id) throw new HttpError(400, 'Invalid Id');
const id = parseInt(req.params.id);
if (!id) throw new HttpError(400, 'Invalid id');
await relationshipService.unblockUser(req.user, id);
res.status(204).send();
Expand Down
Loading

0 comments on commit 88e67a6

Please sign in to comment.