From 96dff0cefc5f4a3bfcd3139b379f3970b3142ccd Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Sun, 29 Sep 2024 09:18:33 +0100 Subject: [PATCH] feat: add admin routes for contract tasks --- .../admin/contract/create_contract.rs | 80 +++++++++++++++++++ src/endpoints/admin/contract/mod.rs | 2 + .../admin/contract/update_contract.rs | 79 ++++++++++++++++++ src/endpoints/admin/mod.rs | 1 + src/models.rs | 2 +- 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/endpoints/admin/contract/create_contract.rs create mode 100644 src/endpoints/admin/contract/mod.rs create mode 100644 src/endpoints/admin/contract/update_contract.rs diff --git a/src/endpoints/admin/contract/create_contract.rs b/src/endpoints/admin/contract/create_contract.rs new file mode 100644 index 0000000..a31b679 --- /dev/null +++ b/src/endpoints/admin/contract/create_contract.rs @@ -0,0 +1,80 @@ +use crate::models::{QuestDocument, QuestTaskDocument, Call}; +use crate::utils::verify_quest_auth; +use crate::{models::AppState, utils::get_error}; +use crate::middleware::auth::auth_middleware; +use axum::{ + extract::{Extension, State}, + http::StatusCode, + response::{IntoResponse, Json} +}; +use axum_auto_routes::route; +use mongodb::bson::doc; +use mongodb::options::FindOneOptions; +use serde::Deserialize; +use serde_json::json; +use std::sync::Arc; + +pub_struct!(Deserialize; CreateContract { + quest_id: i64, + name: String, + desc: String, + href: String, + cta: String, + calls: Vec +}); + +#[route(post, "/admin/tasks/contract/create", auth_middleware)] +pub async fn handler( + State(state): State>, + Extension(sub): Extension, + Json(body): Json, +) -> impl IntoResponse { + let collection = state.db.collection::("tasks"); + // Get the last id in increasing order + let last_id_filter = doc! {}; + let options = FindOneOptions::builder().sort(doc! {"id": -1}).build(); + let last_doc = &collection.find_one(last_id_filter, options).await.unwrap(); + + let quests_collection = state.db.collection::("quests"); + + let res = verify_quest_auth(sub, &quests_collection, &(body.quest_id as i64)).await; + if !res { + return get_error("Error creating task".to_string()); + }; + + let mut next_id = 1; + if let Some(doc) = last_doc { + let last_id = doc.id; + next_id = last_id + 1; + } + + let new_document = QuestTaskDocument { + name: body.name.clone(), + desc: body.desc.clone(), + verify_redirect: None, + href: body.href.clone(), + total_amount: None, + quest_id: body.quest_id, + id: next_id, + cta: body.cta.clone(), + verify_endpoint: "quests/verify_contract".to_string(), + verify_endpoint_type: "default".to_string(), + task_type: Some("contract".to_string()), + discord_guild_id: None, + quiz_name: None, + contracts: None, + calls: Some(body.calls), + api_url: None, + regex: None, + }; + + // insert document to boost collection + return match collection.insert_one(new_document, None).await { + Ok(_) => ( + StatusCode::OK, + Json(json!({"message": "Task created successfully"})).into_response(), + ) + .into_response(), + Err(_e) => get_error("Error creating tasks".to_string()), + }; +} diff --git a/src/endpoints/admin/contract/mod.rs b/src/endpoints/admin/contract/mod.rs new file mode 100644 index 0000000..b0acadf --- /dev/null +++ b/src/endpoints/admin/contract/mod.rs @@ -0,0 +1,2 @@ +pub mod create_contract; +pub mod update_contract; \ No newline at end of file diff --git a/src/endpoints/admin/contract/update_contract.rs b/src/endpoints/admin/contract/update_contract.rs new file mode 100644 index 0000000..597b466 --- /dev/null +++ b/src/endpoints/admin/contract/update_contract.rs @@ -0,0 +1,79 @@ +use crate::models::{QuestTaskDocument, Call}; +use crate::{models::AppState, utils::get_error}; +use crate::middleware::auth::auth_middleware; +use crate::utils::verify_task_auth; + +use axum::{ + extract::{Extension, State}, + http::StatusCode, + response::{IntoResponse, Json}, +}; +use axum_auto_routes::route; +use mongodb::bson::{doc, to_bson}; +use serde::Deserialize; +use serde_json::json; +use std::sync::Arc; + +pub_struct!(Deserialize; UpdateContract { + id: i64, + name: Option, + desc: Option, + href: Option, + cta: Option, + calls: Option> +}); + +#[route(post, "/admin/tasks/contract/update", auth_middleware)] +pub async fn handler( + State(state): State>, + Extension(sub): Extension, + Json(body): Json, +) -> impl IntoResponse { + + let collection = state.db.collection::("tasks"); + + let res = verify_task_auth(sub, &collection, &(body.id as i32)).await; + if !res { + return get_error("Error updating tasks".to_string()); + } + + // filter to get existing quest + let filter = doc! { + "id": &body.id, + }; + + let mut update_doc = doc! {}; + + if let Some(name) = &body.name { + update_doc.insert("name", name); + } + if let Some(desc) = &body.desc { + update_doc.insert("desc", desc); + } + if let Some(href) = &body.href { + update_doc.insert("href", href); + } + + if let Some(cta) = &body.cta { + update_doc.insert("cta", cta); + } + + if let Some(calls) = &body.calls { + update_doc.insert("calls", to_bson(calls).unwrap()); + } + + // update quest query + let update = doc! { + "$set": update_doc + }; + + // insert document to boost collection + return match collection.find_one_and_update(filter, update, None).await { + Ok(_) => ( + StatusCode::OK, + Json(json!({"message": "Task updated successfully"})).into_response(), + ) + .into_response(), + Err(_e) => get_error("Error updating tasks".to_string()), + }; +} \ No newline at end of file diff --git a/src/endpoints/admin/mod.rs b/src/endpoints/admin/mod.rs index ebafdef..20bf77f 100644 --- a/src/endpoints/admin/mod.rs +++ b/src/endpoints/admin/mod.rs @@ -11,3 +11,4 @@ pub mod quiz; pub mod twitter; pub mod user; pub mod custom_api; +pub mod contract; \ No newline at end of file diff --git a/src/models.rs b/src/models.rs index 19f6e9f..c3f5190 100644 --- a/src/models.rs +++ b/src/models.rs @@ -107,7 +107,7 @@ pub struct CompletedTaskDocument { timestamp: i64, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Call { pub contract: String, pub call_data: Vec,