From 8b8b275889bbbd54fb12ec2b76ee2116c0e6cc17 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 11:13:18 +0300 Subject: [PATCH 01/37] add health tests --- Cargo.lock | 134 ++++++++++++------ src/cat-data-service/Cargo.toml | 2 +- .../src/service/api/health/mod.rs | 30 +++- .../src/service/api/health/started_get.rs | 1 - src/cat-data-service/src/service/api/mod.rs | 20 ++- src/cat-data-service/src/service/docs/mod.rs | 7 +- .../src/service/poem_service.rs | 7 +- 7 files changed, 139 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cb883219f..e453dfa7d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,7 +354,7 @@ dependencies = [ "async-stream", "async-trait", "base64 0.13.1", - "bytes", + "bytes 1.4.0", "fast_chemail", "fnv", "futures-util", @@ -408,7 +408,7 @@ version = "4.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a941b499fead4a3fb5392cabf42446566d18c86313f69f2deab69560394d65f" dependencies = [ - "bytes", + "bytes 1.4.0", "indexmap 1.9.3", "serde", "serde_json", @@ -519,7 +519,7 @@ dependencies = [ "async-trait", "axum-core", "bitflags", - "bytes", + "bytes 1.4.0", "futures-util", "http", "http-body", @@ -549,7 +549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" dependencies = [ "async-trait", - "bytes", + "bytes 1.4.0", "futures-util", "http", "http-body", @@ -855,6 +855,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.4.0" @@ -944,7 +950,7 @@ version = "0.1.0" dependencies = [ "arc-swap", "axum", - "bytes", + "bytes 1.4.0", "chain-impl-mockchain", "chrono", "clap 4.2.1", @@ -1219,7 +1225,7 @@ dependencies = [ "chain-crypto", "futures", "http-body", - "pin-project", + "pin-project 1.0.12", "prost 0.9.0", "rand 0.8.5", "rand_core 0.6.4", @@ -2739,6 +2745,18 @@ dependencies = [ "slab", ] +[[package]] +name = "futures_codec" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce54d63f8b0c75023ed920d46fd71d0cbbb830b0ee012726b5b4f506fb6dea5b" +dependencies = [ + "bytes 0.5.6", + "futures", + "memchr", + "pin-project 0.4.30", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -2955,7 +2973,7 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ - "bytes", + "bytes 1.4.0", "fnv", "futures-core", "futures-sink", @@ -3033,7 +3051,7 @@ checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", "bitflags", - "bytes", + "bytes 1.4.0", "headers-core", "http", "httpdate", @@ -3179,7 +3197,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "bytes", + "bytes 1.4.0", "fnv", "itoa", ] @@ -3190,7 +3208,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", + "bytes 1.4.0", "http", "pin-project-lite", ] @@ -3235,7 +3253,7 @@ version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-channel", "futures-core", "futures-util", @@ -3645,7 +3663,7 @@ dependencies = [ "base64 0.13.1", "bech32 0.8.1", "bincode", - "bytes", + "bytes 1.4.0", "chain-addr", "chain-core", "chain-crypto", @@ -4609,7 +4627,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" dependencies = [ - "bytes", + "bytes 1.4.0", "encoding_rs", "futures-util", "http", @@ -4659,7 +4677,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed1ec6589a6d4a1e0b33b4c0a3f6ee96dfba88ebdb3da51403fd7cf0a24a4b04" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-core", "httparse", "memchr", @@ -5350,13 +5368,33 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" +dependencies = [ + "pin-project-internal 0.4.30", +] + [[package]] name = "pin-project" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ - "pin-project-internal", + "pin-project-internal 1.0.12", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -5442,7 +5480,7 @@ checksum = "ebc7ae19f3e791ae8108b08801abb3708d64d3a16490c720e0b81040cae87b5d" dependencies = [ "async-compression", "async-trait", - "bytes", + "bytes 1.4.0", "chrono", "cookie", "futures-util", @@ -5469,6 +5507,7 @@ dependencies = [ "serde_urlencoded", "serde_yaml 0.9.25", "smallvec", + "sse-codec", "tempfile", "thiserror", "time 0.3.20", @@ -5521,7 +5560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc9663e1e8909b1dbd47bc99314f0b876c26f9194543e58cdfbdc942d821ed3" dependencies = [ "base64 0.21.0", - "bytes", + "bytes 1.4.0", "derive_more", "futures-util", "indexmap 2.0.0", @@ -5618,7 +5657,7 @@ version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bed5017bc2ff49649c0075d0d7a9d676933c1292480c1d137776fb205b5cd18" dependencies = [ - "bytes", + "bytes 1.4.0", "fallible-iterator", "futures-util", "log", @@ -5634,7 +5673,7 @@ checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d" dependencies = [ "base64 0.21.0", "byteorder", - "bytes", + "bytes 1.4.0", "fallible-iterator", "hmac 0.12.1", "md-5", @@ -5650,7 +5689,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6" dependencies = [ - "bytes", + "bytes 1.4.0", "chrono", "fallible-iterator", "postgres-protocol", @@ -5865,7 +5904,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ - "bytes", + "bytes 1.4.0", "prost-derive 0.9.0", ] @@ -5875,7 +5914,7 @@ version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" dependencies = [ - "bytes", + "bytes 1.4.0", "prost-derive 0.11.8", ] @@ -5885,7 +5924,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ - "bytes", + "bytes 1.4.0", "heck 0.3.3", "itertools 0.10.5", "lazy_static", @@ -5931,7 +5970,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ - "bytes", + "bytes 1.4.0", "prost 0.9.0", ] @@ -6378,7 +6417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" dependencies = [ "base64 0.21.0", - "bytes", + "bytes 1.4.0", "encoding_rs", "futures-core", "futures-util", @@ -6538,7 +6577,7 @@ dependencies = [ "borsh", "bytecheck", "byteorder", - "bytes", + "bytes 1.4.0", "num-traits", "postgres", "rand 0.8.5", @@ -7268,6 +7307,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sse-codec" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a59f811350c44b4a037aabeb72dc6a9591fc22aa95a036db9a96297c58085a" +dependencies = [ + "bytes 0.5.6", + "futures-io", + "futures_codec", + "memchr", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -7647,7 +7698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", - "bytes", + "bytes 1.4.0", "libc", "mio", "num_cpus", @@ -7688,7 +7739,7 @@ checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1" dependencies = [ "async-trait", "byteorder", - "bytes", + "bytes 1.4.0", "fallible-iterator", "futures-channel", "futures-util", @@ -7745,7 +7796,7 @@ version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-core", "futures-sink", "log", @@ -7760,8 +7811,9 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -7803,7 +7855,7 @@ dependencies = [ "async-stream", "async-trait", "base64 0.13.1", - "bytes", + "bytes 1.4.0", "futures-core", "futures-util", "h2", @@ -7812,7 +7864,7 @@ dependencies = [ "hyper", "hyper-timeout", "percent-encoding", - "pin-project", + "pin-project 1.0.12", "prost 0.9.0", "prost-derive 0.9.0", "tokio", @@ -7835,7 +7887,7 @@ dependencies = [ "async-trait", "axum", "base64 0.13.1", - "bytes", + "bytes 1.4.0", "futures-core", "futures-util", "h2", @@ -7844,7 +7896,7 @@ dependencies = [ "hyper", "hyper-timeout", "percent-encoding", - "pin-project", + "pin-project 1.0.12", "prost 0.11.8", "prost-derive 0.11.8", "tokio", @@ -7878,7 +7930,7 @@ dependencies = [ "futures-core", "futures-util", "indexmap 1.9.3", - "pin-project", + "pin-project 1.0.12", "pin-project-lite", "rand 0.8.5", "slab", @@ -7896,7 +7948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" dependencies = [ "bitflags", - "bytes", + "bytes 1.4.0", "futures-core", "futures-util", "http", @@ -7980,7 +8032,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project", + "pin-project 1.0.12", "tracing", ] @@ -7990,7 +8042,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6d094204165dcfc9cffe7b2c22d98e4a7bc86f1e8a052c83c7c5442ee325bf4" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-channel", "futures-util", "hostname", @@ -8168,7 +8220,7 @@ checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" dependencies = [ "base64 0.13.1", "byteorder", - "bytes", + "bytes 1.4.0", "http", "httparse", "log", @@ -8804,7 +8856,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c" dependencies = [ - "bytes", + "bytes 1.4.0", "futures-channel", "futures-util", "headers", @@ -8815,7 +8867,7 @@ dependencies = [ "mime_guess", "multiparty", "percent-encoding", - "pin-project", + "pin-project 1.0.12", "rustls-pemfile", "scoped-tls", "serde", diff --git a/src/cat-data-service/Cargo.toml b/src/cat-data-service/Cargo.toml index a3e7ee1a6b..1cf9298b0f 100644 --- a/src/cat-data-service/Cargo.toml +++ b/src/cat-data-service/Cargo.toml @@ -31,7 +31,7 @@ chrono = { workspace = true } jormungandr-lib = { workspace = true, optional = true } chain-impl-mockchain = { workspace = true, optional = true } -poem = { version = "1.3.58", features = ["embed", "prometheus", "compression"] } +poem = { version = "1.3.58", features = ["embed", "prometheus", "compression", "test"] } poem-openapi = { version = "3.0.4", features = [ "openapi-explorer", "rapidoc", diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index a3c2634707..1ad58bfbb0 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -1,12 +1,11 @@ +use crate::service::common::tags::ApiTags; +use poem_openapi::OpenApi; + mod live_get; mod ready_get; mod started_get; -use crate::service::common::tags::ApiTags; - -use poem_openapi::OpenApi; - -pub(crate) struct HealthApi; +pub struct HealthApi; #[OpenApi(prefix_path = "/health", tag = "ApiTags::Health")] impl HealthApi { @@ -72,3 +71,24 @@ impl HealthApi { live_get::endpoint().await } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::service::api::tests::mk_test_app; + use poem::http::StatusCode; + + #[tokio::test] + async fn health_test() { + let app = mk_test_app(HealthApi); + + let resp = app.get("/health/started").send().await; + resp.assert_status(StatusCode::NO_CONTENT); + + let resp = app.get("/health/ready").send().await; + resp.assert_status(StatusCode::NO_CONTENT); + + let resp = app.get("/health/live").send().await; + resp.assert_status(StatusCode::NO_CONTENT); + } +} diff --git a/src/cat-data-service/src/service/api/health/started_get.rs b/src/cat-data-service/src/service/api/health/started_get.rs index fb18a77151..faddf12a03 100644 --- a/src/cat-data-service/src/service/api/health/started_get.rs +++ b/src/cat-data-service/src/service/api/health/started_get.rs @@ -2,7 +2,6 @@ use crate::service::common::responses::resp_2xx::NoContent; use crate::service::common::responses::resp_5xx::{ServerError, ServiceUnavailable}; - use poem_extensions::response; use poem_extensions::UniResponse::T204; diff --git a/src/cat-data-service/src/service/api/mod.rs b/src/cat-data-service/src/service/api/mod.rs index ac213abbd8..51eaa0b46d 100644 --- a/src/cat-data-service/src/service/api/mod.rs +++ b/src/cat-data-service/src/service/api/mod.rs @@ -2,12 +2,11 @@ //! //! This defines all endpoints for the Catalyst Data Service API. //! It however does NOT contain any processing for them, that is defined elsewhere. +use crate::settings::API_URL_PREFIX; use health::HealthApi; use poem_openapi::{ContactObject, LicenseObject, OpenApiService, ServerObject}; use test_endpoints::TestApi; -use crate::settings::API_URL_PREFIX; - mod health; mod test_endpoints; @@ -54,11 +53,8 @@ fn get_api_license() -> LicenseObject { const TERMS_OF_SERVICE: &str = "https://github.com/input-output-hk/catalyst-core/blob/main/book/src/98_CODE_OF_CONDUCT.md"; -/// Combine all the API's into one -pub(crate) type OpenApiServiceT = OpenApiService<(TestApi, HealthApi), ()>; - /// Create the OpenAPI definition -pub(crate) fn mk_api(hosts: Vec) -> OpenApiServiceT { +pub(crate) fn mk_api(hosts: Vec) -> OpenApiService<(TestApi, HealthApi), ()> { let mut service = OpenApiService::new((TestApi, HealthApi), API_TITLE, API_VERSION) .contact(get_api_contact()) .description(API_DESCRIPTION) @@ -74,3 +70,15 @@ pub(crate) fn mk_api(hosts: Vec) -> OpenApiServiceT { service } + +#[cfg(test)] +mod tests { + use poem::{test::TestClient, Route}; + use poem_openapi::{OpenApi, OpenApiService}; + + pub fn mk_test_app(api: Api) -> TestClient { + let service = OpenApiService::new(api, "Test API", "0.1.0"); + let app = Route::new().nest("/", service); + TestClient::new(app) + } +} diff --git a/src/cat-data-service/src/service/docs/mod.rs b/src/cat-data-service/src/service/docs/mod.rs index 73f05f0cf9..a538a2c1cb 100644 --- a/src/cat-data-service/src/service/docs/mod.rs +++ b/src/cat-data-service/src/service/docs/mod.rs @@ -1,10 +1,11 @@ mod stoplight_elements; use poem::{endpoint::EmbeddedFileEndpoint, get, Route}; - -use super::api::OpenApiServiceT; +use poem_openapi::{OpenApi, OpenApiService, Webhook}; use rust_embed::RustEmbed; -pub(crate) fn docs(api_service: &OpenApiServiceT) -> Route { +pub(crate) fn docs( + api_service: &OpenApiService, +) -> Route { let spec = api_service.spec(); let swagger_ui = api_service.swagger_ui(); diff --git a/src/cat-data-service/src/service/poem_service.rs b/src/cat-data-service/src/service/poem_service.rs index 930acfeb13..c61154be8a 100644 --- a/src/cat-data-service/src/service/poem_service.rs +++ b/src/cat-data-service/src/service/poem_service.rs @@ -2,19 +2,16 @@ //! //! This provides only the primary entrypoint to the service. -use crate::service::docs::{docs, favicon}; -use crate::service::Error; - use crate::service::api::mk_api; +use crate::service::docs::{docs, favicon}; use crate::service::utilities::catch_panic::{set_panic_hook, ServicePanicHandler}; use crate::service::utilities::middleware::{ chain_axum::ChainAxum, tracing_mw::{init_prometheus, Tracing}, }; - +use crate::service::Error; use crate::settings::{get_api_hostnames, API_URL_PREFIX}; use crate::state::State; - use poem::endpoint::PrometheusExporter; use poem::listener::TcpListener; use poem::middleware::{CatchPanic, Compression, Cors}; From d20c45a70a2bdc9f9b8a6112590b519349358b59 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 13:46:09 +0300 Subject: [PATCH 02/37] refactor --- .../src/service/api/health/live_get.rs | 1 - .../src/service/api/health/ready_get.rs | 1 - .../src/service/common/responses/resp_2xx.rs | 6 ++++-- .../src/service/common/responses/resp_4xx.rs | 16 ++++++++-------- .../src/service/common/responses/resp_5xx.rs | 11 +++++------ src/event-db/src/queries/registration.rs | 4 ++-- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/cat-data-service/src/service/api/health/live_get.rs b/src/cat-data-service/src/service/api/health/live_get.rs index 04faaa708a..725a0eee01 100644 --- a/src/cat-data-service/src/service/api/health/live_get.rs +++ b/src/cat-data-service/src/service/api/health/live_get.rs @@ -2,7 +2,6 @@ use crate::service::common::responses::resp_2xx::NoContent; use crate::service::common::responses::resp_5xx::{ServerError, ServiceUnavailable}; - use poem_extensions::response; use poem_extensions::UniResponse::T204; use tracing::{error, info, warn}; diff --git a/src/cat-data-service/src/service/api/health/ready_get.rs b/src/cat-data-service/src/service/api/health/ready_get.rs index ad873fde99..425a0fe367 100644 --- a/src/cat-data-service/src/service/api/health/ready_get.rs +++ b/src/cat-data-service/src/service/api/health/ready_get.rs @@ -2,7 +2,6 @@ use crate::service::common::responses::resp_2xx::NoContent; use crate::service::common::responses::resp_5xx::{ServerError, ServiceUnavailable}; - use poem_extensions::response; use poem_extensions::UniResponse::T204; diff --git a/src/cat-data-service/src/service/common/responses/resp_2xx.rs b/src/cat-data-service/src/service/common/responses/resp_2xx.rs index 90cf809ad0..895fae4bf5 100644 --- a/src/cat-data-service/src/service/common/responses/resp_2xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_2xx.rs @@ -1,11 +1,13 @@ //! This module contains common and re-usable responses with a 2xx response code. //! +use poem::IntoResponse; use poem_extensions::OneResponse; +use poem_openapi::payload::Payload; #[derive(OneResponse)] #[oai(status = 200)] -pub(crate) struct EmptyOK; +pub struct OK(T); #[derive(OneResponse)] #[oai(status = 204)] @@ -14,4 +16,4 @@ pub(crate) struct EmptyOK; /// The operation completed successfully, but there is no data to return. /// /// #### NO DATA BODY IS RETURNED FOR THIS RESPONSE -pub(crate) struct NoContent; +pub struct NoContent; diff --git a/src/cat-data-service/src/service/common/responses/resp_4xx.rs b/src/cat-data-service/src/service/common/responses/resp_4xx.rs index 25e834d068..d396ad5f1a 100644 --- a/src/cat-data-service/src/service/common/responses/resp_4xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_4xx.rs @@ -7,37 +7,37 @@ use poem_openapi::payload::{Payload, PlainText}; #[derive(OneResponse)] #[oai(status = 400)] -pub(crate) struct BadRequest(T); +pub struct BadRequest(T); #[derive(OneResponse)] #[oai(status = 400)] /// This error means that the request was malformed. /// It has failed to pass validation, as specified by the OpenAPI schema. -pub(crate) struct ApiValidationError(PlainText); +pub struct ApiValidationError(PlainText); #[derive(OneResponse)] #[oai(status = 401)] -pub(crate) struct Unauthorized; +pub struct Unauthorized; #[derive(OneResponse)] #[oai(status = 403)] -pub(crate) struct Forbidden; +pub struct Forbidden; #[derive(OneResponse)] #[oai(status = 404)] -pub(crate) struct NotFound; +pub struct NotFound; #[derive(OneResponse)] #[oai(status = 405)] -pub(crate) struct MethodNotAllowed; +pub struct MethodNotAllowed; #[derive(OneResponse)] #[oai(status = 406)] -pub(crate) struct NotAcceptable; +pub struct NotAcceptable; #[derive(OneResponse)] #[oai(status = 422)] /// Common automatically produced validation error for every endpoint. /// Is generated automatically when any of the OpenAPI validation rules fail. /// Can also be generated manually. -pub(crate) struct ValidationError; +pub struct ValidationError; diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index b78a208720..a2c0e69816 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -1,6 +1,7 @@ //! This module contains common and re-usable responses with a 4xx response code. //! +use crate::settings::generate_github_issue_url; use poem::error::ResponseError; use poem::http::StatusCode; use poem_extensions::OneResponse; @@ -10,8 +11,6 @@ use poem_openapi::Object; use url::Url; use uuid::Uuid; -use crate::settings::generate_github_issue_url; - #[derive(Debug, Object)] #[oai(example, skip_serializing_if_is_none)] /// Response payload to a Bad request. @@ -51,16 +50,16 @@ impl Example for ServerErrorPayload { /// An internal server error occurred. /// /// *The contents of this response should be reported to the projects issue tracker.* -pub(crate) struct ServerError(Json); +pub struct ServerError(Json); impl ServerError { /// Create a new Server Error Response. - pub(crate) fn new(msg: Option) -> Self { + pub fn new(msg: Option) -> Self { Self(Json(ServerErrorPayload::new(msg))) } /// Get the id of this Server Error. - pub(crate) fn id(&self) -> Uuid { + pub fn id(&self) -> Uuid { self.0.id } } @@ -81,4 +80,4 @@ impl ResponseError for ServerError { /// or has become unavailable.* /// /// #### NO DATA BODY IS RETURNED FOR THIS RESPONSE -pub(crate) struct ServiceUnavailable; +pub struct ServiceUnavailable; diff --git a/src/event-db/src/queries/registration.rs b/src/event-db/src/queries/registration.rs index 7a782ad78e..22db863208 100644 --- a/src/event-db/src/queries/registration.rs +++ b/src/event-db/src/queries/registration.rs @@ -12,13 +12,13 @@ use chrono::{NaiveDateTime, Utc}; pub trait RegistrationQueries: Sync + Send + 'static { async fn get_voter( &self, - version: &Option, + event: &Option, voting_key: String, with_delegations: bool, ) -> Result; async fn get_delegator( &self, - version: &Option, + event: &Option, stake_public_key: String, ) -> Result; } From 27e596a9f01fe14fcdefc4e1d7056e19eb858bdc Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 14:50:44 +0300 Subject: [PATCH 03/37] add get_voter endpoint --- src/cat-data-service/src/main.rs | 1 + src/cat-data-service/src/poem_types/mod.rs | 12 +++ .../src/poem_types/registration.rs | 73 +++++++++++++++++++ .../src/service/api/health/mod.rs | 19 ----- src/cat-data-service/src/service/api/mod.rs | 24 ++++-- .../src/service/api/registration/mod.rs | 30 ++++++++ .../api/registration/voter_info_get.rs | 23 ++++++ .../src/service/common/mod.rs | 4 +- .../src/service/common/responses/mod.rs | 6 +- .../src/service/common/responses/resp_2xx.rs | 2 +- .../src/service/common/responses/resp_4xx.rs | 1 + .../src/service/common/responses/resp_5xx.rs | 1 - .../src/service/common/tags.rs | 4 +- src/cat-data-service/src/types/mod.rs | 1 - 14 files changed, 165 insertions(+), 36 deletions(-) create mode 100644 src/cat-data-service/src/poem_types/mod.rs create mode 100644 src/cat-data-service/src/poem_types/registration.rs create mode 100644 src/cat-data-service/src/service/api/registration/mod.rs create mode 100644 src/cat-data-service/src/service/api/registration/voter_info_get.rs diff --git a/src/cat-data-service/src/main.rs b/src/cat-data-service/src/main.rs index c80ff4182a..5ea4c5bb8d 100644 --- a/src/cat-data-service/src/main.rs +++ b/src/cat-data-service/src/main.rs @@ -3,6 +3,7 @@ use clap::Parser; mod cli; mod legacy_service; mod logger; +mod poem_types; mod service; mod settings; mod state; diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs new file mode 100644 index 0000000000..34f7f31751 --- /dev/null +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -0,0 +1,12 @@ +use chrono::{DateTime, Utc}; +use serde::Serializer; + +pub mod registration; + +#[allow(dead_code)] +pub fn serialize_datetime_as_rfc3339( + time: &DateTime, + serializer: S, +) -> Result { + serializer.serialize_str(&time.to_rfc3339()) +} diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs new file mode 100644 index 0000000000..95e5fe6965 --- /dev/null +++ b/src/cat-data-service/src/poem_types/registration.rs @@ -0,0 +1,73 @@ +use poem_openapi::{NewType, Object}; +use serde::Deserialize; + +/// A Voting Key. +#[derive(NewType, Deserialize)] +pub struct VotingKey(pub String); + +/// Voter Group ID. +/// `direct` = Direct voter. +/// `rep` = Delegated Representative. +#[derive(NewType)] +pub struct VoterGroupId(pub String); + +impl From for VoterGroupId { + fn from(value: event_db::types::registration::VoterGroupId) -> Self { + Self(value.0) + } +} + +/// Voter Info +#[derive(Object)] +pub struct VoterInfo { + /// Voter's voting power. + /// This is the true voting power, subject to minimum voting power and max cap. + voting_power: i64, + voting_group: VoterGroupId, + /// Total voting power delegated to this voter. + /// This is not capped and not subject to minimum voting power. + delegations_power: i64, + /// Number of registration which delegated to this voter. + delegations_count: i64, + /// Voting power's share of the total voting power. + /// Can be used to gauge potential voting power saturation. + /// This value is NOT saturated however, and gives the raw share of total registered voting power. + voting_power_saturation: f64, + #[oai(skip_serializing_if = "Option::is_none")] + /// List of stake public key addresses which delegated to this voting key. + delegator_addresses: Option>, +} + +impl From for VoterInfo { + fn from(value: event_db::types::registration::VoterInfo) -> Self { + Self { + voting_power: value.voting_power, + voting_group: value.voting_group.into(), + delegations_power: value.delegations_power, + delegations_count: value.delegations_count, + voting_power_saturation: value.voting_power_saturation, + delegator_addresses: value.delegator_addresses, + } + } +} + +/// Voter +#[derive(Object)] +pub struct Voter { + voter_info: VoterInfo, + // #[oai(serialize_with = "serialize_datetime_as_rfc3339")] + // as_at: DateTime, + // #[oai(serialize_with = "serialize_datetime_as_rfc3339")] + // last_updated: DateTime, + #[oai(rename = "final")] + is_final: bool, +} + +impl From for Voter { + fn from(value: event_db::types::registration::Voter) -> Self { + Self { + voter_info: value.voter_info.into(), + is_final: value.is_final, + } + } +} diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 1ad58bfbb0..1c97486455 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -15,12 +15,6 @@ impl HealthApi { /// This endpoint is used to determine if the service has started properly /// and is able to serve requests. /// - /// ## Responses - /// - /// * 204 No Content - Service is Started and can serve requests. - /// * 500 Server Error - If anything within this function fails unexpectedly. - /// * 503 Service Unavailable - Service has not started, do not send other requests yet. - /// /// ## Note /// /// *This endpoint is for internal use of the service deployment infrastructure. @@ -35,13 +29,6 @@ impl HealthApi { /// /// This endpoint is used to determine if the service is ready and able to serve requests. /// - /// ## Responses - /// - /// * 204 No Content - Service is Ready and can serve requests. - /// * 500 Server Error - If anything within this function fails unexpectedly. - /// * 503 Service Unavailable - Service is not ready, requests to other - /// endpoints should not be sent until the service becomes ready. - /// /// ## Note /// /// *This endpoint is for internal use of the service deployment infrastructure. @@ -56,12 +43,6 @@ impl HealthApi { /// /// This endpoint is used to determine if the service is live. /// - /// ## Responses - /// - /// * 204 No Content - Service is Live and can serve requests. - /// * 500 Server Error - If anything within this function fails unexpectedly. - /// * 503 Service Unavailable - Service is not Live. It may need to be restarted. - /// /// ## Note /// /// *This endpoint is for internal use of the service deployment infrastructure. diff --git a/src/cat-data-service/src/service/api/mod.rs b/src/cat-data-service/src/service/api/mod.rs index 51eaa0b46d..d715234210 100644 --- a/src/cat-data-service/src/service/api/mod.rs +++ b/src/cat-data-service/src/service/api/mod.rs @@ -5,9 +5,11 @@ use crate::settings::API_URL_PREFIX; use health::HealthApi; use poem_openapi::{ContactObject, LicenseObject, OpenApiService, ServerObject}; +use registration::RegistrationApi; use test_endpoints::TestApi; mod health; +mod registration; mod test_endpoints; /// The name of the API @@ -54,14 +56,20 @@ const TERMS_OF_SERVICE: &str = "https://github.com/input-output-hk/catalyst-core/blob/main/book/src/98_CODE_OF_CONDUCT.md"; /// Create the OpenAPI definition -pub(crate) fn mk_api(hosts: Vec) -> OpenApiService<(TestApi, HealthApi), ()> { - let mut service = OpenApiService::new((TestApi, HealthApi), API_TITLE, API_VERSION) - .contact(get_api_contact()) - .description(API_DESCRIPTION) - .license(get_api_license()) - .summary(API_SUMMARY) - .terms_of_service(TERMS_OF_SERVICE) - .url_prefix(API_URL_PREFIX.as_str()); +pub(crate) fn mk_api( + hosts: Vec, +) -> OpenApiService<(TestApi, HealthApi, RegistrationApi), ()> { + let mut service = OpenApiService::new( + (TestApi, HealthApi, RegistrationApi), + API_TITLE, + API_VERSION, + ) + .contact(get_api_contact()) + .description(API_DESCRIPTION) + .license(get_api_license()) + .summary(API_SUMMARY) + .terms_of_service(TERMS_OF_SERVICE) + .url_prefix(API_URL_PREFIX.as_str()); // Add all the hosts where this API should be reachable. for host in hosts { diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs new file mode 100644 index 0000000000..d89f70f477 --- /dev/null +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -0,0 +1,30 @@ +use crate::{poem_types::registration::VotingKey, service::common::tags::ApiTags, state::State}; +use poem::web::{Data, Path}; +use poem_openapi::OpenApi; +use std::sync::Arc; + +mod voter_info_get; + +pub struct RegistrationApi; + +#[OpenApi(prefix_path = "/registration", tag = "ApiTags::Registration")] +impl RegistrationApi { + #[oai( + path = "/voter/:voting_key", + method = "get", + operation_id = "getVoterInfo" + )] + /// Voter's info + /// + /// Get voter's registration and voting power by their voting key. + /// If the `event_id` query parameter is omitted, then the latest voting power is retrieved. + /// If the `with_delegators` query parameter is ommitted, then `delegator_addresses` field of `VoterInfo` type does not provided. + /// + async fn get_voter_info( + &self, + pool: Data<&Arc>, + path: Path, + ) -> voter_info_get::AllResponses { + voter_info_get::endpoint(pool.0, path.0).await + } +} diff --git a/src/cat-data-service/src/service/api/registration/voter_info_get.rs b/src/cat-data-service/src/service/api/registration/voter_info_get.rs new file mode 100644 index 0000000000..c1911d1b94 --- /dev/null +++ b/src/cat-data-service/src/service/api/registration/voter_info_get.rs @@ -0,0 +1,23 @@ +use crate::poem_types::registration::{Voter, VotingKey}; +use crate::service::common::responses::resp_2xx::OK; +use crate::service::common::responses::resp_4xx::NotFound; +use crate::service::common::responses::resp_5xx::ServerError; +use crate::state::State; +use poem_extensions::response; +use poem_extensions::UniResponse::{T200, T404, T500}; +use poem_openapi::payload::Json; + +pub type AllResponses = response! { + 200: OK>, + 404: NotFound, + 500: ServerError, +}; + +pub async fn endpoint(state: &State, voting_key: VotingKey) -> AllResponses { + let voter = state.event_db.get_voter(&None, voting_key.0, false).await; + match voter { + Ok(voter) => T200(OK(Json(voter.into()))), + Err(event_db::error::Error::NotFound(_)) => T404(NotFound), + Err(err) => T500(ServerError::new(Some(err.to_string()))), + } +} diff --git a/src/cat-data-service/src/service/common/mod.rs b/src/cat-data-service/src/service/common/mod.rs index 22faeddab7..70578205ad 100644 --- a/src/cat-data-service/src/service/common/mod.rs +++ b/src/cat-data-service/src/service/common/mod.rs @@ -1,5 +1,5 @@ //! Define common and reusable api components here. //! these components should be structured into their own sub modules. //! -pub(crate) mod responses; -pub(crate) mod tags; +pub mod responses; +pub mod tags; diff --git a/src/cat-data-service/src/service/common/responses/mod.rs b/src/cat-data-service/src/service/common/responses/mod.rs index 4c3fa4d191..a73482f289 100644 --- a/src/cat-data-service/src/service/common/responses/mod.rs +++ b/src/cat-data-service/src/service/common/responses/mod.rs @@ -1,6 +1,6 @@ //! Generic Responses are all contained in their own modules, grouped by response codes. //! -pub(crate) mod resp_2xx; -pub(crate) mod resp_4xx; -pub(crate) mod resp_5xx; +pub mod resp_2xx; +pub mod resp_4xx; +pub mod resp_5xx; diff --git a/src/cat-data-service/src/service/common/responses/resp_2xx.rs b/src/cat-data-service/src/service/common/responses/resp_2xx.rs index 895fae4bf5..34b3dd80c7 100644 --- a/src/cat-data-service/src/service/common/responses/resp_2xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_2xx.rs @@ -7,7 +7,7 @@ use poem_openapi::payload::Payload; #[derive(OneResponse)] #[oai(status = 200)] -pub struct OK(T); +pub struct OK(pub T); #[derive(OneResponse)] #[oai(status = 204)] diff --git a/src/cat-data-service/src/service/common/responses/resp_4xx.rs b/src/cat-data-service/src/service/common/responses/resp_4xx.rs index d396ad5f1a..05f30f931e 100644 --- a/src/cat-data-service/src/service/common/responses/resp_4xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_4xx.rs @@ -25,6 +25,7 @@ pub struct Forbidden; #[derive(OneResponse)] #[oai(status = 404)] +/// ## Content not found pub struct NotFound; #[derive(OneResponse)] diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index a2c0e69816..7233aa000b 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -14,7 +14,6 @@ use uuid::Uuid; #[derive(Debug, Object)] #[oai(example, skip_serializing_if_is_none)] /// Response payload to a Bad request. -/*pub(crate)*/ struct ServerErrorPayload { /// Unique ID of this Server Error so that it can be located easily for debugging. id: Uuid, diff --git a/src/cat-data-service/src/service/common/tags.rs b/src/cat-data-service/src/service/common/tags.rs index 33777bd329..2543752c0d 100644 --- a/src/cat-data-service/src/service/common/tags.rs +++ b/src/cat-data-service/src/service/common/tags.rs @@ -3,9 +3,11 @@ use poem_openapi::Tags; #[derive(Tags)] -pub(crate) enum ApiTags { +pub enum ApiTags { // Health Endpoints Health, + // Information relating to Voter Registration, Delegations and Calculated Voting Power. + Registration, // Test Endpoints (Not part of the API) Test, TestTag2, diff --git a/src/cat-data-service/src/types/mod.rs b/src/cat-data-service/src/types/mod.rs index ac282bbb51..2f1f0a7ca8 100644 --- a/src/cat-data-service/src/types/mod.rs +++ b/src/cat-data-service/src/types/mod.rs @@ -38,7 +38,6 @@ pub fn serialize_datetime_as_rfc3339( serializer.serialize_str(&time.to_rfc3339()) } -#[allow(dead_code)] pub fn serialize_option_datetime_as_rfc3339( time: &Option>, serializer: S, From 98fa4e00ae1f58df6df26da27acd5b74a116100a Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 16:09:00 +0300 Subject: [PATCH 04/37] update --- Cargo.lock | 1 + src/cat-data-service/Cargo.toml | 3 +- src/cat-data-service/src/poem_types/mod.rs | 11 ---- .../src/poem_types/registration.rs | 19 +++--- .../src/service/api/health/mod.rs | 28 ++++++-- src/cat-data-service/src/service/api/mod.rs | 12 ---- .../src/service/api/registration/mod.rs | 66 ++++++++++++++++--- .../api/registration/voter_info_get.rs | 23 ------- .../src/service/poem_service.rs | 19 ++++-- 9 files changed, 107 insertions(+), 75 deletions(-) delete mode 100644 src/cat-data-service/src/service/api/registration/voter_info_get.rs diff --git a/Cargo.lock b/Cargo.lock index e453dfa7d7..fdc762adcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5561,6 +5561,7 @@ checksum = "ebc9663e1e8909b1dbd47bc99314f0b876c26f9194543e58cdfbdc942d821ed3" dependencies = [ "base64 0.21.0", "bytes 1.4.0", + "chrono", "derive_more", "futures-util", "indexmap 2.0.0", diff --git a/src/cat-data-service/Cargo.toml b/src/cat-data-service/Cargo.toml index 1cf9298b0f..1708df6846 100644 --- a/src/cat-data-service/Cargo.toml +++ b/src/cat-data-service/Cargo.toml @@ -38,7 +38,8 @@ poem-openapi = { version = "3.0.4", features = [ "redoc", "swagger-ui", "uuid", - "url" + "url", + "chrono", ] } poem-extensions = { version = "0.7.2" } diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs index 34f7f31751..038a1c755f 100644 --- a/src/cat-data-service/src/poem_types/mod.rs +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -1,12 +1 @@ -use chrono::{DateTime, Utc}; -use serde::Serializer; - pub mod registration; - -#[allow(dead_code)] -pub fn serialize_datetime_as_rfc3339( - time: &DateTime, - serializer: S, -) -> Result { - serializer.serialize_str(&time.to_rfc3339()) -} diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs index 95e5fe6965..b07addfb3c 100644 --- a/src/cat-data-service/src/poem_types/registration.rs +++ b/src/cat-data-service/src/poem_types/registration.rs @@ -1,14 +1,15 @@ +use chrono::{DateTime, Utc}; use poem_openapi::{NewType, Object}; use serde::Deserialize; -/// A Voting Key. #[derive(NewType, Deserialize)] pub struct VotingKey(pub String); +#[derive(NewType)] /// Voter Group ID. /// `direct` = Direct voter. /// `rep` = Delegated Representative. -#[derive(NewType)] +#[oai(external_docs = "Voter Group ID.")] pub struct VoterGroupId(pub String); impl From for VoterGroupId { @@ -17,8 +18,8 @@ impl From for VoterGroupId { } } -/// Voter Info #[derive(Object)] +// Voter Info pub struct VoterInfo { /// Voter's voting power. /// This is the true voting power, subject to minimum voting power and max cap. @@ -51,14 +52,14 @@ impl From for VoterInfo { } } -/// Voter #[derive(Object)] +/// Voter pub struct Voter { voter_info: VoterInfo, - // #[oai(serialize_with = "serialize_datetime_as_rfc3339")] - // as_at: DateTime, - // #[oai(serialize_with = "serialize_datetime_as_rfc3339")] - // last_updated: DateTime, + /// Date and time the latest snapshot represents. + as_at: DateTime, + /// Date and time for the latest update to this snapshot information. + last_updated: DateTime, #[oai(rename = "final")] is_final: bool, } @@ -67,6 +68,8 @@ impl From for Voter { fn from(value: event_db::types::registration::Voter) -> Self { Self { voter_info: value.voter_info.into(), + as_at: value.as_at, + last_updated: value.last_updated, is_final: value.is_final, } } diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 1c97486455..0efe22db35 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -53,23 +53,39 @@ impl HealthApi { } } +/// Need to setup and run a test event db instance +/// To do it you can use the following commands: +/// Prepare docker images +/// ``` +/// earthly ./containers/event-db-migrations+docker --data=test +/// ``` +/// Run event-db container +/// ``` +/// docker-compose -f src/event-db/docker-compose.yml up migrations +/// ``` +/// Also need establish `EVENT_DB_URL` env variable with the following value +/// ``` +/// EVENT_DB_URL="postgres://catalyst-event-dev:CHANGE_ME@localhost/CatalystEventDev" +/// ``` +/// https://github.com/input-output-hk/catalyst-core/tree/main/src/event-db/Readme.md #[cfg(test)] mod tests { - use super::*; - use crate::service::api::tests::mk_test_app; + use crate::{service::poem_service::tests::mk_test_app, state::State}; use poem::http::StatusCode; + use std::sync::Arc; #[tokio::test] async fn health_test() { - let app = mk_test_app(HealthApi); + let state = Arc::new(State::new(None).await.unwrap()); + let app = mk_test_app(state); - let resp = app.get("/health/started").send().await; + let resp = app.get("/api/health/started").send().await; resp.assert_status(StatusCode::NO_CONTENT); - let resp = app.get("/health/ready").send().await; + let resp = app.get("/api/health/ready").send().await; resp.assert_status(StatusCode::NO_CONTENT); - let resp = app.get("/health/live").send().await; + let resp = app.get("/api/health/live").send().await; resp.assert_status(StatusCode::NO_CONTENT); } } diff --git a/src/cat-data-service/src/service/api/mod.rs b/src/cat-data-service/src/service/api/mod.rs index d715234210..2238f6c499 100644 --- a/src/cat-data-service/src/service/api/mod.rs +++ b/src/cat-data-service/src/service/api/mod.rs @@ -78,15 +78,3 @@ pub(crate) fn mk_api( service } - -#[cfg(test)] -mod tests { - use poem::{test::TestClient, Route}; - use poem_openapi::{OpenApi, OpenApiService}; - - pub fn mk_test_app(api: Api) -> TestClient { - let service = OpenApiService::new(api, "Test API", "0.1.0"); - let app = Route::new().nest("/", service); - TestClient::new(app) - } -} diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index d89f70f477..253c4051d7 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -1,10 +1,14 @@ -use crate::{poem_types::registration::VotingKey, service::common::tags::ApiTags, state::State}; -use poem::web::{Data, Path}; -use poem_openapi::OpenApi; +use crate::poem_types::registration::{Voter, VotingKey}; +use crate::service::common::responses::resp_2xx::OK; +use crate::service::common::responses::resp_4xx::NotFound; +use crate::service::common::responses::resp_5xx::ServerError; +use crate::{service::common::tags::ApiTags, state::State}; +use poem::web::Data; +use poem_extensions::response; +use poem_extensions::UniResponse::{T200, T404, T500}; +use poem_openapi::{param::Path, payload::Json, OpenApi}; use std::sync::Arc; -mod voter_info_get; - pub struct RegistrationApi; #[OpenApi(prefix_path = "/registration", tag = "ApiTags::Registration")] @@ -23,8 +27,54 @@ impl RegistrationApi { async fn get_voter_info( &self, pool: Data<&Arc>, - path: Path, - ) -> voter_info_get::AllResponses { - voter_info_get::endpoint(pool.0, path.0).await + voting_key: Path, + ) -> response! { + 200: OK>, + 404: NotFound, + 500: ServerError, + } { + let voter = pool.event_db.get_voter(&None, voting_key.0 .0, false).await; + match voter { + Ok(voter) => T200(OK(Json(voter.into()))), + Err(event_db::error::Error::NotFound(_)) => T404(NotFound), + Err(err) => T500(ServerError::new(Some(err.to_string()))), + } + } +} + +/// Need to setup and run a test event db instance +/// To do it you can use the following commands: +/// Prepare docker images +/// ``` +/// earthly ./containers/event-db-migrations+docker --data=test +/// ``` +/// Run event-db container +/// ``` +/// docker-compose -f src/event-db/docker-compose.yml up migrations +/// ``` +/// Also need establish `EVENT_DB_URL` env variable with the following value +/// ``` +/// EVENT_DB_URL="postgres://catalyst-event-dev:CHANGE_ME@localhost/CatalystEventDev" +/// ``` +/// https://github.com/input-output-hk/catalyst-core/tree/main/src/event-db/Readme.md +#[cfg(test)] +mod tests { + use crate::{service::poem_service::tests::mk_test_app, state::State}; + use poem::http::StatusCode; + use std::sync::Arc; + + #[tokio::test] + async fn voter_test() { + let state = Arc::new(State::new(None).await.unwrap()); + let app = mk_test_app(state); + + let resp = app.get("/api/health/started").send().await; + resp.assert_status(StatusCode::NO_CONTENT); + + let resp = app.get("/api/health/ready").send().await; + resp.assert_status(StatusCode::NO_CONTENT); + + let resp = app.get("/api/health/live").send().await; + resp.assert_status(StatusCode::NO_CONTENT); } } diff --git a/src/cat-data-service/src/service/api/registration/voter_info_get.rs b/src/cat-data-service/src/service/api/registration/voter_info_get.rs deleted file mode 100644 index c1911d1b94..0000000000 --- a/src/cat-data-service/src/service/api/registration/voter_info_get.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::poem_types::registration::{Voter, VotingKey}; -use crate::service::common::responses::resp_2xx::OK; -use crate::service::common::responses::resp_4xx::NotFound; -use crate::service::common::responses::resp_5xx::ServerError; -use crate::state::State; -use poem_extensions::response; -use poem_extensions::UniResponse::{T200, T404, T500}; -use poem_openapi::payload::Json; - -pub type AllResponses = response! { - 200: OK>, - 404: NotFound, - 500: ServerError, -}; - -pub async fn endpoint(state: &State, voting_key: VotingKey) -> AllResponses { - let voter = state.event_db.get_voter(&None, voting_key.0, false).await; - match voter { - Ok(voter) => T200(OK(Json(voter.into()))), - Err(event_db::error::Error::NotFound(_)) => T404(NotFound), - Err(err) => T500(ServerError::new(Some(err.to_string()))), - } -} diff --git a/src/cat-data-service/src/service/poem_service.rs b/src/cat-data-service/src/service/poem_service.rs index c61154be8a..e3de4a4b0c 100644 --- a/src/cat-data-service/src/service/poem_service.rs +++ b/src/cat-data-service/src/service/poem_service.rs @@ -16,16 +16,12 @@ use poem::endpoint::PrometheusExporter; use poem::listener::TcpListener; use poem::middleware::{CatchPanic, Compression, Cors}; use poem::web::CompressionLevel; -use poem::{EndpointExt, IntoEndpoint, Route}; +use poem::{Endpoint, EndpointExt, Route}; use std::net::SocketAddr; use std::sync::Arc; /// This exists to allow us to add extra routes to the service for testing purposes. -pub(crate) fn mk_app( - hosts: Vec, - base_route: Option, - state: Arc, -) -> impl IntoEndpoint { +pub fn mk_app(hosts: Vec, base_route: Option, state: Arc) -> impl Endpoint { // Get the base route if defined, or a new route if not. let base_route = match base_route { Some(route) => route, @@ -83,3 +79,14 @@ pub async fn run(addr: &SocketAddr, state: Arc) -> Result<(), Error> { .await .map_err(Error::Io) } + +#[cfg(test)] +pub mod tests { + use super::*; + use poem::test::TestClient; + + pub fn mk_test_app(state: Arc) -> TestClient { + let app = mk_app(vec![], None, state); + TestClient::new(app) + } +} From ba891e3a0970a86e2487d920771a2c8fcea16186 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 16:31:21 +0300 Subject: [PATCH 05/37] fix --- src/cat-data-service/src/poem_types/registration.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs index b07addfb3c..143d27409c 100644 --- a/src/cat-data-service/src/poem_types/registration.rs +++ b/src/cat-data-service/src/poem_types/registration.rs @@ -5,11 +5,10 @@ use serde::Deserialize; #[derive(NewType, Deserialize)] pub struct VotingKey(pub String); -#[derive(NewType)] /// Voter Group ID. /// `direct` = Direct voter. /// `rep` = Delegated Representative. -#[oai(external_docs = "Voter Group ID.")] +#[derive(NewType)] pub struct VoterGroupId(pub String); impl From for VoterGroupId { @@ -18,8 +17,8 @@ impl From for VoterGroupId { } } +/// Voter Info #[derive(Object)] -// Voter Info pub struct VoterInfo { /// Voter's voting power. /// This is the true voting power, subject to minimum voting power and max cap. @@ -34,7 +33,7 @@ pub struct VoterInfo { /// Can be used to gauge potential voting power saturation. /// This value is NOT saturated however, and gives the raw share of total registered voting power. voting_power_saturation: f64, - #[oai(skip_serializing_if = "Option::is_none")] + #[oai(skip_serializing_if_is_none = true)] /// List of stake public key addresses which delegated to this voting key. delegator_addresses: Option>, } @@ -52,8 +51,8 @@ impl From for VoterInfo { } } -#[derive(Object)] /// Voter +#[derive(Object)] pub struct Voter { voter_info: VoterInfo, /// Date and time the latest snapshot represents. From d4ba8cb88240388565e61a017b1ed466ebe3a3ba Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 17:57:18 +0300 Subject: [PATCH 06/37] add tests --- src/cat-data-service/src/poem_types/event.rs | 11 ++ src/cat-data-service/src/poem_types/mod.rs | 1 + .../src/service/api/registration/mod.rs | 132 ++++++++++++++++-- 3 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 src/cat-data-service/src/poem_types/event.rs diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/poem_types/event.rs new file mode 100644 index 0000000000..4decb2b762 --- /dev/null +++ b/src/cat-data-service/src/poem_types/event.rs @@ -0,0 +1,11 @@ +use poem_openapi::NewType; +use serde::Deserialize; + +#[derive(NewType, Deserialize)] +pub struct EventId(pub i32); + +impl Into for EventId { + fn into(self) -> event_db::types::event::EventId { + event_db::types::event::EventId(self.0) + } +} diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs index 038a1c755f..f3c2d9d48a 100644 --- a/src/cat-data-service/src/poem_types/mod.rs +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -1 +1,2 @@ +pub mod event; pub mod registration; diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 253c4051d7..9b91288d77 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -1,3 +1,4 @@ +use crate::poem_types::event::EventId; use crate::poem_types::registration::{Voter, VotingKey}; use crate::service::common::responses::resp_2xx::OK; use crate::service::common::responses::resp_4xx::NotFound; @@ -6,7 +7,11 @@ use crate::{service::common::tags::ApiTags, state::State}; use poem::web::Data; use poem_extensions::response; use poem_extensions::UniResponse::{T200, T404, T500}; -use poem_openapi::{param::Path, payload::Json, OpenApi}; +use poem_openapi::{ + param::{Path, Query}, + payload::Json, + OpenApi, +}; use std::sync::Arc; pub struct RegistrationApi; @@ -27,13 +32,26 @@ impl RegistrationApi { async fn get_voter_info( &self, pool: Data<&Arc>, + /// A Voting Key. voting_key: Path, + /// The Event ID to return results for. + event_id: Query>, + /// Flag to include delegators list in the response. + #[oai(default)] + with_delegators: Query, ) -> response! { 200: OK>, 404: NotFound, 500: ServerError, } { - let voter = pool.event_db.get_voter(&None, voting_key.0 .0, false).await; + let voter = pool + .event_db + .get_voter( + &event_id.0.map(Into::into), + voting_key.0 .0, + *with_delegators, + ) + .await; match voter { Ok(voter) => T200(OK(Json(voter.into()))), Err(event_db::error::Error::NotFound(_)) => T404(NotFound), @@ -68,13 +86,111 @@ mod tests { let state = Arc::new(State::new(None).await.unwrap()); let app = mk_test_app(state); - let resp = app.get("/api/health/started").send().await; - resp.assert_status(StatusCode::NO_CONTENT); + let resp = app + .get(format!("/api/v1/registration/voter/{0}", "voting_key_1")) + .send() + .await; + resp.assert_status(StatusCode::OK); + resp.assert_json(serde_json::json!( + { + "voter_info": { + "voting_power": 250, + "voting_group": "rep", + "delegations_power": 250, + "delegations_count": 2, + "voting_power_saturation": 0.625, + }, + "as_at": "2022-03-31T12:00:00+00:00", + "last_updated": "2022-03-31T12:00:00+00:00", + "final": true + } + )) + .await; - let resp = app.get("/api/health/ready").send().await; - resp.assert_status(StatusCode::NO_CONTENT); + let resp = app + .get(format!( + "/api/v1/registration/voter/{0}?with_delegators=true", + "voting_key_1" + )) + .send() + .await; + resp.assert_status(StatusCode::OK); + resp.assert_json(serde_json::json!( + { + "voter_info": { + "voting_power": 250, + "voting_group": "rep", + "delegations_power": 250, + "delegations_count": 2, + "voting_power_saturation": 0.625, + "delegator_addresses": ["stake_public_key_1", "stake_public_key_2"] + }, + "as_at": "2022-03-31T12:00:00+00:00", + "last_updated": "2022-03-31T12:00:00+00:00", + "final": true + } + )) + .await; - let resp = app.get("/api/health/live").send().await; - resp.assert_status(StatusCode::NO_CONTENT); + let resp = app + .get(format!( + "/api/v1/registration/voter/{0}?event_id={1}", + "voting_key_1", 1 + )) + .send() + .await; + resp.assert_status(StatusCode::OK); + resp.assert_json(serde_json::json!( + { + "voter_info": { + "voting_power": 250, + "voting_group": "rep", + "delegations_power": 250, + "delegations_count": 2, + "voting_power_saturation": 0.625, + }, + "as_at": "2020-03-31T12:00:00+00:00", + "last_updated": "2020-03-31T12:00:00+00:00", + "final": true + } + )) + .await; + + let resp = app + .get(format!( + "/api/v1/registration/voter/{0}?event_id={1}&with_delegators=true", + "voting_key_1", 1 + )) + .send() + .await; + resp.assert_status(StatusCode::OK); + resp.assert_json(serde_json::json!( + { + "voter_info": { + "voting_power": 250, + "voting_group": "rep", + "delegations_power": 250, + "delegations_count": 2, + "voting_power_saturation": 0.625, + "delegator_addresses": ["stake_public_key_1", "stake_public_key_2"] + }, + "as_at": "2020-03-31T12:00:00+00:00", + "last_updated": "2020-03-31T12:00:00+00:00", + "final": true + } + )) + .await; + + let resp = app + .get(format!("/api/v1/registration/voter/{0}", "voting_key")) + .send() + .await; + resp.assert_status(StatusCode::NOT_FOUND); + + let resp = app + .get(format!("/api/v1/registration/voter/{0}", "voting_key")) + .send() + .await; + resp.assert_status(StatusCode::NOT_FOUND); } } From 7ecff290fd6c090fa6ad19e49f7717fb34a6e5c6 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 12 Sep 2023 18:42:07 +0300 Subject: [PATCH 07/37] fix clippy --- src/cat-data-service/src/poem_types/event.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/poem_types/event.rs index 4decb2b762..3dfb949734 100644 --- a/src/cat-data-service/src/poem_types/event.rs +++ b/src/cat-data-service/src/poem_types/event.rs @@ -4,8 +4,8 @@ use serde::Deserialize; #[derive(NewType, Deserialize)] pub struct EventId(pub i32); -impl Into for EventId { - fn into(self) -> event_db::types::event::EventId { - event_db::types::event::EventId(self.0) +impl From for event_db::types::event::EventId { + fn from(event_id: EventId) -> Self { + event_db::types::event::EventId(event_id.0) } } From d3147f9ca8d233dacd49dc855083bff8d197d956 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Thu, 14 Sep 2023 12:48:20 +0300 Subject: [PATCH 08/37] return back Responses sections --- .../src/service/api/health/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 0efe22db35..4a5c207599 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -20,6 +20,11 @@ impl HealthApi { /// *This endpoint is for internal use of the service deployment infrastructure. /// It may not be exposed publicly.* /// + /// ## Responses + /// + /// * 204 No Content - Service is OK and can keep running. + /// * 500 Server Error - If anything within this function fails unexpectedly. (Possible but unlikely) + /// * 503 Service Unavailable - Service is possibly not running reliably. async fn started_get(&self) -> started_get::AllResponses { started_get::endpoint().await } @@ -34,6 +39,11 @@ impl HealthApi { /// *This endpoint is for internal use of the service deployment infrastructure. /// It may not be exposed publicly.* /// + /// ## Responses + /// + /// * 204 No Content - Service is Ready to serve requests. + /// * 500 Server Error - If anything within this function fails unexpectedly. (Possible but unlikely) + /// * 503 Service Unavailable - Service is not ready, do not send other requests. async fn ready_get(&self) -> ready_get::AllResponses { ready_get::endpoint().await } @@ -48,6 +58,11 @@ impl HealthApi { /// *This endpoint is for internal use of the service deployment infrastructure. /// It may not be exposed publicly. Refer to []* /// + /// ## Responses + /// + /// * 204 No Content - Service is OK and can keep running. + /// * 500 Server Error - If anything within this function fails unexpectedly. (Possible but unlikely) + /// * 503 Service Unavailable - Service is possibly not running reliably. async fn live_get(&self) -> live_get::AllResponses { live_get::endpoint().await } From 6499a490d2e7ccc5a745983cad31c0c52228e51c Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Thu, 14 Sep 2023 23:33:38 +0300 Subject: [PATCH 09/37] update --- src/cat-data-service/src/main.rs | 1 - src/cat-data-service/src/poem_types/mod.rs | 2 - .../src/poem_types/registration.rs | 75 ------------------- .../src/service/api/registration/mod.rs | 18 +++-- .../src/service/common/mod.rs | 1 + .../common/objects/event_id.rs} | 10 ++- .../src/service/common/objects/mod.rs | 6 ++ .../common/objects/stake_public_key.rs | 12 +++ .../src/service/common/objects/voter.rs | 44 +++++++++++ .../service/common/objects/voter_group_id.rs | 30 ++++++++ .../src/service/common/objects/voter_info.rs | 70 +++++++++++++++++ .../src/service/common/objects/voting_key.rs | 12 +++ .../src/service/common/responses/mod.rs | 1 + .../src/service/common/responses/resp_5xx.rs | 20 ++++- .../src/service/utilities/catch_panic.rs | 4 +- 15 files changed, 216 insertions(+), 90 deletions(-) delete mode 100644 src/cat-data-service/src/poem_types/mod.rs delete mode 100644 src/cat-data-service/src/poem_types/registration.rs rename src/cat-data-service/src/{poem_types/event.rs => service/common/objects/event_id.rs} (56%) create mode 100644 src/cat-data-service/src/service/common/objects/stake_public_key.rs create mode 100644 src/cat-data-service/src/service/common/objects/voter.rs create mode 100644 src/cat-data-service/src/service/common/objects/voter_group_id.rs create mode 100644 src/cat-data-service/src/service/common/objects/voter_info.rs create mode 100644 src/cat-data-service/src/service/common/objects/voting_key.rs diff --git a/src/cat-data-service/src/main.rs b/src/cat-data-service/src/main.rs index 5ea4c5bb8d..c80ff4182a 100644 --- a/src/cat-data-service/src/main.rs +++ b/src/cat-data-service/src/main.rs @@ -3,7 +3,6 @@ use clap::Parser; mod cli; mod legacy_service; mod logger; -mod poem_types; mod service; mod settings; mod state; diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs deleted file mode 100644 index f3c2d9d48a..0000000000 --- a/src/cat-data-service/src/poem_types/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod event; -pub mod registration; diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs deleted file mode 100644 index 143d27409c..0000000000 --- a/src/cat-data-service/src/poem_types/registration.rs +++ /dev/null @@ -1,75 +0,0 @@ -use chrono::{DateTime, Utc}; -use poem_openapi::{NewType, Object}; -use serde::Deserialize; - -#[derive(NewType, Deserialize)] -pub struct VotingKey(pub String); - -/// Voter Group ID. -/// `direct` = Direct voter. -/// `rep` = Delegated Representative. -#[derive(NewType)] -pub struct VoterGroupId(pub String); - -impl From for VoterGroupId { - fn from(value: event_db::types::registration::VoterGroupId) -> Self { - Self(value.0) - } -} - -/// Voter Info -#[derive(Object)] -pub struct VoterInfo { - /// Voter's voting power. - /// This is the true voting power, subject to minimum voting power and max cap. - voting_power: i64, - voting_group: VoterGroupId, - /// Total voting power delegated to this voter. - /// This is not capped and not subject to minimum voting power. - delegations_power: i64, - /// Number of registration which delegated to this voter. - delegations_count: i64, - /// Voting power's share of the total voting power. - /// Can be used to gauge potential voting power saturation. - /// This value is NOT saturated however, and gives the raw share of total registered voting power. - voting_power_saturation: f64, - #[oai(skip_serializing_if_is_none = true)] - /// List of stake public key addresses which delegated to this voting key. - delegator_addresses: Option>, -} - -impl From for VoterInfo { - fn from(value: event_db::types::registration::VoterInfo) -> Self { - Self { - voting_power: value.voting_power, - voting_group: value.voting_group.into(), - delegations_power: value.delegations_power, - delegations_count: value.delegations_count, - voting_power_saturation: value.voting_power_saturation, - delegator_addresses: value.delegator_addresses, - } - } -} - -/// Voter -#[derive(Object)] -pub struct Voter { - voter_info: VoterInfo, - /// Date and time the latest snapshot represents. - as_at: DateTime, - /// Date and time for the latest update to this snapshot information. - last_updated: DateTime, - #[oai(rename = "final")] - is_final: bool, -} - -impl From for Voter { - fn from(value: event_db::types::registration::Voter) -> Self { - Self { - voter_info: value.voter_info.into(), - as_at: value.as_at, - last_updated: value.last_updated, - is_final: value.is_final, - } - } -} diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 9b91288d77..2b43f34e91 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -1,8 +1,7 @@ -use crate::poem_types::event::EventId; -use crate::poem_types::registration::{Voter, VotingKey}; +use crate::service::common::objects::{event_id::EventId, voter::Voter, voting_key::VotingKey}; use crate::service::common::responses::resp_2xx::OK; use crate::service::common::responses::resp_4xx::NotFound; -use crate::service::common::responses::resp_5xx::ServerError; +use crate::service::common::responses::resp_5xx::{server_error, ServerError}; use crate::{service::common::tags::ApiTags, state::State}; use poem::web::Data; use poem_extensions::response; @@ -32,10 +31,15 @@ impl RegistrationApi { async fn get_voter_info( &self, pool: Data<&Arc>, - /// A Voting Key. + + /// A Voting Key. + #[oai(validator(max_length = 64, min_length = 64, pattern = "[0-9a-f]{64}"))] voting_key: Path, + /// The Event ID to return results for. + #[oai(validator(minimum(value = "0")))] event_id: Query>, + /// Flag to include delegators list in the response. #[oai(default)] with_delegators: Query, @@ -52,8 +56,12 @@ impl RegistrationApi { *with_delegators, ) .await; + server_error!(""); match voter { - Ok(voter) => T200(OK(Json(voter.into()))), + Ok(voter) => match voter.try_into() { + Ok(voter) => T200(OK(Json(voter))), + Err(err) => T500(ServerError::new(Some(err.to_string()))), + }, Err(event_db::error::Error::NotFound(_)) => T404(NotFound), Err(err) => T500(ServerError::new(Some(err.to_string()))), } diff --git a/src/cat-data-service/src/service/common/mod.rs b/src/cat-data-service/src/service/common/mod.rs index 70578205ad..556654d15d 100644 --- a/src/cat-data-service/src/service/common/mod.rs +++ b/src/cat-data-service/src/service/common/mod.rs @@ -1,5 +1,6 @@ //! Define common and reusable api components here. //! these components should be structured into their own sub modules. //! +pub mod objects; pub mod responses; pub mod tags; diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/service/common/objects/event_id.rs similarity index 56% rename from src/cat-data-service/src/poem_types/event.rs rename to src/cat-data-service/src/service/common/objects/event_id.rs index 3dfb949734..f5fe23a3e3 100644 --- a/src/cat-data-service/src/poem_types/event.rs +++ b/src/cat-data-service/src/service/common/objects/event_id.rs @@ -1,9 +1,17 @@ -use poem_openapi::NewType; +use poem_openapi::{types::Example, NewType}; use serde::Deserialize; +/// The Numeric ID of a Voting Event #[derive(NewType, Deserialize)] +#[oai(example = true)] pub struct EventId(pub i32); +impl Example for EventId { + fn example() -> Self { + Self(11) + } +} + impl From for event_db::types::event::EventId { fn from(event_id: EventId) -> Self { event_db::types::event::EventId(event_id.0) diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 2a90a90f7b..80a2984f50 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1 +1,7 @@ //! This module contains common and re-usable objects. +pub mod event_id; +pub mod voting_key; +pub mod voter_group_id; +pub mod voter_info; +pub mod voter; +pub mod stake_public_key; \ No newline at end of file diff --git a/src/cat-data-service/src/service/common/objects/stake_public_key.rs b/src/cat-data-service/src/service/common/objects/stake_public_key.rs new file mode 100644 index 0000000000..956e2d6fef --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/stake_public_key.rs @@ -0,0 +1,12 @@ +use poem_openapi::{types::Example, NewType}; +use serde::Deserialize; + +#[derive(NewType, Deserialize)] +#[oai(example = true)] +pub struct StakePublicKey(pub String); + +impl Example for StakePublicKey { + fn example() -> Self { + Self("ad4b948699193634a39dd56f779a2951a24779ad52aa7916f6912b8ec4702cee".into()) + } +} diff --git a/src/cat-data-service/src/service/common/objects/voter.rs b/src/cat-data-service/src/service/common/objects/voter.rs new file mode 100644 index 0000000000..d824a7dd7b --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/voter.rs @@ -0,0 +1,44 @@ +use super::voter_info::VoterInfo; +use chrono::{DateTime, Utc}; +use poem_openapi::{types::Example, Object}; + +/// Voter +#[derive(Object)] +#[oai(example = true)] +pub struct Voter { + voter_info: VoterInfo, + + /// Date and time the latest snapshot represents. + as_at: DateTime, + + /// Date and time for the latest update to this snapshot information. + last_updated: DateTime, + + /// `True` - this is the final snapshot which will be used for voting power in the event. + /// `False` - this is an interim snapshot, subject to change. + #[oai(rename = "final")] + is_final: bool, +} + +impl Example for Voter { + fn example() -> Self { + Self { + voter_info: VoterInfo::example(), + as_at: Utc::now(), + last_updated: Utc::now(), + is_final: true, + } + } +} + +impl TryFrom for Voter { + type Error = String; + fn try_from(value: event_db::types::registration::Voter) -> Result { + Ok(Self { + voter_info: value.voter_info.try_into()?, + as_at: value.as_at, + last_updated: value.last_updated, + is_final: value.is_final, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/voter_group_id.rs b/src/cat-data-service/src/service/common/objects/voter_group_id.rs new file mode 100644 index 0000000000..ebf75a1e46 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/voter_group_id.rs @@ -0,0 +1,30 @@ +use poem_openapi::{types::Example, Enum}; + +/// Voter Group ID. +#[derive(Enum)] +pub enum VoterGroupId { + /// Delegated Representative. + #[oai(rename = "rep")] + Rep, + + /// Direct voter. + #[oai(rename = "direct")] + Direct, +} + +impl Example for VoterGroupId { + fn example() -> Self { + Self::Rep + } +} + +impl TryFrom for VoterGroupId { + type Error = String; + fn try_from(value: event_db::types::registration::VoterGroupId) -> Result { + match value.0.as_str() { + "rep" => Ok(Self::Rep), + "direct" => Ok(Self::Direct), + value => Err(format!("Unknown VoterGroupId: {}", value)), + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/voter_info.rs b/src/cat-data-service/src/service/common/objects/voter_info.rs new file mode 100644 index 0000000000..c1eea8ba39 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/voter_info.rs @@ -0,0 +1,70 @@ +use super::voter_group_id::VoterGroupId; +use poem_openapi::{types::Example, Object}; + +#[derive(Object)] +struct DelegatorAddress { + #[oai(validator(pattern = "[0-9a-f]{64}"))] + address: String, +} + +/// Voter Info +#[derive(Object)] +#[oai(example = true)] +pub struct VoterInfo { + /// Voter's voting power. + /// This is the true voting power, subject to minimum voting power and max cap. + #[oai(validator(minimum(value = "0")))] + voting_power: i64, + + voting_group: VoterGroupId, + + /// Total voting power delegated to this voter. + /// This is not capped and not subject to minimum voting power. + #[oai(validator(minimum(value = "0")))] + delegations_power: i64, + + /// Number of registration which delegated to this voter. + #[oai(validator(minimum(value = "0")))] + delegations_count: i64, + + /// Voting power's share of the total voting power. + /// Can be used to gauge potential voting power saturation. + /// This value is NOT saturated however, and gives the raw share of total registered voting power. + #[oai(validator(minimum(value = "0"), maximum(value = "100")))] + voting_power_saturation: f64, + + /// List of stake public key addresses which delegated to this voting key. + #[oai(skip_serializing_if_is_none = true)] + delegator_addresses: Option>, +} + +impl Example for VoterInfo { + fn example() -> Self { + Self { + voting_power: 0, + voting_group: VoterGroupId::example(), + delegations_power: 0, + delegations_count: 0, + voting_power_saturation: 0.0, + delegator_addresses: Some(vec![]), + } + } +} + +impl TryFrom for VoterInfo { + type Error = String; + fn try_from(value: event_db::types::registration::VoterInfo) -> Result { + Ok(Self { + voting_power: value.voting_power, + voting_group: value.voting_group.try_into()?, + delegations_power: value.delegations_power, + delegations_count: value.delegations_count, + voting_power_saturation: value.voting_power_saturation, + delegator_addresses: value.delegator_addresses.map(|val| { + val.into_iter() + .map(|address| DelegatorAddress { address }) + .collect() + }), + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/voting_key.rs b/src/cat-data-service/src/service/common/objects/voting_key.rs new file mode 100644 index 0000000000..560fa58678 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/voting_key.rs @@ -0,0 +1,12 @@ +use poem_openapi::{types::Example, NewType}; +use serde::Deserialize; + +#[derive(NewType, Deserialize)] +#[oai(example = true)] +pub struct VotingKey(pub String); + +impl Example for VotingKey { + fn example() -> Self { + Self("a6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663".into()) + } +} diff --git a/src/cat-data-service/src/service/common/responses/mod.rs b/src/cat-data-service/src/service/common/responses/mod.rs index a73482f289..bbb44304a1 100644 --- a/src/cat-data-service/src/service/common/responses/mod.rs +++ b/src/cat-data-service/src/service/common/responses/mod.rs @@ -1,5 +1,6 @@ //! Generic Responses are all contained in their own modules, grouped by response codes. //! +#[macro_use] pub mod resp_2xx; pub mod resp_4xx; diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index 7233aa000b..2d0a25b9b0 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -1,6 +1,5 @@ //! This module contains common and re-usable responses with a 4xx response code. -//! - +/// While using macro-vis lib, you will get the uncommon_codepoints warning, so you will probably want to place this in your crate root use crate::settings::generate_github_issue_url; use poem::error::ResponseError; use poem::http::StatusCode; @@ -11,6 +10,18 @@ use poem_openapi::Object; use url::Url; use uuid::Uuid; +/// Create a new Server Error Response. +/// Logging error message. +macro_rules! server_error { + ($($t:tt)*) => {{ + let error = ServerError::new(None); + let id = error.id(); + tracing::error!(id = format!("{id}"), $($t)*); + error + }}; +} +pub(crate) use server_error; + #[derive(Debug, Object)] #[oai(example, skip_serializing_if_is_none)] /// Response payload to a Bad request. @@ -54,7 +65,10 @@ pub struct ServerError(Json); impl ServerError { /// Create a new Server Error Response. pub fn new(msg: Option) -> Self { - Self(Json(ServerErrorPayload::new(msg))) + let msg = msg.unwrap_or( + "Internal Server Error. Please report the issue to the service owner.".to_string(), + ); + Self(Json(ServerErrorPayload::new(Some(msg)))) } /// Get the id of this Server Error. diff --git a/src/cat-data-service/src/service/utilities/catch_panic.rs b/src/cat-data-service/src/service/utilities/catch_panic.rs index 5935f57798..898c34104d 100644 --- a/src/cat-data-service/src/service/utilities/catch_panic.rs +++ b/src/cat-data-service/src/service/utilities/catch_panic.rs @@ -51,9 +51,7 @@ impl PanicHandler for ServicePanicHandler { /// Handle a panic. /// Log the panic and respond with a 500 with appropriate data. fn get_response(&self, err: Box) -> ServerError { - let response = ServerError::new(Some( - "Internal Server Error. Please report the issue to the service owner.".to_string(), - )); + let response = ServerError::new(None); // Get the unique identifier for this panic, so we can find it in the logs. let panic_identifier = response.id().to_string(); From ed2939dcf28e6965e4bb0160bf5af351b14e5151 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Thu, 14 Sep 2023 23:47:21 +0300 Subject: [PATCH 10/37] update --- src/cat-data-service/src/service/api/registration/mod.rs | 5 ++--- .../src/service/common/responses/resp_5xx.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 2b43f34e91..1379a99943 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -56,14 +56,13 @@ impl RegistrationApi { *with_delegators, ) .await; - server_error!(""); match voter { Ok(voter) => match voter.try_into() { Ok(voter) => T200(OK(Json(voter))), - Err(err) => T500(ServerError::new(Some(err.to_string()))), + Err(err) => T500(server_error!("{}", err.to_string())), }, Err(event_db::error::Error::NotFound(_)) => T404(NotFound), - Err(err) => T500(ServerError::new(Some(err.to_string()))), + Err(err) => T500(server_error!("{}", err.to_string())), } } } diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index 2d0a25b9b0..4b7856b155 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -14,9 +14,9 @@ use uuid::Uuid; /// Logging error message. macro_rules! server_error { ($($t:tt)*) => {{ - let error = ServerError::new(None); + let error = crate::service::common::responses::resp_5xx::ServerError::new(None); let id = error.id(); - tracing::error!(id = format!("{id}"), $($t)*); + tracing::error!(id = format!("{id}") ,$($t)*); error }}; } From b42867c530a5991c893d00d9936c8ec06085d357 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 10:28:35 +0300 Subject: [PATCH 11/37] fix visibility --- .../src/service/api/health/mod.rs | 2 +- .../src/service/api/registration/mod.rs | 2 +- .../src/service/common/objects/event_id.rs | 2 +- .../service/common/objects/stake_public_key.rs | 2 +- .../src/service/common/objects/voter.rs | 2 +- .../src/service/common/objects/voter_group_id.rs | 2 +- .../src/service/common/objects/voter_info.rs | 2 +- .../src/service/common/objects/voting_key.rs | 2 +- .../src/service/common/responses/resp_2xx.rs | 4 ++-- .../src/service/common/responses/resp_4xx.rs | 16 ++++++++-------- .../src/service/common/responses/resp_5xx.rs | 4 ++-- src/cat-data-service/src/service/common/tags.rs | 2 +- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 4a5c207599..353fc596ee 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -5,7 +5,7 @@ mod live_get; mod ready_get; mod started_get; -pub struct HealthApi; +pub(crate) struct HealthApi; #[OpenApi(prefix_path = "/health", tag = "ApiTags::Health")] impl HealthApi { diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 1379a99943..4a6f374015 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -13,7 +13,7 @@ use poem_openapi::{ }; use std::sync::Arc; -pub struct RegistrationApi; +pub(crate) struct RegistrationApi; #[OpenApi(prefix_path = "/registration", tag = "ApiTags::Registration")] impl RegistrationApi { diff --git a/src/cat-data-service/src/service/common/objects/event_id.rs b/src/cat-data-service/src/service/common/objects/event_id.rs index f5fe23a3e3..d6b153b808 100644 --- a/src/cat-data-service/src/service/common/objects/event_id.rs +++ b/src/cat-data-service/src/service/common/objects/event_id.rs @@ -4,7 +4,7 @@ use serde::Deserialize; /// The Numeric ID of a Voting Event #[derive(NewType, Deserialize)] #[oai(example = true)] -pub struct EventId(pub i32); +pub(crate) struct EventId(pub i32); impl Example for EventId { fn example() -> Self { diff --git a/src/cat-data-service/src/service/common/objects/stake_public_key.rs b/src/cat-data-service/src/service/common/objects/stake_public_key.rs index 956e2d6fef..ba0e4351e6 100644 --- a/src/cat-data-service/src/service/common/objects/stake_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/stake_public_key.rs @@ -3,7 +3,7 @@ use serde::Deserialize; #[derive(NewType, Deserialize)] #[oai(example = true)] -pub struct StakePublicKey(pub String); +pub(crate) struct StakePublicKey(pub String); impl Example for StakePublicKey { fn example() -> Self { diff --git a/src/cat-data-service/src/service/common/objects/voter.rs b/src/cat-data-service/src/service/common/objects/voter.rs index d824a7dd7b..945e08bf1b 100644 --- a/src/cat-data-service/src/service/common/objects/voter.rs +++ b/src/cat-data-service/src/service/common/objects/voter.rs @@ -5,7 +5,7 @@ use poem_openapi::{types::Example, Object}; /// Voter #[derive(Object)] #[oai(example = true)] -pub struct Voter { +pub(crate) struct Voter { voter_info: VoterInfo, /// Date and time the latest snapshot represents. diff --git a/src/cat-data-service/src/service/common/objects/voter_group_id.rs b/src/cat-data-service/src/service/common/objects/voter_group_id.rs index ebf75a1e46..5897ea31f7 100644 --- a/src/cat-data-service/src/service/common/objects/voter_group_id.rs +++ b/src/cat-data-service/src/service/common/objects/voter_group_id.rs @@ -2,7 +2,7 @@ use poem_openapi::{types::Example, Enum}; /// Voter Group ID. #[derive(Enum)] -pub enum VoterGroupId { +pub(crate) enum VoterGroupId { /// Delegated Representative. #[oai(rename = "rep")] Rep, diff --git a/src/cat-data-service/src/service/common/objects/voter_info.rs b/src/cat-data-service/src/service/common/objects/voter_info.rs index c1eea8ba39..ee059ef96e 100644 --- a/src/cat-data-service/src/service/common/objects/voter_info.rs +++ b/src/cat-data-service/src/service/common/objects/voter_info.rs @@ -10,7 +10,7 @@ struct DelegatorAddress { /// Voter Info #[derive(Object)] #[oai(example = true)] -pub struct VoterInfo { +pub(crate) struct VoterInfo { /// Voter's voting power. /// This is the true voting power, subject to minimum voting power and max cap. #[oai(validator(minimum(value = "0")))] diff --git a/src/cat-data-service/src/service/common/objects/voting_key.rs b/src/cat-data-service/src/service/common/objects/voting_key.rs index 560fa58678..2fc4defdb8 100644 --- a/src/cat-data-service/src/service/common/objects/voting_key.rs +++ b/src/cat-data-service/src/service/common/objects/voting_key.rs @@ -3,7 +3,7 @@ use serde::Deserialize; #[derive(NewType, Deserialize)] #[oai(example = true)] -pub struct VotingKey(pub String); +pub(crate) struct VotingKey(pub String); impl Example for VotingKey { fn example() -> Self { diff --git a/src/cat-data-service/src/service/common/responses/resp_2xx.rs b/src/cat-data-service/src/service/common/responses/resp_2xx.rs index 34b3dd80c7..b8d85471e8 100644 --- a/src/cat-data-service/src/service/common/responses/resp_2xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_2xx.rs @@ -7,7 +7,7 @@ use poem_openapi::payload::Payload; #[derive(OneResponse)] #[oai(status = 200)] -pub struct OK(pub T); +pub(crate) struct OK(pub T); #[derive(OneResponse)] #[oai(status = 204)] @@ -16,4 +16,4 @@ pub struct OK(pub T); /// The operation completed successfully, but there is no data to return. /// /// #### NO DATA BODY IS RETURNED FOR THIS RESPONSE -pub struct NoContent; +pub(crate) struct NoContent; diff --git a/src/cat-data-service/src/service/common/responses/resp_4xx.rs b/src/cat-data-service/src/service/common/responses/resp_4xx.rs index 05f30f931e..46b3871829 100644 --- a/src/cat-data-service/src/service/common/responses/resp_4xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_4xx.rs @@ -7,38 +7,38 @@ use poem_openapi::payload::{Payload, PlainText}; #[derive(OneResponse)] #[oai(status = 400)] -pub struct BadRequest(T); +pub(crate) struct BadRequest(T); #[derive(OneResponse)] #[oai(status = 400)] /// This error means that the request was malformed. /// It has failed to pass validation, as specified by the OpenAPI schema. -pub struct ApiValidationError(PlainText); +pub(crate) struct ApiValidationError(PlainText); #[derive(OneResponse)] #[oai(status = 401)] -pub struct Unauthorized; +pub(crate) struct Unauthorized; #[derive(OneResponse)] #[oai(status = 403)] -pub struct Forbidden; +pub(crate) struct Forbidden; #[derive(OneResponse)] #[oai(status = 404)] /// ## Content not found -pub struct NotFound; +pub(crate) struct NotFound; #[derive(OneResponse)] #[oai(status = 405)] -pub struct MethodNotAllowed; +pub(crate) struct MethodNotAllowed; #[derive(OneResponse)] #[oai(status = 406)] -pub struct NotAcceptable; +pub(crate) struct NotAcceptable; #[derive(OneResponse)] #[oai(status = 422)] /// Common automatically produced validation error for every endpoint. /// Is generated automatically when any of the OpenAPI validation rules fail. /// Can also be generated manually. -pub struct ValidationError; +pub(crate) struct ValidationError; diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index 4b7856b155..91ff87cb76 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -60,7 +60,7 @@ impl Example for ServerErrorPayload { /// An internal server error occurred. /// /// *The contents of this response should be reported to the projects issue tracker.* -pub struct ServerError(Json); +pub(crate) struct ServerError(Json); impl ServerError { /// Create a new Server Error Response. @@ -93,4 +93,4 @@ impl ResponseError for ServerError { /// or has become unavailable.* /// /// #### NO DATA BODY IS RETURNED FOR THIS RESPONSE -pub struct ServiceUnavailable; +pub(crate) struct ServiceUnavailable; diff --git a/src/cat-data-service/src/service/common/tags.rs b/src/cat-data-service/src/service/common/tags.rs index 2543752c0d..020d6e3944 100644 --- a/src/cat-data-service/src/service/common/tags.rs +++ b/src/cat-data-service/src/service/common/tags.rs @@ -3,7 +3,7 @@ use poem_openapi::Tags; #[derive(Tags)] -pub enum ApiTags { +pub(crate) enum ApiTags { // Health Endpoints Health, // Information relating to Voter Registration, Delegations and Calculated Voting Power. From bced403898736b46141a9067a6c8583dbcfd2b9b Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 11:11:23 +0300 Subject: [PATCH 12/37] fix --- src/cat-data-service/src/service/api/health/mod.rs | 13 +++++++------ .../src/service/common/objects/mod.rs | 12 ++++++------ .../src/service/common/responses/mod.rs | 6 +++--- .../src/service/common/responses/resp_5xx.rs | 4 ++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 353fc596ee..04022feeb2 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -22,9 +22,9 @@ impl HealthApi { /// /// ## Responses /// - /// * 204 No Content - Service is OK and can keep running. - /// * 500 Server Error - If anything within this function fails unexpectedly. (Possible but unlikely) - /// * 503 Service Unavailable - Service is possibly not running reliably. + /// * 204 No Content - Service is Started and can serve requests. + /// * 500 Server Error - If anything within this function fails unexpectedly. + /// * 503 Service Unavailable - Service has not started, do not send other requests yet. async fn started_get(&self) -> started_get::AllResponses { started_get::endpoint().await } @@ -41,9 +41,10 @@ impl HealthApi { /// /// ## Responses /// - /// * 204 No Content - Service is Ready to serve requests. - /// * 500 Server Error - If anything within this function fails unexpectedly. (Possible but unlikely) - /// * 503 Service Unavailable - Service is not ready, do not send other requests. + /// * 204 No Content - Service is Ready and can serve requests. + /// * 500 Server Error - If anything within this function fails unexpectedly. + /// * 503 Service Unavailable - Service is not ready, requests to other + /// endpoints should not be sent until the service becomes ready. async fn ready_get(&self) -> ready_get::AllResponses { ready_get::endpoint().await } diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 80a2984f50..60416ab207 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,7 +1,7 @@ //! This module contains common and re-usable objects. -pub mod event_id; -pub mod voting_key; -pub mod voter_group_id; -pub mod voter_info; -pub mod voter; -pub mod stake_public_key; \ No newline at end of file +pub(crate) mod event_id; +pub(crate) mod voting_key; +pub(crate) mod voter_group_id; +pub(crate) mod voter_info; +pub(crate) mod voter; +pub(crate) mod stake_public_key; \ No newline at end of file diff --git a/src/cat-data-service/src/service/common/responses/mod.rs b/src/cat-data-service/src/service/common/responses/mod.rs index bbb44304a1..f4cfd9f991 100644 --- a/src/cat-data-service/src/service/common/responses/mod.rs +++ b/src/cat-data-service/src/service/common/responses/mod.rs @@ -2,6 +2,6 @@ //! #[macro_use] -pub mod resp_2xx; -pub mod resp_4xx; -pub mod resp_5xx; +pub(crate) mod resp_2xx; +pub(crate) mod resp_4xx; +pub(crate) mod resp_5xx; diff --git a/src/cat-data-service/src/service/common/responses/resp_5xx.rs b/src/cat-data-service/src/service/common/responses/resp_5xx.rs index 91ff87cb76..e1cc08c32f 100644 --- a/src/cat-data-service/src/service/common/responses/resp_5xx.rs +++ b/src/cat-data-service/src/service/common/responses/resp_5xx.rs @@ -64,7 +64,7 @@ pub(crate) struct ServerError(Json); impl ServerError { /// Create a new Server Error Response. - pub fn new(msg: Option) -> Self { + pub(crate) fn new(msg: Option) -> Self { let msg = msg.unwrap_or( "Internal Server Error. Please report the issue to the service owner.".to_string(), ); @@ -72,7 +72,7 @@ impl ServerError { } /// Get the id of this Server Error. - pub fn id(&self) -> Uuid { + pub(crate) fn id(&self) -> Uuid { self.0.id } } From 6a8f3f4d5539ab77796b5ec437e49288241b1e59 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 11:15:33 +0300 Subject: [PATCH 13/37] update --- .../common/objects/delegator_address.rs | 22 +++++++++++++++++++ .../src/service/common/objects/mod.rs | 7 +++--- .../src/service/common/objects/voter_info.rs | 18 +++++---------- 3 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 src/cat-data-service/src/service/common/objects/delegator_address.rs diff --git a/src/cat-data-service/src/service/common/objects/delegator_address.rs b/src/cat-data-service/src/service/common/objects/delegator_address.rs new file mode 100644 index 0000000000..e9eb7e3e68 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/delegator_address.rs @@ -0,0 +1,22 @@ +use poem_openapi::{types::Example, Object}; + +#[derive(Object)] +pub(crate) struct DelegatorAddress { + #[oai(validator(pattern = "[0-9a-f]{64}"))] + address: String, +} + +impl From for DelegatorAddress { + fn from(address: String) -> Self { + Self { address } + } +} + +impl Example for DelegatorAddress { + fn example() -> Self { + Self { + address: "0xad4b948699193634a39dd56f779a2951a24779ad52aa7916f6912b8ec4702cee" + .to_string(), + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 60416ab207..efa71253fb 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,7 +1,8 @@ //! This module contains common and re-usable objects. +pub(crate) mod delegator_address; pub(crate) mod event_id; -pub(crate) mod voting_key; +pub(crate) mod stake_public_key; +pub(crate) mod voter; pub(crate) mod voter_group_id; pub(crate) mod voter_info; -pub(crate) mod voter; -pub(crate) mod stake_public_key; \ No newline at end of file +pub(crate) mod voting_key; diff --git a/src/cat-data-service/src/service/common/objects/voter_info.rs b/src/cat-data-service/src/service/common/objects/voter_info.rs index ee059ef96e..2970008eda 100644 --- a/src/cat-data-service/src/service/common/objects/voter_info.rs +++ b/src/cat-data-service/src/service/common/objects/voter_info.rs @@ -1,12 +1,6 @@ -use super::voter_group_id::VoterGroupId; +use super::{delegator_address::DelegatorAddress, voter_group_id::VoterGroupId}; use poem_openapi::{types::Example, Object}; -#[derive(Object)] -struct DelegatorAddress { - #[oai(validator(pattern = "[0-9a-f]{64}"))] - address: String, -} - /// Voter Info #[derive(Object)] #[oai(example = true)] @@ -46,7 +40,7 @@ impl Example for VoterInfo { delegations_power: 0, delegations_count: 0, voting_power_saturation: 0.0, - delegator_addresses: Some(vec![]), + delegator_addresses: Some(vec![DelegatorAddress::example()]), } } } @@ -60,11 +54,9 @@ impl TryFrom for VoterInfo { delegations_power: value.delegations_power, delegations_count: value.delegations_count, voting_power_saturation: value.voting_power_saturation, - delegator_addresses: value.delegator_addresses.map(|val| { - val.into_iter() - .map(|address| DelegatorAddress { address }) - .collect() - }), + delegator_addresses: value + .delegator_addresses + .map(|val| val.into_iter().map(Into::into).collect()), }) } } From aed00f9af41b4627d52f4606cc1329926a553c60 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 11:39:33 +0300 Subject: [PATCH 14/37] move axum types under the legacy_service module --- src/cat-data-service/src/legacy_service/mod.rs | 1 + .../src/{ => legacy_service}/types/ballot.rs | 0 .../src/{ => legacy_service}/types/event.rs | 0 .../src/{ => legacy_service}/types/jorm_mock.rs | 0 .../src/{ => legacy_service}/types/mod.rs | 0 .../src/{ => legacy_service}/types/objective.rs | 0 .../src/{ => legacy_service}/types/proposal.rs | 0 .../src/{ => legacy_service}/types/registration.rs | 0 .../src/{ => legacy_service}/types/review.rs | 0 .../src/{ => legacy_service}/types/search.rs | 0 .../src/{ => legacy_service}/types/vit_ss/challenge.rs | 0 .../src/{ => legacy_service}/types/vit_ss/fund.rs | 0 .../src/{ => legacy_service}/types/vit_ss/goal.rs | 0 .../src/{ => legacy_service}/types/vit_ss/group.rs | 0 .../src/{ => legacy_service}/types/vit_ss/mod.rs | 0 .../src/{ => legacy_service}/types/vit_ss/vote_plan.rs | 0 .../src/{ => legacy_service}/types/voting_status.rs | 0 src/cat-data-service/src/legacy_service/v0/fund.rs | 6 +++++- .../src/legacy_service/v1/event/ballots.rs | 6 +++++- src/cat-data-service/src/legacy_service/v1/event/mod.rs | 6 +++++- .../src/legacy_service/v1/event/objective/ballots.rs | 6 +++++- .../src/legacy_service/v1/event/objective/mod.rs | 3 +-- .../legacy_service/v1/event/objective/proposal/ballot.rs | 6 +++++- .../src/legacy_service/v1/event/objective/proposal/mod.rs | 3 +-- .../legacy_service/v1/event/objective/proposal/review.rs | 3 +-- .../src/legacy_service/v1/event/objective/review_type.rs | 3 +-- .../src/legacy_service/v1/jorm_mock/mod.rs | 6 ++++-- .../src/legacy_service/v1/registration.rs | 6 +++++- src/cat-data-service/src/legacy_service/v1/search.rs | 6 +++++- src/cat-data-service/src/main.rs | 1 - src/cat-data-service/src/state/jorm_mock.rs | 2 +- src/cat-data-service/src/state/mod.rs | 8 -------- 32 files changed, 45 insertions(+), 27 deletions(-) rename src/cat-data-service/src/{ => legacy_service}/types/ballot.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/event.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/jorm_mock.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/mod.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/objective.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/proposal.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/registration.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/review.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/search.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/challenge.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/fund.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/goal.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/group.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/mod.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/vit_ss/vote_plan.rs (100%) rename src/cat-data-service/src/{ => legacy_service}/types/voting_status.rs (100%) diff --git a/src/cat-data-service/src/legacy_service/mod.rs b/src/cat-data-service/src/legacy_service/mod.rs index cddb4259ca..6d61cbff90 100644 --- a/src/cat-data-service/src/legacy_service/mod.rs +++ b/src/cat-data-service/src/legacy_service/mod.rs @@ -17,6 +17,7 @@ use tokio::try_join; use tower_http::cors::{Any, CorsLayer}; mod health; +pub(crate) mod types; mod v0; mod v1; diff --git a/src/cat-data-service/src/types/ballot.rs b/src/cat-data-service/src/legacy_service/types/ballot.rs similarity index 100% rename from src/cat-data-service/src/types/ballot.rs rename to src/cat-data-service/src/legacy_service/types/ballot.rs diff --git a/src/cat-data-service/src/types/event.rs b/src/cat-data-service/src/legacy_service/types/event.rs similarity index 100% rename from src/cat-data-service/src/types/event.rs rename to src/cat-data-service/src/legacy_service/types/event.rs diff --git a/src/cat-data-service/src/types/jorm_mock.rs b/src/cat-data-service/src/legacy_service/types/jorm_mock.rs similarity index 100% rename from src/cat-data-service/src/types/jorm_mock.rs rename to src/cat-data-service/src/legacy_service/types/jorm_mock.rs diff --git a/src/cat-data-service/src/types/mod.rs b/src/cat-data-service/src/legacy_service/types/mod.rs similarity index 100% rename from src/cat-data-service/src/types/mod.rs rename to src/cat-data-service/src/legacy_service/types/mod.rs diff --git a/src/cat-data-service/src/types/objective.rs b/src/cat-data-service/src/legacy_service/types/objective.rs similarity index 100% rename from src/cat-data-service/src/types/objective.rs rename to src/cat-data-service/src/legacy_service/types/objective.rs diff --git a/src/cat-data-service/src/types/proposal.rs b/src/cat-data-service/src/legacy_service/types/proposal.rs similarity index 100% rename from src/cat-data-service/src/types/proposal.rs rename to src/cat-data-service/src/legacy_service/types/proposal.rs diff --git a/src/cat-data-service/src/types/registration.rs b/src/cat-data-service/src/legacy_service/types/registration.rs similarity index 100% rename from src/cat-data-service/src/types/registration.rs rename to src/cat-data-service/src/legacy_service/types/registration.rs diff --git a/src/cat-data-service/src/types/review.rs b/src/cat-data-service/src/legacy_service/types/review.rs similarity index 100% rename from src/cat-data-service/src/types/review.rs rename to src/cat-data-service/src/legacy_service/types/review.rs diff --git a/src/cat-data-service/src/types/search.rs b/src/cat-data-service/src/legacy_service/types/search.rs similarity index 100% rename from src/cat-data-service/src/types/search.rs rename to src/cat-data-service/src/legacy_service/types/search.rs diff --git a/src/cat-data-service/src/types/vit_ss/challenge.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/challenge.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/challenge.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/challenge.rs diff --git a/src/cat-data-service/src/types/vit_ss/fund.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/fund.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/fund.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/fund.rs diff --git a/src/cat-data-service/src/types/vit_ss/goal.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/goal.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/goal.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/goal.rs diff --git a/src/cat-data-service/src/types/vit_ss/group.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/group.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/group.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/group.rs diff --git a/src/cat-data-service/src/types/vit_ss/mod.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/mod.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/mod.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/mod.rs diff --git a/src/cat-data-service/src/types/vit_ss/vote_plan.rs b/src/cat-data-service/src/legacy_service/types/vit_ss/vote_plan.rs similarity index 100% rename from src/cat-data-service/src/types/vit_ss/vote_plan.rs rename to src/cat-data-service/src/legacy_service/types/vit_ss/vote_plan.rs diff --git a/src/cat-data-service/src/types/voting_status.rs b/src/cat-data-service/src/legacy_service/types/voting_status.rs similarity index 100% rename from src/cat-data-service/src/types/voting_status.rs rename to src/cat-data-service/src/legacy_service/types/voting_status.rs diff --git a/src/cat-data-service/src/legacy_service/v0/fund.rs b/src/cat-data-service/src/legacy_service/v0/fund.rs index f3146102c0..cb8006e20e 100644 --- a/src/cat-data-service/src/legacy_service/v0/fund.rs +++ b/src/cat-data-service/src/legacy_service/v0/fund.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{routing::get, Router}; use event_db::types::vit_ss::fund::FundWithNext; use std::sync::Arc; diff --git a/src/cat-data-service/src/legacy_service/v1/event/ballots.rs b/src/cat-data-service/src/legacy_service/v1/event/ballots.rs index 5120d84ce3..57afa96aeb 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/ballots.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/ballots.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{extract::Path, routing::get, Router}; use event_db::types::{ballot::ObjectiveBallots, event::EventId}; use std::sync::Arc; diff --git a/src/cat-data-service/src/legacy_service/v1/event/mod.rs b/src/cat-data-service/src/legacy_service/v1/event/mod.rs index 46441685c5..1fb8d8ce6a 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/mod.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/mod.rs @@ -1,5 +1,9 @@ use super::LimitOffset; -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{ extract::{Path, Query}, routing::get, diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/ballots.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/ballots.rs index 60e02638ee..23f68f7f51 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/ballots.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/ballots.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{extract::Path, routing::get, Router}; use event_db::types::{ballot::ProposalBallot, event::EventId, objective::ObjectiveId}; use std::sync::Arc; diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/mod.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/mod.rs index a40ffb719f..5792ced0de 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/mod.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/mod.rs @@ -1,8 +1,7 @@ use crate::{ - legacy_service::{handle_result, v1::LimitOffset}, + legacy_service::{handle_result, types::SerdeType, v1::LimitOffset}, service::Error, state::State, - types::SerdeType, }; use axum::{ extract::{Path, Query}, diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/ballot.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/ballot.rs index 665ab48494..91785a6442 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/ballot.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/ballot.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{extract::Path, routing::get, Router}; use event_db::types::{ ballot::Ballot, event::EventId, objective::ObjectiveId, proposal::ProposalId, diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/mod.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/mod.rs index 28c43a7287..f34eab01cb 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/mod.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/mod.rs @@ -1,8 +1,7 @@ use crate::{ - legacy_service::{handle_result, v1::LimitOffset}, + legacy_service::{handle_result, types::SerdeType, v1::LimitOffset}, service::Error, state::State, - types::SerdeType, }; use axum::{ extract::{Path, Query}, diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/review.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/review.rs index 79f1360b50..220315e223 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/review.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/proposal/review.rs @@ -1,8 +1,7 @@ use crate::{ - legacy_service::{handle_result, v1::LimitOffset}, + legacy_service::{handle_result, types::SerdeType, v1::LimitOffset}, service::Error, state::State, - types::SerdeType, }; use axum::{ extract::{Path, Query}, diff --git a/src/cat-data-service/src/legacy_service/v1/event/objective/review_type.rs b/src/cat-data-service/src/legacy_service/v1/event/objective/review_type.rs index dc89c5f4b7..d739042403 100644 --- a/src/cat-data-service/src/legacy_service/v1/event/objective/review_type.rs +++ b/src/cat-data-service/src/legacy_service/v1/event/objective/review_type.rs @@ -1,8 +1,7 @@ use crate::{ - legacy_service::{handle_result, v1::LimitOffset}, + legacy_service::{handle_result, types::SerdeType, v1::LimitOffset}, service::Error, state::State, - types::SerdeType, }; use axum::{ extract::{Path, Query}, diff --git a/src/cat-data-service/src/legacy_service/v1/jorm_mock/mod.rs b/src/cat-data-service/src/legacy_service/v1/jorm_mock/mod.rs index d3db8d8ed6..35c6464904 100644 --- a/src/cat-data-service/src/legacy_service/v1/jorm_mock/mod.rs +++ b/src/cat-data-service/src/legacy_service/v1/jorm_mock/mod.rs @@ -1,8 +1,10 @@ use crate::{ - legacy_service::handle_result, + legacy_service::{ + handle_result, + types::jorm_mock::{AccountId, AccountVote, Fragments, FragmentsProcessingSummary}, + }, service::Error, state::State, - types::jorm_mock::{AccountId, AccountVote, Fragments, FragmentsProcessingSummary}, }; use axum::{ extract::Path, diff --git a/src/cat-data-service/src/legacy_service/v1/registration.rs b/src/cat-data-service/src/legacy_service/v1/registration.rs index d949e05cd8..7aa9d3f18b 100644 --- a/src/cat-data-service/src/legacy_service/v1/registration.rs +++ b/src/cat-data-service/src/legacy_service/v1/registration.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{ extract::{Path, Query}, routing::get, diff --git a/src/cat-data-service/src/legacy_service/v1/search.rs b/src/cat-data-service/src/legacy_service/v1/search.rs index a8b9dcb77d..d3bba00ef4 100644 --- a/src/cat-data-service/src/legacy_service/v1/search.rs +++ b/src/cat-data-service/src/legacy_service/v1/search.rs @@ -1,4 +1,8 @@ -use crate::{legacy_service::handle_result, service::Error, state::State, types::SerdeType}; +use crate::{ + legacy_service::{handle_result, types::SerdeType}, + service::Error, + state::State, +}; use axum::{extract::Query, routing::post, Json, Router}; use event_db::types::search::{SearchQuery, SearchResult}; use serde::Deserialize; diff --git a/src/cat-data-service/src/main.rs b/src/cat-data-service/src/main.rs index c80ff4182a..f591793640 100644 --- a/src/cat-data-service/src/main.rs +++ b/src/cat-data-service/src/main.rs @@ -6,7 +6,6 @@ mod logger; mod service; mod settings; mod state; -mod types; #[tokio::main] async fn main() -> Result<(), cli::Error> { diff --git a/src/cat-data-service/src/state/jorm_mock.rs b/src/cat-data-service/src/state/jorm_mock.rs index 983a799bbc..f098f3d7c9 100644 --- a/src/cat-data-service/src/state/jorm_mock.rs +++ b/src/cat-data-service/src/state/jorm_mock.rs @@ -1,4 +1,4 @@ -use crate::types::jorm_mock::{ +use crate::legacy_service::types::jorm_mock::{ AccountId, AccountVote, Fragment, FragmentId, FragmentsProcessingSummary, ProposalIndex, Reason, RejectedInfo, VotePlanId, DEFAULT_POOL_NUMBER, }; diff --git a/src/cat-data-service/src/state/mod.rs b/src/cat-data-service/src/state/mod.rs index a05157cc53..56a2cde867 100644 --- a/src/cat-data-service/src/state/mod.rs +++ b/src/cat-data-service/src/state/mod.rs @@ -1,8 +1,6 @@ use crate::cli::Error; -//use arc_swap::ArcSwap; use event_db::queries::EventDbQueries; use std::sync::Arc; -//use tracing::warn; #[cfg(feature = "jorm-mock")] pub mod jorm_mock; @@ -27,12 +25,6 @@ impl State { None => Arc::new(event_db::establish_connection(None).await?), }; - //let event_db = if let Some(url) = database_url { - // Arc::new(event_db::establish_connection(Some(url.as_str())).await?) - //} else { - // Arc::new(event_db::establish_connection(None).await?) - //}; - #[cfg(feature = "jorm-mock")] let jorm = jorm_mock::JormState::new(*crate::settings::JORM_CLEANUP_TIMEOUT); From 544e1532152f64037da1188a7fd8e2790d44991d Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 10:52:12 +0300 Subject: [PATCH 15/37] add `/delegations/` endpoint --- .../src/legacy_service/types/registration.rs | 2 +- .../src/service/api/registration/mod.rs | 12 ++++++------ src/event-db/src/types/registration.rs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cat-data-service/src/legacy_service/types/registration.rs b/src/cat-data-service/src/legacy_service/types/registration.rs index c8a5863314..daa8f79726 100644 --- a/src/cat-data-service/src/legacy_service/types/registration.rs +++ b/src/cat-data-service/src/legacy_service/types/registration.rs @@ -144,7 +144,7 @@ impl Serialize for SerdeType<&RewardAddress> { reward_payable: bool, } RewardAddressSerde { - reward_address: self.reward_address(), + reward_address: &self.reward_address(), reward_payable: self.reward_payable(), } .serialize(serializer) diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 4a6f374015..483d37a058 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -17,17 +17,17 @@ pub(crate) struct RegistrationApi; #[OpenApi(prefix_path = "/registration", tag = "ApiTags::Registration")] impl RegistrationApi { - #[oai( - path = "/voter/:voting_key", - method = "get", - operation_id = "getVoterInfo" - )] /// Voter's info /// /// Get voter's registration and voting power by their voting key. - /// If the `event_id` query parameter is omitted, then the latest voting power is retrieved. + /// If the `event_id` query parameter is missing, then the "Latest" registration is returned. /// If the `with_delegators` query parameter is ommitted, then `delegator_addresses` field of `VoterInfo` type does not provided. /// + #[oai( + path = "/voter/:voting_key", + method = "get", + operation_id = "getVoterInfo" + )] async fn get_voter_info( &self, pool: Data<&Arc>, diff --git a/src/event-db/src/types/registration.rs b/src/event-db/src/types/registration.rs index c602586dc5..c5dbe4197c 100644 --- a/src/event-db/src/types/registration.rs +++ b/src/event-db/src/types/registration.rs @@ -51,8 +51,8 @@ impl RewardAddress { } } - pub fn reward_address(&self) -> &str { - &self.reward_address + pub fn reward_address(&self) -> String { + self.reward_address.clone() } pub fn reward_payable(&self) -> bool { From e41c49798427afa3f170556ba9de5b298b1ae557 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 11:31:55 +0300 Subject: [PATCH 16/37] add event types --- src/cat-data-service/src/poem_types/event.rs | 276 +++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 src/cat-data-service/src/poem_types/event.rs diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/poem_types/event.rs new file mode 100644 index 0000000000..271b3802a4 --- /dev/null +++ b/src/cat-data-service/src/poem_types/event.rs @@ -0,0 +1,276 @@ +use chrono::{DateTime, Utc}; +use poem_openapi::{Enum, NewType, Object}; +use rust_decimal::prelude::ToPrimitive; +use serde::Deserialize; + +/// The Numeric ID of a Voting Event. +#[derive(NewType, Deserialize)] +pub struct EventId(pub i32); + +impl From for event_db::types::event::EventId { + fn from(event_id: EventId) -> Self { + event_db::types::event::EventId(event_id.0) + } +} + +impl From for EventId { + fn from(event_id: event_db::types::event::EventId) -> Self { + Self(event_id.0) + } +} + +/// The Name of a Voting Event. +#[derive(NewType)] +pub struct EventName(pub String); + +/// A Summary of an individual Voting Event. +#[derive(Object)] +pub struct EventSummary { + id: EventId, + name: EventName, + + /// Date-Time when the Voting Event commences. + #[oai(skip_serializing_if_is_none = true)] + starts: Option>, + + /// Date-Time when the Voting Event is expected to finish. + #[oai(skip_serializing_if_is_none = true)] + ends: Option>, + + /// Last time registrations and Voting power were checked. + /// If not present, no registration or voting power records exist for this event. + #[oai(skip_serializing_if_is_none = true)] + reg_checked: Option>, + + /// True if the event is finished and no changes can be made to it. + /// Does not Including payment of rewards or funding of projects. + #[oai(rename = "final")] + is_final: bool, +} + +impl From for EventSummary { + fn from(value: event_db::types::event::EventSummary) -> Self { + Self { + id: value.id.into(), + name: EventName(value.name), + starts: value.starts.map(Into::into), + ends: value.ends.map(Into::into), + reg_checked: value.reg_checked.map(Into::into), + is_final: value.is_final, + } + } +} + +/// The Voting Power Algorithm. +#[derive(Enum)] +pub enum VotingPowerAlgorithm { + /// Linear Voting Power in Staked ADA, With a minimum limit and maximum relative threshold. + #[oai(rename = "threshold_staked_ADA")] + ThresholdStakedADA, +} + +impl From for VotingPowerAlgorithm { + fn from(value: event_db::types::event::VotingPowerAlgorithm) -> Self { + match value { + event_db::types::event::VotingPowerAlgorithm::ThresholdStakedADA => { + VotingPowerAlgorithm::ThresholdStakedADA + } + } + } +} + +/// The Settings Used to configure the voting power calculation. +#[derive(Object)] +struct VotingPowerSettings { + alg: VotingPowerAlgorithm, + + /// Minimum staked funds required for a valid voter registration. + /// This amount is in Whole ADA. If not present, there is no minimum. + /// + /// Valid for `alg`: + /// * `threshold_staked_ADA` + #[oai(skip_serializing_if_is_none = true)] + min_ada: Option, + + /// Maximum Percentage of total registered voting power allowed for voting power. + /// For example `1.23` = `1.23%` of total registered staked ADA as maximum voting power. + /// If not present, there is no maximum percentage. + /// + /// Valid for `alg`: + /// * `threshold_staked_ADA` + #[oai(skip_serializing_if_is_none = true)] + max_pct: Option, +} + +impl TryFrom for VotingPowerSettings { + type Error = String; + fn try_from(value: event_db::types::event::VotingPowerSettings) -> Result { + Ok(Self { + alg: value.alg.into(), + min_ada: value.min_ada, + max_pct: if let Some(max_pct) = value.max_pct { + Some( + max_pct + .to_f64() + .ok_or_else(|| format!("cannot convert decimal to f64: {}", max_pct))?, + ) + } else { + None + }, + }) + } +} + +/// Details about Voting Event Registration. +#[derive(Object)] +struct EventRegistration { + /// The Registration Purpose. + #[oai(skip_serializing_if_is_none = true)] + purpose: Option, + + /// The deadline for Registration/Voting Power to be fixed. + /// Changes to Registrations or Voting power after this time are not considered. + #[oai(skip_serializing_if_is_none = true)] + deadline: Option>, + + /// The time after which Final Registration/Voting Power will be calculated. + /// This is usually after the deadline, to allow for potential instability in the head of the blockchain to stabilize. + #[oai(skip_serializing_if_is_none = true)] + taken: Option>, +} + +impl From for EventRegistration { + fn from(value: event_db::types::event::EventRegistration) -> Self { + Self { + purpose: value.purpose, + deadline: value.deadline.map(Into::into), + taken: value.taken.map(Into::into), + } + } +} + +/// An Individual Event Goal. +#[derive(Object)] +struct EventGoal { + /// The Relative order of this Goal. 0 being highest. + idx: i32, + + /// The name/short description of the goal. + name: String, +} + +impl From for EventGoal { + fn from(value: event_db::types::event::EventGoal) -> Self { + Self { + idx: value.idx, + name: value.name, + } + } +} + +/// The chronological sequence of stages of the voting event. +/// Stages run chronologically and only 1 stage can run at a time. +/// Each new stage terminates the previous stage. +/// Any omitted entries are assumed to not exist as a stage in this event. +#[derive(Object)] +struct EventSchedule { + /// Date-Time when Insight Sharing Starts. + #[oai(skip_serializing_if_is_none = true)] + insight_sharing: Option>, + + /// Date-Time when Proposals can be submitted to the Voting Event. + #[oai(skip_serializing_if_is_none = true)] + proposal_submission: Option>, + + /// Date-Time when Proposal refinement begins. + #[oai(skip_serializing_if_is_none = true)] + refine_proposals: Option>, + + /// Date-Time when Proposal Finalization starts. + #[oai(skip_serializing_if_is_none = true)] + finalize_proposals: Option>, + + /// Date-Time when Proposal Assessment starts. + #[oai(skip_serializing_if_is_none = true)] + proposal_assessment: Option>, + + /// Date-Time when Assessment QA starts. + #[oai(skip_serializing_if_is_none = true)] + assessment_qa_start: Option>, + + /// Date-Time when Voting commences. + #[oai(skip_serializing_if_is_none = true)] + voting: Option>, + + /// Date-Time when Voting ends and tallying commences. + #[oai(skip_serializing_if_is_none = true)] + tallying: Option>, + + /// Date-Time when Tallying Ends. + #[oai(skip_serializing_if_is_none = true)] + tallying_end: Option>, +} + +impl From for EventSchedule { + fn from(value: event_db::types::event::EventSchedule) -> Self { + Self { + insight_sharing: value.insight_sharing.map(Into::into), + proposal_submission: value.proposal_submission.map(Into::into), + refine_proposals: value.refine_proposals.map(Into::into), + finalize_proposals: value.finalize_proposals.map(Into::into), + proposal_assessment: value.proposal_assessment.map(Into::into), + assessment_qa_start: value.assessment_qa_start.map(Into::into), + voting: value.voting.map(Into::into), + tallying: value.tallying.map(Into::into), + tallying_end: value.tallying_end.map(Into::into), + } + } +} + +/// Detailed information for an individual voting event. +#[derive(Object)] +struct EventDetails { + /// How Voting Power is Calculated and its parameters. + voting_power_settings: VotingPowerSettings, + + /// Registration deadlines and when its finalized. Plus any other parameters. + registration: EventRegistration, + + /// The schedule of the voting Event. + schedule: EventSchedule, + + /// Description of the voting events goals. + /// If this field is not present, there are no listed goals for the event. + goals: Vec, +} + +impl TryFrom for EventDetails { + type Error = String; + fn try_from(value: event_db::types::event::EventDetails) -> Result { + Ok(Self { + voting_power_settings: value.voting_power.try_into()?, + registration: value.registration.into(), + schedule: value.schedule.into(), + goals: value.goals.into_iter().map(Into::into).collect(), + }) + } +} + +/// Complete Details about an individual Voting Event. +#[derive(Object)] +pub struct Event { + #[oai(flatten)] + summary: EventSummary, + #[oai(flatten)] + details: EventDetails, +} + +impl TryFrom for Event { + type Error = String; + fn try_from(value: event_db::types::event::Event) -> Result { + Ok(Self { + summary: value.summary.into(), + details: value.details.try_into()?, + }) + } +} From 452aa3b14167a86280031e5f6dc510ae62fc4574 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 11:33:16 +0300 Subject: [PATCH 17/37] update --- .../src/poem_types/registration.rs | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/cat-data-service/src/poem_types/registration.rs diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs new file mode 100644 index 0000000000..738806d260 --- /dev/null +++ b/src/cat-data-service/src/poem_types/registration.rs @@ -0,0 +1,168 @@ +use chrono::{DateTime, Utc}; +use poem_openapi::{NewType, Object}; +use serde::Deserialize; + +#[derive(NewType, Deserialize)] +pub struct VotingKey(pub String); + +/// Voter Group ID. +/// `direct` = Direct voter. +/// `rep` = Delegated Representative. +#[derive(NewType)] +pub struct VoterGroupId(pub String); + +impl From for VoterGroupId { + fn from(value: event_db::types::registration::VoterGroupId) -> Self { + Self(value.0) + } +} + +/// Voter Info +#[derive(Object)] +pub struct VoterInfo { + /// Voter's voting power. + /// This is the true voting power, subject to minimum voting power and max cap. + voting_power: i64, + voting_group: VoterGroupId, + + /// Total voting power delegated to this voter. + /// This is not capped and not subject to minimum voting power. + delegations_power: i64, + + /// Number of registration which delegated to this voter. + delegations_count: i64, + + /// Voting power's share of the total voting power. + /// Can be used to gauge potential voting power saturation. + /// This value is NOT saturated however, and gives the raw share of total registered voting power. + voting_power_saturation: f64, + + /// List of stake public key addresses which delegated to this voting key. + #[oai(skip_serializing_if_is_none = true)] + delegator_addresses: Option>, +} + +impl From for VoterInfo { + fn from(value: event_db::types::registration::VoterInfo) -> Self { + Self { + voting_power: value.voting_power, + voting_group: value.voting_group.into(), + delegations_power: value.delegations_power, + delegations_count: value.delegations_count, + voting_power_saturation: value.voting_power_saturation, + delegator_addresses: value.delegator_addresses, + } + } +} + +/// Voter +#[derive(Object)] +pub struct Voter { + voter_info: VoterInfo, + + /// Date and time the latest snapshot represents. + as_at: DateTime, + + /// Date and time for the latest update to this snapshot information. + last_updated: DateTime, + + /// `True` - this is the final snapshot which will be used for voting power in the event. + /// `False` - this is an interim snapshot, subject to change. + #[oai(rename = "final")] + is_final: bool, +} + +impl From for Voter { + fn from(value: event_db::types::registration::Voter) -> Self { + Self { + voter_info: value.voter_info.into(), + as_at: value.as_at, + last_updated: value.last_updated, + is_final: value.is_final, + } + } +} + +/// Voter's delegation info +#[derive(Object)] +pub struct Delegation { + /// Hex encoded voting key for this delegation. + voting_key: String, + group: VoterGroupId, + + /// Relative weight assigned to this voting key. + weight: i32, + + /// Raw voting power distributed to this voting key. + value: i64, +} + +impl From for Delegation { + fn from(value: event_db::types::registration::Delegation) -> Self { + Self { + voting_key: value.voting_key, + group: value.group.into(), + weight: value.weight, + value: value.value, + } + } +} + +#[derive(Object)] +pub struct RewardAddress { + /// Reward address for this delegation. + reward_address: String, + + /// Flag which reflects does the `reward_address` valid or not, contains it "addr" or "addr_test" prefix or not. + reward_payable: bool, +} + +impl From for RewardAddress { + fn from(value: event_db::types::registration::RewardAddress) -> Self { + Self { + reward_address: value.reward_address(), + reward_payable: value.reward_payable(), + } + } +} + +#[derive(Object)] +pub struct Delegator { + /// List off delegations made by this stake address. + /// In the order as presented in the voters registration. + delegations: Vec, + + #[oai(flatten)] + reward_address: RewardAddress, + + /// Raw total voting power from stake address. + raw_power: i64, + + /// Total voting power, across all registered voters. + total_power: i64, + + /// Date and time for the latest update to this snapshot information. + as_at: DateTime, + + /// Date and time the latest snapshot represents. + last_updated: DateTime, + + /// `True` - this is the final snapshot which will be used for voting power in the event. + /// `False`- this is an interim snapshot, subject to change. + #[oai(rename = "final")] + is_final: bool, +} + +impl From for Delegator { + fn from(value: event_db::types::registration::Delegator) -> Self { + Self { + delegations: value.delegations.into_iter().map(Into::into).collect(), + reward_address: value.reward_address.into(), + raw_power: value.raw_power, + total_power: value.total_power, + as_at: value.as_at, + last_updated: value.last_updated, + is_final: value.is_final, + } + } +} From 5be6fd6d7ae56f4282c8a36b087b744511f0ee13 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 12:08:21 +0300 Subject: [PATCH 18/37] add Objective types --- .../src/legacy_service/types/objective.rs | 16 +- src/cat-data-service/src/poem_types/ballot.rs | 15 ++ src/cat-data-service/src/poem_types/event.rs | 14 +- src/cat-data-service/src/poem_types/mod.rs | 4 + .../src/poem_types/objective.rs | 152 ++++++++++++++++++ src/event-db/src/queries/event/objective.rs | 8 +- src/event-db/src/types/objective.rs | 4 +- 7 files changed, 192 insertions(+), 21 deletions(-) create mode 100644 src/cat-data-service/src/poem_types/ballot.rs create mode 100644 src/cat-data-service/src/poem_types/mod.rs create mode 100644 src/cat-data-service/src/poem_types/objective.rs diff --git a/src/cat-data-service/src/legacy_service/types/objective.rs b/src/cat-data-service/src/legacy_service/types/objective.rs index 9141ef42af..9d87c2f8ae 100644 --- a/src/cat-data-service/src/legacy_service/types/objective.rs +++ b/src/cat-data-service/src/legacy_service/types/objective.rs @@ -1,8 +1,8 @@ use super::SerdeType; use event_db::types::{ objective::{ - Objective, ObjectiveDetails, ObjectiveId, ObjectiveSummary, ObjectiveType, RewardDefintion, - VoterGroup, + Objective, ObjectiveDetails, ObjectiveId, ObjectiveSummary, ObjectiveType, + RewardDefinition, VoterGroup, }, registration::VoterGroupId, }; @@ -97,7 +97,7 @@ impl Serialize for SerdeType { } } -impl Serialize for SerdeType<&RewardDefintion> { +impl Serialize for SerdeType<&RewardDefinition> { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -115,7 +115,7 @@ impl Serialize for SerdeType<&RewardDefintion> { } } -impl Serialize for SerdeType { +impl Serialize for SerdeType { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -162,7 +162,7 @@ impl Serialize for SerdeType<&ObjectiveDetails> { struct ObjectiveDetailsSerde<'a> { groups: Vec>, #[serde(skip_serializing_if = "Option::is_none")] - reward: Option>, + reward: Option>, #[serde(skip_serializing_if = "Option::is_none")] supplemental: &'a Option, } @@ -284,7 +284,7 @@ mod tests { #[test] fn reward_definition_json_test() { - let reward_definition = SerdeType(RewardDefintion { + let reward_definition = SerdeType(RewardDefinition { currency: "ADA".to_string(), value: 100, }); @@ -327,7 +327,7 @@ mod tests { group: Some(VoterGroupId("group".to_string())), voting_token: Some("token".to_string()), }], - reward: Some(RewardDefintion { + reward: Some(RewardDefinition { currency: "ADA".to_string(), value: 100, }), @@ -373,7 +373,7 @@ mod tests { group: Some(VoterGroupId("group".to_string())), voting_token: Some("token".to_string()), }], - reward: Some(RewardDefintion { + reward: Some(RewardDefinition { currency: "ADA".to_string(), value: 100, }), diff --git a/src/cat-data-service/src/poem_types/ballot.rs b/src/cat-data-service/src/poem_types/ballot.rs new file mode 100644 index 0000000000..0e36d22289 --- /dev/null +++ b/src/cat-data-service/src/poem_types/ballot.rs @@ -0,0 +1,15 @@ +use poem_openapi::NewType; +use serde::Deserialize; + +/// The kind of ballot to be cast on this Objective. +/// * `public` - All Ballots are public when cast. +/// * `private` - All Ballots are private. +/// * `cast-private` - All Ballots are cast privately but become public after the tally. +#[derive(NewType, Deserialize)] +pub struct BallotType(String); + +impl From for BallotType { + fn from(value: event_db::types::ballot::BallotType) -> Self { + Self(value.0) + } +} diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/poem_types/event.rs index 271b3802a4..34eb085a06 100644 --- a/src/cat-data-service/src/poem_types/event.rs +++ b/src/cat-data-service/src/poem_types/event.rs @@ -5,7 +5,7 @@ use serde::Deserialize; /// The Numeric ID of a Voting Event. #[derive(NewType, Deserialize)] -pub struct EventId(pub i32); +pub struct EventId(i32); impl From for event_db::types::event::EventId { fn from(event_id: EventId) -> Self { @@ -21,7 +21,7 @@ impl From for EventId { /// The Name of a Voting Event. #[derive(NewType)] -pub struct EventName(pub String); +pub struct EventName(String); /// A Summary of an individual Voting Event. #[derive(Object)] @@ -81,7 +81,7 @@ impl From for VotingPowerAlgorithm /// The Settings Used to configure the voting power calculation. #[derive(Object)] -struct VotingPowerSettings { +pub struct VotingPowerSettings { alg: VotingPowerAlgorithm, /// Minimum staked funds required for a valid voter registration. @@ -123,7 +123,7 @@ impl TryFrom for VotingPowerSetting /// Details about Voting Event Registration. #[derive(Object)] -struct EventRegistration { +pub struct EventRegistration { /// The Registration Purpose. #[oai(skip_serializing_if_is_none = true)] purpose: Option, @@ -151,7 +151,7 @@ impl From for EventRegistration { /// An Individual Event Goal. #[derive(Object)] -struct EventGoal { +pub struct EventGoal { /// The Relative order of this Goal. 0 being highest. idx: i32, @@ -173,7 +173,7 @@ impl From for EventGoal { /// Each new stage terminates the previous stage. /// Any omitted entries are assumed to not exist as a stage in this event. #[derive(Object)] -struct EventSchedule { +pub struct EventSchedule { /// Date-Time when Insight Sharing Starts. #[oai(skip_serializing_if_is_none = true)] insight_sharing: Option>, @@ -229,7 +229,7 @@ impl From for EventSchedule { /// Detailed information for an individual voting event. #[derive(Object)] -struct EventDetails { +pub struct EventDetails { /// How Voting Power is Calculated and its parameters. voting_power_settings: VotingPowerSettings, diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs new file mode 100644 index 0000000000..16b32c1b3c --- /dev/null +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -0,0 +1,4 @@ +pub mod ballot; +pub mod event; +pub mod objective; +pub mod registration; diff --git a/src/cat-data-service/src/poem_types/objective.rs b/src/cat-data-service/src/poem_types/objective.rs new file mode 100644 index 0000000000..0e487883e5 --- /dev/null +++ b/src/cat-data-service/src/poem_types/objective.rs @@ -0,0 +1,152 @@ +use super::registration::VoterGroupId; +use poem_openapi::{NewType, Object}; +use serde::Deserialize; +use serde_json::Value; + +/// The Numeric ID of an Objective to be decided in a Voting Event. +#[derive(NewType, Deserialize)] +pub struct ObjectiveId(i32); + +impl From for ObjectiveId { + fn from(value: event_db::types::objective::ObjectiveId) -> Self { + Self(value.0) + } +} + +#[derive(Object)] +pub struct ObjectiveType { + /// Objective Type defines the rules of the objective. + id: String, + + /// An explanaiton of the rules of this Objective Type. + description: String, +} + +impl From for ObjectiveType { + fn from(value: event_db::types::objective::ObjectiveType) -> Self { + Self { + id: value.id, + description: value.description, + } + } +} + +/// Summary off an Individual Objective. +#[derive(Object)] +pub struct ObjectiveSummary { + /// The ID of this objective for the Voting Event. + id: ObjectiveId, + + /// The "Type" of Objective + #[oai(rename = "type")] + objective_type: ObjectiveType, + + /// The title for this Objective. + title: String, + + /// Long form explanation of this particular objective. + /// *May contain HTML Markup.* + /// *May contain Links to external content or assets.* + description: String, + + /// Whether this Objective has been deleted or not. + deleted: bool, +} + +impl From for ObjectiveSummary { + fn from(value: event_db::types::objective::ObjectiveSummary) -> Self { + Self { + id: value.id.into(), + objective_type: value.objective_type.into(), + title: value.title, + description: value.description, + deleted: value.deleted, + } + } +} + +#[derive(Object)] +pub struct RewardDefinition { + /// Currency of the Reward. + currency: String, + + /// The total value of the reward + value: i64, +} + +impl From for RewardDefinition { + fn from(value: event_db::types::objective::RewardDefinition) -> Self { + Self { + currency: value.currency, + value: value.value, + } + } +} + +#[derive(Object)] +pub struct VoterGroup { + #[oai(skip_serializing_if_is_none = true)] + group: Option, + + /// The identifier of voting power token used withing this group. + /// All vote plans within a group are guaranteed to use the same token. + #[oai(skip_serializing_if_is_none = true)] + voting_token: Option, +} + +impl From for VoterGroup { + fn from(value: event_db::types::objective::VoterGroup) -> Self { + Self { + group: value.group.map(Into::into), + voting_token: value.voting_token, + } + } +} + +/// Individual Objective Details +#[derive(Object)] +pub struct ObjectiveDetails { + /// The valid voter groups for this voting event. + groups: Vec, + + /// The Total Reward being offered for this Objective. + /// Distribution of the Reward is determined under the rules of this Objective. + /// If this field is not present there is no reward being offered for the Objective. + #[oai(skip_serializing_if_is_none = true)] + reward: Option, + + /// Objective Supplemental Data + /// + /// Extra Data which can be used to enrich the information shared about the Objective. + /// All Information here is optional. + /// If there is no supplemental information for the Objective this field is omitted. + #[oai(skip_serializing_if_is_none = true)] + supplemental: Option, +} + +impl From for ObjectiveDetails { + fn from(value: event_db::types::objective::ObjectiveDetails) -> Self { + Self { + groups: value.groups.into_iter().map(Into::into).collect(), + reward: value.reward.map(Into::into), + supplemental: value.supplemental, + } + } +} + +#[derive(Object)] +pub struct Objective { + #[oai(flatten)] + summary: ObjectiveSummary, + #[oai(flatten)] + details: ObjectiveDetails, +} + +impl From for Objective { + fn from(value: event_db::types::objective::Objective) -> Self { + Self { + summary: value.summary.into(), + details: value.details.into(), + } + } +} diff --git a/src/event-db/src/queries/event/objective.rs b/src/event-db/src/queries/event/objective.rs index 0d45f8f87a..58c2acb06a 100644 --- a/src/event-db/src/queries/event/objective.rs +++ b/src/event-db/src/queries/event/objective.rs @@ -6,7 +6,7 @@ use crate::{ event::EventId, objective::{ Objective, ObjectiveDetails, ObjectiveId, ObjectiveSummary, ObjectiveType, - RewardDefintion, VoterGroup, + RewardDefinition, VoterGroup, }, }, }, @@ -72,7 +72,7 @@ impl ObjectiveQueries for EventDB { let currency: Option<_> = row.try_get("rewards_currency")?; let value: Option<_> = row.try_get("rewards_total")?; let reward = match (currency, value) { - (Some(currency), Some(value)) => Some(RewardDefintion { currency, value }), + (Some(currency), Some(value)) => Some(RewardDefinition { currency, value }), _ => None, }; @@ -157,7 +157,7 @@ mod tests { voting_token: Some("voting token 2".to_string()), } ], - reward: Some(RewardDefintion { + reward: Some(RewardDefinition { currency: "ADA".to_string(), value: 100 }), @@ -218,7 +218,7 @@ mod tests { voting_token: Some("voting token 2".to_string()), } ], - reward: Some(RewardDefintion { + reward: Some(RewardDefinition { currency: "ADA".to_string(), value: 100 }), diff --git a/src/event-db/src/types/objective.rs b/src/event-db/src/types/objective.rs index 8c8a388e65..db22613505 100644 --- a/src/event-db/src/types/objective.rs +++ b/src/event-db/src/types/objective.rs @@ -20,7 +20,7 @@ pub struct ObjectiveSummary { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDefintion { +pub struct RewardDefinition { pub currency: String, pub value: i64, } @@ -34,7 +34,7 @@ pub struct VoterGroup { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ObjectiveDetails { pub groups: Vec, - pub reward: Option, + pub reward: Option, pub supplemental: Option, } From 94df3a33451de79add6e9f23894da4281f69e854 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 13:20:12 +0300 Subject: [PATCH 19/37] add Proposal types --- src/cat-data-service/src/poem_types/mod.rs | 1 + .../src/poem_types/proposal.rs | 120 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/cat-data-service/src/poem_types/proposal.rs diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs index 16b32c1b3c..cb6d51d5cd 100644 --- a/src/cat-data-service/src/poem_types/mod.rs +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -1,4 +1,5 @@ pub mod ballot; pub mod event; pub mod objective; +pub mod proposal; pub mod registration; diff --git a/src/cat-data-service/src/poem_types/proposal.rs b/src/cat-data-service/src/poem_types/proposal.rs new file mode 100644 index 0000000000..17391abe1a --- /dev/null +++ b/src/cat-data-service/src/poem_types/proposal.rs @@ -0,0 +1,120 @@ +use poem_openapi::{NewType, Object}; +use serde::Deserialize; +use serde_json::Value; + +#[derive(NewType, Deserialize)] +pub struct ProposalId(i32); + +impl From for ProposalId { + fn from(value: event_db::types::proposal::ProposalId) -> Self { + Self(value.0) + } +} + +/// Summary of a Proposal for an Objective. +#[derive(Object)] +pub struct ProposalSummary { + /// The ID of this proposal. + id: ProposalId, + + /// Short title of the proposal. + title: String, + + /// Brief description of the proposal. + summary: String, + + /// Whether this Proposal has been deleted or not. + deleted: bool, +} + +impl From for ProposalSummary { + fn from(value: event_db::types::proposal::ProposalSummary) -> Self { + Self { + id: value.id.into(), + title: value.title, + summary: value.summary, + deleted: value.deleted, + } + } +} + +/// Details about a proposer for a particular proposal. +#[derive(Object)] +pub struct ProposerDetails { + /// Name of the author/s of the proposal. + name: String, + + /// Email contact address of the author's of the proposal. + /// If not present, there is no known contact email for the authors. + email: String, + + /// URL to a web resource with details about the author's of the proposal. + url: String, + + /// The Payment Address the Funds requested will be paid to. + /// Will not be included if the proposal does not request funds. + payment_key: String, +} + +impl From for ProposerDetails { + fn from(value: event_db::types::proposal::ProposerDetails) -> Self { + Self { + name: value.name, + email: value.email, + url: value.url, + payment_key: value.payment_key, + } + } +} + +/// Details of a particular Proposal. +#[derive(Object)] +pub struct ProposalDetails { + /// The amount of funds requested by this proposal. + /// In the denomination of the Objectives Reward. + /// If not present, then this proposal is not requesting any funds. + funds: i64, + + /// URL to a web page with details on this proposal. + url: String, + + /// Link to extra files associated with this proposal. + /// Only included if there are linked files. + files: String, + + /// List of all proposers making this proposal. + proposer: Vec, + + /// Additional Information related to the proposal. + #[oai(skip_serializing_if_is_none = true)] + supplemental: Option, +} + +impl From for ProposalDetails { + fn from(value: event_db::types::proposal::ProposalDetails) -> Self { + Self { + funds: value.funds, + url: value.url, + files: value.files, + proposer: value.proposer.into_iter().map(Into::into).collect(), + supplemental: value.supplemental, + } + } +} + +#[derive(Object)] +pub struct Proposal { + #[oai(flatten)] + summary: ProposalSummary, + #[oai(flatten)] + details: ProposalDetails, +} + +impl From for Proposal { + fn from(value: event_db::types::proposal::Proposal) -> Self { + Self { + summary: value.summary.into(), + details: value.details.into(), + } + } +} From 727bf99497a6024c3c17e3bc20904aedf82ccbea Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 13:29:01 +0300 Subject: [PATCH 20/37] add reviews types --- .../src/poem_types/reviews.rs | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/cat-data-service/src/poem_types/reviews.rs diff --git a/src/cat-data-service/src/poem_types/reviews.rs b/src/cat-data-service/src/poem_types/reviews.rs new file mode 100644 index 0000000000..81a8d9deb9 --- /dev/null +++ b/src/cat-data-service/src/poem_types/reviews.rs @@ -0,0 +1,108 @@ +use poem_openapi::Object; +use serde_json::Value; + +/// Details about a Type of review. +#[derive(Object)] +pub struct ReviewType { + /// The Unique ID for this review type. + id: i32, + + /// The unique name for the review type. + name: String, + + /// Description about what the review type is. + #[oai(skip_serializing_if_is_none = true)] + description: Option, + + /// The inclusive Minimum value for the reviews rating. + /// By definition, lower value ratings are considered lower ratings. + /// Therefore this field represents the lowest possible rating. + min: i32, + + /// The inclusive Maximum value for the reviews rating. + /// By definition, higher value ratings are considered higher ratings. + /// Therefore this field represents the highest possible rating. + max: i32, + + /// Optional sequential list of mapped named values for rating scores. + /// * If not present, the rating score is numeric. + /// * If present: + /// * all possible rating scores must be represented with mapped names and the rating is represented by the value in the map. + /// * The lowest numbered score comes first in the array. + /// * The array is sequential with no gaps. + map: Vec, + + /// Does the Review Type include a note? + /// * Null - *Optional*, may or may not include a note. + /// * False - **MUST NOT** include a note. + /// * True - **MUST** include a note. + #[oai(skip_serializing_if_is_none = true)] + note: Option, + + /// The reviewer group who can create this review type. + #[oai(skip_serializing_if_is_none = true)] + group: Option, +} + +impl From for ReviewType { + fn from(value: event_db::types::reviews::ReviewType) -> Self { + Self { + id: value.id, + name: value.name, + description: value.description, + min: value.min, + max: value.max, + map: value.map, + note: value.note, + group: value.group, + } + } +} + +/// Individual Rating. +#[derive(Object)] +struct Rating { + /// The review type being rated. Maps to the ReviewType id. + review_type: i32, + + /// Score given to this rating. + /// Will be bounded by the `min` and `max` of the ReviewType. + score: i32, + + /// Reason why this rating was given. + /// If NO reason was given, this field is omitted. + #[oai(skip_serializing_if_is_none = true)] + note: &'a Option, +} + +impl From for Rating { + fn from(value: event_db::types::reviews::Rating) -> Self { + Self { + review_type: value.review_type, + score: value.score, + note: value.note, + } + } +} + +/// Review of a Proposal by a Community Advisor. +#[derive(Object)] +struct AdvisorReview { + /// Anonymized Assessor identity. + /// All reviews by the same Assessor will have the same identity string. + assessor: String, + + /// List of review ratings given by this reviewer. + ratings: Vec, +} + +impl From for AdvisorReview { + fn from(value: event_db::types::reviews::AdvisorReview) -> Self { + Self { + assessor: value.assessor, + ratings: value.ratings.into_iter().map(Into::into).collect(), + } + } +} + + From 260f683862e0fed691929ed8079ff3a5421d452b Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 13:41:18 +0300 Subject: [PATCH 21/37] add ballot types --- src/cat-data-service/src/poem_types/ballot.rs | 59 ++++++++++++++++++- .../src/poem_types/reviews.rs | 6 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/cat-data-service/src/poem_types/ballot.rs b/src/cat-data-service/src/poem_types/ballot.rs index 0e36d22289..9fc174eb74 100644 --- a/src/cat-data-service/src/poem_types/ballot.rs +++ b/src/cat-data-service/src/poem_types/ballot.rs @@ -1,5 +1,12 @@ -use poem_openapi::NewType; -use serde::Deserialize; +use super::registration::VoterGroupId; +use poem_openapi::{NewType, Object}; +use serde::{Deserialize, Serialize}; + +/// Ordered list of choices available for all proposals in this Objective. +/// The offset into the array is the index of the choice. +/// For example, the first element is Choice 0, second is Choice 1 and so on. +#[derive(Deserialize, Serialize)] +pub struct ObjectiveChoices(Vec); /// The kind of ballot to be cast on this Objective. /// * `public` - All Ballots are public when cast. @@ -13,3 +20,51 @@ impl From for BallotType { Self(value.0) } } + +/// The voteplan to use for this group. +#[derive(Object)] +pub struct VotePlan { + /// The Index of the proposal, needed to create a ballot for it. + chain_proposal_index: i64, + + /// The name of the group. + #[oai(skip_serializing_if_is_none = true)] + group: Option, + + /// The type of ballot this group must cast. + ballot_type: BallotType, + + /// Blockchain ID of the vote plan transaction. + chain_voteplan_id: String, + + /// The public encryption key used. ONLY if required by the ballot type (private, cast-private). + #[oai(skip_serializing_if_is_none = true)] + encryption_key: Option, +} + +impl From for VotePlan { + fn from(value: event_db::types::ballot::VotePlan) -> Self { + Self { + chain_proposal_index: value.chain_proposal_index, + group: value.group.map(Into::into), + ballot_type: value.ballot_type.into(), + chain_voteplan_id: value.chain_voteplan_id, + encryption_key: value.encryption_key, + } + } +} + +/// List of groups and the voteplans they use when voting on this proposal. +/// Each valid group for this Objective: +/// * Must be listed. +/// * Must not be repeated. +// #[derive(Deserialize)] +pub struct GroupVotePlans(Vec); + +/// Details necessary to complete a ballot for the specific proposal and objective. +// #[derive(Object)] +pub struct Ballot { + /// Ballot Choices present for all proposals in this Objective. + choices: ObjectiveChoices, + voteplans: GroupVotePlans, +} diff --git a/src/cat-data-service/src/poem_types/reviews.rs b/src/cat-data-service/src/poem_types/reviews.rs index 81a8d9deb9..b36e97a369 100644 --- a/src/cat-data-service/src/poem_types/reviews.rs +++ b/src/cat-data-service/src/poem_types/reviews.rs @@ -61,7 +61,7 @@ impl From for ReviewType { /// Individual Rating. #[derive(Object)] -struct Rating { +pub struct Rating { /// The review type being rated. Maps to the ReviewType id. review_type: i32, @@ -87,7 +87,7 @@ impl From for Rating { /// Review of a Proposal by a Community Advisor. #[derive(Object)] -struct AdvisorReview { +pub struct AdvisorReview { /// Anonymized Assessor identity. /// All reviews by the same Assessor will have the same identity string. assessor: String, @@ -104,5 +104,3 @@ impl From for AdvisorReview { } } } - - From b3d02a269ab23e68ecdd8c1884979ad52838d5bf Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 14:27:18 +0300 Subject: [PATCH 22/37] fixes --- src/cat-data-service/src/poem_types/registration.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs index 738806d260..9803995b51 100644 --- a/src/cat-data-service/src/poem_types/registration.rs +++ b/src/cat-data-service/src/poem_types/registration.rs @@ -2,6 +2,7 @@ use chrono::{DateTime, Utc}; use poem_openapi::{NewType, Object}; use serde::Deserialize; +/// Voting Key. #[derive(NewType, Deserialize)] pub struct VotingKey(pub String); From 1f85f822bbfa8f69817d07e27898efd7123f8e94 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Wed, 13 Sep 2023 14:40:36 +0300 Subject: [PATCH 23/37] update --- src/cat-data-service/src/poem_types/ballot.rs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/cat-data-service/src/poem_types/ballot.rs b/src/cat-data-service/src/poem_types/ballot.rs index 9fc174eb74..09542683dc 100644 --- a/src/cat-data-service/src/poem_types/ballot.rs +++ b/src/cat-data-service/src/poem_types/ballot.rs @@ -1,12 +1,6 @@ use super::registration::VoterGroupId; use poem_openapi::{NewType, Object}; -use serde::{Deserialize, Serialize}; - -/// Ordered list of choices available for all proposals in this Objective. -/// The offset into the array is the index of the choice. -/// For example, the first element is Choice 0, second is Choice 1 and so on. -#[derive(Deserialize, Serialize)] -pub struct ObjectiveChoices(Vec); +use serde::Deserialize; /// The kind of ballot to be cast on this Objective. /// * `public` - All Ballots are public when cast. @@ -54,17 +48,19 @@ impl From for VotePlan { } } -/// List of groups and the voteplans they use when voting on this proposal. -/// Each valid group for this Objective: -/// * Must be listed. -/// * Must not be repeated. -// #[derive(Deserialize)] -pub struct GroupVotePlans(Vec); - /// Details necessary to complete a ballot for the specific proposal and objective. -// #[derive(Object)] +#[derive(Object)] pub struct Ballot { /// Ballot Choices present for all proposals in this Objective. - choices: ObjectiveChoices, - voteplans: GroupVotePlans, + /// + /// Ordered list of choices available for all proposals in this Objective. + /// The offset into the array is the index of the choice. + /// For example, the first element is Choice 0, second is Choice 1 and so on. + choices: Vec, + + /// List of groups and the voteplans they use when voting on this proposal. + /// Each valid group for this Objective: + /// * Must be listed. + /// * Must not be repeated. + voteplans: Vec, } From 4738b034928d6cf720bc9297fd94c396f0a52924 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 13:23:42 +0300 Subject: [PATCH 24/37] add objective summary and other types --- .../src/service/common/objects/mod.rs | 4 ++ .../service/common/objects/objective_id.rs | 18 +++++++++ .../common/objects/objective_summary.rs | 38 +++++++++++++++++++ .../service/common/objects/objective_type.rs | 29 ++++++++++++++ .../service/common/objects/objective_types.rs | 30 +++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 src/cat-data-service/src/service/common/objects/objective_id.rs create mode 100644 src/cat-data-service/src/service/common/objects/objective_summary.rs create mode 100644 src/cat-data-service/src/service/common/objects/objective_type.rs create mode 100644 src/cat-data-service/src/service/common/objects/objective_types.rs diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index efa71253fb..d92cb7b41d 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,6 +1,10 @@ //! This module contains common and re-usable objects. pub(crate) mod delegator_address; pub(crate) mod event_id; +pub(crate) mod objective_id; +pub(crate) mod objective_summary; +pub(crate) mod objective_type; +pub(crate) mod objective_types; pub(crate) mod stake_public_key; pub(crate) mod voter; pub(crate) mod voter_group_id; diff --git a/src/cat-data-service/src/service/common/objects/objective_id.rs b/src/cat-data-service/src/service/common/objects/objective_id.rs new file mode 100644 index 0000000000..1635196985 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective_id.rs @@ -0,0 +1,18 @@ +use poem_openapi::{types::Example, NewType}; +use serde::Deserialize; + +/// The Numeric ID of an Objective to be decided in a Voting Event. +#[derive(NewType, Deserialize)] +pub(crate) struct ObjectiveId(i32); + +impl Example for ObjectiveId { + fn example() -> Self { + Self(1) + } +} + +impl From for ObjectiveId { + fn from(value: event_db::types::objective::ObjectiveId) -> Self { + Self(value.0) + } +} diff --git a/src/cat-data-service/src/service/common/objects/objective_summary.rs b/src/cat-data-service/src/service/common/objects/objective_summary.rs new file mode 100644 index 0000000000..517a1e1328 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective_summary.rs @@ -0,0 +1,38 @@ +use super::{objective_id::ObjectiveId, objective_type::ObjectiveType}; +use poem_openapi::Object; + +/// Summary off an Individual Objective. +#[derive(Object)] +pub(crate) struct ObjectiveSummary { + /// The ID of this objective for the Voting Event. + #[oai(validator(minimum(value = "0")))] + id: ObjectiveId, + + /// The "Type" of Objective + #[oai(rename = "type")] + objective_type: ObjectiveType, + + /// The title for this Objective. + title: String, + + /// Long form explanation of this particular objective. + /// *May contain HTML Markup.* + /// *May contain Links to external content or assets.* + description: String, + + /// Whether this Objective has been deleted or not. + deleted: bool, +} + +impl TryFrom for ObjectiveSummary { + type Error = String; + fn try_from(value: event_db::types::objective::ObjectiveSummary) -> Result { + Ok(Self { + id: value.id.into(), + objective_type: value.objective_type.try_into()?, + title: value.title, + description: value.description, + deleted: value.deleted, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/objective_type.rs b/src/cat-data-service/src/service/common/objects/objective_type.rs new file mode 100644 index 0000000000..a59b511963 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective_type.rs @@ -0,0 +1,29 @@ +use super::objective_types::ObjectiveTypes; +use poem_openapi::{types::Example, Object}; + +#[derive(Object)] +pub(crate) struct ObjectiveType { + id: ObjectiveTypes, + + /// An explanation of the rules of this Objective Type. + description: String, +} + +impl Example for ObjectiveType { + fn example() -> Self { + Self { + id: ObjectiveTypes::Simple, + description: "Objective type description".to_string(), + } + } +} + +impl TryFrom for ObjectiveType { + type Error = String; + fn try_from(value: event_db::types::objective::ObjectiveType) -> Result { + Ok(Self { + id: value.id.try_into()?, + description: value.description, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/objective_types.rs b/src/cat-data-service/src/service/common/objects/objective_types.rs new file mode 100644 index 0000000000..c6e2ee44d9 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective_types.rs @@ -0,0 +1,30 @@ +use poem_openapi::{types::Example, Enum}; + +/// Objective Type defines the rules of the objective. +#[derive(Enum)] +pub(crate) enum ObjectiveTypes { + #[oai(rename = "catalyst-simple")] + Simple, + #[oai(rename = "catalyst-native")] + Native, + #[oai(rename = "catalyst-community-choice")] + CommunityChoice, +} + +impl Example for ObjectiveTypes { + fn example() -> Self { + Self::Simple + } +} + +impl TryFrom for ObjectiveTypes { + type Error = String; + fn try_from(value: String) -> Result { + match value.as_str() { + "catalyst-simple" => Ok(Self::Simple), + "catalyst-native" => Ok(Self::Native), + "catalyst-community-choice" => Ok(Self::CommunityChoice), + _ => Err(format!("Unknown Objective Type: {}", value)), + } + } +} From 82ec594f7276d73fa69b84f6f3d1e3828acb3bb3 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 18 Sep 2023 13:34:42 +0300 Subject: [PATCH 25/37] add reward definition type --- .../src/service/common/objects/mod.rs | 2 ++ .../common/objects/objective_summary.rs | 14 +++++++- .../service/common/objects/objective_type.rs | 1 + .../service/common/objects/reward_currency.rs | 23 +++++++++++++ .../common/objects/reward_definition.rs | 32 +++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/cat-data-service/src/service/common/objects/reward_currency.rs create mode 100644 src/cat-data-service/src/service/common/objects/reward_definition.rs diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index d92cb7b41d..906f90fea8 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -5,6 +5,8 @@ pub(crate) mod objective_id; pub(crate) mod objective_summary; pub(crate) mod objective_type; pub(crate) mod objective_types; +pub(crate) mod reward_currency; +pub(crate) mod reward_definition; pub(crate) mod stake_public_key; pub(crate) mod voter; pub(crate) mod voter_group_id; diff --git a/src/cat-data-service/src/service/common/objects/objective_summary.rs b/src/cat-data-service/src/service/common/objects/objective_summary.rs index 517a1e1328..1379d1997d 100644 --- a/src/cat-data-service/src/service/common/objects/objective_summary.rs +++ b/src/cat-data-service/src/service/common/objects/objective_summary.rs @@ -1,5 +1,5 @@ use super::{objective_id::ObjectiveId, objective_type::ObjectiveType}; -use poem_openapi::Object; +use poem_openapi::{types::Example, Object}; /// Summary off an Individual Objective. #[derive(Object)] @@ -24,6 +24,18 @@ pub(crate) struct ObjectiveSummary { deleted: bool, } +impl Example for ObjectiveSummary { + fn example() -> Self { + Self { + id: ObjectiveId::example(), + objective_type: ObjectiveType::example(), + title: "Objective Title".to_string(), + description: "Objective Description".to_string(), + deleted: false, + } + } +} + impl TryFrom for ObjectiveSummary { type Error = String; fn try_from(value: event_db::types::objective::ObjectiveSummary) -> Result { diff --git a/src/cat-data-service/src/service/common/objects/objective_type.rs b/src/cat-data-service/src/service/common/objects/objective_type.rs index a59b511963..99084c6d61 100644 --- a/src/cat-data-service/src/service/common/objects/objective_type.rs +++ b/src/cat-data-service/src/service/common/objects/objective_type.rs @@ -1,6 +1,7 @@ use super::objective_types::ObjectiveTypes; use poem_openapi::{types::Example, Object}; +/// Objective type definition. #[derive(Object)] pub(crate) struct ObjectiveType { id: ObjectiveTypes, diff --git a/src/cat-data-service/src/service/common/objects/reward_currency.rs b/src/cat-data-service/src/service/common/objects/reward_currency.rs new file mode 100644 index 0000000000..bc90abc92e --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/reward_currency.rs @@ -0,0 +1,23 @@ +use poem_openapi::{types::Example, Enum}; + +/// Currency of the Reward. +#[derive(Enum)] +pub(crate) enum RewardCurrency { + ADA, +} + +impl Example for RewardCurrency { + fn example() -> Self { + Self::ADA + } +} + +impl TryFrom for RewardCurrency { + type Error = String; + fn try_from(value: String) -> Result { + match value.as_str() { + "ADA" => Ok(Self::ADA), + _ => Err(format!("Unknown Reward Currency: {}", value)), + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/reward_definition.rs b/src/cat-data-service/src/service/common/objects/reward_definition.rs new file mode 100644 index 0000000000..c1950d8ecf --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/reward_definition.rs @@ -0,0 +1,32 @@ +use super::reward_currency::RewardCurrency; +use poem_openapi::{types::Example, Object}; + +/// Represents a reward definition. +#[derive(Object)] +pub(crate) struct RewardDefiniton { + /// Currency of the Reward. + currency: RewardCurrency, + + /// The total value of the reward + #[oai(validator(minimum(value = "0")))] + value: i64, +} + +impl Example for RewardDefiniton { + fn example() -> Self { + Self { + currency: RewardCurrency::example(), + value: 100, + } + } +} + +impl TryFrom for RewardDefiniton { + type Error = String; + fn try_from(value: event_db::types::objective::RewardDefinition) -> Result { + Ok(Self { + currency: value.currency.try_into()?, + value: value.value, + }) + } +} From 9f969a65d9f387f2a73a1b7cc1923693fdff8f2e Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 10:16:01 +0300 Subject: [PATCH 26/37] add objective --- .../src/service/common/objects/mod.rs | 3 ++ .../src/service/common/objects/objective.rs | 30 +++++++++++ .../common/objects/objective_details.rs | 53 +++++++++++++++++++ .../src/service/common/objects/voter_group.rs | 37 +++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 src/cat-data-service/src/service/common/objects/objective.rs create mode 100644 src/cat-data-service/src/service/common/objects/objective_details.rs create mode 100644 src/cat-data-service/src/service/common/objects/voter_group.rs diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 906f90fea8..9cbd537eb3 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,6 +1,8 @@ //! This module contains common and re-usable objects. pub(crate) mod delegator_address; pub(crate) mod event_id; +pub(crate) mod objective; +pub(crate) mod objective_details; pub(crate) mod objective_id; pub(crate) mod objective_summary; pub(crate) mod objective_type; @@ -9,6 +11,7 @@ pub(crate) mod reward_currency; pub(crate) mod reward_definition; pub(crate) mod stake_public_key; pub(crate) mod voter; +pub(crate) mod voter_group; pub(crate) mod voter_group_id; pub(crate) mod voter_info; pub(crate) mod voting_key; diff --git a/src/cat-data-service/src/service/common/objects/objective.rs b/src/cat-data-service/src/service/common/objects/objective.rs new file mode 100644 index 0000000000..cb2b79a2a2 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective.rs @@ -0,0 +1,30 @@ +use super::{objective_details::ObjectiveDetails, objective_summary::ObjectiveSummary}; +use poem_openapi::{types::Example, Object}; + +/// Full Objective info. +#[derive(Object)] +pub(crate) struct Objective { + #[oai(flatten)] + summary: ObjectiveSummary, + #[oai(flatten)] + details: ObjectiveDetails, +} + +impl Example for Objective { + fn example() -> Self { + Self { + summary: ObjectiveSummary::example(), + details: ObjectiveDetails::example(), + } + } +} + +impl TryFrom for Objective { + type Error = String; + fn try_from(value: event_db::types::objective::Objective) -> Result { + Ok(Self { + summary: value.summary.try_into()?, + details: value.details.try_into()?, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/objective_details.rs b/src/cat-data-service/src/service/common/objects/objective_details.rs new file mode 100644 index 0000000000..8b83c111f8 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/objective_details.rs @@ -0,0 +1,53 @@ +use super::{reward_definition::RewardDefiniton, voter_group::VoterGroup}; +use poem_openapi::{types::Example, Object}; +use serde_json::Value; + +#[derive(Object)] +pub(crate) struct ObjectiveDetails { + /// The valid voter groups for this voting event. + groups: Vec, + + /// The Total Reward being offered for this Objective. + /// Distribution of the Reward is determined under the rules of this Objective. + /// If this field is not present there is no reward being offered for the Objective. + #[oai(skip_serializing_if_is_none = true)] + reward: Option, + + /// Objective Supplemental Data + /// + /// Extra Data which can be used to enrich the information shared about the Objective. + /// All Information here is optional. + /// If there is no supplemental information for the Objective this field is omitted. + #[oai(skip_serializing_if_is_none = true)] + supplemental: Option, +} + +impl Example for ObjectiveDetails { + fn example() -> Self { + Self { + groups: vec![VoterGroup::example()], + reward: Some(RewardDefiniton::example()), + supplemental: None, + } + } +} + +impl TryFrom for ObjectiveDetails { + type Error = String; + fn try_from(value: event_db::types::objective::ObjectiveDetails) -> Result { + let mut groups = Vec::new(); + for group in value.groups { + groups.push(group.try_into()?); + } + let reward = if let Some(reward) = value.reward { + Some(reward.try_into()?) + } else { + None + }; + Ok(Self { + groups, + reward, + supplemental: value.supplemental, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/voter_group.rs b/src/cat-data-service/src/service/common/objects/voter_group.rs new file mode 100644 index 0000000000..78e7d03348 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/voter_group.rs @@ -0,0 +1,37 @@ +use super::voter_group_id::VoterGroupId; +use poem_openapi::{types::Example, Object}; + +#[derive(Object)] +pub(crate) struct VoterGroup { + #[oai(skip_serializing_if_is_none = true)] + group: Option, + + /// The identifier of voting power token used withing this group. + /// All vote plans within a group are guaranteed to use the same token. + #[oai(skip_serializing_if_is_none = true)] + voting_token: Option, +} + +impl Example for VoterGroup { + fn example() -> Self { + Self { + group: Some(VoterGroupId::Direct), + voting_token: Some("voting_token id".to_string()), + } + } +} + +impl TryFrom for VoterGroup { + type Error = String; + fn try_from(value: event_db::types::objective::VoterGroup) -> Result { + let group = if let Some(group) = value.group { + Some(group.try_into()?) + } else { + None + }; + Ok(Self { + group, + voting_token: value.voting_token, + }) + } +} From 2628a133a00a356a18422b167e20e56b7229eb21 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 12:20:03 +0300 Subject: [PATCH 27/37] update --- .../src/service/common/objects/delegate_public_key.rs | 2 ++ .../src/service/common/objects/voting_public_key.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cat-data-service/src/service/common/objects/delegate_public_key.rs b/src/cat-data-service/src/service/common/objects/delegate_public_key.rs index b422e94a6d..afac19c750 100644 --- a/src/cat-data-service/src/service/common/objects/delegate_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/delegate_public_key.rs @@ -2,6 +2,8 @@ //! use poem_openapi::{types::Example, Object}; +/// A Delegate Public ED25519 Key (as registered in their most recent valid +/// [CIP-36](https://cips.cardano.org/cips/cip36) registration). #[derive(Object)] #[oai(example = true)] pub(crate) struct DelegatePublicKey { diff --git a/src/cat-data-service/src/service/common/objects/voting_public_key.rs b/src/cat-data-service/src/service/common/objects/voting_public_key.rs index c153af53cc..3e1bd5dbce 100644 --- a/src/cat-data-service/src/service/common/objects/voting_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/voting_public_key.rs @@ -3,12 +3,14 @@ use poem_openapi::{types::Example, NewType}; use serde::Deserialize; +/// A Voters Public ED25519 Key (as registered in their most recent valid +/// [CIP-15](https://cips.cardano.org/cips/cip15) or [CIP-36](https://cips.cardano.org/cips/cip36) registration). #[derive(NewType, Deserialize)] #[oai(example = true)] pub(crate) struct VotingPublicKey(pub String); impl Example for VotingPublicKey { fn example() -> Self { - Self("a6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663".into()) + Self("0xa6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663".into()) } } From 3ffb57aac32a6eebdf9b419ffca5a05a2ecd2414 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 12:22:51 +0300 Subject: [PATCH 28/37] add docs --- src/cat-data-service/src/service/api/health/mod.rs | 3 +++ src/cat-data-service/src/service/api/registration/mod.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 04022feeb2..0200feeeb6 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -1,3 +1,6 @@ +//! Health endpoints, which return the status of the service. +//! Mostly used by Grafana. +//! use crate::service::common::tags::ApiTags; use poem_openapi::OpenApi; diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index 40bf32b3a7..defc4e607b 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -1,3 +1,5 @@ +//! Registration endpoints, which return relevant voter's registration information. +//! use crate::service::common::objects::{ event_id::EventId, voter_registration::VoterRegistration, voting_public_key::VotingPublicKey, }; From e514e6a20a37a9ce3bcbb46e94315009db7d8003 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 13:02:10 +0300 Subject: [PATCH 29/37] update --- .../src/service/api/health/mod.rs | 2 +- .../src/service/api/registration/mod.rs | 2 +- .../common/objects/delegate_public_key.rs | 2 +- .../common/objects/delegator_address.rs | 22 ---------- .../src/service/common/objects/event_id.rs | 2 +- .../src/service/common/objects/mod.rs | 3 -- .../src/service/common/objects/objective.rs | 3 ++ .../common/objects/objective_details.rs | 3 ++ .../service/common/objects/objective_id.rs | 3 ++ .../common/objects/objective_summary.rs | 3 ++ .../service/common/objects/objective_type.rs | 3 ++ .../service/common/objects/objective_types.rs | 2 + .../service/common/objects/reward_currency.rs | 2 + .../common/objects/reward_definition.rs | 3 ++ .../common/objects/stake_public_key.rs | 2 +- .../src/service/common/objects/voter.rs | 44 ------------------- .../src/service/common/objects/voter_group.rs | 4 ++ .../src/service/common/objects/voter_info.rs | 2 +- .../common/objects/voter_registration.rs | 3 +- .../src/service/common/objects/voting_key.rs | 12 ----- .../common/objects/voting_public_key.rs | 2 +- 21 files changed, 35 insertions(+), 89 deletions(-) delete mode 100644 src/cat-data-service/src/service/common/objects/delegator_address.rs delete mode 100644 src/cat-data-service/src/service/common/objects/voter.rs delete mode 100644 src/cat-data-service/src/service/common/objects/voting_key.rs diff --git a/src/cat-data-service/src/service/api/health/mod.rs b/src/cat-data-service/src/service/api/health/mod.rs index 0200feeeb6..edca4712eb 100644 --- a/src/cat-data-service/src/service/api/health/mod.rs +++ b/src/cat-data-service/src/service/api/health/mod.rs @@ -1,6 +1,6 @@ //! Health endpoints, which return the status of the service. //! Mostly used by Grafana. -//! +//! use crate::service::common::tags::ApiTags; use poem_openapi::OpenApi; diff --git a/src/cat-data-service/src/service/api/registration/mod.rs b/src/cat-data-service/src/service/api/registration/mod.rs index defc4e607b..0191fcd88b 100644 --- a/src/cat-data-service/src/service/api/registration/mod.rs +++ b/src/cat-data-service/src/service/api/registration/mod.rs @@ -1,5 +1,5 @@ //! Registration endpoints, which return relevant voter's registration information. -//! +//! use crate::service::common::objects::{ event_id::EventId, voter_registration::VoterRegistration, voting_public_key::VotingPublicKey, }; diff --git a/src/cat-data-service/src/service/common/objects/delegate_public_key.rs b/src/cat-data-service/src/service/common/objects/delegate_public_key.rs index afac19c750..3a01893664 100644 --- a/src/cat-data-service/src/service/common/objects/delegate_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/delegate_public_key.rs @@ -1,4 +1,4 @@ -//! Define the Public Key used by a Delegate. +//! Defines the Public Key used by a Delegate. //! use poem_openapi::{types::Example, Object}; diff --git a/src/cat-data-service/src/service/common/objects/delegator_address.rs b/src/cat-data-service/src/service/common/objects/delegator_address.rs deleted file mode 100644 index e9eb7e3e68..0000000000 --- a/src/cat-data-service/src/service/common/objects/delegator_address.rs +++ /dev/null @@ -1,22 +0,0 @@ -use poem_openapi::{types::Example, Object}; - -#[derive(Object)] -pub(crate) struct DelegatorAddress { - #[oai(validator(pattern = "[0-9a-f]{64}"))] - address: String, -} - -impl From for DelegatorAddress { - fn from(address: String) -> Self { - Self { address } - } -} - -impl Example for DelegatorAddress { - fn example() -> Self { - Self { - address: "0xad4b948699193634a39dd56f779a2951a24779ad52aa7916f6912b8ec4702cee" - .to_string(), - } - } -} diff --git a/src/cat-data-service/src/service/common/objects/event_id.rs b/src/cat-data-service/src/service/common/objects/event_id.rs index e79bd4c6e8..f02b4a61ec 100644 --- a/src/cat-data-service/src/service/common/objects/event_id.rs +++ b/src/cat-data-service/src/service/common/objects/event_id.rs @@ -1,4 +1,4 @@ -//! Define the ID of an Event +//! Defines the ID of an Event. //! use poem_openapi::{types::Example, NewType}; use serde::Deserialize; diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index fad0a107db..6cc72c5893 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,6 +1,5 @@ //! This module contains common and re-usable objects. pub(crate) mod delegate_public_key; -pub(crate) mod delegator_address; pub(crate) mod event_id; pub(crate) mod objective; pub(crate) mod objective_details; @@ -11,10 +10,8 @@ pub(crate) mod objective_types; pub(crate) mod reward_currency; pub(crate) mod reward_definition; pub(crate) mod stake_public_key; -pub(crate) mod voter; pub(crate) mod voter_group; pub(crate) mod voter_group_id; pub(crate) mod voter_info; pub(crate) mod voter_registration; -pub(crate) mod voting_key; pub(crate) mod voting_public_key; diff --git a/src/cat-data-service/src/service/common/objects/objective.rs b/src/cat-data-service/src/service/common/objects/objective.rs index cb2b79a2a2..5ec4b6bfef 100644 --- a/src/cat-data-service/src/service/common/objects/objective.rs +++ b/src/cat-data-service/src/service/common/objects/objective.rs @@ -1,8 +1,11 @@ +//! Defines the full objective information. +//! use super::{objective_details::ObjectiveDetails, objective_summary::ObjectiveSummary}; use poem_openapi::{types::Example, Object}; /// Full Objective info. #[derive(Object)] +#[oai(example = true)] pub(crate) struct Objective { #[oai(flatten)] summary: ObjectiveSummary, diff --git a/src/cat-data-service/src/service/common/objects/objective_details.rs b/src/cat-data-service/src/service/common/objects/objective_details.rs index 8b83c111f8..e41c53fa15 100644 --- a/src/cat-data-service/src/service/common/objects/objective_details.rs +++ b/src/cat-data-service/src/service/common/objects/objective_details.rs @@ -1,8 +1,11 @@ +//! Defines the objective details. +//! use super::{reward_definition::RewardDefiniton, voter_group::VoterGroup}; use poem_openapi::{types::Example, Object}; use serde_json::Value; #[derive(Object)] +#[oai(example = true)] pub(crate) struct ObjectiveDetails { /// The valid voter groups for this voting event. groups: Vec, diff --git a/src/cat-data-service/src/service/common/objects/objective_id.rs b/src/cat-data-service/src/service/common/objects/objective_id.rs index 1635196985..d55c89a682 100644 --- a/src/cat-data-service/src/service/common/objects/objective_id.rs +++ b/src/cat-data-service/src/service/common/objects/objective_id.rs @@ -1,8 +1,11 @@ +//! Defines the ID of an objective. +//! use poem_openapi::{types::Example, NewType}; use serde::Deserialize; /// The Numeric ID of an Objective to be decided in a Voting Event. #[derive(NewType, Deserialize)] +#[oai(example = true)] pub(crate) struct ObjectiveId(i32); impl Example for ObjectiveId { diff --git a/src/cat-data-service/src/service/common/objects/objective_summary.rs b/src/cat-data-service/src/service/common/objects/objective_summary.rs index 1379d1997d..61b51ebd30 100644 --- a/src/cat-data-service/src/service/common/objects/objective_summary.rs +++ b/src/cat-data-service/src/service/common/objects/objective_summary.rs @@ -1,8 +1,11 @@ +//! Defines the objective summary. +//! use super::{objective_id::ObjectiveId, objective_type::ObjectiveType}; use poem_openapi::{types::Example, Object}; /// Summary off an Individual Objective. #[derive(Object)] +#[oai(example = true)] pub(crate) struct ObjectiveSummary { /// The ID of this objective for the Voting Event. #[oai(validator(minimum(value = "0")))] diff --git a/src/cat-data-service/src/service/common/objects/objective_type.rs b/src/cat-data-service/src/service/common/objects/objective_type.rs index 99084c6d61..b91d46ae8b 100644 --- a/src/cat-data-service/src/service/common/objects/objective_type.rs +++ b/src/cat-data-service/src/service/common/objects/objective_type.rs @@ -1,8 +1,11 @@ +//! Defines the objective type definition. +//! use super::objective_types::ObjectiveTypes; use poem_openapi::{types::Example, Object}; /// Objective type definition. #[derive(Object)] +#[oai(example = true)] pub(crate) struct ObjectiveType { id: ObjectiveTypes, diff --git a/src/cat-data-service/src/service/common/objects/objective_types.rs b/src/cat-data-service/src/service/common/objects/objective_types.rs index c6e2ee44d9..be79a055e0 100644 --- a/src/cat-data-service/src/service/common/objects/objective_types.rs +++ b/src/cat-data-service/src/service/common/objects/objective_types.rs @@ -1,3 +1,5 @@ +//! Defines the objective types. +//! use poem_openapi::{types::Example, Enum}; /// Objective Type defines the rules of the objective. diff --git a/src/cat-data-service/src/service/common/objects/reward_currency.rs b/src/cat-data-service/src/service/common/objects/reward_currency.rs index bc90abc92e..918810d4d5 100644 --- a/src/cat-data-service/src/service/common/objects/reward_currency.rs +++ b/src/cat-data-service/src/service/common/objects/reward_currency.rs @@ -1,3 +1,5 @@ +//! Defines the currency of a reward. +//! use poem_openapi::{types::Example, Enum}; /// Currency of the Reward. diff --git a/src/cat-data-service/src/service/common/objects/reward_definition.rs b/src/cat-data-service/src/service/common/objects/reward_definition.rs index c1950d8ecf..05f084e285 100644 --- a/src/cat-data-service/src/service/common/objects/reward_definition.rs +++ b/src/cat-data-service/src/service/common/objects/reward_definition.rs @@ -1,8 +1,11 @@ +//! Defines the reward definition. +//! use super::reward_currency::RewardCurrency; use poem_openapi::{types::Example, Object}; /// Represents a reward definition. #[derive(Object)] +#[oai(example = true)] pub(crate) struct RewardDefiniton { /// Currency of the Reward. currency: RewardCurrency, diff --git a/src/cat-data-service/src/service/common/objects/stake_public_key.rs b/src/cat-data-service/src/service/common/objects/stake_public_key.rs index db31c4f919..2fdfb15d81 100644 --- a/src/cat-data-service/src/service/common/objects/stake_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/stake_public_key.rs @@ -1,4 +1,4 @@ -//! Define the Stake Public Key type +//! Defines the Stake Public Key type //! use poem_openapi::{types::Example, NewType}; use serde::Deserialize; diff --git a/src/cat-data-service/src/service/common/objects/voter.rs b/src/cat-data-service/src/service/common/objects/voter.rs deleted file mode 100644 index 945e08bf1b..0000000000 --- a/src/cat-data-service/src/service/common/objects/voter.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::voter_info::VoterInfo; -use chrono::{DateTime, Utc}; -use poem_openapi::{types::Example, Object}; - -/// Voter -#[derive(Object)] -#[oai(example = true)] -pub(crate) struct Voter { - voter_info: VoterInfo, - - /// Date and time the latest snapshot represents. - as_at: DateTime, - - /// Date and time for the latest update to this snapshot information. - last_updated: DateTime, - - /// `True` - this is the final snapshot which will be used for voting power in the event. - /// `False` - this is an interim snapshot, subject to change. - #[oai(rename = "final")] - is_final: bool, -} - -impl Example for Voter { - fn example() -> Self { - Self { - voter_info: VoterInfo::example(), - as_at: Utc::now(), - last_updated: Utc::now(), - is_final: true, - } - } -} - -impl TryFrom for Voter { - type Error = String; - fn try_from(value: event_db::types::registration::Voter) -> Result { - Ok(Self { - voter_info: value.voter_info.try_into()?, - as_at: value.as_at, - last_updated: value.last_updated, - is_final: value.is_final, - }) - } -} diff --git a/src/cat-data-service/src/service/common/objects/voter_group.rs b/src/cat-data-service/src/service/common/objects/voter_group.rs index 78e7d03348..e37fc8192a 100644 --- a/src/cat-data-service/src/service/common/objects/voter_group.rs +++ b/src/cat-data-service/src/service/common/objects/voter_group.rs @@ -1,7 +1,11 @@ +//! Defines the voter group details. +//! use super::voter_group_id::VoterGroupId; use poem_openapi::{types::Example, Object}; +/// Voter group details. #[derive(Object)] +#[oai(example = true)] pub(crate) struct VoterGroup { #[oai(skip_serializing_if_is_none = true)] group: Option, diff --git a/src/cat-data-service/src/service/common/objects/voter_info.rs b/src/cat-data-service/src/service/common/objects/voter_info.rs index 66eb22d65d..991f016b1e 100644 --- a/src/cat-data-service/src/service/common/objects/voter_info.rs +++ b/src/cat-data-service/src/service/common/objects/voter_info.rs @@ -1,4 +1,4 @@ -//! Define individual Voter Information +//! Defines individual Voter Information //! use super::{delegate_public_key::DelegatePublicKey, voter_group_id::VoterGroupId}; use poem_openapi::{types::Example, Object}; diff --git a/src/cat-data-service/src/service/common/objects/voter_registration.rs b/src/cat-data-service/src/service/common/objects/voter_registration.rs index e3091e5daa..ffc1ac61c6 100644 --- a/src/cat-data-service/src/service/common/objects/voter_registration.rs +++ b/src/cat-data-service/src/service/common/objects/voter_registration.rs @@ -1,4 +1,5 @@ -//! Define information about the Voters Registration. +//! Defines information about the Voters Registration. +//! use super::voter_info::VoterInfo; use chrono::{DateTime, Utc}; use poem_openapi::{types::Example, Object}; diff --git a/src/cat-data-service/src/service/common/objects/voting_key.rs b/src/cat-data-service/src/service/common/objects/voting_key.rs deleted file mode 100644 index 2fc4defdb8..0000000000 --- a/src/cat-data-service/src/service/common/objects/voting_key.rs +++ /dev/null @@ -1,12 +0,0 @@ -use poem_openapi::{types::Example, NewType}; -use serde::Deserialize; - -#[derive(NewType, Deserialize)] -#[oai(example = true)] -pub(crate) struct VotingKey(pub String); - -impl Example for VotingKey { - fn example() -> Self { - Self("a6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663".into()) - } -} diff --git a/src/cat-data-service/src/service/common/objects/voting_public_key.rs b/src/cat-data-service/src/service/common/objects/voting_public_key.rs index 3e1bd5dbce..c75d032e8a 100644 --- a/src/cat-data-service/src/service/common/objects/voting_public_key.rs +++ b/src/cat-data-service/src/service/common/objects/voting_public_key.rs @@ -1,4 +1,4 @@ -//! Define the Voters Public Key +//! Defines the Voters Public Key //! use poem_openapi::{types::Example, NewType}; use serde::Deserialize; From 67b148f933538ee859806096fd9140ef5b82ca89 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 13:38:54 +0300 Subject: [PATCH 30/37] update voting_token docs --- src/cat-data-service/src/service/common/objects/voter_group.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cat-data-service/src/service/common/objects/voter_group.rs b/src/cat-data-service/src/service/common/objects/voter_group.rs index e37fc8192a..17c432007e 100644 --- a/src/cat-data-service/src/service/common/objects/voter_group.rs +++ b/src/cat-data-service/src/service/common/objects/voter_group.rs @@ -13,6 +13,7 @@ pub(crate) struct VoterGroup { /// The identifier of voting power token used withing this group. /// All vote plans within a group are guaranteed to use the same token. #[oai(skip_serializing_if_is_none = true)] + #[oai(validator(max_length = 121, min_length = 59, pattern = r"[0-9a-f]{56}\.[0-9a-f]{2,64}"))] voting_token: Option, } @@ -20,7 +21,7 @@ impl Example for VoterGroup { fn example() -> Self { Self { group: Some(VoterGroupId::Direct), - voting_token: Some("voting_token id".to_string()), + voting_token: Some("134c2d0a0b5761445d3f2d08492a5c193e3a19194453511426153630.0418401957301613".to_string()), } } } From 0d133bc5172f2278fb91e052a56675d898d338d5 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 13:52:58 +0300 Subject: [PATCH 31/37] remove poem_types::objective module --- src/cat-data-service/src/poem_types/mod.rs | 1 - .../src/poem_types/objective.rs | 152 ------------------ 2 files changed, 153 deletions(-) delete mode 100644 src/cat-data-service/src/poem_types/objective.rs diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs index cb6d51d5cd..7b6ab5fe96 100644 --- a/src/cat-data-service/src/poem_types/mod.rs +++ b/src/cat-data-service/src/poem_types/mod.rs @@ -1,5 +1,4 @@ pub mod ballot; pub mod event; -pub mod objective; pub mod proposal; pub mod registration; diff --git a/src/cat-data-service/src/poem_types/objective.rs b/src/cat-data-service/src/poem_types/objective.rs deleted file mode 100644 index 0e487883e5..0000000000 --- a/src/cat-data-service/src/poem_types/objective.rs +++ /dev/null @@ -1,152 +0,0 @@ -use super::registration::VoterGroupId; -use poem_openapi::{NewType, Object}; -use serde::Deserialize; -use serde_json::Value; - -/// The Numeric ID of an Objective to be decided in a Voting Event. -#[derive(NewType, Deserialize)] -pub struct ObjectiveId(i32); - -impl From for ObjectiveId { - fn from(value: event_db::types::objective::ObjectiveId) -> Self { - Self(value.0) - } -} - -#[derive(Object)] -pub struct ObjectiveType { - /// Objective Type defines the rules of the objective. - id: String, - - /// An explanaiton of the rules of this Objective Type. - description: String, -} - -impl From for ObjectiveType { - fn from(value: event_db::types::objective::ObjectiveType) -> Self { - Self { - id: value.id, - description: value.description, - } - } -} - -/// Summary off an Individual Objective. -#[derive(Object)] -pub struct ObjectiveSummary { - /// The ID of this objective for the Voting Event. - id: ObjectiveId, - - /// The "Type" of Objective - #[oai(rename = "type")] - objective_type: ObjectiveType, - - /// The title for this Objective. - title: String, - - /// Long form explanation of this particular objective. - /// *May contain HTML Markup.* - /// *May contain Links to external content or assets.* - description: String, - - /// Whether this Objective has been deleted or not. - deleted: bool, -} - -impl From for ObjectiveSummary { - fn from(value: event_db::types::objective::ObjectiveSummary) -> Self { - Self { - id: value.id.into(), - objective_type: value.objective_type.into(), - title: value.title, - description: value.description, - deleted: value.deleted, - } - } -} - -#[derive(Object)] -pub struct RewardDefinition { - /// Currency of the Reward. - currency: String, - - /// The total value of the reward - value: i64, -} - -impl From for RewardDefinition { - fn from(value: event_db::types::objective::RewardDefinition) -> Self { - Self { - currency: value.currency, - value: value.value, - } - } -} - -#[derive(Object)] -pub struct VoterGroup { - #[oai(skip_serializing_if_is_none = true)] - group: Option, - - /// The identifier of voting power token used withing this group. - /// All vote plans within a group are guaranteed to use the same token. - #[oai(skip_serializing_if_is_none = true)] - voting_token: Option, -} - -impl From for VoterGroup { - fn from(value: event_db::types::objective::VoterGroup) -> Self { - Self { - group: value.group.map(Into::into), - voting_token: value.voting_token, - } - } -} - -/// Individual Objective Details -#[derive(Object)] -pub struct ObjectiveDetails { - /// The valid voter groups for this voting event. - groups: Vec, - - /// The Total Reward being offered for this Objective. - /// Distribution of the Reward is determined under the rules of this Objective. - /// If this field is not present there is no reward being offered for the Objective. - #[oai(skip_serializing_if_is_none = true)] - reward: Option, - - /// Objective Supplemental Data - /// - /// Extra Data which can be used to enrich the information shared about the Objective. - /// All Information here is optional. - /// If there is no supplemental information for the Objective this field is omitted. - #[oai(skip_serializing_if_is_none = true)] - supplemental: Option, -} - -impl From for ObjectiveDetails { - fn from(value: event_db::types::objective::ObjectiveDetails) -> Self { - Self { - groups: value.groups.into_iter().map(Into::into).collect(), - reward: value.reward.map(Into::into), - supplemental: value.supplemental, - } - } -} - -#[derive(Object)] -pub struct Objective { - #[oai(flatten)] - summary: ObjectiveSummary, - #[oai(flatten)] - details: ObjectiveDetails, -} - -impl From for Objective { - fn from(value: event_db::types::objective::Objective) -> Self { - Self { - summary: value.summary.into(), - details: value.details.into(), - } - } -} From 9745836d6f2e4db0a2f11aa724eeeac6eaa22aac Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 19 Sep 2023 17:51:17 +0300 Subject: [PATCH 32/37] fix fmt --- .../src/service/common/objects/voter_group.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cat-data-service/src/service/common/objects/voter_group.rs b/src/cat-data-service/src/service/common/objects/voter_group.rs index 17c432007e..572847c3e0 100644 --- a/src/cat-data-service/src/service/common/objects/voter_group.rs +++ b/src/cat-data-service/src/service/common/objects/voter_group.rs @@ -13,7 +13,11 @@ pub(crate) struct VoterGroup { /// The identifier of voting power token used withing this group. /// All vote plans within a group are guaranteed to use the same token. #[oai(skip_serializing_if_is_none = true)] - #[oai(validator(max_length = 121, min_length = 59, pattern = r"[0-9a-f]{56}\.[0-9a-f]{2,64}"))] + #[oai(validator( + max_length = 121, + min_length = 59, + pattern = r"[0-9a-f]{56}\.[0-9a-f]{2,64}" + ))] voting_token: Option, } @@ -21,7 +25,10 @@ impl Example for VoterGroup { fn example() -> Self { Self { group: Some(VoterGroupId::Direct), - voting_token: Some("134c2d0a0b5761445d3f2d08492a5c193e3a19194453511426153630.0418401957301613".to_string()), + voting_token: Some( + "134c2d0a0b5761445d3f2d08492a5c193e3a19194453511426153630.0418401957301613" + .to_string(), + ), } } } From 6a8b0d9d32040e5643993a3263cdf2cba99a37dc Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 25 Sep 2023 13:13:33 +0300 Subject: [PATCH 33/37] remove poem_types module --- src/cat-data-service/src/poem_types/ballot.rs | 66 ----- src/cat-data-service/src/poem_types/event.rs | 276 ------------------ src/cat-data-service/src/poem_types/mod.rs | 4 - .../src/poem_types/proposal.rs | 120 -------- .../src/poem_types/registration.rs | 169 ----------- .../src/poem_types/reviews.rs | 106 ------- 6 files changed, 741 deletions(-) delete mode 100644 src/cat-data-service/src/poem_types/ballot.rs delete mode 100644 src/cat-data-service/src/poem_types/event.rs delete mode 100644 src/cat-data-service/src/poem_types/mod.rs delete mode 100644 src/cat-data-service/src/poem_types/proposal.rs delete mode 100644 src/cat-data-service/src/poem_types/registration.rs delete mode 100644 src/cat-data-service/src/poem_types/reviews.rs diff --git a/src/cat-data-service/src/poem_types/ballot.rs b/src/cat-data-service/src/poem_types/ballot.rs deleted file mode 100644 index 09542683dc..0000000000 --- a/src/cat-data-service/src/poem_types/ballot.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::registration::VoterGroupId; -use poem_openapi::{NewType, Object}; -use serde::Deserialize; - -/// The kind of ballot to be cast on this Objective. -/// * `public` - All Ballots are public when cast. -/// * `private` - All Ballots are private. -/// * `cast-private` - All Ballots are cast privately but become public after the tally. -#[derive(NewType, Deserialize)] -pub struct BallotType(String); - -impl From for BallotType { - fn from(value: event_db::types::ballot::BallotType) -> Self { - Self(value.0) - } -} - -/// The voteplan to use for this group. -#[derive(Object)] -pub struct VotePlan { - /// The Index of the proposal, needed to create a ballot for it. - chain_proposal_index: i64, - - /// The name of the group. - #[oai(skip_serializing_if_is_none = true)] - group: Option, - - /// The type of ballot this group must cast. - ballot_type: BallotType, - - /// Blockchain ID of the vote plan transaction. - chain_voteplan_id: String, - - /// The public encryption key used. ONLY if required by the ballot type (private, cast-private). - #[oai(skip_serializing_if_is_none = true)] - encryption_key: Option, -} - -impl From for VotePlan { - fn from(value: event_db::types::ballot::VotePlan) -> Self { - Self { - chain_proposal_index: value.chain_proposal_index, - group: value.group.map(Into::into), - ballot_type: value.ballot_type.into(), - chain_voteplan_id: value.chain_voteplan_id, - encryption_key: value.encryption_key, - } - } -} - -/// Details necessary to complete a ballot for the specific proposal and objective. -#[derive(Object)] -pub struct Ballot { - /// Ballot Choices present for all proposals in this Objective. - /// - /// Ordered list of choices available for all proposals in this Objective. - /// The offset into the array is the index of the choice. - /// For example, the first element is Choice 0, second is Choice 1 and so on. - choices: Vec, - - /// List of groups and the voteplans they use when voting on this proposal. - /// Each valid group for this Objective: - /// * Must be listed. - /// * Must not be repeated. - voteplans: Vec, -} diff --git a/src/cat-data-service/src/poem_types/event.rs b/src/cat-data-service/src/poem_types/event.rs deleted file mode 100644 index 34eb085a06..0000000000 --- a/src/cat-data-service/src/poem_types/event.rs +++ /dev/null @@ -1,276 +0,0 @@ -use chrono::{DateTime, Utc}; -use poem_openapi::{Enum, NewType, Object}; -use rust_decimal::prelude::ToPrimitive; -use serde::Deserialize; - -/// The Numeric ID of a Voting Event. -#[derive(NewType, Deserialize)] -pub struct EventId(i32); - -impl From for event_db::types::event::EventId { - fn from(event_id: EventId) -> Self { - event_db::types::event::EventId(event_id.0) - } -} - -impl From for EventId { - fn from(event_id: event_db::types::event::EventId) -> Self { - Self(event_id.0) - } -} - -/// The Name of a Voting Event. -#[derive(NewType)] -pub struct EventName(String); - -/// A Summary of an individual Voting Event. -#[derive(Object)] -pub struct EventSummary { - id: EventId, - name: EventName, - - /// Date-Time when the Voting Event commences. - #[oai(skip_serializing_if_is_none = true)] - starts: Option>, - - /// Date-Time when the Voting Event is expected to finish. - #[oai(skip_serializing_if_is_none = true)] - ends: Option>, - - /// Last time registrations and Voting power were checked. - /// If not present, no registration or voting power records exist for this event. - #[oai(skip_serializing_if_is_none = true)] - reg_checked: Option>, - - /// True if the event is finished and no changes can be made to it. - /// Does not Including payment of rewards or funding of projects. - #[oai(rename = "final")] - is_final: bool, -} - -impl From for EventSummary { - fn from(value: event_db::types::event::EventSummary) -> Self { - Self { - id: value.id.into(), - name: EventName(value.name), - starts: value.starts.map(Into::into), - ends: value.ends.map(Into::into), - reg_checked: value.reg_checked.map(Into::into), - is_final: value.is_final, - } - } -} - -/// The Voting Power Algorithm. -#[derive(Enum)] -pub enum VotingPowerAlgorithm { - /// Linear Voting Power in Staked ADA, With a minimum limit and maximum relative threshold. - #[oai(rename = "threshold_staked_ADA")] - ThresholdStakedADA, -} - -impl From for VotingPowerAlgorithm { - fn from(value: event_db::types::event::VotingPowerAlgorithm) -> Self { - match value { - event_db::types::event::VotingPowerAlgorithm::ThresholdStakedADA => { - VotingPowerAlgorithm::ThresholdStakedADA - } - } - } -} - -/// The Settings Used to configure the voting power calculation. -#[derive(Object)] -pub struct VotingPowerSettings { - alg: VotingPowerAlgorithm, - - /// Minimum staked funds required for a valid voter registration. - /// This amount is in Whole ADA. If not present, there is no minimum. - /// - /// Valid for `alg`: - /// * `threshold_staked_ADA` - #[oai(skip_serializing_if_is_none = true)] - min_ada: Option, - - /// Maximum Percentage of total registered voting power allowed for voting power. - /// For example `1.23` = `1.23%` of total registered staked ADA as maximum voting power. - /// If not present, there is no maximum percentage. - /// - /// Valid for `alg`: - /// * `threshold_staked_ADA` - #[oai(skip_serializing_if_is_none = true)] - max_pct: Option, -} - -impl TryFrom for VotingPowerSettings { - type Error = String; - fn try_from(value: event_db::types::event::VotingPowerSettings) -> Result { - Ok(Self { - alg: value.alg.into(), - min_ada: value.min_ada, - max_pct: if let Some(max_pct) = value.max_pct { - Some( - max_pct - .to_f64() - .ok_or_else(|| format!("cannot convert decimal to f64: {}", max_pct))?, - ) - } else { - None - }, - }) - } -} - -/// Details about Voting Event Registration. -#[derive(Object)] -pub struct EventRegistration { - /// The Registration Purpose. - #[oai(skip_serializing_if_is_none = true)] - purpose: Option, - - /// The deadline for Registration/Voting Power to be fixed. - /// Changes to Registrations or Voting power after this time are not considered. - #[oai(skip_serializing_if_is_none = true)] - deadline: Option>, - - /// The time after which Final Registration/Voting Power will be calculated. - /// This is usually after the deadline, to allow for potential instability in the head of the blockchain to stabilize. - #[oai(skip_serializing_if_is_none = true)] - taken: Option>, -} - -impl From for EventRegistration { - fn from(value: event_db::types::event::EventRegistration) -> Self { - Self { - purpose: value.purpose, - deadline: value.deadline.map(Into::into), - taken: value.taken.map(Into::into), - } - } -} - -/// An Individual Event Goal. -#[derive(Object)] -pub struct EventGoal { - /// The Relative order of this Goal. 0 being highest. - idx: i32, - - /// The name/short description of the goal. - name: String, -} - -impl From for EventGoal { - fn from(value: event_db::types::event::EventGoal) -> Self { - Self { - idx: value.idx, - name: value.name, - } - } -} - -/// The chronological sequence of stages of the voting event. -/// Stages run chronologically and only 1 stage can run at a time. -/// Each new stage terminates the previous stage. -/// Any omitted entries are assumed to not exist as a stage in this event. -#[derive(Object)] -pub struct EventSchedule { - /// Date-Time when Insight Sharing Starts. - #[oai(skip_serializing_if_is_none = true)] - insight_sharing: Option>, - - /// Date-Time when Proposals can be submitted to the Voting Event. - #[oai(skip_serializing_if_is_none = true)] - proposal_submission: Option>, - - /// Date-Time when Proposal refinement begins. - #[oai(skip_serializing_if_is_none = true)] - refine_proposals: Option>, - - /// Date-Time when Proposal Finalization starts. - #[oai(skip_serializing_if_is_none = true)] - finalize_proposals: Option>, - - /// Date-Time when Proposal Assessment starts. - #[oai(skip_serializing_if_is_none = true)] - proposal_assessment: Option>, - - /// Date-Time when Assessment QA starts. - #[oai(skip_serializing_if_is_none = true)] - assessment_qa_start: Option>, - - /// Date-Time when Voting commences. - #[oai(skip_serializing_if_is_none = true)] - voting: Option>, - - /// Date-Time when Voting ends and tallying commences. - #[oai(skip_serializing_if_is_none = true)] - tallying: Option>, - - /// Date-Time when Tallying Ends. - #[oai(skip_serializing_if_is_none = true)] - tallying_end: Option>, -} - -impl From for EventSchedule { - fn from(value: event_db::types::event::EventSchedule) -> Self { - Self { - insight_sharing: value.insight_sharing.map(Into::into), - proposal_submission: value.proposal_submission.map(Into::into), - refine_proposals: value.refine_proposals.map(Into::into), - finalize_proposals: value.finalize_proposals.map(Into::into), - proposal_assessment: value.proposal_assessment.map(Into::into), - assessment_qa_start: value.assessment_qa_start.map(Into::into), - voting: value.voting.map(Into::into), - tallying: value.tallying.map(Into::into), - tallying_end: value.tallying_end.map(Into::into), - } - } -} - -/// Detailed information for an individual voting event. -#[derive(Object)] -pub struct EventDetails { - /// How Voting Power is Calculated and its parameters. - voting_power_settings: VotingPowerSettings, - - /// Registration deadlines and when its finalized. Plus any other parameters. - registration: EventRegistration, - - /// The schedule of the voting Event. - schedule: EventSchedule, - - /// Description of the voting events goals. - /// If this field is not present, there are no listed goals for the event. - goals: Vec, -} - -impl TryFrom for EventDetails { - type Error = String; - fn try_from(value: event_db::types::event::EventDetails) -> Result { - Ok(Self { - voting_power_settings: value.voting_power.try_into()?, - registration: value.registration.into(), - schedule: value.schedule.into(), - goals: value.goals.into_iter().map(Into::into).collect(), - }) - } -} - -/// Complete Details about an individual Voting Event. -#[derive(Object)] -pub struct Event { - #[oai(flatten)] - summary: EventSummary, - #[oai(flatten)] - details: EventDetails, -} - -impl TryFrom for Event { - type Error = String; - fn try_from(value: event_db::types::event::Event) -> Result { - Ok(Self { - summary: value.summary.into(), - details: value.details.try_into()?, - }) - } -} diff --git a/src/cat-data-service/src/poem_types/mod.rs b/src/cat-data-service/src/poem_types/mod.rs deleted file mode 100644 index 7b6ab5fe96..0000000000 --- a/src/cat-data-service/src/poem_types/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod ballot; -pub mod event; -pub mod proposal; -pub mod registration; diff --git a/src/cat-data-service/src/poem_types/proposal.rs b/src/cat-data-service/src/poem_types/proposal.rs deleted file mode 100644 index 17391abe1a..0000000000 --- a/src/cat-data-service/src/poem_types/proposal.rs +++ /dev/null @@ -1,120 +0,0 @@ -use poem_openapi::{NewType, Object}; -use serde::Deserialize; -use serde_json::Value; - -#[derive(NewType, Deserialize)] -pub struct ProposalId(i32); - -impl From for ProposalId { - fn from(value: event_db::types::proposal::ProposalId) -> Self { - Self(value.0) - } -} - -/// Summary of a Proposal for an Objective. -#[derive(Object)] -pub struct ProposalSummary { - /// The ID of this proposal. - id: ProposalId, - - /// Short title of the proposal. - title: String, - - /// Brief description of the proposal. - summary: String, - - /// Whether this Proposal has been deleted or not. - deleted: bool, -} - -impl From for ProposalSummary { - fn from(value: event_db::types::proposal::ProposalSummary) -> Self { - Self { - id: value.id.into(), - title: value.title, - summary: value.summary, - deleted: value.deleted, - } - } -} - -/// Details about a proposer for a particular proposal. -#[derive(Object)] -pub struct ProposerDetails { - /// Name of the author/s of the proposal. - name: String, - - /// Email contact address of the author's of the proposal. - /// If not present, there is no known contact email for the authors. - email: String, - - /// URL to a web resource with details about the author's of the proposal. - url: String, - - /// The Payment Address the Funds requested will be paid to. - /// Will not be included if the proposal does not request funds. - payment_key: String, -} - -impl From for ProposerDetails { - fn from(value: event_db::types::proposal::ProposerDetails) -> Self { - Self { - name: value.name, - email: value.email, - url: value.url, - payment_key: value.payment_key, - } - } -} - -/// Details of a particular Proposal. -#[derive(Object)] -pub struct ProposalDetails { - /// The amount of funds requested by this proposal. - /// In the denomination of the Objectives Reward. - /// If not present, then this proposal is not requesting any funds. - funds: i64, - - /// URL to a web page with details on this proposal. - url: String, - - /// Link to extra files associated with this proposal. - /// Only included if there are linked files. - files: String, - - /// List of all proposers making this proposal. - proposer: Vec, - - /// Additional Information related to the proposal. - #[oai(skip_serializing_if_is_none = true)] - supplemental: Option, -} - -impl From for ProposalDetails { - fn from(value: event_db::types::proposal::ProposalDetails) -> Self { - Self { - funds: value.funds, - url: value.url, - files: value.files, - proposer: value.proposer.into_iter().map(Into::into).collect(), - supplemental: value.supplemental, - } - } -} - -#[derive(Object)] -pub struct Proposal { - #[oai(flatten)] - summary: ProposalSummary, - #[oai(flatten)] - details: ProposalDetails, -} - -impl From for Proposal { - fn from(value: event_db::types::proposal::Proposal) -> Self { - Self { - summary: value.summary.into(), - details: value.details.into(), - } - } -} diff --git a/src/cat-data-service/src/poem_types/registration.rs b/src/cat-data-service/src/poem_types/registration.rs deleted file mode 100644 index 9803995b51..0000000000 --- a/src/cat-data-service/src/poem_types/registration.rs +++ /dev/null @@ -1,169 +0,0 @@ -use chrono::{DateTime, Utc}; -use poem_openapi::{NewType, Object}; -use serde::Deserialize; - -/// Voting Key. -#[derive(NewType, Deserialize)] -pub struct VotingKey(pub String); - -/// Voter Group ID. -/// `direct` = Direct voter. -/// `rep` = Delegated Representative. -#[derive(NewType)] -pub struct VoterGroupId(pub String); - -impl From for VoterGroupId { - fn from(value: event_db::types::registration::VoterGroupId) -> Self { - Self(value.0) - } -} - -/// Voter Info -#[derive(Object)] -pub struct VoterInfo { - /// Voter's voting power. - /// This is the true voting power, subject to minimum voting power and max cap. - voting_power: i64, - voting_group: VoterGroupId, - - /// Total voting power delegated to this voter. - /// This is not capped and not subject to minimum voting power. - delegations_power: i64, - - /// Number of registration which delegated to this voter. - delegations_count: i64, - - /// Voting power's share of the total voting power. - /// Can be used to gauge potential voting power saturation. - /// This value is NOT saturated however, and gives the raw share of total registered voting power. - voting_power_saturation: f64, - - /// List of stake public key addresses which delegated to this voting key. - #[oai(skip_serializing_if_is_none = true)] - delegator_addresses: Option>, -} - -impl From for VoterInfo { - fn from(value: event_db::types::registration::VoterInfo) -> Self { - Self { - voting_power: value.voting_power, - voting_group: value.voting_group.into(), - delegations_power: value.delegations_power, - delegations_count: value.delegations_count, - voting_power_saturation: value.voting_power_saturation, - delegator_addresses: value.delegator_addresses, - } - } -} - -/// Voter -#[derive(Object)] -pub struct Voter { - voter_info: VoterInfo, - - /// Date and time the latest snapshot represents. - as_at: DateTime, - - /// Date and time for the latest update to this snapshot information. - last_updated: DateTime, - - /// `True` - this is the final snapshot which will be used for voting power in the event. - /// `False` - this is an interim snapshot, subject to change. - #[oai(rename = "final")] - is_final: bool, -} - -impl From for Voter { - fn from(value: event_db::types::registration::Voter) -> Self { - Self { - voter_info: value.voter_info.into(), - as_at: value.as_at, - last_updated: value.last_updated, - is_final: value.is_final, - } - } -} - -/// Voter's delegation info -#[derive(Object)] -pub struct Delegation { - /// Hex encoded voting key for this delegation. - voting_key: String, - group: VoterGroupId, - - /// Relative weight assigned to this voting key. - weight: i32, - - /// Raw voting power distributed to this voting key. - value: i64, -} - -impl From for Delegation { - fn from(value: event_db::types::registration::Delegation) -> Self { - Self { - voting_key: value.voting_key, - group: value.group.into(), - weight: value.weight, - value: value.value, - } - } -} - -#[derive(Object)] -pub struct RewardAddress { - /// Reward address for this delegation. - reward_address: String, - - /// Flag which reflects does the `reward_address` valid or not, contains it "addr" or "addr_test" prefix or not. - reward_payable: bool, -} - -impl From for RewardAddress { - fn from(value: event_db::types::registration::RewardAddress) -> Self { - Self { - reward_address: value.reward_address(), - reward_payable: value.reward_payable(), - } - } -} - -#[derive(Object)] -pub struct Delegator { - /// List off delegations made by this stake address. - /// In the order as presented in the voters registration. - delegations: Vec, - - #[oai(flatten)] - reward_address: RewardAddress, - - /// Raw total voting power from stake address. - raw_power: i64, - - /// Total voting power, across all registered voters. - total_power: i64, - - /// Date and time for the latest update to this snapshot information. - as_at: DateTime, - - /// Date and time the latest snapshot represents. - last_updated: DateTime, - - /// `True` - this is the final snapshot which will be used for voting power in the event. - /// `False`- this is an interim snapshot, subject to change. - #[oai(rename = "final")] - is_final: bool, -} - -impl From for Delegator { - fn from(value: event_db::types::registration::Delegator) -> Self { - Self { - delegations: value.delegations.into_iter().map(Into::into).collect(), - reward_address: value.reward_address.into(), - raw_power: value.raw_power, - total_power: value.total_power, - as_at: value.as_at, - last_updated: value.last_updated, - is_final: value.is_final, - } - } -} diff --git a/src/cat-data-service/src/poem_types/reviews.rs b/src/cat-data-service/src/poem_types/reviews.rs deleted file mode 100644 index b36e97a369..0000000000 --- a/src/cat-data-service/src/poem_types/reviews.rs +++ /dev/null @@ -1,106 +0,0 @@ -use poem_openapi::Object; -use serde_json::Value; - -/// Details about a Type of review. -#[derive(Object)] -pub struct ReviewType { - /// The Unique ID for this review type. - id: i32, - - /// The unique name for the review type. - name: String, - - /// Description about what the review type is. - #[oai(skip_serializing_if_is_none = true)] - description: Option, - - /// The inclusive Minimum value for the reviews rating. - /// By definition, lower value ratings are considered lower ratings. - /// Therefore this field represents the lowest possible rating. - min: i32, - - /// The inclusive Maximum value for the reviews rating. - /// By definition, higher value ratings are considered higher ratings. - /// Therefore this field represents the highest possible rating. - max: i32, - - /// Optional sequential list of mapped named values for rating scores. - /// * If not present, the rating score is numeric. - /// * If present: - /// * all possible rating scores must be represented with mapped names and the rating is represented by the value in the map. - /// * The lowest numbered score comes first in the array. - /// * The array is sequential with no gaps. - map: Vec, - - /// Does the Review Type include a note? - /// * Null - *Optional*, may or may not include a note. - /// * False - **MUST NOT** include a note. - /// * True - **MUST** include a note. - #[oai(skip_serializing_if_is_none = true)] - note: Option, - - /// The reviewer group who can create this review type. - #[oai(skip_serializing_if_is_none = true)] - group: Option, -} - -impl From for ReviewType { - fn from(value: event_db::types::reviews::ReviewType) -> Self { - Self { - id: value.id, - name: value.name, - description: value.description, - min: value.min, - max: value.max, - map: value.map, - note: value.note, - group: value.group, - } - } -} - -/// Individual Rating. -#[derive(Object)] -pub struct Rating { - /// The review type being rated. Maps to the ReviewType id. - review_type: i32, - - /// Score given to this rating. - /// Will be bounded by the `min` and `max` of the ReviewType. - score: i32, - - /// Reason why this rating was given. - /// If NO reason was given, this field is omitted. - #[oai(skip_serializing_if_is_none = true)] - note: &'a Option, -} - -impl From for Rating { - fn from(value: event_db::types::reviews::Rating) -> Self { - Self { - review_type: value.review_type, - score: value.score, - note: value.note, - } - } -} - -/// Review of a Proposal by a Community Advisor. -#[derive(Object)] -pub struct AdvisorReview { - /// Anonymized Assessor identity. - /// All reviews by the same Assessor will have the same identity string. - assessor: String, - - /// List of review ratings given by this reviewer. - ratings: Vec, -} - -impl From for AdvisorReview { - fn from(value: event_db::types::reviews::AdvisorReview) -> Self { - Self { - assessor: value.assessor, - ratings: value.ratings.into_iter().map(Into::into).collect(), - } - } -} From 100fa19ecf05a7ee8774e626fca7ff6efdc68cfc Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Mon, 25 Sep 2023 13:18:13 +0300 Subject: [PATCH 34/37] fix clippy --- .../src/service/common/objects/reward_currency.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cat-data-service/src/service/common/objects/reward_currency.rs b/src/cat-data-service/src/service/common/objects/reward_currency.rs index 918810d4d5..b905c1a52c 100644 --- a/src/cat-data-service/src/service/common/objects/reward_currency.rs +++ b/src/cat-data-service/src/service/common/objects/reward_currency.rs @@ -5,12 +5,13 @@ use poem_openapi::{types::Example, Enum}; /// Currency of the Reward. #[derive(Enum)] pub(crate) enum RewardCurrency { - ADA, + #[oai(rename = "ADA")] + Ada, } impl Example for RewardCurrency { fn example() -> Self { - Self::ADA + Self::Ada } } @@ -18,7 +19,7 @@ impl TryFrom for RewardCurrency { type Error = String; fn try_from(value: String) -> Result { match value.as_str() { - "ADA" => Ok(Self::ADA), + "ADA" => Ok(Self::Ada), _ => Err(format!("Unknown Reward Currency: {}", value)), } } From 5d4651be9044563a4325fc326d6bde3104704403 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 26 Sep 2023 12:57:51 +0300 Subject: [PATCH 35/37] add proposal types --- .../src/service/common/objects/mod.rs | 5 ++ .../src/service/common/objects/proposal.rs | 32 +++++++++++ .../common/objects/proposal_details.rs | 56 +++++++++++++++++++ .../src/service/common/objects/proposal_id.rs | 21 +++++++ .../common/objects/proposal_summary.rs | 43 ++++++++++++++ .../common/objects/proposer_details.rs | 47 ++++++++++++++++ 6 files changed, 204 insertions(+) create mode 100644 src/cat-data-service/src/service/common/objects/proposal.rs create mode 100644 src/cat-data-service/src/service/common/objects/proposal_details.rs create mode 100644 src/cat-data-service/src/service/common/objects/proposal_id.rs create mode 100644 src/cat-data-service/src/service/common/objects/proposal_summary.rs create mode 100644 src/cat-data-service/src/service/common/objects/proposer_details.rs diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 6cc72c5893..92d404265a 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -7,6 +7,11 @@ pub(crate) mod objective_id; pub(crate) mod objective_summary; pub(crate) mod objective_type; pub(crate) mod objective_types; +pub(crate) mod proposal; +pub(crate) mod proposal_details; +pub(crate) mod proposal_id; +pub(crate) mod proposal_summary; +pub(crate) mod proposer_details; pub(crate) mod reward_currency; pub(crate) mod reward_definition; pub(crate) mod stake_public_key; diff --git a/src/cat-data-service/src/service/common/objects/proposal.rs b/src/cat-data-service/src/service/common/objects/proposal.rs new file mode 100644 index 0000000000..47fddd79b2 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/proposal.rs @@ -0,0 +1,32 @@ +//! Defines the full proposal information. +//! +use super::{proposal_details::ProposalDetails, proposal_summary::ProposalSummary}; +use poem_openapi::{types::Example, Object}; + +/// Full Objective info. +#[derive(Object)] +#[oai(example = true)] +pub(crate) struct Proposal { + #[oai(flatten)] + summary: ProposalSummary, + #[oai(flatten)] + details: ProposalDetails, +} + +impl Example for Proposal { + fn example() -> Self { + Self { + summary: ProposalSummary::example(), + details: ProposalDetails::example(), + } + } +} + +impl From for Proposal { + fn from(value: event_db::types::proposal::Proposal) -> Self { + Self { + summary: value.summary.into(), + details: value.details.into(), + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/proposal_details.rs b/src/cat-data-service/src/service/common/objects/proposal_details.rs new file mode 100644 index 0000000000..983f8615c0 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/proposal_details.rs @@ -0,0 +1,56 @@ +//! Defines the proposal details. +//! +use super::proposer_details::ProposerDetails; +use poem_openapi::{types::Example, Object}; +use serde_json::Value; + +/// Details of a particular Proposal. +#[derive(Object)] +pub(crate) struct ProposalDetails { + /// The amount of funds requested by this proposal. + /// In the denomination of the Objectives Reward. + /// If not present, then this proposal is not requesting any funds. + funds: i64, + + /// URL to a web page with details on this proposal. + url: String, + + /// Link to extra files associated with this proposal. + /// Only included if there are linked files. + files: String, + + /// List of all proposers making this proposal. + proposer: Vec, + + /// Proposal Supplemental Data + /// + /// Extra Data which can be used to enrich the information shared about the Proposal. + /// All Information here is optional. + /// If there is no supplemental information for the Proposal this field is omitted. + #[oai(skip_serializing_if_is_none = true)] + supplemental: Option, +} + +impl Example for ProposalDetails { + fn example() -> Self { + Self { + funds: 0, + url: "URL to a web page with details on this proposal".to_string(), + files: "Link to extra files associated with this proposal".to_string(), + proposer: vec![ProposerDetails::example()], + supplemental: None, + } + } +} + +impl From for ProposalDetails { + fn from(value: event_db::types::proposal::ProposalDetails) -> Self { + Self { + funds: value.funds, + url: value.url, + files: value.files, + proposer: value.proposer.into_iter().map(Into::into).collect(), + supplemental: value.supplemental, + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/proposal_id.rs b/src/cat-data-service/src/service/common/objects/proposal_id.rs new file mode 100644 index 0000000000..d48c2444cd --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/proposal_id.rs @@ -0,0 +1,21 @@ +//! Defines the ID of a proposal. +//! +use poem_openapi::{types::Example, NewType}; +use serde::Deserialize; + +/// The Numeric ID of a Proposal. +#[derive(NewType, Deserialize)] +#[oai(example = true)] +pub(crate) struct ProposalId(i32); + +impl Example for ProposalId { + fn example() -> Self { + Self(1) + } +} + +impl From for ProposalId { + fn from(value: event_db::types::proposal::ProposalId) -> Self { + Self(value.0) + } +} diff --git a/src/cat-data-service/src/service/common/objects/proposal_summary.rs b/src/cat-data-service/src/service/common/objects/proposal_summary.rs new file mode 100644 index 0000000000..cff4459b8f --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/proposal_summary.rs @@ -0,0 +1,43 @@ +//! Defines the proposal summary. +//! +use super::proposal_id::ProposalId; +use poem_openapi::{types::Example, Object}; + +/// Summary of a Proposal. +#[derive(Object)] +#[oai(example = true)] +pub(crate) struct ProposalSummary { + /// The ID of this proposal. + id: ProposalId, + + /// Short title of the proposal. + title: String, + + /// Brief description of the proposal. + summary: String, + + /// Whether this Proposal has been deleted or not. + deleted: bool, +} + +impl Example for ProposalSummary { + fn example() -> Self { + Self { + id: ProposalId::example(), + title: "Proposal Title".to_string(), + summary: "Proposal Summary".to_string(), + deleted: false, + } + } +} + +impl From for ProposalSummary { + fn from(value: event_db::types::proposal::ProposalSummary) -> Self { + Self { + id: value.id.into(), + title: value.title, + summary: value.summary, + deleted: value.deleted, + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/proposer_details.rs b/src/cat-data-service/src/service/common/objects/proposer_details.rs new file mode 100644 index 0000000000..90e228b448 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/proposer_details.rs @@ -0,0 +1,47 @@ +//! Defines the proposer details. +//! +use poem_openapi::{types::Example, Object}; + +/// Details about a proposer for a particular proposal. +#[derive(Object)] +#[oai(example = true)] +pub(crate) struct ProposerDetails { + /// Name of the author/s of the proposal. + name: String, + + /// Email contact address of the author's of the proposal. + /// If not present, there is no known contact email for the authors. + email: String, + + /// URL to a web resource with details about the author's of the proposal. + url: String, + + /// The Payment Address the Funds requested will be paid to. + /// Will not be included if the proposal does not request funds. + #[oai(validator(max_length = 66, min_length = 66, pattern = "0x[0-9a-f]{64}"))] + payment_key: String, +} + +impl Example for ProposerDetails { + fn example() -> Self { + Self { + name: "Name of the author/s of the proposal".to_string(), + email: "Email contact address of the author/s of the proposal".to_string(), + url: "URL to a web resource with details about the author/s of the proposal" + .to_string(), + payment_key: "0xb7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde" + .to_string(), + } + } +} + +impl From for ProposerDetails { + fn from(value: event_db::types::proposal::ProposerDetails) -> Self { + Self { + name: value.name, + email: value.email, + url: value.url, + payment_key: value.payment_key, + } + } +} From d188702c093ed8b0dbf978ac3ef49fbde1d72ff8 Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 26 Sep 2023 13:41:14 +0300 Subject: [PATCH 36/37] fixes, add voteplan and ballot_type --- .../src/service/common/objects/ballot_type.rs | 37 +++++++++++ .../src/service/common/objects/mod.rs | 2 + .../service/common/objects/objective_types.rs | 2 +- .../common/objects/proposal_details.rs | 1 + .../common/objects/proposal_summary.rs | 1 + .../service/common/objects/reward_currency.rs | 2 +- .../src/service/common/objects/vote_plan.rs | 64 +++++++++++++++++++ .../service/common/objects/voter_group_id.rs | 2 +- 8 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/cat-data-service/src/service/common/objects/ballot_type.rs create mode 100644 src/cat-data-service/src/service/common/objects/vote_plan.rs diff --git a/src/cat-data-service/src/service/common/objects/ballot_type.rs b/src/cat-data-service/src/service/common/objects/ballot_type.rs new file mode 100644 index 0000000000..8a0fac6a1c --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/ballot_type.rs @@ -0,0 +1,37 @@ +//! Defines the ballot type. +//! +use poem_openapi::{types::Example, Enum}; + +/// The kind of ballot to be cast on this Objective. +#[derive(Enum)] +pub(crate) enum BallotType { + /// All Ballots are public when cast. + #[oai(rename = "public")] + Public, + + /// All Ballots are private. + #[oai(rename = "private")] + Private, + + /// All Ballots are cast privately but become public after the tally. + #[oai(rename = "cast-private")] + CastPrivate, +} + +impl Example for BallotType { + fn example() -> Self { + Self::Public + } +} + +impl TryFrom for BallotType { + type Error = String; + fn try_from(value: event_db::types::ballot::BallotType) -> Result { + match value.0.as_str() { + "public" => Ok(Self::Public), + "private" => Ok(Self::Private), + "cast-private" => Ok(Self::CastPrivate), + _ => Err(format!("Unknown ballot type: {}", value.0)), + } + } +} diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index 92d404265a..d49e915f3f 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,4 +1,5 @@ //! This module contains common and re-usable objects. +pub(crate) mod ballot_type; pub(crate) mod delegate_public_key; pub(crate) mod event_id; pub(crate) mod objective; @@ -15,6 +16,7 @@ pub(crate) mod proposer_details; pub(crate) mod reward_currency; pub(crate) mod reward_definition; pub(crate) mod stake_public_key; +pub(crate) mod vote_plan; pub(crate) mod voter_group; pub(crate) mod voter_group_id; pub(crate) mod voter_info; diff --git a/src/cat-data-service/src/service/common/objects/objective_types.rs b/src/cat-data-service/src/service/common/objects/objective_types.rs index be79a055e0..535290da2c 100644 --- a/src/cat-data-service/src/service/common/objects/objective_types.rs +++ b/src/cat-data-service/src/service/common/objects/objective_types.rs @@ -26,7 +26,7 @@ impl TryFrom for ObjectiveTypes { "catalyst-simple" => Ok(Self::Simple), "catalyst-native" => Ok(Self::Native), "catalyst-community-choice" => Ok(Self::CommunityChoice), - _ => Err(format!("Unknown Objective Type: {}", value)), + _ => Err(format!("Unknown objective type: {}", value)), } } } diff --git a/src/cat-data-service/src/service/common/objects/proposal_details.rs b/src/cat-data-service/src/service/common/objects/proposal_details.rs index 983f8615c0..fae064aea2 100644 --- a/src/cat-data-service/src/service/common/objects/proposal_details.rs +++ b/src/cat-data-service/src/service/common/objects/proposal_details.rs @@ -10,6 +10,7 @@ pub(crate) struct ProposalDetails { /// The amount of funds requested by this proposal. /// In the denomination of the Objectives Reward. /// If not present, then this proposal is not requesting any funds. + #[oai(validator(minimum(value = "0")))] funds: i64, /// URL to a web page with details on this proposal. diff --git a/src/cat-data-service/src/service/common/objects/proposal_summary.rs b/src/cat-data-service/src/service/common/objects/proposal_summary.rs index cff4459b8f..3f45179523 100644 --- a/src/cat-data-service/src/service/common/objects/proposal_summary.rs +++ b/src/cat-data-service/src/service/common/objects/proposal_summary.rs @@ -8,6 +8,7 @@ use poem_openapi::{types::Example, Object}; #[oai(example = true)] pub(crate) struct ProposalSummary { /// The ID of this proposal. + #[oai(validator(minimum(value = "0")))] id: ProposalId, /// Short title of the proposal. diff --git a/src/cat-data-service/src/service/common/objects/reward_currency.rs b/src/cat-data-service/src/service/common/objects/reward_currency.rs index b905c1a52c..c45b884316 100644 --- a/src/cat-data-service/src/service/common/objects/reward_currency.rs +++ b/src/cat-data-service/src/service/common/objects/reward_currency.rs @@ -20,7 +20,7 @@ impl TryFrom for RewardCurrency { fn try_from(value: String) -> Result { match value.as_str() { "ADA" => Ok(Self::Ada), - _ => Err(format!("Unknown Reward Currency: {}", value)), + _ => Err(format!("Unknown reward currency: {}", value)), } } } diff --git a/src/cat-data-service/src/service/common/objects/vote_plan.rs b/src/cat-data-service/src/service/common/objects/vote_plan.rs new file mode 100644 index 0000000000..498a79837b --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/vote_plan.rs @@ -0,0 +1,64 @@ +//! Defines the vote plan. +//! +use super::{ballot_type::BallotType, voter_group_id::VoterGroupId}; +use poem_openapi::{types::Example, Object}; + +/// The vote plan assigned to a voter group. +#[derive(Object)] +#[oai(example = true)] +pub(crate) struct VotePlan { + /// The Index of the proposal, needed to create a ballot for it. + #[oai(validator(minimum(value = "0")))] + chain_proposal_index: i64, + + /// The name of the group. + #[oai(skip_serializing_if_is_none = true)] + group: Option, + + /// The type of ballot this group must cast. + ballot_type: BallotType, + + /// Blockchain ID of the vote plan transaction. + #[oai(validator(max_length = 66, min_length = 66, pattern = "0x[0-9a-f]{64}"))] + chain_voteplan_id: String, + + /// The public encryption key used. ONLY if required by the ballot type (private, cast-private). + #[oai( + skip_serializing_if_is_none = true, + validator(max_length = 66, min_length = 66, pattern = "0x[0-9a-f]{64}") + )] + encryption_key: Option, +} + +impl Example for VotePlan { + fn example() -> Self { + Self { + chain_proposal_index: 0, + group: None, + ballot_type: BallotType::example(), + chain_voteplan_id: "0xad6eaebafd2cca7e1829df26c57b340a98b9d513b7eddec8561883f1b99f3b9e" + .to_string(), + encryption_key: Some( + "0xbc5fdebafd2cca7e1829df26c57b340a98b9d513b7eddec8561883f1b99f3b9e".to_string(), + ), + } + } +} + +impl TryFrom for VotePlan { + type Error = String; + fn try_from(value: event_db::types::ballot::VotePlan) -> Result { + let group = if let Some(group) = value.group { + Some(group.try_into()?) + } else { + None + }; + Ok(Self { + chain_proposal_index: value.chain_proposal_index, + group, + ballot_type: value.ballot_type.try_into()?, + chain_voteplan_id: value.chain_voteplan_id, + encryption_key: value.encryption_key, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/voter_group_id.rs b/src/cat-data-service/src/service/common/objects/voter_group_id.rs index 2e28fb1ec2..e3db85c744 100644 --- a/src/cat-data-service/src/service/common/objects/voter_group_id.rs +++ b/src/cat-data-service/src/service/common/objects/voter_group_id.rs @@ -26,7 +26,7 @@ impl TryFrom for VoterGroupId { match value.0.as_str() { "rep" => Ok(Self::Rep), "direct" => Ok(Self::Direct), - value => Err(format!("Unknown VoterGroupId: {}", value)), + value => Err(format!("Unknown voter group id: {}", value)), } } } From 16a252c663bcf656374861ed4ef882de5e4022ad Mon Sep 17 00:00:00 2001 From: Mr-Leshiy Date: Tue, 26 Sep 2023 15:31:16 +0300 Subject: [PATCH 37/37] add Ballot type --- .../src/service/common/objects/ballot.rs | 44 +++++++++++++++++++ .../src/service/common/objects/mod.rs | 1 + 2 files changed, 45 insertions(+) create mode 100644 src/cat-data-service/src/service/common/objects/ballot.rs diff --git a/src/cat-data-service/src/service/common/objects/ballot.rs b/src/cat-data-service/src/service/common/objects/ballot.rs new file mode 100644 index 0000000000..e84a2de345 --- /dev/null +++ b/src/cat-data-service/src/service/common/objects/ballot.rs @@ -0,0 +1,44 @@ +//! Defines the Ballot type. +//! +use super::vote_plan::VotePlan; +use poem_openapi::{types::Example, Object}; + +/// Details necessary to complete a ballot for the specific proposal and objective. +#[derive(Object)] +#[oai(example = true)] +pub struct Ballot { + /// Ballot Choices present for all proposals in this Objective. + /// + /// Ordered list of choices available for all proposals in this Objective. + /// The offset into the array is the index of the choice. + choices: Vec, + + /// List of groups and the voteplans they use when voting on this proposal. + /// Each valid group for this Objective: + /// * Must be listed. + /// * Must not be repeated. + voteplans: Vec, +} + +impl Example for Ballot { + fn example() -> Self { + Self { + choices: vec!["yes".to_string(), "no".to_string(), "abstain".to_string()], + voteplans: vec![VotePlan::example()], + } + } +} + +impl TryFrom for Ballot { + type Error = String; + fn try_from(value: event_db::types::ballot::Ballot) -> Result { + let mut voteplans = Vec::new(); + for voteplan in value.voteplans.0 { + voteplans.push(voteplan.try_into()?); + } + Ok(Self { + choices: value.choices.0, + voteplans, + }) + } +} diff --git a/src/cat-data-service/src/service/common/objects/mod.rs b/src/cat-data-service/src/service/common/objects/mod.rs index d49e915f3f..85a8679a4f 100644 --- a/src/cat-data-service/src/service/common/objects/mod.rs +++ b/src/cat-data-service/src/service/common/objects/mod.rs @@ -1,4 +1,5 @@ //! This module contains common and re-usable objects. +pub(crate) mod ballot; pub(crate) mod ballot_type; pub(crate) mod delegate_public_key; pub(crate) mod event_id;