diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/fund_get.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/fund_get.rs new file mode 100644 index 00000000000..5e2b9f5a862 --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/fund_get.rs @@ -0,0 +1,21 @@ +//! Implementation of the GET /setting endpoint +use poem_openapi::{payload::Json, ApiResponse}; + +use crate::service::common::{objects::legacy::fund::Fund, responses::WithErrorResponses}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint() -> AllResponses { + Responses::Ok(Json(Fund::default())).into() +} diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/mod.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/mod.rs index e92b2ba85e4..73155f68c32 100644 --- a/catalyst-gateway/bin/src/service/api/legacy/v0/mod.rs +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/mod.rs @@ -1,12 +1,25 @@ //! `v0` Endpoints -use poem_openapi::{payload::Binary, OpenApi}; +use poem_openapi::{ + param::Path, + payload::{Binary, Json}, + OpenApi, +}; use crate::service::{ - common::{auth::none::NoAuthorization, tags::ApiTags}, + common::{ + auth::none::NoAuthorization, objects::legacy::vote_history::VoteHistoryItem, tags::ApiTags, + }, utilities::middleware::schema_validation::schema_version_validation, }; + +mod fund_get; mod message_post; mod plans_get; +mod proposal_by_id_get; +mod proposals_get; +mod proposals_post; +mod review_by_proposal_id_get; +mod settings_get; /// `v0` API Endpoints pub(crate) struct V0Api; @@ -41,4 +54,97 @@ impl V0Api { async fn plans_get(&self, _auth: NoAuthorization) -> plans_get::AllResponses { plans_get::endpoint().await } + + /// Get settings. + /// + /// Get settings information including fees detail. + #[oai( + path = "/settings", + method = "get", + operation_id = "GetSettings", + deprecated = true + )] + async fn settings_get(&self, _auth: NoAuthorization) -> settings_get::AllResponses { + settings_get::endpoint().await + } + + /// Get fund. + /// + /// Get fund information. + #[oai( + path = "/fund/", + method = "get", + operation_id = "GetFund", + deprecated = true + )] + async fn fund_get(&self, _auth: NoAuthorization) -> fund_get::AllResponses { + fund_get::endpoint().await + } + + /// Get list of proposals. + /// + /// Get list of proposals and the proposal's detail. + #[oai( + path = "/proposals", + method = "get", + operation_id = "GetProposals", + deprecated = true + )] + async fn proposals_get(&self, _auth: NoAuthorization) -> proposals_get::AllResponses { + proposals_get::endpoint().await + } + + /// Get list of proposals. + /// + /// Get list of proposals according to the filter options. + /// This is a POST method, only to send the filter data over the HTTP body. + #[oai( + path = "/proposals", + method = "post", + operation_id = "GetProposalsByFilter", + deprecated = true + )] + async fn proposals_post( + &self, message: Json>, _auth: NoAuthorization, + ) -> proposals_post::AllResponses { + proposals_post::endpoint(message.0).await + } + + /// Get a proposal. + /// + /// Get a proposal filtering by its identifier. + #[oai( + path = "/proposals/:id", + method = "get", + operation_id = "ShowProposalById", + deprecated = true + )] + async fn proposal_by_id_get( + &self, + /// The proposal identifier to be retrieved. + #[oai(validator(max_length = 256, min_length = 0, pattern = "[A-Za-z0-9_-]"))] + id: Path, + _auth: NoAuthorization, + ) -> proposal_by_id_get::AllResponses { + proposal_by_id_get::endpoint(id.0).await + } + + /// Get proposal reviews. + /// + /// Get proposal reviews by proposal identifier. + #[oai( + path = "/reviews/:proposal_id", + method = "get", + operation_id = "GetReviewByProposalId", + deprecated = true + )] + async fn review_by_proposal_id_get( + &self, + /// The proposal identifier to retrieve the reviews. + #[oai(validator(max_length = 256, min_length = 0, pattern = "[A-Za-z0-9_-]"))] + proposal_id: Path, + _auth: NoAuthorization, + ) -> review_by_proposal_id_get::AllResponses { + review_by_proposal_id_get::endpoint(proposal_id.0).await + } } diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/proposal_by_id_get.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/proposal_by_id_get.rs new file mode 100644 index 00000000000..73b60f87a12 --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/proposal_by_id_get.rs @@ -0,0 +1,21 @@ +//! Implementation of the GET /setting endpoint +use poem_openapi::{payload::Json, ApiResponse}; + +use crate::service::common::{objects::legacy::proposal::Proposal, responses::WithErrorResponses}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint(_id: String) -> AllResponses { + Responses::Ok(Json(Proposal::default())).into() +} diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_get.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_get.rs new file mode 100644 index 00000000000..66f9dd4fda4 --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_get.rs @@ -0,0 +1,21 @@ +//! Implementation of the GET /setting endpoint +use poem_openapi::{payload::Json, ApiResponse}; + +use crate::service::common::{objects::legacy::proposal::Proposal, responses::WithErrorResponses}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json>), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint() -> AllResponses { + Responses::Ok(Json(Default::default())).into() +} diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_post.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_post.rs new file mode 100644 index 00000000000..4ce4b5e90bb --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/proposals_post.rs @@ -0,0 +1,22 @@ +//! Implementation of the GET /setting endpoint +use poem_openapi::{payload::Json, ApiResponse}; + +use super::VoteHistoryItem; +use crate::service::common::{objects::legacy::proposal::Proposal, responses::WithErrorResponses}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json>), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint(_message: Vec) -> AllResponses { + Responses::Ok(Json(Vec::new())).into() +} diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/review_by_proposal_id_get.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/review_by_proposal_id_get.rs new file mode 100644 index 00000000000..c6d3a170d61 --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/review_by_proposal_id_get.rs @@ -0,0 +1,23 @@ +//! Implementation of the GET /setting endpoint +use std::collections::HashMap; + +use poem_openapi::{payload::Json, ApiResponse}; + +use crate::service::common::{objects::legacy::review::Review, responses::WithErrorResponses}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json>), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint(_id: String) -> AllResponses { + Responses::Ok(Json(HashMap::default())).into() +} diff --git a/catalyst-gateway/bin/src/service/api/legacy/v0/settings_get.rs b/catalyst-gateway/bin/src/service/api/legacy/v0/settings_get.rs new file mode 100644 index 00000000000..eef113b86c6 --- /dev/null +++ b/catalyst-gateway/bin/src/service/api/legacy/v0/settings_get.rs @@ -0,0 +1,23 @@ +//! Implementation of the GET /setting endpoint +use poem_openapi::{payload::Json, ApiResponse}; + +use crate::service::common::{ + objects::legacy::settings_info::SettingsInfo, responses::WithErrorResponses, +}; + +/// Endpoint responses +#[derive(ApiResponse)] +pub(crate) enum Responses { + /// The default success response. + #[oai(status = 200)] + Ok(Json), +} + +/// All responses +pub(crate) type AllResponses = WithErrorResponses; + +/// The service endpoint +#[allow(clippy::unused_async)] +pub(crate) async fn endpoint() -> AllResponses { + Responses::Ok(Json(SettingsInfo::default())).into() +} diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/fund.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/fund.rs new file mode 100644 index 00000000000..bdc279dd632 --- /dev/null +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/fund.rs @@ -0,0 +1,11 @@ +//! Define the Fund + +use poem_openapi::Object; + +/// The fund information object. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct Fund { + #[oai(validator(max_length = 256, min_length = 0, pattern = "[A-Za-z0-9_-]"))] + id: String, +} diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/mod.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/mod.rs index 40b61cca759..ee342458483 100644 --- a/catalyst-gateway/bin/src/service/common/objects/legacy/mod.rs +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/mod.rs @@ -7,8 +7,13 @@ pub(crate) mod event_id; pub(crate) mod fragment_status; pub(crate) mod fragments_batch; pub(crate) mod fragments_processing_summary; +pub(crate) mod fund; pub(crate) mod hash; +pub(crate) mod proposal; +pub(crate) mod review; +pub(crate) mod settings_info; pub(crate) mod stake_public_key; +pub(crate) mod vote_history; pub(crate) mod vote_plan; pub(crate) mod voter_group_id; pub(crate) mod voter_info; diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/proposal.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/proposal.rs new file mode 100644 index 00000000000..9581d709a45 --- /dev/null +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/proposal.rs @@ -0,0 +1,60 @@ +//! Define the Proposal + +use std::collections::HashMap; + +use poem_openapi::Object; + +/// The proposal object. +#[allow(clippy::missing_docs_in_private_items)] +#[allow(clippy::struct_field_names)] +#[derive(Object, Default)] +pub(crate) struct Proposal { + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + internal_id: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + chain_voteplan_id: String, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + chain_proposal_index: u32, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + chain_vote_encryption_key: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + chain_voteplan_payload: String, + #[oai(validator( + max_length = 32767, + min_length = 0, + pattern = "[\\s\\S]", + max_properties = 100, + min_properties = 0 + ))] + chain_vote_options: HashMap, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_public_key: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + fund_id: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_summary: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_importance: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_title: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_goal: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposal_url: String, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + proposal_funds: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + reviews_count: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + proposal_impact_score: u32, + #[oai] + proposer: Option, +} + +/// The proposer object. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct Proposer { + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + proposer_name: String, +} diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/review.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/review.rs new file mode 100644 index 00000000000..f46c04abe57 --- /dev/null +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/review.rs @@ -0,0 +1,25 @@ +//! Define the Review + +use poem_openapi::Object; + +/// The proposal review object from a reviewer. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct Review { + #[oai(validator(max_length = 256, min_length = 0, pattern = "[A-Za-z0-9_-]"))] + id: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + assessor: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + impact_alignment_note: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + impact_alignment_rating_given: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + auditability_note: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + auditability_rating_given: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + feasibility_note: String, + #[oai(validator(max_length = 32767, min_length = 0, pattern = "[\\s\\S]"))] + feasibility_rating_given: String, +} diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/settings_info.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/settings_info.rs new file mode 100644 index 00000000000..537374d0ea7 --- /dev/null +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/settings_info.rs @@ -0,0 +1,61 @@ +//! Define the Settings Info + +use poem_openapi::Object; + +/// The setting info object. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct SettingsInfo { + #[oai( + rename = "block0Hash", + validator(max_length = 66, min_length = 0, pattern = "[0-9a-f]") + )] + block_0_hash: String, + #[oai] + fees: Fees, + #[oai( + rename = "slotsPerEpoch", + validator(max_length = 256, min_length = 1, pattern = "[0-9]+") + )] + slots_per_epoch: String, +} + +/// The fee information object. +#[allow(clippy::missing_docs_in_private_items)] +#[allow(clippy::struct_field_names)] +#[derive(Object, Default)] +pub(crate) struct Fees { + #[oai] + per_certificate_fees: PerCertificateFee, + #[oai] + per_vote_certificate_fees: PerVoteCertificateFees, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + constant: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + coefficient: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate: u32, +} + +/// The per-certificate fee object. +#[allow(clippy::missing_docs_in_private_items)] +#[allow(clippy::struct_field_names)] +#[derive(Object, Default)] +pub(crate) struct PerCertificateFee { + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate_pool_registration: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate_stake_delegation: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate_owner_stake_delegation: u32, +} + +/// The per-vote certificate fee object. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct PerVoteCertificateFees { + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate_vote_plan: u32, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + certificate_vote_cast: u32, +} diff --git a/catalyst-gateway/bin/src/service/common/objects/legacy/vote_history.rs b/catalyst-gateway/bin/src/service/common/objects/legacy/vote_history.rs new file mode 100644 index 00000000000..a46b41cbb74 --- /dev/null +++ b/catalyst-gateway/bin/src/service/common/objects/legacy/vote_history.rs @@ -0,0 +1,13 @@ +//! Define the Vote history + +use poem_openapi::Object; + +/// An option item to specify proposal to query. +#[allow(clippy::missing_docs_in_private_items)] +#[derive(Object, Default)] +pub(crate) struct VoteHistoryItem { + #[oai(validator(max_length = 256, min_length = 0, pattern = "[A-Za-z0-9_-]"))] + vote_plan_id: String, + #[oai(validator(minimum(value = "0"), maximum(value = "4294967295")))] + indexes: u32, +} diff --git a/catalyst-gateway/tests/.oapi-v3.spectral.yml b/catalyst-gateway/tests/.oapi-v3.spectral.yml index 9d8710175cc..c126c3dc7c6 100644 --- a/catalyst-gateway/tests/.oapi-v3.spectral.yml +++ b/catalyst-gateway/tests/.oapi-v3.spectral.yml @@ -92,6 +92,8 @@ overrides: # ONLY Legacy endpoints may be added to this override. - files: - "**#/components/schemas/FragmentStatus" + - "**#/components/schemas/Review" + - "**#/components/schemas/Proposal/properties/chain_vote_options" rules: # Ref: https://github.com/stoplightio/spectral-owasp-ruleset/blob/2fd49c377794222352ff10dee99ed2a106c35199/src/ruleset.ts#L678 owasp:api3:2023-no-additionalProperties: off @@ -101,6 +103,9 @@ overrides: - files: - "**#/paths/~1api~1v0~1vote~1active~1plans/get/responses" - "**#/paths/~1api~1v1~1votes~1plan~1account-votes~1%7Baccount_id%7D/get/responses" + - "**#/paths/~1api~1v0~1proposals/get/responses" + - "**#/paths/~1api~1v0~1proposals/post/requestBody" + - "**#/paths/~1api~1v0~1proposals/post/responses" rules: # Ref: https://github.com/stoplightio/spectral-owasp-ruleset/blob/2fd49c377794222352ff10dee99ed2a106c35199/src/ruleset.ts#L506 owasp:api4:2023-array-limit: off @@ -109,6 +114,7 @@ overrides: # ONLY Legacy endpoints may be added to this override. - files: - "**#/paths/~1api~1v1~1fragments~1statuses/get/responses" + - "**#/paths/~1api~1v0~1reviews~1%7Bproposal_id%7D/get/responses" rules: # Ref: https://github.com/stoplightio/spectral-owasp-ruleset/blob/2fd49c377794222352ff10dee99ed2a106c35199/src/ruleset.ts#L678 owasp:api3:2023-constrained-additionalProperties: off