initial commit
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package com.project.movienight
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
@ConfigurationPropertiesScan("com.project.movienight.config")
|
||||
class MovieNightApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<MovieNightApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.project.movienight
|
||||
|
||||
import com.project.movienight.application.ports.input.CreateFilmCommand
|
||||
import com.project.movienight.application.ports.input.CreateUserCommand
|
||||
import com.project.movienight.application.ports.input.EditFilmCommand
|
||||
import com.project.movienight.application.ports.input.EditUserCommand
|
||||
import com.project.movienight.application.services.FilmService
|
||||
import com.project.movienight.application.services.UserService
|
||||
import com.project.movienight.config.FilmServiceProperties
|
||||
import com.project.movienight.config.UserServiceProperties
|
||||
import org.springframework.boot.CommandLineRunner
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class MovieNightService(
|
||||
private val userService: UserService,
|
||||
private val userConfig: UserServiceProperties,
|
||||
private val filmService: FilmService,
|
||||
private val filmConfig: FilmServiceProperties,
|
||||
) : CommandLineRunner {
|
||||
fun performActions() {
|
||||
println("Заблокированные имена пользователей: ${userConfig.blockedNames}")
|
||||
println("Заблокированные паттерны в описании фильмов: ${filmConfig.blockedPatterns}")
|
||||
|
||||
println("Создание пользователей...")
|
||||
|
||||
var userAboba = userService.create(CreateUserCommand(name = "абоба", email = "aboba228@mail.com"))
|
||||
println(userAboba)
|
||||
|
||||
val userAlice = userService.create(CreateUserCommand(name = "алиса", email = "alice@mail.com"))
|
||||
println(userAlice)
|
||||
|
||||
val userBob = userService.create(CreateUserCommand(name = "боб", email = "bob@mail.com"))
|
||||
println(userBob)
|
||||
|
||||
println("Создание фильмов...")
|
||||
|
||||
var filmSpiderMan =
|
||||
filmService.create(
|
||||
CreateFilmCommand(
|
||||
"Spider-Man: Beyond the Spider-Verse",
|
||||
"Spider-Man: Beyond the Spider-Verse is an upcoming American animated superhero film based on Marvel Comics featuring the character Miles Morales / Spider-Man.",
|
||||
),
|
||||
)
|
||||
println(filmSpiderMan)
|
||||
|
||||
val filmStarWars =
|
||||
filmService.create(
|
||||
CreateFilmCommand(
|
||||
"Star Wars: Episode III – Revenge of the Sith",
|
||||
"is a 2005 American epic space opera film written and directed by George Lucas. The sequel to Attack of the Clones (2002), it is the sixth film in the Star Wars film series.",
|
||||
),
|
||||
)
|
||||
println(filmStarWars)
|
||||
|
||||
println("Редактирование фильма ${filmSpiderMan.title}")
|
||||
filmSpiderMan = filmService.edit(filmSpiderMan.id, EditFilmCommand("Delayed", "-"))
|
||||
println(filmSpiderMan)
|
||||
|
||||
println("Редактирование пользователя ${userAboba.name}")
|
||||
userAboba = userService.edit(userAboba.id, EditUserCommand("абеме"))
|
||||
println(userAboba)
|
||||
|
||||
println("Создание пользователя с запрещённым именем")
|
||||
try {
|
||||
userService.create(CreateUserCommand(name = "admin", email = "admin@mail.com"))
|
||||
} catch (e: IllegalArgumentException) {
|
||||
println("error: ${e.message}")
|
||||
}
|
||||
|
||||
println("Создание фильмов с запрещённым паттернами")
|
||||
try {
|
||||
filmService.create(CreateFilmCommand("Python", "Python is the best language"))
|
||||
} catch (e: IllegalArgumentException) {
|
||||
println("error: ${e.message}")
|
||||
}
|
||||
|
||||
println("Удаление пользователей")
|
||||
userService.delete(userAboba.id)
|
||||
userService.delete(userAlice.id)
|
||||
userService.delete(userBob.id)
|
||||
|
||||
println("Удаление фильмов")
|
||||
filmService.delete(filmSpiderMan.id)
|
||||
filmService.delete(filmStarWars.id)
|
||||
}
|
||||
|
||||
override fun run(vararg args: String) {
|
||||
println("Запустился сервис")
|
||||
performActions()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.project.movienight.adapters.id
|
||||
|
||||
import com.project.movienight.application.ports.output.IdGenerator
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.UUID
|
||||
|
||||
@Component
|
||||
class UuidGenerator : IdGenerator {
|
||||
override fun generateId(): UUID = UUID.randomUUID()
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.project.movienight.adapters.persistence.inmemory
|
||||
|
||||
import com.project.movienight.application.ports.output.FilmLibraryRepositoryPort
|
||||
import com.project.movienight.domain.model.FilmLibrary
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Repository
|
||||
class FilmLibraryRepositoryAdapter : FilmLibraryRepositoryPort {
|
||||
private val storage: MutableMap<UUID, FilmLibrary> = ConcurrentHashMap()
|
||||
private val userIdIndex: MutableMap<UUID, UUID> = ConcurrentHashMap()
|
||||
|
||||
override fun save(filmLibrary: FilmLibrary): FilmLibrary {
|
||||
storage[filmLibrary.id] = filmLibrary
|
||||
userIdIndex[filmLibrary.userId] = filmLibrary.id
|
||||
return filmLibrary
|
||||
}
|
||||
|
||||
override fun findById(id: UUID): FilmLibrary? {
|
||||
return storage[id]
|
||||
}
|
||||
|
||||
override fun findAll(): List<FilmLibrary> {
|
||||
return storage.values.toList()
|
||||
}
|
||||
|
||||
override fun deleteById(id: UUID) {
|
||||
val filmLibrary = storage[id]
|
||||
if (filmLibrary != null) {
|
||||
userIdIndex.remove(filmLibrary.userId)
|
||||
}
|
||||
storage.remove(id)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.project.movienight.adapters.persistence.inmemory
|
||||
|
||||
import com.project.movienight.application.ports.output.FilmRepositoryPort
|
||||
import com.project.movienight.domain.model.Film
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Repository
|
||||
class FilmRepositoryAdapter : FilmRepositoryPort {
|
||||
private val films: MutableMap<UUID, Film> = ConcurrentHashMap()
|
||||
|
||||
override fun save(film: Film): Film {
|
||||
films[film.id] = film
|
||||
|
||||
return film
|
||||
}
|
||||
|
||||
override fun findById(id: UUID): Film? = films[id]
|
||||
|
||||
override fun findAll(): List<Film> = films.values.toList()
|
||||
|
||||
override fun deleteById(id: UUID) {
|
||||
films.remove(id)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.project.movienight.adapters.persistence.inmemory
|
||||
|
||||
import com.project.movienight.application.ports.output.UserRepositoryPort
|
||||
import com.project.movienight.domain.model.User
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Repository
|
||||
class UserRepositoryAdapter : UserRepositoryPort {
|
||||
private val users: MutableMap<UUID, User> = ConcurrentHashMap()
|
||||
|
||||
override fun save(user: User): User {
|
||||
users[user.id] = user
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
override fun findById(id: UUID): User? = users[id]
|
||||
|
||||
override fun findAll(): List<User> = users.values.toList()
|
||||
|
||||
override fun deleteById(id: UUID) {
|
||||
users.remove(id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.project.movienight.application.ports.input
|
||||
|
||||
import com.project.movienight.domain.model.FilmLibrary
|
||||
import java.util.UUID
|
||||
|
||||
// 1. Создание бибилиотеки пользователя
|
||||
|
||||
interface CreateFilmLibraryUseCase {
|
||||
fun create(command: CreateFilmLibraryCommand): FilmLibrary
|
||||
}
|
||||
|
||||
data class CreateFilmLibraryCommand(
|
||||
val userId: UUID,
|
||||
val name: String = "Мои фильмы"
|
||||
)
|
||||
|
||||
|
||||
// 2. Добавление фильма в библиотеку
|
||||
|
||||
interface AddFilmToLibraryUseCase {
|
||||
fun addFilm(command: AddFilmToLibraryCommand): FilmLibrary
|
||||
}
|
||||
|
||||
data class AddFilmToLibraryCommand(
|
||||
val userId: UUID,
|
||||
val filmId: UUID
|
||||
)
|
||||
|
||||
// 3. Удаление фильма из библиотеки
|
||||
|
||||
interface RemoveFilmFromLibraryUseCase {
|
||||
fun removeFilm(command: RemoveFilmFromLibraryCommand): FilmLibrary
|
||||
}
|
||||
|
||||
data class RemoveFilmFromLibraryCommand(
|
||||
val userId: UUID,
|
||||
val filmId: UUID,
|
||||
val libraryId: UUID? = null
|
||||
)
|
||||
|
||||
// 4. Получение библиотеки пользователя
|
||||
|
||||
interface GetFilmLibraryUseCase {
|
||||
fun getLibrary(query: GetFilmLibraryQuery): FilmLibrary
|
||||
}
|
||||
|
||||
data class GetFilmLibraryQuery(
|
||||
val userId: UUID,
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.project.movienight.application.ports.input
|
||||
|
||||
import com.project.movienight.domain.model.Film
|
||||
import java.util.UUID
|
||||
|
||||
interface CreateFilmUseCase {
|
||||
fun create(command: CreateFilmCommand): Film
|
||||
}
|
||||
|
||||
data class CreateFilmCommand(
|
||||
val title: String,
|
||||
val description: String,
|
||||
)
|
||||
|
||||
interface EditFilmUseCase {
|
||||
fun edit(
|
||||
id: UUID,
|
||||
command: EditFilmCommand,
|
||||
): Film
|
||||
}
|
||||
|
||||
data class EditFilmCommand(
|
||||
val title: String,
|
||||
val description: String,
|
||||
)
|
||||
|
||||
interface DeleteFilmUseCase {
|
||||
fun delete(id: UUID)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.project.movienight.application.ports.input
|
||||
|
||||
import com.project.movienight.domain.model.User
|
||||
import java.util.UUID
|
||||
|
||||
interface CreateUserUseCase {
|
||||
fun create(command: CreateUserCommand): User
|
||||
}
|
||||
|
||||
data class CreateUserCommand(
|
||||
val name: String,
|
||||
val email: String,
|
||||
)
|
||||
|
||||
interface EditUserUseCase {
|
||||
fun edit(
|
||||
id: UUID,
|
||||
command: EditUserCommand,
|
||||
): User
|
||||
}
|
||||
|
||||
data class EditUserCommand(
|
||||
val name: String,
|
||||
)
|
||||
|
||||
interface DeleteUserUseCase {
|
||||
fun delete(id: UUID)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.project.movienight.application.ports.output
|
||||
|
||||
import com.project.movienight.domain.model.FilmLibrary
|
||||
import java.util.UUID
|
||||
|
||||
interface FilmLibraryRepositoryPort {
|
||||
fun save(filmLibrary: FilmLibrary): FilmLibrary
|
||||
|
||||
fun findById(id: UUID): FilmLibrary?
|
||||
|
||||
fun findAll(): List<FilmLibrary>
|
||||
|
||||
fun deleteById(id: UUID)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.project.movienight.application.ports.output
|
||||
|
||||
import com.project.movienight.domain.model.Film
|
||||
import java.util.UUID
|
||||
|
||||
interface FilmRepositoryPort {
|
||||
fun save(film: Film): Film
|
||||
|
||||
fun findById(id: UUID): Film?
|
||||
|
||||
fun findAll(): List<Film>
|
||||
|
||||
fun deleteById(id: UUID)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.project.movienight.application.ports.output
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
interface IdGenerator {
|
||||
fun generateId(): UUID
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.project.movienight.application.ports.output
|
||||
|
||||
import com.project.movienight.domain.model.User
|
||||
import java.util.UUID
|
||||
|
||||
interface UserRepositoryPort {
|
||||
fun save(user: User): User
|
||||
|
||||
fun findById(id: UUID): User?
|
||||
|
||||
fun findAll(): List<User>
|
||||
|
||||
fun deleteById(id: UUID)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.project.movienight.application.services
|
||||
|
||||
import com.project.movienight.application.ports.input.CreateFilmCommand
|
||||
import com.project.movienight.application.ports.input.CreateFilmUseCase
|
||||
import com.project.movienight.application.ports.input.DeleteFilmUseCase
|
||||
import com.project.movienight.application.ports.input.EditFilmCommand
|
||||
import com.project.movienight.application.ports.input.EditFilmUseCase
|
||||
import com.project.movienight.application.ports.output.FilmRepositoryPort
|
||||
import com.project.movienight.application.ports.output.IdGenerator
|
||||
import com.project.movienight.config.FilmServiceProperties
|
||||
import com.project.movienight.domain.model.Film
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class FilmService(
|
||||
private val filmRepository: FilmRepositoryPort,
|
||||
private val idGenerator: IdGenerator,
|
||||
private val filmConfig: FilmServiceProperties,
|
||||
) : CreateFilmUseCase,
|
||||
EditFilmUseCase,
|
||||
DeleteFilmUseCase {
|
||||
override fun create(command: CreateFilmCommand): Film {
|
||||
if (filmConfig.isBlocked(command.title)) {
|
||||
throw IllegalArgumentException("Film with this title is not acceptable")
|
||||
}
|
||||
if (filmConfig.isBlocked(command.description)) {
|
||||
throw IllegalArgumentException("Film with this description is not acceptable")
|
||||
}
|
||||
|
||||
val film =
|
||||
Film(
|
||||
id = idGenerator.generateId(),
|
||||
title = command.title,
|
||||
description = command.description,
|
||||
)
|
||||
return filmRepository.save(film)
|
||||
}
|
||||
|
||||
override fun edit(
|
||||
id: UUID,
|
||||
command: EditFilmCommand,
|
||||
): Film {
|
||||
if (filmConfig.isBlocked(command.title)) {
|
||||
throw IllegalArgumentException("Film with this title is not acceptable")
|
||||
}
|
||||
if (filmConfig.isBlocked(command.description)) {
|
||||
throw IllegalArgumentException("Film with this description is not acceptable")
|
||||
}
|
||||
|
||||
var film = filmRepository.findById(id) ?: throw IllegalArgumentException("Film with id $id not found")
|
||||
|
||||
film = film.copy(title = command.title, description = command.description)
|
||||
|
||||
return filmRepository.save(film)
|
||||
}
|
||||
|
||||
override fun delete(id: UUID) {
|
||||
filmRepository.findById(id) ?: throw IllegalArgumentException("Film with id $id not found")
|
||||
|
||||
filmRepository.deleteById(id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.project.movienight.application.services
|
||||
|
||||
import com.project.movienight.application.ports.input.CreateUserCommand
|
||||
import com.project.movienight.application.ports.input.CreateUserUseCase
|
||||
import com.project.movienight.application.ports.input.DeleteUserUseCase
|
||||
import com.project.movienight.application.ports.input.EditUserCommand
|
||||
import com.project.movienight.application.ports.input.EditUserUseCase
|
||||
import com.project.movienight.application.ports.output.IdGenerator
|
||||
import com.project.movienight.application.ports.output.UserRepositoryPort
|
||||
import com.project.movienight.config.UserServiceProperties
|
||||
import com.project.movienight.domain.model.User
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class UserService(
|
||||
private val userRepository: UserRepositoryPort,
|
||||
private val idGenerator: IdGenerator,
|
||||
private val userConfig: UserServiceProperties,
|
||||
) : CreateUserUseCase,
|
||||
EditUserUseCase,
|
||||
DeleteUserUseCase {
|
||||
override fun create(command: CreateUserCommand): User {
|
||||
if (userConfig.isBlocked(command.name)) {
|
||||
throw IllegalArgumentException("User with this name is not acceptable")
|
||||
}
|
||||
|
||||
val user =
|
||||
User(
|
||||
id = idGenerator.generateId(),
|
||||
name = command.name,
|
||||
email = command.email,
|
||||
library = null,
|
||||
)
|
||||
return userRepository.save(user)
|
||||
}
|
||||
|
||||
override fun edit(
|
||||
id: UUID,
|
||||
command: EditUserCommand,
|
||||
): User {
|
||||
if (userConfig.isBlocked(command.name)) {
|
||||
throw IllegalArgumentException("User with this name is not acceptable")
|
||||
}
|
||||
|
||||
var user = userRepository.findById(id) ?: throw IllegalArgumentException("User with id $id not found")
|
||||
|
||||
user = user.copy(name = command.name)
|
||||
|
||||
return userRepository.save(user)
|
||||
}
|
||||
|
||||
override fun delete(id: UUID) {
|
||||
userRepository.findById(id) ?: throw IllegalArgumentException("User with id $id not found")
|
||||
|
||||
userRepository.deleteById(id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.project.movienight.config
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ConfigurationProperties(prefix = "services.film")
|
||||
data class FilmServiceProperties(
|
||||
val blockedPatterns: List<String> = listOf(),
|
||||
) {
|
||||
val normalized: Set<String> =
|
||||
blockedPatterns
|
||||
.map { it.trim().lowercase() }
|
||||
.filter { it.isNotBlank() }
|
||||
.toSet()
|
||||
|
||||
fun isBlocked(fieldValue: String): Boolean {
|
||||
val normalizedFieldValue = fieldValue.lowercase()
|
||||
|
||||
return normalized.any { pattern -> normalizedFieldValue.contains(pattern) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.project.movienight.config
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ConfigurationProperties(prefix = "services.user")
|
||||
data class UserServiceProperties(
|
||||
val blockedNames: List<String> = listOf(),
|
||||
) {
|
||||
private val normalized: Set<String> = blockedNames.map { it.trim().lowercase() }.toSet()
|
||||
|
||||
fun isBlocked(name: String): Boolean = name.trim().lowercase() in normalized
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.project.movienight.domain.model
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class Film(
|
||||
val id: UUID,
|
||||
val title: String,
|
||||
val description: String,
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.project.movienight.domain.model
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class FilmLibrary(
|
||||
val id: UUID,
|
||||
val userId: UUID,
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.project.movienight.domain.model
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class User(
|
||||
val id: UUID,
|
||||
val name: String,
|
||||
val email: String,
|
||||
val library: FilmLibrary?,
|
||||
)
|
||||
Reference in New Issue
Block a user