From 9e9e2244abbfdb7190c9663eeac2f8d81579b5d3 Mon Sep 17 00:00:00 2001 From: Elena Date: Fri, 22 May 2026 15:38:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/FilmLibraryService.kt | 360 ++++++++++-------- .../application/services/FilmService.kt | 152 ++++---- .../application/services/UserService.kt | 45 ++- 3 files changed, 305 insertions(+), 252 deletions(-) diff --git a/src/main/kotlin/com/project/movienight/application/services/FilmLibraryService.kt b/src/main/kotlin/com/project/movienight/application/services/FilmLibraryService.kt index bdc184e..07d8d5a 100644 --- a/src/main/kotlin/com/project/movienight/application/services/FilmLibraryService.kt +++ b/src/main/kotlin/com/project/movienight/application/services/FilmLibraryService.kt @@ -1,168 +1,192 @@ -package com.project.movienight.application.services - -import com.project.movienight.adapters.metrics.BusinessMetricsService -import com.project.movienight.application.ports.input.AddFilmToLibraryCommand -import com.project.movienight.application.ports.input.AddFilmToLibraryUseCase -import com.project.movienight.application.ports.input.CreateFilmLibraryCommand -import com.project.movienight.application.ports.input.CreateFilmLibraryUseCase -import com.project.movienight.application.ports.input.GetFilmLibraryQuery -import com.project.movienight.application.ports.input.GetFilmLibraryUseCase -import com.project.movienight.application.ports.input.ListFilmLibraryEntriesUseCase -import com.project.movienight.application.ports.input.MarkFilmViewedCommand -import com.project.movienight.application.ports.input.MarkFilmViewedUseCase -import com.project.movienight.application.ports.input.RemoveFilmFromLibraryCommand -import com.project.movienight.application.ports.input.RemoveFilmFromLibraryUseCase -import com.project.movienight.application.ports.output.FilmLibraryRepositoryPort -import com.project.movienight.application.ports.output.IdGenerator -import com.project.movienight.domain.exception.DomainException -import com.project.movienight.domain.exception.EntityNotFoundException -import com.project.movienight.domain.model.FilmLibrary -import org.slf4j.LoggerFactory -import org.springframework.stereotype.Service -import java.util.UUID - -@Service -class FilmLibraryService( - private val filmLibraryRepository: FilmLibraryRepositoryPort, - private val idGenerator: IdGenerator, - private val businessMetricsService: BusinessMetricsService, -) : CreateFilmLibraryUseCase, - AddFilmToLibraryUseCase, - MarkFilmViewedUseCase, - RemoveFilmFromLibraryUseCase, - GetFilmLibraryUseCase, - ListFilmLibraryEntriesUseCase { - - private val log = LoggerFactory.getLogger(javaClass) - - override fun create(command: CreateFilmLibraryCommand): FilmLibrary { - log.info("Creating film library for user: {}", command.userId) - log.debug("Create library request: userId={}, name={}", command.userId, command.name) - - val existing = findByUserId(command.userId) - if (existing != null) { - log.debug("Library already exists for user {}: libraryId={}", command.userId, existing.id) - return existing - } - - log.warn("Library not found for user {}, cannot create", command.userId) - throw EntityNotFoundException(entity = "Film library", id = command.userId.toString()) - } - - override fun addFilm(command: AddFilmToLibraryCommand): FilmLibrary { - log.info("Adding film to library: userId={}, filmId={}", command.userId, command.filmId) - - val existingEntry = findByUserAndFilmId(command.userId, command.filmId) - if (existingEntry != null) { - log.debug("Film already in library, resetting as not viewed: entryId={}", existingEntry.id) - val saved = filmLibraryRepository.save( - existingEntry.copy( - isViewed = false, - watchedAt = null, - ) - ) - businessMetricsService.recordLibraryEvent() - log.info( - "Film re-added to library: userId={}, filmId={}, entryId={}", - command.userId, command.filmId, saved.id) - return saved - } - - val saved = filmLibraryRepository.save( - FilmLibrary( - id = idGenerator.generateId(), - userId = command.userId, - filmId = command.filmId, - comment = null, - isViewed = false, - watchedAt = null, - ) - ) - businessMetricsService.recordLibraryEvent() - log.info("Film added to library: userId={}, filmId={}, entryId={}", command.userId, command.filmId, saved.id) - return saved - } - - override fun removeFilm(command: RemoveFilmFromLibraryCommand): FilmLibrary { - log.info("Removing film from library: userId={}, filmId={}", command.userId, command.filmId) - - val existingLibrary = if (command.libraryId != null) { - log.debug("Looking up by libraryId: {}", command.libraryId) - filmLibraryRepository.findById(command.libraryId) - ?: throw EntityNotFoundException(entity = "Film library", id = command.libraryId.toString()) - } else { - log.debug("Looking up by userId and filmId") - findByUserAndFilmId(command.userId, command.filmId) - ?: throw EntityNotFoundException(entity = "Film library", id = command.filmId.toString()) - } - - if (existingLibrary.userId != command.userId || existingLibrary.filmId != command.filmId) { - log.warn("Film not found in user's library: userId={}, filmId={}", command.userId, command.filmId) - throw DomainException("Film with id ${command.filmId} not found in user's library") - } - - filmLibraryRepository.deleteById(existingLibrary.id) - businessMetricsService.recordLibraryEvent() - log.info( - "Film removed from library: userId={}, filmId={}, entryId={}", - command.userId, command.filmId, existingLibrary.id) - return existingLibrary - } - - override fun markViewed(command: MarkFilmViewedCommand): FilmLibrary { - log.info("Marking film as viewed: userId={}, filmId={}", command.userId, command.filmId) - - val existingEntry = findByUserAndFilmId(command.userId, command.filmId) - val watchedAt = command.watchedAt ?: java.time.LocalDateTime.now() - - log.debug("Marking as viewed at: {}", watchedAt) - - val saved = if (existingEntry == null) { - log.debug("Film not in library, creating new entry as viewed") - filmLibraryRepository.save( - FilmLibrary( - id = idGenerator.generateId(), - userId = command.userId, - filmId = command.filmId, - comment = null, - isViewed = true, - watchedAt = watchedAt, - ) - ) - } else { - log.debug("Updating existing entry: entryId={}, was viewed={}", existingEntry.id, existingEntry.isViewed) - filmLibraryRepository.save( - existingEntry.copy( - isViewed = true, - watchedAt = watchedAt, - ) - ) - } - businessMetricsService.recordLibraryEvent() - log.info("Film marked as viewed: userId={}, filmId={}, entryId={}", command.userId, command.filmId, saved.id) - return saved - } - - override fun getLibrary(query: GetFilmLibraryQuery): FilmLibrary { - log.debug("Getting library for user: {}", query.userId) - val library = findByUserId(query.userId) - ?: throw EntityNotFoundException(entity = "Film library", id = query.userId.toString()) - log.debug("Library found: userId={}, libraryId={}", query.userId, library.id) - return library - } - - override fun list(userId: UUID): List { - log.debug("Listing all library entries for user: {}", userId) - val entries = filmLibraryRepository.findAll().filter { it.userId == userId } - log.info("User {} has {} films in library", userId, entries.size) - return entries - } - - private fun findByUserId(userId: UUID): FilmLibrary? { - return filmLibraryRepository.findAll().firstOrNull { it.userId == userId } - } - - private fun findByUserAndFilmId(userId: UUID, filmId: UUID): FilmLibrary? { - return filmLibraryRepository.findAll().firstOrNull { it.userId == userId && it.filmId == filmId } - } -} +//package com.project.movienight.application.services +// +//import com.project.movienight.adapters.metrics.BusinessMetricsService +//import com.project.movienight.application.ports.input.AddFilmToLibraryCommand +//import com.project.movienight.application.ports.input.AddFilmToLibraryUseCase +//import com.project.movienight.application.ports.input.CreateFilmLibraryCommand +//import com.project.movienight.application.ports.input.CreateFilmLibraryUseCase +//import com.project.movienight.application.ports.input.GetFilmLibraryQuery +//import com.project.movienight.application.ports.input.GetFilmLibraryUseCase +//import com.project.movienight.application.ports.input.ListFilmLibraryEntriesUseCase +//import com.project.movienight.application.ports.input.MarkFilmViewedCommand +//import com.project.movienight.application.ports.input.MarkFilmViewedUseCase +//import com.project.movienight.application.ports.input.RemoveFilmFromLibraryCommand +//import com.project.movienight.application.ports.input.RemoveFilmFromLibraryUseCase +//import com.project.movienight.application.ports.output.FilmLibraryRepositoryPort +//import com.project.movienight.application.ports.output.IdGenerator +//import com.project.movienight.domain.exception.DomainException +//import com.project.movienight.domain.exception.EntityNotFoundException +//import com.project.movienight.domain.model.FilmLibrary +//import org.slf4j.LoggerFactory +//import org.springframework.stereotype.Service +//import java.util.UUID +// +//@Service +//class FilmLibraryService( +// private val filmLibraryRepository: FilmLibraryRepositoryPort, +// private val idGenerator: IdGenerator, +// private val businessMetricsService: BusinessMetricsService, +//) : CreateFilmLibraryUseCase, +// AddFilmToLibraryUseCase, +// MarkFilmViewedUseCase, +// RemoveFilmFromLibraryUseCase, +// GetFilmLibraryUseCase, +// ListFilmLibraryEntriesUseCase { +// private val log = LoggerFactory.getLogger(javaClass) +// +// override fun create(command: CreateFilmLibraryCommand): FilmLibrary { +// log.info("Creating film library for user: {}", command.userId) +// log.debug("Create library request: userId={}, name={}", command.userId, command.name) +// +// val existing = findByUserId(command.userId) +// if (existing != null) { +// log.debug("Library already exists for user {}: libraryId={}", command.userId, existing.id) +// return existing +// } +// +// log.warn("Library not found for user {}, cannot create", command.userId) +// throw EntityNotFoundException(entity = "Film library", id = command.userId.toString()) +// } +// +// override fun addFilm(command: AddFilmToLibraryCommand): FilmLibrary { +// log.info("Adding film to library: userId={}, filmId={}", command.userId, command.filmId) +// +// val existingEntry = findByUserAndFilmId(command.userId, command.filmId) +// if (existingEntry != null) { +// log.debug("Film already in library, resetting as not viewed: entryId={}", existingEntry.id) +// val saved = +// filmLibraryRepository.save( +// existingEntry.copy( +// isViewed = false, +// watchedAt = null, +// ), +// ) +// businessMetricsService.recordLibraryEvent() +// log.info( +// "Film re-added to library: userId={}, filmId={}, entryId={}", +// command.userId, +// command.filmId, +// saved.id, +// ) +// return saved +// } +// +// val saved = +// filmLibraryRepository.save( +// FilmLibrary( +// id = idGenerator.generateId(), +// userId = command.userId, +// filmId = command.filmId, +// comment = null, +// isViewed = false, +// watchedAt = null, +// ), +// ) +// businessMetricsService.recordLibraryEvent() +// log.info("Film added to library: userId={}, filmId={}, entryId={}", command.userId, command.filmId, saved.id) +// return saved +// } +// +// override fun removeFilm(command: RemoveFilmFromLibraryCommand): FilmLibrary { +// log.info("Removing film from library: userId={}, filmId={}", command.userId, command.filmId) +// +// val existingLibrary = +// if (command.libraryId != null) { +// log.debug("Looking up by libraryId: {}", command.libraryId) +// filmLibraryRepository.findById(command.libraryId) +// ?: throw EntityNotFoundException(entity = "Film library", id = command.libraryId.toString()) +// } else { +// log.debug("Looking up by userId and filmId") +// findByUserAndFilmId(command.userId, command.filmId) +// ?: throw EntityNotFoundException(entity = "Film library", id = command.filmId.toString()) +// } +// +// if (existingLibrary.userId != command.userId || existingLibrary.filmId != command.filmId) { +// log.warn("Film not found in user's library: userId={}, filmId={}", command.userId, command.filmId) +// throw DomainException("Film with id ${command.filmId} not found in user's library") +// } +// +// filmLibraryRepository.deleteById(existingLibrary.id) +// businessMetricsService.recordLibraryEvent() +// log.info( +// "Film removed from library: userId={}, filmId={}, entryId={}", +// command.userId, +// command.filmId, +// existingLibrary.id, +// ) +// return existingLibrary +// } +// +// override fun markViewed(command: MarkFilmViewedCommand): FilmLibrary { +// log.info("Marking film as viewed: userId={}, filmId={}", command.userId, command.filmId) +// +// val existingEntry = findByUserAndFilmId(command.userId, command.filmId) +// val watchedAt = command.watchedAt ?: java.time.LocalDateTime.now() +// +// log.debug("Marking as viewed at: {}", watchedAt) +// +// val saved = +// if (existingEntry == null) { +// log.debug("Film not in library, creating new entry as viewed") +// filmLibraryRepository.save( +// FilmLibrary( +// id = idGenerator.generateId(), +// userId = command.userId, +// filmId = command.filmId, +// comment = null, +// isViewed = true, +// watchedAt = watchedAt, +// ), +// ) +// } else { +// log.debug( +// "Updating existing entry: entryId={}, was viewed={}", +// existingEntry.id, +// existingEntry.isViewed, +// ) +// filmLibraryRepository.save( +// existingEntry.copy( +// isViewed = true, +// watchedAt = watchedAt, +// ), +// ) +// } +// businessMetricsService.recordLibraryEvent() +// log.info( +// "Film marked as viewed: userId={}, filmId={}, entryId={}", +// command.userId, +// command.filmId, +// saved.id, +// ) +// return saved +// } +// +// override fun getLibrary(query: GetFilmLibraryQuery): FilmLibrary { +// log.debug("Getting library for user: {}", query.userId) +// val library = +// findByUserId(query.userId) +// ?: throw EntityNotFoundException(entity = "Film library", id = query.userId.toString()) +// log.debug("Library found: userId={}, libraryId={}", query.userId, library.id) +// return library +// } +// +// override fun list(userId: UUID): List { +// log.debug("Listing all library entries for user: {}", userId) +// val entries = filmLibraryRepository.findAll().filter { it.userId == userId } +// log.info("User {} has {} films in library", userId, entries.size) +// return entries +// } +// +// private fun findByUserId(userId: UUID): FilmLibrary? = +// filmLibraryRepository.findAll().firstOrNull { +// it.userId == userId +// } +// +// private fun findByUserAndFilmId( +// userId: UUID, +// filmId: UUID, +// ): FilmLibrary? = +// filmLibraryRepository.findAll().firstOrNull { +// it.userId == userId && it.filmId == filmId +// } +//} diff --git a/src/main/kotlin/com/project/movienight/application/services/FilmService.kt b/src/main/kotlin/com/project/movienight/application/services/FilmService.kt index c1efda4..93de089 100644 --- a/src/main/kotlin/com/project/movienight/application/services/FilmService.kt +++ b/src/main/kotlin/com/project/movienight/application/services/FilmService.kt @@ -33,13 +33,17 @@ class FilmService( GetFilmByIdUseCase, GetAllFilmsUseCase, SearchFilmByTitleUseCase { - private val log = LoggerFactory.getLogger(javaClass) override fun create(command: CreateFilmCommand): Film { log.info("Creating new film: title='{}', contentType={}", command.title, command.contentType) - log.debug("Create film request details: title='{}', descriptionLength={}, genres={}, releaseYear={}", - command.title, command.description.length, command.genres, command.releaseYear) + log.debug( + "Create film request details: title='{}', descriptionLength={}, genres={}, releaseYear={}", + command.title, + command.description.length, + command.genres, + command.releaseYear, + ) val sample = Timer.start(meterRegistry) @@ -55,21 +59,22 @@ class FilmService( throw BlockedValueException(target = "Film", field = "description") } - val film = Film( - id = idGenerator.generateId(), - title = command.title, - description = command.description, - contentType = command.contentType, - releaseYear = command.releaseYear, - genres = command.genres, - cast = command.cast, - directors = command.directors, - imdbRating = command.imdbRating, - platformRating = command.platformRating, - externalUrl = command.externalUrl, - jellyfinItemId = command.jellyfinItemId, - jellyfinLibraryId = command.jellyfinLibraryId, - ) + val film = + Film( + id = idGenerator.generateId(), + title = command.title, + description = command.description, + contentType = command.contentType, + releaseYear = command.releaseYear, + genres = command.genres, + cast = command.cast, + directors = command.directors, + imdbRating = command.imdbRating, + platformRating = command.platformRating, + externalUrl = command.externalUrl, + jellyfinItemId = command.jellyfinItemId, + jellyfinLibraryId = command.jellyfinLibraryId, + ) val saved = filmRepository.save(film) filmCreatedCounter.increment() @@ -80,10 +85,18 @@ class FilmService( } } - override fun edit(id: UUID, command: EditFilmCommand): Film { + override fun edit( + id: UUID, + command: EditFilmCommand, + ): Film { log.info("Editing film: id={}", id) - log.debug("Edit film request details: id={}, title='{}', descriptionLength={}, genres={}", - id, command.title, command.description.length, command.genres) + log.debug( + "Edit film request details: id={}, title='{}', descriptionLength={}, genres={}", + id, + command.title, + command.description.length, + command.genres, + ) val sample = Timer.start(meterRegistry) @@ -108,20 +121,21 @@ class FilmService( log.debug("Existing film found: id={}, current title='{}'", film.id, film.title) - film = film.copy( - title = command.title, - description = command.description, - contentType = command.contentType, - releaseYear = command.releaseYear, - genres = command.genres, - cast = command.cast, - directors = command.directors, - imdbRating = command.imdbRating, - platformRating = command.platformRating, - externalUrl = command.externalUrl, - jellyfinItemId = command.jellyfinItemId, - jellyfinLibraryId = command.jellyfinLibraryId, - ) + film = + film.copy( + title = command.title, + description = command.description, + contentType = command.contentType, + releaseYear = command.releaseYear, + genres = command.genres, + cast = command.cast, + directors = command.directors, + imdbRating = command.imdbRating, + platformRating = command.platformRating, + externalUrl = command.externalUrl, + jellyfinItemId = command.jellyfinItemId, + jellyfinLibraryId = command.jellyfinLibraryId, + ) val saved = filmRepository.save(film) filmEditedCounter.increment() @@ -157,8 +171,9 @@ class FilmService( override fun getById(id: UUID): Film { log.debug("Fetching film by id: {}", id) - val film = filmRepository.findById(id) - ?: throw EntityNotFoundException(entity = "Film", id = id.toString()) + val film = + filmRepository.findById(id) + ?: throw EntityNotFoundException(entity = "Film", id = id.toString()) log.debug("Film found: id={}, title='{}'", film.id, film.title) return film } @@ -181,38 +196,45 @@ class FilmService( return film } - private val filmCreatedCounter = Counter - .builder("film_created_total") - .description("Total number of created films") - .register(meterRegistry) + private val filmCreatedCounter = + Counter + .builder("film_created_total") + .description("Total number of created films") + .register(meterRegistry) - private val filmEditedCounter = Counter - .builder("film_edited_total") - .description("Total number of successfully edited films") - .register(meterRegistry) + private val filmEditedCounter = + Counter + .builder("film_edited_total") + .description("Total number of successfully edited films") + .register(meterRegistry) - private val filmDeletedCounter = Counter - .builder("film_deleted_total") - .description("Total number of successfully deleted films") - .register(meterRegistry) + private val filmDeletedCounter = + Counter + .builder("film_deleted_total") + .description("Total number of successfully deleted films") + .register(meterRegistry) - private val filmBlockedCounter = Counter - .builder("films.blocked") - .description("Total blocked film operations") - .register(meterRegistry) + private val filmBlockedCounter = + Counter + .builder("films.blocked") + .description("Total blocked film operations") + .register(meterRegistry) - private val createFilmTimer = Timer - .builder("films.create.duration") - .description("Film creation duration") - .register(meterRegistry) + private val createFilmTimer = + Timer + .builder("films.create.duration") + .description("Film creation duration") + .register(meterRegistry) - private val editFilmTimer = Timer - .builder("films.edit.duration") - .description("Film edit duration") - .register(meterRegistry) + private val editFilmTimer = + Timer + .builder("films.edit.duration") + .description("Film edit duration") + .register(meterRegistry) - private val deleteFilmTimer = Timer - .builder("films.delete.duration") - .description("Film deletion duration") - .register(meterRegistry) + private val deleteFilmTimer = + Timer + .builder("films.delete.duration") + .description("Film deletion duration") + .register(meterRegistry) } diff --git a/src/main/kotlin/com/project/movienight/application/services/UserService.kt b/src/main/kotlin/com/project/movienight/application/services/UserService.kt index 8926742..ba8fd76 100644 --- a/src/main/kotlin/com/project/movienight/application/services/UserService.kt +++ b/src/main/kotlin/com/project/movienight/application/services/UserService.kt @@ -27,7 +27,6 @@ class UserService( DeleteUserUseCase, GetUserByIdUseCase, GetAllUsersUseCase { - private val log = LoggerFactory.getLogger(javaClass) override fun create(command: CreateUserCommand): User { @@ -39,20 +38,24 @@ class UserService( throw BlockedValueException(target = "User", field = "name") } - val user = User( - id = idGenerator.generateId(), - name = command.name, - email = command.email, - library = null, - jellyfinUserId = null, - ) + val user = + User( + id = idGenerator.generateId(), + name = command.name, + email = command.email, + library = null, + jellyfinUserId = null, + ) val saved = userRepository.save(user) log.info("User created successfully: id={}, email='{}'", saved.id, saved.email) return saved } - override fun edit(id: UUID, command: EditUserCommand): User { + override fun edit( + id: UUID, + command: EditUserCommand, + ): User { log.info("Editing user: id={}", id) log.debug("Edit user request: id={}, name='{}', jellyfinUserId={}", id, command.name, command.jellyfinUserId) @@ -61,15 +64,17 @@ class UserService( throw BlockedValueException(target = "User", field = "name") } - var user = userRepository.findById(id) - ?: throw EntityNotFoundException(entity = "User", id = id.toString()) + var user = + userRepository.findById(id) + ?: throw EntityNotFoundException(entity = "User", id = id.toString()) log.debug("Existing user found: id={}, current name='{}'", user.id, user.name) - user = user.copy( - name = command.name, - jellyfinUserId = command.jellyfinUserId ?: user.jellyfinUserId, - ) + user = + user.copy( + name = command.name, + jellyfinUserId = command.jellyfinUserId ?: user.jellyfinUserId, + ) val saved = userRepository.save(user) log.info("User edited successfully: id={}, new name='{}'", saved.id, saved.name) @@ -80,8 +85,9 @@ class UserService( log.info("Deleting user: id={}", id) log.debug("Delete user request: id={}", id) - val user = userRepository.findById(id) - ?: throw EntityNotFoundException(entity = "User", id = id.toString()) + val user = + userRepository.findById(id) + ?: throw EntityNotFoundException(entity = "User", id = id.toString()) log.debug("User found for deletion: id={}, email='{}'", user.id, user.email) @@ -91,8 +97,9 @@ class UserService( override fun getById(id: UUID): User { log.debug("Fetching user by id: {}", id) - val user = userRepository.findById(id) - ?: throw EntityNotFoundException(entity = "User", id = id.toString()) + val user = + userRepository.findById(id) + ?: throw EntityNotFoundException(entity = "User", id = id.toString()) log.debug("User found: id={}, name='{}', email='{}'", user.id, user.name, user.email) return user }