test #164
| @@ -0,0 +1,30 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import org.springframework.security.access.prepost.PreAuthorize | ||||
| import org.springframework.web.bind.annotation.PostMapping | ||||
| import org.springframework.web.bind.annotation.PutMapping | ||||
| import org.springframework.web.bind.annotation.RequestBody | ||||
| import org.springframework.web.bind.annotation.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RestController | ||||
|  | ||||
| @RestController | ||||
| @PreAuthorize("hasRole('ADMIN')") | ||||
| @RequestMapping("/admin/audio-content/series/genre") | ||||
| class AdminContentSeriesGenreController(private val service: AdminContentSeriesGenreService) { | ||||
|     @PostMapping | ||||
|     fun createSeriesGenre(@RequestBody request: CreateSeriesGenreRequest) = | ||||
|         ApiResponse.ok(service.createSeriesGenre(genre = request.genre), "생성되었습니다.") | ||||
|  | ||||
|     @PutMapping | ||||
|     fun modifySeriesGenre(@RequestBody request: ModifySeriesGenreRequest) = ApiResponse.ok( | ||||
|         service.modifySeriesGenre(request = request), | ||||
|         "수정되었습니다." | ||||
|     ) | ||||
|  | ||||
|     @PutMapping("/orders") | ||||
|     fun modifySeriesGenreOrders(@RequestBody request: ModifySeriesGenreOrderRequest) = ApiResponse.ok( | ||||
|         service.modifySeriesGenreOrders(ids = request.ids), | ||||
|         "수정되었습니다." | ||||
|     ) | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface AdminContentSeriesGenreRepository : JpaRepository<SeriesGenre, Long>, AdminContentSeriesGenreQueryRepository | ||||
|  | ||||
| interface AdminContentSeriesGenreQueryRepository | ||||
|  | ||||
| class AdminContentSeriesGenreQueryRepositoryImpl : AdminContentSeriesGenreQueryRepository | ||||
| @@ -0,0 +1,49 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import org.springframework.data.repository.findByIdOrNull | ||||
| import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | ||||
|  | ||||
| @Service | ||||
| class AdminContentSeriesGenreService(private val repository: AdminContentSeriesGenreRepository) { | ||||
|  | ||||
|     @Transactional | ||||
|     fun createSeriesGenre(genre: String) { | ||||
|         val seriesGenre = SeriesGenre(genre = genre.trim()) | ||||
|         repository.save(seriesGenre) | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun modifySeriesGenre(request: ModifySeriesGenreRequest) { | ||||
|         if (request.genre == null && request.isAdult == null && request.isActive == null) { | ||||
|             throw SodaException("변경사항이 없습니다.") | ||||
|         } | ||||
|  | ||||
|         val seriesGenre = repository.findByIdOrNull(id = request.id) | ||||
|             ?: throw SodaException("잘못된 요청입니다.") | ||||
|  | ||||
|         if (request.genre != null) { | ||||
|             seriesGenre.genre = request.genre | ||||
|         } | ||||
|  | ||||
|         if (request.isAdult != null) { | ||||
|             seriesGenre.isAdult = request.isAdult | ||||
|         } | ||||
|  | ||||
|         if (request.isActive != null) { | ||||
|             seriesGenre.isActive = request.isActive | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun modifySeriesGenreOrders(ids: List<Long>) { | ||||
|         for (index in ids.indices) { | ||||
|             val seriesGenre = repository.findByIdOrNull(ids[index]) | ||||
|  | ||||
|             if (seriesGenre != null) { | ||||
|                 seriesGenre.orders = index + 1 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| data class CreateSeriesGenreRequest(val genre: String, val isAdult: Boolean) | ||||
| @@ -0,0 +1,5 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| data class ModifySeriesGenreRequest(val id: Long, val genre: String?, val isAdult: Boolean?, val isActive: Boolean?) | ||||
|  | ||||
| data class ModifySeriesGenreOrderRequest(val ids: List<Long>) | ||||
| @@ -0,0 +1,17 @@ | ||||
| package kr.co.vividnext.sodalive.admin.content.series.genre | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import javax.persistence.Column | ||||
| import javax.persistence.Entity | ||||
|  | ||||
| @Entity | ||||
| data class SeriesGenre( | ||||
|     @Column(nullable = false) | ||||
|     var genre: String, | ||||
|     @Column(nullable = false) | ||||
|     var isAdult: Boolean = false, | ||||
|     @Column(nullable = false) | ||||
|     var isActive: Boolean = true, | ||||
|     @Column(nullable = false) | ||||
|     var orders: Int = 1 | ||||
| ) : BaseEntity() | ||||
| @@ -269,10 +269,21 @@ class ChargeService( | ||||
|                     productId, | ||||
|                     purchaseToken | ||||
|                 ) | ||||
|                 charge.payment!!.status = PaymentStatus.COMPLETE | ||||
|                 member.charge(charge.chargeCan, 0, "aos") | ||||
|  | ||||
|                 return true | ||||
|                 val response = androidPublisher.purchases().products() | ||||
|                     .get("kr.co.vividnext.sodalive", productId, purchaseToken) | ||||
|                     .execute() ?: throw SodaException("결제정보에 오류가 있습니다.") | ||||
|  | ||||
|                 if (response.consumptionState == 1) { | ||||
|                     charge.payment!!.status = PaymentStatus.COMPLETE | ||||
|                     member.charge(charge.chargeCan, 0, "aos") | ||||
|  | ||||
|                     return true | ||||
|                 } else { | ||||
|                     attempt += 1 | ||||
|                     Thread.sleep(delay) | ||||
|                     delay *= 2 | ||||
|                 } | ||||
|             } catch (e: Exception) { | ||||
|                 lastError = e | ||||
|                 attempt += 1 | ||||
| @@ -280,6 +291,7 @@ class ChargeService( | ||||
|                 delay *= 2 | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         lastError?.printStackTrace() | ||||
|         return false | ||||
|     } | ||||
|   | ||||
| @@ -0,0 +1,42 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series | ||||
|  | ||||
| import kr.co.vividnext.sodalive.admin.content.series.genre.SeriesGenre | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import javax.persistence.CollectionTable | ||||
| import javax.persistence.Column | ||||
| import javax.persistence.ElementCollection | ||||
| import javax.persistence.Entity | ||||
| import javax.persistence.EnumType | ||||
| import javax.persistence.Enumerated | ||||
| import javax.persistence.FetchType | ||||
| import javax.persistence.JoinColumn | ||||
| import javax.persistence.OneToOne | ||||
|  | ||||
| enum class SeriesPublishedDaysOfWeek { | ||||
|     SUN, MON, TUE, WED, THU, FRI, SAT, RANDOM | ||||
| } | ||||
|  | ||||
| enum class SeriesState { | ||||
|     PROCEEDING, SUSPEND, COMPLETE | ||||
| } | ||||
|  | ||||
| @Entity | ||||
| data class Series( | ||||
|     var title: String, | ||||
|     @Column(columnDefinition = "TEXT", nullable = false) | ||||
|     var introduction: String, | ||||
|     @Enumerated(value = EnumType.STRING) | ||||
|     var state: SeriesState = SeriesState.PROCEEDING, | ||||
|     @ElementCollection(targetClass = SeriesPublishedDaysOfWeek::class, fetch = FetchType.EAGER) | ||||
|     @Enumerated(value = EnumType.STRING) | ||||
|     @CollectionTable(name = "series_published_days_of_week", joinColumns = [JoinColumn(name = "series_id")]) | ||||
|     val publishedDaysOfWeek: Set<SeriesPublishedDaysOfWeek> = mutableSetOf(), | ||||
|     var isAdult: Boolean = false, | ||||
|     var isActive: Boolean = true | ||||
| ) : BaseEntity() { | ||||
|     @OneToOne(fetch = FetchType.EAGER) | ||||
|     @JoinColumn(name = "genre_id", nullable = false) | ||||
|     var genre: SeriesGenre? = null | ||||
|  | ||||
|     var coverImage: String? = null | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series.genre | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import org.springframework.security.access.prepost.PreAuthorize | ||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||
| import org.springframework.web.bind.annotation.GetMapping | ||||
| import org.springframework.web.bind.annotation.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RestController | ||||
|  | ||||
| @RestController | ||||
| @PreAuthorize("hasRole('CREATOR')") | ||||
| @RequestMapping("/creator-admin/audio-content/series/genre") | ||||
| class CreatorAdminContentSeriesGenreController(private val service: CreatorAdminContentSeriesGenreService) { | ||||
|     @GetMapping | ||||
|     fun getGenreList( | ||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||
|     ) = run { | ||||
|         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||
|  | ||||
|         ApiResponse.ok(service.getGenreList(isAdult = member.auth != null)) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series.genre | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.admin.content.series.genre.QSeriesGenre.seriesGenre | ||||
| import kr.co.vividnext.sodalive.admin.content.series.genre.SeriesGenre | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface CreatorAdminContentSeriesGenreRepository : | ||||
|     JpaRepository<SeriesGenre, Long>, CreatorAdminContentSeriesGenreQueryRepository | ||||
|  | ||||
| interface CreatorAdminContentSeriesGenreQueryRepository { | ||||
|     fun getGenreList(isAdult: Boolean): List<GetGenreListResponse> | ||||
| } | ||||
|  | ||||
| class CreatorAdminContentSeriesGenreQueryRepositoryImpl( | ||||
|     private val queryFactory: JPAQueryFactory | ||||
| ) : CreatorAdminContentSeriesGenreQueryRepository { | ||||
|     override fun getGenreList(isAdult: Boolean): List<GetGenreListResponse> { | ||||
|         var where = seriesGenre.isActive.isTrue | ||||
|  | ||||
|         if (!isAdult) { | ||||
|             where = where.and(seriesGenre.isAdult.isFalse) | ||||
|         } | ||||
|  | ||||
|         return queryFactory | ||||
|             .select(QGetGenreListResponse(seriesGenre.id, seriesGenre.genre)) | ||||
|             .from(seriesGenre) | ||||
|             .where(where) | ||||
|             .orderBy(seriesGenre.orders.asc()) | ||||
|             .fetch() | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series.genre | ||||
|  | ||||
| import org.springframework.stereotype.Service | ||||
|  | ||||
| @Service | ||||
| class CreatorAdminContentSeriesGenreService(private val repository: CreatorAdminContentSeriesGenreRepository) { | ||||
|     fun getGenreList(isAdult: Boolean): List<GetGenreListResponse> { | ||||
|         return repository.getGenreList(isAdult = isAdult) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,5 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series.genre | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
|  | ||||
| data class GetGenreListResponse @QueryProjection constructor(val id: Long, val genre: String) | ||||
| @@ -0,0 +1,22 @@ | ||||
| package kr.co.vividnext.sodalive.creator.admin.content.series.keyword | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.content.hashtag.HashTag | ||||
| import kr.co.vividnext.sodalive.creator.admin.content.series.Series | ||||
| import javax.persistence.Entity | ||||
| import javax.persistence.FetchType | ||||
| import javax.persistence.JoinColumn | ||||
| import javax.persistence.ManyToOne | ||||
|  | ||||
| @Entity | ||||
| class SeriesKeyword : BaseEntity() { | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "series_id", nullable = false) | ||||
|     var series: Series? = null | ||||
|  | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "keyword_id", nullable = false) | ||||
|     var keyword: HashTag? = null | ||||
|  | ||||
|     var isActive: Boolean = true | ||||
| } | ||||
		Reference in New Issue
	
	Block a user