Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { Body, Controller, Post, HttpCode, HttpStatus, Request , UseGuards, Put, Param, Get} from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthDto, CheckDto, SetNicknameDto } from './dto/auth.dto';
Expand Down Expand Up @@ -56,4 +55,27 @@ export class AuthController {
const email = req.user.email;
return this.authService.getNicknameByEmail(email);
}

@UseGuards(AuthGuard('jwt'))
@ApiOperation({ summary: '친구 요청' })
@Post('request')
async sendFriendRequest(@Request() req, @Body('nickname') nickname: string) {
const email = req.user.email;
return await this.authService.sendFriendRequest(email, nickname);
}

@UseGuards(AuthGuard('jwt'))
@Post('accept')
async acceptFriendRequest(@Request() req) {
const user_email = req.user.email;
return await this.authService.acceptFriendRequest(user_email);
}

@UseGuards(AuthGuard('jwt'))
@Post('reject')
async rejectFriendRequest(@Request() req) {
const user_email = req.user.email;
return await this.authService.rejectFriendRequest(user_email);
}

}
8 changes: 6 additions & 2 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { APP_GUARD, NestFactory } from '@nestjs/core';
import { AuthGuard } from './auth.guard';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from 'src/jwt.strategy';

import { FriendshipSchema, FriendSummarySchema } from './schemas/auth.friend.schema';


@Module({
Expand All @@ -23,7 +23,11 @@ import { JwtStrategy } from 'src/jwt.strategy';
signOptions: { expiresIn: process.env.JWT_EXPIRES },
}),
}),
MongooseModule.forFeature([{ name: 'Auth', schema: AuthSchema }]),
MongooseModule.forFeature([
{ name: 'Auth', schema: AuthSchema },
{ name: 'Friendship', schema: FriendshipSchema },
{ name: 'FriendSummary', schema: FriendSummarySchema },
]),
],
providers: [AuthService, {
provide: APP_GUARD,
Expand Down
147 changes: 146 additions & 1 deletion src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ObjectId } from 'mongoose';
import { FriendSummary, Friendship, FriendshipSchema } from './schemas/auth.friend.schema';
import { AuthDto } from './dto/auth.dto';
import { Injectable, UnauthorizedException, BadRequestException,ConflictException, HttpException, HttpStatus } from '@nestjs/common';
import { Injectable, UnauthorizedException, BadRequestException,ConflictException, HttpException, HttpStatus, NotFoundException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Auth, AuthSchema} from './schemas/auth.schema';
Expand All @@ -11,7 +12,9 @@ import * as bcrypt from 'bcrypt';
export class AuthService {
usersService: any;
constructor(
@InjectModel(Friendship.name) private friendshipModel: Model<Friendship>,
@InjectModel(Auth.name) private readonly authModel: Model<Auth>,
@InjectModel(FriendSummary.name) private friendSummaryModel: Model<FriendSummary>,
private jwtService: JwtService
) {}

Expand Down Expand Up @@ -139,4 +142,146 @@ export class AuthService {
const user = await this.authModel.findOne({ _id: userid });
return user.socketid;
}

async getUserByNickname(nickname: string) {
const user = await this.authModel.findOne({ nickname: nickname });
if (!user) {
throw new NotFoundException('User not found');
}
return user;
}

async sendFriendRequest(senderEmail: string, receiverNickname: string) {
const sender = await this.authModel.findOne({ email: senderEmail });
const receiver = await this.authModel.findOne({ nickname: receiverNickname });

if (!sender || !receiver) {
throw new Error('Sender or receiver not found.');
}

// Create a new friendship request and save it
const friendRequest = new this.friendshipModel({
user: sender._id,
friend: receiver._id,
isRequest: true,
isConfirmed: false,
nickname: sender.nickname,
level: sender.level,
online: sender.online,
});


const savedFriendRequest = await friendRequest.save();

const friendRequestForReceiver = new this.friendshipModel({
nickname: sender.nickname,
});

receiver.friendRequests.push(sender.nickname);
await receiver.save();

return {message: "친구 요청 성공!"};
}

async acceptFriendRequest(userEmail: string) {
const user = await this.authModel.findOne({ email: userEmail });

if (!user) {
throw new NotFoundException('유저를 찾을 수 없습니다.');
}
const friendFriendRequest = await this.friendshipModel.findOne({
friend: user._id,
isRequest: true,
});

if (!friendFriendRequest) {
throw new BadRequestException('친구 요청을 찾을 수 없습니다.');
}

// Accept the friend request and update it in the database
friendFriendRequest.isRequest = false;
friendFriendRequest.isConfirmed = true;
await friendFriendRequest.save();

const friend = new this.friendSummaryModel({
user: friendFriendRequest.friend,
nickname: friendFriendRequest.nickname,
online: friendFriendRequest.online,
level: friendFriendRequest.level,
});
user.friends.push(friend);
await user.save();

const friendUser = await this.authModel.findOne({ _id: friendFriendRequest.user });

const userSummary = new this.friendSummaryModel({
user: user._id,
nickname: user.nickname,
online: user.online,
level: user.level,
});

friendUser.friends.push(userSummary);
await friendUser.save();
user.friendRequests = user.friendRequests.filter(request => request !== friendFriendRequest.nickname);
await user.save();

return {
message: `${user.nickname}님과 ${friendFriendRequest.nickname}님이 친구가 되었습니다.`
};
}



async rejectFriendRequest(userEmail: string) {
const user = await this.authModel.findOne({ email: userEmail });

if (!user) {
throw new NotFoundException('User not found.');
}

const friendFriendRequest = await this.friendshipModel.findOne({
friend: user._id,
isRequest: true,
});

if (!friendFriendRequest) {
throw new BadRequestException('Friend request not found.');
}

//데이터 베이스에서 request를 찾아서 삭제
await this.friendshipModel.deleteOne({ _id: friendFriendRequest._id });
user.friendRequests = user.friendRequests.filter(request => request !== friendFriendRequest.nickname);
await user.save();

//친구수락 거절 메세지를 리턴
return { message: '친구 요청 거절' };
}

async getFriendList(userEmail: string) {
const user = await this.authModel.findOne({ email: userEmail });

if (!user) {
throw new Error('User not found.');
}

const friendList = user.friends.map(friend => {
return {
nickname: friend.nickname,
online: friend.online,
level: friend.level
};
});

const friendRequests = user.friendRequests.map(request => {
return {
nickname: request
};
});

return {
friendlist: friendList,
friendRequests: friendRequests
};
}
}
46 changes: 46 additions & 0 deletions src/auth/schemas/auth.friend.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Schema, Prop, SchemaFactory } from "@nestjs/mongoose"
import { Document } from "mongoose";



@Schema()
export class Friendship extends Document {
@Prop({ ref: 'Auth', required: true })
user: string; // Reference to the user's ObjectId

@Prop({ ref: 'Auth', required: true })
friend: string;

@Prop({ default: false })
isRequest: boolean; // true 라면 친구 수락전, false 라면 친구 수락 이후

@Prop({ default: false })
isConfirmed: boolean; // true 라면 친구 수락 상태 , false 라면 아직 친구 수락 대기상태

@Prop()
nickname: string; // 친구의 닉네임

@Prop()
online: boolean; // 친구의 온라인 상태

@Prop()
level: number; // 친구의 레벨
}

@Schema()
export class FriendSummary extends Document {
@Prop({ ref: 'Auth', required: true })
user: string; // 유저 ObjectID

@Prop()
nickname: string; // 친구의 닉네임

@Prop()
online: boolean; // 친구의 온라인 상태

@Prop()
level: number; // 친구의 레벨
}

export const FriendshipSchema = SchemaFactory.createForClass(Friendship);
export const FriendSummarySchema = SchemaFactory.createForClass(FriendSummary);
7 changes: 7 additions & 0 deletions src/auth/schemas/auth.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema, Prop, SchemaFactory } from "@nestjs/mongoose"
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { Document, SchemaOptions } from "mongoose";
import { FriendSummary, FriendSummarySchema } from "./auth.friend.schema";

@Schema()
export class Auth extends Document {
Expand Down Expand Up @@ -38,6 +39,12 @@ export class Auth extends Document {

@Prop({default : null})
socketid : string;

@Prop({ type: [FriendSummarySchema] })
friends: FriendSummary[];

@Prop({})
friendRequests: string[];
}

export const AuthSchema = SchemaFactory.createForClass(Auth);
1 change: 1 addition & 0 deletions src/gateway/gateway.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { RoomModule } from 'src/room/room.module';
import { UsersModule } from 'src/users/users.module';
import { PassportModule } from '@nestjs/passport';
import { CodingtestModule } from 'src/codingtest/codingtest.module';

@Module({
imports: [UsersModule, RoomModule, CodingtestModule, AuthModule],
providers : [AppGateway],
Expand Down
10 changes: 10 additions & 0 deletions src/gateway/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { userInfo } from 'os';




@ApiTags('Room')
@UseGuards(jwtSocketIoMiddleware)
@WebSocketGateway({cors : true, namespace: 'room'})
Expand Down Expand Up @@ -317,6 +318,14 @@ export class AppGateway implements OnGatewayConnection, OnGatewayDisconnect{
}


@SubscribeMessage('friendlist')
async handleFriendList(@ConnectedSocket() socket: ExtendedSocket) {
const friendList = await this.authService.getFriendList(socket.decoded.email);
socket.emit('friendlist', { success: true, payload: friendList });
}



@SubscribeMessage('timer')
async handleTimer(
@MessageBody('title') title: string,
Expand All @@ -341,4 +350,5 @@ export class AppGateway implements OnGatewayConnection, OnGatewayDisconnect{
}, 1000);

}

}