From 47caadd047e76323b4a825b3faf547b8b3d9fefa Mon Sep 17 00:00:00 2001 From: DD <48818566+fucct@users.noreply.github.com> Date: Fri, 19 Jun 2020 14:23:16 +0900 Subject: [PATCH] =?UTF-8?q?[=EB=94=94=EB=94=94]=20JPA=20=EB=AF=B8=EC=85=98?= =?UTF-8?q?=20=EC=A0=9C=EC=B6=9C=ED=95=A9=EB=8B=88=EB=8B=A4.=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 리뷰 반영 2 - Favorite 메서드명 수정 * refactor: JPA 수정 전 Interceptor 수정 * feat: JPA Domain feature & Context Load * refactor: properties, query * feat: LineStation 정상화 - 정상적으로 동작하도록 메서드 수정 - data.sql 오류 제거 * refactor: 전체 테스트 수정 * refactor: 다양한 리팩터링 - EnableJdbcAuditingConfig.java 클래스 명 수정 - Favorite 생성자 파라미터명 수정 - 불필요한 fetchType 제거 - 불필요한 메서드 제거 * refactor: 리뷰 반영 - JpaAuditing - equals & hashcode * refactor: BaseEntity 필드 삭제 - createdBy, updatedBy 삭제 * refactor: equals 메서드 수정 --- build.gradle | 3 +- src/docs/asciidoc/api-guide.adoc | 21 +- .../subway/SubwayAdminApplication.java | 8 +- .../subway/config/ETagHeaderFilter.java | 3 +- .../config/EnableJdbcAuditingConfig.java | 9 - .../subway/domain/common/BaseEntity.java | 47 ++ .../subway/domain/favorite/Favorite.java | 96 ++-- .../domain/favorite/FavoriteRepository.java | 12 +- .../java/wooteco/subway/domain/line/Line.java | 91 ++-- .../subway/domain/line/LineRepository.java | 8 +- .../subway/domain/line/LineStation.java | 58 --- .../subway/domain/line/LineStations.java | 76 --- .../wooteco/subway/domain/line/Lines.java | 43 -- .../domain/linestation/LineStation.java | 65 +++ .../linestation/LineStationRepository.java | 6 + .../domain/linestation/LineStations.java | 90 ++++ .../wooteco/subway/domain/member/Member.java | 73 +-- .../domain/member/MemberRepository.java | 11 +- .../wooteco/subway/domain/path/PathType.java | 5 +- .../subway/domain/station/Station.java | 51 +- .../domain/station/StationRepository.java | 16 +- .../subway/domain/station/Stations.java | 22 - .../subway/infra/JwtTokenProvider.java | 15 +- .../subway/service/line/LineService.java | 79 +-- .../service/line/LineStationService.java | 56 ++- .../service/line/dto/LineDetailResponse.java | 16 +- .../subway/service/line/dto/LineRequest.java | 6 +- .../subway/service/line/dto/LineResponse.java | 28 +- .../service/line/dto/WholeSubwayResponse.java | 8 +- .../subway/service/path/GraphService.java | 24 +- .../subway/service/path/PathService.java | 69 +-- .../subway/service/path/dto/PathResponse.java | 4 +- .../service/station/StationService.java | 35 +- .../station/dto/StationCreateRequest.java | 11 +- .../service/station/dto/StationResponse.java | 39 +- .../subway/web/controller/LineController.java | 25 +- .../web/controller/LoginMemberController.java | 8 +- .../subway/web/controller/PathController.java | 4 +- .../web/controller/StationController.java | 17 +- .../exception/AuthenticationException.java | 2 +- .../web/exception/BusinessException.java | 2 +- .../InvalidAuthenticationException.java | 2 +- .../web/prehandler/BearerAuthInterceptor.java | 31 +- .../LoginMemberMethodArgumentResolver.java | 6 +- .../validator/PasswordMatchValidator.java | 23 +- .../web/service/favorite/FavoriteService.java | 33 +- .../favorite/dto/FavoriteResponse.java | 6 +- .../web/service/member/MemberService.java | 13 +- .../web/service/member/dto/LoginRequest.java | 27 +- .../web/service/member/dto/MemberRequest.java | 6 +- src/main/resources/application.properties | 9 - src/main/resources/application.yml | 31 ++ src/main/resources/data.sql | 13 +- src/main/resources/logback-access.xml | 2 +- src/main/resources/schema.sql | 48 -- .../static/admin/js/views/AdminEdge.js | 56 ++- .../static/admin/js/views/AdminLine.js | 70 +-- .../static/admin/js/views/AdminStation.js | 38 +- .../static/admin/lib/slider/tiny-slider.css | 29 ++ .../static/admin/lib/slider/tiny-slider.js | 475 ++++++++++-------- .../static/admin/lib/snackbar/snackbar.js | 32 +- .../resources/static/admin/ui/CustomModal.js | 1 - .../resources/static/admin/utils/templates.js | 3 +- .../resources/static/service/api/index.js | 10 +- src/main/resources/static/service/css/app.css | 1 + .../static/service/js/views/MyPage.js | 4 +- .../static/service/js/views/MyPageEdit.js | 6 +- .../static/service/js/views/Search.js | 8 +- .../static/service/lib/slider/tiny-slider.css | 29 ++ .../static/service/lib/slider/tiny-slider.js | 475 ++++++++++-------- .../static/service/lib/snackbar/snackbar.js | 32 +- .../resources/templates/admin/admin-edge.html | 301 +++++------ .../resources/templates/admin/admin-line.html | 84 +++- .../templates/admin/admin-station.html | 92 ++-- src/main/resources/templates/admin/index.html | 80 +-- .../resources/templates/service/favorite.html | 18 +- .../resources/templates/service/index.html | 93 ++-- .../resources/templates/service/join.html | 145 +++--- .../resources/templates/service/login.html | 106 ++-- src/main/resources/templates/service/map.html | 87 ++-- .../templates/service/mypage-edit.html | 181 +++---- .../resources/templates/service/mypage.html | 71 +-- .../resources/templates/service/search.html | 40 +- .../subway/SubwayAdminApplicationTests.java | 6 +- .../subway/acceptance/AcceptanceTest.java | 24 +- .../subway/acceptance/PageAcceptanceTest.java | 49 +- .../wooteco/subway/doc/ApiDocumentUtils.java | 1 - .../subway/doc/DocumentFormatGenerator.java | 4 +- .../domain/line/LineRepositoryTest.java | 30 -- .../wooteco/subway/domain/line/LineTest.java | 37 +- .../subway/domain/member/MemberTest.java | 40 +- .../domain/station/StationRepositoryTest.java | 22 - .../service/favorite/FavoriteServiceTest.java | 105 ++-- .../subway/service/line/LineServiceTest.java | 75 +-- .../service/line/LineStationServiceTest.java | 62 ++- .../service/member/MemberServiceTest.java | 10 +- .../subway/service/path/GraphServiceTest.java | 51 +- .../subway/service/path/PathServiceTest.java | 186 +++---- .../service/station/StationServiceTest.java | 64 +-- .../web/favorite/FavoriteControllerTest.java | 11 +- .../subway/web/line/LineControllerTest.java | 78 ++- src/test/resources/application.properties | 5 +- .../restdocs/templates/request-fields.snippet | 23 +- src/test/resources/truncate.sql | 4 +- 104 files changed, 2592 insertions(+), 2374 deletions(-) delete mode 100644 src/main/java/wooteco/subway/config/EnableJdbcAuditingConfig.java create mode 100644 src/main/java/wooteco/subway/domain/common/BaseEntity.java delete mode 100644 src/main/java/wooteco/subway/domain/line/LineStation.java delete mode 100644 src/main/java/wooteco/subway/domain/line/LineStations.java delete mode 100644 src/main/java/wooteco/subway/domain/line/Lines.java create mode 100644 src/main/java/wooteco/subway/domain/linestation/LineStation.java create mode 100644 src/main/java/wooteco/subway/domain/linestation/LineStationRepository.java create mode 100644 src/main/java/wooteco/subway/domain/linestation/LineStations.java delete mode 100644 src/main/java/wooteco/subway/domain/station/Stations.java delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml delete mode 100644 src/main/resources/schema.sql delete mode 100644 src/test/java/wooteco/subway/domain/line/LineRepositoryTest.java delete mode 100644 src/test/java/wooteco/subway/domain/station/StationRepositoryTest.java diff --git a/build.gradle b/build.gradle index cf378221a..5bd98d756 100644 --- a/build.gradle +++ b/build.gradle @@ -15,11 +15,12 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.0' implementation 'org.jgrapht:jgrapht-core:1.0.1' implementation 'io.jsonwebtoken:jjwt:0.9.1' + compile group: 'org.projectlombok', name: 'lombok', version: '1.18.12' testImplementation 'io.rest-assured:rest-assured:3.3.0' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:2.0.4.RELEASE' testImplementation('org.springframework.boot:spring-boot-starter-test') { diff --git a/src/docs/asciidoc/api-guide.adoc b/src/docs/asciidoc/api-guide.adoc index 1e0401e26..9403c02b0 100644 --- a/src/docs/asciidoc/api-guide.adoc +++ b/src/docs/asciidoc/api-guide.adoc @@ -21,19 +21,20 @@ endif::[] [[resources-members-create-success]] ===== 성공 -operation::members/create[snippets='http-request,http-response,request-fields'] +operation::members/create[snippets='http-request,http-response,request-fields'] [[resources-members-create-fail]] ==== 실패 [[resources-members-create-fail-duplicated-email]] ===== 이메일 중복 -operation::members/duplicate-create[snippets='http-request,http-response,request-fields'] +operation::members/duplicate-create[snippets='http-request,http-response,request-fields'] [[resources-members-create-fail-not-match-password]] ===== 패스워드 불일치 + operation::members/not-match-password-create[snippets='http-request,http-response,request-fields'] [[resources-members-login]] @@ -41,6 +42,7 @@ operation::members/not-match-password-create[snippets='http-request,http-respons [[resources-members-login-successful]] ===== 성공 + operation::members/login[snippets='http-request,http-response,request-fields'] [[resources-members-login-fail]] @@ -48,10 +50,12 @@ operation::members/login[snippets='http-request,http-response,request-fields'] [[resources-members-login-fail-not-exist-email]] ===== 존재하지 않는 이메일 + operation::members/login-with-not-exist-email[snippets='http-request,http-response,request-fields'] [[resources-members-login-fail-not-match-password]] ===== 비밀번호 불일치 + operation::members/login-with-wrong-password[snippets='http-request,http-response,request-fields'] [[resources-members-get]] @@ -59,6 +63,7 @@ operation::members/login-with-wrong-password[snippets='http-request,http-respons [[resources-members-get-successful]] ===== 성공 + operation::members/get[snippets='http-request,http-response'] [[resources-members-get-fail]] @@ -66,14 +71,15 @@ operation::members/get[snippets='http-request,http-response'] [[resources-members-get-fail-not-login]] ===== 토큰이 존재하지 않음 -operation::members/not-exist-get[snippets='http-request,http-response'] +operation::members/not-exist-get[snippets='http-request,http-response'] [[resources-members-update]] === 회원 정보 수정 [[resources-members-update-successful]] ===== 성공 + operation::members/update[snippets='http-request,http-response,request-fields'] [[resources-members-update-fail]] @@ -81,10 +87,12 @@ operation::members/update[snippets='http-request,http-response,request-fields'] [[resources-members-update-fail-not-login]] ===== 토큰이 존재하지 않음 + operation::members/not-exist-token-update[snippets='http-request,http-response,request-fields,response-fields'] [[resources-members-update-fail-not-match-password]] ===== 비밀번호가 올바르지 않 + operation::members/not-match-password-update[snippets='http-request,http-response,request-fields,response-fields'] [[resources-members-delete]] @@ -92,6 +100,7 @@ operation::members/not-match-password-update[snippets='http-request,http-respons [[resources-members-delete-successful]] ===== 성공 + operation::members/delete[snippets='http-request,http-response'] [[resources-members-delete-fail]] @@ -99,6 +108,7 @@ operation::members/delete[snippets='http-request,http-response'] [[resources-members-delete-not-login]] ===== 토큰이 존재하지 않음 + operation::members/delete-not-exist-token[snippets='http-request,http-response,response-fields'] [[resources-favorites]] @@ -109,6 +119,7 @@ operation::members/delete-not-exist-token[snippets='http-request,http-response,r [[resources-favorites-create-successful]] ===== 성공 + operation::favorites/create[snippets='http-request,http-response,request-fields'] [[resources-favorites-create-fail]] @@ -116,9 +127,11 @@ operation::favorites/create[snippets='http-request,http-response,request-fields' [[resources-favorites-create-fail-no-login]] ===== 토큰이 존재하지 않음 + operation::favorites/create-no-login[snippets='http-request,http-response,request-fields,response-fields'] ===== 즐겨찾기 중복 + operation::favorites/create-duplicated[snippets='http-request,http-response,request-fields,response-fields'] [[resources-favorites-delete]] @@ -126,6 +139,7 @@ operation::favorites/create-duplicated[snippets='http-request,http-response,requ [[resources-favorites-delete-successful]] ===== 성공 + operation::favorites/delete[snippets='http-request,http-response'] [[resources-favorites-delete-fail]] @@ -133,6 +147,7 @@ operation::favorites/delete[snippets='http-request,http-response'] [[resources-favorites-delete-fail-not-login]] ===== 토큰이 존재하지 않음 + operation::favorites/delete-not-login[snippets='http-request,http-response, response-fields'] diff --git a/src/main/java/wooteco/subway/SubwayAdminApplication.java b/src/main/java/wooteco/subway/SubwayAdminApplication.java index 34839cf01..7105a46c4 100644 --- a/src/main/java/wooteco/subway/SubwayAdminApplication.java +++ b/src/main/java/wooteco/subway/SubwayAdminApplication.java @@ -2,11 +2,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class SubwayAdminApplication { - public static void main(String[] args) { - SpringApplication.run(SubwayAdminApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(SubwayAdminApplication.class, args); + } } diff --git a/src/main/java/wooteco/subway/config/ETagHeaderFilter.java b/src/main/java/wooteco/subway/config/ETagHeaderFilter.java index b6ddc721b..c008d8180 100644 --- a/src/main/java/wooteco/subway/config/ETagHeaderFilter.java +++ b/src/main/java/wooteco/subway/config/ETagHeaderFilter.java @@ -9,7 +9,8 @@ public class ETagHeaderFilter { @Bean public FilterRegistrationBean shallowEtagHeaderFilter() { - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( + new ShallowEtagHeaderFilter()); filterRegistrationBean.addUrlPatterns("/lines/detail"); filterRegistrationBean.setName("etagFilter"); return filterRegistrationBean; diff --git a/src/main/java/wooteco/subway/config/EnableJdbcAuditingConfig.java b/src/main/java/wooteco/subway/config/EnableJdbcAuditingConfig.java deleted file mode 100644 index f1110e829..000000000 --- a/src/main/java/wooteco/subway/config/EnableJdbcAuditingConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package wooteco.subway.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing; - -@EnableJdbcAuditing -@Configuration -public class EnableJdbcAuditingConfig { -} diff --git a/src/main/java/wooteco/subway/domain/common/BaseEntity.java b/src/main/java/wooteco/subway/domain/common/BaseEntity.java new file mode 100644 index 000000000..0e1039c94 --- /dev/null +++ b/src/main/java/wooteco/subway/domain/common/BaseEntity.java @@ -0,0 +1,47 @@ +package wooteco.subway.domain.common; + +import static javax.persistence.GenerationType.*; + +import java.time.LocalDateTime; +import java.util.Objects; + +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@MappedSuperclass +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@EntityListeners(AuditingEntityListener.class) +public abstract class BaseEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + protected Long id; + + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; + + @Override + public boolean equals(Object o) { + BaseEntity that = (BaseEntity)o; + return getId().equals(that.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(getId()); + } +} diff --git a/src/main/java/wooteco/subway/domain/favorite/Favorite.java b/src/main/java/wooteco/subway/domain/favorite/Favorite.java index 1d6223baf..5f4bf52f0 100644 --- a/src/main/java/wooteco/subway/domain/favorite/Favorite.java +++ b/src/main/java/wooteco/subway/domain/favorite/Favorite.java @@ -1,51 +1,53 @@ package wooteco.subway.domain.favorite; -import java.util.Objects; - -import org.springframework.data.annotation.Id; - -public class Favorite { - @Id - private Long id; - private Long memberId; - private Long sourceId; - private Long targetId; - - protected Favorite() { - } - - public Favorite(Long id, Long memberId, Long sourceId, Long targetId) { - this.id = id; - this.memberId = memberId; - this.sourceId = sourceId; - this.targetId = targetId; - } - - public static Favorite of(Long id, Long memberId, Long sourceId, Long targetId) { - return new Favorite(id, memberId, sourceId, targetId); - } - - public static Favorite of(Long memberId, Long sourceId, Long targetId) { - return new Favorite(null, memberId, sourceId, targetId); - } - - public Long getId() { - return id; - } - - public Long getMemberId() { - return memberId; - } - - public Long getSourceId() { - return sourceId; - } - - public Long getTargetId() { - return targetId; - } - - public boolean isSameId(Long id) { - return Objects.equals(this.id, id); +import static javax.persistence.FetchType.*; + +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.common.BaseEntity; +import wooteco.subway.domain.member.Member; +import wooteco.subway.domain.station.Station; +import wooteco.subway.web.exception.AuthenticationException; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@AttributeOverride(name = "id", column = @Column(name = "FAVORITE_ID")) +public class Favorite extends BaseEntity { + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "MEMBER_ID") + private Member member; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "SOURCE_STATION_ID") + private Station sourceStation; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "TARGET_STATION_ID") + private Station targetStation; + + public Favorite(Long id, Member member, Station source, Station target) { + this(member, source, target); + super.id = id; + } + + public static Favorite of(Member member, Station sourceStation, Station targetStation) { + return new Favorite(member, sourceStation, targetStation); + } + + public void validateMember(Member member) { + if (!this.member.equals(member)) { + throw new AuthenticationException(); + } } } diff --git a/src/main/java/wooteco/subway/domain/favorite/FavoriteRepository.java b/src/main/java/wooteco/subway/domain/favorite/FavoriteRepository.java index 791aee302..d4bf7f5ac 100644 --- a/src/main/java/wooteco/subway/domain/favorite/FavoriteRepository.java +++ b/src/main/java/wooteco/subway/domain/favorite/FavoriteRepository.java @@ -1,16 +1,10 @@ package wooteco.subway.domain.favorite; import java.util.List; -import java.util.Optional; -import org.springframework.data.jdbc.repository.query.Query; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; +import org.springframework.data.jpa.repository.JpaRepository; -public interface FavoriteRepository extends CrudRepository { - @Query("select * from favorite where (id = :id) and (member_id = :memberId)") - Optional findByIdAndMemberId(@Param("id") Long id, @Param("memberId") Long memberId); +public interface FavoriteRepository extends JpaRepository { - @Query("select * from favorite where member_id = :memberId") - List findAllByMemberId(@Param("memberId") Long memberId); + List findAllByMemberId(Long id); } diff --git a/src/main/java/wooteco/subway/domain/line/Line.java b/src/main/java/wooteco/subway/domain/line/Line.java index 83fda710e..fe4f2112d 100644 --- a/src/main/java/wooteco/subway/domain/line/Line.java +++ b/src/main/java/wooteco/subway/domain/line/Line.java @@ -1,73 +1,44 @@ package wooteco.subway.domain.line; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.relational.core.mapping.Embedded; - -import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; -import java.util.Set; -public class Line { - @Id - private Long id; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.common.BaseEntity; +import wooteco.subway.domain.linestation.LineStation; +import wooteco.subway.domain.linestation.LineStations; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +@AttributeOverride(name = "id", column = @Column(name = "LINE_ID")) +public class Line extends BaseEntity { + + @Column(name = "LINE_NAME") private String name; private LocalTime startTime; private LocalTime endTime; private int intervalTime; - @CreatedDate - private LocalDateTime createdAt; - @LastModifiedDate - private LocalDateTime updatedAt; - @Embedded.Empty - private LineStations stations = LineStations.empty(); - public Line() { - } + @Embedded + private LineStations stations = LineStations.empty(); public Line(Long id, String name, LocalTime startTime, LocalTime endTime, int intervalTime) { - this.name = name; - this.startTime = startTime; - this.endTime = endTime; - this.intervalTime = intervalTime; - } - - public Line(String name, LocalTime startTime, LocalTime endTime, int intervalTime) { - this(null, name, startTime, endTime, intervalTime); - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public LocalTime getStartTime() { - return startTime; - } - - public LocalTime getEndTime() { - return endTime; - } - - public int getIntervalTime() { - return intervalTime; + this(name, startTime, endTime, intervalTime, LineStations.empty()); + super.id = id; } - public Set getStations() { - return stations.getStations(); - } - - public LocalDateTime getCreatedAt() { - return createdAt; - } - - public LocalDateTime getUpdatedAt() { - return updatedAt; + public static Line of(String name, LocalTime startTime, LocalTime endTime, int intervalTime) { + return new Line(name, startTime, endTime, intervalTime, LineStations.empty()); } public void update(Line line) { @@ -85,14 +56,14 @@ public void update(Line line) { } } - public void addLineStation(LineStation lineStation) { - stations.add(lineStation); - } - public void removeLineStationById(Long stationId) { stations.removeById(stationId); } + public List getStations() { + return stations.getStations(); + } + public List getStationIds() { return stations.getStationIds(); } diff --git a/src/main/java/wooteco/subway/domain/line/LineRepository.java b/src/main/java/wooteco/subway/domain/line/LineRepository.java index d533b8df3..53d2d973e 100644 --- a/src/main/java/wooteco/subway/domain/line/LineRepository.java +++ b/src/main/java/wooteco/subway/domain/line/LineRepository.java @@ -1,10 +1,6 @@ package wooteco.subway.domain.line; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; - -public interface LineRepository extends CrudRepository { - @Override - List findAll(); +public interface LineRepository extends JpaRepository { } diff --git a/src/main/java/wooteco/subway/domain/line/LineStation.java b/src/main/java/wooteco/subway/domain/line/LineStation.java deleted file mode 100644 index dd731b059..000000000 --- a/src/main/java/wooteco/subway/domain/line/LineStation.java +++ /dev/null @@ -1,58 +0,0 @@ -package wooteco.subway.domain.line; - -import java.util.Objects; - -public class LineStation { - private Long preStationId; - private Long stationId; - private int distance; - private int duration; - - public LineStation(Long preStationId, Long stationId, int distance, int duration) { - this.preStationId = preStationId; - this.stationId = stationId; - this.distance = distance; - this.duration = duration; - } - - public Long getPreStationId() { - return preStationId; - } - - public Long getStationId() { - return stationId; - } - - public int getDistance() { - return distance; - } - - public int getDuration() { - return duration; - } - - public void updatePreLineStation(Long preStationId) { - this.preStationId = preStationId; - } - - public boolean isLineStationOf(Long preStationId, Long stationId) { - return this.preStationId == preStationId && this.stationId == stationId - || this.preStationId == stationId && this.stationId == preStationId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - LineStation that = (LineStation) o; - return distance == that.distance && - duration == that.duration && - Objects.equals(preStationId, that.preStationId) && - Objects.equals(stationId, that.stationId); - } - - @Override - public int hashCode() { - return Objects.hash(preStationId, stationId, distance, duration); - } -} diff --git a/src/main/java/wooteco/subway/domain/line/LineStations.java b/src/main/java/wooteco/subway/domain/line/LineStations.java deleted file mode 100644 index cbb0485cb..000000000 --- a/src/main/java/wooteco/subway/domain/line/LineStations.java +++ /dev/null @@ -1,76 +0,0 @@ -package wooteco.subway.domain.line; - -import java.util.*; - -public class LineStations { - private Set stations; - - public LineStations(Set stations) { - this.stations = stations; - } - - public static LineStations empty() { - return new LineStations(new HashSet<>()); - } - - public Set getStations() { - return stations; - } - - public void add(LineStation targetLineStation) { - updatePreStationOfNextLineStation(targetLineStation.getPreStationId(), targetLineStation.getStationId()); - stations.add(targetLineStation); - } - - private void remove(LineStation targetLineStation) { - updatePreStationOfNextLineStation(targetLineStation.getStationId(), targetLineStation.getPreStationId()); - stations.remove(targetLineStation); - } - - public void removeById(Long targetStationId) { - extractByStationId(targetStationId) - .ifPresent(this::remove); - } - - public List getStationIds() { - List result = new ArrayList<>(); - extractNext(null, result); - return result; - } - - private void extractNext(Long preStationId, List ids) { - stations.stream() - .filter(it -> Objects.equals(it.getPreStationId(), preStationId)) - .findFirst() - .ifPresent(it -> { - Long nextStationId = it.getStationId(); - ids.add(nextStationId); - extractNext(nextStationId, ids); - }); - } - - private void updatePreStationOfNextLineStation(Long targetStationId, Long newPreStationId) { - extractByPreStationId(targetStationId) - .ifPresent(it -> it.updatePreLineStation(newPreStationId)); - } - - private Optional extractByStationId(Long stationId) { - return stations.stream() - .filter(it -> Objects.equals(it.getStationId(), stationId)) - .findFirst(); - } - - private Optional extractByPreStationId(Long preStationId) { - return stations.stream() - .filter(it -> Objects.equals(it.getPreStationId(), preStationId)) - .findFirst(); - } - - public int getTotalDistance() { - return stations.stream().mapToInt(it -> it.getDistance()).sum(); - } - - public int getTotalDuration() { - return stations.stream().mapToInt(it -> it.getDuration()).sum(); - } -} diff --git a/src/main/java/wooteco/subway/domain/line/Lines.java b/src/main/java/wooteco/subway/domain/line/Lines.java deleted file mode 100644 index b2fc68108..000000000 --- a/src/main/java/wooteco/subway/domain/line/Lines.java +++ /dev/null @@ -1,43 +0,0 @@ -package wooteco.subway.domain.line; - -import java.util.List; -import java.util.stream.Collectors; - -public class Lines { - private List lines; - - public Lines(List lines) { - this.lines = lines; - } - - public List getLines() { - return lines; - } - - public List getStationIds() { - return lines.stream() - .flatMap(it -> it.getStations().stream()) - .map(it -> it.getStationId()) - .collect(Collectors.toList()); - } -// -// public LineStations extractLineStationByStationIds(List stationIds) { -// for (Long stationId : stationIds) { -// List lineStations = findLineStation(null, stationId); -// } -// Set lineStations = stationIds.stream() -// .map(it -> getLineStationByStationId(it)) -// .collect(Collectors.toSet()); -// -// return new LineStations(lineStations); -// } -// -// private LineStation getLineStationByStationId(Long stationId) { -// return lines.stream() -// .flatMap(it -> it.getStations().stream()) -//// .filter(it -> Objects.nonNull(it.getPreStationId())) -// .filter(it -> it.getStationId() == stationId) -// .findFirst() -// .orElseThrow(RuntimeException::new); -// } -} diff --git a/src/main/java/wooteco/subway/domain/linestation/LineStation.java b/src/main/java/wooteco/subway/domain/linestation/LineStation.java new file mode 100644 index 000000000..bcd941ee2 --- /dev/null +++ b/src/main/java/wooteco/subway/domain/linestation/LineStation.java @@ -0,0 +1,65 @@ +package wooteco.subway.domain.linestation; + +import java.util.Objects; + +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.common.BaseEntity; +import wooteco.subway.domain.line.Line; +import wooteco.subway.domain.station.Station; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AttributeOverride(name = "id", column = @Column(name = "LINE_STATION_ID")) +public class LineStation extends BaseEntity { + + @ManyToOne + @JoinColumn(name = "PRE_STATION_ID") + private Station preStation; + + @ManyToOne + @JoinColumn(name = "NEXT_STATION_ID") + private Station nextStation; + + private int distance; + private int duration; + + @ManyToOne + @JoinColumn(name = "LINE_ID") + private Line line; + + public LineStation(Station preStation, Station nextStation, int distance, int duration) { + this.preStation = preStation; + this.nextStation = nextStation; + this.distance = distance; + this.duration = duration; + } + + public boolean isLineStationOf(Long preStationId, Long stationId) { + return preStation.isSameId(preStationId) && nextStation.isSameId(stationId); + } + + public void applyLine(Line line) { + if (Objects.nonNull(this.line)) { + this.line.getStations().remove(this); + } + this.line = line; + line.getStations().add(this); + } + + public void updatePreLineStation(Station newPreStation) { + this.preStation = newPreStation; + } + + public Long getId() { + return nextStation.getId(); + } +} diff --git a/src/main/java/wooteco/subway/domain/linestation/LineStationRepository.java b/src/main/java/wooteco/subway/domain/linestation/LineStationRepository.java new file mode 100644 index 000000000..8f12f9249 --- /dev/null +++ b/src/main/java/wooteco/subway/domain/linestation/LineStationRepository.java @@ -0,0 +1,6 @@ +package wooteco.subway.domain.linestation; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface LineStationRepository extends JpaRepository { +} diff --git a/src/main/java/wooteco/subway/domain/linestation/LineStations.java b/src/main/java/wooteco/subway/domain/linestation/LineStations.java new file mode 100644 index 000000000..7c7d3d708 --- /dev/null +++ b/src/main/java/wooteco/subway/domain/linestation/LineStations.java @@ -0,0 +1,90 @@ +package wooteco.subway.domain.linestation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.OneToMany; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.station.Station; + +@Embeddable +@NoArgsConstructor +@Getter +public class LineStations { + + @OneToMany(mappedBy = "line", cascade = CascadeType.ALL, orphanRemoval = true) + private List stations = new ArrayList<>(); + + public LineStations(List stations) { + this.stations = stations; + } + + public static LineStations empty() { + return new LineStations(new ArrayList<>()); + } + + public List getStations() { + return stations; + } + + public void add(LineStation targetLineStation) { + updatePreStationOfNextLineStation(targetLineStation.getPreStation().getId(), + targetLineStation.getNextStation()); + stations.add(targetLineStation); + } + + private void remove(LineStation targetLineStation) { + updatePreStationOfNextLineStation(targetLineStation.getNextStation().getId(), + targetLineStation.getPreStation()); + stations.remove(targetLineStation); + } + + public void removeById(Long targetStationId) { + LineStation lineStation = stations.stream() + .filter(lineStation1 -> lineStation1.getNextStation().isSameId(targetStationId)) + .findAny() + .orElseThrow(RuntimeException::new); + remove(lineStation); + } + + public List getStationIds() { + return stations.stream().map(lineStation -> lineStation.getNextStation().getId()).collect( + Collectors.toList()); + } + + private void extractNext(Long preStationId, List ids) { + stations.stream() + .filter(it -> Objects.equals(it.getPreStation().getId(), preStationId)) + .findFirst() + .ifPresent(it -> { + Long nextStationId = it.getNextStation().getId(); + ids.add(nextStationId); + extractNext(nextStationId, ids); + }); + } + + private void updatePreStationOfNextLineStation(Long targetStationId, Station newPreStation) { + extractByPreStationId(targetStationId) + .ifPresent(it -> it.updatePreLineStation(newPreStation)); + } + + private Optional extractByStationId(Long stationId) { + return stations.stream() + .filter(it -> Objects.equals(it.getNextStation().getId(), stationId)) + .findFirst(); + } + + private Optional extractByPreStationId(Long preStationId) { + return stations.stream() + .filter(it -> Objects.nonNull(it.getPreStation()) && Objects.equals( + it.getPreStation().getId(), preStationId)) + .findFirst(); + } +} diff --git a/src/main/java/wooteco/subway/domain/member/Member.java b/src/main/java/wooteco/subway/domain/member/Member.java index 840abd14a..b6b23709f 100644 --- a/src/main/java/wooteco/subway/domain/member/Member.java +++ b/src/main/java/wooteco/subway/domain/member/Member.java @@ -1,45 +1,48 @@ package wooteco.subway.domain.member; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.annotation.Id; +import java.util.ArrayList; +import java.util.List; -public class Member { - @Id - private Long id; - private String email; - private String name; - private String password; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.OneToMany; - public Member() { - } +import org.apache.commons.lang3.StringUtils; - public Member(String email, String name, String password) { - this.email = email; - this.name = name; - this.password = password; - } +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.common.BaseEntity; +import wooteco.subway.domain.favorite.Favorite; - public Member(Long id, String email, String name, String password) { - this.id = id; - this.email = email; - this.name = name; - this.password = password; - } +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Entity +@AttributeOverride(name = "id", column = @Column(name = "MEMBER_ID")) +public class Member extends BaseEntity { - public Long getId() { - return id; - } + @Column(name = "MEMBER_NAME") + private String name; + private String email; + private String password; - public String getEmail() { - return email; + @OneToMany(mappedBy = "member", orphanRemoval = true) + private List favorites; + + public Member(Long id, String name, String email, String password) { + this(email, name, password, new ArrayList<>()); + super.id = id; } - public String getName() { - return name; + public static Member of(String name, String email, String password) { + return new Member(name, email, password, new ArrayList<>()); } - public String getPassword() { - return password; + public static Member of() { + return new Member(); } public void update(String name, String password) { @@ -55,7 +58,13 @@ public boolean checkPassword(String password) { return this.password.equals(password); } - public boolean isSameId(Long id) { - return this.id.equals(id); + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode(); } } diff --git a/src/main/java/wooteco/subway/domain/member/MemberRepository.java b/src/main/java/wooteco/subway/domain/member/MemberRepository.java index 0ec707369..c798b2419 100644 --- a/src/main/java/wooteco/subway/domain/member/MemberRepository.java +++ b/src/main/java/wooteco/subway/domain/member/MemberRepository.java @@ -1,12 +1,7 @@ package wooteco.subway.domain.member; -import org.springframework.data.jdbc.repository.query.Query; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; +import org.springframework.data.jpa.repository.JpaRepository; -import java.util.Optional; - -public interface MemberRepository extends CrudRepository { - @Query("select * from member where email = :email") - Optional findByEmail(@Param("email") String email); +public interface MemberRepository extends JpaRepository { + Member findByEmail(String email); } diff --git a/src/main/java/wooteco/subway/domain/path/PathType.java b/src/main/java/wooteco/subway/domain/path/PathType.java index 0c3eab04a..9f7c7959a 100644 --- a/src/main/java/wooteco/subway/domain/path/PathType.java +++ b/src/main/java/wooteco/subway/domain/path/PathType.java @@ -1,9 +1,9 @@ package wooteco.subway.domain.path; -import wooteco.subway.domain.line.LineStation; - import java.util.function.Function; +import wooteco.subway.domain.linestation.LineStation; + public enum PathType { DISTANCE(lineStation -> lineStation.getDistance()), DURATION(lineStation -> lineStation.getDuration()); @@ -14,7 +14,6 @@ public enum PathType { this.expression = expression; } - public int findWeightOf(LineStation lineStation) { return expression.apply(lineStation); } diff --git a/src/main/java/wooteco/subway/domain/station/Station.java b/src/main/java/wooteco/subway/domain/station/Station.java index 8060292e4..dda055157 100644 --- a/src/main/java/wooteco/subway/domain/station/Station.java +++ b/src/main/java/wooteco/subway/domain/station/Station.java @@ -1,38 +1,35 @@ package wooteco.subway.domain.station; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.Id; - -import java.time.LocalDateTime; - -public class Station { - @Id - private Long id; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.common.BaseEntity; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +@AttributeOverride(name = "id", column = @Column(name = "STATION_ID")) +public class Station extends BaseEntity { + + @Column(name = "STATION_NAME", unique = true) private String name; - @CreatedDate - private LocalDateTime createdAt; - public Station() { - } - - public Station(String name) { + public Station(long id, String name) { + super.id = id; this.name = name; } - public Station(Long id, String name) { - this.id = id; - this.name = name; - } - - public Long getId() { - return id; - } - - public String getName() { - return name; + public static Station of(String name) { + return new Station(name); } - public LocalDateTime getCreatedAt() { - return createdAt; + public boolean isSameId(Long stationId) { + return super.id.equals(stationId); } } diff --git a/src/main/java/wooteco/subway/domain/station/StationRepository.java b/src/main/java/wooteco/subway/domain/station/StationRepository.java index 2a3d33fb8..dfa893bdf 100644 --- a/src/main/java/wooteco/subway/domain/station/StationRepository.java +++ b/src/main/java/wooteco/subway/domain/station/StationRepository.java @@ -3,17 +3,13 @@ import java.util.List; import java.util.Optional; -import org.springframework.data.jdbc.repository.query.Query; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -public interface StationRepository extends CrudRepository { - @Override - List findAllById(Iterable ids); +public interface StationRepository extends JpaRepository { + Optional findByName(String name); - @Override - List findAll(); - - @Query("select * from station where name = :stationName") - Optional findByName(@Param("stationName") String stationName); + @Query("select s from Station s where s.name in (:stations)") + List findAllByStationName(@Param("stations") List stations); } diff --git a/src/main/java/wooteco/subway/domain/station/Stations.java b/src/main/java/wooteco/subway/domain/station/Stations.java deleted file mode 100644 index f3a5918b3..000000000 --- a/src/main/java/wooteco/subway/domain/station/Stations.java +++ /dev/null @@ -1,22 +0,0 @@ -package wooteco.subway.domain.station; - -import java.util.List; - -public class Stations { - private List stations; - - public Stations(List stations) { - this.stations = stations; - } - - public List getStations() { - return stations; - } - - public Station extractStationById(Long stationId) { - return stations.stream() - .filter(it -> it.getId() == stationId) - .findFirst() - .orElseThrow(RuntimeException::new); - } -} diff --git a/src/main/java/wooteco/subway/infra/JwtTokenProvider.java b/src/main/java/wooteco/subway/infra/JwtTokenProvider.java index b1fa55a04..48fbbc9c4 100644 --- a/src/main/java/wooteco/subway/infra/JwtTokenProvider.java +++ b/src/main/java/wooteco/subway/infra/JwtTokenProvider.java @@ -18,7 +18,8 @@ public class JwtTokenProvider { private String secretKey; private long validityInMilliseconds; - public JwtTokenProvider(@Value("${security.jwt.token.secret-key}") String secretKey, @Value("${security.jwt.token.expire-length}") long validityInMilliseconds) { + public JwtTokenProvider(@Value("${security.jwt.token.secret-key}") String secretKey, + @Value("${security.jwt.token.expire-length}") long validityInMilliseconds) { this.secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); this.validityInMilliseconds = validityInMilliseconds; } @@ -28,14 +29,14 @@ public String createToken(String subject) { Date now = new Date(); Date validity = new Date(now.getTime() - + validityInMilliseconds); + + validityInMilliseconds); return Jwts.builder() - .setClaims(claims) - .setIssuedAt(now) - .setExpiration(validity) - .signWith(SignatureAlgorithm.HS256, secretKey) - .compact(); + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); } public String getSubject(String token) { diff --git a/src/main/java/wooteco/subway/service/line/LineService.java b/src/main/java/wooteco/subway/service/line/LineService.java index 2f2485c1a..4f920a6e4 100644 --- a/src/main/java/wooteco/subway/service/line/LineService.java +++ b/src/main/java/wooteco/subway/service/line/LineService.java @@ -1,36 +1,54 @@ package wooteco.subway.service.line; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + import org.springframework.stereotype.Service; + +import lombok.AllArgsConstructor; +import wooteco.subway.domain.line.Line; +import wooteco.subway.domain.line.LineRepository; +import wooteco.subway.domain.linestation.LineStation; +import wooteco.subway.domain.station.Station; import wooteco.subway.service.line.dto.LineDetailResponse; import wooteco.subway.service.line.dto.LineRequest; +import wooteco.subway.service.line.dto.LineResponse; import wooteco.subway.service.line.dto.LineStationCreateRequest; import wooteco.subway.service.line.dto.WholeSubwayResponse; -import wooteco.subway.domain.line.Line; -import wooteco.subway.domain.line.LineRepository; -import wooteco.subway.domain.line.LineStation; - -import java.util.List; @Service +@AllArgsConstructor public class LineService { private LineStationService lineStationService; private LineRepository lineRepository; - public LineService(LineStationService lineStationService, LineRepository lineRepository) { - this.lineStationService = lineStationService; - this.lineRepository = lineRepository; - } - - public Line save(Line line) { - return lineRepository.save(line); + public LineResponse save(Line line) { + return LineResponse.of(lineRepository.save(line)); } - public List findLines() { - return lineRepository.findAll(); + public List findLines() { + return LineResponse.listOf(lineRepository.findAll()); } - public Line findLineById(Long id) { - return lineRepository.findById(id).orElseThrow(RuntimeException::new); + public void addLineStation(Long id, LineStationCreateRequest request) { + Line line = lineRepository.findById(id).orElseThrow(RuntimeException::new); + List stations = lineStationService.findAllByStation( + Arrays.asList(request.getPreStationId(), request.getStationId())); + Station preStation = stations.stream() + .filter( + station -> Objects.nonNull(station) && station.isSameId(request.getPreStationId())) + .findAny() + .orElse(null); + Station nextStation = stations.stream() + .filter(station -> Objects.nonNull(station) && station.isSameId(request.getStationId())) + .findAny() + .orElseThrow(RuntimeException::new); + LineStation lineStation = new LineStation(preStation, nextStation, request.getDistance(), + request.getDuration()); + lineStation.applyLine(line); + lineRepository.save(line); } public void updateLine(Long id, LineRequest request) { @@ -39,29 +57,30 @@ public void updateLine(Long id, LineRequest request) { lineRepository.save(persistLine); } - public void deleteLineById(Long id) { - lineRepository.deleteById(id); - } - - public void addLineStation(Long id, LineStationCreateRequest request) { - Line line = lineRepository.findById(id).orElseThrow(RuntimeException::new); - LineStation lineStation = new LineStation(request.getPreStationId(), request.getStationId(), request.getDistance(), request.getDuration()); - line.addLineStation(lineStation); - - lineRepository.save(line); - } - public void removeLineStation(Long lineId, Long stationId) { Line line = lineRepository.findById(lineId).orElseThrow(RuntimeException::new); line.removeLineStationById(stationId); lineRepository.save(line); } + public void deleteLine(Long id) { + lineRepository.deleteById(id); + } + public LineDetailResponse retrieveLine(Long id) { return lineStationService.findLineWithStationsById(id); } - public WholeSubwayResponse findLinesWithStations() { - return lineStationService.findLinesWithStations(); + public WholeSubwayResponse findAllLines() { + List responses = lineRepository.findAll().stream() + .map(line -> { + List stations = line.getStations() + .stream() + .map(LineStation::getNextStation) + .collect(Collectors.toList()); + return LineDetailResponse.of(line, stations); + }).collect(Collectors.toList()); + + return WholeSubwayResponse.of(responses); } } diff --git a/src/main/java/wooteco/subway/service/line/LineStationService.java b/src/main/java/wooteco/subway/service/line/LineStationService.java index b3f79d842..6d3d18fde 100644 --- a/src/main/java/wooteco/subway/service/line/LineStationService.java +++ b/src/main/java/wooteco/subway/service/line/LineStationService.java @@ -1,50 +1,43 @@ package wooteco.subway.service.line; +import java.util.List; +import java.util.stream.Collectors; + import org.springframework.stereotype.Service; -import wooteco.subway.service.line.dto.LineDetailResponse; -import wooteco.subway.service.line.dto.WholeSubwayResponse; + +import lombok.AllArgsConstructor; import wooteco.subway.domain.line.Line; import wooteco.subway.domain.line.LineRepository; -import wooteco.subway.domain.line.Lines; +import wooteco.subway.domain.linestation.LineStation; import wooteco.subway.domain.station.Station; import wooteco.subway.domain.station.StationRepository; - -import java.util.List; -import java.util.stream.Collectors; +import wooteco.subway.service.line.dto.LineDetailResponse; +import wooteco.subway.service.line.dto.WholeSubwayResponse; @Service +@AllArgsConstructor public class LineStationService { private LineRepository lineRepository; private StationRepository stationRepository; - public LineStationService(LineRepository lineRepository, StationRepository stationRepository) { - this.lineRepository = lineRepository; - this.stationRepository = stationRepository; - } - public LineDetailResponse findLineWithStationsById(Long lineId) { Line line = lineRepository.findById(lineId).orElseThrow(RuntimeException::new); - List lineStationIds = line.getStationIds(); - List stations = stationRepository.findAllById(lineStationIds); + List stations = line.getStations() + .stream() + .map(LineStation::getNextStation) + .collect(Collectors.toList()); - return LineDetailResponse.of(line, mapStations(lineStationIds, stations)); + return LineDetailResponse.of(line, stations); } - public WholeSubwayResponse findLinesWithStations() { - Lines lines = new Lines(lineRepository.findAll()); - List stations = stationRepository.findAllById(lines.getStationIds()); - - List lineDetailResponses = lines.getLines().stream() - .map(it -> LineDetailResponse.of(it, mapStations(it.getStationIds(), stations))) - .collect(Collectors.toList()); - - return WholeSubwayResponse.of(lineDetailResponses); + public List findAllByStation(Iterable stations) { + return stationRepository.findAllById(stations); } private List mapStations(List stationsIds, List stations) { return stations.stream() - .filter(it -> stationsIds.contains(it.getId())) - .collect(Collectors.toList()); + .filter(it -> stationsIds.contains(it.getId())) + .collect(Collectors.toList()); } public void deleteLineStationByStationId(Long stationId) { @@ -52,4 +45,17 @@ public void deleteLineStationByStationId(Long stationId) { lines.stream().forEach(it -> it.removeLineStationById(stationId)); lineRepository.saveAll(lines); } + + public WholeSubwayResponse findLinesWithStations() { + List responses = lineRepository.findAll().stream() + .map(line -> { + List stations = line.getStations() + .stream() + .map(LineStation::getNextStation) + .collect(Collectors.toList()); + return LineDetailResponse.of(line, stations); + }).collect(Collectors.toList()); + + return WholeSubwayResponse.of(responses); + } } diff --git a/src/main/java/wooteco/subway/service/line/dto/LineDetailResponse.java b/src/main/java/wooteco/subway/service/line/dto/LineDetailResponse.java index 42d3b18b7..b9f53f265 100644 --- a/src/main/java/wooteco/subway/service/line/dto/LineDetailResponse.java +++ b/src/main/java/wooteco/subway/service/line/dto/LineDetailResponse.java @@ -1,13 +1,13 @@ package wooteco.subway.service.line.dto; -import wooteco.subway.service.station.dto.StationResponse; -import wooteco.subway.domain.station.Station; -import wooteco.subway.domain.line.Line; - import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; +import wooteco.subway.domain.line.Line; +import wooteco.subway.domain.station.Station; +import wooteco.subway.service.station.dto.StationResponse; + public class LineDetailResponse { private Long id; private String name; @@ -21,7 +21,9 @@ public class LineDetailResponse { public LineDetailResponse() { } - public LineDetailResponse(Long id, String name, LocalTime startTime, LocalTime endTime, int intervalTime, LocalDateTime createdAt, LocalDateTime updatedAt, List stations) { + public LineDetailResponse(Long id, String name, LocalTime startTime, LocalTime endTime, + int intervalTime, LocalDateTime createdAt, LocalDateTime updatedAt, + List stations) { this.id = id; this.name = name; this.startTime = startTime; @@ -33,7 +35,9 @@ public LineDetailResponse(Long id, String name, LocalTime startTime, LocalTime e } public static LineDetailResponse of(Line line, List stations) { - return new LineDetailResponse(line.getId(), line.getName(), line.getStartTime(), line.getEndTime(), line.getIntervalTime(), line.getCreatedAt(), line.getUpdatedAt(), stations); + return new LineDetailResponse(line.getId(), line.getName(), line.getStartTime(), + line.getEndTime(), line.getIntervalTime(), line.getCreatedAt(), line.getUpdatedAt(), + stations); } public Long getId() { diff --git a/src/main/java/wooteco/subway/service/line/dto/LineRequest.java b/src/main/java/wooteco/subway/service/line/dto/LineRequest.java index 4900b2171..b26c47776 100644 --- a/src/main/java/wooteco/subway/service/line/dto/LineRequest.java +++ b/src/main/java/wooteco/subway/service/line/dto/LineRequest.java @@ -1,9 +1,9 @@ package wooteco.subway.service.line.dto; -import wooteco.subway.domain.line.Line; - import java.time.LocalTime; +import wooteco.subway.domain.line.Line; + public class LineRequest { private String name; private LocalTime startTime; @@ -30,6 +30,6 @@ public int getIntervalTime() { } public Line toLine() { - return new Line(name, startTime, endTime, intervalTime); + return Line.of(name, startTime, endTime, intervalTime); } } diff --git a/src/main/java/wooteco/subway/service/line/dto/LineResponse.java b/src/main/java/wooteco/subway/service/line/dto/LineResponse.java index 08e16d70d..adcb8b35a 100644 --- a/src/main/java/wooteco/subway/service/line/dto/LineResponse.java +++ b/src/main/java/wooteco/subway/service/line/dto/LineResponse.java @@ -1,12 +1,12 @@ package wooteco.subway.service.line.dto; -import wooteco.subway.domain.line.Line; - import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; import java.util.stream.Collectors; +import wooteco.subway.domain.line.Line; + public class LineResponse { private Long id; private String name; @@ -16,20 +16,11 @@ public class LineResponse { private LocalDateTime createdAt; private LocalDateTime updatedAt; - public static LineResponse of(Line line) { - return new LineResponse(line.getId(), line.getName(), line.getStartTime(), line.getEndTime(), line.getIntervalTime(), line.getCreatedAt(), line.getUpdatedAt()); - } - - public static List listOf(List lines) { - return lines.stream() - .map(it -> LineResponse.of(it)) - .collect(Collectors.toList()); - } - public LineResponse() { } - public LineResponse(Long id, String name, LocalTime startTime, LocalTime endTime, int intervalTime, LocalDateTime createdAt, LocalDateTime updatedAt) { + public LineResponse(Long id, String name, LocalTime startTime, LocalTime endTime, + int intervalTime, LocalDateTime createdAt, LocalDateTime updatedAt) { this.id = id; this.name = name; this.startTime = startTime; @@ -39,6 +30,17 @@ public LineResponse(Long id, String name, LocalTime startTime, LocalTime endTime this.updatedAt = updatedAt; } + public static LineResponse of(Line line) { + return new LineResponse(line.getId(), line.getName(), line.getStartTime(), + line.getEndTime(), line.getIntervalTime(), line.getCreatedAt(), line.getUpdatedAt()); + } + + public static List listOf(List lines) { + return lines.stream() + .map(it -> LineResponse.of(it)) + .collect(Collectors.toList()); + } + public Long getId() { return id; } diff --git a/src/main/java/wooteco/subway/service/line/dto/WholeSubwayResponse.java b/src/main/java/wooteco/subway/service/line/dto/WholeSubwayResponse.java index 1eb0bbd6f..a34b64d6d 100644 --- a/src/main/java/wooteco/subway/service/line/dto/WholeSubwayResponse.java +++ b/src/main/java/wooteco/subway/service/line/dto/WholeSubwayResponse.java @@ -5,10 +5,6 @@ public class WholeSubwayResponse { private List lineDetailResponse; - public static WholeSubwayResponse of(List lineDetailResponses) { - return new WholeSubwayResponse(lineDetailResponses); - } - public WholeSubwayResponse() { } @@ -16,6 +12,10 @@ public WholeSubwayResponse(List lineDetailResponse) { this.lineDetailResponse = lineDetailResponse; } + public static WholeSubwayResponse of(List lineDetailResponses) { + return new WholeSubwayResponse(lineDetailResponses); + } + public List getLineDetailResponse() { return lineDetailResponse; } diff --git a/src/main/java/wooteco/subway/service/path/GraphService.java b/src/main/java/wooteco/subway/service/path/GraphService.java index b8683cdd1..969b37d8c 100644 --- a/src/main/java/wooteco/subway/service/path/GraphService.java +++ b/src/main/java/wooteco/subway/service/path/GraphService.java @@ -1,29 +1,35 @@ package wooteco.subway.service.path; +import java.util.List; +import java.util.Objects; + import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.WeightedMultigraph; import org.springframework.stereotype.Service; + import wooteco.subway.domain.line.Line; +import wooteco.subway.domain.linestation.LineStation; import wooteco.subway.domain.path.PathType; -import java.util.List; -import java.util.Objects; - @Service public class GraphService { public List findPath(List lines, Long source, Long target, PathType type) { WeightedMultigraph graph - = new WeightedMultigraph(DefaultWeightedEdge.class); + = new WeightedMultigraph(DefaultWeightedEdge.class); lines.stream() - .flatMap(it -> it.getStationIds().stream()) - .forEach(it -> graph.addVertex(it)); + .flatMap(it -> it.getStations().stream()) + .map(LineStation::getId) + .forEach(graph::addVertex); lines.stream() - .flatMap(it -> it.getStations().stream()) - .filter(it -> Objects.nonNull(it.getPreStationId())) - .forEach(it -> graph.setEdgeWeight(graph.addEdge(it.getPreStationId(), it.getStationId()), type.findWeightOf(it))); + .flatMap(it -> it.getStations().stream()) + .filter(it -> Objects.nonNull(it.getPreStation())) + .forEach( + it -> graph.setEdgeWeight( + graph.addEdge(it.getPreStation().getId(), it.getNextStation().getId()), + type.findWeightOf(it))); DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph); return dijkstraShortestPath.getPath(source, target).getVertexList(); diff --git a/src/main/java/wooteco/subway/service/path/PathService.java b/src/main/java/wooteco/subway/service/path/PathService.java index ad038bda1..30059cea7 100644 --- a/src/main/java/wooteco/subway/service/path/PathService.java +++ b/src/main/java/wooteco/subway/service/path/PathService.java @@ -1,31 +1,28 @@ package wooteco.subway.service.path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + import org.springframework.stereotype.Service; -import wooteco.subway.service.path.dto.PathResponse; -import wooteco.subway.service.station.dto.StationResponse; + +import lombok.AllArgsConstructor; import wooteco.subway.domain.line.Line; import wooteco.subway.domain.line.LineRepository; -import wooteco.subway.domain.line.LineStation; +import wooteco.subway.domain.linestation.LineStation; import wooteco.subway.domain.path.PathType; import wooteco.subway.domain.station.Station; import wooteco.subway.domain.station.StationRepository; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; +import wooteco.subway.service.path.dto.PathResponse; +import wooteco.subway.service.station.dto.StationResponse; @Service +@AllArgsConstructor public class PathService { - private StationRepository stationRepository; - private LineRepository lineRepository; - private GraphService graphService; - - public PathService(StationRepository stationRepository, LineRepository lineRepository, GraphService graphService) { - this.stationRepository = stationRepository; - this.lineRepository = lineRepository; - this.graphService = graphService; - } + private final StationRepository stationRepository; + private final LineRepository lineRepository; + private final GraphService graphService; public PathResponse findPath(String source, String target, PathType type) { if (Objects.equals(source, target)) { @@ -33,36 +30,40 @@ public PathResponse findPath(String source, String target, PathType type) { } List lines = lineRepository.findAll(); - Station sourceStation = stationRepository.findByName(source).orElseThrow(RuntimeException::new); - Station targetStation = stationRepository.findByName(target).orElseThrow(RuntimeException::new); + Station sourceStation = stationRepository.findByName(source) + .orElseThrow(RuntimeException::new); + Station targetStation = stationRepository.findByName(target) + .orElseThrow(RuntimeException::new); - List path = graphService.findPath(lines, sourceStation.getId(), targetStation.getId(), type); + List path = graphService.findPath(lines, sourceStation.getId(), targetStation.getId(), + type); List stations = stationRepository.findAllById(path); List lineStations = lines.stream() - .flatMap(it -> it.getStations().stream()) - .filter(it -> Objects.nonNull(it.getPreStationId())) - .collect(Collectors.toList()); + .flatMap(it -> it.getStations().stream()) + .filter(it -> Objects.nonNull(it.getPreStation())) + .collect(Collectors.toList()); List paths = extractPathLineStation(path, lineStations); - int duration = paths.stream().mapToInt(it -> it.getDuration()).sum(); - int distance = paths.stream().mapToInt(it -> it.getDistance()).sum(); + int duration = paths.stream().mapToInt(LineStation::getDuration).sum(); + int distance = paths.stream().mapToInt(LineStation::getDistance).sum(); List pathStation = path.stream() - .map(it -> extractStation(it, stations)) - .collect(Collectors.toList()); + .map(it -> extractStation(it, stations)) + .collect(Collectors.toList()); return new PathResponse(StationResponse.listOf(pathStation), duration, distance); } private Station extractStation(Long stationId, List stations) { return stations.stream() - .filter(it -> it.getId() == stationId) - .findFirst() - .orElseThrow(RuntimeException::new); + .filter(it -> it.getId().equals(stationId)) + .findFirst() + .orElseThrow(RuntimeException::new); } - private List extractPathLineStation(List path, List lineStations) { + private List extractPathLineStation(List path, + List lineStations) { Long preStationId = null; List paths = new ArrayList<>(); @@ -74,9 +75,9 @@ private List extractPathLineStation(List path, List it.isLineStationOf(finalPreStationId, stationId)) - .findFirst() - .orElseThrow(RuntimeException::new); + .filter(it -> it.isLineStationOf(finalPreStationId, stationId)) + .findFirst() + .orElseThrow(RuntimeException::new); paths.add(lineStation); preStationId = stationId; diff --git a/src/main/java/wooteco/subway/service/path/dto/PathResponse.java b/src/main/java/wooteco/subway/service/path/dto/PathResponse.java index 7d03a8f70..8f1be3aba 100644 --- a/src/main/java/wooteco/subway/service/path/dto/PathResponse.java +++ b/src/main/java/wooteco/subway/service/path/dto/PathResponse.java @@ -1,9 +1,9 @@ package wooteco.subway.service.path.dto; -import wooteco.subway.service.station.dto.StationResponse; - import java.util.List; +import wooteco.subway.service.station.dto.StationResponse; + public class PathResponse { private List stations; private int duration; diff --git a/src/main/java/wooteco/subway/service/station/StationService.java b/src/main/java/wooteco/subway/service/station/StationService.java index 871d67eac..6134bc0f5 100644 --- a/src/main/java/wooteco/subway/service/station/StationService.java +++ b/src/main/java/wooteco/subway/service/station/StationService.java @@ -5,24 +5,18 @@ import org.springframework.stereotype.Service; +import lombok.AllArgsConstructor; import wooteco.subway.domain.station.Station; import wooteco.subway.domain.station.StationRepository; -import wooteco.subway.service.line.LineStationService; -import wooteco.subway.web.exception.NotFoundStationException; +import wooteco.subway.service.station.dto.StationCreateRequest; @Service +@AllArgsConstructor public class StationService { - private LineStationService lineStationService; - private StationRepository stationRepository; + private final StationRepository stationRepository; - public StationService(LineStationService lineStationService, - StationRepository stationRepository) { - this.lineStationService = lineStationService; - this.stationRepository = stationRepository; - } - - public Station createStation(Station station) { - return stationRepository.save(station); + public Station createStation(StationCreateRequest request) { + return stationRepository.save(request.toStation()); } public List findStations() { @@ -30,17 +24,22 @@ public List findStations() { } public void deleteStationById(Long id) { - lineStationService.deleteLineStationByStationId(id); stationRepository.deleteById(id); } - public Long findStationIdByName(String name) { - return stationRepository.findByName(name) - .map(Station::getId) - .orElseThrow(() -> new NotFoundStationException(name + "역을 찾을 수 없습니다.")); - } + // public Long findStationIdByName(String name) { + // return stationRepository.findByName(name) + // .stream() + // .map(Station::getId) + // .findAny() + // .orElseThrow(() -> new NotFoundStationException(name + "역을 찾을 수 없습니다.")); + // } public List findAllById(Collection ids) { return stationRepository.findAllById(ids); } + + public List findAllByStationName(List stations) { + return stationRepository.findAllByStationName(stations); + } } diff --git a/src/main/java/wooteco/subway/service/station/dto/StationCreateRequest.java b/src/main/java/wooteco/subway/service/station/dto/StationCreateRequest.java index a58ae9289..1f4eb6e06 100644 --- a/src/main/java/wooteco/subway/service/station/dto/StationCreateRequest.java +++ b/src/main/java/wooteco/subway/service/station/dto/StationCreateRequest.java @@ -1,16 +1,15 @@ package wooteco.subway.service.station.dto; - +import lombok.Getter; +import lombok.NoArgsConstructor; import wooteco.subway.domain.station.Station; +@Getter +@NoArgsConstructor public class StationCreateRequest { private String name; - public String getName() { - return name; - } - public Station toStation() { - return new Station(name); + return Station.of(name); } } diff --git a/src/main/java/wooteco/subway/service/station/dto/StationResponse.java b/src/main/java/wooteco/subway/service/station/dto/StationResponse.java index 18011a71a..6f13a3d3b 100644 --- a/src/main/java/wooteco/subway/service/station/dto/StationResponse.java +++ b/src/main/java/wooteco/subway/service/station/dto/StationResponse.java @@ -1,44 +1,31 @@ package wooteco.subway.service.station.dto; -import wooteco.subway.domain.station.Station; - import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import wooteco.subway.domain.station.Station; + +@NoArgsConstructor +@AllArgsConstructor +@Getter public class StationResponse { private Long id; private String name; private LocalDateTime createdAt; + private LocalDateTime updatedAt; public static StationResponse of(Station station) { - return new StationResponse(station.getId(), station.getName(), station.getCreatedAt()); + return new StationResponse(station.getId(), station.getName(), station.getCreatedAt(), + station.getUpdatedAt()); } public static List listOf(List stations) { return stations.stream() - .map(StationResponse::of) - .collect(Collectors.toList()); - } - - public StationResponse() { - } - - public StationResponse(Long id, String name, LocalDateTime createdAt) { - this.id = id; - this.name = name; - this.createdAt = createdAt; - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public LocalDateTime getCreatedAt() { - return createdAt; + .map(StationResponse::of) + .collect(Collectors.toList()); } } diff --git a/src/main/java/wooteco/subway/web/controller/LineController.java b/src/main/java/wooteco/subway/web/controller/LineController.java index c9b94ef69..20d35cf2e 100644 --- a/src/main/java/wooteco/subway/web/controller/LineController.java +++ b/src/main/java/wooteco/subway/web/controller/LineController.java @@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import wooteco.subway.domain.line.Line; import wooteco.subway.service.line.LineService; import wooteco.subway.service.line.dto.LineDetailResponse; import wooteco.subway.service.line.dto.LineRequest; @@ -30,16 +29,16 @@ public LineController(LineService lineService) { @PostMapping(value = "/lines") public ResponseEntity createLine(@RequestBody LineRequest view) { - Line persistLine = lineService.save(view.toLine()); + LineResponse persistLine = lineService.save(view.toLine()); return ResponseEntity - .created(URI.create("/lines/" + persistLine.getId())) - .body(LineResponse.of(persistLine)); + .created(URI.create("/lines/" + persistLine.getId())) + .body(persistLine); } @GetMapping("/lines") public ResponseEntity> showLine() { - return ResponseEntity.ok().body(LineResponse.listOf(lineService.findLines())); + return ResponseEntity.ok().body(lineService.findLines()); } @GetMapping("/lines/{id}") @@ -48,32 +47,34 @@ public ResponseEntity retrieveLine(@PathVariable Long id) { } @PutMapping("/lines/{id}") - public ResponseEntity updateLine(@PathVariable Long id, @RequestBody LineRequest view) { + public ResponseEntity updateLine(@PathVariable Long id, @RequestBody LineRequest view) { lineService.updateLine(id, view); return ResponseEntity.ok().build(); } @DeleteMapping("/lines/{id}") - public ResponseEntity deleteLine(@PathVariable Long id) { - lineService.deleteLineById(id); + public ResponseEntity deleteLine(@PathVariable Long id) { + lineService.deleteLine(id); return ResponseEntity.noContent().build(); } @PostMapping("/lines/{lineId}/stations") - public ResponseEntity addLineStation(@PathVariable Long lineId, @RequestBody LineStationCreateRequest view) { + public ResponseEntity addLineStation(@PathVariable Long lineId, + @RequestBody LineStationCreateRequest view) { lineService.addLineStation(lineId, view); return ResponseEntity.ok().build(); } @DeleteMapping("/lines/{lineId}/stations/{stationId}") - public ResponseEntity removeLineStation(@PathVariable Long lineId, @PathVariable Long stationId) { + public ResponseEntity removeLineStation(@PathVariable Long lineId, + @PathVariable Long stationId) { lineService.removeLineStation(lineId, stationId); return ResponseEntity.noContent().build(); } @GetMapping("/lines/detail") - public ResponseEntity wholeLines() { - WholeSubwayResponse result = lineService.findLinesWithStations(); + public ResponseEntity wholeLines() { + WholeSubwayResponse result = lineService.findAllLines(); return ResponseEntity.ok().body(result); } } diff --git a/src/main/java/wooteco/subway/web/controller/LoginMemberController.java b/src/main/java/wooteco/subway/web/controller/LoginMemberController.java index c6f64b0c3..f9130b81d 100644 --- a/src/main/java/wooteco/subway/web/controller/LoginMemberController.java +++ b/src/main/java/wooteco/subway/web/controller/LoginMemberController.java @@ -44,15 +44,17 @@ public ResponseEntity getMemberOfMineBasic(@LoginMember Member m @IsAuth @GetMapping("/me/detail") - public ResponseEntity getMemberDetailOfMineBasic(@LoginMember Member member) { + public ResponseEntity getMemberDetailOfMineBasic( + @LoginMember Member member) { Set responses = favoriteService.getAll(member); return ResponseEntity.ok().body(MemberDetailResponse.of(member, responses)); } @IsAuth @GetMapping("/me/favorites") - public ResponseEntity> getMemberFavorites(@LoginMember Member member) { - Set responses = favoriteService.getAll(member); + public ResponseEntity> getMemberFavorites( + @LoginMember Member member) { + Set responses = favoriteService.getAll(member); return ResponseEntity.ok().body(responses); } } diff --git a/src/main/java/wooteco/subway/web/controller/PathController.java b/src/main/java/wooteco/subway/web/controller/PathController.java index 6f90262ba..e2ebec3fb 100644 --- a/src/main/java/wooteco/subway/web/controller/PathController.java +++ b/src/main/java/wooteco/subway/web/controller/PathController.java @@ -18,8 +18,8 @@ public PathController(PathService pathService) { @GetMapping("/paths") public ResponseEntity findPath(@RequestParam String source, - @RequestParam String target, - @RequestParam PathType type) { + @RequestParam String target, + @RequestParam PathType type) { return ResponseEntity.ok(pathService.findPath(source, target, type)); } } diff --git a/src/main/java/wooteco/subway/web/controller/StationController.java b/src/main/java/wooteco/subway/web/controller/StationController.java index 8111f2590..8fe94833f 100644 --- a/src/main/java/wooteco/subway/web/controller/StationController.java +++ b/src/main/java/wooteco/subway/web/controller/StationController.java @@ -11,26 +11,25 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import lombok.AllArgsConstructor; import wooteco.subway.domain.station.Station; import wooteco.subway.service.station.StationService; import wooteco.subway.service.station.dto.StationCreateRequest; import wooteco.subway.service.station.dto.StationResponse; @RestController +@AllArgsConstructor public class StationController { private final StationService stationService; - public StationController(StationService stationService) { - this.stationService = stationService; - } - @PostMapping("/stations") - public ResponseEntity createStation(@RequestBody StationCreateRequest view) { - Station persistStation = stationService.createStation(view.toStation()); + public ResponseEntity createStation( + @RequestBody StationCreateRequest request) { + Station persistStation = stationService.createStation(request); return ResponseEntity - .created(URI.create("/stations/" + persistStation.getId())) - .body(StationResponse.of(persistStation)); + .created(URI.create("/stations/" + persistStation.getId())) + .body(StationResponse.of(persistStation)); } @GetMapping("/stations") @@ -39,7 +38,7 @@ public ResponseEntity> showStations() { } @DeleteMapping("/stations/{id}") - public ResponseEntity deleteStation(@PathVariable Long id) { + public ResponseEntity deleteStation(@PathVariable Long id) { stationService.deleteStationById(id); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/wooteco/subway/web/exception/AuthenticationException.java b/src/main/java/wooteco/subway/web/exception/AuthenticationException.java index b3721e3ec..b07f50045 100644 --- a/src/main/java/wooteco/subway/web/exception/AuthenticationException.java +++ b/src/main/java/wooteco/subway/web/exception/AuthenticationException.java @@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.UNAUTHORIZED) -public class AuthenticationException extends RuntimeException{ +public class AuthenticationException extends RuntimeException { public AuthenticationException() { super(); } diff --git a/src/main/java/wooteco/subway/web/exception/BusinessException.java b/src/main/java/wooteco/subway/web/exception/BusinessException.java index eeee8d3df..9e666515e 100644 --- a/src/main/java/wooteco/subway/web/exception/BusinessException.java +++ b/src/main/java/wooteco/subway/web/exception/BusinessException.java @@ -1,6 +1,6 @@ package wooteco.subway.web.exception; -public class BusinessException extends RuntimeException{ +public class BusinessException extends RuntimeException { public BusinessException() { super(); } diff --git a/src/main/java/wooteco/subway/web/exception/InvalidAuthenticationException.java b/src/main/java/wooteco/subway/web/exception/InvalidAuthenticationException.java index 01b8ca1f8..2a3f3d5e3 100644 --- a/src/main/java/wooteco/subway/web/exception/InvalidAuthenticationException.java +++ b/src/main/java/wooteco/subway/web/exception/InvalidAuthenticationException.java @@ -1,6 +1,6 @@ package wooteco.subway.web.exception; -public class InvalidAuthenticationException extends AuthenticationException{ +public class InvalidAuthenticationException extends AuthenticationException { public InvalidAuthenticationException(String message) { super(message); } diff --git a/src/main/java/wooteco/subway/web/prehandler/BearerAuthInterceptor.java b/src/main/java/wooteco/subway/web/prehandler/BearerAuthInterceptor.java index c24d5a235..0bd9f6281 100644 --- a/src/main/java/wooteco/subway/web/prehandler/BearerAuthInterceptor.java +++ b/src/main/java/wooteco/subway/web/prehandler/BearerAuthInterceptor.java @@ -19,38 +19,43 @@ public class BearerAuthInterceptor implements HandlerInterceptor { private AuthorizationExtractor authExtractor; private JwtTokenProvider jwtTokenProvider; - public BearerAuthInterceptor(AuthorizationExtractor authExtractor, JwtTokenProvider jwtTokenProvider) { + public BearerAuthInterceptor(AuthorizationExtractor authExtractor, + JwtTokenProvider jwtTokenProvider) { this.authExtractor = authExtractor; this.jwtTokenProvider = jwtTokenProvider; } @Override public boolean preHandle(HttpServletRequest request, - HttpServletResponse response, Object handler) { - IsAuth annotation = getAnnotation((HandlerMethod)handler, IsAuth.class); - if (!ObjectUtils.isEmpty(annotation)) { - String bearer = authExtractor.extract(request); - jwtTokenProvider.validateToken(bearer); - String email = jwtTokenProvider.getSubject(bearer); - request.setAttribute("loginMemberEmail", email); + HttpServletResponse response, Object handler) { + if (handler instanceof HandlerMethod) { + IsAuth annotation = getAnnotation((HandlerMethod)handler, IsAuth.class); + if (!ObjectUtils.isEmpty(annotation)) { + String bearer = authExtractor.extract(request); + jwtTokenProvider.validateToken(bearer); + String email = jwtTokenProvider.getSubject(bearer); + request.setAttribute("loginMemberEmail", email); + } } return true; } @Override public void postHandle(HttpServletRequest request, - HttpServletResponse response, - Object handler, - ModelAndView modelAndView) throws Exception { + HttpServletResponse response, + Object handler, + ModelAndView modelAndView) throws Exception { } @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, + Object handler, Exception ex) throws Exception { } - private A getAnnotation(HandlerMethod handlerMethod, Class annotationType) { + private A getAnnotation(HandlerMethod handlerMethod, + Class annotationType) { return Optional.ofNullable(handlerMethod.getMethodAnnotation(annotationType)) .orElse(handlerMethod.getBeanType().getAnnotation(annotationType)); } diff --git a/src/main/java/wooteco/subway/web/prehandler/LoginMemberMethodArgumentResolver.java b/src/main/java/wooteco/subway/web/prehandler/LoginMemberMethodArgumentResolver.java index afd84393b..fd6742cb2 100644 --- a/src/main/java/wooteco/subway/web/prehandler/LoginMemberMethodArgumentResolver.java +++ b/src/main/java/wooteco/subway/web/prehandler/LoginMemberMethodArgumentResolver.java @@ -29,10 +29,10 @@ public boolean supportsParameter(MethodParameter parameter) { @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { - String email = (String) webRequest.getAttribute("loginMemberEmail", SCOPE_REQUEST); + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + String email = (String)webRequest.getAttribute("loginMemberEmail", SCOPE_REQUEST); if (StringUtils.isBlank(email)) { - return new Member(); + return Member.of(); } try { return memberService.findMemberByEmail(email); diff --git a/src/main/java/wooteco/subway/web/prehandler/validator/PasswordMatchValidator.java b/src/main/java/wooteco/subway/web/prehandler/validator/PasswordMatchValidator.java index e1c67e4a6..7b9f7ac37 100644 --- a/src/main/java/wooteco/subway/web/prehandler/validator/PasswordMatchValidator.java +++ b/src/main/java/wooteco/subway/web/prehandler/validator/PasswordMatchValidator.java @@ -8,19 +8,18 @@ import org.springframework.beans.BeanWrapperImpl; public class PasswordMatchValidator implements ConstraintValidator { - private String field; - private String fieldMatch; + private String field; + private String fieldMatch; + public void initialize(PasswordMatch constraint) { + this.field = constraint.field(); + this.fieldMatch = constraint.fieldMatch(); + } - public void initialize(PasswordMatch constraint) { - this.field = constraint.field(); - this.fieldMatch = constraint.fieldMatch(); - } + public boolean isValid(Object value, ConstraintValidatorContext context) { + Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field); + Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch); - public boolean isValid(Object value, ConstraintValidatorContext context) { - Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field); - Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch); - - return Objects.equals(fieldValue, fieldMatchValue); - } + return Objects.equals(fieldValue, fieldMatchValue); + } } diff --git a/src/main/java/wooteco/subway/web/service/favorite/FavoriteService.java b/src/main/java/wooteco/subway/web/service/favorite/FavoriteService.java index 7cd76b8bf..6d0ca6a57 100644 --- a/src/main/java/wooteco/subway/web/service/favorite/FavoriteService.java +++ b/src/main/java/wooteco/subway/web/service/favorite/FavoriteService.java @@ -1,5 +1,6 @@ package wooteco.subway.web.service.favorite; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -36,39 +37,41 @@ public FavoriteService(MemberService memberService, StationService stationServic } public FavoriteResponse create(Member member, FavoriteRequest request) { - Favorite favorite = getFavorite(member, request); + Favorite favorite = makeFavorite(member, request); return FavoriteResponse.of(favoriteRepository.save(favorite)); } public void delete(Member member, Long id) { - Favorite favorite = favoriteRepository.findByIdAndMemberId(id, member.getId()) + Favorite favorite = favoriteRepository.findById(id) .orElseThrow(() -> new NotFoundFavoriteException(id)); + favorite.validateMember(member); favoriteRepository.delete(favorite); } - private Favorite getFavorite(Member member, FavoriteRequest request) { - Long sourceId = stationService.findStationIdByName(request.getSourceName()); - Long targetId = stationService.findStationIdByName(request.getTargetName()); - - return Favorite.of(member.getId(), sourceId, targetId); - } - public Set getAll(Member member) { List favorites = favoriteRepository.findAllByMemberId(member.getId()); Set ids = new HashSet<>(); for (Favorite favorite : favorites) { - ids.add(favorite.getSourceId()); - ids.add(favorite.getTargetId()); + ids.add(favorite.getSourceStation().getId()); + ids.add(favorite.getTargetStation().getId()); } List stations = stationService.findAllById(ids); Map idToName = stations.stream() .collect(Collectors.toMap(Station::getId, Station::getName)); return favorites.stream() - .map(favorite -> new FavoriteDetailResponse(favorite.getId(), favorite.getMemberId(), - favorite.getSourceId(), favorite.getTargetId(), - idToName.get(favorite.getSourceId()), - idToName.get(favorite.getTargetId()))) + .map(favorite -> new FavoriteDetailResponse(favorite.getId(), + favorite.getMember().getId(), + favorite.getSourceStation().getId(), favorite.getTargetStation().getId(), + idToName.get(favorite.getSourceStation().getId()), + idToName.get(favorite.getTargetStation().getId()))) .collect(Collectors.toSet()); } + + private Favorite makeFavorite(Member member, FavoriteRequest request) { + List stations = stationService + .findAllByStationName(Arrays.asList(request.getSourceName(), request.getTargetName())); + + return Favorite.of(member, stations.get(0), stations.get(1)); + } } diff --git a/src/main/java/wooteco/subway/web/service/favorite/dto/FavoriteResponse.java b/src/main/java/wooteco/subway/web/service/favorite/dto/FavoriteResponse.java index a2df34e0c..2f15b981c 100644 --- a/src/main/java/wooteco/subway/web/service/favorite/dto/FavoriteResponse.java +++ b/src/main/java/wooteco/subway/web/service/favorite/dto/FavoriteResponse.java @@ -22,9 +22,9 @@ public FavoriteResponse(Long id, Long memberId, Long sourceId, Long targetId) { } public static FavoriteResponse of(Favorite favorite) { - return new FavoriteResponse(favorite.getId(), favorite.getMemberId(), - favorite.getSourceId(), - favorite.getTargetId()); + return new FavoriteResponse(favorite.getId(), favorite.getMember().getId(), + favorite.getSourceStation().getId(), + favorite.getTargetStation().getId()); } public static Set setOf(Set favorites) { diff --git a/src/main/java/wooteco/subway/web/service/member/MemberService.java b/src/main/java/wooteco/subway/web/service/member/MemberService.java index ce46df01b..736af5166 100644 --- a/src/main/java/wooteco/subway/web/service/member/MemberService.java +++ b/src/main/java/wooteco/subway/web/service/member/MemberService.java @@ -1,6 +1,6 @@ package wooteco.subway.web.service.member; -import java.util.Optional; +import java.util.Objects; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -44,9 +44,8 @@ public void deleteMember(Long id) { @Transactional(readOnly = true) public String createToken(LoginRequest param) { - Member member = memberRepository.findByEmail(param.getEmail()) - .orElseThrow(() -> new NotFoundMemberException(param.getEmail())); - if (!member.checkPassword(param.getPassword())) { + Member member = memberRepository.findByEmail(param.getEmail()); + if (Objects.isNull(member) || !member.checkPassword(param.getPassword())) { throw new NotMatchPasswordException(); } @@ -55,13 +54,11 @@ public String createToken(LoginRequest param) { @Transactional(readOnly = true) public Member findMemberByEmail(String email) { - return memberRepository.findByEmail(email) - .orElseThrow(() -> new NotFoundMemberException(email)); + return memberRepository.findByEmail(email); } @Transactional(readOnly = true) public boolean isExistEmail(String email) { - Optional byEmail = memberRepository.findByEmail(email); - return byEmail.isPresent(); + return Objects.nonNull(memberRepository.findByEmail(email)); } } diff --git a/src/main/java/wooteco/subway/web/service/member/dto/LoginRequest.java b/src/main/java/wooteco/subway/web/service/member/dto/LoginRequest.java index 7e6f501ea..fa34329df 100644 --- a/src/main/java/wooteco/subway/web/service/member/dto/LoginRequest.java +++ b/src/main/java/wooteco/subway/web/service/member/dto/LoginRequest.java @@ -1,22 +1,19 @@ package wooteco.subway.web.service.member.dto; -public class LoginRequest { - private String email; - private String password; +import javax.validation.constraints.NotBlank; - public LoginRequest() { - } +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; - public LoginRequest(String email, String password) { - this.email = email; - this.password = password; - } +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class LoginRequest { - public String getEmail() { - return email; - } + @NotBlank(message = "이메일은 필수 입력 사항입니다.") + private String email; - public String getPassword() { - return password; - } + @NotBlank(message = "비밀번호는 필수 입력 사항입니다.") + private String password; } diff --git a/src/main/java/wooteco/subway/web/service/member/dto/MemberRequest.java b/src/main/java/wooteco/subway/web/service/member/dto/MemberRequest.java index 27ac2f073..48cfe91cf 100644 --- a/src/main/java/wooteco/subway/web/service/member/dto/MemberRequest.java +++ b/src/main/java/wooteco/subway/web/service/member/dto/MemberRequest.java @@ -13,7 +13,9 @@ ) public class MemberRequest { - @Email @DuplicateCheck @NotBlank(message = "이메일은 필수 입력 사항입니다.") + @Email + @DuplicateCheck + @NotBlank(message = "이메일은 필수 입력 사항입니다.") private String email; @NotBlank(message = "이름은 필수 입력 사항입니다.") @@ -36,7 +38,7 @@ public MemberRequest(String email, String name, String password, String password } public Member toMember() { - return new Member(email, name, password); + return Member.of(name, email, password); } public String getEmail() { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 75ddeac2c..000000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,9 +0,0 @@ -logging.level.org.springframework.jdbc.core.JdbcTemplate=debug -spring.h2.console.enabled=true -spring.datasource.data=classpath:data.sql -handlebars.suffix=.html -security.jwt.token.secret-key=secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret -security.jwt.token.expire-length=3600000 -logging.level.org.springframework.web=DEBUG -logging.level.root=debug -spring.output.ansi.enabled=detect \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 000000000..791eda10f --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,31 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:tcp://localhost/~/jpa-subway + username: sa + password: + data: classpath:data.sql + + jpa: + database-platform: org.hibernate.dialect.H2Dialect + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + use_sql_comments: true + +logging: + level: + org: + hibernate: + SQL: DEBUG + +handlebars: + suffix: .html + +security: + jwt: + token: + secret-key: secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret + expire-length: 3600000 \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index b4c36e683..bb4bd7505 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,7 +1,6 @@ -INSERT INTO member (email, name, password) -VALUES ('dd@email.com', 'dd', 123); +insert into member (MEMBER_NAME, EMAIL, PASSWORD) values ('김디디', 'fucct@naver.com', 'c940429kk'); -insert into station (name) +insert into station (station_name) VALUES ('잠실'), ('잠실새내'), ('종합운동장'), @@ -11,20 +10,20 @@ VALUES ('잠실'), ('부산'), ('대구'); -insert into line (name, start_time, end_time, interval_time) +insert into line (line_name, start_time, end_time, interval_time) VALUES ('2호선', current_time, current_time, 3), ('9호선', current_time, current_time, 3), ('8호선', current_time, current_time, 3), ('ktx', current_time, current_time, 3); -insert into line_station (line, station_id, pre_station_id, distance, duration) +insert into line_station (line_id, next_station_id, pre_station_id, distance, duration) VALUES (1, 1, null, 0, 0), (1, 2, 1, 10, 1), (1, 3, 2, 10, 1), (2, 3, null, 0, 0), (2, 4, 3, 10, 1), - (2, 5, 4, 1, 10), - (2, 6, 5, 1, 10), + (2, 4, 5, 1, 10), + (2, 5, 6, 1, 10), (3, 1, null, 0, 0), (3, 6, 1, 1, 10), (4, 7, null, 10, 10), diff --git a/src/main/resources/logback-access.xml b/src/main/resources/logback-access.xml index f234ab8e2..ebf1f1f3f 100644 --- a/src/main/resources/logback-access.xml +++ b/src/main/resources/logback-access.xml @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql deleted file mode 100644 index d512800a1..000000000 --- a/src/main/resources/schema.sql +++ /dev/null @@ -1,48 +0,0 @@ -create table if not exists STATION -( - id bigint auto_increment not null, - name varchar(255) not null unique, - created_at datetime, - primary key(id) -); - -create table if not exists LINE -( - id bigint auto_increment not null, - name varchar(255) not null, - start_time time not null, - end_time time not null, - interval_time int not null, - created_at datetime, - updated_at datetime, - primary key(id) -); - -create table if not exists LINE_STATION -( - line bigint not null, - station_id bigint not null, - pre_station_id bigint, - distance int, - duration int, - created_at datetime, - updated_at datetime -); - -create table if not exists MEMBER -( - id bigint auto_increment not null, - email varchar(255) not null unique, - name varchar(255) not null, - password varchar(255) not null, - primary key(id) -); - -create table if not exists FAVORITE -( - id bigint auto_increment not null unique, - member_id bigint not null, - source_id bigint not null, - target_id bigint not null, - primary key(id) -); \ No newline at end of file diff --git a/src/main/resources/static/admin/js/views/AdminEdge.js b/src/main/resources/static/admin/js/views/AdminEdge.js index edf33835c..81430301a 100644 --- a/src/main/resources/static/admin/js/views/AdminEdge.js +++ b/src/main/resources/static/admin/js/views/AdminEdge.js @@ -1,6 +1,6 @@ -import { optionTemplate, subwayLinesItemTemplate, subwayLinesTemplate } from '../../utils/templates.js' +import { optionTemplate, subwayLinesItemTemplate } from '../../utils/templates.js' import tns from '../../lib/slider/tiny-slider.js' -import { EVENT_TYPE, ERROR_MESSAGE } from '../../utils/constants.js' +import { ERROR_MESSAGE, EVENT_TYPE } from '../../utils/constants.js' import Modal from '../../ui/Modal.js' import api from '../../api/index.js' @@ -37,24 +37,25 @@ function AdminEdge() { const lineId = $target.closest('.subway-line-item').dataset.id const stationId = $target.closest('.list-item').dataset.id api.line - .deleteLineStation(lineId, stationId) - .then(() => $target.closest('.list-item').remove()) - .catch(() => alert(ERROR_MESSAGE.COMMON)) + .deleteLineStation(lineId, stationId) + .then(() => $target.closest('.list-item').remove()) + .catch(() => alert(ERROR_MESSAGE.COMMON)) } const initSubwayLinesView = () => { api.line - .getAllDetail() - .then(data => { - subwayLines = data.lineDetailResponse - if (subwayLines.length > 0) { - $subwayLinesSlider.innerHTML = subwayLines.map(line => subwayLinesItemTemplate(line)).join('') - initSubwayLinesSlider() - } - }) - .catch(error => { - alert('데이터를 불러오는데 실패했습니다.') - }) + .getAllDetail() + .then(data => { + subwayLines = data.lineDetailResponse + if (subwayLines.length > 0) { + $subwayLinesSlider.innerHTML = subwayLines.map(line => subwayLinesItemTemplate(line)).join( + '') + initSubwayLinesSlider() + } + }) + .catch(error => { + alert('데이터를 불러오는데 실패했습니다.') + }) } const onCreateEdgeHandler = event => { @@ -67,12 +68,12 @@ function AdminEdge() { duration: document.querySelector('#duration').value } api.line - .addLineStation(lineId, newEdge) - .then(() => { - createSubwayEdgeModal.toggle() - initSubwayLinesView() - }) - .catch(error => alert(ERROR_MESSAGE)) + .addLineStation(lineId, newEdge) + .then(() => { + createSubwayEdgeModal.toggle() + initSubwayLinesView() + }) + .catch(error => alert(ERROR_MESSAGE)) } const initCreateEdgeForm = event => { @@ -94,11 +95,12 @@ function AdminEdge() { const initNextStationOptions = () => { api.station - .getAll() - .then(stations => { - $nextStationSelectOptions.innerHTML = stations.map(station => optionTemplate(station)).join('') - }) - .catch(() => alert(ERROR_MESSAGE.COMMON)) + .getAll() + .then(stations => { + $nextStationSelectOptions.innerHTML = stations.map(station => optionTemplate(station)) + .join('') + }) + .catch(() => alert(ERROR_MESSAGE.COMMON)) } const initLineOptions = subwayLines => { diff --git a/src/main/resources/static/admin/js/views/AdminLine.js b/src/main/resources/static/admin/js/views/AdminLine.js index 55058d498..25febaa1d 100644 --- a/src/main/resources/static/admin/js/views/AdminLine.js +++ b/src/main/resources/static/admin/js/views/AdminLine.js @@ -25,14 +25,14 @@ function AdminLine() { intervalTime: $subwayIntervalTime.value } api.line - .create(newSubwayLine) - .then(response => { - $subwayLineList.insertAdjacentHTML('beforeend', subwayLinesTemplate(response)) - subwayLineModal.toggle() - }) - .catch(error => { - alert('에러가 발생했습니다.') - }) + .create(newSubwayLine) + .then(response => { + $subwayLineList.insertAdjacentHTML('beforeend', subwayLinesTemplate(response)) + subwayLineModal.toggle() + }) + .catch(error => { + alert('에러가 발생했습니다.') + }) } const onDeleteSubwayLineHandler = event => { @@ -44,13 +44,13 @@ function AdminLine() { } const lineId = $subwayLineItem.dataset.id api.line - .delete(lineId) - .then(() => { - $subwayLineItem.remove() - }) - .catch(error => { - alert(error) - }) + .delete(lineId) + .then(() => { + $subwayLineItem.remove() + }) + .catch(error => { + alert(error) + }) } const onShowUpdateSubwayLineModal = event => { @@ -63,18 +63,18 @@ function AdminLine() { $activeSubwayLineItem = $subwayLineItem const lineId = $subwayLineItem.dataset.id api.line - .get(lineId) - .then(line => { - $subwayLineNameInput.value = line.name - $subwayLineStartTime.value = line.startTime - $subwayLineEndTime.value = line.endTime - $subwayIntervalTime.value = line.intervalTime - subwayLineModal.toggle() - $submitButton.classList.add('update-submit-button') - }) - .catch(() => { - alert(ERROR_MESSAGE.COMMON) - }) + .get(lineId) + .then(line => { + $subwayLineNameInput.value = line.name + $subwayLineStartTime.value = line.startTime + $subwayLineEndTime.value = line.endTime + $subwayIntervalTime.value = line.intervalTime + subwayLineModal.toggle() + $submitButton.classList.add('update-submit-button') + }) + .catch(() => { + alert(ERROR_MESSAGE.COMMON) + }) } const updateSubwayLine = () => { @@ -85,12 +85,12 @@ function AdminLine() { intervalTime: $subwayIntervalTime.value } api.line - .update($activeSubwayLineItem.dataset.id, updatedSubwayLine) - .then(() => { - subwayLineModal.toggle() - $activeSubwayLineItem.querySelector('.line-name').innerText = updatedSubwayLine.name - }) - .catch(error => alert(ERROR_MESSAGE.COMMON)) + .update($activeSubwayLineItem.dataset.id, updatedSubwayLine) + .then(() => { + subwayLineModal.toggle() + $activeSubwayLineItem.querySelector('.line-name').innerText = updatedSubwayLine.name + }) + .catch(error => alert(ERROR_MESSAGE.COMMON)) } const onSubmitHandler = event => { @@ -118,7 +118,9 @@ function AdminLine() { const initCreateSubwayLineForm = () => { const $colorSelectContainer = document.querySelector('#subway-line-color-select-container') - $colorSelectContainer.innerHTML = subwayLineColorOptions.map((option, index) => colorSelectOptionTemplate(option, index)).join('') + $colorSelectContainer.innerHTML = subwayLineColorOptions.map((option, index) => colorSelectOptionTemplate( + option, + index)).join('') $colorSelectContainer.addEventListener(EVENT_TYPE.CLICK, onSelectColorHandler) } diff --git a/src/main/resources/static/admin/js/views/AdminStation.js b/src/main/resources/static/admin/js/views/AdminStation.js index 604a0ceb2..106758812 100644 --- a/src/main/resources/static/admin/js/views/AdminStation.js +++ b/src/main/resources/static/admin/js/views/AdminStation.js @@ -1,4 +1,4 @@ -import { EVENT_TYPE, ERROR_MESSAGE, KEY_TYPE } from '../../utils/constants.js' +import { ERROR_MESSAGE, EVENT_TYPE, KEY_TYPE } from '../../utils/constants.js' import { listItemTemplate } from '../../utils/templates.js' import api from '../../api/index.js' @@ -21,14 +21,14 @@ function AdminStation() { name: stationName } api.station - .create(newStation) - .then(data => { - $stationInput.value = '' - $stationList.insertAdjacentHTML('beforeend', listItemTemplate(data)) - }) - .catch(() => { - alert('에러가 발생했습니다.') - }) + .create(newStation) + .then(data => { + $stationInput.value = '' + $stationList.insertAdjacentHTML('beforeend', listItemTemplate(data)) + }) + .catch(() => { + alert('에러가 발생했습니다.') + }) } const onDeleteStationHandler = event => { @@ -38,20 +38,20 @@ function AdminStation() { return } api.station - .delete($target.closest('.list-item').dataset.id) - .then(() => { - $target.closest('.list-item').remove() - }) - .catch(() => alert(ERROR_MESSAGE.COMMON)) + .delete($target.closest('.list-item').dataset.id) + .then(() => { + $target.closest('.list-item').remove() + }) + .catch(() => alert(ERROR_MESSAGE.COMMON)) } const initStations = () => { api.station - .getAll() - .then(stations => { - $stationList.innerHTML = stations.map(station => listItemTemplate(station)).join('') - }) - .catch(() => alert(ERROR_MESSAGE.COMMON)) + .getAll() + .then(stations => { + $stationList.innerHTML = stations.map(station => listItemTemplate(station)).join('') + }) + .catch(() => alert(ERROR_MESSAGE.COMMON)) } const initEventListeners = () => { diff --git a/src/main/resources/static/admin/lib/slider/tiny-slider.css b/src/main/resources/static/admin/lib/slider/tiny-slider.css index 4cb211af8..613c54b7f 100755 --- a/src/main/resources/static/admin/lib/slider/tiny-slider.css +++ b/src/main/resources/static/admin/lib/slider/tiny-slider.css @@ -1,51 +1,63 @@ .tns-outer { padding: 0 !important; } + .tns-outer [hidden] { display: none !important; } + .tns-outer [aria-controls], .tns-outer [data-action] { cursor: pointer; } + .tns-slider { -webkit-transition: all 0s; -moz-transition: all 0s; transition: all 0s; } + .tns-slider > .tns-item { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } + .tns-horizontal.tns-subpixel { white-space: nowrap; } + .tns-horizontal.tns-subpixel > .tns-item { display: inline-block; vertical-align: top; white-space: normal; } + .tns-horizontal.tns-no-subpixel:after { content: ""; display: table; clear: both; } + .tns-horizontal.tns-no-subpixel > .tns-item { float: left; } + .tns-horizontal.tns-carousel.tns-no-subpixel > .tns-item { margin-right: -100%; } + .tns-no-calc { position: relative; left: 0; } + .tns-gallery { position: relative; left: 0; min-height: 1px; } + .tns-gallery > .tns-item { position: absolute; left: -100%; @@ -53,61 +65,75 @@ -moz-transition: transform 0s, opacity 0s; transition: transform 0s, opacity 0s; } + .tns-gallery > .tns-slide-active { position: relative; left: auto !important; } + .tns-gallery > .tns-moving { -webkit-transition: all 0.25s; -moz-transition: all 0.25s; transition: all 0.25s; } + .tns-autowidth { display: inline-block; } + .tns-lazy-img { -webkit-transition: opacity 0.6s; -moz-transition: opacity 0.6s; transition: opacity 0.6s; opacity: 0.6; } + .tns-lazy-img.tns-complete { opacity: 1; } + .tns-ah { -webkit-transition: height 0s; -moz-transition: height 0s; transition: height 0s; } + .tns-ovh { overflow: hidden; } + .tns-visually-hidden { position: absolute; left: -10000em; } + .tns-transparent { opacity: 0; visibility: hidden; } + .tns-fadeIn { opacity: 1; filter: alpha(opacity=100); z-index: 0; } + .tns-normal, .tns-fadeOut { opacity: 0; filter: alpha(opacity=0); z-index: -1; } + .tns-vpfix { white-space: nowrap; } + .tns-vpfix > div, .tns-vpfix > li { display: inline-block; } + .tns-t-subp2 { margin: 0 auto; width: 310px; @@ -115,6 +141,7 @@ height: 10px; overflow: hidden; } + .tns-t-ct { width: 2333.3333333%; width: -webkit-calc(100% * 70 / 3); @@ -123,11 +150,13 @@ position: absolute; right: 0; } + .tns-t-ct:after { content: ""; display: table; clear: both; } + .tns-t-ct > div { width: 1.4285714%; width: -webkit-calc(100% / 70); diff --git a/src/main/resources/static/admin/lib/slider/tiny-slider.js b/src/main/resources/static/admin/lib/slider/tiny-slider.js index de774bdda..21fccc925 100644 --- a/src/main/resources/static/admin/lib/slider/tiny-slider.js +++ b/src/main/resources/static/admin/lib/slider/tiny-slider.js @@ -1,4 +1,4 @@ -var tns = (function() { +var tns = (function () { var win = window var raf = @@ -6,7 +6,7 @@ var tns = (function() { win.webkitRequestAnimationFrame || win.mozRequestAnimationFrame || win.msRequestAnimationFrame || - function(cb) { + function (cb) { return setTimeout(cb, 16) } @@ -15,7 +15,7 @@ var tns = (function() { var caf = win$1.cancelAnimationFrame || win$1.mozCancelAnimationFrame || - function(id) { + function (id) { clearTimeout(id) } @@ -51,7 +51,9 @@ var tns = (function() { if (access) { try { storage.setItem(key, value) - } catch (e) {} + } + catch (e) { + } } return value } @@ -123,7 +125,9 @@ var tns = (function() { break } } - } catch (e) {} + } + catch (e) { + } body.fake ? resetFakeBody(body, docOverflow) : div.remove() @@ -215,7 +219,10 @@ var tns = (function() { // cross browsers addRule method function addCSSRule(sheet, selector, rules, index) { // return raf(function() { - 'insertRule' in sheet ? sheet.insertRule(selector + '{' + rules + '}', index) : sheet.addRule(selector, rules, index) + 'insertRule' in sheet ? sheet.insertRule(selector + '{' + rules + '}', index) : sheet.addRule( + selector, + rules, + index) // }); } @@ -258,36 +265,36 @@ var tns = (function() { var classListSupport = 'classList' in document.createElement('_') var hasClass = classListSupport - ? function(el, str) { - return el.classList.contains(str) - } - : function(el, str) { - return el.className.indexOf(str) >= 0 - } + ? function (el, str) { + return el.classList.contains(str) + } + : function (el, str) { + return el.className.indexOf(str) >= 0 + } var addClass = classListSupport - ? function(el, str) { - if (!hasClass(el, str)) { - el.classList.add(str) - } + ? function (el, str) { + if (!hasClass(el, str)) { + el.classList.add(str) } - : function(el, str) { - if (!hasClass(el, str)) { - el.className += ' ' + str - } + } + : function (el, str) { + if (!hasClass(el, str)) { + el.className += ' ' + str } + } var removeClass = classListSupport - ? function(el, str) { - if (hasClass(el, str)) { - el.classList.remove(str) - } + ? function (el, str) { + if (hasClass(el, str)) { + el.classList.remove(str) } - : function(el, str) { - if (hasClass(el, str)) { - el.className = el.className.replace(str, '') - } + } + : function (el, str) { + if (hasClass(el, str)) { + el.className = el.className.replace(str, '') } + } function hasAttr(el, attr) { return el.hasAttribute(attr) @@ -308,7 +315,7 @@ var tns = (function() { return } - for (var i = els.length; i--; ) { + for (var i = els.length; i--;) { for (var key in attrs) { els[i].setAttribute(key, attrs[key]) } @@ -320,8 +327,8 @@ var tns = (function() { attrs = attrs instanceof Array ? attrs : [attrs] var attrLength = attrs.length - for (var i = els.length; i--; ) { - for (var j = attrLength; j--; ) { + for (var i = els.length; i--;) { + for (var j = attrLength; j--;) { els[i].removeAttribute(attrs[j]) } } @@ -357,7 +364,7 @@ var tns = (function() { Props = props.charAt(0).toUpperCase() + props.substr(1), prefixes = ['Webkit', 'Moz', 'ms', 'O'] - prefixes.forEach(function(prefix) { + prefixes.forEach(function (prefix) { if (prefix !== 'ms' || props === 'transform') { arr.push(prefix + Props) } @@ -426,12 +433,14 @@ var tns = (function() { var supportsPassive = false try { var opts = Object.defineProperty({}, 'passive', { - get: function() { + get: function () { supportsPassive = true } }) window.addEventListener('test', null, opts) - } catch (e) {} + } + catch (e) { + } var passiveOption = supportsPassive ? { passive: true } : false function addEvents(el, obj, preventScrolling) { @@ -451,11 +460,11 @@ var tns = (function() { function Events() { return { topics: {}, - on: function(eventName, fn) { + on: function (eventName, fn) { this.topics[eventName] = this.topics[eventName] || [] this.topics[eventName].push(fn) }, - off: function(eventName, fn) { + off: function (eventName, fn) { if (this.topics[eventName]) { for (var i = 0; i < this.topics[eventName].length; i++) { if (this.topics[eventName][i] === fn) { @@ -465,10 +474,10 @@ var tns = (function() { } } }, - emit: function(eventName, data) { + emit: function (eventName, data) { data.type = eventName if (this.topics[eventName]) { - this.topics[eventName].forEach(function(fn) { + this.topics[eventName].forEach(function (fn) { fn(data, eventName) }) } @@ -482,14 +491,15 @@ var tns = (function() { to = to.replace(unit, ''), from = Number( element.style[attr] - .replace(prefix, '') - .replace(postfix, '') - .replace(unit, '') + .replace(prefix, '') + .replace(postfix, '') + .replace(unit, '') ), positionTick = ((to - from) / duration) * tick, running setTimeout(moveElement, tick) + function moveElement() { duration -= tick from += positionTick @@ -504,7 +514,7 @@ var tns = (function() { // Object.keys if (!Object.keys) { - Object.keys = function(object) { + Object.keys = function (object) { var keys = [] for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { @@ -517,14 +527,14 @@ var tns = (function() { // ChildNode.remove if (!('remove' in Element.prototype)) { - Element.prototype.remove = function() { + Element.prototype.remove = function () { if (this.parentNode) { this.parentNode.removeChild(this) } } } - var tns = function(options) { + var tns = function (options) { options = extend( { container: '.slider', @@ -610,27 +620,35 @@ var tns = (function() { if (!localStorageAccess) { tnsStorage = {} } - } catch (e) { + } + catch (e) { localStorageAccess = false } if (localStorageAccess) { // remove storage when browser version changes if (tnsStorage['tnsApp'] && tnsStorage['tnsApp'] !== browserInfo) { - ;['tC', 'tPL', 'tMQ', 'tTf', 't3D', 'tTDu', 'tTDe', 'tADu', 'tADe', 'tTE', 'tAE'].forEach(function(item) { - tnsStorage.removeItem(item) - }) + ;['tC', 'tPL', 'tMQ', 'tTf', 't3D', 'tTDu', 'tTDe', 'tADu', 'tADe', 'tTE', 'tAE'].forEach( + function (item) { + tnsStorage.removeItem(item) + }) } // update browserInfo localStorage['tnsApp'] = browserInfo } } - var CALC = tnsStorage['tC'] ? checkStorageValue(tnsStorage['tC']) : setLocalStorage(tnsStorage, 'tC', calc(), localStorageAccess), + var CALC = tnsStorage['tC'] ? checkStorageValue(tnsStorage['tC']) : setLocalStorage(tnsStorage, + 'tC', + calc(), + localStorageAccess), PERCENTAGELAYOUT = tnsStorage['tPL'] ? checkStorageValue(tnsStorage['tPL']) : setLocalStorage(tnsStorage, 'tPL', percentageLayout(), localStorageAccess), - CSSMQ = tnsStorage['tMQ'] ? checkStorageValue(tnsStorage['tMQ']) : setLocalStorage(tnsStorage, 'tMQ', mediaquerySupport(), localStorageAccess), + CSSMQ = tnsStorage['tMQ'] ? checkStorageValue(tnsStorage['tMQ']) : setLocalStorage(tnsStorage, + 'tMQ', + mediaquerySupport(), + localStorageAccess), TRANSFORM = tnsStorage['tTf'] ? checkStorageValue(tnsStorage['tTf']) : setLocalStorage(tnsStorage, 'tTf', whichProperty('transform'), localStorageAccess), @@ -639,29 +657,41 @@ var tns = (function() { : setLocalStorage(tnsStorage, 't3D', has3DTransforms(TRANSFORM), localStorageAccess), TRANSITIONDURATION = tnsStorage['tTDu'] ? checkStorageValue(tnsStorage['tTDu']) - : setLocalStorage(tnsStorage, 'tTDu', whichProperty('transitionDuration'), localStorageAccess), + : setLocalStorage(tnsStorage, + 'tTDu', + whichProperty('transitionDuration'), + localStorageAccess), TRANSITIONDELAY = tnsStorage['tTDe'] ? checkStorageValue(tnsStorage['tTDe']) : setLocalStorage(tnsStorage, 'tTDe', whichProperty('transitionDelay'), localStorageAccess), ANIMATIONDURATION = tnsStorage['tADu'] ? checkStorageValue(tnsStorage['tADu']) - : setLocalStorage(tnsStorage, 'tADu', whichProperty('animationDuration'), localStorageAccess), + : setLocalStorage(tnsStorage, + 'tADu', + whichProperty('animationDuration'), + localStorageAccess), ANIMATIONDELAY = tnsStorage['tADe'] ? checkStorageValue(tnsStorage['tADe']) : setLocalStorage(tnsStorage, 'tADe', whichProperty('animationDelay'), localStorageAccess), TRANSITIONEND = tnsStorage['tTE'] ? checkStorageValue(tnsStorage['tTE']) - : setLocalStorage(tnsStorage, 'tTE', getEndProperty(TRANSITIONDURATION, 'Transition'), localStorageAccess), + : setLocalStorage(tnsStorage, + 'tTE', + getEndProperty(TRANSITIONDURATION, 'Transition'), + localStorageAccess), ANIMATIONEND = tnsStorage['tAE'] ? checkStorageValue(tnsStorage['tAE']) - : setLocalStorage(tnsStorage, 'tAE', getEndProperty(ANIMATIONDURATION, 'Animation'), localStorageAccess) + : setLocalStorage(tnsStorage, + 'tAE', + getEndProperty(ANIMATIONDURATION, 'Animation'), + localStorageAccess) // get element nodes from selectors var supportConsoleWarn = win.console && typeof win.console.warn === 'function', tnsList = ['container', 'controlsContainer', 'prevButton', 'nextButton', 'navContainer', 'autoplayButton'], optionsElements = {} - tnsList.forEach(function(item) { + tnsList.forEach(function (item) { if (typeof options[item] === 'string') { var str = options[item], el = doc.querySelector(str) @@ -735,6 +765,7 @@ var tns = (function() { } } } + if (!carousel) { updateOptions(options) } @@ -810,25 +841,26 @@ var tns = (function() { transformPrefix = '', transformPostfix = '', // index - getIndexMax = (function() { + getIndexMax = (function () { if (fixedWidth) { - return function() { + return function () { return center && !loop ? slideCount - 1 : Math.ceil(-rightBoundary / (fixedWidth + gutter)) } } else if (autoWidth) { - return function() { - for (var i = slideCountNew; i--; ) { + return function () { + for (var i = slideCountNew; i--;) { if (slidePositions[i] >= -rightBoundary) { return i } } } } else { - return function() { + return function () { if (center && carousel && !loop) { return slideCount - 1 } else { - return loop || carousel ? Math.max(0, slideCountNew - Math.ceil(items)) : slideCountNew - 1 + return loop || carousel ? Math.max(0, + slideCountNew - Math.ceil(items)) : slideCountNew - 1 } } } @@ -945,12 +977,12 @@ var tns = (function() { panStart = false, rafIndex, getDist = horizontal - ? function(a, b) { - return a.x - b.x - } - : function(a, b) { - return a.y - b.y - } + ? function (a, b) { + return a.x - b.x + } + : function (a, b) { + return a.y - b.y + } } // disable slider when slidecount <= items @@ -1020,8 +1052,8 @@ var tns = (function() { result = navAsThumbnails ? absIndex : fixedWidth || autoWidth - ? Math.ceil(((absIndex + 1) * pages) / slideCount - 1) - : Math.floor(absIndex / items) + ? Math.ceil(((absIndex + 1) * pages) / slideCount - 1) + : Math.floor(absIndex / items) // set active nav to the last one when reaches the right edge if (!loop && carousel && index === indexMax) { @@ -1057,7 +1089,8 @@ var tns = (function() { arr.push(0) } - return Math.ceil(fixedWidth ? viewportMax / Math.min.apply(null, arr) : Math.max.apply(null, arr)) + return Math.ceil(fixedWidth ? viewportMax / Math.min.apply(null, arr) : Math.max.apply(null, + arr)) } } @@ -1274,7 +1307,7 @@ var tns = (function() { // add id, class, aria attributes // before clone slides - forEach(slideItems, function(item, i) { + forEach(slideItems, function (item, i) { addClass(item, 'tns-item') if (!item.id) { item.id = slideId + '-item' + i @@ -1295,7 +1328,7 @@ var tns = (function() { var fragmentBefore = doc.createDocumentFragment(), fragmentAfter = doc.createDocumentFragment() - for (var j = cloneCount; j--; ) { + for (var j = cloneCount; j--;) { var num = j % slideCount, cloneFirst = slideItems[num].cloneNode(true) removeAttrs(cloneFirst, 'id') @@ -1320,7 +1353,7 @@ var tns = (function() { var imgs = container.querySelectorAll('img') // add img load event listener - forEach(imgs, function(img) { + forEach(imgs, function (img) { var src = img.src if (!lazyload) { @@ -1339,8 +1372,8 @@ var tns = (function() { }) // set imgsComplete - raf(function() { - imgsLoadedCheck(arrayFromNodeList(imgs), function() { + raf(function () { + imgsLoadedCheck(arrayFromNodeList(imgs), function () { imgsComplete = true }) }) @@ -1352,9 +1385,9 @@ var tns = (function() { lazyload ? initSliderTransformStyleCheck() - : raf(function() { - imgsLoadedCheck(arrayFromNodeList(imgs), initSliderTransformStyleCheck) - }) + : raf(function () { + imgsLoadedCheck(arrayFromNodeList(imgs), initSliderTransformStyleCheck) + }) } else { // set container transform property if (carousel) { @@ -1378,9 +1411,9 @@ var tns = (function() { Math.abs(left - right) <= 1 ? initSliderTransformCore() - : setTimeout(function() { - stylesApplicationCheck() - }, 16) + : setTimeout(function () { + stylesApplicationCheck() + }, 16) })() } else { initSliderTransformCore() @@ -1450,7 +1483,7 @@ var tns = (function() { ) addCSSRule(sheet, '#' + slideId, 'font-size:0;', getCssRulesLength(sheet)) } else if (carousel) { - forEach(slideItems, function(slide, i) { + forEach(slideItems, function (slide, i) { slide.style.marginLeft = getSlideMarginLeft(i) }) } @@ -1465,12 +1498,18 @@ var tns = (function() { } // inner wrapper styles - str = getInnerWrapperStyles(options.edgePadding, options.gutter, options.fixedWidth, options.speed, options.autoHeight) + str = getInnerWrapperStyles(options.edgePadding, + options.gutter, + options.fixedWidth, + options.speed, + options.autoHeight) addCSSRule(sheet, '#' + slideId + '-iw', str, getCssRulesLength(sheet)) // container styles if (carousel) { - str = horizontal && !autoWidth ? 'width:' + getContainerWidth(options.fixedWidth, options.gutter, options.items) + ';' : '' + str = horizontal && !autoWidth ? 'width:' + getContainerWidth(options.fixedWidth, + options.gutter, + options.items) + ';' : '' if (TRANSITIONDURATION) { str += getTransitionDurationStyle(speed) } @@ -1478,7 +1517,9 @@ var tns = (function() { } // slide styles - str = horizontal && !autoWidth ? getSlideWidthStyle(options.fixedWidth, options.gutter, options.items) : '' + str = horizontal && !autoWidth ? getSlideWidthStyle(options.fixedWidth, + options.gutter, + options.items) : '' if (options.gutter) { str += getSlideGutterStyle(options.gutter) } @@ -1504,7 +1545,10 @@ var tns = (function() { update_carousel_transition_duration() // inner wrapper styles - innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, autoHeight) + innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, + gutter, + fixedWidth, + autoHeight) // container styles if (carousel && horizontal && !autoWidth) { @@ -1543,13 +1587,18 @@ var tns = (function() { gutterBP = getOption('gutter', bp) // middle wrapper string - if (TRANSITIONDURATION && middleWrapper && getOption('autoHeight', bp) && 'speed' in opts) { + if (TRANSITIONDURATION && middleWrapper && getOption('autoHeight', + bp) && 'speed' in opts) { middleWrapperStr = '#' + slideId + '-mw{' + getTransitionDurationStyle(speedBP) + '}' } // inner wrapper string if ('edgePadding' in opts || 'gutter' in opts) { - innerWrapperStr = '#' + slideId + '-iw{' + getInnerWrapperStyles(edgePaddingBP, gutterBP, fixedWidthBP, speedBP, autoHeightBP) + '}' + innerWrapperStr = '#' + slideId + '-iw{' + getInnerWrapperStyles(edgePaddingBP, + gutterBP, + fixedWidthBP, + speedBP, + autoHeightBP) + '}' } // container string @@ -1587,7 +1636,8 @@ var tns = (function() { str = middleWrapperStr + innerWrapperStr + containerStr + slideStr if (str) { - sheet.insertRule('@media (min-width: ' + bp / 16 + 'em) {' + str + '}', sheet.cssRules.length) + sheet.insertRule('@media (min-width: ' + bp / 16 + 'em) {' + str + '}', + sheet.cssRules.length) } } } @@ -1601,10 +1651,10 @@ var tns = (function() { outerWrapper.insertAdjacentHTML( 'afterbegin', '
slide ' + - getLiveRegionStr() + - ' of ' + - slideCount + - '
' + getLiveRegionStr() + + ' of ' + + slideCount + + '' ) liveregionCurrent = outerWrapper.querySelector('.tns-liveregion .current') @@ -1645,7 +1695,7 @@ var tns = (function() { if (navContainer) { setAttrs(navContainer, { 'aria-label': 'Carousel Pagination' }) navItems = navContainer.children - forEach(navItems, function(item, i) { + forEach(navItems, function (item, i) { setAttrs(item, { 'data-nav': i, tabindex: '-1', @@ -1683,7 +1733,8 @@ var tns = (function() { // add transition if (TRANSITIONDURATION) { - var prefix = TRANSITIONDURATION.substring(0, TRANSITIONDURATION.length - 18).toLowerCase(), + var prefix = TRANSITIONDURATION.substring(0, TRANSITIONDURATION.length - 18) + .toLowerCase(), str = 'transition: all ' + speed / 1000 + 's' if (prefix) { @@ -1693,7 +1744,8 @@ var tns = (function() { addCSSRule(sheet, '[aria-controls^=' + slideId + '-item]', str, getCssRulesLength(sheet)) } - setAttrs(navItems[navCurrentIndex], { 'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent }) + setAttrs(navItems[navCurrentIndex], + { 'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent }) removeAttrs(navItems[navCurrentIndex], 'tabindex') addClass(navItems[navCurrentIndex], navActiveClass) @@ -1707,14 +1759,14 @@ var tns = (function() { outerWrapper.insertAdjacentHTML( getInsertPosition(options.controlsPosition), '
' + slideId + + '">' + + controlsText[0] + + '' ) controlsContainer = outerWrapper.querySelector('.tns-controls') @@ -1781,7 +1833,7 @@ var tns = (function() { } if (nested === 'inner') { - events.on('outerResized', function() { + events.on('outerResized', function () { resizeTasks() events.emit('innerLoaded', info()) }) @@ -1861,7 +1913,7 @@ var tns = (function() { // cache Object values in options && reset HTML var htmlList = [containerHTML, controlsContainerHTML, prevButtonHTML, nextButtonHTML, navContainerHTML, autoplayButtonHTML] - tnsList.forEach(function(item, i) { + tnsList.forEach(function (item, i) { var el = item === 'container' ? outerWrapper : options[item] if (typeof el === 'object' && el) { @@ -1888,7 +1940,7 @@ var tns = (function() { // === ON RESIZE === // responsive || fixedWidth || autoWidth || !horizontal function onResize(e) { - raf(function() { + raf(function () { resizeTasks(getEvent(e)) }) } @@ -2066,7 +2118,9 @@ var tns = (function() { nav ? showElement(navContainer) : hideElement(navContainer) } if (touch !== touchTem) { - touch ? addEvents(container, touchEvents, options.preventScrollOnTouch) : removeEvents(container, touchEvents) + touch ? addEvents(container, touchEvents, options.preventScrollOnTouch) : removeEvents( + container, + touchEvents) } if (mouseDrag !== mouseDragTem) { mouseDrag ? addEvents(container, dragEvents) : removeEvents(container, dragEvents) @@ -2089,10 +2143,12 @@ var tns = (function() { } } if (autoplayHoverPause !== autoplayHoverPauseTem) { - autoplayHoverPause ? addEvents(container, hoverEvents) : removeEvents(container, hoverEvents) + autoplayHoverPause ? addEvents(container, hoverEvents) : removeEvents(container, + hoverEvents) } if (autoplayResetOnVisibility !== autoplayResetOnVisibilityTem) { - autoplayResetOnVisibility ? addEvents(doc, visibilityEvent) : removeEvents(doc, visibilityEvent) + autoplayResetOnVisibility ? addEvents(doc, visibilityEvent) : removeEvents(doc, + visibilityEvent) } if (bpChanged) { @@ -2155,7 +2211,11 @@ var tns = (function() { // inner wrapper styles if (edgePadding !== edgePaddingTem || gutter !== gutterTem) { - innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, speed, autoHeight) + innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, + gutter, + fixedWidth, + speed, + autoHeight) } if (horizontal) { @@ -2218,52 +2278,52 @@ var tns = (function() { } // (slideBy, indexMin, indexMax) => index - var updateIndex = (function() { + var updateIndex = (function () { return loop ? carousel ? // loop + carousel - function() { - var leftEdge = indexMin, - rightEdge = indexMax + function () { + var leftEdge = indexMin, + rightEdge = indexMax - leftEdge += slideBy - rightEdge -= slideBy + leftEdge += slideBy + rightEdge -= slideBy - // adjust edges when has edge paddings - // or fixed-width slider with extra space on the right side - if (edgePadding) { - leftEdge += 1 + // adjust edges when has edge paddings + // or fixed-width slider with extra space on the right side + if (edgePadding) { + leftEdge += 1 + rightEdge -= 1 + } else if (fixedWidth) { + if ((viewport + gutter) % (fixedWidth + gutter)) { rightEdge -= 1 - } else if (fixedWidth) { - if ((viewport + gutter) % (fixedWidth + gutter)) { - rightEdge -= 1 - } } + } - if (cloneCount) { - if (index > rightEdge) { - index -= slideCount - } else if (index < leftEdge) { - index += slideCount - } + if (cloneCount) { + if (index > rightEdge) { + index -= slideCount + } else if (index < leftEdge) { + index += slideCount } } + } : // loop + gallery - function() { - if (index > indexMax) { - while (index >= indexMin + slideCount) { - index -= slideCount - } - } else if (index < indexMin) { - while (index <= indexMax - slideCount) { - index += slideCount - } + function () { + if (index > indexMax) { + while (index >= indexMin + slideCount) { + index -= slideCount + } + } else if (index < indexMin) { + while (index <= indexMax - slideCount) { + index += slideCount } } - : // non-loop - function() { - index = Math.max(indexMin, Math.min(indexMax, index)) } + : // non-loop + function () { + index = Math.max(indexMin, Math.min(indexMax, index)) + } })() function disableUI() { @@ -2321,7 +2381,7 @@ var tns = (function() { // add class tns-transparent to cloned slides if (cloneCount) { var str = 'tns-transparent' - for (var i = cloneCount; i--; ) { + for (var i = cloneCount; i--;) { if (carousel) { addClass(slideItems[i], str) } @@ -2349,7 +2409,7 @@ var tns = (function() { // remove class tns-transparent to cloned slides if (cloneCount) { var str = 'tns-transparent' - for (var i = cloneCount; i--; ) { + for (var i = cloneCount; i--;) { if (carousel) { removeClass(slideItems[i], str) } @@ -2372,7 +2432,7 @@ var tns = (function() { container.className = container.className.replace(newContainerClasses.substring(1), '') removeAttrs(container, ['style']) if (loop) { - for (var j = cloneCount; j--; ) { + for (var j = cloneCount; j--;) { if (carousel) { hideElement(slideItems[j]) } @@ -2411,7 +2471,7 @@ var tns = (function() { doContainerTransformSilent() if (loop) { - for (var j = cloneCount; j--; ) { + for (var j = cloneCount; j--;) { if (carousel) { showElement(slideItems[j]) } @@ -2474,7 +2534,7 @@ var tns = (function() { // get start, end // - check auto width if (autoWidth) { - slidePositions.forEach(function(point, i) { + slidePositions.forEach(function (point, i) { if (i < slideCountNew) { if ((center || edgePadding) && point <= rangestart + 0.5) { start = i @@ -2530,11 +2590,11 @@ var tns = (function() { var arg = getVisibleSlideRange() arg.push(lazyloadSelector) - getImageArray.apply(null, arg).forEach(function(img) { + getImageArray.apply(null, arg).forEach(function (img) { if (!hasClass(img, imgCompleteClass)) { // stop propagation transitionend event to container var eve = {} - eve[TRANSITIONEND] = function(e) { + eve[TRANSITIONEND] = function (e) { e.stopPropagation() } addEvents(img, eve) @@ -2587,7 +2647,7 @@ var tns = (function() { } while (start <= end) { - forEach(slideItems[start].querySelectorAll(imgSelector), function(img) { + forEach(slideItems[start].querySelectorAll(imgSelector), function (img) { imgs.push(img) }) start++ @@ -2600,7 +2660,7 @@ var tns = (function() { // and update container height if it's done function doAutoHeight() { var imgs = getImageArray.apply(null, getVisibleSlideRange()) - raf(function() { + raf(function () { imgsLoadedCheck(imgs, updateInnerWrapperHeight) }) } @@ -2612,7 +2672,7 @@ var tns = (function() { } // check image classes - imgs.forEach(function(img, index) { + imgs.forEach(function (img, index) { if (!lazyload && img.complete) { imgCompleted(img) } // Check image.complete @@ -2627,7 +2687,7 @@ var tns = (function() { } // otherwise execute this functiona again - raf(function() { + raf(function () { imgsLoadedCheck(imgs, cb) }) } @@ -2661,7 +2721,8 @@ var tns = (function() { // 3. update inner wrapper height to max-height // 4. set transitionDuration to 0s after transition done function updateInnerWrapperHeight() { - var maxHeight = autoHeight ? getMaxSlideHeight(index, items) : getMaxSlideHeight(cloneCount, slideCount), + var maxHeight = autoHeight ? getMaxSlideHeight(index, items) : getMaxSlideHeight(cloneCount, + slideCount), wp = middleWrapper ? middleWrapper : innerWrapper if (wp.style.height !== maxHeight) { @@ -2677,7 +2738,7 @@ var tns = (function() { attr2 = horizontal ? 'right' : 'bottom', base = slideItems[0].getBoundingClientRect()[attr] - forEach(slideItems, function(item, i) { + forEach(slideItems, function (item, i) { // skip the first slide if (i) { slidePositions.push(item.getBoundingClientRect()[attr] - base) @@ -2695,7 +2756,7 @@ var tns = (function() { start = range[0], end = range[1] - forEach(slideItems, function(item, i) { + forEach(slideItems, function (item, i) { // show slides if (i >= start && i <= end) { if (hasAttr(item, 'aria-hidden')) { @@ -2718,7 +2779,7 @@ var tns = (function() { // gallery: update slide position function updateGallerySlidePositions() { var l = index + Math.min(slideCount, items) - for (var i = slideCountNew; i--; ) { + for (var i = slideCountNew; i--;) { var item = slideItems[i] if (i >= index && i < l) { @@ -2739,8 +2800,8 @@ var tns = (function() { } // removing '.tns-moving' - setTimeout(function() { - forEach(slideItems, function(el) { + setTimeout(function () { + forEach(slideItems, function (el) { removeClass(el, 'tns-moving') }) }, 300) @@ -2837,8 +2898,8 @@ var tns = (function() { return autoWidth ? (viewport - gap - (slidePositions[num + 1] - slidePositions[num] - gutter)) / 2 : fixedWidth - ? (viewport - fixedWidth) / 2 - : (items - 1) / 2 + ? (viewport - fixedWidth) / 2 + : (items - 1) / 2 } function getRightBoundary() { @@ -2933,45 +2994,51 @@ var tns = (function() { // make transfer after click/drag: // 1. change 'transform' property for mordern browsers // 2. change 'left' property for legacy browsers - var transformCore = (function() { + var transformCore = (function () { return carousel - ? function() { - resetDuration(container, '') - if (TRANSITIONDURATION || !speed) { - // for morden browsers with non-zero duration or - // zero duration for all browsers - doContainerTransform() - // run fallback function manually - // when duration is 0 / container is hidden - if (!speed || !isVisible(container)) { - onTransitionEnd() - } - } else { - // for old browser with non-zero duration - jsTransform(container, transformAttr, transformPrefix, transformPostfix, getContainerTransformValue(), speed, onTransitionEnd) + ? function () { + resetDuration(container, '') + if (TRANSITIONDURATION || !speed) { + // for morden browsers with non-zero duration or + // zero duration for all browsers + doContainerTransform() + // run fallback function manually + // when duration is 0 / container is hidden + if (!speed || !isVisible(container)) { + onTransitionEnd() } + } else { + // for old browser with non-zero duration + jsTransform(container, + transformAttr, + transformPrefix, + transformPostfix, + getContainerTransformValue(), + speed, + onTransitionEnd) + } - if (!horizontal) { - updateContentWrapperHeight() - } + if (!horizontal) { + updateContentWrapperHeight() } - : function() { - slideItemsOut = [] + } + : function () { + slideItemsOut = [] - var eve = {} - eve[TRANSITIONEND] = eve[ANIMATIONEND] = onTransitionEnd - removeEvents(slideItems[indexCached], eve) - addEvents(slideItems[index], eve) + var eve = {} + eve[TRANSITIONEND] = eve[ANIMATIONEND] = onTransitionEnd + removeEvents(slideItems[indexCached], eve) + addEvents(slideItems[index], eve) - animateSlide(indexCached, animateIn, animateOut, true) - animateSlide(index, animateNormal, animateIn) + animateSlide(indexCached, animateIn, animateOut, true) + animateSlide(index, animateNormal, animateIn) - // run fallback function manually - // when transition or animation not supported / duration is 0 - if (!TRANSITIONEND || !ANIMATIONEND || !speed || !isVisible(container)) { - onTransitionEnd() - } + // run fallback function manually + // when transition or animation not supported / duration is 0 + if (!TRANSITIONEND || !ANIMATIONEND || !speed || !isVisible(container)) { + onTransitionEnd() } + } })() function render(e, sliderMoved) { @@ -3209,7 +3276,8 @@ var tns = (function() { if (hasAttr(target, 'data-nav')) { var navIndex = (navClicked = Number(getAttr(target, 'data-nav'))), targetIndexBase = fixedWidth || autoWidth ? (navIndex * slideCount) / pages : navIndex * items, - targetIndex = navAsThumbnails ? navIndex : Math.min(Math.ceil(targetIndexBase), slideCount - 1) + targetIndex = navAsThumbnails ? navIndex : Math.min(Math.ceil(targetIndexBase), + slideCount - 1) goTo(targetIndex, e) if (navCurrentIndex === navIndex) { @@ -3223,7 +3291,7 @@ var tns = (function() { // autoplay functions function setAutoplayTimer() { - autoplayTimer = setInterval(function() { + autoplayTimer = setInterval(function () { onControlsClick(null, autoplayDirection) }, autoplayTimeout) @@ -3261,6 +3329,7 @@ var tns = (function() { autoplayUserPaused = false } } + function pause() { if (animating) { stopAutoplay() @@ -3367,6 +3436,7 @@ var tns = (function() { e = e || win.event return isTouchEvent(e) ? e.changedTouches[0] : e } + function getTarget(e) { return e.target || win.event.srcElement } @@ -3380,7 +3450,8 @@ var tns = (function() { } function getMoveDirectionExpected() { - return getTouchDirection(toDegree(lastPosition.y - initPosition.y, lastPosition.x - initPosition.x), swipeAngle) === options.axis + return getTouchDirection(toDegree(lastPosition.y - initPosition.y, + lastPosition.x - initPosition.x), swipeAngle) === options.axis } function onPanStart(e) { @@ -3425,7 +3496,7 @@ var tns = (function() { if (carousel) { if (!rafIndex) { - rafIndex = raf(function() { + rafIndex = raf(function () { panUpdate(e) }) } @@ -3451,7 +3522,7 @@ var tns = (function() { } caf(rafIndex) if (panStart) { - rafIndex = raf(function() { + rafIndex = raf(function () { panUpdate(e) }) } @@ -3468,7 +3539,9 @@ var tns = (function() { if (e.type) { events.emit(isTouchEvent(e) ? 'touchMove' : 'dragMove', info(e)) } - } catch (err) {} + } + catch (err) { + } var x = translateInit, dist = getDist(lastPosition, initPosition) @@ -3515,7 +3588,7 @@ var tns = (function() { } if (carousel) { - rafIndex = raf(function() { + rafIndex = raf(function () { if (horizontal && !autoWidth) { var indexMoved = (-dist * items) / (viewport + gutter) indexMoved = dist > 0 ? Math.floor(indexMoved) : Math.ceil(indexMoved) @@ -3643,7 +3716,7 @@ var tns = (function() { updateSliderHeight: updateInnerWrapperHeight, refresh: initSliderTransform, destroy: destroy, - rebuild: function() { + rebuild: function () { return tns(extend(options, optionsElements)) } } diff --git a/src/main/resources/static/admin/lib/snackbar/snackbar.js b/src/main/resources/static/admin/lib/snackbar/snackbar.js index 029c9769f..a0ca0087f 100644 --- a/src/main/resources/static/admin/lib/snackbar/snackbar.js +++ b/src/main/resources/static/admin/lib/snackbar/snackbar.js @@ -7,11 +7,11 @@ * https://github.com/polonel/Snackbar/blob/master/LICENSE */ -(function(root, factory) { +(function (root, factory) { "use strict"; if (typeof define === "function" && define.amd) { - define([], function() { + define([], function () { return (root.Snackbar = factory()); }); } else if (typeof module === "object" && module.exports) { @@ -19,7 +19,7 @@ } else { root.Snackbar = factory(); } -})(this, function() { +})(this, function () { var Snackbar = {}; Snackbar.current = null; @@ -37,20 +37,22 @@ pos: "bottom-left", duration: 5000, customClass: "", - onActionClick: function(element) { + onActionClick: function (element) { element.style.opacity = 0; }, - onSecondButtonClick: function(element) {}, - onClose: function(element) {} + onSecondButtonClick: function (element) { + }, + onClose: function (element) { + } }; - Snackbar.show = function($options) { + Snackbar.show = function ($options) { var options = Extend(true, $defaults, $options); if (Snackbar.current) { Snackbar.current.style.opacity = 0; setTimeout( - function() { + function () { var $parent = this.parentElement; if ($parent) // possible null if too many/fast Snackbars @@ -79,7 +81,7 @@ secondButton.className = "action"; secondButton.innerHTML = options.secondButtonText; secondButton.style.color = options.secondButtonTextColor; - secondButton.addEventListener("click", function() { + secondButton.addEventListener("click", function () { options.onSecondButtonClick(Snackbar.snackbar); }); Snackbar.snackbar.appendChild(secondButton); @@ -90,7 +92,7 @@ actionButton.className = "action"; actionButton.innerHTML = options.actionText; actionButton.style.color = options.actionTextColor; - actionButton.addEventListener("click", function() { + actionButton.addEventListener("click", function () { options.onActionClick(Snackbar.snackbar); }); Snackbar.snackbar.appendChild(actionButton); @@ -98,7 +100,7 @@ if (options.duration) { setTimeout( - function() { + function () { if (Snackbar.current === this) { Snackbar.current.style.opacity = 0; // When natural remove event occurs let's move the snackbar to its origins @@ -112,7 +114,7 @@ Snackbar.snackbar.addEventListener( "transitionend", - function(event, elapsed) { + function (event, elapsed) { if (event.propertyName === "opacity" && this.style.opacity === "0") { if (typeof options.onClose === "function") options.onClose(this); @@ -137,7 +139,7 @@ options.pos; }; - Snackbar.close = function() { + Snackbar.close = function () { if (Snackbar.current) { Snackbar.current.style.opacity = 0; } @@ -145,7 +147,7 @@ // Pure JS Extend // http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/ - var Extend = function() { + var Extend = function () { var extended = {}; var deep = false; var i = 0; @@ -156,7 +158,7 @@ i++; } - var merge = function(obj) { + var merge = function (obj) { for (var prop in obj) { if (Object.prototype.hasOwnProperty.call(obj, prop)) { if ( diff --git a/src/main/resources/static/admin/ui/CustomModal.js b/src/main/resources/static/admin/ui/CustomModal.js index a591eb0f8..7f699f956 100644 --- a/src/main/resources/static/admin/ui/CustomModal.js +++ b/src/main/resources/static/admin/ui/CustomModal.js @@ -1,4 +1,3 @@ -import { EVENT_TYPE } from "../utils/constants.js"; import Modal from "./Modal.js"; export default function CustomModal() { diff --git a/src/main/resources/static/admin/utils/templates.js b/src/main/resources/static/admin/utils/templates.js index ccd7690cc..81ec68edd 100644 --- a/src/main/resources/static/admin/utils/templates.js +++ b/src/main/resources/static/admin/utils/templates.js @@ -45,7 +45,8 @@ const navTemplate = `