Skip to content

Commit

Permalink
release: deploy to prod (#83)
Browse files Browse the repository at this point in the history
* fix: 누적 잔액이 정상 반영되도록 한다. (#75)

* refactor: LedgerService 메소드 분리

* refactor: move updateTotalBalance method to Entity

* refactor: change calculator return type to int

* refactor: 누적 잔고가 정상 반영되도록 한다.

* feat: kakao 로그인 예외 처리를 세분화한다. (#76)

* feat: 장부 내역 조회 api v2를 추가한다. (#77)

* feat: 내정보 조회 api에 provider field를 추가한다.

* feat: 특정 기간의 장부를 반환하는 메소드를 추가한다.

* feat: LedgerReader의 공통 코드를 메소드 분리한다.

* feat: LedgerControllerV2, RequestV2를 추가한다.

* config: swagger scan 패키지를 수정한다. (#79)

* feat: swagger scan 패키지를 수정한다.

* feat: 누락된 Tag, Operation을 추가한다.

* feat: Apple OAuth Login을 추가한다. (#80)

* chore: remove unused util class

* feat: OAuthProvider에 Apple을 추가한다.

* feat: bouncy castle, JWT decode 라이브러리를 추가한다.

* feat: yml에 apple 환경 변수를 추가한다.

* feat: apple login service를 구현한다.

* refactor: Apple login 시 name을 http body로 받는다.

* feat: OAuth 계정을 revoke하는 메소드를 추가한다.

* feat: 최초 로그인 시 authorizationCode로 refreshToken을 취득한다.

* feat: AppleUser 정보를 저장하는 Entity를 추가한다.

* feat: 회원가입 시 Apple User인 경우 AppleUser를 저장한다.

* feat: 소속 조회 결과에 소속 생성일자를 포함한다. (#82)

* feat: 내 소속 조회 결과에 소속의 생성일자도 포함한다.

* chore: remove unused fields

* chore: userToken 필드를 삭제한다.
  • Loading branch information
rlarltj authored May 14, 2024
1 parent 301050c commit 2a8641f
Show file tree
Hide file tree
Showing 38 changed files with 351 additions and 77 deletions.
4 changes: 4 additions & 0 deletions .docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ services:
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
APPLE_PRIVATE_KEY: ${APPLE_PRIVATE_KEY}
APPLE_TEAM_ID: ${APPLE_TEAM_ID}
APPLE_KEY_ID: ${APPLE_KEY_ID}
APPLE_CLIENT_ID: ${APPLE_CLIENT_ID}

redis:
container_name: moneymong-redis
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
implementation 'org.bouncycastle:bcprov-jdk18on:1.75'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.75'
implementation "com.auth0:java-jwt:4.4.0"

// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@
@AllArgsConstructor
public class CreateAgencyRequest {
private String name;
private String description;
private AgencyType agencyType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import lombok.Builder;
import lombok.Getter;

import java.time.ZonedDateTime;

@Getter
@Builder
@AllArgsConstructor
Expand All @@ -14,13 +16,15 @@ public class AgencyResponse {
private String name;
private int headCount;
private AgencyType type;
private ZonedDateTime createdAt;

public static AgencyResponse from(Agency agency) {
return AgencyResponse.builder()
.id(agency.getId())
.name(agency.getAgencyName())
.headCount(agency.getHeadCount())
.type(agency.getAgencyType())
.createdAt(agency.getCreatedAt())
.build();
}
}
8 changes: 2 additions & 6 deletions src/main/java/com/moneymong/domain/agency/entity/Agency.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,22 @@ public class Agency extends BaseEntity {
)
private Integer headCount;

private String description;

@Column(name = "university_name")
private String universityName;

@Builder
private Agency(Long id, String agencyName, AgencyType agencyType, Integer headCount, String description, String universityName) {
private Agency(Long id, String agencyName, AgencyType agencyType, Integer headCount, String universityName) {
this.id = id;
this.agencyName = agencyName;
this.agencyType = agencyType;
this.headCount = headCount;
this.description = description;
this.universityName = universityName;
}

public static Agency of(String agencyName, AgencyType agencyType, String description, int headCount, String universityName) {
public static Agency of(String agencyName, AgencyType agencyType, int headCount, String universityName) {
return Agency.builder()
.agencyName(agencyName)
.agencyType(agencyType)
.description(description)
.headCount(headCount)
.universityName(universityName)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@

public enum AgencyType {
STUDENT_COUNCIL,
IN_SCHOOL_CLUB,
OUT_OF_SCHOOL_CLUB
IN_SCHOOL_CLUB
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AgencyService {

private static final int INITIAL_HEAD_COUNT = 1;
Expand Down Expand Up @@ -65,7 +66,6 @@ public CreateAgencyResponse create(Long userId, CreateAgencyRequest request) {
Agency agency = Agency.of(
request.getName(),
request.getAgencyType(),
request.getDescription(),
INITIAL_HEAD_COUNT,
universityName
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import com.moneymong.domain.invitationcode.service.InvitationCodeService;
import com.moneymong.global.security.token.dto.jwt.JwtAuthentication;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@Tag(name = "4. [초대코드]")
@RequestMapping("/api/v1/agencies/{agencyId}/invitation-code")
@RequiredArgsConstructor
@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ public class LoginRequest {
@NotBlank
private String provider;

@NotBlank
private String accessToken;

private String name;

private String code;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.moneymong.domain.user.api.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;

@Getter
public class UserDeleteRequest {
@NotBlank
private String provider;

@NotBlank
private String token;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
@AllArgsConstructor
public class UserProfileResponse {
private Long id;
private String userToken;
private String provider;
private String nickname;
private String email;
Expand All @@ -21,7 +20,6 @@ public class UserProfileResponse {
public static UserProfileResponse from(User user, UserUniversity userUniversity) {
return UserProfileResponse.builder()
.id(user.getId())
.userToken(user.getUserToken())
.provider(user.getProvider())
.nickname(user.getNickname())
.email(user.getEmail())
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/moneymong/domain/user/entity/AppleUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.moneymong.domain.user.entity;

import com.moneymong.global.domain.BaseEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

import static lombok.AccessLevel.PROTECTED;

@Table(name = "apple_users")
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = PROTECTED)
@Where(clause = "deleted = false")
@SQLDelete(sql = "UPDATE users SET deleted = true where id=?")
public class AppleUser extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long userId;

private String appleRefreshToken;

public static AppleUser of(Long userId, String appleRefreshToken) {
return AppleUser.builder()
.userId(userId)
.appleRefreshToken(appleRefreshToken)
.build();
}
}
10 changes: 1 addition & 9 deletions src/main/java/com/moneymong/domain/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ public class User extends BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(
name = "user_token",
unique = true,
nullable = false
)
private String userToken;

@Column(nullable = false)
private String email;

Expand All @@ -56,9 +49,8 @@ public class User extends BaseEntity {

private LocalDate birthDay;

public static User of(String userToken, String email, String nickname, String provider, String oauthId) {
public static User of(String email, String nickname, String provider, String oauthId) {
return User.builder()
.userToken(userToken)
.email(email)
.nickname(nickname)
.provider(provider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;

import static com.moneymong.utils.TextValidator.checkText;
import static lombok.AccessLevel.PROTECTED;

@Table(name = "user_universities")
Expand Down Expand Up @@ -45,14 +45,14 @@ public class UserUniversity extends TimeBaseEntity {
private int grade;

public void update(String universityName, int grade) {
checkText(universityName, "대학 이름은 필수 입력값입니다.");
Assert.hasText(universityName, "대학 이름은 필수 입력값입니다.");

this.universityName = universityName;
this.grade = grade;
}

public static UserUniversity of(Long userId, String universityName, int grade) {
checkText(universityName, "대학 이름은 필수 입력값입니다.");
Assert.hasText(universityName, "대학 이름은 필수 입력값입니다.");

return UserUniversity.builder()
.userId(userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.moneymong.domain.user.repository;

import com.moneymong.domain.user.entity.AppleUser;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AppleUserRepository extends JpaRepository<AppleUser, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@
import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
Optional<User> findByUserToken(String userToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.moneymong.domain.agency.service.AgencyUserService;
import com.moneymong.domain.user.api.request.LoginRequest;
import com.moneymong.domain.user.api.request.UserDeleteRequest;
import com.moneymong.global.security.oauth.dto.AuthUserInfo;
import com.moneymong.domain.user.api.response.LoginSuccessResponse;
import com.moneymong.global.security.oauth.dto.OAuthUserDataResponse;
Expand Down Expand Up @@ -43,4 +44,10 @@ public void delete(Long userId) {
userUniversityService.delete(userId);
agencyUserService.deleteAll(userId);
}

@Transactional
public void revoke(UserDeleteRequest deleteRequest, Long userId) {
oAuthService.revoke(deleteRequest);
delete(userId);
}
}
35 changes: 27 additions & 8 deletions src/main/java/com/moneymong/domain/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.moneymong.domain.user.service;

import com.moneymong.domain.user.api.response.UserProfileResponse;
import com.moneymong.domain.user.entity.AppleUser;
import com.moneymong.domain.user.entity.User;
import com.moneymong.domain.user.entity.UserUniversity;
import com.moneymong.domain.user.repository.AppleUserRepository;
import com.moneymong.domain.user.repository.UserRepository;
import com.moneymong.domain.user.repository.UserUniversityRepository;
import com.moneymong.global.exception.custom.NotFoundException;
Expand All @@ -25,19 +27,13 @@ public class UserService {
private final UserRepository userRepository;
private final UserUniversityRepository userUniversityRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final AppleUserRepository appleUserRepository;

@Transactional
public AuthUserInfo getOrRegister(OAuthUserInfo oauthUserInfo) {
User user = userRepository
.findByUserIdByProviderAndOauthId(oauthUserInfo.getProvider(), oauthUserInfo.getOauthId())
.orElseGet(() -> save(
User.of(UUID.randomUUID().toString(),
oauthUserInfo.getEmail(),
oauthUserInfo.getNickname(),
oauthUserInfo.getProvider(),
oauthUserInfo.getOauthId()
)
));
.orElseGet(() -> registerUser(oauthUserInfo));

return AuthUserInfo.from(user.getId(), user.getNickname(), DEFAULT_ROLE);
}
Expand All @@ -47,6 +43,29 @@ public User save(User unsavedUser) {
return userRepository.save(unsavedUser);
}

@Transactional
public User registerUser(OAuthUserInfo oauthUserInfo) {
User newUser = User.of(
oauthUserInfo.getEmail(),
oauthUserInfo.getNickname(),
oauthUserInfo.getProvider(),
oauthUserInfo.getOauthId()
);
newUser = save(newUser);

if (oauthUserInfo.getAppleRefreshToken() != null) {
appleUserRepository.save(
AppleUser.of(
newUser.getId(),
oauthUserInfo.getAppleRefreshToken()
)
);
}

return newUser;
}


@Transactional(readOnly = true)
public UserProfileResponse getUserProfile(Long userId) {
User user = userRepository.findById(userId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.springframework.context.annotation.Profile;

@Configuration
@Profile({"local", "dev", "prod"})
@Profile({"dev", "prod"})
public class OpenApiConfig {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.moneymong.global.image.dto.ImageDeleteRequest;
import com.moneymong.global.image.dto.ImageResponse;
import com.moneymong.global.image.service.ImageService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
Expand All @@ -16,19 +18,22 @@
import static org.springframework.http.MediaType.*;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;

@Tag(name = "9. [이미지]")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/images")
public class ImageController {

private final ImageService imageService;

@Operation(summary = "이미지 업로드")
@PostMapping(consumes = {MULTIPART_FORM_DATA_VALUE, APPLICATION_JSON_VALUE})
public ImageResponse upload(@RequestPart("file") MultipartFile multipartFile) {
ImageResponse response = imageService.upload(multipartFile);
return response;
}

@Operation(summary = "이미지 삭제 API")
@DeleteMapping(consumes = APPLICATION_JSON_VALUE)
public void remove(@RequestBody ImageDeleteRequest deleteRequest) {
imageService.remove(deleteRequest);
Expand Down
Loading

0 comments on commit 2a8641f

Please sign in to comment.