Skip to content
Merged

Dev #74

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
18 changes: 17 additions & 1 deletion src/chat-message/chat-message.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export class ChatMessageService {
where: { id: newMessage.id },
relations: ['fromUser', 'toUser'],
});

return {
id: newMessageWithUser.id,
chatRoomId: chatRoomId,
Expand Down Expand Up @@ -90,4 +89,21 @@ export class ChatMessageService {
content: body.message,
});
}

async deleteMessages(chatRoomId: number): Promise<void> {
const messages = await this.chatMessageRepository.find({
where: { chatRoom: { id: chatRoomId }, status: StatusEnum.ACTIVATED },
});

if (messages.length === 0) {
return;
}

for (const message of messages) {
message.status = StatusEnum.DEACTIVATED;
message.softDelete();
}

await this.chatMessageRepository.save(messages);
}
}
7 changes: 5 additions & 2 deletions src/chat-room/chat-room.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ChatMessageService } from 'src/chat-message/chat-message.service';
import { ChatRoom } from 'src/common/entities/chat-room.entity';
import { Matching } from 'src/common/entities/matching.entity';
import { StatusEnum } from 'src/common/enum/entityStatus';
Expand All @@ -13,6 +14,7 @@ export class ChatRoomService {
constructor(
@InjectRepository(ChatRoom)
private readonly chatRoomRepository: Repository<ChatRoom>,
private readonly chatMessageService: ChatMessageService,
) {}

async getChatRoomsWithLatestMessage(userId: number) {
Expand Down Expand Up @@ -77,15 +79,15 @@ export class ChatRoomService {
fromUser: { id: body.requesterId },
toUser: { id: body.targetId },
matching: matching,
requestStatus: 'pending',
requestStatus: MatchingRequestStatusEnum.PENDING,
});
}

async deleteChatRoom(chatRoomId: number, userId: number): Promise<void> {
const chatRoom = await this.chatRoomRepository.findOne({
where: { id: chatRoomId },
relations: ['fromUser', 'toUser'],
});

if (!chatRoom) {
throw DataNotFoundException('채팅방을 찾을 수 없습니다.');
}
Expand All @@ -102,6 +104,7 @@ export class ChatRoomService {
if (chatRoom.fromUserLeavedAt && chatRoom.toUserLeavedAt) {
chatRoom.status = StatusEnum.DEACTIVATED;
chatRoom.softDelete();
await this.chatMessageService.deleteMessages(chatRoomId);
}

await this.chatRoomRepository.save(chatRoom);
Expand Down
14 changes: 14 additions & 0 deletions src/eventGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
import { Server, Socket } from 'socket.io';
import { ChatRoomService } from './chat-room/chat-room.service';
import { ChatMessageService } from './chat-message/chat-message.service';
import { UserService } from './user/user.service';
import { UserBlockService } from './user-block/user-block.service';

//클라이언트의 패킷들이 게이트웨이를 통해서 들어오게 됩니다.
@WebSocketGateway({ namespace: '/socket/chatting' })
Expand All @@ -19,6 +21,8 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
constructor(
private readonly chatRoomService: ChatRoomService,
private readonly chatMessageService: ChatMessageService,
private readonly userService: UserService,
private readonly userBlockService: UserBlockService,
) {}
/*
유저정보는 같지만 소켓이 여러개가 연결되어 있을 경우
Expand Down Expand Up @@ -74,6 +78,16 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
},
) {
const { chatRoomId, toUserId, content, fromUserId, createdAt } = payload;
const toUser = await this.userService.getUserById(toUserId);
const blockedUserIds =
await this.userBlockService.getBlockedUserIds(toUserId);
if (!toUser || blockedUserIds.includes(fromUserId)) {
const errorMessage = !toUser
? '존재하지 않는 사용자입니다.'
: '차단된 사용자에게 메시지를 보낼 수 없습니다.';
client.emit('error', errorMessage);
return;
}

// 메시지 저장 로직
const newMessage = await this.chatMessageService.saveMessage(
Expand Down
6 changes: 3 additions & 3 deletions src/matching/dto/matching.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ class RepresentativePost {
{ url: 'https://example.com/image2.jpg', orderNum: 2 },
],
})
postImages: { url: string; orderNum: number }[];
postImages?: { url: string; orderNum: number }[];

@ApiProperty({
description: '매칭 요청자의 게시물 스타일 태그 목록',
type: [String],
example: ['classic', 'basic'],
})
styleTags: string[];
styleTags?: string[];
}
class RequesterResponse {
@ApiProperty({
Expand All @@ -78,7 +78,7 @@ class RequesterResponse {
type: RepresentativePost,
})
@Type(() => RepresentativePost)
representativePost: RepresentativePost;
representativePost?: RepresentativePost;
}

class Matching {
Expand Down
3 changes: 3 additions & 0 deletions src/matching/matching.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ChatMessageModule } from 'src/chat-message/chat-message.module';
import { ChatRoomModule } from 'src/chat-room/chat-room.module';
import { UserModule } from 'src/user/user.module';
import { PostModule } from 'src/post/post.module';
import { UserBlock } from 'src/common/entities/user-block.entity';
import { UserBlockModule } from 'src/user-block/user-block.module';

@Module({
imports: [
Expand All @@ -15,6 +17,7 @@ import { PostModule } from 'src/post/post.module';
ChatRoomModule,
forwardRef(() => UserModule),
PostModule,
UserBlockModule,
],
controllers: [MatchingController],
providers: [MatchingService],
Expand Down
41 changes: 25 additions & 16 deletions src/matching/matching.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { GetMatchingsResponse } from './dto/matching.response';
import { MatchingRequestStatusEnum } from 'src/common/enum/matchingRequestStatus';
import { StatusEnum } from 'src/common/enum/entityStatus';
import { UserBlockService } from 'src/user-block/user-block.service';

@Injectable()
export class MatchingService {
Expand All @@ -22,6 +23,7 @@ export class MatchingService {
private readonly chatRoomService: ChatRoomService,
private readonly chatMessageService: ChatMessageService,
private readonly dataSource: DataSource,
private readonly userBlockService: UserBlockService,
) {}

async getMatchingsByCurrentId(currentUserId: number): Promise<Matching[]> {
Expand Down Expand Up @@ -103,6 +105,8 @@ export class MatchingService {
}

async getMatchings(currentUserId: number): Promise<GetMatchingsResponse> {
const blockedUserIds =
await this.userBlockService.getBlockedUserIds(currentUserId);
const matchings = await this.matchingRepository
.createQueryBuilder('matching')
.leftJoinAndSelect('matching.requester', 'requester')
Expand All @@ -120,12 +124,15 @@ export class MatchingService {
.andWhere('requester.status = :activated', {
activated: StatusEnum.ACTIVATED,
})
.orderBy(
// 우선순위: isRepresentative가 true인 게시물 먼저, 그 다음은 최신 게시물
'CASE WHEN post.isRepresentative = true THEN 0 ELSE 1 END',
'ASC',
.andWhere(
blockedUserIds.length > 0
? 'requester.id NOT IN (:...blockedUserIds)'
: '1=1',
{ blockedUserIds },
)
.addOrderBy('post.createdAt', 'DESC')
.orderBy('matching.createdAt', 'DESC')
.addOrderBy('post.isRepresentative', 'DESC') // 'isRepresentative'가 true인 게시물을 우선적으로 정렬
.addOrderBy('post.createdAt', 'DESC') // 그 다음은 최신 게시물 우선으로 정렬
.getMany();

const response: GetMatchingsResponse = {
Expand All @@ -140,17 +147,19 @@ export class MatchingService {
id: matching.requester.id,
nickname: matching.requester.nickname,
profilePictureUrl: matching.requester.profilePictureUrl,
representativePost: {
postImages: requesterPost.postImages.map((image) => ({
url: image.url,
orderNum: image.orderNum,
})),
styleTags: requesterPost.postStyletags
? requesterPost.postStyletags.map(
(styleTag) => styleTag.styletag.tag,
)
: [],
},
representativePost: requesterPost
? {
postImages: requesterPost.postImages.map((image) => ({
url: image.url,
orderNum: image.orderNum,
})),
styleTags: requesterPost.postStyletags
? requesterPost.postStyletags.map(
(styleTag) => styleTag.styletag.tag,
)
: [],
}
: {},
},
};
}),
Expand Down
4 changes: 2 additions & 2 deletions src/post-clothing/post-clothing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class PostClothingService {
// 빈 배열이 들어온 경우
if (uploadClothingDtos.length === 0) {
const clothingsToDeactivate = existingPostClothings.filter(
(existingClothing) => existingClothing.status === 'activated',
(existingClothing) => existingClothing.status === StatusEnum.ACTIVATED,
);

await this.deletePostClothing(clothingsToDeactivate, queryRunner);
Expand All @@ -62,7 +62,7 @@ export class PostClothingService {
// 삭제할 PostClothing
const postClothingsToRemove = existingPostClothings.filter(
(existingPostClothing) =>
existingPostClothing.status === 'activated' &&
existingPostClothing.status === StatusEnum.ACTIVATED &&
!uploadClothingDtos.some(
(newClothing) => newClothing.id === existingPostClothing.clothing.id,
),
Expand Down
2 changes: 1 addition & 1 deletion src/post-image/post-image.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class PostImageService {
// 삭제할 이미지 목록
const imagesToRemove = existingImages.filter(
(existingImage) =>
existingImage.status === 'activated' &&
existingImage.status === StatusEnum.ACTIVATED &&
!postImages.some((newImage) => newImage.url === existingImage.url),
);

Expand Down
6 changes: 3 additions & 3 deletions src/post-like/post-like.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ export class PostLikeService {
await this.postLikeRepository.save(likeData);
return {
id: likeData.post.id,
isPostLike: likeData.status === 'activated',
isPostLike: likeData.status === StatusEnum.ACTIVATED,
postLikesCount:
likeData.status === 'activated'
likeData.status === StatusEnum.ACTIVATED
? allLikesData.length + 1
: allLikesData.length - 1,
};
Expand All @@ -124,7 +124,7 @@ export class PostLikeService {
await this.postLikeRepository.save(newLike);
return {
id: newLike.post.id,
isPostLike: newLike.status === 'activated',
isPostLike: newLike.status === StatusEnum.ACTIVATED,
postLikesCount: allLikesData.length + 1,
};
}
Expand Down
5 changes: 3 additions & 2 deletions src/post-styletag/post-styletag.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export class PostStyletagService {

if (newTags.length === 0) {
const tagsToDelete = existingPostStyletags.filter(
(existingPostStyletag) => existingPostStyletag.status === 'activated',
(existingPostStyletag) =>
existingPostStyletag.status === StatusEnum.ACTIVATED,
);

await this.deletePostStyletags(tagsToDelete, queryRunner);
Expand All @@ -88,7 +89,7 @@ export class PostStyletagService {
const newTagIds = styleTags.map((tag) => tag.id);
const tagsToRemove = existingPostStyletags.filter(
(existingTag) =>
existingTag.status === 'activated' &&
existingTag.status === StatusEnum.ACTIVATED &&
!newTagIds.includes(existingTag.styletag.id),
);

Expand Down
Loading
Loading