Skip to content
This repository was archived by the owner on Jun 8, 2025. It is now read-only.

Commit b4b3576

Browse files
authored
Merge pull request #100 from halotukozak/polishing
Polishing
2 parents 77ae6bd + 2653713 commit b4b3576

25 files changed

+2100
-1319
lines changed

backend/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
FROM gradle:8.3.0-jdk17 AS build
33
WORKDIR /backend
44
COPY . .
5-
RUN gradle build --no-daemon
5+
RUN gradle assemble --no-daemon
66

77
# Run stage
88
FROM openjdk:17-slim

backend/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ val exposed_version: String by project
44
val h2_version: String by project
55
val kotlin_version: String by project
66
val logback_version: String by project
7+
val testcontainers_version: String by project
8+
79

810
plugins {
911
kotlin("jvm") version "2.1.20"
@@ -66,4 +68,7 @@ dependencies {
6668
implementation("io.github.serpro69:kotlin-faker:1.14.0")
6769
testImplementation("io.ktor:ktor-server-test-host")
6870
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
71+
testImplementation("org.testcontainers:testcontainers:$testcontainers_version")
72+
testImplementation("org.testcontainers:postgresql:$testcontainers_version")
73+
testImplementation("org.testcontainers:junit-jupiter:$testcontainers_version")
6974
}

backend/gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ h2_version=2.3.232
44
kotlin_version=2.1.20
55
ktor_version=3.1.2
66
logback_version=1.4.14
7+
testcontainers_version=1.20.6

backend/src/main/kotlin/edu/agh/roomie/Databases.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import kotlin.random.Random
1313

1414
fun Application.configureDatabases(): Database {
1515
val database = if (isDeployment) Database.connect(
16-
url = "jdbc:postgresql://dpg-cvtqhis9c44c738puva0-a.oregon-postgres.render.com/roomie_hkrz",
16+
url = System.getenv("DATABASE_URL"),
1717
driver = "org.postgresql.Driver",
18-
user = "roomie",
19-
password = "A9hloke0pADrSXz8TzIGEUTYfiJzQM72"
18+
user = System.getenv("DB_USER"),
19+
password = System.getenv("DB_PASSWORD")
2020
) else Database.connect(
2121
url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
2222
user = "root",

backend/src/main/kotlin/edu/agh/roomie/service/MatchService.kt

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ class MatchService(database: Database) {
1616

1717
class InvitationEntity(id: EntityID<Int>) : IntEntity(id) {
1818
companion object : IntEntityClass<InvitationEntity>(InvitationTable) {
19-
fun findMatchesForUser(userId: Int) = find {
19+
fun findMatchesForUser(userId: Int): List<EntityID<Int>> = find {
2020
(InvitationTable.userId eq userId) and (InvitationTable.requestStatus eq MatchStatus.ACK) and (InvitationTable.responseStatus eq MatchStatus.ACK)
21-
}.toList().map { it.matchedUserId }
21+
}.map { it.matchedUserId }
2222

23-
fun findRequestReceivedForUser(userId: Int) = find {
23+
fun findRequestReceivedForUser(userId: Int): List<EntityID<Int>> = find {
2424
(InvitationTable.matchedUserId eq userId) and (InvitationTable.responseStatus eq MatchStatus.NONE) and (InvitationTable.requestStatus eq MatchStatus.ACK)
25-
}.toList().map { it.userId }
25+
}.map { it.userId }
2626

27-
fun findResponseSentForUser(userId: Int) = find {
28-
(InvitationTable.userId eq userId) and (InvitationTable.requestStatus neq MatchStatus.NACK)
29-
}.toList()
27+
fun findPendingSentRequestsForUser(userId: Int): List<EntityID<Int>> = find {
28+
(InvitationTable.userId eq userId) and (InvitationTable.requestStatus eq MatchStatus.ACK) and (InvitationTable.responseStatus eq MatchStatus.NONE)
29+
}.map { it.matchedUserId }
3030
}
3131

3232
var userId by InvitationTable.userId
@@ -51,49 +51,46 @@ class MatchService(database: Database) {
5151
}
5252

5353
fun getResultsForUser(userId: Int): MatchResultResponse = transaction {
54-
val user = UserService.UserEntity.findById(userId)!!.toShared()
54+
val user = UserService.UserEntity.findById(userId)?.toShared() ?: throw IllegalArgumentException("User not found")
5555

5656
val matches = InvitationEntity.findMatchesForUser(userId)
57-
val sentRequests =
58-
InvitationEntity.findResponseSentForUser(userId)
59-
.filter { it.requestStatus == MatchStatus.ACK && it.responseStatus == MatchStatus.NONE }
60-
.map { it.matchedUserId }
57+
val sentRequests = InvitationEntity.findPendingSentRequestsForUser(userId)
6158
val receivedRequests = InvitationEntity.findRequestReceivedForUser(userId)
62-
val allUsers = UserService.UserEntity.findByIds(
63-
matches + sentRequests + receivedRequests
64-
)
59+
60+
val allUserIds = (matches + sentRequests + receivedRequests).distinct()
61+
val allUsers = UserService.UserEntity.findByIds(allUserIds).associateBy { it.id }
6562

6663
MatchResultResponse(
67-
allUsers.filter { it.id in matches }.map { Match(it.toShared(), countScore(it.toShared(), user)) },
68-
allUsers.filter { it.id in sentRequests }.map { Match(it.toShared(), countScore(it.toShared(), user)) },
69-
allUsers.filter { it.id in receivedRequests }.map { Match(it.toShared(), countScore(it.toShared(), user)) })
64+
matches = matches.mapNotNull { allUsers[it] }
65+
.map { Match(it.toShared(), countScore(it.toShared(), user)) },
66+
sentRequests = sentRequests.mapNotNull { allUsers[it] }
67+
.map { Match(it.toShared(), countScore(it.toShared(), user)) },
68+
receivedRequests = receivedRequests.mapNotNull { allUsers[it] }
69+
.map { Match(it.toShared(), countScore(it.toShared(), user)) })
7070
}
7171

7272
fun getAvailableMatchesForUser(userId: Int): List<User> = transaction {
73-
val requestsSent =
74-
InvitationEntity.find {
75-
(InvitationTable.userId eq userId) and (InvitationTable.requestStatus neq MatchStatus.NONE)
76-
}.toList().map { it.matchedUserId }
77-
78-
val result =
73+
val requestsSent = InvitationEntity.find {
74+
(InvitationTable.userId eq userId) and (InvitationTable.requestStatus neq MatchStatus.NONE)
75+
}.map { it.matchedUserId }
76+
77+
// Find users who:
78+
// 1. Are not the current user
79+
// 2. Haven't been swiped on by the current user
80+
// 3. Have completed their profile (have info and preferences)
7981
UserService.UserEntity.find {
8082
(UsersTable.id neq userId) and (UsersTable.id notInList requestsSent) and (UsersTable.info neq null) and (UsersTable.preferences neq null)
8183
}.map { it.toShared() }
82-
result
8384
}
8485

8586
fun getRequestReceivedForUser(userId: Int): List<User> = transaction {
86-
val requests = InvitationEntity.findRequestReceivedForUser(userId)
87-
UserService.UserEntity.findByIds(requests).map { it.toShared() }
87+
val requestUserIds = InvitationEntity.findRequestReceivedForUser(userId)
88+
UserService.UserEntity.findByIds(requestUserIds).map { it.toShared() }
8889
}
8990

9091
fun registerSwipe(thisUserId: Int, swipedUserId: Int, status: MatchStatus): MatchStatus = transaction {
91-
val thisUser = UserService.UserEntity.findById(thisUserId)
92-
val swipedUser = UserService.UserEntity.findById(swipedUserId)
93-
94-
if (thisUser == null || swipedUser == null) {
95-
throw IllegalArgumentException("User not found")
96-
}
92+
val thisUser = UserService.UserEntity.findById(thisUserId) ?: throw IllegalArgumentException("User not found")
93+
val swipedUser = UserService.UserEntity.findById(swipedUserId) ?: throw IllegalArgumentException("User not found")
9794

9895
val invitation = InvitationEntity.find {
9996
(InvitationTable.userId eq thisUser.id) and (InvitationTable.matchedUserId eq swipedUser.id)

backend/src/main/kotlin/edu/agh/roomie/service/UserService.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class UserService(database: Database) {
1919
return hash.joinToString("") { "%02x".format(it) }
2020
}
2121

22-
private fun verifyPassword(password: String, hashedPassword: String): Boolean {
23-
return hashPassword(password) == hashedPassword
24-
}
22+
private fun verifyPassword(password: String, hashedPassword: String): Boolean = hashPassword(password) == hashedPassword
2523

2624
class UserEntity(id: EntityID<Int>) : IntEntity(id) {
2725
companion object : IntEntityClass<UserEntity>(UsersTable) {
@@ -62,7 +60,6 @@ class UserService(database: Database) {
6260
if (user != null && verifyPassword(password, user.password)) {
6361
user.id.value
6462
} else {
65-
println("Authentication failed for user: $email")
6663
null
6764
}
6865
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package edu.agh.roomie
2+
3+
import org.jetbrains.exposed.sql.Database
4+
import org.jetbrains.exposed.sql.SchemaUtils
5+
import org.jetbrains.exposed.sql.transactions.transaction
6+
import org.testcontainers.containers.PostgreSQLContainer
7+
import org.testcontainers.utility.DockerImageName
8+
9+
object TestUtils {
10+
private val postgresContainer by lazy {
11+
PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:15-alpine")).apply {
12+
withDatabaseName("testdb")
13+
withUsername("test")
14+
withPassword("test")
15+
start()
16+
}
17+
}
18+
19+
/**
20+
* Creates a PostgreSQL database for testing using TestContainers
21+
*/
22+
23+
val testDatabase: Database by lazy {
24+
Database.connect(
25+
url = postgresContainer.jdbcUrl,
26+
user = postgresContainer.username,
27+
driver = "org.postgresql.Driver",
28+
password = postgresContainer.password
29+
)
30+
}
31+
32+
fun createTestDatabase(): Database {
33+
// Ensure the container is started
34+
if (!postgresContainer.isRunning) {
35+
postgresContainer.start()
36+
}
37+
38+
return testDatabase.also {
39+
transaction { SchemaUtils.dropDatabase() }
40+
}
41+
}
42+
43+
/**
44+
* Executes a transaction on the test database
45+
*/
46+
fun <T> withTestDatabase(block: () -> T): T {
47+
val database = createTestDatabase()
48+
return transaction(database) {
49+
block()
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)