diff --git a/src/main/java/poomasi/domain/auth/config/SecurityBeanGenerator.java b/src/main/java/poomasi/domain/auth/config/SecurityBeanGenerator.java index 2aa3d5d6..de30f9d0 100644 --- a/src/main/java/poomasi/domain/auth/config/SecurityBeanGenerator.java +++ b/src/main/java/poomasi/domain/auth/config/SecurityBeanGenerator.java @@ -2,20 +2,13 @@ import jdk.jfr.Description; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import poomasi.domain.auth.token.blacklist.service.TokenBlacklistService; -import poomasi.domain.auth.token.refreshtoken.service.TokenStorageService; -import poomasi.domain.auth.token.util.JwtUtil; -import poomasi.domain.auth.token.refreshtoken.service.TokenRedisService; -import poomasi.domain.member.service.MemberService; + @RequiredArgsConstructor @Configuration diff --git a/src/main/java/poomasi/domain/auth/config/SecurityConfig.java b/src/main/java/poomasi/domain/auth/config/SecurityConfig.java index 14acee13..0f544b13 100644 --- a/src/main/java/poomasi/domain/auth/config/SecurityConfig.java +++ b/src/main/java/poomasi/domain/auth/config/SecurityConfig.java @@ -15,14 +15,11 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutFilter; -import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import poomasi.domain.auth.security.filter.CustomUsernamePasswordAuthenticationFilter; import poomasi.domain.auth.security.filter.JwtAuthenticationFilter; import poomasi.domain.auth.security.handler.CustomSuccessHandler; import poomasi.domain.auth.security.userdetail.OAuth2UserDetailServiceImpl; -import poomasi.domain.auth.security.handler.*; import poomasi.domain.auth.security.userdetail.UserDetailsServiceImpl; import poomasi.domain.auth.token.util.JwtUtil; @@ -78,7 +75,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers(HttpMethod.GET, "/api/review/**").permitAll() .requestMatchers(HttpMethod.GET, "/health").permitAll() .requestMatchers(HttpMethod.GET, "/api/image/**").permitAll() - .requestMatchers("/api/sign-up", "/api/login", "api/reissue", "api/payment/**", "api/order/**", "api/reservation/**", "/api/v1/farmer/reservations").permitAll() + .requestMatchers("/api/member/sign-up", "/api/login", "api/reissue", "api/payment/**", "api/order/**", "api/reservation/**", "/api/v1/farmer/reservations").permitAll() .requestMatchers("/api/need-auth/**").authenticated() .anyRequest(). authenticated() diff --git a/src/main/java/poomasi/domain/farm/controller/FarmController.java b/src/main/java/poomasi/domain/farm/controller/FarmController.java index cb3c81af..f1763f5f 100644 --- a/src/main/java/poomasi/domain/farm/controller/FarmController.java +++ b/src/main/java/poomasi/domain/farm/controller/FarmController.java @@ -25,4 +25,9 @@ public ResponseEntity getFarm(@PathVariable Long farmId) { public ResponseEntity getFarmList(Pageable pageable) { return ResponseEntity.ok(farmPlatformService.getFarmList(pageable)); } + + @GetMapping("byFarmer/{farmerId}") + public ResponseEntity getFarmsByFarmerId(@PathVariable Long farmerId) { + return ResponseEntity.ok(farmPlatformService.getFarmsByFarmerId(farmerId)); + } } diff --git a/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java b/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java index 54032ecf..2ace44df 100644 --- a/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java +++ b/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java @@ -22,4 +22,10 @@ public List getFarmList(Pageable pageable) { .map(FarmResponse::fromEntity) .collect(Collectors.toList()); } + + public List getFarmsByFarmerId(Long farmerId) { + return farmService.getFarmListByOwnerId(farmerId).stream() + .map(FarmResponse::fromEntity) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteFactory.java b/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteFactory.java new file mode 100644 index 00000000..821b7353 --- /dev/null +++ b/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteFactory.java @@ -0,0 +1,25 @@ +package poomasi.domain.image.deleteLinker; + +import org.springframework.stereotype.Component; +import poomasi.domain.image.entity.ImageType; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class ImageDeleteFactory { + + private final Map handlerMap; + + public ImageDeleteFactory( + ProductDeleteLinker productDeleteLinker, + MemberProfileDeleteLinker memberProfileDeleteLinker) { + this.handlerMap = new HashMap<>(); + handlerMap.put(ImageType.PRODUCT, productDeleteLinker); + handlerMap.put(ImageType.MEMBER_PROFILE, memberProfileDeleteLinker); + } + + public ImageDeleteLinker getDeleteLinker(ImageType type) { + return handlerMap.get(type); + } +} diff --git a/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteLinker.java b/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteLinker.java new file mode 100644 index 00000000..c5820c90 --- /dev/null +++ b/src/main/java/poomasi/domain/image/deleteLinker/ImageDeleteLinker.java @@ -0,0 +1,7 @@ +package poomasi.domain.image.deleteLinker; + +import poomasi.domain.image.entity.Image; + +public interface ImageDeleteLinker { + void handleImageDeletion(Image image); +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/image/deleteLinker/MemberProfileDeleteLinker.java b/src/main/java/poomasi/domain/image/deleteLinker/MemberProfileDeleteLinker.java new file mode 100644 index 00000000..696bed0d --- /dev/null +++ b/src/main/java/poomasi/domain/image/deleteLinker/MemberProfileDeleteLinker.java @@ -0,0 +1,24 @@ +package poomasi.domain.image.deleteLinker; + +import org.springframework.stereotype.Component; +import poomasi.domain.image.entity.Image; +import poomasi.domain.member._profile.entity.MemberProfile; +import poomasi.domain.member._profile.service.MemberProfileService; + +@Component +public class MemberProfileDeleteLinker implements ImageDeleteLinker { + + private final MemberProfileService memberProfileService; + + public MemberProfileDeleteLinker(MemberProfileService memberProfileService) { + this.memberProfileService = memberProfileService; + } + + @Override + public void handleImageDeletion(Image image) { + MemberProfile memberProfile = memberProfileService.getMemberProfileById(image.getReferenceId()); + memberProfile.setProfileImage(null); + memberProfileService.saveMemberProfile(memberProfile); + } +} + diff --git a/src/main/java/poomasi/domain/image/deleteLinker/ProductDeleteLinker.java b/src/main/java/poomasi/domain/image/deleteLinker/ProductDeleteLinker.java new file mode 100644 index 00000000..9453cbce --- /dev/null +++ b/src/main/java/poomasi/domain/image/deleteLinker/ProductDeleteLinker.java @@ -0,0 +1,23 @@ +package poomasi.domain.image.deleteLinker; + +import org.springframework.stereotype.Component; +import poomasi.domain.image.entity.Image; +import poomasi.domain.product.entity.Product; +import poomasi.domain.product.service.ProductService; + +@Component +public class ProductDeleteLinker implements ImageDeleteLinker { + + private final ProductService productService; + + public ProductDeleteLinker(ProductService productService) { + this.productService = productService; + } + + @Override + public void handleImageDeletion(Image image) { + Product product = productService.findProductById(image.getReferenceId()); + product.setImageUrl(null); + productService.saveExistedProduct(product); + } +} diff --git a/src/main/java/poomasi/domain/image/entity/Image.java b/src/main/java/poomasi/domain/image/entity/Image.java index dba3541d..38d70ebb 100644 --- a/src/main/java/poomasi/domain/image/entity/Image.java +++ b/src/main/java/poomasi/domain/image/entity/Image.java @@ -6,11 +6,10 @@ import poomasi.domain.image.dto.ImageRequest; import java.time.LocalDateTime; -import java.util.Date; @Entity @Table(name = "image", uniqueConstraints = { - @UniqueConstraint(columnNames = {"type", "reference_id", "object_key"}) + @UniqueConstraint(columnNames = {"type", "reference_id"}) }) @Getter @Setter @@ -22,10 +21,10 @@ public class Image { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) + @Column(nullable = false, unique = true) private String objectKey; - @Column(nullable = false) + @Column(nullable = false, unique = true) private String imageUrl; @Enumerated(EnumType.STRING) @@ -37,7 +36,7 @@ public class Image { @Column(name = "created_at", nullable = false) @Temporal(TemporalType.TIMESTAMP) - private Date createdAt = new Date(); + private LocalDateTime createdAt = LocalDateTime.now(); @Column(name = "deleted_at") private LocalDateTime deletedAt; diff --git a/src/main/java/poomasi/domain/image/linker/ImageLinker.java b/src/main/java/poomasi/domain/image/linker/ImageLinker.java new file mode 100644 index 00000000..ab0fa128 --- /dev/null +++ b/src/main/java/poomasi/domain/image/linker/ImageLinker.java @@ -0,0 +1,9 @@ +package poomasi.domain.image.linker; + +import poomasi.domain.image.entity.Image; +import poomasi.domain.image.entity.ImageType; + +public interface ImageLinker { + boolean supports(ImageType type); + void link(Long referenceId, Image savedImage); +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/image/linker/ImageLinkerFactory.java b/src/main/java/poomasi/domain/image/linker/ImageLinkerFactory.java new file mode 100644 index 00000000..1064266e --- /dev/null +++ b/src/main/java/poomasi/domain/image/linker/ImageLinkerFactory.java @@ -0,0 +1,23 @@ +package poomasi.domain.image.linker; + +import org.springframework.stereotype.Component; +import poomasi.domain.image.entity.ImageType; + +import java.util.List; + +@Component +public class ImageLinkerFactory { + + private final List linkers; + + public ImageLinkerFactory(List linkers) { + this.linkers = linkers; + } + + public ImageLinker getLinker(ImageType type) { + return linkers.stream() + .filter(linker -> linker.supports(type)) + .findFirst() + .orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/image/linker/MemberProfileImageLinker.java b/src/main/java/poomasi/domain/image/linker/MemberProfileImageLinker.java new file mode 100644 index 00000000..3008f725 --- /dev/null +++ b/src/main/java/poomasi/domain/image/linker/MemberProfileImageLinker.java @@ -0,0 +1,31 @@ +package poomasi.domain.image.linker; + +import org.springframework.stereotype.Service; +import poomasi.domain.image.entity.Image; +import poomasi.domain.image.entity.ImageType; +import poomasi.domain.member._profile.entity.MemberProfile; +import poomasi.domain.member._profile.service.MemberProfileService; + +@Service +public class MemberProfileImageLinker implements ImageLinker { + + private final MemberProfileService memberProfileService; + + public MemberProfileImageLinker(MemberProfileService memberProfileService) { + this.memberProfileService = memberProfileService; + } + + @Override + public boolean supports(ImageType type) { + return type == ImageType.MEMBER_PROFILE; + } + + @Override + public void link(Long referenceId, Image savedImage) { + MemberProfile memberProfile = memberProfileService.getMemberProfileById(referenceId); + memberProfile.setProfileImage(savedImage); + memberProfileService.saveMemberProfile(memberProfile); + } +} + + diff --git a/src/main/java/poomasi/domain/image/linker/ProductImageLinker.java b/src/main/java/poomasi/domain/image/linker/ProductImageLinker.java new file mode 100644 index 00000000..fc75dac6 --- /dev/null +++ b/src/main/java/poomasi/domain/image/linker/ProductImageLinker.java @@ -0,0 +1,29 @@ +package poomasi.domain.image.linker; + +import org.springframework.stereotype.Service; +import poomasi.domain.image.entity.Image; +import poomasi.domain.image.entity.ImageType; +import poomasi.domain.product.entity.Product; +import poomasi.domain.product.service.ProductService; + +@Service +public class ProductImageLinker implements ImageLinker { + + private final ProductService productService; + + public ProductImageLinker(ProductService productService) { + this.productService = productService; + } + + @Override + public boolean supports(ImageType type) { + return type == ImageType.PRODUCT; + } + + @Override + public void link(Long referenceId, Image savedImage) { + Product product = productService.findProductById(referenceId); + product.setImageUrl(savedImage.getImageUrl()); + productService.saveExistedProduct(product); + } +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/image/service/ImageService.java b/src/main/java/poomasi/domain/image/service/ImageService.java index cf72c618..b0cabc50 100644 --- a/src/main/java/poomasi/domain/image/service/ImageService.java +++ b/src/main/java/poomasi/domain/image/service/ImageService.java @@ -3,19 +3,21 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import poomasi.domain.image.deleteLinker.ImageDeleteFactory; +import poomasi.domain.image.deleteLinker.ImageDeleteLinker; import poomasi.domain.image.dto.ImageRequest; import poomasi.domain.image.entity.Image; import poomasi.domain.image.entity.ImageType; +import poomasi.domain.image.linker.ImageLinker; +import poomasi.domain.image.linker.ImageLinkerFactory; import poomasi.domain.image.repository.ImageRepository; -import poomasi.domain.image.validation.ImageOwnerValidator; -import poomasi.domain.image.validation.ImageOwnerValidatorFactory; -import poomasi.domain.member._profile.entity.MemberProfile; -import poomasi.domain.member._profile.service.MemberProfileService; +import poomasi.domain.image.validator.ImageOwnerValidator; +import poomasi.domain.image.validator.ImageOwnerValidatorFactory; import poomasi.domain.member.entity.Member; -import poomasi.domain.member.repository.MemberRepository; +import poomasi.domain.member.service.MemberService; import poomasi.global.error.BusinessException; -import java.util.Date; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -28,13 +30,15 @@ public class ImageService { private static final int DEFAULT_IMAGE_LIMIT = 5; - private static final int MEMBER_PROFILE_IMAGE_LIMIT = 1; + private static final int IMAGE_ONE_LIMIT = 1; private final ImageRepository imageRepository; + private final MemberService memberService; private final ImageOwnerValidatorFactory validatorFactory; - private final MemberRepository memberRepository; - private final MemberProfileService memberProfileService; + private final ImageLinkerFactory imageLinkerFactory; + private final ImageDeleteFactory imageDeleteFactory; + // 이미지 타입에 맞게 link, deleteLink, 개수 제한, ownerValidate @Transactional public Image saveImage(Long memberId, ImageRequest imageRequest) { @@ -46,9 +50,7 @@ public Image saveImage(Long memberId, ImageRequest imageRequest) { .map(existingImage -> recoverImageOrThrow(existingImage, imageRequest)) .orElseGet(() -> imageRequest.toEntity(imageRequest)); - if (imageRequest.type() == ImageType.MEMBER_PROFILE) { - linkImageToMemberProfile(imageRequest.referenceId(), image); - } + imageLink(image); return imageRepository.save(image); } @@ -66,8 +68,7 @@ private void validateImageOwner(Long memberId, ImageType type, Long referenceId) } private boolean isAdmin(Long memberId) { - Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new BusinessException(MEMBER_NOT_FOUND)); + Member member = memberService.findMemberById(memberId); return member.isAdmin(); } @@ -81,15 +82,15 @@ private Image recoverImageOrThrow(Image existingImage, ImageRequest imageRequest throw new BusinessException(IMAGE_ALREADY_EXISTS); } existingImage.setDeletedAt(null); - existingImage.setCreatedAt(new Date()); + existingImage.setCreatedAt(LocalDateTime.now()); existingImage.update(imageRequest); return existingImage; } private void validateImageLimit(ImageRequest imageRequest) { int imageLimit = DEFAULT_IMAGE_LIMIT; - if (imageRequest.type() == ImageType.MEMBER_PROFILE) { - imageLimit = MEMBER_PROFILE_IMAGE_LIMIT; // 멤버 프로필 이미지는 한 장으로 제한 + if (imageRequest.type() == ImageType.MEMBER_PROFILE || imageRequest.type() == ImageType.PRODUCT) { + imageLimit = IMAGE_ONE_LIMIT; // 멤버 프로필, 상품 이미지는 한 장으로 제한 } if (imageRepository.countByTypeAndReferenceIdAndDeletedAtIsNull(imageRequest.type(), imageRequest.referenceId()) >= imageLimit) { @@ -97,12 +98,6 @@ private void validateImageLimit(ImageRequest imageRequest) { } } - private void linkImageToMemberProfile(Long referenceId, Image savedImage) { - MemberProfile memberProfile = memberProfileService.getMemberProfileById(referenceId); - memberProfile.setProfileImage(savedImage); - memberProfileService.saveMemberProfile(memberProfile); - } - // 여러 이미지 저장 @Transactional public List saveMultipleImages(Long memberId, List imageRequests) { @@ -115,7 +110,9 @@ public List saveMultipleImages(Long memberId, List imageReq public void deleteImage(Long memberId, Long id) { Image image = getImageById(id); validateImageOwner(memberId, image.getType(), image.getReferenceId()); - imageRepository.deleteById(id); + imageRepository.delete(image); + + imageDeleteLink(image); } public Image getImageById(Long id) { @@ -138,8 +135,17 @@ public Image updateImage(Long memberId, Long id, ImageRequest imageRequest) { validateImageLimit(imageRequest); } + if (!image.getType().equals(imageRequest.type())) { + imageDeleteLink(image); + } + image.update(imageRequest); + if (!image.getType().equals(imageRequest.type())) { + imageLink(image); + } + + return imageRepository.save(image); } @@ -155,7 +161,27 @@ public void recoverImage(Long memberId, Long id) { validateImageLimit(image.toRequest(image)); image.setDeletedAt(null); + + imageLink(image); + imageRepository.save(image); } + // 이미지와 해당 이미지를 가지는 엔티티 연결 + private void imageLink(Image image){ + ImageLinker linker = imageLinkerFactory.getLinker(image.getType()); + if (linker != null){ + linker.link(image.getReferenceId(), image); + } + } + + // 이미지 삭제 시 해당 이미지를 가지는 엔티티에서도 처리 + private void imageDeleteLink(Image image){ + ImageDeleteLinker imageDeleteLinker = imageDeleteFactory.getDeleteLinker(image.getType()); + if (imageDeleteLinker != null) { + imageDeleteLinker.handleImageDeletion(image); // 해당 타입에 맞는 삭제 처리 + } + } + + } \ No newline at end of file diff --git a/src/main/java/poomasi/domain/image/validation/MemberProfileOwnerValidator.java b/src/main/java/poomasi/domain/image/validation/MemberProfileOwnerValidator.java deleted file mode 100644 index b597d5b0..00000000 --- a/src/main/java/poomasi/domain/image/validation/MemberProfileOwnerValidator.java +++ /dev/null @@ -1,18 +0,0 @@ -package poomasi.domain.image.validation; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import poomasi.domain.member._profile.repository.MemberProfileRepository; - -@Component -@RequiredArgsConstructor -public class MemberProfileOwnerValidator implements ImageOwnerValidator{ - private final MemberProfileRepository memberProfileRepository; - - @Override - public boolean validateOwner(Long memberId, Long referenceId) { - return memberProfileRepository.findById(referenceId) - .filter(memberProfile -> memberProfile.getMember().getId().equals(memberId)) - .isPresent(); - } -} diff --git a/src/main/java/poomasi/domain/image/validation/FarmOwnerValidator.java b/src/main/java/poomasi/domain/image/validator/FarmOwnerValidator.java similarity index 92% rename from src/main/java/poomasi/domain/image/validation/FarmOwnerValidator.java rename to src/main/java/poomasi/domain/image/validator/FarmOwnerValidator.java index ca376272..193aa1a0 100644 --- a/src/main/java/poomasi/domain/image/validation/FarmOwnerValidator.java +++ b/src/main/java/poomasi/domain/image/validator/FarmOwnerValidator.java @@ -1,4 +1,4 @@ -package poomasi.domain.image.validation; +package poomasi.domain.image.validator; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/src/main/java/poomasi/domain/image/validation/ImageOwnerValidator.java b/src/main/java/poomasi/domain/image/validator/ImageOwnerValidator.java similarity index 71% rename from src/main/java/poomasi/domain/image/validation/ImageOwnerValidator.java rename to src/main/java/poomasi/domain/image/validator/ImageOwnerValidator.java index 8b51556f..1faa853f 100644 --- a/src/main/java/poomasi/domain/image/validation/ImageOwnerValidator.java +++ b/src/main/java/poomasi/domain/image/validator/ImageOwnerValidator.java @@ -1,4 +1,4 @@ -package poomasi.domain.image.validation; +package poomasi.domain.image.validator; public interface ImageOwnerValidator { boolean validateOwner(Long memberId, Long referenceId); diff --git a/src/main/java/poomasi/domain/image/validation/ImageOwnerValidatorFactory.java b/src/main/java/poomasi/domain/image/validator/ImageOwnerValidatorFactory.java similarity index 96% rename from src/main/java/poomasi/domain/image/validation/ImageOwnerValidatorFactory.java rename to src/main/java/poomasi/domain/image/validator/ImageOwnerValidatorFactory.java index d22141b2..2de7c789 100644 --- a/src/main/java/poomasi/domain/image/validation/ImageOwnerValidatorFactory.java +++ b/src/main/java/poomasi/domain/image/validator/ImageOwnerValidatorFactory.java @@ -1,4 +1,4 @@ -package poomasi.domain.image.validation; +package poomasi.domain.image.validator; import org.springframework.stereotype.Component; import poomasi.domain.image.entity.ImageType; diff --git a/src/main/java/poomasi/domain/image/validator/MemberProfileOwnerValidator.java b/src/main/java/poomasi/domain/image/validator/MemberProfileOwnerValidator.java new file mode 100644 index 00000000..f49c12ea --- /dev/null +++ b/src/main/java/poomasi/domain/image/validator/MemberProfileOwnerValidator.java @@ -0,0 +1,18 @@ +package poomasi.domain.image.validator; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import poomasi.domain.member.repository.MemberRepository; + +@Component +@RequiredArgsConstructor +public class MemberProfileOwnerValidator implements ImageOwnerValidator{ + private final MemberRepository memberRepository; + + @Override + public boolean validateOwner(Long memberId, Long referenceId) { + return memberRepository.findById(memberId) + .filter(member -> member.getMemberProfile().getId().equals(referenceId)) + .isPresent(); + } +} diff --git a/src/main/java/poomasi/domain/image/validation/ProductOwnerValidator.java b/src/main/java/poomasi/domain/image/validator/ProductOwnerValidator.java similarity index 93% rename from src/main/java/poomasi/domain/image/validation/ProductOwnerValidator.java rename to src/main/java/poomasi/domain/image/validator/ProductOwnerValidator.java index 6afc0bfb..43175fa2 100644 --- a/src/main/java/poomasi/domain/image/validation/ProductOwnerValidator.java +++ b/src/main/java/poomasi/domain/image/validator/ProductOwnerValidator.java @@ -1,4 +1,4 @@ -package poomasi.domain.image.validation; +package poomasi.domain.image.validator; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/src/main/java/poomasi/domain/image/validation/ReviewOwnerValidator.java b/src/main/java/poomasi/domain/image/validator/ReviewOwnerValidator.java similarity index 93% rename from src/main/java/poomasi/domain/image/validation/ReviewOwnerValidator.java rename to src/main/java/poomasi/domain/image/validator/ReviewOwnerValidator.java index 57073e2d..5f8d8d6b 100644 --- a/src/main/java/poomasi/domain/image/validation/ReviewOwnerValidator.java +++ b/src/main/java/poomasi/domain/image/validator/ReviewOwnerValidator.java @@ -1,4 +1,4 @@ -package poomasi.domain.image.validation; +package poomasi.domain.image.validator; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/src/main/java/poomasi/domain/member/_profile/controller/MemberProfileController.java b/src/main/java/poomasi/domain/member/_profile/controller/MemberProfileController.java deleted file mode 100644 index 97de1cdf..00000000 --- a/src/main/java/poomasi/domain/member/_profile/controller/MemberProfileController.java +++ /dev/null @@ -1,14 +0,0 @@ -package poomasi.domain.member._profile.controller; - -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import poomasi.domain.member._profile.service.MemberProfileService; - -@RestController -@RequiredArgsConstructor -@RequestMapping("api/member/profile") -public class MemberProfileController { - - private final MemberProfileService memberProfileService; -} diff --git a/src/main/java/poomasi/domain/member/_profile/dto/request/AddressUpdateRequest.java b/src/main/java/poomasi/domain/member/_profile/dto/request/AddressUpdateRequest.java new file mode 100644 index 00000000..8a8ac1d0 --- /dev/null +++ b/src/main/java/poomasi/domain/member/_profile/dto/request/AddressUpdateRequest.java @@ -0,0 +1,8 @@ +package poomasi.domain.member._profile.dto.request; + +public record AddressUpdateRequest( + String defaultAddress, + String addressDetail, + Long coordinateX, + Long coordinateY) { +} diff --git a/src/main/java/poomasi/domain/member/_profile/dto/request/MemberProfileRequest.java b/src/main/java/poomasi/domain/member/_profile/dto/request/MemberProfileRequest.java deleted file mode 100644 index 3492e58d..00000000 --- a/src/main/java/poomasi/domain/member/_profile/dto/request/MemberProfileRequest.java +++ /dev/null @@ -1,5 +0,0 @@ -package poomasi.domain.member._profile.dto.request; - - -public record MemberProfileRequest() { -} diff --git a/src/main/java/poomasi/domain/member/_profile/dto/response/CommonProfileResponse.java b/src/main/java/poomasi/domain/member/_profile/dto/response/CommonProfileResponse.java deleted file mode 100644 index cb665655..00000000 --- a/src/main/java/poomasi/domain/member/_profile/dto/response/CommonProfileResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package poomasi.domain.member._profile.dto.response; - -import lombok.AllArgsConstructor; -import poomasi.domain.image.entity.Image; -import poomasi.domain.member._profile.entity.MemberProfile; - -import java.time.LocalDateTime; - -@AllArgsConstructor -public class CommonProfileResponse implements MemberProfileResponse { - String phoneNumber; - boolean isBanned; - LocalDateTime createdAt; - Image profileImage; - - public static CommonProfileResponse fromEntity(MemberProfile profile) { - return new CommonProfileResponse( - profile.getPhoneNumber(), - profile.isBanned(), - profile.getCreatedAt(), - profile.getProfileImage() - ); - } - -} diff --git a/src/main/java/poomasi/domain/member/_profile/dto/response/CustomerProfileResponse.java b/src/main/java/poomasi/domain/member/_profile/dto/response/CustomerProfileResponse.java deleted file mode 100644 index 53501e03..00000000 --- a/src/main/java/poomasi/domain/member/_profile/dto/response/CustomerProfileResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package poomasi.domain.member._profile.dto.response; - -import lombok.AllArgsConstructor; -import poomasi.domain.image.entity.Image; -import poomasi.domain.member._profile.entity.CustomerProfile; - -import java.time.LocalDateTime; - -@AllArgsConstructor -public class CustomerProfileResponse implements MemberProfileResponse{ - String phoneNumber; - String address; - String addressDetail; - boolean isBanned; - LocalDateTime createdAt; - Image profileImage; - - public static CustomerProfileResponse fromEntity(CustomerProfile profile) { - return new CustomerProfileResponse( - profile.getPhoneNumber(), - profile.getAddress(), - profile.getAddressDetail(), - profile.isBanned(), - profile.getCreatedAt(), - profile.getProfileImage() - ); - } -} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/member/_profile/dto/response/FarmerProfileResponse.java b/src/main/java/poomasi/domain/member/_profile/dto/response/FarmerProfileResponse.java index 53fed2f5..ec11888f 100644 --- a/src/main/java/poomasi/domain/member/_profile/dto/response/FarmerProfileResponse.java +++ b/src/main/java/poomasi/domain/member/_profile/dto/response/FarmerProfileResponse.java @@ -1,39 +1,22 @@ package poomasi.domain.member._profile.dto.response; -import lombok.AllArgsConstructor; import poomasi.domain.image.entity.Image; -import poomasi.domain.member._profile.entity.FarmerProfile; +import poomasi.domain.member._profile.entity.MemberProfile; import java.time.LocalDateTime; -import java.util.List; -@AllArgsConstructor -public class FarmerProfileResponse implements MemberProfileResponse { - String phoneNumber; - boolean isBanned; - LocalDateTime createdAt; - Image profileImage; - String storeName; - String farmName; - List businessRegistrationNumbers; - String storeAddress; - String storeAddressDetail; - String farmAddress; - String farmAddressDetail; - - public static FarmerProfileResponse fromEntity(FarmerProfile profile) { +public record FarmerProfileResponse( + String phoneNumber, + boolean isBanned, + LocalDateTime createdAt, + Image profileImage +){ + public static FarmerProfileResponse fromEntity(MemberProfile profile) { return new FarmerProfileResponse( profile.getPhoneNumber(), profile.isBanned(), profile.getCreatedAt(), - profile.getProfileImage(), - profile.getStoreName(), - profile.getFarmName(), - profile.getBusinessRegistrationNumbers(), - profile.getStoreAddress(), - profile.getStoreAddressDetail(), - profile.getFarmAddress(), - profile.getFarmAddressDetail() + profile.getProfileImage() ); } } \ No newline at end of file diff --git a/src/main/java/poomasi/domain/member/_profile/dto/response/MemberProfileResponse.java b/src/main/java/poomasi/domain/member/_profile/dto/response/MemberProfileResponse.java index b191dda0..691d8673 100644 --- a/src/main/java/poomasi/domain/member/_profile/dto/response/MemberProfileResponse.java +++ b/src/main/java/poomasi/domain/member/_profile/dto/response/MemberProfileResponse.java @@ -1,18 +1,31 @@ package poomasi.domain.member._profile.dto.response; -import poomasi.domain.member._profile.entity.CustomerProfile; -import poomasi.domain.member._profile.entity.FarmerProfile; +import poomasi.domain.image.entity.Image; import poomasi.domain.member._profile.entity.MemberProfile; -public interface MemberProfileResponse { +import java.time.LocalDateTime; - static MemberProfileResponse fromEntity(MemberProfile profile) { - if (profile instanceof FarmerProfile farmerProfile) { - return FarmerProfileResponse.fromEntity(farmerProfile); - } else if (profile instanceof CustomerProfile customerProfile) { - return CustomerProfileResponse.fromEntity(customerProfile); - } else { - return CommonProfileResponse.fromEntity(profile); - } +public record MemberProfileResponse( + String phoneNumber, + String defaultAddress, + String addressDetail, + Long coordinateX, + Long coordinateY, + boolean isBanned, + LocalDateTime createdAt, + Image profileImage){ + + + public static MemberProfileResponse fromEntity(MemberProfile profile) { + return new MemberProfileResponse( + profile.getPhoneNumber(), + profile.getDefaultAddress(), + profile.getAddressDetail(), + profile.getCoordinateX(), + profile.getCoordinateY(), + profile.isBanned(), + profile.getCreatedAt(), + profile.getProfileImage() + ); } } \ No newline at end of file diff --git a/src/main/java/poomasi/domain/member/_profile/entity/CustomerProfile.java b/src/main/java/poomasi/domain/member/_profile/entity/CustomerProfile.java deleted file mode 100644 index ea7b83ad..00000000 --- a/src/main/java/poomasi/domain/member/_profile/entity/CustomerProfile.java +++ /dev/null @@ -1,23 +0,0 @@ -package poomasi.domain.member._profile.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.Getter; - -@Entity -@Getter -@DiscriminatorValue("CUSTOMER") -public class CustomerProfile extends MemberProfile{ - @Column(nullable = true, length = 255) - private String address; - - @Column(nullable = true, length = 255) - private String addressDetail; - - @Column(nullable=true, length=255) - private Long coordinateX; - - @Column(nullable=true, length=255) - private Long coordinateY; -} diff --git a/src/main/java/poomasi/domain/member/_profile/entity/FarmerProfile.java b/src/main/java/poomasi/domain/member/_profile/entity/FarmerProfile.java deleted file mode 100644 index 06b946c7..00000000 --- a/src/main/java/poomasi/domain/member/_profile/entity/FarmerProfile.java +++ /dev/null @@ -1,47 +0,0 @@ -package poomasi.domain.member._profile.entity; - -import jakarta.persistence.*; -import lombok.Getter; - -import java.util.List; - -@Entity -@Getter -@DiscriminatorValue("FARMER") -public class FarmerProfile extends MemberProfile{ - @Column(nullable = true, length = 100, unique = true) - private String storeName; - - @Column(nullable = true, length = 100) - private String storeAddress; - - @Column(nullable = true, length = 100) - private String storeAddressDetail; - - @Column(nullable=true, length=100) - private Long storeCoordinateX; - - @Column(nullable=true, length=100) - private Long storeCoordinateY; - - @Column(nullable = true, length = 100, unique = true) - private String farmName; - - @Column(nullable = true, length = 100) - private String farmAddress; - - @Column(nullable = true, length = 100) - private String farmAddressDetail; - - @Column(nullable=true, length=100) - private Long farmCoordinateX; - - @Column(nullable=true, length=100) - private Long farmCoordinateY; - - @ElementCollection - @CollectionTable(name = "business_registration_numbers", joinColumns = @JoinColumn(name = "farmer_profile_id")) - @Column(nullable = true, length=255) - private List businessRegistrationNumbers; - -} diff --git a/src/main/java/poomasi/domain/member/_profile/entity/MemberProfile.java b/src/main/java/poomasi/domain/member/_profile/entity/MemberProfile.java index af2b5849..05a969c1 100644 --- a/src/main/java/poomasi/domain/member/_profile/entity/MemberProfile.java +++ b/src/main/java/poomasi/domain/member/_profile/entity/MemberProfile.java @@ -2,8 +2,8 @@ import jakarta.persistence.*; import lombok.*; +import org.hibernate.annotations.SQLDelete; import poomasi.domain.image.entity.Image; -import poomasi.domain.member.entity.Member; import java.time.LocalDateTime; @@ -12,14 +12,14 @@ @Table(name = "member_profile") @AllArgsConstructor @Builder -@Inheritance(strategy = InheritanceType.JOINED) -@DiscriminatorColumn(name = "profile_type") +@SQLDelete(sql = "UPDATE member_profile SET deleted_at = current_timestamp WHERE id = ?") public class MemberProfile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Setter @Column(nullable = true, length = 20) private String phoneNumber; @@ -30,21 +30,55 @@ public class MemberProfile { @Column(nullable = false) private LocalDateTime createdAt; + @Setter + @Column + private LocalDateTime deletedAt; + @Setter @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "profile_image_id") private Image profileImage; - @Setter - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", referencedColumnName = "id") - private Member member; + // 기본 배송지 + @Column(nullable = true, length = 255) + private String defaultAddress; + + @Column(nullable = true, length = 255) + private String addressDetail; + + @Column(nullable=true, length=255) + private Long coordinateX; + + @Column(nullable=true, length=255) + private Long coordinateY; @PrePersist public void prePersist() { this.createdAt = LocalDateTime.now(); } + @PreRemove + public void preRemove() { + // MemberProfile이 삭제되기 전에 연관된 이미지를 삭제 + if (profileImage != null) { + profileImage.setDeletedAt(LocalDateTime.now()); + } + } + public MemberProfile() { } + + public void setAddress( + String defaultAddress, + String addressDetail, + Long coordinateX, + Long coordinateY) { + if (defaultAddress != null) this.defaultAddress = defaultAddress; + if (addressDetail != null) this.addressDetail = addressDetail; + if (coordinateX != null) this.coordinateX = coordinateX; + if (coordinateY != null) this.coordinateY = coordinateY; + + } + + } diff --git a/src/main/java/poomasi/domain/member/_profile/repository/MemberProfileRepository.java b/src/main/java/poomasi/domain/member/_profile/repository/MemberProfileRepository.java index f59a2490..433f671c 100644 --- a/src/main/java/poomasi/domain/member/_profile/repository/MemberProfileRepository.java +++ b/src/main/java/poomasi/domain/member/_profile/repository/MemberProfileRepository.java @@ -1,19 +1,9 @@ package poomasi.domain.member._profile.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import poomasi.domain.member._profile.entity.FarmerProfile; import poomasi.domain.member._profile.entity.MemberProfile; -import java.util.Optional; - @Repository public interface MemberProfileRepository extends JpaRepository { - - // FarmerProfile 타입만 조회 -// @Query("SELECT p FROM FarmerProfile p WHERE p.farmName = :farmName") -// Optional findFarmerByFarmName(@Param("farmName") String farmName); - } \ No newline at end of file diff --git a/src/main/java/poomasi/domain/member/controller/MemberController.java b/src/main/java/poomasi/domain/member/controller/MemberController.java index 2ee754f3..19de271e 100644 --- a/src/main/java/poomasi/domain/member/controller/MemberController.java +++ b/src/main/java/poomasi/domain/member/controller/MemberController.java @@ -9,13 +9,13 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import poomasi.domain.auth.security.userdetail.UserDetailsImpl; -import poomasi.domain.member.dto.request.FarmerQualificationRequest; -import poomasi.domain.member.dto.response.MemberResponse; -import poomasi.domain.member.dto.response.MemberSummaryResponse; +import poomasi.domain.member._profile.dto.request.AddressUpdateRequest; +import poomasi.domain.member.dto.request.CustomerUpdateRequest; +import poomasi.domain.member.dto.request.FarmerUpdateRequest; +import poomasi.domain.member.dto.response.*; import poomasi.domain.member.entity.Member; import poomasi.domain.member.service.MemberService; import poomasi.domain.member.dto.request.SignupRequest; -import poomasi.domain.member.dto.response.SignUpResponse; @RestController @RequiredArgsConstructor @@ -32,10 +32,9 @@ public ResponseEntity signUp(@RequestBody SignupRequest signupRe @PutMapping("/toFarmer") @Secured("ROLE_CUSTOMER") - public ResponseEntity convertToFarmer(@AuthenticationPrincipal UserDetailsImpl userDetails, - @RequestBody FarmerQualificationRequest request) { + public ResponseEntity convertToFarmer(@AuthenticationPrincipal UserDetailsImpl userDetails) { Member member = userDetails.getMember(); - memberService.convertToFarmer(member, request.hasFarmerQualification()); + memberService.convertToFarmer(member); return ResponseEntity.noContent().build(); } @@ -75,5 +74,52 @@ public ResponseEntity getMemberSummaryById(@PathVariable return ResponseEntity.ok(memberSummaryResponse); } + @PutMapping("/customer/update") + @Secured("ROLE_CUSTOMER") + public ResponseEntity updateCustomer( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @RequestBody CustomerUpdateRequest customerUpdateRequest) { + + Member member = userDetails.getMember(); + Member updatedMember = memberService.updateCustomer(member, customerUpdateRequest); + + MemberResponse memberResponse = MemberResponse.fromEntity(updatedMember); + return ResponseEntity.ok(memberResponse); + } + + @PutMapping("/farmer/update") + @Secured("ROLE_FARMER") + public ResponseEntity updateFarmer( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @RequestBody FarmerUpdateRequest farmerUpdateRequest) { + + Member member = userDetails.getMember(); + Member updatedMember = memberService.updateFarmer(member, farmerUpdateRequest); + + FarmerResponse memberResponse = FarmerResponse.fromEntity(updatedMember); + return ResponseEntity.ok(memberResponse); + } + + @PutMapping("/customer/update/address") + @Secured("ROLE_CUSTOMER") + public ResponseEntity updateAddress( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @RequestBody AddressUpdateRequest addressUpdateRequest + ) { + Member member = userDetails.getMember(); + memberService.updateAddress(member, addressUpdateRequest); + return ResponseEntity.ok().build(); + } + + // 회원 탈퇴, 복구, 금지 + // s3스케줄러 구현하긴해야함 + + // 이미지 validator 타입 추가 + + // 이미지 업로드 실패할시 처리 + + + + } diff --git a/src/main/java/poomasi/domain/member/dto/request/CustomerUpdateRequest.java b/src/main/java/poomasi/domain/member/dto/request/CustomerUpdateRequest.java new file mode 100644 index 00000000..693da308 --- /dev/null +++ b/src/main/java/poomasi/domain/member/dto/request/CustomerUpdateRequest.java @@ -0,0 +1,8 @@ +package poomasi.domain.member.dto.request; + +public record CustomerUpdateRequest( + String name, + String email, + String password, + String phoneNumber) { +} diff --git a/src/main/java/poomasi/domain/member/dto/request/FarmerQualificationRequest.java b/src/main/java/poomasi/domain/member/dto/request/FarmerQualificationRequest.java deleted file mode 100644 index d4e6147d..00000000 --- a/src/main/java/poomasi/domain/member/dto/request/FarmerQualificationRequest.java +++ /dev/null @@ -1,3 +0,0 @@ -package poomasi.domain.member.dto.request; - -public record FarmerQualificationRequest(Boolean hasFarmerQualification) {} diff --git a/src/main/java/poomasi/domain/member/dto/request/FarmerUpdateRequest.java b/src/main/java/poomasi/domain/member/dto/request/FarmerUpdateRequest.java new file mode 100644 index 00000000..3e16d19a --- /dev/null +++ b/src/main/java/poomasi/domain/member/dto/request/FarmerUpdateRequest.java @@ -0,0 +1,10 @@ +package poomasi.domain.member.dto.request; + +public record FarmerUpdateRequest( + String name, + String email, + String password, + String phoneNumber, + String storeName, + String storeAddress) { +} diff --git a/src/main/java/poomasi/domain/member/dto/response/FarmerResponse.java b/src/main/java/poomasi/domain/member/dto/response/FarmerResponse.java new file mode 100644 index 00000000..4544c1eb --- /dev/null +++ b/src/main/java/poomasi/domain/member/dto/response/FarmerResponse.java @@ -0,0 +1,22 @@ +package poomasi.domain.member.dto.response; + +import poomasi.domain.member._profile.dto.response.FarmerProfileResponse; +import poomasi.domain.member.entity.Member; + +public record FarmerResponse( + Long id, + String name, + String email, + String role, + FarmerProfileResponse memberProfile +) { + public static FarmerResponse fromEntity(Member member) { + return new FarmerResponse( + member.getId(), + member.getName(), + member.getEmail(), + member.getRole().name(), + member.getMemberProfile() != null ? FarmerProfileResponse.fromEntity(member.getMemberProfile()) : null + ); + } +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/member/dto/response/MemberSummaryResponse.java b/src/main/java/poomasi/domain/member/dto/response/MemberSummaryResponse.java index f57c1bfa..e26fa705 100644 --- a/src/main/java/poomasi/domain/member/dto/response/MemberSummaryResponse.java +++ b/src/main/java/poomasi/domain/member/dto/response/MemberSummaryResponse.java @@ -7,7 +7,7 @@ public record MemberSummaryResponse(String name, Image profileImage) { public static MemberSummaryResponse fromEntity(Member member) { return new MemberSummaryResponse( member.getName(), - member.getMemberProfile().getProfileImage() + member.getMemberProfile() != null ? member.getMemberProfile().getProfileImage() : null ); } } diff --git a/src/main/java/poomasi/domain/member/entity/Member.java b/src/main/java/poomasi/domain/member/entity/Member.java index 2292127a..5849d00d 100644 --- a/src/main/java/poomasi/domain/member/entity/Member.java +++ b/src/main/java/poomasi/domain/member/entity/Member.java @@ -9,11 +9,7 @@ import org.hibernate.annotations.SQLDelete; import poomasi.domain.store.entity.Store; import poomasi.domain.member._profile.entity.MemberProfile; -import poomasi.domain.store.entity.Store; import poomasi.domain.order.entity._product.ProductOrder; -import poomasi.domain.store.entity.Store; -import poomasi.domain.member._profile.entity.MemberProfile; -import poomasi.domain.store.entity.Store; import poomasi.domain.wishlist.entity.WishList; import poomasi.global.error.BusinessError; import poomasi.global.error.BusinessException; @@ -30,12 +26,15 @@ public class Member { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Setter @Column(nullable = true, length = 50) private String name; + @Setter @Column(unique = true, nullable = true, length = 50) private String email; + @Setter @Column(nullable = true) private String password; @@ -52,7 +51,7 @@ public class Member { @Column(nullable = true) private String provideId; - @OneToOne(mappedBy = "member", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY) private MemberProfile memberProfile; @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @@ -70,7 +69,7 @@ public class Member { @Setter @OneToOne(mappedBy="owner", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - Store store; + private Store store; public Member(String name, String email, String password, LoginType loginType, Role role) { this.name = name; @@ -78,18 +77,7 @@ public Member(String name, String email, String password, LoginType loginType, R this.password = password; this.loginType = loginType; this.role = role; - } - - public Member(String email, Role role) { - this.email = email; - this.role = role; - } - - public void setMemberProfile(MemberProfile memberProfile) { - this.memberProfile = memberProfile; - if (memberProfile != null) { - memberProfile.setMember(this); - } + this.memberProfile = getOrCreateProfile(); } @Builder @@ -121,4 +109,21 @@ public Store getStore() { return store; } + public MemberProfile getOrCreateProfile() { + if (this.memberProfile == null) { + this.memberProfile = new MemberProfile(); + } + return memberProfile; + } + + public Store getOrCreateStore() { + if (this.store == null) { + this.store = new Store(); + this.store.setOwner(this); + } + return store; + } + + + } diff --git a/src/main/java/poomasi/domain/member/service/MemberService.java b/src/main/java/poomasi/domain/member/service/MemberService.java index c386ee3c..8d48c257 100644 --- a/src/main/java/poomasi/domain/member/service/MemberService.java +++ b/src/main/java/poomasi/domain/member/service/MemberService.java @@ -7,6 +7,10 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import poomasi.domain.member._profile.dto.request.AddressUpdateRequest; +import poomasi.domain.member._profile.entity.MemberProfile; +import poomasi.domain.member.dto.request.CustomerUpdateRequest; +import poomasi.domain.member.dto.request.FarmerUpdateRequest; import poomasi.domain.member.dto.response.MemberResponse; import poomasi.domain.member.dto.response.MemberSummaryResponse; import poomasi.domain.member.entity.LoginType; @@ -14,8 +18,11 @@ import poomasi.domain.member.repository.MemberRepository; import poomasi.domain.member.dto.request.SignupRequest; import poomasi.domain.member.dto.response.SignUpResponse; +import poomasi.domain.store.entity.Store; import poomasi.global.error.BusinessException; +import java.util.Optional; + import static poomasi.domain.member.entity.Role.ROLE_CUSTOMER; import static poomasi.domain.member.entity.Role.ROLE_FARMER; import static poomasi.global.error.BusinessError.*; @@ -63,15 +70,11 @@ public Page getAllMembersSummary(Pageable pageable) { } @Transactional - public void convertToFarmer(Member member, Boolean hasFarmerQualification) { + public void convertToFarmer(Member member) { if (member.isFarmer()) { throw new BusinessException(MEMBER_ALREADY_FARMER); } - if (!hasFarmerQualification) { - throw new BusinessException(INVALID_FARMER_QUALIFICATION); - } - member.setRole(ROLE_FARMER); memberRepository.save(member); } @@ -93,4 +96,57 @@ public Member findMemberById(Long memberId) { .orElseThrow(() -> new BusinessException(MEMBER_NOT_FOUND)); } + @Transactional + public Member updateCustomer(Member member, CustomerUpdateRequest customerUpdateRequest) + { + if (!member.isCustomer()) { + throw new BusinessException(INVALID_ROLE); + } + + updateCommonAttributes(member, customerUpdateRequest.name(),customerUpdateRequest.email(), customerUpdateRequest.password(), customerUpdateRequest.phoneNumber()); + + return memberRepository.save(member); + } + + @Transactional + public Member updateFarmer(Member member, FarmerUpdateRequest farmerUpdateRequest) + { + if (!member.isFarmer()) { + throw new BusinessException(INVALID_ROLE); + } + + updateCommonAttributes(member, farmerUpdateRequest.name(), farmerUpdateRequest.email(), farmerUpdateRequest.password(), farmerUpdateRequest.phoneNumber()); + + Store store = member.getOrCreateStore(); + + if (farmerUpdateRequest.storeName() != null) { + store.setName(farmerUpdateRequest.storeName()); + } + if (farmerUpdateRequest.storeAddress() != null) { + store.setAddress(farmerUpdateRequest.storeAddress()); + } + + return memberRepository.save(member); + } + + private void updateCommonAttributes(Member member, String name, String email, String password, String phoneNumber) { + if (name != null) member.setName(name); + if (email != null) member.setEmail(email); + if (password != null) member.setPassword(passwordEncoder.encode(password)); + + MemberProfile profile = member.getOrCreateProfile(); + if (phoneNumber != null) { + profile.setPhoneNumber(phoneNumber); + } + } + + @Transactional + public void updateAddress(Member member, AddressUpdateRequest request) { + MemberProfile profile = member.getOrCreateProfile(); + + profile.setAddress(request.defaultAddress(), request.addressDetail(), request.coordinateX(), request.coordinateY()); + + memberRepository.save(member); + } + } diff --git a/src/main/java/poomasi/domain/product/entity/Product.java b/src/main/java/poomasi/domain/product/entity/Product.java index cd80bfbc..fcb8d69e 100644 --- a/src/main/java/poomasi/domain/product/entity/Product.java +++ b/src/main/java/poomasi/domain/product/entity/Product.java @@ -8,6 +8,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import org.hibernate.annotations.Comment; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; @@ -38,6 +39,7 @@ public class Product { @Comment("상품 설명") private String description; + @Setter @Comment("이미지 URL") private String imageUrl; @@ -77,6 +79,13 @@ public class Product { @JoinColumn(name = "order_product_details_id") private List orderProductDetails; +// @PreRemove +// public void preRemove() { +// // Product가 삭제되기 전에 연관된 이미지를 삭제 +// for (Image image : images) { +// image.setDeletedAt(LocalDateTime.now()); +// } +// } @Builder public Product(Long productId, diff --git a/src/main/java/poomasi/domain/product/service/ProductService.java b/src/main/java/poomasi/domain/product/service/ProductService.java index 79b73dca..f2b75ce1 100644 --- a/src/main/java/poomasi/domain/product/service/ProductService.java +++ b/src/main/java/poomasi/domain/product/service/ProductService.java @@ -39,4 +39,8 @@ public Product findProductById(Long productId) { return productRepository.findByIdAndDeletedAtIsNull(productId) .orElseThrow(() -> new BusinessException(BusinessError.PRODUCT_NOT_FOUND)); } + + public void saveExistedProduct(Product product) { + productRepository.save(product); + } } diff --git a/src/main/java/poomasi/domain/store/entity/Store.java b/src/main/java/poomasi/domain/store/entity/Store.java index c4be3f96..84d24c95 100644 --- a/src/main/java/poomasi/domain/store/entity/Store.java +++ b/src/main/java/poomasi/domain/store/entity/Store.java @@ -13,6 +13,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import org.hibernate.annotations.Comment; import poomasi.domain.member.entity.Member; import poomasi.domain.store.dto.StoreRegisterRequest; @@ -26,10 +27,15 @@ public class Store { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + @Setter private String name; + + @Setter private String address; private String phone; + @Setter @OneToOne(fetch = FetchType.LAZY) private Member owner; diff --git a/src/main/java/poomasi/global/config/s3/S3PresignedUrlController.java b/src/main/java/poomasi/global/config/s3/S3PresignedUrlController.java index 44f5e52b..46b49f7b 100644 --- a/src/main/java/poomasi/global/config/s3/S3PresignedUrlController.java +++ b/src/main/java/poomasi/global/config/s3/S3PresignedUrlController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.*; import poomasi.global.config.aws.AwsProperties; import poomasi.global.config.s3.dto.request.PresignedUrlPutRequest; +import poomasi.global.config.s3.dto.response.PresignedPutUrlResponse; @RestController @RequiredArgsConstructor @@ -24,7 +25,10 @@ public ResponseEntity presignedUrlGet(@RequestParam String keyname) { @PostMapping("/presigned-url-put") @Secured({"ROLE_CUSTOMER", "ROLE_FARMER", "ROLE_ADMIN"}) public ResponseEntity presignedUrlPut(@RequestBody PresignedUrlPutRequest request) { - String presignedPutUrl = s3PresignedUrlService.createPresignedPutUrl(awsProperties.getS3().getBucket(), request.keyPrefix(), request.metadata()); + PresignedPutUrlResponse presignedPutUrl = s3PresignedUrlService.createPresignedPutUrl( + awsProperties.getS3().getBucket(), + awsProperties.getS3().getRegion(), + request.keyPrefix(), request.metadata()); return ResponseEntity.ok(presignedPutUrl); } } diff --git a/src/main/java/poomasi/global/config/s3/S3PresignedUrlService.java b/src/main/java/poomasi/global/config/s3/S3PresignedUrlService.java index 241375f3..b8541f7d 100644 --- a/src/main/java/poomasi/global/config/s3/S3PresignedUrlService.java +++ b/src/main/java/poomasi/global/config/s3/S3PresignedUrlService.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import poomasi.global.config.s3.dto.response.PresignedPutUrlResponse; import poomasi.global.util.EncryptionUtil; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectRequest; @@ -46,14 +47,13 @@ public String createPresignedGetUrl(String bucketName, String keyName) { } - public String createPresignedPutUrl(String bucketName, String keyPrefix, Map metadata) { + public PresignedPutUrlResponse createPresignedPutUrl(String bucketName, String region, String keyPrefix, Map metadata) { LocalDateTime now = LocalDateTime.now(); String date = now.format(DATE_FORMATTER); String encodedTime = encryptionUtil.encodeTime(now).substring(0, 10); // jpg 말고 다른 형식 파일 들어오는 경우에 대해서도 따로 처리 필요 // 사진 갯수 5개로 제한하기 - // 극악의 확률로 url이 겹치면?? -> 그럴일 거의 없긴할텐데 생기면 s3 원래 파일 지워짐 String uniqueIdentifier = UUID.randomUUID().toString(); String keyName = String.format("%s/%s/%s_%s.jpg", keyPrefix, date, uniqueIdentifier, encodedTime); @@ -74,7 +74,9 @@ public String createPresignedPutUrl(String bucketName, String keyPrefix, Map metadata = new HashMap<>(); - metadata.put("Content-Type", "image/jpg"); - metadata.put("x-amz-meta-title", "Test Image"); - - // presigned PUT URL 생성 - String presignedUrl = s3PresignedUrlService.createPresignedPutUrl(bucketName, keyPrefix, metadata); - - assertNotNull(presignedUrl); - System.out.println("Presigned PUT URL: " + presignedUrl); - } +// @BeforeEach +// public void setUp() { +// String accessKey = awsProperties.getAccess(); +// String secretKey = awsProperties.getSecret(); +// String region = awsProperties.getS3().getRegion(); +// +// // 자격 증명 설정 +// AwsBasicCredentials awsCreds = AwsBasicCredentials.create( +// accessKey, +// secretKey +// ); +// +// // S3Presigner 인스턴스 생성 +// S3Presigner presigner = S3Presigner.builder() +// .credentialsProvider(StaticCredentialsProvider.create(awsCreds)) +// .region(Region.of(region)) +// .build(); +// +// // S3PresignedUrlService 초기화 +// s3PresignedUrlService = new S3PresignedUrlService(presigner, new EncryptionUtil()); +// } +// +// @Test +// public void testCreatePresignedGetUrl() { +// String objectKey = "object_key"; +// String bucketName = awsProperties.getS3().getBucket(); +// +// String presignedUrl = s3PresignedUrlService.createPresignedGetUrl(bucketName, objectKey); +// +// assertNotNull(presignedUrl); +// System.out.println("Presigned GET URL: " + presignedUrl); +// } +// +// @Test +// public void testCreatePresignedPutUrl() { +// String keyPrefix = "uploads"; +// String bucketName = awsProperties.getS3().getBucket(); +// +// // 메타데이터 생성 +// Map metadata = new HashMap<>(); +// metadata.put("Content-Type", "image/jpg"); +// metadata.put("x-amz-meta-title", "Test Image"); +// +// // presigned PUT URL 생성 +// String presignedUrl = s3PresignedUrlService.createPresignedPutUrl(bucketName, keyPrefix, metadata); +// +// assertNotNull(presignedUrl); +// System.out.println("Presigned PUT URL: " + presignedUrl); +// } }