Skip to content

Commit

Permalink
deploy: v1.0.2 배포 (#173)
Browse files Browse the repository at this point in the history
* [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]>
  • Loading branch information
unanchoi and yungu0010 authored Sep 12, 2023
1 parent d6d8685 commit 5cc64da
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 26 deletions.
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
id 'org.springframework.boot' version '2.7.12'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
id("application")
}

group = 'com.pophory'
Expand Down Expand Up @@ -47,10 +48,15 @@ dependencies {
// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'

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

// slack
implementation("com.slack.api:slack-api-client:1.31.0")

// Database
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
Expand Down
26 changes: 26 additions & 0 deletions scripts/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

# Check if an argument is provided
if [ -z "$1" ]; then
echo "Usage: $0 <environment>"
exit 1
fi

# Set the environment variable
ENV=$1

# Run the Gradle command
./gradlew clean build -x test

# Check if the gradle build command succeeded
if [ $? -ne 0 ]; then
echo "Gradle build failed!"
exit 2
fi

# Change directory and run the Java command
cd build/libs
nohup java -Dspring.profiles.active=${ENV} -jar pophoryserver-0.0.1-SNAPSHOT.jar --server.port=8080 &

echo "Server started with profile: ${ENV}"

14 changes: 14 additions & 0 deletions src/main/java/com/pophory/pophoryserver/domain/album/Album.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import com.pophory.pophoryserver.domain.member.Member;
import com.pophory.pophoryserver.domain.photo.Photo;
import com.pophory.pophoryserver.global.entity.BaseTimeEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.Min;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -29,6 +31,7 @@ public class Album extends BaseTimeEntity {
@OneToOne(fetch = LAZY)
private AlbumDesign albumDesign;

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

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

@Builder
public Album(String title, AlbumDesign albumDesign, int photoLimit, String imageUrl, Member member) {
this.title = title;
this.albumDesign = albumDesign;
this.photoLimit = photoLimit;
this.imageUrl = imageUrl;
this.member = member;
}



public void setAlbumDesign(AlbumDesign albumDesign) {
this.albumDesign = albumDesign;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.pophory.pophoryserver.domain.auth.dto.response.TokenResponseDto;
import com.pophory.pophoryserver.domain.member.Member;
import com.pophory.pophoryserver.domain.member.MemberJpaRepository;
import com.pophory.pophoryserver.domain.member.MemberQueryRepository;
import com.pophory.pophoryserver.global.config.jwt.UserAuthentication;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -15,6 +16,7 @@
public class AuthService {

private final MemberJpaRepository memberJpaRepository;
private final MemberQueryRepository memberQueryRepository;
private final SocialService socialService;

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

@Transactional
public TokenResponseDto reIssue(Long memberId) {
Member member = getMemberById(memberId);
Member member = memberQueryRepository.findMemberById(memberId);
TokenVO tokenVO = socialService.generateToken(new UserAuthentication(member.getId(), null, null));
member.updateRefreshToken(tokenVO.getRefreshToken());
return TokenResponseDto.of(tokenVO.getAccessToken(), tokenVO.getRefreshToken());
}

private Member getMemberById(Long memberId) {
return memberJpaRepository.findById(memberId).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다. memberId: " + memberId));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
import com.pophory.pophoryserver.domain.auth.SocialService;
import com.pophory.pophoryserver.domain.auth.dto.request.AuthRequestDto;
import com.pophory.pophoryserver.domain.auth.dto.response.AuthResponseDto;
import com.pophory.pophoryserver.domain.auth.dto.response.TokenResponseDto;
import com.pophory.pophoryserver.global.config.jwt.JwtTokenProvider;
import com.pophory.pophoryserver.global.config.jwt.UserAuthentication;
import com.pophory.pophoryserver.global.util.MemberUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
Expand All @@ -30,10 +35,8 @@ public class AuthV2Controller {

private final SocialService socialService;
private final AuthService authService;
private final JwtTokenProvider jwtTokenProvider;

@PostMapping
@SecurityRequirement(name = "Authorization")
@Operation(summary = "소셜로그인 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "소셜로그인 성공"),
Expand All @@ -43,4 +46,32 @@ public class AuthV2Controller {
public ResponseEntity<AuthResponseDto> socialLogin(@RequestHeader("Authorization") String socialAccessToken, @RequestBody AuthRequestDto request) throws NoSuchAlgorithmException, InvalidKeySpecException {
return ResponseEntity.ok(socialService.signIn(socialAccessToken, request));
}

@PostMapping("/token")
@SecurityRequirement(name = "Authorization")
@Operation(summary = "토큰 재발급 API")
@Parameter(name = "Authorization", description = "Bearer {access_token}", in = ParameterIn.HEADER, schema = @Schema(type = "string"))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "토큰 재발급 성공"),
@ApiResponse(responseCode = "400", description = "토큰 재발급 실패", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ResponseEntity<TokenResponseDto> reissue(Principal principal) {
return ResponseEntity.ok(authService.reIssue(MemberUtil.getMemberId(principal)));
}


@DeleteMapping(produces = "application/json")
@SecurityRequirement(name = "Authorization")
@Operation(summary = "회원탈퇴 API")
@Parameter(name = "Authorization", description = "Bearer {access_token}", in = ParameterIn.HEADER, required = true, schema = @Schema(type = "string"))
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "회원탈퇴 성공"),
@ApiResponse(responseCode = "400", description = "회원탈퇴 실패", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ResponseEntity<Void> signOut(Principal principal) {
authService.signOut(MemberUtil.getMemberId(principal));
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -22,20 +23,23 @@
@NoArgsConstructor
public class Member extends BaseTimeEntity {

private static final int MEMBER_DELETE_EXPIRE_TIME = 7;

@Id @GeneratedValue
private Long id;

@Column(length = 6)
private String realName;

@Column(length = 15)
@Column(length = 15, unique = true)
private String nickname;

private String profileImage;

@Enumerated(value = STRING)
private SocialType socialType;

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

private String refreshToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface MemberJpaRepository extends JpaRepository<Member, Long> {
Optional<Member> getMemberBySocialIdAndSocialType(String socialId, SocialType socialType);

Optional<Member> findByNickname(String nickname);

Optional<Member> findBySocialId(String socialId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pophory.pophoryserver.domain.member;


import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import static com.pophory.pophoryserver.domain.member.QMember.*;

@Repository
@RequiredArgsConstructor
public class MemberQueryRepository {

private final JPAQueryFactory queryFactory;

public Member findMemberById(Long id) {
return queryFactory.select(member)
.from(member)
.where(member.id.eq(id))
.fetchOne();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.pophory.pophoryserver.domain.slack.SlackService;
import com.pophory.pophoryserver.global.util.RandomUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -32,6 +33,9 @@
@RequiredArgsConstructor
public class MemberService {

@Value("${slack.channel.signin}")
private String SLACK_CHANNEL_SIGNIN;

private final MemberJpaRepository memberJpaRepository;
private final AlbumJpaRepository albumJpaRepository;
private final AlbumDesignJpaRepository albumDesignJpaRepository;
Expand All @@ -40,18 +44,19 @@ public class MemberService {
private final SlackService slackService;

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

@Transactional
public void update(MemberCreateRequestDto request, Long memberId) {
checkNicknameDuplicate(request.getNickname());
slackService.sendSignInAlert(request.getNickname());
slackService.sendMessage(SLACK_CHANNEL_SIGNIN, String.format(SLACK_MESSAGE, request.getNickname()));
updateMemberInfo(request, memberId);
}

@Transactional
public MemberCreateResponseDto updateV2(MemberCreateV2RequestDto request, Long memberId) {
checkNicknameDuplicate(request.getNickname());
slackService.sendSignInAlert(request.getNickname());
slackService.sendMessage(SLACK_CHANNEL_SIGNIN, String.format(SLACK_MESSAGE, request.getNickname()));
return MemberCreateResponseDto.of(updateMemberInfoV2(request, memberId));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
package com.pophory.pophoryserver.domain.slack;

import com.pophory.pophoryserver.domain.slack.dto.SlackMessageDto;
import com.slack.api.methods.MethodsClient;
import com.slack.api.methods.SlackApiException;
import com.slack.api.methods.request.chat.ChatPostMessageRequest;
import com.slack.api.methods.response.chat.ChatPostMessageResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.slack.api.Slack;


import java.io.IOException;
import java.util.Arrays;


@Service
@RequiredArgsConstructor
public class SlackService {

@Value("${slack.webhook.url}")
private String SLACK_WEBHOOK_URL;
@Value("${slack.bot.token}")
private String SLACK_TOKEN;

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

private HttpEntity<SlackMessageDto> createSlackHttpRequest(String text) {
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", "application/json; UTF-8");
return new HttpEntity<>(SlackMessageDto.of(text), headers);

public void sendMessage(String channel, String text) {
try {
Slack slack = Slack.getInstance();
ChatPostMessageResponse response = slack.methods(SLACK_TOKEN).chatPostMessage(req -> req
.channel(channel)
.text("["+getProfiles()+"]"+ text));
System.out.println(response);
} catch (IOException | SlackApiException e) {
throw new RuntimeException(e);
}
}
private String getProfiles() {
return Arrays.stream(env.getActiveProfiles())
.findFirst()
.orElse("");
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.pophory.pophoryserver.domain.studio;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
@Getter
Expand All @@ -16,8 +18,15 @@ public class Studio {
@Id @GeneratedValue
private Long id;

@Column(unique = true, nullable = false)
@NotNull
@Column(unique = true)
private String name;

private String imageUrl;

@Builder
public Studio(String name, String imageUrl) {
this.name = name;
this.imageUrl = imageUrl;
}
}
Loading

0 comments on commit 5cc64da

Please sign in to comment.