core: restore compilation and tests (ports, DTOs, repo fixes, metrics)

This commit is contained in:
ITQ
2026-05-20 16:57:19 +03:00
parent ea7e66c1a0
commit 5f2a6d12ac
18 changed files with 766 additions and 36 deletions
@@ -36,6 +36,7 @@ class FilmLibraryController(
private val markFilmViewedUseCase: MarkFilmViewedUseCase,
private val removeFilmFromLibraryUseCase: RemoveFilmFromLibraryUseCase,
private val getFilmLibraryUseCase: GetFilmLibraryUseCase,
private val getAllFilmsUseCase: GetAllFilmsUseCase,
private val listFilmLibraryEntriesUseCase: ListFilmLibraryEntriesUseCase,
) {
@PostMapping
@@ -0,0 +1,46 @@
package com.project.movienight.adapters.web
import com.project.movienight.adapters.web.dto.request.RateFilmRequest
import com.project.movienight.adapters.web.dto.response.FilmRatingResponse
import com.project.movienight.application.ports.input.GetFilmRatingsUseCase
import com.project.movienight.application.ports.input.RateFilmCommand
import com.project.movienight.application.ports.input.RateFilmUseCase
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import java.util.UUID
@RestController
@RequestMapping("/api/users/{userId}/ratings")
class FilmRatingController(
private val rateFilmUseCase: RateFilmUseCase,
private val getFilmRatingsUseCase: GetFilmRatingsUseCase,
) {
@PostMapping("/films/{filmId}")
@ResponseStatus(HttpStatus.CREATED)
fun rate(
@PathVariable userId: UUID,
@PathVariable filmId: UUID,
@RequestBody request: RateFilmRequest,
): FilmRatingResponse =
FilmRatingResponse.fromDomain(
rateFilmUseCase.rate(
RateFilmCommand(
userId = userId,
filmId = filmId,
score = request.score,
note = request.note,
),
),
)
@GetMapping
fun list(
@PathVariable userId: UUID,
): List<FilmRatingResponse> = getFilmRatingsUseCase.getRatings(userId).map { FilmRatingResponse.fromDomain(it) }
}
@@ -0,0 +1,34 @@
package com.project.movienight.adapters.web
import com.project.movienight.application.ports.input.GetRecommendationsUseCase
import com.project.movienight.application.ports.input.RecommendationQuery
import com.project.movienight.domain.model.ContentType
import com.project.movienight.domain.model.RecommendationResult
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.util.UUID
@RestController
@RequestMapping("/api/users/{userId}/recommendations")
class RecommendationController(
private val getRecommendationsUseCase: GetRecommendationsUseCase,
) {
@GetMapping
fun recommend(
@PathVariable userId: UUID,
@RequestParam(required = false) contentType: String?,
@RequestParam(required = false) mood: String?,
@RequestParam(required = false, defaultValue = "10") limit: Int,
): List<RecommendationResult> =
getRecommendationsUseCase.recommend(
RecommendationQuery(
userId = userId,
contentType = contentType?.let { runCatching { ContentType.valueOf(it) }.getOrNull() },
mood = mood,
limit = limit,
),
)
}
@@ -0,0 +1,53 @@
package com.project.movienight.adapters.web
import com.project.movienight.adapters.web.dto.request.UpsertUserPreferencesRequest
import com.project.movienight.adapters.web.dto.response.UserPreferencesResponse
import com.project.movienight.application.ports.input.GetUserPreferencesUseCase
import com.project.movienight.application.ports.input.UpsertUserPreferencesCommand
import com.project.movienight.application.ports.input.UpsertUserPreferencesUseCase
import com.project.movienight.domain.model.ContentType
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
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
import java.util.UUID
@RestController
@RequestMapping("/api/users/{userId}/preferences")
class UserPreferencesController(
private val upsertUserPreferencesUseCase: UpsertUserPreferencesUseCase,
private val getUserPreferencesUseCase: GetUserPreferencesUseCase,
) {
@PutMapping
fun upsert(
@PathVariable userId: UUID,
@RequestBody request: UpsertUserPreferencesRequest,
): UserPreferencesResponse =
UserPreferencesResponse.fromDomain(
upsertUserPreferencesUseCase.upsert(
UpsertUserPreferencesCommand(
userId = userId,
weightedGenres = request.weightedGenres,
plotTypes = request.plotTypes,
eras = request.eras,
castAndDirectors = request.castAndDirectors,
moods = request.moods,
contentTypes =
request.contentTypes.mapNotNull {
runCatching {
ContentType.valueOf(
it,
)
}.getOrNull()
},
),
),
)
@GetMapping
fun get(
@PathVariable userId: UUID,
): UserPreferencesResponse? = getUserPreferencesUseCase.get(userId)?.let { UserPreferencesResponse.fromDomain(it) }
}
@@ -0,0 +1,6 @@
package com.project.movienight.adapters.web.dto.request
data class RateFilmRequest(
val score: Int,
val note: String? = null,
)
@@ -0,0 +1,10 @@
package com.project.movienight.adapters.web.dto.request
data class UpsertUserPreferencesRequest(
val weightedGenres: Map<String, Int> = emptyMap(),
val plotTypes: List<String> = emptyList(),
val eras: List<String> = emptyList(),
val castAndDirectors: List<String> = emptyList(),
val moods: List<String> = emptyList(),
val contentTypes: List<String> = emptyList(),
)
@@ -0,0 +1,28 @@
package com.project.movienight.adapters.web.dto.response
import com.project.movienight.domain.model.FilmRating
import java.time.LocalDateTime
import java.util.UUID
data class FilmRatingResponse(
val id: UUID,
val userId: UUID,
val filmId: UUID,
val score: Int,
val note: String?,
val createdAt: LocalDateTime,
val updatedAt: LocalDateTime,
) {
companion object {
fun fromDomain(rating: FilmRating): FilmRatingResponse =
FilmRatingResponse(
id = rating.id,
userId = rating.userId,
filmId = rating.filmId,
score = rating.score,
note = rating.note,
createdAt = rating.createdAt,
updatedAt = rating.updatedAt,
)
}
}
@@ -0,0 +1,28 @@
package com.project.movienight.adapters.web.dto.response
import com.project.movienight.domain.model.ContentType
import com.project.movienight.domain.model.UserPreferences
import java.util.UUID
data class UserPreferencesResponse(
val userId: UUID,
val weightedGenres: Map<String, Int>,
val plotTypes: List<String>,
val eras: List<String>,
val castAndDirectors: List<String>,
val moods: List<String>,
val contentTypes: List<ContentType>,
) {
companion object {
fun fromDomain(preferences: UserPreferences): UserPreferencesResponse =
UserPreferencesResponse(
userId = preferences.userId,
weightedGenres = preferences.weightedGenres,
plotTypes = preferences.plotTypes,
eras = preferences.eras,
castAndDirectors = preferences.castAndDirectors,
moods = preferences.moods,
contentTypes = preferences.contentTypes,
)
}
}