From 9107bd526f6dfdd4e3856aa666e390c007719a24 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 12:36:57 +0300 Subject: [PATCH 1/6] #82 Add OpenAPI method Signed-off-by: vityaman --- .../src/main/resources/static/openapi/api.yml | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/backend/people/src/main/resources/static/openapi/api.yml b/backend/people/src/main/resources/static/openapi/api.yml index d750c4e7..f5b6e3da 100644 --- a/backend/people/src/main/resources/static/openapi/api.yml +++ b/backend/people/src/main/resources/static/openapi/api.yml @@ -15,6 +15,7 @@ tags: - name: Monitoring - name: People - name: Photos + - name: Topics - name: Faculties - name: Locations paths: @@ -392,6 +393,33 @@ paths: $ref: "#/components/responses/503" default: $ref: "#/components/responses/Unexpected" + /topics: + get: + tags: [ Topics ] + summary: Get all topics + description: Returns all topics list + security: + - bearerAuth: [ USER ] + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Topic" + maxItems: 512 + "401": + $ref: "#/components/responses/401" + "403": + $ref: "#/components/responses/403" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + default: + $ref: "#/components/responses/Unexpected" /faculties: get: tags: [ Faculties ] @@ -409,6 +437,16 @@ paths: items: $ref: "#/components/schemas/Faculty" maxItems: 512 + "401": + $ref: "#/components/responses/401" + "403": + $ref: "#/components/responses/403" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + default: + $ref: "#/components/responses/Unexpected" /locations: get: tags: [ Locations ] @@ -426,6 +464,16 @@ paths: items: $ref: "#/components/schemas/Location" maxItems: 512 + "401": + $ref: "#/components/responses/401" + "403": + $ref: "#/components/responses/403" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + default: + $ref: "#/components/responses/Unexpected" components: securitySchemes: bearerAuth: @@ -672,8 +720,6 @@ components: pattern: ^[A-Z][a-z]{3,32}$ maxLength: 32 example: Programming - icon: - $ref: "#/components/schemas/Picture" color: type: string description: An RGB color in the hex format @@ -683,7 +729,6 @@ components: required: - id - name - - icon - color LocationId: type: integer From f1753a4b4812f84338d071c732ef107f968145f4 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 13:00:29 +0300 Subject: [PATCH 2/6] #82 Implement getAll query Signed-off-by: vityaman --- .../se/dating/people/api/HttpTopicsApi.kt | 20 ++++++++++ .../dating/people/api/mapping/TopicMapping.kt | 11 +++++ .../se/dating/people/logic/TopicService.kt | 8 ++++ .../people/logic/basic/BasicTopicService.kt | 13 ++++++ .../logic/logging/LoggingTopicService.kt | 16 ++++++++ .../people/logic/spring/SpringTopicService.kt | 15 +++++++ .../ru/ifmo/se/dating/people/model/Topic.kt | 40 +++++++++++++++++++ .../se/dating/people/storage/TopicStorage.kt | 8 ++++ .../people/storage/jooq/JooqTopicStorage.kt | 19 +++++++++ .../storage/jooq/mapping/TopicMapping.kt | 11 +++++ .../src/main/resources/database/changelog.sql | 15 +++++++ 11 files changed, 176 insertions(+) create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/TopicMapping.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/TopicMapping.kt diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt new file mode 100644 index 00000000..c566bd72 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt @@ -0,0 +1,20 @@ +package ru.ifmo.se.dating.people.api + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import ru.ifmo.se.dating.people.api.generated.TopicsApiDelegate +import ru.ifmo.se.dating.people.api.mapping.toMessage +import ru.ifmo.se.dating.people.logic.TopicService +import ru.ifmo.se.dating.people.model.generated.TopicMessage + +@Controller +class HttpTopicsApi( + private val topicService: TopicService, +) : TopicsApiDelegate { + override fun topicsGet(): ResponseEntity> = + topicService.getAll() + .map { it.toMessage() } + .let { ResponseEntity.ok(it) } +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/TopicMapping.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/TopicMapping.kt new file mode 100644 index 00000000..050e96b4 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/TopicMapping.kt @@ -0,0 +1,11 @@ +package ru.ifmo.se.dating.people.api.mapping + +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.people.model.generated.TopicMessage + +fun Topic.toMessage(): TopicMessage = + TopicMessage( + id = id.number.toLong(), + name = name, + color = color.hex, + ) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt new file mode 100644 index 00000000..a3881096 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt @@ -0,0 +1,8 @@ +package ru.ifmo.se.dating.people.logic + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.model.Topic + +interface TopicService { + fun getAll(): Flow +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt new file mode 100644 index 00000000..f375bcd7 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt @@ -0,0 +1,13 @@ +package ru.ifmo.se.dating.people.logic.basic + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.logic.TopicService +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.people.storage.TopicStorage + +class BasicTopicService( + private val storage: TopicStorage, +) : TopicService { + override fun getAll(): Flow = + storage.selectAll() +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt new file mode 100644 index 00000000..ff05387d --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt @@ -0,0 +1,16 @@ +package ru.ifmo.se.dating.people.logic.logging + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.logging.Log.Companion.autoLog +import ru.ifmo.se.dating.people.logic.TopicService +import ru.ifmo.se.dating.people.model.Topic + +class LoggingTopicService(private val origin: TopicService) : TopicService { + private val log = autoLog() + + override fun getAll(): Flow = + runCatching { origin.getAll() } + .onSuccess { log.debug("Got all topics") } + .onFailure { e -> log.warn("Failed to get all topics: ${e.message}") } + .getOrThrow() +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt new file mode 100644 index 00000000..6aa6ccd7 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt @@ -0,0 +1,15 @@ +package ru.ifmo.se.dating.people.logic.spring + +import org.springframework.stereotype.Service +import ru.ifmo.se.dating.people.logic.TopicService +import ru.ifmo.se.dating.people.logic.basic.BasicTopicService +import ru.ifmo.se.dating.people.logic.logging.LoggingTopicService +import ru.ifmo.se.dating.people.storage.TopicStorage + +@Service +class SpringTopicService( + storage: TopicStorage, +) : TopicService by +LoggingTopicService( + BasicTopicService(storage) +) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt new file mode 100644 index 00000000..a77a67c9 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt @@ -0,0 +1,40 @@ +package ru.ifmo.se.dating.people.model + +import ru.ifmo.se.dating.validation.expectId +import ru.ifmo.se.dating.validation.expectMatches + +data class Topic( + val id: Id, + val name: String, + val color: Color, +) { + @JvmInline + value class Id(val number: Int) { + init { + expectId(number) + } + + override fun toString(): String = number.toString() + } + + @JvmInline + value class Color(val hex: String) { + init { + expectMatches("Hex", hex, regex) + } + + override fun toString(): String = hex + + companion object { + private val regex = Regex("#[A-F0-9]{6}") + } + } + + init { + expectMatches("Hex", name, nameRegex) + } + + companion object { + private val nameRegex = Regex("[A-Z][a-z]{3,32}") + } +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt new file mode 100644 index 00000000..12da274b --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt @@ -0,0 +1,8 @@ +package ru.ifmo.se.dating.people.storage + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.model.Topic + +interface TopicStorage { + fun selectAll(): Flow +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt new file mode 100644 index 00000000..63259f86 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt @@ -0,0 +1,19 @@ +package ru.ifmo.se.dating.people.storage.jooq + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.jooq.generated.tables.references.TOPIC +import org.springframework.stereotype.Repository +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.people.storage.TopicStorage +import ru.ifmo.se.dating.people.storage.jooq.mapping.toModel +import ru.ifmo.se.dating.storage.jooq.JooqDatabase + +@Repository +class JooqTopicStorage( + private val database: JooqDatabase, +) : TopicStorage { + override fun selectAll(): Flow = database.flow { + selectFrom(TOPIC) + }.map { it.toModel() } +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/TopicMapping.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/TopicMapping.kt new file mode 100644 index 00000000..910bcf7d --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/TopicMapping.kt @@ -0,0 +1,11 @@ +package ru.ifmo.se.dating.people.storage.jooq.mapping + +import org.jooq.generated.tables.records.TopicRecord +import ru.ifmo.se.dating.people.model.Topic + +fun TopicRecord.toModel(): Topic = + Topic( + id = Topic.Id(id!!), + name = name, + color = Topic.Color(color), + ) diff --git a/backend/people/src/main/resources/database/changelog.sql b/backend/people/src/main/resources/database/changelog.sql index 1e775028..391e6c08 100644 --- a/backend/people/src/main/resources/database/changelog.sql +++ b/backend/people/src/main/resources/database/changelog.sql @@ -63,3 +63,18 @@ CREATE TABLE people.picture ( is_referenced boolean NOT NULL, creation_moment timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP ); + +--changeset vityaman:topic +CREATE TABLE people.topic ( + id serial PRIMARY KEY, + name varchar(32) NOT NULL UNIQUE, + color varchar(8) NOT NULL UNIQUE +); + +INSERT INTO people.topic (name, color) +VALUES + ('Programming', '#9DE19A'), + ('Coding', '#A4C5EA'), + ('Debugging', '#BCA9E1'), + ('Compilers', '#E7ECA3'), + ('DBMS', '#98A7F2'); From 13035ac150eb08431490c88a04623a40c96a42b9 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 13:15:25 +0300 Subject: [PATCH 3/6] #82 Expose endpoint on the gateway Signed-off-by: vityaman --- backend/gateway/src/main/resources/application.yml | 6 ++++++ .../src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt | 2 +- backend/people/src/main/resources/database/changelog.sql | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/gateway/src/main/resources/application.yml b/backend/gateway/src/main/resources/application.yml index 11f8a8d4..01434dcd 100644 --- a/backend/gateway/src/main/resources/application.yml +++ b/backend/gateway/src/main/resources/application.yml @@ -97,6 +97,12 @@ spring: - Method=DELETE - Path=/api/people/*/photos/* + - id: get-people-topics + uri: lb://people + predicates: + - Method=GET + - Path=/api/topics + - id: get-people-faculties uri: lb://people predicates: diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt index a77a67c9..225e5b38 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Topic.kt @@ -31,7 +31,7 @@ data class Topic( } init { - expectMatches("Hex", name, nameRegex) + expectMatches("Name", name, nameRegex) } companion object { diff --git a/backend/people/src/main/resources/database/changelog.sql b/backend/people/src/main/resources/database/changelog.sql index 391e6c08..5c530764 100644 --- a/backend/people/src/main/resources/database/changelog.sql +++ b/backend/people/src/main/resources/database/changelog.sql @@ -77,4 +77,4 @@ VALUES ('Coding', '#A4C5EA'), ('Debugging', '#BCA9E1'), ('Compilers', '#E7ECA3'), - ('DBMS', '#98A7F2'); + ('Databases', '#98A7F2'); From bdb963cafcfd3e0ca0d6250eadc059ebd00e8ea9 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 14:17:47 +0300 Subject: [PATCH 4/6] #82 Connect interests and people Signed-off-by: vityaman --- .../se/dating/people/api/HttpPeopleApi.kt | 28 ++++++ .../se/dating/people/api/HttpTopicsApi.kt | 6 +- .../people/api/mapping/PersonMapping.kt | 22 +++-- .../se/dating/people/logic/InterestService.kt | 12 +++ .../se/dating/people/logic/TopicService.kt | 8 -- .../logic/basic/BasicInterestService.kt | 21 +++++ .../people/logic/basic/BasicTopicService.kt | 13 --- .../logic/logging/LoggingInterestService.kt | 42 +++++++++ .../logic/logging/LoggingTopicService.kt | 16 ---- .../logic/spring/SpringInterestService.kt | 15 ++++ .../people/logic/spring/SpringTopicService.kt | 15 ---- .../ru/ifmo/se/dating/people/model/Person.kt | 17 ++++ .../dating/people/storage/InterestStorage.kt | 13 +++ .../se/dating/people/storage/TopicStorage.kt | 8 -- .../storage/jooq/JooqInterestStorage.kt | 46 ++++++++++ .../people/storage/jooq/JooqPersonStorage.kt | 36 ++++++-- .../people/storage/jooq/JooqTopicStorage.kt | 19 ---- .../storage/jooq/mapping/PersonMapping.kt | 14 ++- .../src/main/resources/database/changelog.sql | 8 ++ .../src/main/resources/static/openapi/api.yml | 88 +++++++++++++++++-- 20 files changed, 345 insertions(+), 102 deletions(-) create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/InterestService.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicInterestService.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingInterestService.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringInterestService.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/InterestStorage.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt create mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqInterestStorage.kt delete mode 100644 backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpPeopleApi.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpPeopleApi.kt index 5147cccd..ef1b2f35 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpPeopleApi.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpPeopleApi.kt @@ -12,19 +12,24 @@ import ru.ifmo.se.dating.pagging.Page import ru.ifmo.se.dating.people.api.generated.PeopleApiDelegate import ru.ifmo.se.dating.people.api.mapping.toMessage import ru.ifmo.se.dating.people.api.mapping.toModel +import ru.ifmo.se.dating.people.logic.InterestService import ru.ifmo.se.dating.people.logic.PersonService import ru.ifmo.se.dating.people.logic.PictureService import ru.ifmo.se.dating.people.model.Faculty +import ru.ifmo.se.dating.people.model.Person import ru.ifmo.se.dating.people.model.Picture +import ru.ifmo.se.dating.people.model.Topic import ru.ifmo.se.dating.people.model.generated.* import ru.ifmo.se.dating.security.auth.User import ru.ifmo.se.dating.spring.security.auth.SpringSecurityContext import java.time.LocalDate import java.time.OffsetDateTime +@Suppress("TooManyFunctions") @Controller class HttpPeopleApi( private val personService: PersonService, + private val interestService: InterestService, private val pictureService: PictureService, ) : PeopleApiDelegate { override fun peopleGet( @@ -109,6 +114,29 @@ class HttpPeopleApi( return ResponseEntity.ok(Unit) } + override suspend fun peoplePersonIdInterestsTopicIdDelete( + personId: Long, + topicId: Long, + ): ResponseEntity { + interestService.remove(User.Id(personId.toInt()), Topic.Id(topicId.toInt())) + return ResponseEntity.ok(Unit) + } + + override suspend fun peoplePersonIdInterestsTopicIdPut( + personId: Long, + topicId: Long, + interestPatchMessage: InterestPatchMessage, + ): ResponseEntity { + interestService.insert( + id = User.Id(personId.toInt()), + interest = Person.Interest( + topicId = Topic.Id(topicId.toInt()), + degree = interestPatchMessage.level.value.toInt(), + ) + ) + return ResponseEntity.ok(Unit) + } + override suspend fun peoplePersonIdPhotosPost( personId: Long, body: Resource?, diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt index c566bd72..a3a47c1c 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/HttpTopicsApi.kt @@ -6,15 +6,15 @@ import org.springframework.http.ResponseEntity import org.springframework.stereotype.Controller import ru.ifmo.se.dating.people.api.generated.TopicsApiDelegate import ru.ifmo.se.dating.people.api.mapping.toMessage -import ru.ifmo.se.dating.people.logic.TopicService +import ru.ifmo.se.dating.people.logic.InterestService import ru.ifmo.se.dating.people.model.generated.TopicMessage @Controller class HttpTopicsApi( - private val topicService: TopicService, + private val interestService: InterestService, ) : TopicsApiDelegate { override fun topicsGet(): ResponseEntity> = - topicService.getAll() + interestService.getAllTopics() .map { it.toMessage() } .let { ResponseEntity.ok(it) } } diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt index 8af6325a..2f1480ee 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt @@ -1,9 +1,6 @@ package ru.ifmo.se.dating.people.api.mapping -import ru.ifmo.se.dating.people.model.Faculty -import ru.ifmo.se.dating.people.model.Location -import ru.ifmo.se.dating.people.model.Person -import ru.ifmo.se.dating.people.model.PersonVariant +import ru.ifmo.se.dating.people.model.* import ru.ifmo.se.dating.people.model.generated.* import ru.ifmo.se.dating.security.auth.User @@ -13,6 +10,7 @@ fun PersonPatchMessage.toModel(id: Int) = Person.Draft( lastName = lastName?.let { Person.Name(it) }, height = height, birthday = birthday, + interests = interests?.map { it.toModel() }?.toSet() ?: emptySet(), facultyId = facultyId?.let { Faculty.Id(it.toInt()) }, locationId = locationId?.let { Location.Id(it.toInt()) }, ) @@ -31,7 +29,7 @@ fun Person.toMessage() = PersonMessage( birthday = birthday, facultyId = facultyId.number.toLong(), locationId = locationId.number.toLong(), - interests = emptySet(), + interests = interests.map { it.toMessage() }.toSet(), zodiac = ZodiacSignMessage.leo, pictures = pictureIds.map { PictureMessage(id = it.number.toLong()) }.toSet() ) @@ -45,6 +43,18 @@ fun Person.Draft.toMessage() = PersonDraftMessage( birthday = birthday, facultyId = facultyId?.number?.toLong(), locationId = locationId?.number?.toLong(), - interests = emptySet(), + interests = interests.map { it.toMessage() }.toSet(), pictures = pictureIds.map { PictureMessage(id = it.number.toLong()) }.toSet() ) + +fun InterestMessage.toModel(): Person.Interest = + Person.Interest( + topicId = Topic.Id(topicId.toInt()), + degree = level.value.toInt(), + ) + +fun Person.Interest.toMessage(): InterestMessage = + InterestMessage( + topicId = topicId.number.toLong(), + level = InterestLevelMessage.forValue(degree.toString()), + ) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/InterestService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/InterestService.kt new file mode 100644 index 00000000..45c7cdb2 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/InterestService.kt @@ -0,0 +1,12 @@ +package ru.ifmo.se.dating.people.logic + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.model.Person +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.security.auth.User + +interface InterestService { + suspend fun insert(id: User.Id, interest: Person.Interest) + suspend fun remove(id: User.Id, topicId: Topic.Id) + fun getAllTopics(): Flow +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt deleted file mode 100644 index a3881096..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/TopicService.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ru.ifmo.se.dating.people.logic - -import kotlinx.coroutines.flow.Flow -import ru.ifmo.se.dating.people.model.Topic - -interface TopicService { - fun getAll(): Flow -} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicInterestService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicInterestService.kt new file mode 100644 index 00000000..a3194a5f --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicInterestService.kt @@ -0,0 +1,21 @@ +package ru.ifmo.se.dating.people.logic.basic + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.logic.InterestService +import ru.ifmo.se.dating.people.model.Person +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.people.storage.InterestStorage +import ru.ifmo.se.dating.security.auth.User + +class BasicInterestService( + private val storage: InterestStorage, +) : InterestService { + override suspend fun insert(id: User.Id, interest: Person.Interest) = + storage.upsert(id, interest) + + override suspend fun remove(id: User.Id, topicId: Topic.Id) = + storage.delete(id, topicId) + + override fun getAllTopics(): Flow = + storage.selectAllTopics() +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt deleted file mode 100644 index f375bcd7..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicTopicService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ru.ifmo.se.dating.people.logic.basic - -import kotlinx.coroutines.flow.Flow -import ru.ifmo.se.dating.people.logic.TopicService -import ru.ifmo.se.dating.people.model.Topic -import ru.ifmo.se.dating.people.storage.TopicStorage - -class BasicTopicService( - private val storage: TopicStorage, -) : TopicService { - override fun getAll(): Flow = - storage.selectAll() -} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingInterestService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingInterestService.kt new file mode 100644 index 00000000..1ece6ff5 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingInterestService.kt @@ -0,0 +1,42 @@ +package ru.ifmo.se.dating.people.logic.logging + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.logging.Log.Companion.autoLog +import ru.ifmo.se.dating.people.logic.InterestService +import ru.ifmo.se.dating.people.model.Person +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.security.auth.User + +class LoggingInterestService(private val origin: InterestService) : InterestService by origin { + private val log = autoLog() + + override suspend fun insert(id: User.Id, interest: Person.Interest) = + runCatching { origin.insert(id, interest) } + .onSuccess { + buildString { + append("Person with id $id is interested in ") + append("${interest.topicId} at degree ${interest.degree}") + }.let { log.info(it) } + } + .getOrThrow() + + override suspend fun remove(id: User.Id, topicId: Topic.Id) = + runCatching { origin.remove(id, topicId) } + .onSuccess { + log.info("Removed an interest in topic with id $topicId from user with id $id") + } + .onFailure { e -> + buildString { + append("Failed to remove an interest in ") + append("topic with id $topicId from ") + append("user with id $id: ${e.message}") + }.let { log.warn(it) } + } + .getOrThrow() + + override fun getAllTopics(): Flow = + runCatching { origin.getAllTopics() } + .onSuccess { log.debug("Got all topics") } + .onFailure { e -> log.warn("Failed to get all topics: ${e.message}") } + .getOrThrow() +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt deleted file mode 100644 index ff05387d..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/logging/LoggingTopicService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package ru.ifmo.se.dating.people.logic.logging - -import kotlinx.coroutines.flow.Flow -import ru.ifmo.se.dating.logging.Log.Companion.autoLog -import ru.ifmo.se.dating.people.logic.TopicService -import ru.ifmo.se.dating.people.model.Topic - -class LoggingTopicService(private val origin: TopicService) : TopicService { - private val log = autoLog() - - override fun getAll(): Flow = - runCatching { origin.getAll() } - .onSuccess { log.debug("Got all topics") } - .onFailure { e -> log.warn("Failed to get all topics: ${e.message}") } - .getOrThrow() -} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringInterestService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringInterestService.kt new file mode 100644 index 00000000..f887ff31 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringInterestService.kt @@ -0,0 +1,15 @@ +package ru.ifmo.se.dating.people.logic.spring + +import org.springframework.stereotype.Service +import ru.ifmo.se.dating.people.logic.InterestService +import ru.ifmo.se.dating.people.logic.basic.BasicInterestService +import ru.ifmo.se.dating.people.logic.logging.LoggingInterestService +import ru.ifmo.se.dating.people.storage.InterestStorage + +@Service +class SpringInterestService( + storage: InterestStorage, +) : InterestService by +LoggingInterestService( + BasicInterestService(storage) +) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt deleted file mode 100644 index 6aa6ccd7..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/spring/SpringTopicService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package ru.ifmo.se.dating.people.logic.spring - -import org.springframework.stereotype.Service -import ru.ifmo.se.dating.people.logic.TopicService -import ru.ifmo.se.dating.people.logic.basic.BasicTopicService -import ru.ifmo.se.dating.people.logic.logging.LoggingTopicService -import ru.ifmo.se.dating.people.storage.TopicStorage - -@Service -class SpringTopicService( - storage: TopicStorage, -) : TopicService by -LoggingTopicService( - BasicTopicService(storage) -) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Person.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Person.kt index 63f94678..109ec3c4 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Person.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/model/Person.kt @@ -1,5 +1,6 @@ package ru.ifmo.se.dating.people.model +import ru.ifmo.se.dating.people.model.Person.Interest import ru.ifmo.se.dating.security.auth.User import ru.ifmo.se.dating.validation.expect import ru.ifmo.se.dating.validation.expectInRange @@ -8,6 +9,7 @@ import java.time.LocalDate sealed class PersonVariant { abstract val id: User.Id + abstract val interests: Set abstract val pictureIds: List abstract val version: Person.Version } @@ -20,6 +22,7 @@ data class Person( val birthday: LocalDate, val facultyId: Faculty.Id, val locationId: Location.Id, + override val interests: Set, override val pictureIds: List, override val version: Version, val isPublished: Boolean, @@ -35,6 +38,19 @@ data class Person( } } + data class Interest( + val topicId: Topic.Id, + val degree: Int, + ) { + init { + expectInRange("Level", degree, degreeRange) + } + + companion object { + private val degreeRange = 1..5 + } + } + @JvmInline value class Version(val number: Int) { init { @@ -48,6 +64,7 @@ data class Person( val lastName: Name? = null, val height: Int? = null, val birthday: LocalDate? = null, + override val interests: Set = emptySet(), val facultyId: Faculty.Id? = null, val locationId: Location.Id? = null, override val pictureIds: List = emptyList(), diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/InterestStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/InterestStorage.kt new file mode 100644 index 00000000..a449d3dd --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/InterestStorage.kt @@ -0,0 +1,13 @@ +package ru.ifmo.se.dating.people.storage + +import kotlinx.coroutines.flow.Flow +import ru.ifmo.se.dating.people.model.Person +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.security.auth.User + +interface InterestStorage { + suspend fun upsert(id: User.Id, interest: Person.Interest) + suspend fun delete(id: User.Id, topicId: Topic.Id) + fun selectInterestsByPersonId(id: User.Id): Flow + fun selectAllTopics(): Flow +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt deleted file mode 100644 index 12da274b..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/TopicStorage.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ru.ifmo.se.dating.people.storage - -import kotlinx.coroutines.flow.Flow -import ru.ifmo.se.dating.people.model.Topic - -interface TopicStorage { - fun selectAll(): Flow -} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqInterestStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqInterestStorage.kt new file mode 100644 index 00000000..d025ccc8 --- /dev/null +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqInterestStorage.kt @@ -0,0 +1,46 @@ +package ru.ifmo.se.dating.people.storage.jooq + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.jooq.generated.tables.references.PERSON_INTEREST +import org.jooq.generated.tables.references.TOPIC +import org.springframework.stereotype.Repository +import ru.ifmo.se.dating.people.model.Person +import ru.ifmo.se.dating.people.model.Topic +import ru.ifmo.se.dating.people.storage.InterestStorage +import ru.ifmo.se.dating.people.storage.jooq.mapping.toModel +import ru.ifmo.se.dating.security.auth.User +import ru.ifmo.se.dating.storage.jooq.JooqDatabase + +@Repository +class JooqInterestStorage( + private val database: JooqDatabase, +) : InterestStorage { + override suspend fun upsert(id: User.Id, interest: Person.Interest) = database.only { + insertInto(PERSON_INTEREST) + .set(PERSON_INTEREST.PERSON_ID, id.number) + .set(PERSON_INTEREST.TOPIC_ID, interest.topicId.number) + .set(PERSON_INTEREST.DEGREE, interest.degree) + .onConflict(PERSON_INTEREST.PERSON_ID, PERSON_INTEREST.TOPIC_ID) + .doUpdate() + .set(PERSON_INTEREST.DEGREE, interest.degree) + .returning() + }.let { } + + override suspend fun delete(id: User.Id, topicId: Topic.Id) = database.only { + delete(PERSON_INTEREST) + .where( + PERSON_INTEREST.PERSON_ID.eq(id.number) + .and(PERSON_INTEREST.TOPIC_ID.eq(topicId.number)) + ) + }.let {} + + override fun selectInterestsByPersonId(id: User.Id) = database.flow { + selectFrom(PERSON_INTEREST) + .where(PERSON_INTEREST.PERSON_ID.eq(id.number)) + }.map { it.toModel() } + + override fun selectAllTopics(): Flow = database.flow { + selectFrom(TOPIC) + }.map { it.toModel() } +} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqPersonStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqPersonStorage.kt index 96e4e2c7..702ae839 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqPersonStorage.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqPersonStorage.kt @@ -1,8 +1,11 @@ package ru.ifmo.se.dating.people.storage.jooq +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.flow.toSet import org.jooq.generated.tables.records.PersonRecord import org.jooq.generated.tables.references.PERSON import org.jooq.impl.DSL.currentOffsetDateTime @@ -11,6 +14,7 @@ import org.springframework.stereotype.Repository import ru.ifmo.se.dating.exception.NotFoundException import ru.ifmo.se.dating.people.model.Person import ru.ifmo.se.dating.people.model.PersonVariant +import ru.ifmo.se.dating.people.storage.InterestStorage import ru.ifmo.se.dating.people.storage.PersonStorage import ru.ifmo.se.dating.people.storage.PictureRecordStorage import ru.ifmo.se.dating.people.storage.jooq.mapping.toModel @@ -26,6 +30,7 @@ class JooqPersonStorage( private val database: JooqDatabase, private val txEnv: TxEnv, private val pictureRecords: PictureRecordStorage, + private val interests: InterestStorage, ) : PersonStorage { @Suppress("CyclomaticComplexMethod") override suspend fun upsert(draft: Person.Draft): PersonVariant = txEnv.transactional { @@ -100,10 +105,29 @@ class JooqPersonStorage( .where(PERSON.READY_MOMENT.isNotNull) }.map { it.enrichToModel() as Person } - private suspend fun PersonRecord.enrichToModel() = - pictureRecords - .selectByOwner(User.Id(accountId)) - .toList(mutableListOf()) - .map { it.id } - .let { ids -> toModel(pictureIds = ids) } + private suspend fun PersonRecord.enrichToModel(): PersonVariant { + val userId = User.Id(accountId) + + val (interests, pictureIds) = coroutineScope { + val interests = async { + interests + .selectInterestsByPersonId(userId) + .toSet(mutableSetOf()) + } + + val pictureIds = async { + pictureRecords + .selectByOwner(userId) + .toList(mutableListOf()) + .map { it.id } + } + + Pair(interests.await(), pictureIds.await()) + } + + return toModel( + interests = interests, + pictureIds = pictureIds, + ) + } } diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt deleted file mode 100644 index 63259f86..00000000 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/JooqTopicStorage.kt +++ /dev/null @@ -1,19 +0,0 @@ -package ru.ifmo.se.dating.people.storage.jooq - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import org.jooq.generated.tables.references.TOPIC -import org.springframework.stereotype.Repository -import ru.ifmo.se.dating.people.model.Topic -import ru.ifmo.se.dating.people.storage.TopicStorage -import ru.ifmo.se.dating.people.storage.jooq.mapping.toModel -import ru.ifmo.se.dating.storage.jooq.JooqDatabase - -@Repository -class JooqTopicStorage( - private val database: JooqDatabase, -) : TopicStorage { - override fun selectAll(): Flow = database.flow { - selectFrom(TOPIC) - }.map { it.toModel() } -} diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/PersonMapping.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/PersonMapping.kt index 4f037d71..3c38ae75 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/PersonMapping.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/storage/jooq/mapping/PersonMapping.kt @@ -1,10 +1,14 @@ package ru.ifmo.se.dating.people.storage.jooq.mapping +import org.jooq.generated.tables.records.PersonInterestRecord import org.jooq.generated.tables.records.PersonRecord import ru.ifmo.se.dating.people.model.* import ru.ifmo.se.dating.security.auth.User -fun PersonRecord.toModel(pictureIds: List): PersonVariant = +fun PersonRecord.toModel( + interests: Set, + pictureIds: List, +): PersonVariant = if (readyMoment != null) { Person( id = User.Id(accountId), @@ -12,6 +16,7 @@ fun PersonRecord.toModel(pictureIds: List): PersonVariant = lastName = Person.Name(lastName!!), height = height!!, birthday = birthday!!, + interests = interests, facultyId = Faculty.Id(facultyId!!), locationId = Location.Id(locationId!!), pictureIds = pictureIds, @@ -25,9 +30,16 @@ fun PersonRecord.toModel(pictureIds: List): PersonVariant = lastName = lastName?.let { Person.Name(it) }, height = height, birthday = birthday, + interests = interests, facultyId = facultyId?.let { Faculty.Id(it) }, locationId = locationId?.let { Location.Id(it) }, pictureIds = pictureIds, version = Person.Version(version!!), ) } + +fun PersonInterestRecord.toModel(): Person.Interest = + Person.Interest( + topicId = Topic.Id(topicId), + degree = degree, + ) diff --git a/backend/people/src/main/resources/database/changelog.sql b/backend/people/src/main/resources/database/changelog.sql index 5c530764..f93b3f25 100644 --- a/backend/people/src/main/resources/database/changelog.sql +++ b/backend/people/src/main/resources/database/changelog.sql @@ -78,3 +78,11 @@ VALUES ('Debugging', '#BCA9E1'), ('Compilers', '#E7ECA3'), ('Databases', '#98A7F2'); + +--changeset vityaman:interest +CREATE TABLE people.person_interest ( + person_id integer NOT NULL REFERENCES people.person(account_id), + topic_id integer NOT NULL REFERENCES people.topic(id), + degree integer NOT NULL, + PRIMARY KEY (person_id, topic_id) +); diff --git a/backend/people/src/main/resources/static/openapi/api.yml b/backend/people/src/main/resources/static/openapi/api.yml index f5b6e3da..cf82de07 100644 --- a/backend/people/src/main/resources/static/openapi/api.yml +++ b/backend/people/src/main/resources/static/openapi/api.yml @@ -15,7 +15,7 @@ tags: - name: Monitoring - name: People - name: Photos - - name: Topics + - name: Interests - name: Faculties - name: Locations paths: @@ -300,6 +300,61 @@ paths: $ref: "#/components/responses/503" default: $ref: "#/components/responses/Unexpected" + /people/{person_id}/interests/{topic_id}: + put: + tags: [ Interests ] + security: + - bearerAuth: [ USER ] + parameters: + - $ref: "#/components/parameters/PersonIdPath" + - $ref: "#/components/parameters/TopicIdPath" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/InterestPatch" + responses: + "204": + description: OK + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "403": + $ref: "#/components/responses/403" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + default: + $ref: "#/components/responses/Unexpected" + delete: + tags: [ Interests ] + security: + - bearerAuth: [ USER ] + parameters: + - $ref: "#/components/parameters/PersonIdPath" + - $ref: "#/components/parameters/TopicIdPath" + responses: + "204": + description: Deleted + "400": + $ref: "#/components/responses/400" + "401": + $ref: "#/components/responses/401" + "403": + $ref: "#/components/responses/403" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + default: + $ref: "#/components/responses/Unexpected" /people/{person_id}/photos: post: tags: [ Photos ] @@ -395,7 +450,7 @@ paths: $ref: "#/components/responses/Unexpected" /topics: get: - tags: [ Topics ] + tags: [ Interests ] summary: Get all topics description: Returns all topics list security: @@ -488,6 +543,12 @@ components: required: true schema: $ref: "#/components/schemas/PersonId" + TopicIdPath: + name: topic_id + in: path + required: true + schema: + $ref: "#/components/schemas/TopicId" PictureIdPath: name: picture_id in: path @@ -688,17 +749,30 @@ components: $ref: "#/components/schemas/PictureId" required: - id + InterestLevel: + type: string + description: A level of interest + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + example: 3 + InterestPatch: + type: object + properties: + level: + $ref: "#/components/schemas/InterestLevel" + required: + - level Interest: type: object properties: topicId: $ref: "#/components/schemas/TopicId" level: - type: integer - description: A level of interest - format: int32 - minimum: 1 - maximum: 5 + $ref: "#/components/schemas/InterestLevel" required: - topicId - level From 987a87dc66a1c5cf790da8e45ea9166bff06d237 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 14:19:44 +0300 Subject: [PATCH 5/6] #82 Expose endpoints on the gateway Signed-off-by: vityaman --- backend/gateway/src/main/resources/application.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/gateway/src/main/resources/application.yml b/backend/gateway/src/main/resources/application.yml index 01434dcd..602dfd55 100644 --- a/backend/gateway/src/main/resources/application.yml +++ b/backend/gateway/src/main/resources/application.yml @@ -97,6 +97,18 @@ spring: - Method=DELETE - Path=/api/people/*/photos/* + - id: put-people-person-id-interests-topic-id + uri: lb://people + predicates: + - Method=PUT + - Path=/api/people/*/interests/* + + - id: delete-people-person-id-interests-topic-id + uri: lb://people + predicates: + - Method=DELETE + - Path=/api/people/*/interests/* + - id: get-people-topics uri: lb://people predicates: From 067a9ff57c8a8a4ecaf40dff6772d86acec58443 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 16 Jan 2025 14:34:40 +0300 Subject: [PATCH 6/6] #82 Fix draft edit bug because of shitcode Signed-off-by: vityaman --- .../ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt | 2 +- .../ru/ifmo/se/dating/people/logic/basic/BasicPersonService.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt index 2f1480ee..f6dbf045 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/api/mapping/PersonMapping.kt @@ -10,7 +10,7 @@ fun PersonPatchMessage.toModel(id: Int) = Person.Draft( lastName = lastName?.let { Person.Name(it) }, height = height, birthday = birthday, - interests = interests?.map { it.toModel() }?.toSet() ?: emptySet(), + interests = emptySet(), facultyId = facultyId?.let { Faculty.Id(it.toInt()) }, locationId = locationId?.let { Location.Id(it.toInt()) }, ) diff --git a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicPersonService.kt b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicPersonService.kt index bd21453b..2e37cd80 100644 --- a/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicPersonService.kt +++ b/backend/people/src/main/kotlin/ru/ifmo/se/dating/people/logic/basic/BasicPersonService.kt @@ -49,6 +49,7 @@ class BasicPersonService( if ( variant is Person.Draft && expected.copy( + interests = variant.interests, pictureIds = variant.pictureIds, version = variant.version, ) != variant