Skip to content

Commit

Permalink
Merge pull request #59 from depromeet/dev
Browse files Browse the repository at this point in the history
알림탭 푸시알림 기능 구현
  • Loading branch information
ImNM authored May 21, 2022
2 parents c848057 + 8aa0193 commit ed9751a
Show file tree
Hide file tree
Showing 49 changed files with 2,806 additions and 198 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,5 @@ dist

# TernJS port file
.tern-port

fcm-admin.json
2,072 changes: 2,012 additions & 60 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"class-validator-mongo-object-id": "^1.3.0",
"cross-env": "^7.0.3",
"express-basic-auth": "^1.2.1",
"firebase-admin": "^10.2.0",
"hbs": "^4.1.2",
"joi": "^17.4.2",
"moment-timezone": "^0.5.34",
Expand Down
9 changes: 9 additions & 0 deletions src/apis/alarm/alarm.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { BullModule } from '@nestjs/bull';
import { PushAlarmProcessor } from './pushAlarm.processor';
import { PUSH_ALARM, SAVE_ALARM } from 'src/common/consts/enum';
import { SaveAlarmProcessor } from './saveAlarm.processor';
import { NotiController } from './noti.controller';
import { FcmModule } from 'src/fcm/fcm.module';
import * as path from 'path';
import { RoomsModule } from '../rooms/rooms.module';

@Module({
imports: [
Expand All @@ -21,7 +25,12 @@ import { SaveAlarmProcessor } from './saveAlarm.processor';
name: SAVE_ALARM,
},
),
FcmModule.forRoot({
credentialPath: path.join(__dirname, '../../../fcm-admin.json'),
}),
RoomsModule,
],
controllers: [NotiController],
providers: [
AlarmService,
AlarmRepository,
Expand Down
69 changes: 58 additions & 11 deletions src/apis/alarm/alarm.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import { Room } from 'src/models/room.model';
import { AlarmIdDto } from 'src/common/dtos/AlarmId.dto';
import { AlarmShowDto } from './dto/alarmShow.dto';
import { plainToInstance } from 'class-transformer';
import { QuestionIdDto } from 'src/common/dtos/QuestionId.dto';
import { PageLastIdDto } from 'src/common/dtos/PageLastIdDto';
import { AlarmPaginationShowDto } from './dto/alarmPaginationShow.dto';
import { FcmService } from 'src/fcm/fcm.service';
import { LetterRoomIdDto } from 'src/common/dtos/LetterRoomId.dto';
@Injectable()
export class AlarmService {
constructor(
Expand Down Expand Up @@ -68,12 +73,18 @@ export class AlarmService {

// 나한테 편지가 왔을 때
// 푸시알림만 해야함
async pushLetterAlarm(sender: User, receiver: UserIdDto, letter: Letter) {
async pushLetterAlarm(
sender: User,
receiver: UserIdDto,
letter: Letter,
letterRoomIdDto: LetterRoomIdDto,
) {
const sendPushAlarmObj: SendPushAlarmPubDto = {
nickname: sender.nickname,
content: letter.message,
pushAlarmType: PUSH_ALARM_TYPE.LETTER,
receivers: [receiver.userId],
letterRoomId: letterRoomIdDto.letterRoomId.toString(),
};
// const redis = await this.pushAlarmQueue.isReady();
// console.log('check', redis);
Expand All @@ -87,10 +98,22 @@ export class AlarmService {
nickname: sender.nickname,
user: receiver.userId.toString(),
alarmType: ALARM_STORE_TYPE.LIGHTNING,
deepLink: '',
};
await this.saveAlarmQueue.add(ALARM_STORE_TYPE.LIGHTNING, saveAlarmDto);
}
// 내 레벨이 올랐을 때 (기획 기달려야함)

async handleLevelUpAlarm(receiver: UserIdDto, level: string) {
const saveAlarmDto: SaveAlarmDto = {
user: receiver.userId.toString(),
content: level,
alarmType: ALARM_STORE_TYPE.LIGHTNING_LEVELUP,
};
await this.saveAlarmQueue.add(
ALARM_STORE_TYPE.LIGHTNING_LEVELUP,
saveAlarmDto,
);
}

// 내 질문에 댓글 달렸을 때 ( 내 댓글이면 제외 시켜야함. (이또한 책임을 알람 서비스로 넘김 ))

Expand All @@ -99,6 +122,7 @@ export class AlarmService {
receiver: UserIdDto,
room: Room,
comment: string,
questionIdDto: QuestionIdDto,
) {
// console.log('check', sender);
const saveAlarmDto: SaveAlarmDto = {
Expand All @@ -107,7 +131,7 @@ export class AlarmService {
content: comment,
roomName: room.name,
alarmType: ALARM_STORE_TYPE.COMMENT,
deepLink: '',
questionId: questionIdDto.questionId.toString(),
};
await this.saveAlarmQueue.add(ALARM_STORE_TYPE.COMMENT, saveAlarmDto);

Expand All @@ -116,13 +140,11 @@ export class AlarmService {
content: comment,
receivers: [receiver.userId],
pushAlarmType: PUSH_ALARM_TYPE.COMMENT,
questionId: questionIdDto.questionId.toString(),
};
await this.pushAlarmQueue.add(PUSH_ALARM_TYPE.COMMENT, sendPushAlarmObj);
}

// 내 레벨이 올랐을 때 (기획 기달려야함)
async handleLevelUpAlarm() {}

// 서비스 공식알림 ( 추후 추가 )

// 알림 읽었을 때
Expand All @@ -141,12 +163,37 @@ export class AlarmService {
await this.alarmRepository.watchAllAlarm(userIdDto);
}

async getMyAlarms(userIdDto: UserIdDto): Promise<AlarmShowDto[]> {
const alarmRawList = await this.alarmRepository.findAlarmByUserId(
userIdDto,
);
async getMyAlarms(
userIdDto: UserIdDto,
pageLastIdDto: PageLastIdDto,
): Promise<AlarmPaginationShowDto> {
console.log(userIdDto);
let alarmRawList = [];
if (!pageLastIdDto.lastId) {
alarmRawList = await this.alarmRepository.findAlarmByUserIdFirst(
userIdDto,
50,
);
} else {
alarmRawList = await this.alarmRepository.findAlarmByUserIdAndLastId(
userIdDto,
pageLastIdDto,
50,
);
}

const alarmList = plainToInstance(AlarmShowDto, alarmRawList, {
excludeExtraneousValues: true,
});
const isLast = alarmList.length === 50 ? false : true;
let lastId;
if (alarmList.length === 50) {
lastId = alarmList[49]._id.toString();
} else {
lastId = null;
}

return plainToInstance(AlarmShowDto, alarmRawList);
return new AlarmPaginationShowDto(alarmList, isLast, lastId);
}

// 안읽은 알림 갯수
Expand Down
36 changes: 36 additions & 0 deletions src/apis/alarm/dto/alarmPaginationShow.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ApiProperty } from '@nestjs/swagger';
import { Expose, Transform, Type } from 'class-transformer';
import { Types } from 'mongoose';
import { ALARM_STORE_TYPE } from 'src/common/consts/enum';
import { AlarmShowDto } from './alarmShow.dto';

// use for message transfor
export class AlarmPaginationShowDto {
constructor(noti_list: AlarmShowDto[], isLast: boolean, lastId: string) {
this.isLast = isLast;
this.lastId = lastId;
this.noti_list = noti_list;
}
// 직렬화
@ApiProperty({
type: String,
description: '알림 리스트',
})
@Expose()
@Type(() => AlarmShowDto)
noti_list: AlarmShowDto[];

@ApiProperty({
type: String,
description: '마지막인지 여부 ',
})
@Expose()
isLast: boolean;

@ApiProperty({
type: String,
description: '마지막 콘텐트의 아이디',
})
@Expose()
lastId: string;
}
60 changes: 52 additions & 8 deletions src/apis/alarm/dto/alarmShow.dto.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
import { ApiProperty } from '@nestjs/swagger';
import { Exclude, Expose, Transform, Type } from 'class-transformer';
import { Exclude, Expose, Transform } from 'class-transformer';
import { ALARM_STORE_TYPE, DEEPLINK_BASEURL } from 'src/common/consts/enum';
import { TransformObjectIdToString } from 'src/common/decorators/Expose.decorator';
import { toKRTimeZone } from 'src/common/funcs/toKRTimezone';
import { Types } from 'mongoose';
import { ALARM_STORE_TYPE } from 'src/common/consts/enum';

// use for message transfor
export class AlarmShowDto {
// 직렬화
@ApiProperty({
type: String,
description: '알림의 고유 아이디 정보',
})
@TransformObjectIdToString({ toClassOnly: true })
@Expose()
_id: Types.ObjectId;

@Exclude({ toPlainOnly: false })
@Exclude({ toPlainOnly: true })
@Expose({ toClassOnly: true })
roomName?: string;

@Exclude({ toPlainOnly: false })
@Exclude({ toPlainOnly: true })
@Expose({ toClassOnly: true })
nickname: string;

@Exclude({ toPlainOnly: false })
@Exclude({ toPlainOnly: true })
@Expose({ toClassOnly: true })
user: string;

@Exclude({ toPlainOnly: false })
@Exclude({ toPlainOnly: true })
@Expose({ toClassOnly: true })
content?: string;

Expand All @@ -30,7 +39,18 @@ export class AlarmShowDto {
description: '딥링크 정보',
})
@Expose()
deepLink: string;
get deepLink(): string {
switch (this.alarmType) {
case ALARM_STORE_TYPE.LIGHTNING:
return DEEPLINK_BASEURL + 'screen-type?mypage';
case ALARM_STORE_TYPE.COMMENT:
return (
DEEPLINK_BASEURL + 'question-detail?question_id=' + this.questionId
);
case ALARM_STORE_TYPE.LIGHTNING_LEVELUP:
return DEEPLINK_BASEURL + 'screen-type?mypage';
}
}

@ApiProperty({
type: String,
Expand All @@ -42,7 +62,11 @@ export class AlarmShowDto {
case ALARM_STORE_TYPE.LIGHTNING:
return this.nickname + '님이 번개를 줬어요 ⚡️';
case ALARM_STORE_TYPE.COMMENT:
return this.nickname + `님이 댓글을 남겼어요 "${this.content}"`;
return (
this.nickname + '님이 댓글을 남겼어요 ' + '“' + this.content + '“'
);
case ALARM_STORE_TYPE.LIGHTNING_LEVELUP:
return `${this.content}로 레벨업을 했어요 축하드려요!`;
case ALARM_STORE_TYPE.OFFICIAL:
return '서비스 공식알림';
}
Expand All @@ -58,6 +82,8 @@ export class AlarmShowDto {
return this.nickname;
case ALARM_STORE_TYPE.COMMENT:
return this.roomName;
case ALARM_STORE_TYPE.LIGHTNING_LEVELUP:
return `레벨 업 축하`;
case ALARM_STORE_TYPE.OFFICIAL:
return '티키타카 비밀 운영자';
}
Expand All @@ -70,4 +96,22 @@ export class AlarmShowDto {
})
@Expose()
alarmType: ALARM_STORE_TYPE;

@ApiProperty({
type: String,
description: '한국시간으로 보정된 시간값',
})
@Transform(({ value }) => toKRTimeZone(value), { toClassOnly: true })
@Expose()
createdAt: Date;

@Exclude({ toPlainOnly: true })
@Expose({ toClassOnly: true })
questionId?: string;
@ApiProperty({
type: Boolean,
description: '내가 봤는지 ',
})
@Expose()
iWatch: boolean;
}
27 changes: 27 additions & 0 deletions src/apis/alarm/dto/chatAlarm.sub.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Expose, Transform, Type } from 'class-transformer';
import { ALARM_STORE_TYPE } from 'src/common/consts/enum';
import { Types } from 'mongoose';

// use for message transfor
export class ChatAlarmSubDto {
// 직렬화
@Expose()
roomId: string;

@Expose()
chatId: string;

@Expose()
nickname: string;

@Expose() // message 내용
content: string;

@Expose()
sender: string;
}

// nickname
// content : message
// chatId : string
// roomId : string
20 changes: 16 additions & 4 deletions src/apis/alarm/dto/saveAlarm.dto.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Expose, Transform, Type } from 'class-transformer';
import { Types } from 'mongoose';
import { ALARM_STORE_TYPE } from 'src/common/consts/enum';
import { Types } from 'mongoose';

// use for message transfor
export class SaveAlarmDto {
// 직렬화
@Expose()
roomName?: string;
@Expose()
nickname: string;
nickname?: string;

@Expose()
@Transform(({ value }) => new Types.ObjectId(value), { toClassOnly: true })
Expand All @@ -17,9 +17,21 @@ export class SaveAlarmDto {
@Expose()
content?: string;

//need to be updated 딥링크 양식 정의 필요 ( 클라와 함께)
@Expose()
deepLink: string;
questionId?: string;

//need to be updated 딥링크 양식 정의 필요 ( 클라와 함께)
// @Expose()
// get deepLink(): string {
// switch (this.alarmType) {
// case ALARM_STORE_TYPE.LIGHTNING:
// return this.roomName + ' 채팅방';
// case ALARM_STORE_TYPE.COMMENT:
// return '내 질문에 새로운 댓글이 달렸어요';
// // case ALARM_STORE_TYPE.OFFICIAL:
// // return '쪽지가 도착했어요';
// }
// }

@Expose()
alarmType: ALARM_STORE_TYPE;
Expand Down
4 changes: 4 additions & 0 deletions src/apis/alarm/dto/sendPushAlarm.pub.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ export class SendPushAlarmPubDto extends PickType(SendPushAlarmSubDto, [
'content',
'pushAlarmType',
'receivers',
'questionId',
'letterRoomId',
'chatId',
'roomId',
] as const) {}
Loading

0 comments on commit ed9751a

Please sign in to comment.