Skip to content

Commit

Permalink
Merge pull request #180 from chani1209/feature/backend/#26-fcm
Browse files Browse the repository at this point in the history
[Feature/backend/#23 fcm] fcm을 통한 알림 구현 및 알림데이터 구현
  • Loading branch information
cdj2073 authored Dec 5, 2023
2 parents 19ccecc + 235891e commit ba09000
Show file tree
Hide file tree
Showing 14 changed files with 507 additions and 85 deletions.
38 changes: 38 additions & 0 deletions backend/src/event/dto/search-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ApiProperty } from '@nestjs/swagger';
import { User } from '../../user/entities/user.entity';
import { StatusEnum } from '../../invite/entities/status.enum';

export class SearchResponseDto {
@ApiProperty()
users: SingleSearchUser[];
static of(users: User[], isFollowed: boolean[], isJoined: StatusEnum[]) {
const res: SingleSearchUser[] = [];
users.forEach((user, index) => {
res.push({
id: user.id,
nickname: user.nickname,
profile: user.profile?.path ?? null,
isFollowed: isFollowed[index] ?? null,
isJoined: isJoined[index] ?? null,
});
});
return { users: res };
}
}

class SingleSearchUser {
@ApiProperty()
id: number;

@ApiProperty()
nickname: string;

@ApiProperty()
profile: string | null;

@ApiProperty()
isFollowed: boolean;

@ApiProperty()
isJoined: StatusEnum;
}
47 changes: 40 additions & 7 deletions backend/src/event/event.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { UpdateScheduleDto } from './dto/updateSchedule.dto';
import { EventsResponseDto } from './dto/events-response.dto';
import { EventResponseDto } from './dto/event-response.dto';
import { EventStoryResponseDto } from './dto/event-story-response.dto';
import { SearchResponseDto } from './dto/search-response.dto';

@ApiBearerAuth()
@ApiTags('event')
Expand Down Expand Up @@ -266,6 +267,7 @@ export class EventController {
required: true,
example: 123,
})
@ApiOkResponse({ type: SearchResponseDto })
async searchUserEvents(
@GetUser() user: User,
@Param('eventId', ParseIntPipe) eventId: number,
Expand Down Expand Up @@ -317,19 +319,50 @@ export class EventController {
},
},
})
async cancelSchedule(
async joinSchedule(
@GetUser() user: User,
@Body('eventId', ParseIntPipe) eventId: number,
) {
return await this.eventService.joinSchedule(user, eventId);
}
@UseGuards(JwtAuthGuard)
@Post('/schedule/accept/:eventId')
async acceptSchedule(@Param('eventId', ParseIntPipe) eventId: number) {}

@UseGuards(JwtAuthGuard)
@Post('/schedule/decline/:eventId')
async declineSchedule(@Param('eventId', ParseIntPipe) eventId: number) {}
@Post('/schedule/accept')
@ApiOperation({
summary: '일정 참여 수락 API',
description: '',
})
@ApiBody({
schema: {
type: 'object',
properties: {
inviteId: {
type: 'number',
},
eventId: {
type: 'number',
},
},
},
})
@ApiQuery({
name: 'accept',
required: false,
description: 'true를 제외한 모든건 false로 처리됩니다.',
})
async acceptSchedule(
@Body('eventId', ParseIntPipe) eventId: number,
@Body('inviteId', ParseIntPipe) inviteId: number,
@GetUser() user: User,
@Query('accept', new DefaultValuePipe(false), ParseBoolPipe)
accept: boolean,
) {
return await this.eventService.acceptSchedule(
user,
eventId,
inviteId,
accept,
);
}

@UseGuards(JwtAuthGuard)
@Get('/user/:userId')
Expand Down
2 changes: 2 additions & 0 deletions backend/src/event/event.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { EventMemberService } from '../event-member/event-member.service';
import { EventMember } from '../event-member/entities/eventMember.entity';
import { FollowModule } from '../follow/follow.module';
import { UserModule } from '../user/user.module';
import { InviteModule } from '../invite/invite.module';

@Module({
imports: [
Expand All @@ -28,6 +29,7 @@ import { UserModule } from '../user/user.module';
CalendarModule,
FollowModule,
UserModule,
InviteModule,
],
controllers: [EventController],
providers: [EventService, CalendarService, DetailService, EventMemberService],
Expand Down
163 changes: 130 additions & 33 deletions backend/src/event/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@ import { EventResponseDto } from './dto/event-response.dto';
import { EventStoryResponseDto } from './dto/event-story-response.dto';
import { Detail } from '../detail/entities/detail.entity';
import { UserService } from '../user/user.service';
import { InviteService } from '../invite/invite.service';
import { StatusEnum } from '../invite/entities/status.enum';
import { SearchResponseDto } from './dto/search-response.dto';
import {
AlreadyJoinedException,
EventForbiddenException,
EventNotFoundException,
ExpiredInviteException,
InvalidAuthorityException,
InvalidRepeatPolicyException,
InviteNotFoundException,
InviteSelfException,
NotEventMemberException,
NotInviteReceiverException,
NotRepeatEventException,
SearchPeriodException,
SearchSelfException,
Expand All @@ -42,6 +49,7 @@ export class EventService {
private eventMemberService: EventMemberService,
private followService: FollowService,
private userService: UserService,
private inviteService: InviteService,
) {}

async getEvents(user: User, startDate: string, endDate: string) {
Expand Down Expand Up @@ -852,16 +860,33 @@ export class EventService {
if (!event) {
throw new EventNotFoundException();
}
const invites = await this.inviteService.getInvitesByEvent(event);
const result: any[] = [];
rawFollowings.forEach((follower) => {
let isJoined;
const eventMember = event.eventMembers.find(
(eventMember) => eventMember.user.id === follower.follower.id,
);
if (!eventMember) {
invites.find((invite) => {
if (invite.receiver.id === follower.follower.id) {
isJoined = this.inviteService.transformStatusEnumResponse(
invite.status.displayName,
);
}
});
if (!isJoined) {
isJoined = StatusEnum.Joinable;
}
} else {
isJoined = StatusEnum.Accepted;
}
result.push({
id: follower.follower.id,
nickname: follower.follower.nickname,
profile: follower.follower.profile?.path ?? null,
isJoined: eventMember ? true : false,
// isJoined: eventMember ? true : false,
isJoined: isJoined,
});
});
return { users: result };
Expand All @@ -877,17 +902,32 @@ export class EventService {
if (!event) {
throw new EventNotFoundException();
}

const invites = await this.inviteService.getInvitesByEvent(event);
const result: any[] = [];
rawFollowers.forEach((follower) => {
let isJoined;
const eventMember = event.eventMembers.find(
(eventMember) => eventMember.user.id === follower.user.id,
);
if (!eventMember) {
invites.find((invite) => {
if (invite.receiver.id === follower.user.id) {
isJoined = this.inviteService.transformStatusEnumResponse(
invite.status.displayName,
);
}
});
if (!isJoined) {
isJoined = StatusEnum.Joinable;
}
} else {
isJoined = StatusEnum.Accepted;
}
result.push({
id: follower.user.id,
nickname: follower.user.nickname,
profile: follower.user.profile?.path ?? null,
isJoined: eventMember ? true : false,
isJoined: isJoined,
});
});
return { users: result };
Expand All @@ -906,26 +946,36 @@ export class EventService {

const findByNickname = await this.userService.findUserByNickname(nickname);
if (!findByNickname) {
throw new UserNotFoundException();
}
if (findByNickname.id === user.id) {
throw new SearchSelfException();
return SearchResponseDto.of([], [], []);
} else {
if (findByNickname.id === user.id) {
throw new SearchSelfException();
}
}

const eventMember = event.eventMembers.find(
(eventMember) => eventMember.user.id === findByNickname.id,
);

return {
id: findByNickname.id,
nickname: findByNickname.nickname,
profile: findByNickname.profile?.path ?? null,
isJoined: eventMember ? true : false,
};
const invites = await this.inviteService.getInvitesByEvent(event);
let isJoined;
if (!eventMember) {
invites.find((invite) => {
if (invite.receiver.id === findByNickname.id) {
isJoined = this.inviteService.transformStatusEnumResponse(
invite.status.displayName,
);
}
});
if (!isJoined) {
isJoined = StatusEnum.Joinable;
}
} else {
isJoined = StatusEnum.Accepted;
}
return SearchResponseDto.of([findByNickname], [], [isJoined]);
}

async inviteSchedule(user: User, userId: number, eventId: number) {
// 초대를 보내야 하지만 현재는 무조건 참여하도록 구현
const event = await this.eventRepository.findOne({
where: { id: eventId },
});
Expand All @@ -944,28 +994,18 @@ export class EventService {
}
});

const detail = {
isVisible: true,
memo: '',
color: -39579,
alarmMinutes: 10,
} as Detail;
const invitedUser = await this.userService.findUserById(userId);

const savedDetail = await this.detailService.createDetailSingle(detail);

const authority = await this.eventMemberService.getAuthorityId('MEMBER');
if (!authority) {
throw new EventForbiddenException();
if (!invitedUser || invitedUser.fcmToken === null) {
throw new UserNotFoundException();
}

await this.eventMemberService.createEventMember(
event,
await this.inviteService.sendInviteEventMessage(
user,
savedDetail,
authority,
event,
invitedUser,
invitedUser.fcmToken,
);

// todo : 초대를 보내는 것으로 구현한다.
return { result: '초대요청이 전송되었습니다.' };
}

Expand Down Expand Up @@ -1004,6 +1044,63 @@ export class EventService {
savedDetail,
authority,
);
return { result: '참여요청이 전송되었습니다.' };
return { result: '일정에 참가하였습니다.' };
}

async acceptSchedule(
user: User,
eventId: number,
inviteId: number,
isAccept: boolean,
) {
const event = await this.eventRepository.findOne({
where: { id: eventId },
});

if (!event) {
throw new NotEventMemberException();
}

const invite = await this.inviteService.getInviteById(inviteId);

if (!invite) {
throw new InviteNotFoundException();
}

if (invite.status.displayName !== StatusEnum.Pending) {
throw new ExpiredInviteException();
}

if (invite.receiver.id !== user.id) {
throw new NotInviteReceiverException();
}

if (isAccept) {
const detail = {
isVisible: true,
memo: '',
color: -39579,
alarmMinutes: 10,
} as Detail;

const savedDetail = await this.detailService.createDetailSingle(detail);

const authority = await this.eventMemberService.getAuthorityId('MEMBER');
if (!authority) {
throw new InvalidAuthorityException();
}

await this.eventMemberService.createEventMember(
event,
user,
savedDetail,
authority,
);
await this.inviteService.updateInvite(invite.id, StatusEnum.Accepted);
return { result: '일정에 참가하였습니다.' };
} else {
await this.inviteService.updateInvite(invite.id, StatusEnum.Rejected);
return { result: '일정에 참가하지 않았습니다.' };
}
}
}
Loading

0 comments on commit ba09000

Please sign in to comment.