refactor: full refactoring of project
Location and contact allocated to classes KDoc added Routes allocated to separate package
This commit is contained in:
parent
591cd28eb4
commit
e6036e2f22
11 changed files with 182 additions and 69 deletions
|
@ -1,17 +0,0 @@
|
|||
package su.coolpeople.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
// https://wiki.dc09.ru/doku.php?id=wiki:coolpeople:dev:backend#анкета
|
||||
@Serializable
|
||||
data class Profile(
|
||||
val name: String,
|
||||
val age: UInt,
|
||||
val lat: Float,
|
||||
val lon: Float,
|
||||
val city: String,
|
||||
val approx_loc: Boolean,
|
||||
val desc: String,
|
||||
val tags: Array<String>, // TODO: maybe MutableList<String>
|
||||
val contacts: Array<String>, // TODO: same
|
||||
)
|
|
@ -1,22 +0,0 @@
|
|||
package su.coolpeople.model
|
||||
|
||||
object ProfileRepository {
|
||||
// TODO: Meilisearch
|
||||
private val profiles = hashMapOf(
|
||||
0u to Profile(
|
||||
"name", 20u,
|
||||
60f, 49f, "city", true,
|
||||
"description",
|
||||
arrayOf("programming", "music"),
|
||||
arrayOf("t.me/example"),
|
||||
),
|
||||
)
|
||||
|
||||
fun get(id: UInt): Profile? {
|
||||
return profiles.get(id)
|
||||
}
|
||||
|
||||
fun delete(id: UInt): Boolean {
|
||||
return profiles.remove(id) != null
|
||||
}
|
||||
}
|
23
src/main/kotlin/su/coolpeople/models/Contact.kt
Normal file
23
src/main/kotlin/su/coolpeople/models/Contact.kt
Normal file
|
@ -0,0 +1,23 @@
|
|||
package su.coolpeople.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import su.coolpeople.models.enums.ContactType
|
||||
|
||||
/**
|
||||
* Контакт пользователя, который он может указать в своей анкете
|
||||
*
|
||||
* @property type соц. сеть от которой это контакт. Например "telegram"
|
||||
* @property id id пользователя в соответствующей соц. сети. Может быть сериализованным числом
|
||||
* @property link ссылка на социальную сеть пользователя в виде URL
|
||||
*/
|
||||
@Serializable
|
||||
data class Contact(
|
||||
val type: ContactType,
|
||||
val id: String,
|
||||
) {
|
||||
val link: String
|
||||
get() = when(type) {
|
||||
ContactType.TELEGRAM -> "tg://user?id=929365483"
|
||||
else -> throw NotImplementedError("Contact type $type does not have link implementation")
|
||||
}
|
||||
}
|
37
src/main/kotlin/su/coolpeople/models/Profile.kt
Normal file
37
src/main/kotlin/su/coolpeople/models/Profile.kt
Normal file
|
@ -0,0 +1,37 @@
|
|||
package su.coolpeople.models
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import su.coolpeople.models.geo.ApproximateLocation
|
||||
|
||||
/**
|
||||
* Анкета пользователя сервиса
|
||||
* [wiki](https://wiki.dc09.ru/doku.php?id=wiki:coolpeople:dev:backend#%D0%B0%D0%BD%D0%BA%D0%B5%D1%82%D0%B0)
|
||||
*
|
||||
* @property id анутренний id пользователя
|
||||
* @property name видимое другим имя пользователя
|
||||
* @property age реальный возраст пользователя
|
||||
* @property location местоположение пользователя. Точные коорд
|
||||
* @property description описание анкеты пользователя TODO: про проверку на XSS не забываем!!
|
||||
* @property tags список тегов по которым и идет матчинг анкет
|
||||
* @property contacts список привязанных к анкете
|
||||
*/
|
||||
@Serializable
|
||||
data class Profile(
|
||||
val id: UInt,
|
||||
val name: String,
|
||||
val age: Int,
|
||||
val location: ApproximateLocation,
|
||||
val description: String,
|
||||
val tags: List<String> = listOf(),
|
||||
val contacts: List<Contact> = listOf(),
|
||||
) {
|
||||
suspend fun addTag(tag: String): Profile {
|
||||
// data-классы как и модели по умолчанию иммутабельны. Поэтому изменяем методом и создаем копию
|
||||
TODO("Реализовать когда настроим базу данных. Должно обновлять запись в бд и возвращать новый экземпляр через .copy()")
|
||||
}
|
||||
|
||||
suspend fun removeTag(tag: String): Profile {
|
||||
TODO("Реализовать когда настроим базу данных. Должно обновлять запись в бд и возвращать новый экземпляр через .copy()")
|
||||
}
|
||||
}
|
30
src/main/kotlin/su/coolpeople/models/ProfileRepository.kt
Normal file
30
src/main/kotlin/su/coolpeople/models/ProfileRepository.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package su.coolpeople.models
|
||||
|
||||
import su.coolpeople.models.enums.ContactType
|
||||
import su.coolpeople.models.geo.ApproximateLocation
|
||||
|
||||
object ProfileRepository {
|
||||
// TODO: Meilisearch
|
||||
private val profiles = mutableMapOf(
|
||||
0U to Profile(
|
||||
0U,
|
||||
"Name",
|
||||
20,
|
||||
ApproximateLocation.fromCity("City"),
|
||||
"im super good and interesting people",
|
||||
tags = listOf("coding", "music"),
|
||||
contacts = listOf(
|
||||
Contact(ContactType.TELEGRAM, "1234567890"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
fun get(id: UInt): Profile? {
|
||||
return profiles[id]
|
||||
}
|
||||
|
||||
/* TODO: а точно ли нужно удалять аккаунты? */
|
||||
fun delete(id: UInt): Boolean {
|
||||
return profiles.remove(id) != null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package su.coolpeople.models.enums
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
enum class ContactType {
|
||||
@SerialName("telegram") TELEGRAM
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package su.coolpeople.models.geo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
/**
|
||||
* Возможно, приблизительное местоположение
|
||||
*
|
||||
* @property accurate является ли местоположение точным
|
||||
* @property location точное местоположение. Не null только если accurate == true
|
||||
* @property city город, в котором находится пользователь. Не null только если accurate == false
|
||||
*/
|
||||
@Serializable
|
||||
data class ApproximateLocation (
|
||||
val accurate: Boolean,
|
||||
val location: Location? = null,
|
||||
val city: String? = null,
|
||||
) {
|
||||
companion object {
|
||||
fun fromLocation(location: Location): ApproximateLocation {
|
||||
return ApproximateLocation(true, location)
|
||||
}
|
||||
|
||||
fun fromCity(city: String): ApproximateLocation {
|
||||
return ApproximateLocation(false, city = city)
|
||||
}
|
||||
}
|
||||
}
|
13
src/main/kotlin/su/coolpeople/models/geo/Location.kt
Normal file
13
src/main/kotlin/su/coolpeople/models/geo/Location.kt
Normal file
|
@ -0,0 +1,13 @@
|
|||
package su.coolpeople.models.geo
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Представление точного местоположения
|
||||
*/
|
||||
@Serializable
|
||||
data class Location(
|
||||
@SerialName("lat") val latitude: Float,
|
||||
@SerialName("lon") val longitude: Float,
|
||||
)
|
|
@ -5,37 +5,11 @@ import io.ktor.server.response.*
|
|||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.plugins.BadRequestException
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import su.coolpeople.model.ProfileRepository
|
||||
import kotlin.text.toUInt
|
||||
import su.coolpeople.models.ProfileRepository
|
||||
import su.coolpeople.routes.profile
|
||||
|
||||
fun Application.configureRouting() {
|
||||
routing {
|
||||
route("/api/profile") {
|
||||
put {
|
||||
TODO()
|
||||
}
|
||||
|
||||
get("/{id}") {
|
||||
val id = call.parameters["id"]?.toUIntOrNull() ?: throw BadRequestException("Invalid ID")
|
||||
|
||||
val profile = ProfileRepository.get(id)
|
||||
if (profile == null) {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
return@get
|
||||
}
|
||||
|
||||
call.respond(profile)
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
val id = call.parameters["id"]?.toUIntOrNull() ?: throw BadRequestException("Invalid ID")
|
||||
|
||||
if (!ProfileRepository.delete(id)) {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
profile()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,14 @@ import io.ktor.server.application.*
|
|||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
fun Application.configureSerialization() {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
val tolerantJson = Json {
|
||||
ignoreUnknownKeys = true // Это проблемы с обратной совместимостью в будующем может решить
|
||||
}
|
||||
|
||||
json(json = tolerantJson)
|
||||
}
|
||||
}
|
||||
|
|
33
src/main/kotlin/su/coolpeople/routes/Profile.kt
Normal file
33
src/main/kotlin/su/coolpeople/routes/Profile.kt
Normal file
|
@ -0,0 +1,33 @@
|
|||
package su.coolpeople.routes
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import su.coolpeople.models.ProfileRepository
|
||||
|
||||
fun Routing.profile() {
|
||||
route("/api/profile") {
|
||||
put {
|
||||
TODO()
|
||||
}
|
||||
|
||||
get("/{id}") {
|
||||
val id = call.parameters["id"]?.toUIntOrNull() ?: throw BadRequestException("Malformed profile id")
|
||||
val profile = ProfileRepository.get(id) ?: throw NotFoundException("Profile not found")
|
||||
|
||||
call.respond(profile)
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
val id = call.parameters["id"]?.toUIntOrNull() ?: throw BadRequestException("Malformed profile id")
|
||||
|
||||
if (!ProfileRepository.delete(id)) {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue