diff options
-rw-r--r-- | server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt | 75 | ||||
-rw-r--r-- | server/core/test-requests/test-hello.http | 5 | ||||
-rw-r--r-- | server/frontend/src/api-schema.d.ts | 198 |
3 files changed, 196 insertions, 82 deletions
diff --git a/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt b/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt index c58763f..4bc6472 100644 --- a/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt +++ b/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt @@ -8,12 +8,23 @@ import io.ktor.server.routing.get import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream +import moe.nea.ledger.ItemChange +import moe.nea.ledger.TransactionType +import moe.nea.ledger.database.DBItemEntry import moe.nea.ledger.database.DBLogEntry import moe.nea.ledger.database.Database +import moe.nea.ledger.database.sql.Clause import moe.nea.ledger.server.core.Profile -import sh.ondr.jsonschema.jsonSchema +import moe.nea.ledger.utils.ULIDWrapper fun Route.apiRouting(database: Database) { get("/profiles") { @@ -51,12 +62,74 @@ fun Route.apiRouting(database: Database) { schema<Map<String, String?>>() } } + get("/entries") { + val logs = mutableMapOf<ULIDWrapper, LogEntry>() + val items = mutableMapOf<ULIDWrapper, MutableList<SerializableItemChange>>() + DBLogEntry.from(database.connection) + .join(DBItemEntry, Clause { column(DBItemEntry.transactionId) eq column(DBLogEntry.transactionId) }) + .select(DBLogEntry.profileId, + DBLogEntry.playerId, + DBLogEntry.transactionId, + DBLogEntry.type, + DBItemEntry.mode, + DBItemEntry.itemId, + DBItemEntry.size) + .forEach { row -> + logs.getOrPut(row[DBLogEntry.transactionId]) { + LogEntry(row[DBLogEntry.type], + row[DBLogEntry.transactionId], + listOf()) + } + items.getOrPut(row[DBLogEntry.transactionId]) { mutableListOf() } + .add(SerializableItemChange( + row[DBItemEntry.itemId].string, + row[DBItemEntry.mode], + row[DBItemEntry.size], + )) + } + val compiled = logs.values.map { it.copy(items = items[it.id]!!) } + call.respond(compiled) + }.docs { + summary = "Get all log entries" + operationId = "getLogEntries" + tag(Tags.DATA) + respondsOk { + schema<List<LogEntry>>() + } + } +} + +@Serializable +data class LogEntry( + val type: TransactionType, + val id: @Serializable(ULIDSerializer::class) ULIDWrapper, + val items: List<SerializableItemChange>, +) + +@Serializable +data class SerializableItemChange( + val itemId: String, + val direction: ItemChange.ChangeDirection, + val amount: Double, +) + +object ULIDSerializer : KSerializer<ULIDWrapper> { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ULID", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): ULIDWrapper { + return ULIDWrapper(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: ULIDWrapper) { + encoder.encodeString(value.wrapped) + } } enum class Tags : IntoTag { PROFILE, HYPIXEL, MANAGEMENT, + DATA, ; override fun intoTag(): String { diff --git a/server/core/test-requests/test-hello.http b/server/core/test-requests/test-hello.http deleted file mode 100644 index 3ddf352..0000000 --- a/server/core/test-requests/test-hello.http +++ /dev/null @@ -1,5 +0,0 @@ -### GET request to example server -GET localhost:8080/ - -### GET profiles -GET localhost:8080/api/profiles
\ No newline at end of file diff --git a/server/frontend/src/api-schema.d.ts b/server/frontend/src/api-schema.d.ts index 93bedc9..eab0d7e 100644 --- a/server/frontend/src/api-schema.d.ts +++ b/server/frontend/src/api-schema.d.ts @@ -4,95 +4,141 @@ */ export interface paths { - "/profiles": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + "/profiles": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List all profiles and players known to ledger */ + get: operations["listProfiles"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/item": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get item names for item ids */ + get: operations["getItemNames"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - /** List all profiles and players known to ledger */ - get: operations["listProfiles"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/item": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + "/entries": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get all log entries */ + get: operations["getLogEntries"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - /** Get item names for item ids */ - get: operations["getItemNames"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; } export type webhooks = Record<string, never>; export interface components { - schemas: never; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; + schemas: never; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; } export type $defs = Record<string, never>; export interface operations { - listProfiles: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; + listProfiles: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - content: { - "application/json": { - playerId: string; - profileId: string; - }[]; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + playerId: string; + profileId: string; + }[]; + }; + }; }; - }; }; - }; - getItemNames: { - parameters: { - query?: { - itemId?: string[]; - }; - header?: never; - path?: never; - cookie?: never; + getItemNames: { + parameters: { + query?: { + itemId?: string[]; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: string; + }; + }; + }; + }; }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; + getLogEntries: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - content: { - "application/json": { - [key: string]: string; - }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @enum {string} */ + type: "ACCESSORIES_SWAPPING" | "ALLOWANCE_GAIN" | "AUCTION_BOUGHT" | "AUCTION_LISTING_CHARGE" | "AUCTION_SOLD" | "AUTOMERCHANT_PROFIT_COLLECT" | "BANK_DEPOSIT" | "BANK_WITHDRAW" | "BAZAAR_BUY_INSTANT" | "BAZAAR_BUY_ORDER" | "BAZAAR_SELL_INSTANT" | "BAZAAR_SELL_ORDER" | "BITS_PURSE_STATUS" | "BOOSTER_COOKIE_ATE" | "CAPSAICIN_EYEDROPS_USED" | "COMMUNITY_SHOP_BUY" | "CORPSE_DESECRATED" | "DIE_ROLLED" | "DRACONIC_SACRIFICE" | "DUNGEON_CHEST_OPEN" | "FORGED" | "GOD_POTION_DRANK" | "GOD_POTION_MIXIN_DRANK" | "GUMMY_POLAR_BEAR_ATE" | "KAT_TIMESKIP" | "KAT_UPGRADE" | "KISMET_REROLL" | "KUUDRA_CHEST_OPEN" | "NPC_BUY" | "NPC_SELL" | "PEST_REPELLENT_USED" | "VISITOR_BARGAIN" | "WYRM_EVOKED"; + id: string; + items: { + itemId: string; + /** @enum {string} */ + direction: "GAINED" | "TRANSFORM" | "SYNC" | "CATALYST" | "LOST"; + amount: number; + }[]; + }[]; + }; + }; }; - }; }; - }; } |