From caabc59bf30ec916e662a5767f052aefff911dd0 Mon Sep 17 00:00:00 2001 From: ITQ Date: Sat, 18 Apr 2026 13:46:30 +0300 Subject: [PATCH] chore(repositories): refactored jdbc adapters and fixed security issues --- .../persistence/FilmLibraryRepository.kt | 88 ------------------- .../adapters/persistence/FilmRepository.kt | 68 -------------- .../adapters/persistence/UserRepository.kt | 83 ----------------- .../persistence/jdbc/FilmLibraryRepository.kt | 73 +++++++++++++++ .../persistence/jdbc/FilmRepository.kt | 67 ++++++++++++++ .../persistence/jdbc/UserRepository.kt | 68 ++++++++++++++ 6 files changed, 208 insertions(+), 239 deletions(-) delete mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/FilmLibraryRepository.kt delete mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/FilmRepository.kt delete mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/UserRepository.kt create mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmLibraryRepository.kt create mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmRepository.kt create mode 100644 src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/FilmLibraryRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/FilmLibraryRepository.kt deleted file mode 100644 index 4cef7d4..0000000 --- a/src/main/kotlin/com/project/movienight/adapters/persistence/FilmLibraryRepository.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.project.movienight.adapters.persistence - -import com.project.movienight.domain.model.FilmLibrary -import org.springframework.jdbc.core.JdbcTemplate -import org.springframework.stereotype.Repository -import java.util.UUID - -@Repository -class FilmLibraryRepository(private val jdbc: JdbcTemplate) { - - fun findById(id: Int): FilmLibrary? = - jdbc.queryForObject( - "SELECT * FROM favorites WHERE id = ?", - { rs, _ -> - FilmLibrary( - id = UUID.fromString(rs.getString("id")), - userId = UUID.fromString(rs.getString("userid")), - filmId = UUID.fromString(rs.getString("film_id")), - comment = rs.getString("comment"), - isViewed = rs.getBoolean("is_viewed"), - ) - }, - id - ) - - fun findAllByUserId(userId: Int): List = - jdbc.query( - "SELECT * FROM favorites WHERE userid = ?", - { rs, _ -> - FilmLibrary( - id = UUID.fromString(rs.getString("id")), - userId = UUID.fromString(rs.getString("userid")), - filmId = UUID.fromString(rs.getString("film_id")), - comment = rs.getString("comment"), - isViewed = rs.getBoolean("is_viewed"), - ) - }, - userId - ) - - fun findAll(): List = - jdbc.query( - "SELECT * FROM favorites" - ) { rs, _ -> - FilmLibrary( - id = UUID.fromString(rs.getString("id")), - userId = UUID.fromString(rs.getString("userid")), - filmId = UUID.fromString(rs.getString("film_id")), - comment = rs.getString("comment"), - isViewed = rs.getBoolean("is_viewed"), - ) - } - - fun findTopN(limit: Int, sortBy: String = "id"): List = - jdbc.query( - "SELECT * FROM favorites ORDER BY $sortBy LIMIT ?", - { rs, _ -> - FilmLibrary( - id = UUID.fromString(rs.getString("id")), - userId = UUID.fromString(rs.getString("userid")), - filmId = UUID.fromString(rs.getString("film_id")), - comment = rs.getString("comment"), - isViewed = rs.getBoolean("is_viewed"), - ) - }, - limit - ) - - fun save(library: FilmLibrary) { - jdbc.update( - """ - INSERT INTO favorites (userid, film_id, comment, is_viewed) - VALUES (?, ?, ?, ?) - ON CONFLICT (id) DO UPDATE - SET comment = ?, is_viewed = ? - """, - library.userId, library.filmId, library.comment, library.isViewed, - library.comment, library.isViewed - ) - } - - fun deleteById(id: Int) { - jdbc.update( - "DELETE FROM favorites WHERE id = ?", - id - ) - } -} diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/FilmRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/FilmRepository.kt deleted file mode 100644 index 7caabf2..0000000 --- a/src/main/kotlin/com/project/movienight/adapters/persistence/FilmRepository.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.project.movienight.adapters.persistence - -import com.project.movienight.domain.model.Film -import org.springframework.jdbc.core.JdbcTemplate -import org.springframework.stereotype.Repository -import java.time.LocalDate -import java.util.UUID - -@Repository -class FilmRepository(private val jdbc: JdbcTemplate) { - - fun findById(id: Int): Film? = - jdbc.queryForObject( - "SELECT * FROM films WHERE id = ?", - { rs, _ -> - Film( - id = UUID.fromString(rs.getString("id")), - title = rs.getString("title"), - description = rs.getString("description"), - ) - }, - id - ) - - fun findAll(): List = - jdbc.query( - "SELECT * FROM films" - ) { rs, _ -> - Film( - id = UUID.fromString(rs.getString("id")), - title = rs.getString("title"), - description = rs.getString("description"), - ) - } - - fun findTopN(limit: Int, sortBy: String = "title"): List = - jdbc.query( - "SELECT * FROM films ORDER BY $sortBy LIMIT ?", - { rs, _ -> - Film( - id = UUID.fromString(rs.getString("id")), - title = rs.getString("title"), - description = rs.getString("description"), - ) - }, - limit - ) - - fun save(film: Film) { - jdbc.update( - """ - INSERT INTO films (title, genre_id, issue_date) - VALUES (?, ?, ?) - ON CONFLICT (id) DO UPDATE - SET title = ?, genre_id = ?, issue_date = ? - """, - film.title, - film.title, - ) - } - - fun deleteById(id: Int) { - jdbc.update( - "DELETE FROM films WHERE id = ?", - id - ) - } -} diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/UserRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/UserRepository.kt deleted file mode 100644 index e453043..0000000 --- a/src/main/kotlin/com/project/movienight/adapters/persistence/UserRepository.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.project.movienight.adapters.persistence - -import com.project.movienight.domain.model.Film -import com.project.movienight.domain.model.User -import org.springframework.jdbc.core.JdbcTemplate -import org.springframework.stereotype.Repository -import java.util.UUID - -@Repository -class UserRepository(private val jdbc: JdbcTemplate) { - - fun findById(id: UUID): User? = - jdbc.queryForObject( - "SELECT * FROM users WHERE id = ?", - {rs, _ -> - User( - id = UUID.fromString(rs.getString("id")), - name = rs.getString("name"), - email = rs.getString("email"), - library = null // брать библиотеку пользователя лучше отдельным запросом, - // который будет в FilmLibraryRepository - ) - }, - id.toString() - ) - - fun save(user: User) { - jdbc.update( - """ - INSERT INTO users(id, name, email, library) - VALUES (:id, :name, :email, :library) - ON CONFLICT (id) - DO UPDATE SET name = :name, email = :email, library = :library - """, - user.id.toString(), user.name, user.email, user.library, - user.name, user.email, user.library - ) - } - - fun deleteById(id: UUID) { - jdbc.update( - "DELETE FROM users WHERE id = ?", - id.toString() - ) - } - - fun findByEmail(email: String): User? = - jdbc.queryForObject( - "SELECT * FROM users WHERE email = ?", - {rs, _ -> - User( - id = UUID.fromString(rs.getString("id")), - name = rs.getString("name"), - email = rs.getString("email"), - library = null - ) - }, - - ) - fun findTopN(limit: Int, sortBy: String = "name"): List = - jdbc.query( - "SELECT * FROM users ORDER BY $sortBy LIMIT ?", - { rs, _ -> - User( - id = UUID.fromString(rs.getString("id")), - name = rs.getString("name"), - email = rs.getString("email"), - library = null - ) - }, - limit - ) - - fun existsByEmail(email: String): Boolean { - val count = jdbc.queryForObject( - "SELECT COUNT(*) FROM users WHERE email = ?", - Int::class.java, - email - ) ?: 0 - return count > 0 - } - -} diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmLibraryRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmLibraryRepository.kt new file mode 100644 index 0000000..f5603cb --- /dev/null +++ b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmLibraryRepository.kt @@ -0,0 +1,73 @@ +package com.project.movienight.adapters.persistence.jdbc + +import com.project.movienight.application.ports.output.FilmLibraryRepositoryPort +import com.project.movienight.domain.model.FilmLibrary +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Repository +import java.sql.ResultSet +import java.util.UUID + +@Repository +class FilmLibraryRepository( + private val jdbc: JdbcTemplate, +) : FilmLibraryRepositoryPort { + private val filmLibraryRowMapper = { rs: ResultSet, _: Int -> + FilmLibrary( + id = UUID.fromString(rs.getString("id")), + userId = UUID.fromString(rs.getString("user_id")), + filmId = UUID.fromString(rs.getString("film_id")), + comment = rs.getString("comment"), + isViewed = rs.getBoolean("is_viewed"), + ) + } + + override fun save(filmLibrary: FilmLibrary): FilmLibrary { + val updatedRows = + jdbc.update( + """ + UPDATE favorites + SET user_id = ?, film_id = ?, comment = ?, is_viewed = ? + WHERE id = ? + """.trimIndent(), + filmLibrary.userId, + filmLibrary.filmId, + filmLibrary.comment, + filmLibrary.isViewed, + filmLibrary.id, + ) + if (updatedRows == 0) { + jdbc.update( + """ + INSERT INTO favorites (id, user_id, film_id, comment, is_viewed) + VALUES (?, ?, ?, ?, ?) + """.trimIndent(), + filmLibrary.id, + filmLibrary.userId, + filmLibrary.filmId, + filmLibrary.comment, + filmLibrary.isViewed, + ) + } + return filmLibrary + } + + override fun findById(id: UUID): FilmLibrary? { + val entries = + jdbc.query( + "SELECT id, user_id, film_id, comment, is_viewed FROM favorites WHERE id = ?", + filmLibraryRowMapper, + id, + ) + return entries.firstOrNull() + } + + override fun findAll(): List = + jdbc.query( + "SELECT id, user_id, film_id, comment, is_viewed FROM favorites", + filmLibraryRowMapper, + ) + + override fun deleteById(id: UUID) { + jdbc.update("DELETE FROM favorites WHERE id = ?", id) + } +} diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmRepository.kt new file mode 100644 index 0000000..2883aca --- /dev/null +++ b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/FilmRepository.kt @@ -0,0 +1,67 @@ +package com.project.movienight.adapters.persistence.jdbc + +import com.project.movienight.application.ports.output.FilmRepositoryPort +import com.project.movienight.domain.model.Film +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Repository +import java.sql.ResultSet +import java.util.UUID + +@Repository +class FilmRepository( + private val jdbc: JdbcTemplate, +) : FilmRepositoryPort { + private val filmRowMapper = { rs: ResultSet, _: Int -> + Film( + id = UUID.fromString(rs.getString("id")), + title = rs.getString("title"), + description = rs.getString("description"), + ) + } + + override fun save(film: Film): Film { + val updatedRows = + jdbc.update( + """ + UPDATE films + SET title = ?, description = ? + WHERE id = ? + """.trimIndent(), + film.title, + film.description, + film.id, + ) + if (updatedRows == 0) { + jdbc.update( + """ + INSERT INTO films (id, title, description) + VALUES (?, ?, ?) + """.trimIndent(), + film.id, + film.title, + film.description, + ) + } + return film + } + + override fun findById(id: UUID): Film? { + val films = + jdbc.query( + "SELECT id, title, description FROM films WHERE id = ?", + filmRowMapper, + id, + ) + return films.firstOrNull() + } + + override fun findAll(): List = + jdbc.query( + "SELECT id, title, description FROM films", + filmRowMapper, + ) + + override fun deleteById(id: UUID) { + jdbc.update("DELETE FROM films WHERE id = ?", id) + } +} diff --git a/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt new file mode 100644 index 0000000..a6607e5 --- /dev/null +++ b/src/main/kotlin/com/project/movienight/adapters/persistence/jdbc/UserRepository.kt @@ -0,0 +1,68 @@ +package com.project.movienight.adapters.persistence.jdbc + +import com.project.movienight.application.ports.output.UserRepositoryPort +import com.project.movienight.domain.model.User +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Repository +import java.sql.ResultSet +import java.util.UUID + +@Repository +class UserRepository( + private val jdbc: JdbcTemplate, +) : UserRepositoryPort { + private val userRowMapper = { rs: ResultSet, _: Int -> + User( + id = UUID.fromString(rs.getString("id")), + name = rs.getString("name"), + email = rs.getString("email"), + library = null, + ) + } + + override fun save(user: User): User { + val updatedRows = + jdbc.update( + """ + UPDATE users + SET name = ?, email = ? + WHERE id = ? + """.trimIndent(), + user.name, + user.email, + user.id, + ) + if (updatedRows == 0) { + jdbc.update( + """ + INSERT INTO users (id, name, email) + VALUES (?, ?, ?) + """.trimIndent(), + user.id, + user.name, + user.email, + ) + } + return user + } + + override fun findById(id: UUID): User? { + val users = + jdbc.query( + "SELECT id, name, email FROM users WHERE id = ?", + userRowMapper, + id, + ) + return users.firstOrNull() + } + + override fun findAll(): List = + jdbc.query( + "SELECT id, name, email FROM users", + userRowMapper, + ) + + override fun deleteById(id: UUID) { + jdbc.update("DELETE FROM users WHERE id = ?", id) + } +}