Skip to content

Commit

Permalink
✨ [STMT-263] 활동 수정 API 구현 (#142)
Browse files Browse the repository at this point in the history
* ✨ [STMT-263] 에러 전역 처리기: 에러 추적 결과 출력 기능 추가

* ✨ [STMT-263] activity 수정 메서드 구현

* ✨ [STMT-263] activity image update 기능 구현

* ✨ [STMT-263] activity participant update 기능 추가

* ♻️ [STMT-263] activity create -> save 이름 변경

* ✨ [STMT-263] activity 수정 API 구현

* ♻️ [STMT-263] activityCreateSource -> activitySource 이름 변경

* ✅ [STMT-263] DEFAULT 유형의 활동의 setup 데이터에서 기한 제거

* ♻️ [STMT-263] modify -> update로 클래스 이름 변경

* ♻️ [STMT-263] period 검증 로직을 Activity 클래스에 공통 메서드로 추출

* ✅ [STMT-263] 활동 수정 API 테스트 케이스 작성

* 🐛 [STMT-263] isAuthor 메서드 접근 제한자 변경
  • Loading branch information
05AM authored Jul 26, 2024
1 parent a5c6b66 commit c1a4749
Show file tree
Hide file tree
Showing 24 changed files with 669 additions and 220 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.stumeet.server.activity.adapter.in;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.stumeet.server.activity.application.port.in.ActivityUpdateUseCase;
import com.stumeet.server.activity.application.port.in.command.ActivityUpdateCommand;
import com.stumeet.server.common.annotation.WebAdapter;
import com.stumeet.server.common.auth.model.LoginMember;
import com.stumeet.server.common.model.ApiResponse;
import com.stumeet.server.common.response.SuccessCode;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@WebAdapter
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class ActivityUpdateApi {

private final ActivityUpdateUseCase activityUpdateUseCase;

@PatchMapping("/studies/{studyId}/activities/{activityId}")
public ResponseEntity<ApiResponse<Void>> update(
@AuthenticationPrincipal LoginMember loginMember,
@PathVariable Long studyId,
@PathVariable Long activityId,
@RequestBody @Valid ActivityUpdateCommand command
) {
activityUpdateUseCase.update(loginMember.getId(), studyId, activityId, command);

return ResponseEntity.status(HttpStatus.OK)
.body(ApiResponse.success(SuccessCode.UPDATE_SUCCESS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.stumeet.server.activity.adapter.out.model.ActivityJpaEntity;
import com.stumeet.server.activity.adapter.out.model.ActivityLinkedStudyJpaEntity;
import com.stumeet.server.activity.adapter.out.model.ActivityMemberJpaEntity;
import com.stumeet.server.activity.application.service.model.ActivityCreateSource;
import com.stumeet.server.activity.application.service.model.ActivitySource;
import com.stumeet.server.activity.domain.model.Activity;
import com.stumeet.server.activity.domain.model.Meet;

Expand All @@ -17,9 +17,9 @@
public class ActivityPersistenceMapper {

public Activity toDomain(ActivityJpaEntity entity) {
ActivityCreateSource request = ActivityCreateSource.builder()
ActivitySource request = ActivitySource.builder()
.id(entity.getId())
.author(ActivityCreateSource.ActivityMemberCreateSource.builder()
.author(ActivitySource.ActivityMemberCreateSource.builder()
.id(entity.getAuthor().getId())
.name(entity.getAuthor().getName())
.image(entity.getAuthor().getImage())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@ public void deleteAllByActivityId(Long studyId, Long activityId) {
jpaActivityImageRepository.deleteAllByActivityId(activityId);
EventPublisher.raise(new ActivityImageDeleteEvent(this, studyId, activityId));
}

@Override
public void update(Long activityId, List<ActivityImage> activityImages) {
jpaActivityImageRepository.deleteAllByActivityId(activityId);
create(activityImages);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,10 @@ public List<ActivityParticipant> findAllByActivityId(Long activityId) {
public void deleteByActivityId(Long activityId) {
jpaActivityParticipantRepository.deleteAllByActivityId(activityId);
}

@Override
public void update(Long activityId, List<ActivityParticipant> participants) {
deleteByActivityId(activityId);
create(participants);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import com.stumeet.server.activity.adapter.out.mapper.ActivityPersistenceMapper;
import com.stumeet.server.activity.adapter.out.model.ActivityJpaEntity;
import com.stumeet.server.activity.application.port.out.ActivityAuthorValidationPort;
import com.stumeet.server.activity.application.port.out.ActivityCreatePort;
import com.stumeet.server.activity.application.port.out.ActivitySavePort;
import com.stumeet.server.activity.application.port.out.ActivityDeletePort;
import com.stumeet.server.activity.application.port.out.ActivityQueryPort;
import com.stumeet.server.activity.domain.exception.NotExistsActivityException;
Expand All @@ -22,54 +22,54 @@

@PersistenceAdapter
@RequiredArgsConstructor
public class ActivityPersistenceAdapter implements ActivityCreatePort, ActivityQueryPort, ActivityAuthorValidationPort, ActivityDeletePort {

private final JpaActivityRepository jpaActivityRepository;
private final ActivityPersistenceMapper activityPersistenceMapper;

@Override
public Activity create(Activity activity) {
ActivityJpaEntity entity = activityPersistenceMapper.toEntity(activity);

return activityPersistenceMapper.toDomain(jpaActivityRepository.save(entity));
}

@Override
public Activity getById(Long activityId) {
ActivityJpaEntity entity = jpaActivityRepository.findById(activityId)
.orElseThrow(() -> new NotExistsActivityException(activityId));

return activityPersistenceMapper.toDomain(entity);
}

@Override
public Page<Activity> getDetailPagesByCondition(Pageable pageable, Boolean isNotice, Long studyId, ActivityCategory category) {
Page<ActivityJpaEntity> entities =
jpaActivityRepository.findDetailPagesByCondition(pageable, isNotice, studyId, category);

return activityPersistenceMapper.toDomainPages(entities);
}

@Override
public Page<ActivityListBriefResponse> getPaginatedBriefsByCondition(Pageable pageable, Boolean isNotice, Long memberId,
Long studyId, ActivityCategory category, LocalDateTime startDate, LocalDateTime endDate) {
return jpaActivityRepository.findBriefsByConditionWithPagination(pageable, isNotice, memberId, studyId, category, startDate, endDate);
}

@Override
public List<ActivityListBriefResponse> getBriefsByCondition(Boolean isNotice, Long memberId, Long studyId,
ActivityCategory category, LocalDateTime startDate, LocalDateTime endDate) {
return jpaActivityRepository.findBriefsByCondition(isNotice, memberId, studyId, category, startDate, endDate);
}

@Override
public boolean isNotActivityAuthor(Long memberId, Long activityId) {
return jpaActivityRepository.findByIdAndAuthorId(activityId, memberId)
.isEmpty();
}

@Override
public void deleteById(Long activityId) {
jpaActivityRepository.deleteById(activityId);
}
public class ActivityPersistenceAdapter implements ActivitySavePort, ActivityQueryPort, ActivityAuthorValidationPort, ActivityDeletePort {

private final JpaActivityRepository jpaActivityRepository;
private final ActivityPersistenceMapper activityPersistenceMapper;

@Override
public Activity save(Activity activity) {
ActivityJpaEntity entity = activityPersistenceMapper.toEntity(activity);

return activityPersistenceMapper.toDomain(jpaActivityRepository.save(entity));
}

@Override
public Activity getById(Long activityId) {
ActivityJpaEntity entity = jpaActivityRepository.findById(activityId)
.orElseThrow(() -> new NotExistsActivityException(activityId));

return activityPersistenceMapper.toDomain(entity);
}

@Override
public Page<Activity> getDetailPagesByCondition(Pageable pageable, Boolean isNotice, Long studyId, ActivityCategory category) {
Page<ActivityJpaEntity> entities =
jpaActivityRepository.findDetailPagesByCondition(pageable, isNotice, studyId, category);

return activityPersistenceMapper.toDomainPages(entities);
}

@Override
public Page<ActivityListBriefResponse> getPaginatedBriefsByCondition(Pageable pageable, Boolean isNotice, Long memberId,
Long studyId, ActivityCategory category, LocalDateTime startDate, LocalDateTime endDate) {
return jpaActivityRepository.findBriefsByConditionWithPagination(pageable, isNotice, memberId, studyId, category, startDate, endDate);
}

@Override
public List<ActivityListBriefResponse> getBriefsByCondition(Boolean isNotice, Long memberId, Long studyId,
ActivityCategory category, LocalDateTime startDate, LocalDateTime endDate) {
return jpaActivityRepository.findBriefsByCondition(isNotice, memberId, studyId, category, startDate, endDate);
}

@Override
public boolean isNotActivityAuthor(Long memberId, Long activityId) {
return jpaActivityRepository.findByIdAndAuthorId(activityId, memberId)
.isEmpty();
}

@Override
public void deleteById(Long activityId) {
jpaActivityRepository.deleteById(activityId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stumeet.server.activity.application.port.in;

import com.stumeet.server.activity.application.port.in.command.ActivityUpdateCommand;

public interface ActivityUpdateUseCase {

void update(Long memberId, Long studyId, Long activityId, ActivityUpdateCommand command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.stumeet.server.activity.application.port.in.command;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.format.annotation.DateTimeFormat;

import com.stumeet.server.common.annotation.validator.NullOrNotBlank;

import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Builder;

@Builder
public record ActivityUpdateCommand(
@NotBlank(message = "활동 카테고리를 입력해주세요")
String category,

@NotBlank(message = "활동 제목을 입력해주세요")
@Size(max = 100, message = "활동 제목은 100자 이하여야 합니다")
String title,

@NotBlank(message = "활동 내용을 입력해주세요")
@Size(max = 500, message = "활동 내용은 500자 이하여야 합니다")
String content,

@NotNull(message = "이미지 리스트를 전달해주세요")
@Size(max = 5, message = "이미지는 5개 이하로 등록할 수 있습니다")
List<String> images,

boolean isNotice,

@Nullable
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime startDate,

@Nullable
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime endDate,

@NullOrNotBlank
String location,

@NullOrNotBlank
String link,

@NotNull(message = "참여 멤버 리스트를 전달해주세요")
List<Long> participants
) {
}
Loading

0 comments on commit c1a4749

Please sign in to comment.