diff --git a/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java b/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java index a666b57..ca5ccec 100644 --- a/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java +++ b/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java @@ -33,7 +33,8 @@ public enum ErrorCode { DUPLICATE_EMAIL(CONFLICT, "이메일이 이미 존재합니다."), DUPLICATE_PAYMENT(CONFLICT, "해당 좌석은 현재 판매된 좌석입니다."), DUPLICATE_MOVIE(CONFLICT, "해당 영화 정보가 이미 존재합니다."), - DELETED_EMAIL(CONFLICT, "이미 삭제된 이메일 입니다."); + DELETED_EMAIL(CONFLICT, "이미 삭제된 이메일 입니다."), + DELETED_MOVIE(CONFLICT, "이미 삭제된 영화 입니다."); private final HttpStatus httpStatus; private final String detail; @@ -98,4 +99,8 @@ public enum ErrorCode { throw new TicketingException(DELETED_EMAIL); } + public static TicketingException throwDeletedMovie() { + throw new TicketingException(DELETED_MOVIE); + } + } diff --git a/server/src/main/java/com/ticketing/server/movie/application/MovieController.java b/server/src/main/java/com/ticketing/server/movie/application/MovieController.java index 570c890..5ab9090 100644 --- a/server/src/main/java/com/ticketing/server/movie/application/MovieController.java +++ b/server/src/main/java/com/ticketing/server/movie/application/MovieController.java @@ -1,8 +1,15 @@ package com.ticketing.server.movie.application; +import static com.ticketing.server.user.domain.UserGrade.ROLES.STAFF; + +import com.ticketing.server.movie.application.request.MovieDeleteRequest; import com.ticketing.server.movie.application.request.MovieRegisterRequest; +import com.ticketing.server.movie.application.response.MovieDeleteResponse; import com.ticketing.server.movie.application.response.MovieListResponse; -import com.ticketing.server.movie.application.response.MovieTitleResponse; +import com.ticketing.server.movie.application.response.MovieInfoResponse; +import com.ticketing.server.movie.service.dto.DeletedMovieDTO; +import com.ticketing.server.movie.service.dto.MovieListDTO; +import com.ticketing.server.movie.service.dto.RegisteredMovieDTO; import com.ticketing.server.movie.service.interfaces.MovieService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -12,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -29,25 +37,37 @@ public class MovieController { @PostMapping() @ApiOperation(value = "영화 정보 등록") - @Secured("ROLE_STAFF") - public ResponseEntity registerMovie(@RequestBody @Valid MovieRegisterRequest request) { + @Secured(STAFF) + public ResponseEntity registerMovie(@RequestBody @Valid MovieRegisterRequest request) { + RegisteredMovieDTO registeredMovieDto = + movieService.registerMovie(request.getTitle(), request.getRunningTime()); + return ResponseEntity.status(HttpStatus.OK) .body( - MovieTitleResponse.from( - movieService.registerMovie(request.toMovieRegisterDTO()) - ) + registeredMovieDto.toResponse() ); } @GetMapping() @ApiOperation(value = "영화 목록 조회") public ResponseEntity getMovies() { + MovieListDTO movieListDto = movieService.getMovies(); + return ResponseEntity.status(HttpStatus.OK) .body( - MovieListResponse.from( - movieService.getMovies() - ) + movieListDto.toResponse() ); } + @DeleteMapping() + @ApiOperation(value = "영화 정보 삭제") + @Secured(STAFF) + public ResponseEntity deleteMovie(@RequestBody @Valid MovieDeleteRequest request) { + DeletedMovieDTO deletedMovieDto = movieService.deleteMovie(request.getId()); + + return ResponseEntity.status(HttpStatus.OK) + .body( + deletedMovieDto.toResponse() + ); + } } diff --git a/server/src/main/java/com/ticketing/server/movie/application/request/MovieDeleteRequest.java b/server/src/main/java/com/ticketing/server/movie/application/request/MovieDeleteRequest.java new file mode 100644 index 0000000..8dfb859 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/application/request/MovieDeleteRequest.java @@ -0,0 +1,16 @@ +package com.ticketing.server.movie.application.request; + +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class MovieDeleteRequest { + + @NotNull(message = "{validation.not.null.id}") + private Long id; + +} diff --git a/server/src/main/java/com/ticketing/server/movie/application/response/MovieDeleteResponse.java b/server/src/main/java/com/ticketing/server/movie/application/response/MovieDeleteResponse.java new file mode 100644 index 0000000..9104bfd --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/application/response/MovieDeleteResponse.java @@ -0,0 +1,17 @@ +package com.ticketing.server.movie.application.response; + +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class MovieDeleteResponse { + + private final Long id; + + private final String title; + + private final LocalDateTime deletedAt; + +} diff --git a/server/src/main/java/com/ticketing/server/movie/application/response/MovieInfoResponse.java b/server/src/main/java/com/ticketing/server/movie/application/response/MovieInfoResponse.java new file mode 100644 index 0000000..b73e687 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/application/response/MovieInfoResponse.java @@ -0,0 +1,17 @@ +package com.ticketing.server.movie.application.response; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class MovieInfoResponse { + + @ApiModelProperty(value = "영화 ID") + private Long movieId; + + @ApiModelProperty(value = "영화 제목") + private String title; + +} diff --git a/server/src/main/java/com/ticketing/server/movie/application/response/MovieListResponse.java b/server/src/main/java/com/ticketing/server/movie/application/response/MovieListResponse.java index 5b3eab1..92c69af 100644 --- a/server/src/main/java/com/ticketing/server/movie/application/response/MovieListResponse.java +++ b/server/src/main/java/com/ticketing/server/movie/application/response/MovieListResponse.java @@ -3,19 +3,14 @@ package com.ticketing.server.movie.application.response; import com.ticketing.server.movie.service.dto.MovieDTO; import io.swagger.annotations.ApiModelProperty; import java.util.List; -import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor public class MovieListResponse { @ApiModelProperty(value = "영화 제목") private List movieDtos; - public static MovieListResponse from(List movieDtos) { - return new MovieListResponse(movieDtos); - } - } diff --git a/server/src/main/java/com/ticketing/server/movie/application/response/MovieTitleResponse.java b/server/src/main/java/com/ticketing/server/movie/application/response/MovieTitleResponse.java deleted file mode 100644 index aa056df..0000000 --- a/server/src/main/java/com/ticketing/server/movie/application/response/MovieTitleResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ticketing.server.movie.application.response; - -import com.ticketing.server.movie.service.dto.MovieDTO; -import io.swagger.annotations.ApiModelProperty; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) -public class MovieTitleResponse { - - @ApiModelProperty(value = "영화 제목") - private String title; - - public static MovieTitleResponse from(MovieDTO movieDto) { - return new MovieTitleResponse(movieDto.getTitle()); - } - -} diff --git a/server/src/main/java/com/ticketing/server/movie/domain/Movie.java b/server/src/main/java/com/ticketing/server/movie/domain/Movie.java index 9a10bbf..083a321 100644 --- a/server/src/main/java/com/ticketing/server/movie/domain/Movie.java +++ b/server/src/main/java/com/ticketing/server/movie/domain/Movie.java @@ -1,7 +1,9 @@ package com.ticketing.server.movie.domain; import com.ticketing.server.global.dto.repository.AbstractEntity; -import javax.persistence.Column; +import com.ticketing.server.global.exception.ErrorCode; +import com.ticketing.server.movie.service.dto.MovieDTO; +import java.time.LocalDateTime; import javax.persistence.Entity; import javax.validation.constraints.NotNull; import lombok.AccessLevel; @@ -16,7 +18,6 @@ import lombok.NoArgsConstructor; public class Movie extends AbstractEntity { @NotNull - @Column(unique = true) private String title; @NotNull @@ -28,4 +29,18 @@ public class Movie extends AbstractEntity { this.runningTime = runningTime; } + public Movie delete() { + if (deletedAt != null) { + throw ErrorCode.throwDeletedMovie(); + } + + deletedAt = LocalDateTime.now(); + + return this; + } + + public MovieDTO toMovieDTO() { + return new MovieDTO(this.id, this.title); + } + } diff --git a/server/src/main/java/com/ticketing/server/movie/domain/repository/MovieRepository.java b/server/src/main/java/com/ticketing/server/movie/domain/repository/MovieRepository.java index c1888a2..a48315d 100644 --- a/server/src/main/java/com/ticketing/server/movie/domain/repository/MovieRepository.java +++ b/server/src/main/java/com/ticketing/server/movie/domain/repository/MovieRepository.java @@ -13,6 +13,14 @@ public interface MovieRepository extends JpaRepository { Optional findByTitle(String title); + Optional findByIdAndDeletedAtNull(Long id); + + @Query(value = "SELECT m " + + "FROM Movie m " + + "WHERE title = :title " + + "AND deleted_at IS NULL") + Optional findValidMovieWithTitle(String title); + @Query(value = "SELECT * " + "FROM movie " + "WHERE deleted_at IS NULL", nativeQuery = true) diff --git a/server/src/main/java/com/ticketing/server/movie/service/MovieServiceImpl.java b/server/src/main/java/com/ticketing/server/movie/service/MovieServiceImpl.java index 1c142f0..593900a 100644 --- a/server/src/main/java/com/ticketing/server/movie/service/MovieServiceImpl.java +++ b/server/src/main/java/com/ticketing/server/movie/service/MovieServiceImpl.java @@ -3,12 +3,15 @@ package com.ticketing.server.movie.service; import com.ticketing.server.global.exception.ErrorCode; import com.ticketing.server.movie.domain.Movie; import com.ticketing.server.movie.domain.repository.MovieRepository; +import com.ticketing.server.movie.service.dto.DeletedMovieDTO; import com.ticketing.server.movie.service.dto.MovieDTO; -import com.ticketing.server.movie.service.dto.MovieRegisterDTO; +import com.ticketing.server.movie.service.dto.MovieListDTO; +import com.ticketing.server.movie.service.dto.RegisteredMovieDTO; import com.ticketing.server.movie.service.interfaces.MovieService; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import javax.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -21,24 +24,39 @@ public class MovieServiceImpl implements MovieService { private final MovieRepository movieRepository; @Override - public MovieDTO registerMovie(MovieRegisterDTO movieRegisterDto) { - Optional movie = movieRepository.findByTitle(movieRegisterDto.getTitle()); + public RegisteredMovieDTO registerMovie(String title, Long runningTime) { + Optional movie = movieRepository.findValidMovieWithTitle(title); if(movie.isEmpty()) { - return MovieDTO.from(movieRepository.save(movieRegisterDto.toMovie())); + Movie newMovie = movieRepository.save( + new Movie(title, runningTime) + ); + + return new RegisteredMovieDTO(newMovie); } throw ErrorCode.throwDuplicateMovie(); } @Override - public List getMovies() { + public MovieListDTO getMovies() { List movies = movieRepository.findValidMovies(); - return movies.stream() - .map(MovieDTO::from) + List movieDtos = movies.stream() + .map(movie -> movie.toMovieDTO()) .collect(Collectors.toList()); + return new MovieListDTO(movieDtos); } + @Override + @Transactional + public DeletedMovieDTO deleteMovie(Long id) { + Movie movie = movieRepository.findByIdAndDeletedAtNull(id) + .orElseThrow(ErrorCode::throwMovieNotFound); + + Movie deletedMovie = movie.delete(); + + return new DeletedMovieDTO(deletedMovie); + } } diff --git a/server/src/main/java/com/ticketing/server/movie/service/dto/DeletedMovieDTO.java b/server/src/main/java/com/ticketing/server/movie/service/dto/DeletedMovieDTO.java new file mode 100644 index 0000000..4725c7a --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/service/dto/DeletedMovieDTO.java @@ -0,0 +1,32 @@ +package com.ticketing.server.movie.service.dto; + +import com.ticketing.server.movie.application.response.MovieDeleteResponse; +import com.ticketing.server.movie.domain.Movie; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class DeletedMovieDTO { + + private final Long id; + + private final String title; + + private final LocalDateTime deletedAt; + + public DeletedMovieDTO(Movie movie) { + this( + movie.getId(), + movie.getTitle(), + movie.getDeletedAt() + ); + } + + public MovieDeleteResponse toResponse() { + return new MovieDeleteResponse(id, title, deletedAt); + } + +} diff --git a/server/src/main/java/com/ticketing/server/movie/service/dto/MovieDTO.java b/server/src/main/java/com/ticketing/server/movie/service/dto/MovieDTO.java index 546a5f4..b42c972 100644 --- a/server/src/main/java/com/ticketing/server/movie/service/dto/MovieDTO.java +++ b/server/src/main/java/com/ticketing/server/movie/service/dto/MovieDTO.java @@ -1,18 +1,14 @@ package com.ticketing.server.movie.service.dto; -import com.ticketing.server.movie.domain.Movie; -import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor public class MovieDTO { + private Long movieId; + private String title; - public static MovieDTO from(Movie movie) { - return new MovieDTO(movie.getTitle()); - } - } diff --git a/server/src/main/java/com/ticketing/server/movie/service/dto/MovieListDTO.java b/server/src/main/java/com/ticketing/server/movie/service/dto/MovieListDTO.java new file mode 100644 index 0000000..047fb3a --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/service/dto/MovieListDTO.java @@ -0,0 +1,18 @@ +package com.ticketing.server.movie.service.dto; + +import com.ticketing.server.movie.application.response.MovieListResponse; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor() +public class MovieListDTO { + + private final List movieDtos; + + public MovieListResponse toResponse() { + return new MovieListResponse(movieDtos); + } + +} diff --git a/server/src/main/java/com/ticketing/server/movie/service/dto/RegisteredMovieDTO.java b/server/src/main/java/com/ticketing/server/movie/service/dto/RegisteredMovieDTO.java new file mode 100644 index 0000000..6d98ad4 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/movie/service/dto/RegisteredMovieDTO.java @@ -0,0 +1,28 @@ +package com.ticketing.server.movie.service.dto; + +import com.ticketing.server.movie.application.response.MovieInfoResponse; +import com.ticketing.server.movie.domain.Movie; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class RegisteredMovieDTO { + + private final Long id; + + private final String title; + + public RegisteredMovieDTO(Movie movie) { + this( + movie.getId(), + movie.getTitle() + ); + } + + public MovieInfoResponse toResponse() { + return new MovieInfoResponse(id, title); + } + +} diff --git a/server/src/main/java/com/ticketing/server/movie/service/interfaces/MovieService.java b/server/src/main/java/com/ticketing/server/movie/service/interfaces/MovieService.java index cfad36c..ca461c7 100644 --- a/server/src/main/java/com/ticketing/server/movie/service/interfaces/MovieService.java +++ b/server/src/main/java/com/ticketing/server/movie/service/interfaces/MovieService.java @@ -1,13 +1,14 @@ package com.ticketing.server.movie.service.interfaces; -import com.ticketing.server.movie.service.dto.MovieDTO; -import com.ticketing.server.movie.service.dto.MovieRegisterDTO; -import java.util.List; +import com.ticketing.server.movie.service.dto.DeletedMovieDTO; +import com.ticketing.server.movie.service.dto.MovieListDTO; +import com.ticketing.server.movie.service.dto.RegisteredMovieDTO; public interface MovieService { - MovieDTO registerMovie(MovieRegisterDTO movieRegisterDto); + RegisteredMovieDTO registerMovie(String title, Long runningTime); - List getMovies(); + MovieListDTO getMovies(); + DeletedMovieDTO deleteMovie(Long id); } diff --git a/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java b/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java index 522346d..f4e577f 100644 --- a/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java +++ b/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java @@ -3,11 +3,11 @@ package com.ticketing.server.user.service.interfaces; import com.ticketing.server.user.domain.ChangeGradeDTO; import com.ticketing.server.user.domain.User; import com.ticketing.server.user.domain.UserGrade; -import com.ticketing.server.user.service.dto.ChangePasswordDTO; import com.ticketing.server.user.service.dto.ChangedPasswordUserDTO; +import com.ticketing.server.user.service.dto.DeletedUserDTO; +import com.ticketing.server.user.service.dto.ChangePasswordDTO; import com.ticketing.server.user.service.dto.CreatedUserDTO; import com.ticketing.server.user.service.dto.DeleteUserDTO; -import com.ticketing.server.user.service.dto.DeletedUserDTO; import com.ticketing.server.user.service.dto.SignUpDTO; import com.ticketing.server.user.service.dto.UserDetailDTO; import javax.validation.Valid; diff --git a/server/src/test/java/com/ticketing/server/movie/service/MovieServiceImplTest.java b/server/src/test/java/com/ticketing/server/movie/service/MovieServiceImplTest.java index 3e0b210..959f4e0 100644 --- a/server/src/test/java/com/ticketing/server/movie/service/MovieServiceImplTest.java +++ b/server/src/test/java/com/ticketing/server/movie/service/MovieServiceImplTest.java @@ -6,6 +6,7 @@ import static org.mockito.Mockito.when; import com.ticketing.server.movie.domain.Movie; import com.ticketing.server.movie.domain.repository.MovieRepository; import com.ticketing.server.movie.service.dto.MovieDTO; +import com.ticketing.server.movie.service.dto.MovieListDTO; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -38,10 +39,10 @@ public class MovieServiceImplTest { .thenReturn(Collections.emptyList()); // when - List movieDTOList = movieService.getMovies(); + MovieListDTO movieListDto = movieService.getMovies(); // then - assertTrue(movieDTOList.isEmpty()); + assertTrue(movieListDto.getMovieDtos().isEmpty()); } @Test @@ -49,18 +50,16 @@ public class MovieServiceImplTest { void shouldAbleToGetMovies() { // given movie = new Movie("범죄도시2", 106L); - movieDto = movieDto.from(movie); movies.add(movie); - movieDTOS.add(movieDto); when(movieRepository.findValidMovies()) .thenReturn(movies); // when - List movieDTOList = movieService.getMovies(); + MovieListDTO movieListDto = movieService.getMovies(); // then - assertTrue(!movieDTOList.isEmpty()); + assertTrue(!movieListDto.getMovieDtos().isEmpty()); } }