Skip to content

Commit 5cc64da

Browse files
unanchoiyungu0010
andauthored
deploy: v1.0.2 배포 (#173)
* [fix #142] 앨범 내 사진 조회 최신순으로 정렬 (#143) * [fix #140] 앨범 공유 수락 API 로직 수정 (#144) * [feat #128] 포토부스 관련 API 구현 (#146) * [feat #128] 포토부스 관련 API 구현 * [fix #128] Photo 공유 수락 API 로직 수정 * [chore #128] swagger 업데이트 * [chore #128] 공백 제거 * [fix #147] 포포리즘 공유 API 수정 (#148) * [feat #128] 포토부스 관련 API 구현 * [fix #128] Photo 공유 수락 API 로직 수정 * [chore #128] swagger 업데이트 * [chore #128] 공백 제거 * [fix #147] 포포리즘 공유 API 수정 * [chore #147] swagger 수정 * [hotfix #149] 포포리즘 공유 API request body 수정 (#150) * [hotfix #149] 포포리즘 공유 request body 수정 * [chore #149] 사용하지 않는 import 제거 * [setting #149] banner 추가 * [chore #149] CI 스크립트 수정 * [chore #149] CI prod 스크립트 수정 * [chore #149] cd 스크립트 수정 * [fix #151] 배포 전 버그 수정 (access token 만료 시간 변경, 포포리즘 공유 API 수정) (#152) * [fix #151] Access Token 만료시간 변경 * [fix #151] 사진 upload url 변경 * [fix #151] 포포리즘 공유시에 이미지 저장 url 변경 (#153) * [fix #151] Access Token 만료시간 변경 * [fix #151] 사진 upload url 변경 * [hotfix #151] 포포리즘 저장 url 변경 * [refactor #156] slack 회원가입시에 알람 추가 (#157) * [refactor #156] slack 회원가입시에 알람 추가 * [fix #156] IOException 처리 * [fix #158] slack 메세지 알림 수정 (#159) * [fix #158] 어노테이션 변경 (#160) * [fix #158] slack 메세지 알림 수정 * [fix #158] annotation 변경 * [test #163] add domain test code (#167) * [feat #169] 토큰 재발급, 회원 탈퇴 API V2 구현 (#170) * [feat #169] 토큰 재발급, 회원 탈퇴 API V2 구현 * [feat #169] 애플리케이션 실행 스크립트 추가 * [refactor #165] slack 알림 기능 고도화 (#171) --------- Co-authored-by: Yunseo Kang <[email protected]>
1 parent d6d8685 commit 5cc64da

File tree

18 files changed

+347
-26
lines changed

18 files changed

+347
-26
lines changed

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ plugins {
99
id 'org.springframework.boot' version '2.7.12'
1010
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
1111
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
12+
id("application")
1213
}
1314

1415
group = 'com.pophory'
@@ -47,10 +48,15 @@ dependencies {
4748
// Lombok
4849
compileOnly 'org.projectlombok:lombok'
4950
annotationProcessor 'org.projectlombok:lombok'
51+
testAnnotationProcessor 'org.projectlombok:lombok'
52+
testCompileOnly 'org.projectlombok:lombok'
5053

5154
// sentry
5255
implementation 'io.sentry:sentry-spring-boot-starter:6.23.0'
5356

57+
// slack
58+
implementation("com.slack.api:slack-api-client:1.31.0")
59+
5460
// Database
5561
runtimeOnly 'com.h2database:h2'
5662
runtimeOnly 'com.mysql:mysql-connector-j'

scripts/run.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
# Check if an argument is provided
4+
if [ -z "$1" ]; then
5+
echo "Usage: $0 <environment>"
6+
exit 1
7+
fi
8+
9+
# Set the environment variable
10+
ENV=$1
11+
12+
# Run the Gradle command
13+
./gradlew clean build -x test
14+
15+
# Check if the gradle build command succeeded
16+
if [ $? -ne 0 ]; then
17+
echo "Gradle build failed!"
18+
exit 2
19+
fi
20+
21+
# Change directory and run the Java command
22+
cd build/libs
23+
nohup java -Dspring.profiles.active=${ENV} -jar pophoryserver-0.0.1-SNAPSHOT.jar --server.port=8080 &
24+
25+
echo "Server started with profile: ${ENV}"
26+

src/main/java/com/pophory/pophoryserver/domain/album/Album.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import com.pophory.pophoryserver.domain.member.Member;
66
import com.pophory.pophoryserver.domain.photo.Photo;
77
import com.pophory.pophoryserver.global.entity.BaseTimeEntity;
8+
import lombok.Builder;
89
import lombok.Getter;
910
import lombok.NoArgsConstructor;
1011

1112
import javax.persistence.*;
13+
import javax.validation.constraints.Min;
1214
import java.time.LocalDateTime;
1315
import java.util.ArrayList;
1416
import java.util.List;
@@ -29,6 +31,7 @@ public class Album extends BaseTimeEntity {
2931
@OneToOne(fetch = LAZY)
3032
private AlbumDesign albumDesign;
3133

34+
@Min(value = 1, message = "사진제한은 1장 이상이어야 합니다.")
3235
private int photoLimit;
3336

3437
private String imageUrl;
@@ -48,6 +51,17 @@ public void softDelete() {
4851
this.deletedAt = LocalDateTime.now();
4952
}
5053

54+
@Builder
55+
public Album(String title, AlbumDesign albumDesign, int photoLimit, String imageUrl, Member member) {
56+
this.title = title;
57+
this.albumDesign = albumDesign;
58+
this.photoLimit = photoLimit;
59+
this.imageUrl = imageUrl;
60+
this.member = member;
61+
}
62+
63+
64+
5165
public void setAlbumDesign(AlbumDesign albumDesign) {
5266
this.albumDesign = albumDesign;
5367
}

src/main/java/com/pophory/pophoryserver/domain/auth/AuthService.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.pophory.pophoryserver.domain.auth.dto.response.TokenResponseDto;
55
import com.pophory.pophoryserver.domain.member.Member;
66
import com.pophory.pophoryserver.domain.member.MemberJpaRepository;
7+
import com.pophory.pophoryserver.domain.member.MemberQueryRepository;
78
import com.pophory.pophoryserver.global.config.jwt.UserAuthentication;
89
import lombok.RequiredArgsConstructor;
910
import org.springframework.stereotype.Service;
@@ -15,6 +16,7 @@
1516
public class AuthService {
1617

1718
private final MemberJpaRepository memberJpaRepository;
19+
private final MemberQueryRepository memberQueryRepository;
1820
private final SocialService socialService;
1921

2022
@Transactional
@@ -24,14 +26,9 @@ public void signOut(Long memberId) {
2426

2527
@Transactional
2628
public TokenResponseDto reIssue(Long memberId) {
27-
Member member = getMemberById(memberId);
29+
Member member = memberQueryRepository.findMemberById(memberId);
2830
TokenVO tokenVO = socialService.generateToken(new UserAuthentication(member.getId(), null, null));
2931
member.updateRefreshToken(tokenVO.getRefreshToken());
3032
return TokenResponseDto.of(tokenVO.getAccessToken(), tokenVO.getRefreshToken());
3133
}
32-
33-
private Member getMemberById(Long memberId) {
34-
return memberJpaRepository.findById(memberId).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다. memberId: " + memberId));
35-
}
36-
3734
}

src/main/java/com/pophory/pophoryserver/domain/auth/controller/AuthV2Controller.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
import com.pophory.pophoryserver.domain.auth.SocialService;
55
import com.pophory.pophoryserver.domain.auth.dto.request.AuthRequestDto;
66
import com.pophory.pophoryserver.domain.auth.dto.response.AuthResponseDto;
7+
import com.pophory.pophoryserver.domain.auth.dto.response.TokenResponseDto;
78
import com.pophory.pophoryserver.global.config.jwt.JwtTokenProvider;
89
import com.pophory.pophoryserver.global.config.jwt.UserAuthentication;
10+
import com.pophory.pophoryserver.global.util.MemberUtil;
911
import io.swagger.v3.oas.annotations.Operation;
12+
import io.swagger.v3.oas.annotations.Parameter;
13+
import io.swagger.v3.oas.annotations.enums.ParameterIn;
1014
import io.swagger.v3.oas.annotations.media.Content;
15+
import io.swagger.v3.oas.annotations.media.Schema;
1116
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1217
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1318
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -30,10 +35,8 @@ public class AuthV2Controller {
3035

3136
private final SocialService socialService;
3237
private final AuthService authService;
33-
private final JwtTokenProvider jwtTokenProvider;
3438

3539
@PostMapping
36-
@SecurityRequirement(name = "Authorization")
3740
@Operation(summary = "소셜로그인 API")
3841
@ApiResponses(value = {
3942
@ApiResponse(responseCode = "201", description = "소셜로그인 성공"),
@@ -43,4 +46,32 @@ public class AuthV2Controller {
4346
public ResponseEntity<AuthResponseDto> socialLogin(@RequestHeader("Authorization") String socialAccessToken, @RequestBody AuthRequestDto request) throws NoSuchAlgorithmException, InvalidKeySpecException {
4447
return ResponseEntity.ok(socialService.signIn(socialAccessToken, request));
4548
}
49+
50+
@PostMapping("/token")
51+
@SecurityRequirement(name = "Authorization")
52+
@Operation(summary = "토큰 재발급 API")
53+
@Parameter(name = "Authorization", description = "Bearer {access_token}", in = ParameterIn.HEADER, schema = @Schema(type = "string"))
54+
@ApiResponses(value = {
55+
@ApiResponse(responseCode = "200", description = "토큰 재발급 성공"),
56+
@ApiResponse(responseCode = "400", description = "토큰 재발급 실패", content = @Content),
57+
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
58+
})
59+
public ResponseEntity<TokenResponseDto> reissue(Principal principal) {
60+
return ResponseEntity.ok(authService.reIssue(MemberUtil.getMemberId(principal)));
61+
}
62+
63+
64+
@DeleteMapping(produces = "application/json")
65+
@SecurityRequirement(name = "Authorization")
66+
@Operation(summary = "회원탈퇴 API")
67+
@Parameter(name = "Authorization", description = "Bearer {access_token}", in = ParameterIn.HEADER, required = true, schema = @Schema(type = "string"))
68+
@ApiResponses(value = {
69+
@ApiResponse(responseCode = "204", description = "회원탈퇴 성공"),
70+
@ApiResponse(responseCode = "400", description = "회원탈퇴 실패", content = @Content),
71+
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
72+
})
73+
public ResponseEntity<Void> signOut(Principal principal) {
74+
authService.signOut(MemberUtil.getMemberId(principal));
75+
return ResponseEntity.noContent().build();
76+
}
4677
}

src/main/java/com/pophory/pophoryserver/domain/member/Member.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import lombok.NoArgsConstructor;
1111

1212
import javax.persistence.*;
13+
import javax.validation.constraints.NotNull;
1314
import java.time.LocalDateTime;
1415
import java.util.ArrayList;
1516
import java.util.List;
@@ -22,20 +23,23 @@
2223
@NoArgsConstructor
2324
public class Member extends BaseTimeEntity {
2425

26+
private static final int MEMBER_DELETE_EXPIRE_TIME = 7;
27+
2528
@Id @GeneratedValue
2629
private Long id;
2730

2831
@Column(length = 6)
2932
private String realName;
3033

31-
@Column(length = 15)
34+
@Column(length = 15, unique = true)
3235
private String nickname;
3336

3437
private String profileImage;
3538

3639
@Enumerated(value = STRING)
3740
private SocialType socialType;
3841

42+
@NotNull(message = "소셜 아이디는 필수입니다.")
3943
private String socialId;
4044

4145
private String refreshToken;

src/main/java/com/pophory/pophoryserver/domain/member/MemberJpaRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ public interface MemberJpaRepository extends JpaRepository<Member, Long> {
1313
Optional<Member> getMemberBySocialIdAndSocialType(String socialId, SocialType socialType);
1414

1515
Optional<Member> findByNickname(String nickname);
16+
17+
Optional<Member> findBySocialId(String socialId);
1618
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.pophory.pophoryserver.domain.member;
2+
3+
4+
import com.querydsl.jpa.impl.JPAQueryFactory;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Repository;
7+
8+
import static com.pophory.pophoryserver.domain.member.QMember.*;
9+
10+
@Repository
11+
@RequiredArgsConstructor
12+
public class MemberQueryRepository {
13+
14+
private final JPAQueryFactory queryFactory;
15+
16+
public Member findMemberById(Long id) {
17+
return queryFactory.select(member)
18+
.from(member)
19+
.where(member.id.eq(id))
20+
.fetchOne();
21+
}
22+
}

src/main/java/com/pophory/pophoryserver/domain/member/MemberService.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.pophory.pophoryserver.domain.slack.SlackService;
1818
import com.pophory.pophoryserver.global.util.RandomUtil;
1919
import lombok.RequiredArgsConstructor;
20+
import org.springframework.beans.factory.annotation.Value;
2021
import org.springframework.stereotype.Service;
2122
import org.springframework.transaction.annotation.Transactional;
2223

@@ -32,6 +33,9 @@
3233
@RequiredArgsConstructor
3334
public class MemberService {
3435

36+
@Value("${slack.channel.signin}")
37+
private String SLACK_CHANNEL_SIGNIN;
38+
3539
private final MemberJpaRepository memberJpaRepository;
3640
private final AlbumJpaRepository albumJpaRepository;
3741
private final AlbumDesignJpaRepository albumDesignJpaRepository;
@@ -40,18 +44,19 @@ public class MemberService {
4044
private final SlackService slackService;
4145

4246
private static final int INITIAL_PHOTO_LIMIT = 15;
47+
private static final String SLACK_MESSAGE = " \uD83C\uDF89 %s 님이 포포리의 회원가입을 완료했습니다. \uD83C\uDF89";
4348

4449
@Transactional
4550
public void update(MemberCreateRequestDto request, Long memberId) {
4651
checkNicknameDuplicate(request.getNickname());
47-
slackService.sendSignInAlert(request.getNickname());
52+
slackService.sendMessage(SLACK_CHANNEL_SIGNIN, String.format(SLACK_MESSAGE, request.getNickname()));
4853
updateMemberInfo(request, memberId);
4954
}
5055

5156
@Transactional
5257
public MemberCreateResponseDto updateV2(MemberCreateV2RequestDto request, Long memberId) {
5358
checkNicknameDuplicate(request.getNickname());
54-
slackService.sendSignInAlert(request.getNickname());
59+
slackService.sendMessage(SLACK_CHANNEL_SIGNIN, String.format(SLACK_MESSAGE, request.getNickname()));
5560
return MemberCreateResponseDto.of(updateMemberInfoV2(request, memberId));
5661
}
5762

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,48 @@
11
package com.pophory.pophoryserver.domain.slack;
22

33
import com.pophory.pophoryserver.domain.slack.dto.SlackMessageDto;
4+
import com.slack.api.methods.MethodsClient;
5+
import com.slack.api.methods.SlackApiException;
6+
import com.slack.api.methods.request.chat.ChatPostMessageRequest;
7+
import com.slack.api.methods.response.chat.ChatPostMessageResponse;
8+
import lombok.RequiredArgsConstructor;
49
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.core.env.Environment;
511
import org.springframework.http.HttpEntity;
612
import org.springframework.http.HttpHeaders;
713
import org.springframework.stereotype.Service;
814
import org.springframework.web.client.RestTemplate;
15+
import com.slack.api.Slack;
16+
17+
18+
import java.io.IOException;
19+
import java.util.Arrays;
920

1021

1122
@Service
23+
@RequiredArgsConstructor
1224
public class SlackService {
1325

14-
@Value("${slack.webhook.url}")
15-
private String SLACK_WEBHOOK_URL;
26+
@Value("${slack.bot.token}")
27+
private String SLACK_TOKEN;
1628

17-
public void sendSignInAlert(String nickname){
18-
RestTemplate restTemplate = new RestTemplate();
19-
restTemplate.postForEntity(
20-
SLACK_WEBHOOK_URL,
21-
createSlackHttpRequest("🎉 " + nickname + "님이 포포리의 회원가입을 완료했습니다. 🎉"),
22-
String.class);
23-
}
29+
private final Environment env;
2430

25-
private HttpEntity<SlackMessageDto> createSlackHttpRequest(String text) {
26-
HttpHeaders headers = new HttpHeaders();
27-
headers.add("Accept", "application/json; UTF-8");
28-
return new HttpEntity<>(SlackMessageDto.of(text), headers);
31+
32+
public void sendMessage(String channel, String text) {
33+
try {
34+
Slack slack = Slack.getInstance();
35+
ChatPostMessageResponse response = slack.methods(SLACK_TOKEN).chatPostMessage(req -> req
36+
.channel(channel)
37+
.text("["+getProfiles()+"]"+ text));
38+
System.out.println(response);
39+
} catch (IOException | SlackApiException e) {
40+
throw new RuntimeException(e);
41+
}
42+
}
43+
private String getProfiles() {
44+
return Arrays.stream(env.getActiveProfiles())
45+
.findFirst()
46+
.orElse("");
2947
}
3048
}

0 commit comments

Comments
 (0)