diff --git a/src/endpoints/admin/custom_api/create_custom_api.rs b/src/endpoints/admin/custom_api/create_custom_api.rs new file mode 100644 index 00000000..7b33631a --- /dev/null +++ b/src/endpoints/admin/custom_api/create_custom_api.rs @@ -0,0 +1,81 @@ +use crate::models::{QuestDocument, QuestTaskDocument}; +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; CreateCustomAPI { + quest_id: i64, + name: String, + desc: String, + href: String, + cta: String, + api_url: String, + regex: String, +}); + +#[route(post, "/admin/tasks/custom_api/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_custom_api".to_string(), + verify_endpoint_type: "default".to_string(), + calls: None, + task_type: Some("custom_api".to_string()), + discord_guild_id: None, + quiz_name: None, + contracts: None, + api_url: Some(body.api_url.clone()), + regex: Some(body.regex.clone()), + }; + + // 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/custom_api/mod.rs b/src/endpoints/admin/custom_api/mod.rs new file mode 100644 index 00000000..59c8d4fd --- /dev/null +++ b/src/endpoints/admin/custom_api/mod.rs @@ -0,0 +1,2 @@ +pub mod create_custom_api; +pub mod update_custom_api; \ No newline at end of file diff --git a/src/endpoints/admin/custom_api/update_custom_api.rs b/src/endpoints/admin/custom_api/update_custom_api.rs new file mode 100644 index 00000000..2128f260 --- /dev/null +++ b/src/endpoints/admin/custom_api/update_custom_api.rs @@ -0,0 +1,80 @@ +use crate::models::QuestTaskDocument; +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; +use serde::Deserialize; +use serde_json::json; +use std::sync::Arc; + +pub_struct!(Deserialize; UpdateCustomAPI { + id: i64, + name: Option, + desc: Option, + href: Option, + cta: Option, + api_url: Option, + regex: Option, +}); + +#[route(post, "/admin/tasks/custom_api/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(api_url) = &body.api_url { + update_doc.insert("api_url", api_url); + } + if let Some(regex) = &body.regex { + update_doc.insert("regex", regex); + } + + // 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()), + }; +} diff --git a/src/endpoints/admin/mod.rs b/src/endpoints/admin/mod.rs index da45ab39..ebafdef6 100644 --- a/src/endpoints/admin/mod.rs +++ b/src/endpoints/admin/mod.rs @@ -10,3 +10,4 @@ pub mod quest_boost; pub mod quiz; pub mod twitter; pub mod user; +pub mod custom_api; diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 08822929..4181eb68 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -16,4 +16,4 @@ pub mod has_completed_quest; pub mod leaderboard; pub mod quest_boost; pub mod quests; -pub mod unique_page_visit; +pub mod unique_page_visit; \ No newline at end of file diff --git a/src/models.rs b/src/models.rs index ca47b690..19f6e9f6 100644 --- a/src/models.rs +++ b/src/models.rs @@ -126,8 +126,6 @@ pub struct QuestTaskDocument { pub verify_endpoint: String, pub href: String, pub verify_endpoint_type: String, - pub api_url: Option, - pub regex: Option, pub calls: Option>, #[serde(default)] pub verify_redirect: Option, @@ -139,6 +137,8 @@ pub struct QuestTaskDocument { pub(crate) discord_guild_id: Option, #[serde(default)] pub(crate) contracts: Option>, + pub api_url: Option, + pub regex: Option, } pub_struct!(Serialize; Reward {