Skip to content

Commit 269bddd

Browse files
authored
Merge branch 'develop' into feat/#25-1
2 parents 81741dc + a678c27 commit 269bddd

45 files changed

Lines changed: 920 additions & 116 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/gat-deploy.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ jobs:
4646
run: |
4747
mkdir -p src/main/resources
4848
echo "${{ secrets.GAT_SECRET_YML }}" > src/main/resources/application-secret.yml
49-
49+
50+
# FCM을 위한 자격 증명 파일 fcm-service-key.json 생성
51+
- name: Create fcm-service-key.json before Docker build
52+
run: |
53+
echo "${{ secrets.FCM_SERVICE_KEY }}" | base64 --decode > src/main/resources/fcm-service-key.json
54+
5055
# Docker 이미지 태그 준비 (SHA 해시와 latest 태그 포함)
5156
- name: Prepare image tags
5257
id: meta

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ out/
4242
.DS_Store
4343

4444
### secret yml ###
45-
src/main/resources/application-secret.yml
45+
src/main/resources/application-secret.yml
46+
src/main/resources/fcm-service-key.json

build.gradle.kts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@ dependencies {
4949
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
5050

5151
// webClient
52-
implementation ("org.springframework.boot:spring-boot-starter-webflux")
52+
implementation("org.springframework.boot:spring-boot-starter-webflux")
5353

5454
// Aop
55-
implementation ("org.springframework.boot:spring-boot-starter-aop")
55+
implementation("org.springframework.boot:spring-boot-starter-aop")
56+
57+
// fcm
58+
implementation("com.google.firebase:firebase-admin:9.2.0")
5659

5760
compileOnly("org.projectlombok:lombok")
5861
runtimeOnly("com.mysql:mysql-connector-j")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package gat_be.dev.common.config
2+
3+
import com.google.auth.oauth2.GoogleCredentials
4+
import com.google.firebase.FirebaseApp
5+
import com.google.firebase.FirebaseOptions
6+
import gat_be.dev.common.exception.GeneralException
7+
import gat_be.dev.common.status.ErrorStatus
8+
import jakarta.annotation.PostConstruct
9+
import org.springframework.beans.factory.annotation.Value
10+
import org.springframework.context.annotation.Configuration
11+
import org.springframework.core.io.Resource
12+
13+
14+
@Configuration
15+
class FirebaseConfig(
16+
@Value("\${fcm.credentials.path}") private val accountKey: Resource
17+
) {
18+
19+
@PostConstruct
20+
fun initialize() {
21+
try {
22+
val serviceAccount = accountKey.inputStream
23+
24+
val options = FirebaseOptions.builder()
25+
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
26+
.build()
27+
28+
if (FirebaseApp.getApps().isEmpty()) {
29+
FirebaseApp.initializeApp(options)
30+
}
31+
32+
} catch (e: Exception) {
33+
e.printStackTrace()
34+
throw GeneralException(ErrorStatus.INITIAL_FIREBASE_INTERNAL_SERVER_ERROR)
35+
}
36+
}
37+
38+
}

src/main/kotlin/gat_be/dev/common/config/SecurityConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class SecurityConfig(
7575
@Bean
7676
fun corsConfigurationSource(): CorsConfigurationSource {
7777
val config = CorsConfiguration().apply {
78-
allowedOrigins = listOf("http://localhost:8000", "http://localhost:3000")
78+
allowedOrigins = listOf("https://get-a-team.site", "http://localhost:8000", "http://localhost:3000")
7979
allowedMethods = listOf("GET", "POST", "PATCH", "DELETE")
8080
allowedHeaders = listOf("Authorization", "Content-Type")
8181
exposedHeaders = listOf("Authorization")

src/main/kotlin/gat_be/dev/common/log/discord/DiscordAlarmSender.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ class DiscordAlarmSender(
3737
)
3838
}
3939

40+
41+
42+
4043
}

src/main/kotlin/gat_be/dev/common/status/ErrorStatus.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum class ErrorStatus(
2222
/**
2323
* User
2424
*/
25+
USER_SCRAPPED_TEAM_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_404", "존재하지 않는 유저 스크랩 내역입니다."),
2526

2627

2728
/**
@@ -90,4 +91,14 @@ enum class ErrorStatus(
9091
CANNOT_CREATE_REVIEW_WHEN_TEAM_IS_NOT_DONE(HttpStatus.CONFLICT, "REVIEW_409", "팀 활동이 종료되기 전에는 리뷰를 작성할 수 없습니다"),
9192
INVALID_REVIEW_LIST_SORT_PARAM(HttpStatus.BAD_REQUEST, "REVIEW_400", "리뷰 리스트 조회를 위한 정렬 조건이 잘못 되었습니다."),
9293
REVIEW_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW_404", "해당 리뷰 정보를 찾을 수 없습니다")
94+
95+
/**
96+
* Notification
97+
*/
98+
NOTIFICATION_FORBIDDEN(HttpStatus.FORBIDDEN, "NOTIFICATION_403", "알림에 대한 접근 권한이 없습니다."),
99+
NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTIFICATION_404", "존재하지 않는 알림입니다."),
100+
INITIAL_FIREBASE_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "NOTIFICATION_500", "Firebase 인증 초기화 중 오류가 발생했습니다."),
101+
SEND_FCM_NOTIFICATION_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "NOTIFICATION_500", "FCM 알림 전송 중 오류가 발생했습니다.")
102+
103+
93104
}

src/main/kotlin/gat_be/dev/common/status/SuccessStatus.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ enum class SuccessStatus(
2020
GET_USER_MY_PAGE_SUCCESS(HttpStatus.OK,"USER_200","유저 마이 페이지 조회 성공"),
2121
GET_USER_PROFILE_SUCCESS(HttpStatus.OK, "USER_200", "유저 프로필 조회 성공"),
2222
UPDATE_USER_PROFILE_SUCCESS(HttpStatus.OK, "USER_200", "유저 프로필 수정 성공"),
23+
GET_USER_SCRAP_LIST_SUCCESS(HttpStatus.OK,"USER_200","스크랩 내역 조회 성공"),
2324
CREATE_USER_SCRAP_SUCCESS(HttpStatus.OK, "USER_200", "스크랩 기능 성공"),
25+
CANCEL_USER_SCRAP_SUCCESS(HttpStatus.OK, "USER_200", "스크랩 취소 성공"),
26+
GET_USER_VIEWED_TEAM_LIST_SUCCESS(HttpStatus.OK, "USER_200", "최근 본 글 조회 성공"),
2427

2528
/**
2629
* Team
@@ -30,6 +33,7 @@ enum class SuccessStatus(
3033
GET_TEAM_INFO_SUCCESS(HttpStatus.OK, "TEAM_200", "팀 상세정보 조회 성공"),
3134
GET_TEAM_LIST_SUCCESS(HttpStatus.OK, "TEAM_200", "모집 중인 팀 리스트 조회 성공"),
3235
GET_MY_TEAM_LIST_SUCCESS(HttpStatus.OK, "TEAM_200", "나의 팀 리스트 조회 성공"),
36+
GET_TEAM_LIST_FOR_SEARCH_SUCCESS(HttpStatus.OK, "TEAM_200", "팀 리스트 검색 성공"),
3337

3438
/**
3539
* Application
@@ -55,6 +59,12 @@ enum class SuccessStatus(
5559
CREATE_TOKEN_SUCCESS(HttpStatus.OK, "AUTH_200", "토큰 재발급 성공"),
5660
CREATE_USER_SUCCESS(HttpStatus.CREATED, "AUTH_201", "회원가입 성공"),
5761

62+
/**
63+
* Notification
64+
*/
65+
MARK_NOTIFICATION_AS_READ_SUCCESS(HttpStatus.OK, "NOTIFICATION_200", "알림 읽음 표시 성공"),
66+
GET_NOTIFICATION_LIST_SUCCESS(HttpStatus.OK, "NOTIFICATION_200", "알림 리스트 조회 성공"),
67+
5868
/**
5969
* Review
6070
*/

src/main/kotlin/gat_be/dev/domain/application/facade/ApplicationApplyFacade.kt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,46 @@
11
package gat_be.dev.domain.application.facade
22

3+
import gat_be.dev.common.exception.GeneralException
34
import gat_be.dev.domain.application.dto.request.CreateApplicationRequest
45
import gat_be.dev.domain.application.dto.response.CreateApplicationResponse
56
import gat_be.dev.domain.application.service.ApplicationService
7+
import gat_be.dev.domain.notification.service.NotificationService
68
import gat_be.dev.domain.team.service.TeamService
9+
import gat_be.dev.domain.user.service.UserService
710
import jakarta.transaction.Transactional
11+
import org.slf4j.LoggerFactory
812
import org.springframework.stereotype.Service
913

1014
@Service
1115
class ApplicationApplyFacade(
1216
private val applicationService: ApplicationService,
13-
private val teamService: TeamService
17+
private val teamService: TeamService,
18+
private val userService: UserService,
19+
private val notificationService: NotificationService
1420
) {
1521

22+
private val log = LoggerFactory.getLogger(this::class.java)
23+
1624
@Transactional
1725
fun createApplication(userId: Long, request: CreateApplicationRequest): CreateApplicationResponse {
1826
applicationService.validateIsDuplicatedApplication(userId, request.teamId)
19-
teamService.validateTeamIsRecruitingForStack(request.teamId, request.techStack)
2027

28+
val team = teamService.validateTeamIsRecruitingForStack(request.teamId, request.techStack)
2129
val application = applicationService.createAndSaveApplication(userId, request)
2230

23-
// TODO: [Notification] 팀 리더에게 새로운 지원 생성 알림 전송
31+
team.leader?.let { leader ->
32+
try {
33+
val receiver = userService.findUserByUserId(leader.userId)
34+
35+
notificationService.registerNewTeamApplicationNotification(
36+
receiver,
37+
team.title,
38+
application.applicationId
39+
)
40+
} catch (e: GeneralException) {
41+
log.warn("[*] 리더 유저를 찾을 수 없어 알림 전송 생략: ${leader.userId}")
42+
}
43+
}
2444

2545
return CreateApplicationResponse(application.applicationId)
2646
}

src/main/kotlin/gat_be/dev/domain/application/facade/ApplicationManageFacade.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package gat_be.dev.domain.application.facade
22

33
import gat_be.dev.domain.application.service.ApplicationService
4+
import gat_be.dev.domain.notification.service.NotificationService
45
import gat_be.dev.domain.team.service.TeamService
6+
import gat_be.dev.domain.user.service.UserService
57
import jakarta.transaction.Transactional
68
import org.springframework.stereotype.Service
79

810
@Service
911
class ApplicationManageFacade(
1012
private val applicationService: ApplicationService,
11-
private val teamService: TeamService
13+
private val teamService: TeamService,
14+
private val notificationService: NotificationService,
15+
private val userService: UserService
1216
) {
1317

1418
// 팀 지원 수락
@@ -18,9 +22,14 @@ class ApplicationManageFacade(
1822
teamService.validateLeaderAndCanProcessApplication(userId, application.teamId)
1923
application.accept()
2024

21-
teamService.acceptNewTeamMember(application.userId, application.teamId, application.role)
25+
val team = teamService.acceptNewTeamMember(application.userId, application.teamId, application.role)
26+
val receiver = userService.findUserByUserId(application.userId)
2227

23-
// TODO: [Notification] 지원 수락 알림 발송
28+
notificationService.registerTeamAcceptanceNotification(
29+
receiver,
30+
team.title,
31+
application.applicationId
32+
)
2433
}
2534

2635
// 팀 지원 거절

0 commit comments

Comments
 (0)