Skip to content

Commit

Permalink
release: 0.1.7 (#125)
Browse files Browse the repository at this point in the history
* feat: 모임 삭제 기능 구현 (#102)

* refactor: 기획 변경에 따른 회원 카드 등록 API 리팩토링 (#105)

* refactor: sql 변경 (#104)

* refactor: User 클래스 필드명 변경 (#104)

* refactor: API 변경에 따른 코드 리팩토링 (#104)

* refactor: 불필요한 getId() 제거 ( 피드백 반영 ) (#104)

* feat: 유효성 검증 관련 에러 일괄 처리을 위한 메소드 추가 (#104)

* test: API 변경에 따른 통합 테스트 수정 및 단위 테스트 구현 (#104)

* refactor: UserMeGetResponse 필드 변경 (#104)

* fix: CI 에러 수정 (#104)

* refactor: 피드백 반영 (#104)

* fix: CI 에러 수정 (#104)

* refactor: JWT 에러 응답 리팩토링 및 인가 인증 예최 처리 코드 수정 (#103)

* refactor: 기타 코드 리팩토링( 피드백 반영 ) (#101)

* chore: JWT 관련 의존성 변경 (#101)

* refactor: JWT 및 인증 관련 로직 리팩토링 (#101)

* test: 테스트 코드 및 설정 관련 변경(#101)

* refactor: ObjectMapper Autowired 로 주입 (#101)

* refactor: AuthService 반환 타입 Optional<User> -> User 변경 (#101)

* fix: V6_create_users_interests.sql 추가 (#109) (#110)

* refactor: 회원 카드 등록시 JWT 정보도 함께 반환하도록 수정 (#114)

* chore : application.properties 에 jwt 관련 설정 값 추가 (#113)

* refactor : userService 회원 카드 등록 로직 수정 (#113)

* feat : UserRegisterResponse 필드 추가(#113)

* test: API 변경에 따른 테스트 관련 코드 수정 (#113)

* fix: 소셜 로그인 관련 500 에러 수정 및 OAuth 로직 일부 개선 (#112)

* fix: OAuthLoginController @RestController 어노테이션 추가(나는 바보..) 및 favicon 관련 임시 컨트롤러 생성 (#111)

* refactor : 설정 yml 리팩토링 (#111)

* refactor : SecurityConfig 리팩토링 (#111)

* refactor : 기타 OAuth 관련 로직 리팩토링(#111)

* refactor : Cors 허용 주소 임시 전부 허용 (#111)

* fix : SonarCloud 오류 수정 (#111)

* fix : SonarCloud 오류 수정 (#111)

* feat: 위치 기반 API 구현 및 테스트 (#108)

* refactor: 기타 코드 리팩토링( 피드백 반영 ) (#101)

* chore: JWT 관련 의존성 변경 (#101)

* refactor: JWT 및 인증 관련 로직 리팩토링 (#101)

* test: 테스트 코드 및 설정 관련 변경(#101)

* refactor: ObjectMapper Autowired 로 주입 (#101)

* refactor: AuthService 반환 타입 Optional<User> -> User 변경 (#101)

* refactor: application.properties redis.port 변경 (#91)

* refactor: 기존 Redis 설정 리팩토링 및 추가 구현 (#91)

* feat: 유저 위치 기반 관련 DTO 및 VO 구현 (#91)

* feat: 유저 위치 기반 API 구현 (#91)

* test: 유저 위치 기반 통합 테스트 관련 클래스 구현 및 테스트 (#91)

* test: redis port 변경에 따른 테스트 수정 (#91)

* fix: CI 에러 수정 (#91)

* fix: sonarCloud 에러 수정 (#91)

* refactor: 리뷰 반영 (#108)

* build: Gatling 세팅 (#115)

* feat: 부하테스트 툴 Gatling을 세팅한다

* feat: 예시 코드를 작성한다

* refactor: Sample 코드의 이름을 변경한다

* feat: 내 정보 조회에 Oauth 정보 추가 (#119)

* feat: 내 정보 조회에 Oauth 정보 추가

* test: Oauth 정보 추가에 따른 테스트 변경

* fix: 모임 목록 조회 조건에 활동 지역 조건이 안걸리는 버그 수정 (#121)

* feat: 회원 탈퇴 사유 저장 로직 추가 및 cors 관련 재설정 (#123)

* refactor: SecurityConfig Cors 관련 전체 허용으로 변경 및 회원 카드 등록 API permitAll 로 변경 (#117)

* refactor: 기존 엔티티 관련 리팩토링 (#117)

* feat: WithdrawReason 생성 sql 추가 (#117)

* feat: WithdrawReason 관련 도메인 구현 (#117)

* feat: 회원 탈퇴 시 탈퇴 사유 기능 추가 (#117)

* test: 회원 탈퇴 단위 테스트 (#117)

* refactor: 회원 탈퇴 API POST 로 수정 (#117)

* refactor: 회원탈퇴 관련 통합 테스트 수정 및 요청 DTO 수정 (#117)

* refactor: meeting 엔티티명 다시 복구 - 모든 테이블에 `s` 붙이는 방향 논의 필요 (#117)

* feat: withdraw_reason 테이블 이름 변경 (#117)

* fix: CI 에러 해결 (#117)

---------

Co-authored-by: ddingmin <[email protected]>
Co-authored-by: xb205 <[email protected]>
  • Loading branch information
3 people authored Jan 19, 2024
1 parent 61df878 commit 4b6b6d9
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/main/java/net/teumteum/core/security/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public WebSecurityCustomizer webSecurityCustomizer() {
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable).cors(cors -> cors.configurationSource(corsConfigurationSource()))
.authorizeHttpRequests(request -> request.requestMatchers(PATTERNS).permitAll()
.requestMatchers(HttpMethod.POST, "/users/registers").permitAll()
.requestMatchers(HttpMethod.POST, "/users").permitAll()
.anyRequest().authenticated()).httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(STATELESS))
Expand All @@ -64,7 +64,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
config.addExposedHeader("Authorization");
Expand Down
26 changes: 18 additions & 8 deletions src/main/java/net/teumteum/meeting/domain/Meeting.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package net.teumteum.meeting.domain;

import jakarta.persistence.*;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.PrePersist;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import net.teumteum.core.entity.TimeBaseEntity;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "meeting")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Meeting extends TimeBaseEntity {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ private UserAroundLocationsResponse getUserAroundLocationsResponse(GeoResults<Ge
int count = 0;

for (GeoResult<GeoLocation<Object>> geoResult : Objects.requireNonNull(geoResults)) {
String userSavedTime = String.valueOf(geoResult.getContent().getName()).split(":")[1];
String userSavedTime = String.valueOf(geoResult.getContent().getName()).split(":")[5];
long timestamp = Long.parseLong(userSavedTime);

if (currentTime - timestamp < LOCATION_EXPIRATION.toMillis()) {
String userDataJson = String.valueOf(geoResult.getContent().getName()).split(":")[0];
String savedUserLocation = String.valueOf(geoResult.getContent().getName());
String userDataJson = savedUserLocation.substring(savedUserLocation.lastIndexOf(":") + 1);

UserData userData = null;
try {
userData = objectMapper.readValue(userDataJson, UserData.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import net.teumteum.core.security.service.SecurityService;
import net.teumteum.user.domain.request.UserRegisterRequest;
import net.teumteum.user.domain.request.UserUpdateRequest;
import net.teumteum.user.domain.request.UserWithdrawRequest;
import net.teumteum.user.domain.response.FriendsResponse;
import net.teumteum.user.domain.response.InterestQuestionResponse;
import net.teumteum.user.domain.response.UserGetResponse;
Expand All @@ -20,7 +21,6 @@
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand Down Expand Up @@ -87,10 +87,10 @@ public InterestQuestionResponse getInterestQuestion(@RequestParam("user-id") Lis
return userService.getInterestQuestionByUserIds(userIds, balance);
}

@DeleteMapping
@PostMapping("/withdraw")
@ResponseStatus(HttpStatus.OK)
public void withdraw() {
userService.withdraw(getCurrentUserId());
public void withdraw(@Valid @RequestBody UserWithdrawRequest request) {
userService.withdraw(request, getCurrentUserId());
}

@PostMapping
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/net/teumteum/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -24,9 +25,9 @@
import org.springframework.util.Assert;

@Getter
@Entity(name = "users")
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "users")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User extends TimeBaseEntity {

@Id
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/net/teumteum/user/domain/WithdrawReason.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package net.teumteum.user.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import net.teumteum.core.entity.TimeBaseEntity;

@Getter
@AllArgsConstructor
@Entity(name = "withdraw_reasons")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class WithdrawReason extends TimeBaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "withdraw_reason", nullable = false)
private String reason;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.teumteum.user.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface WithdrawReasonRepository extends JpaRepository<WithdrawReason, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.teumteum.user.domain.request;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import jakarta.validation.constraints.Size;
import java.util.List;
import net.teumteum.user.domain.WithdrawReason;

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public record UserWithdrawRequest(
@Size(min = 1, max = 3, message = "탈퇴 사유는 최소 1개, 최대 3개의 입력값입니다.")
List<String> withdrawReasons
) {

private static final Long IGNORE_ID = null;

public List<WithdrawReason> toEntity() {
return withdrawReasons.stream()
.map(withdrawReason -> new WithdrawReason(IGNORE_ID, withdrawReason))
.toList();
}
}
7 changes: 6 additions & 1 deletion src/main/java/net/teumteum/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import net.teumteum.user.domain.InterestQuestion;
import net.teumteum.user.domain.User;
import net.teumteum.user.domain.UserRepository;
import net.teumteum.user.domain.WithdrawReasonRepository;
import net.teumteum.user.domain.request.UserRegisterRequest;
import net.teumteum.user.domain.request.UserUpdateRequest;
import net.teumteum.user.domain.request.UserWithdrawRequest;
import net.teumteum.user.domain.response.FriendsResponse;
import net.teumteum.user.domain.response.InterestQuestionResponse;
import net.teumteum.user.domain.response.UserGetResponse;
Expand All @@ -28,6 +30,7 @@
public class UserService {

private final UserRepository userRepository;
private final WithdrawReasonRepository withdrawReasonRepository;
private final InterestQuestion interestQuestion;
private final RedisService redisService;
private final JwtService jwtService;
Expand Down Expand Up @@ -71,11 +74,13 @@ public void addFriends(Long myId, Long friendId) {
}

@Transactional
public void withdraw(Long userId) {
public void withdraw(UserWithdrawRequest request, Long userId) {
var existUser = getUser(userId);

userRepository.delete(existUser);
redisService.deleteData(String.valueOf(userId));

withdrawReasonRepository.saveAll(request.toEntity());
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
create table if not exists withdraw_reason
(
id bigint not null auto_increment,
withdraw_reason varchar(30) not null,
created_at timestamp(6) not null,
updated_at timestamp(6) not null,
primary key (id)
);
10 changes: 10 additions & 0 deletions src/main/resources/db/migration/V8__rename_withdraw_reason.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
drop table withdraw_reason;

create table if not exists withdraw_reasons
(
id bigint not null auto_increment,
withdraw_reason varchar(30) not null,
created_at timestamp(6) not null,
updated_at timestamp(6) not null,
primary key (id)
);
9 changes: 6 additions & 3 deletions src/test/java/net/teumteum/integration/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import net.teumteum.teum_teum.domain.request.UserLocationRequest;
import net.teumteum.user.domain.request.UserRegisterRequest;
import net.teumteum.user.domain.request.UserUpdateRequest;
import net.teumteum.user.domain.request.UserWithdrawRequest;
import org.springframework.boot.test.context.TestComponent;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -137,10 +138,12 @@ ResponseSpec reissueJwt(String accessToken, String refreshToken) {
.exchange();
}

ResponseSpec withdrawUser(String accessToken) {
return webTestClient.delete()
.uri("/users")
ResponseSpec withdrawUser(String accessToken, UserWithdrawRequest request) {
return webTestClient
.post()
.uri("/users/withdraw")
.header(HttpHeaders.AUTHORIZATION, accessToken)
.bodyValue(request)
.exchange();
}

Expand Down
6 changes: 6 additions & 0 deletions src/test/java/net/teumteum/integration/RequestFixture.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.teumteum.integration;

import java.util.List;
import java.util.UUID;
import net.teumteum.core.security.Authenticated;
import net.teumteum.user.domain.User;
Expand All @@ -8,9 +9,14 @@
import net.teumteum.user.domain.request.UserRegisterRequest.Terms;
import net.teumteum.user.domain.request.UserUpdateRequest;
import net.teumteum.user.domain.request.UserUpdateRequest.NewJob;
import net.teumteum.user.domain.request.UserWithdrawRequest;

public class RequestFixture {

public static UserWithdrawRequest userWithdrawRequest(List<String> withdrawReasons) {
return new UserWithdrawRequest(withdrawReasons);
}

public static UserUpdateRequest userUpdateRequest(User user) {
return new UserUpdateRequest(user.getId(), "new_name", user.getBirth(), user.getCharacterId(),
user.getActivityArea(), user.getMbti(), user.getStatus().name(), user.getGoal(), newJob(user),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,10 @@ void Withdraw_user_info_api() {

loginContext.setUserId(me.getId());

// when & then
var request = RequestFixture.userWithdrawRequest(List.of("쓰지 않는 앱이에요", "오류가 생겨서 쓸 수 없어요"));

assertThatCode(() -> api.withdrawUser(VALID_TOKEN))
// when & then
assertThatCode(() -> api.withdrawUser(VALID_TOKEN, request))
.doesNotThrowAnyException();
}

Expand All @@ -252,8 +253,10 @@ void Return_500_error_if_user_not_exist() {
// given
repository.clearUserRepository();

var request = RequestFixture.userWithdrawRequest(List.of("쓰지 않는 앱이에요", "오류가 생겨서 쓸 수 없어요"));

// when
var result = api.withdrawUser(VALID_TOKEN);
var result = api.withdrawUser(VALID_TOKEN, request);

// then
Assertions.assertThat(result.expectStatus().is5xxServerError()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import net.teumteum.core.security.SecurityConfig;
import net.teumteum.core.security.filter.JwtAuthenticationFilter;
import net.teumteum.core.security.service.JwtService;
Expand All @@ -22,6 +24,7 @@
import net.teumteum.user.domain.User;
import net.teumteum.user.domain.UserFixture;
import net.teumteum.user.domain.request.UserRegisterRequest;
import net.teumteum.user.domain.request.UserWithdrawRequest;
import net.teumteum.user.domain.response.UserRegisterResponse;
import net.teumteum.user.service.UserService;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -35,7 +38,6 @@
import org.springframework.context.annotation.FilterType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;

@WebMvcTest(value = UserController.class,
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class),
Expand All @@ -48,8 +50,10 @@
public class UserControllerTest {

@Autowired
private MockMvc mockMvc;
ObjectMapper objectMapper;

@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;

Expand Down Expand Up @@ -79,7 +83,7 @@ void Register_user_card_with_201_created() throws Exception {

// when & then
mockMvc.perform(post("/users")
.content(new ObjectMapper().writeValueAsString(request))
.content(objectMapper.writeValueAsString(request))
.contentType(APPLICATION_JSON)
.with(csrf())
.header(AUTHORIZATION, VALID_ACCESS_TOKEN))
Expand All @@ -98,7 +102,7 @@ void Register_user_card_with_400_bad_request() throws Exception {
// when
// then
mockMvc.perform(post("/users")
.content(new ObjectMapper().writeValueAsString(request))
.content(objectMapper.writeValueAsString(request))
.contentType(APPLICATION_JSON)
.with(csrf())
.header(AUTHORIZATION, VALID_ACCESS_TOKEN))
Expand All @@ -107,4 +111,26 @@ void Register_user_card_with_400_bad_request() throws Exception {
.andExpect(jsonPath("$.message").isNotEmpty());
}
}

@Nested
@DisplayName("회원 탈퇴 API는")
class Withdraw_user_api_unit {

@Test
@DisplayName("회원 탈퇴 사유와 회원 탈퇴 요청이 들어오면, 탈퇴를 진행하고 200 OK을 반환한다.")
void Withdraw_user_with_200_ok() throws Exception {
// given
UserWithdrawRequest request
= RequestFixture.userWithdrawRequest(List.of("쓰지 않는 앱이에요", "오류가 생겨서 쓸 수 없어요"));

// when & then
mockMvc.perform(post("/users/withdraw")
.content(new ObjectMapper().writeValueAsString(request))
.contentType(APPLICATION_JSON)
.with(csrf())
.header(AUTHORIZATION, VALID_ACCESS_TOKEN))
.andDo(print())
.andExpect(status().isOk());
}
}
}
Loading

0 comments on commit 4b6b6d9

Please sign in to comment.