From 9ba6f36d7277d05cfee272820589462d5a42daf2 Mon Sep 17 00:00:00 2001 From: jaykayudo Date: Sat, 21 Dec 2024 00:02:44 +0100 Subject: [PATCH] (chore) add subscription retrieval service --- src/http/mod.rs | 5 ++- src/http/subscription.rs | 76 +++++++++++++++++++++++++++++++++++++-- src/http/types.rs | 21 +++++++++++ tests/api/subscription.rs | 14 ++++++++ 4 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index 99f9248..e2d027a 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -21,7 +21,10 @@ pub fn router() -> Router { post(transaction_logs::log_transaction_to_db), ) .route("/unsubscribe", post(unsubscription::handle_unsubscribe)) - .route("/subscriptions", post(subscription::create_subscription)) + .route( + "/subscriptions", + get(subscription::get_subscription).post(subscription::create_subscription), + ) .route("/log_retrieval", get(activity_log_retrieval::log_retrieval)) .route( "/update-percentage", diff --git a/src/http/subscription.rs b/src/http/subscription.rs index 2173ae5..0699cf1 100644 --- a/src/http/subscription.rs +++ b/src/http/subscription.rs @@ -1,7 +1,17 @@ -use axum::{extract::State, http::StatusCode, Json}; +use axum::{extract::Query, extract::State, http::StatusCode, Json}; -use super::types::{CreateSubscriptionRequest, CreateSubscriptionResponse}; +use super::types::{ + CreateSubscriptionRequest, CreateSubscriptionResponse, GetSubscriptionRequest, + GetSubscriptionResponse, SubscriptionData, +}; +use crate::api_error::ApiError; use crate::AppState; +use time::format_description::well_known::Rfc3339; +use time::OffsetDateTime; + +use serde_json::{json, Value}; + +const LIMIT: i32 = 10; pub async fn create_subscription( State(state): State, @@ -64,3 +74,65 @@ pub async fn create_subscription( wallet_address: payload.wallet_address, })) } + +pub async fn get_subscription( + State(state): State, + Query(params): Query, +) -> Result, ApiError> { + let cursor: String = match params.cursor { + Some(cursor1) => match OffsetDateTime::parse(&cursor1, &Rfc3339) { + Ok(cur) => cur.format(&Rfc3339).unwrap(), + Err(_) => return Err(ApiError::InvalidRequest("Invalid cursor".to_string())), + }, + + None => { + let now = OffsetDateTime::now_utc(); + now.format(&Rfc3339).unwrap() + } + }; + + let rows: Vec = sqlx::query_as::<_, SubscriptionData>( + r#" + SELECT + swap_subscription_from_token.from_token AS from_token, + swap_subscription.to_token AS to_token, + swap_subscription_from_token.percentage AS percentage, + swap_subscription.is_active AS is_active, + TO_CHAR(swap_subscription_from_token.created_at, 'YYYY-MM-DD"T"HH24:MI:SSZ') AS created_at + FROM swap_subscription_from_token + INNER JOIN swap_subscription ON swap_subscription_from_token.wallet_address = swap_subscription.wallet_address + WHERE swap_subscription_from_token.created_at < $1::TIMESTAMPTZ + AND swap_subscription_from_token.wallet_address = $2; + "# + ) + .bind(cursor) + .bind(¶ms.wallet_address) + .fetch_all(&state.db.pool) + .await + .map_err(ApiError::DatabaseError)?; + + let mut response_data: GetSubscriptionResponse = GetSubscriptionResponse { + data: rows + .into_iter() + .map(|row| SubscriptionData { + from_token: row.from_token, + to_token: row.to_token, + percentage: row.percentage, + is_active: row.is_active, + created_at: row.created_at, + }) + .collect(), + next_cursor: None, + }; + + match response_data.data.len() == LIMIT as usize { + true => { + response_data.next_cursor = Some(response_data.data.last().unwrap().created_at.clone()); + } + false => { + response_data.next_cursor = None; + } + }; + + Ok(Json(json!(response_data))) +} diff --git a/src/http/types.rs b/src/http/types.rs index b1652c5..5579502 100644 --- a/src/http/types.rs +++ b/src/http/types.rs @@ -44,6 +44,27 @@ pub struct CreateSubscriptionResponse { pub wallet_address: String, } +#[derive(FromRow, Debug, Serialize)] +pub struct SubscriptionData { + pub to_token: String, + pub is_active: bool, + pub from_token: String, + pub percentage: i16, + pub created_at: String, +} + +#[derive(Debug, Deserialize)] +pub struct GetSubscriptionRequest { + pub wallet_address: String, + pub cursor: Option, +} + +#[derive(Debug, Serialize)] +pub struct GetSubscriptionResponse { + pub data: Vec, + pub next_cursor: Option, +} + #[derive(sqlx::Type)] pub struct TimeStamptz(pub OffsetDateTime); diff --git a/tests/api/subscription.rs b/tests/api/subscription.rs index e93d1f9..5d6d392 100644 --- a/tests/api/subscription.rs +++ b/tests/api/subscription.rs @@ -197,3 +197,17 @@ async fn test_invalid_to_token_address() { let resp = app.request(req).await; assert_eq!(resp.status(), StatusCode::BAD_REQUEST); } + +#[tokio::test] +async fn test_successful_subscription_retrieval() { + let app = TestApp::new().await; + + let req = Request::builder() + .method("GET") + .uri("/subscriptions?wallet_address=0x742d35Cc6634C0532925a3b844Bc454e4438f44e") + .header(CONTENT_TYPE, "application/json") + .body(Body::empty()) + .unwrap(); + let resp = app.request(req).await; + assert_eq!(resp.status(), StatusCode::OK); +}