Skip to content

Commit

Permalink
refactor: modify API and add feature recommender registration (#144)
Browse files Browse the repository at this point in the history
* refactor(member): add field 'recommenderPhone' to MEMBER table

* feat(recommend): add recommend feature & test

* feat(recommend): add recommend API controller & test

* chore(log): add h2-console path to LogExceptionPattern

* fix: remove unnecessary code

* chore(sub): change commit pointer

* refactor(login): add 'withdrawl' field to SmsLoginResponse

* feat(teamImage): add query related TeamImage Entity & test

* feat(s3): add s3 delete object feature & test

* feat(s3): add team image service provides team image upload, update, delete

* test(s3): add team image service test

* feat(teamImage): add team image controller & test

* refactor(team): refactor related team service

* chore(sub): change submodule commit pointer

* docs: update api specification

* fix: seperate sql statement

---------

Co-authored-by: KAispread <[email protected]>
  • Loading branch information
KAispread and KAispread authored Sep 25, 2023
1 parent f2ed42a commit 0a55aaf
Show file tree
Hide file tree
Showing 37 changed files with 1,385 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ private LogExceptionPattern() {
public static final Pattern SWAGGER_UI_RESOURCE_PATTERN = Pattern.compile("^/static/dist.*");
public static final Pattern SWAGGER_SPECIFICATION_PATTERN = Pattern.compile("^/static/swagger-ui.*");
public static final Pattern SWAGGER_API_PATTERN = Pattern.compile("^/api-docs.*");
public static final Pattern H2_CONSOLE_PATTERN = Pattern.compile("^/h2-console.*");

public static final List<Pattern> LOG_EXCEPTION_LIST = List.of(
SWAGGER_SPECIFICATION_PATTERN,
SWAGGER_UI_RESOURCE_PATTERN,
SWAGGER_API_PATTERN
SWAGGER_API_PATTERN,
H2_CONSOLE_PATTERN
);

public static boolean isMatchedExceptionUrls(final String requestUrl) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.e2i.wemeet.controller.member;

import com.e2i.wemeet.config.resolver.member.MemberId;
import com.e2i.wemeet.dto.request.member.RecommenderRequestDto;
import com.e2i.wemeet.dto.response.ResponseDto;
import com.e2i.wemeet.service.member.RecommendService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/v1/recommend")
@RestController
public class RecommendController {

private final RecommendService recommendService;

@PostMapping
public ResponseDto<Long> recommend(@MemberId Long memberId,
@RequestBody @Valid RecommenderRequestDto requestDto) {
recommendService.recommend(memberId, requestDto.phoneNumber());
return ResponseDto.success("Recommend Success", null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.e2i.wemeet.controller.team;

import com.e2i.wemeet.config.resolver.member.MemberId;
import com.e2i.wemeet.dto.request.team.DeleteTeamImageRequestDto;
import com.e2i.wemeet.dto.response.ResponseDto;
import com.e2i.wemeet.service.team.TeamImageService;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RequiredArgsConstructor
@RequestMapping("/v1/team/image")
@RestController
public class TeamImageController {

private final TeamImageService teamImageService;

@PostMapping
public ResponseDto<List<String>> upload(@MemberId Long memberId, @RequestPart("images") List<MultipartFile> images) {
List<String> uploadedImageUrls = teamImageService.uploadTeamImage(memberId, images);
return ResponseDto.success("Team Image Upload Success", uploadedImageUrls);
}

@PutMapping
public ResponseDto<List<String>> update(@MemberId Long memberId, @RequestPart("images") List<MultipartFile> images) {
List<String> uploadedImageUrls = teamImageService.updateTeamImage(memberId, images);
return ResponseDto.success("Team Image Update Success", uploadedImageUrls);
}

@DeleteMapping
public ResponseDto<Void> delete(@Valid @RequestBody DeleteTeamImageRequestDto requestDto) {
teamImageService.deleteTeamImage(requestDto.deleteImageUrls());
return ResponseDto.success("Delete Team Image Success");
}

}
1 change: 1 addition & 0 deletions src/main/java/com/e2i/wemeet/domain/cost/Earn.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@Getter
public enum Earn {
EVENT("이벤트"),
RECOMMEND("친구에게 추천하여 가입"),
ADVERTISEMENT("광고 시청");

private final String detail;
Expand Down
17 changes: 14 additions & 3 deletions src/main/java/com/e2i/wemeet/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.e2i.wemeet.dto.request.member.UpdateMemberRequestDto;
import com.e2i.wemeet.exception.badrequest.MemberHasBeenDeletedException;
import com.e2i.wemeet.exception.badrequest.ProfileImageNotExistsException;
import com.e2i.wemeet.exception.badrequest.RecommenderAlreadyExist;
import com.e2i.wemeet.exception.badrequest.TeamExistsException;
import com.e2i.wemeet.exception.badrequest.TeamNotExistsException;
import com.e2i.wemeet.exception.unauthorized.CreditNotEnoughException;
Expand Down Expand Up @@ -85,6 +86,10 @@ public class Member extends BaseTimeEntity {
@Embedded
private ProfileImage profileImage;

@Convert(converter = CryptoConverter.class)
@Column(length = 24)
private String recommenderPhone;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
Expand All @@ -101,11 +106,10 @@ public class Member extends BaseTimeEntity {
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<History> history = new ArrayList<>();


@Builder
public Member(String nickname, Gender gender, String phoneNumber, String email,
CollegeInfo collegeInfo, Mbti mbti, Integer credit, Boolean imageAuth,
Boolean allowMarketing, ProfileImage profileImage, Role role) {
CollegeInfo collegeInfo, Mbti mbti, Integer credit, Boolean allowMarketing,
ProfileImage profileImage, Role role) {
this.nickname = nickname;
this.gender = gender;
this.phoneNumber = phoneNumber;
Expand Down Expand Up @@ -223,5 +227,12 @@ public boolean isProfileImageExists() {
public String getCollegeName() {
return this.collegeInfo.getCollegeCode().getCodeValue();
}

public void registerRecommender(final String recommenderPhone) {
if (this.recommenderPhone != null) {
throw new RecommenderAlreadyExist();
}
this.recommenderPhone = recommenderPhone;
}
}

Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
package com.e2i.wemeet.domain.team_image;

import com.e2i.wemeet.domain.team.Team;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface TeamImageRepository extends JpaRepository<TeamImage, Long> {

/*
* 팀 이미지 전체 삭제
*/
void deleteAllByTeamTeamId(Long teamId);

@Query("SELECT t FROM Team t JOIN t.teamLeader m WHERE m.memberId = :memberId")
Optional<Team> findTeamByMemberId(@Param("memberId") Long memberId);

@Query("SELECT ti FROM TeamImage ti JOIN ti.team t WHERE t.teamId = :teamId")
List<TeamImage> findTeamImagesByTeamId(@Param("teamId") Long teamId);

int countByTeamTeamId(Long teamId);

@Modifying(clearAutomatically = true)
@Query("DELETE FROM TeamImage ti WHERE ti.teamImageUrl IN :teamImageUrls")
void deleteAllByTeamImageUrl(@Param("teamImageUrls") Collection<String> teamImageUrls);

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ public Member toEntity(Code collegeCode) {
.mbti(Mbti.valueOf(this.mbti))
.allowMarketing(this.allowMarketing)
.credit(40)
.imageAuth(false)
.role(Role.USER)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.e2i.wemeet.dto.request.member;

import com.e2i.wemeet.util.validator.bean.PhoneValid;
import jakarta.validation.constraints.NotNull;

public record RecommenderRequestDto(

@NotNull
@PhoneValid
String phoneNumber

) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.e2i.wemeet.dto.request.team;

import jakarta.validation.constraints.NotEmpty;
import java.util.List;

public record DeleteTeamImageRequestDto(

@NotEmpty
List<String> deleteImageUrls

) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.e2i.wemeet.util.validator.bean.AdditionalActivityValid;
import com.e2i.wemeet.util.validator.bean.DrinkRateValid;
import com.e2i.wemeet.util.validator.bean.DrinkWithGameValid;
import com.e2i.wemeet.util.validator.bean.KakaoOpenChatLinkValid;
import com.e2i.wemeet.util.validator.bean.RegionValid;
import jakarta.annotation.Nullable;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -37,7 +36,6 @@ public record UpdateTeamRequestDto(
String introduction,

@NotNull
@KakaoOpenChatLinkValid
String chatLink,

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

// TODO :: service refactoring
// SMS 인증 응답
public record SmsCredentialResponse(
Long memberId,
boolean isRegistered,
boolean withdrawal,
Collection<? extends GrantedAuthority> role
) {

public static SmsCredentialResponse of(final MemberPrincipal principal) {
return new SmsCredentialResponse(
principal.getMemberId(),
principal.isRegistered(),
principal.isWithdrawal(),
principal.getAuthorities()
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/e2i/wemeet/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public enum ErrorCode {
SUGGESTION_HISTORY_EXISTS(40035, "suggestion.history.exists"),
DUPLICATE_MEETING_REQUEST(40041, "duplicate.meeting.request"),
MEETING_ALREADY_EXIST(40042, "meeting.already.exist"),
RECOMMENDER_ALREADY_EXIST(40043, "recommender.already.exist"),
IMAGE_COUNT_EXCEEDED(40044, "image.count.exceeded"),

NOTFOUND_SMS_CREDENTIAL(40100, "notfound.sms.credential"),
MEMBER_NOT_FOUND(40101, "member.not.found"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.e2i.wemeet.exception.badrequest;

import com.e2i.wemeet.exception.ErrorCode;

public class ImageCountExceedException extends BadRequestException {

public ImageCountExceedException() {
super(ErrorCode.IMAGE_COUNT_EXCEEDED);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.e2i.wemeet.exception.badrequest;

import static com.e2i.wemeet.exception.ErrorCode.RECOMMENDER_ALREADY_EXIST;

public class RecommenderAlreadyExist extends BadRequestException {

public RecommenderAlreadyExist() {
super(RECOMMENDER_ALREADY_EXIST);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
public class MemberPrincipal implements UserDetails {

private final Long memberId;
private final boolean withdrawal;

/*
* Authority 는 인가 정책을 적용할 때 필요함
Expand All @@ -27,21 +28,25 @@ public class MemberPrincipal implements UserDetails {

public MemberPrincipal() {
this.memberId = null;
this.withdrawal = false;
this.authorities = List.of(Role.GUEST::getRoleAttachedPrefix);
}

public MemberPrincipal(final Member member) {
this.memberId = member.getMemberId();
this.withdrawal = member.getDeletedAt() != null;
this.authorities = getAuthorities(member.getRole().name());
}

public MemberPrincipal(final Payload payload) {
this.memberId = payload.getMemberId();
this.withdrawal = false;
this.authorities = getAuthorities(payload.getRole());
}

public MemberPrincipal(final Long memberId, final String role) {
this.memberId = memberId;
this.withdrawal = false;
this.authorities = getAuthorities(role);
}

Expand All @@ -59,6 +64,10 @@ public boolean isRegistered() {
.orElseGet(() -> null) == null;
}

public boolean isWithdrawal() {
return this.withdrawal;
}

public boolean hasManagerRole() {
return AuthorityUtils.authorityListToSet(getAuthorities())
.contains(Role.getRoleAttachedPrefix(Role.MANAGER.name()));
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/e2i/wemeet/service/aws/s3/S3Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ public interface S3Service {
* S3 오브젝트 업로드
* */
void upload(MultipartFile multipartFile, String objectKey, String bucket);

/*
* S3 오브젝트 삭제
* */
void delete(String bucket, String targetObjectKeyPrefix);
}
Loading

0 comments on commit 0a55aaf

Please sign in to comment.