Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Weekly/10] authorization 로직 추가 #72

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public enum ErrorCode {

FAIL_TO_READ_IMAGE(HttpStatus.CONFLICT.value(), "-20400", "Fail to read image"),

UNAUTHORIZED(HttpStatus.UNAUTHORIZED.value(), "-20400", "Unauthorized, %s id is not matched."),

ENTITY_PARAM_IS_NULL(HttpStatus.BAD_REQUEST.value(), "-20400", "%s is null");

private final Integer status;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.ktc2.cokaen.wouldyouin._common.exception;

import org.ktc2.cokaen.wouldyouin._common.error.ErrorCode;

public class UnauthorizedException extends BusinessException {

public UnauthorizedException(String message) {
super(message, ErrorCode.UNAUTHORIZED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import org.ktc2.cokaen.wouldyouin.advertisement.api.dto.AdvertisementRequest;
import org.ktc2.cokaen.wouldyouin.advertisement.api.dto.AdvertisementResponse;
import org.ktc2.cokaen.wouldyouin.advertisement.application.AdvertisementService;
import org.ktc2.cokaen.wouldyouin.auth.Authorize;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand Down Expand Up @@ -41,20 +44,24 @@ public ResponseEntity<ApiResponseBody<AdvertisementResponse>> getAdvertisementBy
@PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<ApiResponseBody<AdvertisementResponse>> createAdvertisement(
@Valid @RequestPart AdvertisementRequest advertisementRequest,
@RequestPart(required = false) MultipartFile image) {
@RequestPart(required = false) MultipartFile image,
@Authorize(MemberType.admin) MemberIdentifier memberIdentifier) {
return ApiResponse.created(advertisementService.create(advertisementRequest, image));
}

@PutMapping(path = "/{adId}", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<ApiResponseBody<AdvertisementResponse>> updateAdvertisement(
@PathVariable Long adId,
@Valid @RequestPart AdvertisementRequest advertisementRequest,
@RequestPart(required = false) MultipartFile image) {
@RequestPart(required = false) MultipartFile image,
@Authorize(MemberType.admin) MemberIdentifier memberIdentifier) {
return ApiResponse.ok(advertisementService.update(adId, advertisementRequest, image));
}

@DeleteMapping("/{adId}")
public ResponseEntity<ApiResponseBody<Void>> deleteAdvertisement(@PathVariable Long adId) {
public ResponseEntity<ApiResponseBody<Void>> deleteAdvertisement(
@PathVariable Long adId,
@Authorize(MemberType.admin) MemberIdentifier memberIdentifier) {
advertisementService.delete(adId);
return ApiResponse.noContent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponse;
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponseBody;
import org.ktc2.cokaen.wouldyouin._common.persist.Area;
import org.ktc2.cokaen.wouldyouin.auth.Authorize;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationCreateRequest;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationEditRequest;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationResponse;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationSliceResponse;
import org.ktc2.cokaen.wouldyouin.curation.application.CurationService;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -33,9 +35,9 @@ public class CurationController {
@GetMapping
public ResponseEntity<ApiResponseBody<CurationSliceResponse>> getCurationsByAreaOrderByCreatedDateDesc(
@RequestParam Area area,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page}") Integer page,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page-size}") Integer size,
@RequestParam(defaultValue = "${spring.controller.pageable.default-last-id}") Long lastId
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(defaultValue = Long.MAX_VALUE + "") Long lastId
) {
return ApiResponse.ok(curationService.getAllByAreaOrderByCreatedDateDesc(
area, PageRequest.of(page, size), lastId));
Expand All @@ -44,9 +46,9 @@ public ResponseEntity<ApiResponseBody<CurationSliceResponse>> getCurationsByArea
@GetMapping("/curators/{curatorId}")
public ResponseEntity<ApiResponseBody<CurationSliceResponse>> getCurationsByCuratorIdOrderByCreatedDateDesc(
@PathVariable("curatorId") Long curatorId,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page}") Integer page,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page-size}") Integer size,
@RequestParam(defaultValue = "${spring.controller.pageable.default-last-id}") Long lastId
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(defaultValue = Long.MAX_VALUE + "") Long lastId
) {
return ApiResponse.ok(curationService.getAllByCuratorIdOrderByCreatedDateDesc(
curatorId, PageRequest.of(page, size), lastId));
Expand All @@ -61,20 +63,23 @@ public ResponseEntity<ApiResponseBody<CurationResponse>> getCurationByCurationId
@PostMapping
public ResponseEntity<ApiResponseBody<CurationResponse>> createCuration(
@Valid @RequestBody CurationCreateRequest curationCreateRequest,
MemberIdentifier curator) {
@Authorize({MemberType.curator, MemberType.admin}) MemberIdentifier curator) {
return ApiResponse.created(curationService.create(curator.id(), curationCreateRequest));
}

@PutMapping("/{curationId}")
public ResponseEntity<ApiResponseBody<CurationResponse>> updateCuration(@PathVariable Long curationId,
public ResponseEntity<ApiResponseBody<CurationResponse>> updateCuration(
@PathVariable Long curationId,
@Valid @RequestBody CurationEditRequest curationEditRequest,
MemberIdentifier curator) {
return ApiResponse.ok(curationService.update(curator.id(), curationEditRequest));
@Authorize({MemberType.curator, MemberType.admin}) MemberIdentifier curator) {
return ApiResponse.ok(curationService.update(curator.id(), curationId, curationEditRequest));
}

@DeleteMapping("/{curationId}")
public ResponseEntity<ApiResponseBody<Void>> deleteCuration(@PathVariable Long curationId) {
curationService.delete(curationId);
public ResponseEntity<ApiResponseBody<Void>> deleteCuration(
@PathVariable Long curationId,
@Authorize({MemberType.curator, MemberType.admin}) MemberIdentifier curator) {
curationService.delete(curator.id(), curationId);
return ApiResponse.noContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin._common.persist.Area;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationCreateRequest;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.CurationEditRequest;
Expand Down Expand Up @@ -75,24 +76,32 @@ public CurationResponse create(Long curatorId, CurationCreateRequest curationCre
return CurationResponse.from(curation);
}

// Todo: 큐레이터 id 검증 로직 분리
@Transactional
public CurationResponse update(Long curationId, CurationEditRequest curationEditRequest) {
Curation target = getByIdOrThrow(curationId);
public CurationResponse update(Long curatorId, Long curationId, CurationEditRequest curationEditRequest) {
Curation curation = getByIdOrThrow(curationId);
if (curatorId != curation.getCurator().getId()) {
throw new UnauthorizedException("Curator");
}
List<CurationCard> curationCards = curationEditRequest.getCurationCards().stream()
.map(curationCardService::create)
.toList();
List<Event> events = curationEditRequest.getEventIds().stream()
.map(eventService::getByIdOrThrow)
.toList();
target.getCurationCards().forEach(card -> curationCardService.delete(card.getId()));
target.updateFrom(curationEditRequest, curationCards, events);
curationCards.forEach(curationCard -> curationCardService.setCuration(curationCard, target));
return CurationResponse.from(target);
curation.getCurationCards().forEach(card -> curationCardService.delete(card.getId()));
curation.updateFrom(curationEditRequest, curationCards, events);
curationCards.forEach(curationCard -> curationCardService.setCuration(curationCard, curation));
return CurationResponse.from(curation);
}

// Todo: 큐레이터 id 검증 로직 분리
@Transactional
public void delete(Long curationId) {
public void delete(Long curatorId, Long curationId) {
Curation curation = getByIdOrThrow(curationId);
if (curatorId != curation.getCurator().getId()) {
throw new UnauthorizedException("Curator");
}
curation.getCurationCards()
.forEach(curationCard -> curationCardService.delete(curationCard.getId()));
curationRepository.deleteById(curationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import org.ktc2.cokaen.wouldyouin._common.persist.Area;
import org.ktc2.cokaen.wouldyouin._common.persist.Category;
import org.ktc2.cokaen.wouldyouin._common.persist.Location;
import org.ktc2.cokaen.wouldyouin.auth.Authorize;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.curation.api.dto.LocationFilter;
import org.ktc2.cokaen.wouldyouin.event.api.dto.EventCreateRequest;
import org.ktc2.cokaen.wouldyouin.event.api.dto.EventEditRequest;
import org.ktc2.cokaen.wouldyouin.event.api.dto.EventResponse;
import org.ktc2.cokaen.wouldyouin.event.api.dto.EventSliceResponse;
import org.ktc2.cokaen.wouldyouin.event.application.EventService;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -38,21 +41,23 @@ public ResponseEntity<ApiResponseBody<EventSliceResponse>> getEventsByFilterOrde
@RequestParam Location currentLocation,
@RequestParam(defaultValue = "전체") Category category,
@RequestParam(defaultValue = "전체") Area area,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page}") Integer page,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page-size}") Integer size,
@RequestParam(defaultValue = "${spring.controller.pageable.default-last-id}") Long lastId
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(defaultValue = Long.MAX_VALUE + "") Long lastId
) {
return ApiResponse.ok(eventService.getAllByFilterOrderByDistanceAsc(locationFilter, currentLocation, category, area, PageRequest.of(page, size), lastId));
return ApiResponse.ok(eventService.getAllByFilterOrderByDistanceAsc(
locationFilter, currentLocation, category, area, PageRequest.of(page, size), lastId));
}

@GetMapping("/hosts/{hostId}")
public ResponseEntity<ApiResponseBody<EventSliceResponse>> getEventsByHostId(
@PathVariable Long hostId,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page}") Integer page,
@RequestParam(defaultValue = "${spring.controller.pageable.default-page-size}") Integer size,
@RequestParam(defaultValue = "${spring.controller.pageable.default-last-id}") Long lastId
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(defaultValue = Long.MAX_VALUE + "") Long lastId
) {
return ApiResponse.ok(eventService.getAllByHostIdOrderByCreatedDateDesc(hostId, PageRequest.of(page, size), lastId));
return ApiResponse.ok(eventService.getAllByHostIdOrderByCreatedDateDesc(
hostId, PageRequest.of(page, size), lastId));
}

@GetMapping("/{eventId}")
Expand All @@ -63,20 +68,23 @@ public ResponseEntity<ApiResponseBody<EventResponse>> getEventByEventId(

@PostMapping
public ResponseEntity<ApiResponseBody<EventResponse>> createEvent(
@Valid @RequestBody EventCreateRequest eventCreateRequest) {
return ApiResponse.created(eventService.create(eventCreateRequest));
@Valid @RequestBody EventCreateRequest eventCreateRequest,
@Authorize(MemberType.host) MemberIdentifier host) {
return ApiResponse.created(eventService.create(host.id(), eventCreateRequest));
}

@PutMapping("/{eventId}")
public ResponseEntity<ApiResponseBody<EventResponse>> updateEvent(@PathVariable Long eventId,
@Valid @RequestBody EventEditRequest eventEditRequest) {
return ApiResponse.ok(eventService.update(eventId, eventEditRequest));
@Valid @RequestBody EventEditRequest eventEditRequest,
@Authorize(MemberType.host) MemberIdentifier host) {
return ApiResponse.ok(eventService.update(host.id(), eventId, eventEditRequest));
}

@DeleteMapping("/{eventId}")
public ResponseEntity<ApiResponseBody<Void>> deleteEvent(
@PathVariable("eventId") Long eventId) {
eventService.delete(eventId);
@PathVariable("eventId") Long eventId,
@Authorize(MemberType.host) MemberIdentifier host) {
eventService.delete(host.id(), eventId);
return ApiResponse.noContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
@Builder
public class EventCreateRequest {

@NotNull(message = "hostId는 필수입니다.")
private Long hostId;

@NotBlank(message = "제목은 필수입니다.")
private String title;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.RequiredArgsConstructor;
import org.ktc2.cokaen.wouldyouin.Image.application.EventImageService;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin._common.persist.Area;
import org.ktc2.cokaen.wouldyouin._common.persist.Category;
import org.ktc2.cokaen.wouldyouin._common.persist.Location;
Expand Down Expand Up @@ -63,31 +64,40 @@ public Event getByIdOrThrow(Long id) throws EntityNotFoundException {
}

@Transactional
public EventResponse create(EventCreateRequest eventCreateRequest) {
return EventResponse.from(eventRepository.save(eventCreateRequest.toEntity(
hostService.getByIdOrThrow(eventCreateRequest.getHostId()),
public EventResponse create(Long hostId, EventCreateRequest eventCreateRequest) {
return EventResponse.from(
eventRepository.save(eventCreateRequest.toEntity(
hostService.getByIdOrThrow(hostId),
eventCreateRequest.getImageIds().stream()
.map(eventImageService::getById)
.toList())));
}

// Todo: 호스트 id 검증 로직 분리
@Transactional
public EventResponse update(Long id, EventEditRequest eventEditRequest) {
Event target = getByIdOrThrow(id);
target.updateFrom(eventEditRequest, eventEditRequest.getImageIds().stream()
public EventResponse update(Long hostId, Long eventId, EventEditRequest eventEditRequest) {
Event event = getByIdOrThrow(eventId);
if (hostId != event.getId()) {
throw new UnauthorizedException("Host");
}
event.updateFrom(eventEditRequest, eventEditRequest.getImageIds().stream()
.map(eventImageService::getById)
.toList());
return EventResponse.from(target);
return EventResponse.from(event);
}

// Todo: 호스트 id 검증 로직 분리
@Transactional
public void decreaseLeftSeat(Long id, Integer count) {
getByIdOrThrow(id).decreaseLeftSeat(count);
public void delete(Long hostId, Long eventId) {
Event event = getByIdOrThrow(eventId);
if (hostId != event.getId()) {
throw new UnauthorizedException("Host");
}
eventRepository.deleteById(eventId);
}

@Transactional
public void delete(Long id) {
getByIdOrThrow(id);
eventRepository.deleteById(id);
public void decreaseLeftSeat(Long id, Integer count) {
getByIdOrThrow(id).decreaseLeftSeat(count);
}
}