From eacad888f2dcd19d60f641342a3ba5f8f4fd63a2 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Sun, 3 Mar 2024 21:32:49 +0530 Subject: [PATCH 01/14] feat: update models --- src/models.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/models.rs b/src/models.rs index 652d8852..a5df0fe4 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,4 +1,5 @@ use mongodb::{bson, Database}; +use mongodb::bson::DateTime; use serde::{Deserialize, Serialize}; use serde_json::Value; use starknet::{ @@ -46,12 +47,14 @@ pub_struct!(Debug, Serialize, Deserialize; QuestDocument { pub_struct!(Deserialize; CompletedTasks { address: String, task_id: u32, + timestamp: i64, }); #[derive(Debug, Serialize, Deserialize)] pub struct CompletedTaskDocument { address: String, task_id: u32, + timestamp: DateTime, } pub_struct!(Serialize; Reward { @@ -92,6 +95,7 @@ pub_struct!(Deserialize; VerifyAchievementQuery { pub_struct!(Debug, Serialize, Deserialize; AchievedDocument { addr: String, achievement_id: u32, + timestamp:DateTime, }); pub_struct!(Debug, Serialize, Deserialize; AchievementDocument { From c5d72e6ac3c1252fbbf72f38d9d4f19a625fb158 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Sun, 3 Mar 2024 21:48:41 +0530 Subject: [PATCH 02/14] feat: add utils --- src/utils.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 059cea95..be4a14ae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -125,8 +125,9 @@ impl CompletedTasksTrait for AppState { ) -> Result { let completed_tasks_collection: Collection = self.db.collection("completed_tasks"); + let timestamp = Utc::now().timestamp_millis() as f64; let filter = doc! { "address": addr.to_string(), "task_id": task_id }; - let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id } }; + let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id , "timestamp":timestamp} }; let options = UpdateOptions::builder().upsert(true).build(); let result = completed_tasks_collection @@ -229,7 +230,6 @@ impl CompletedTasksTrait for AppState { // save the user_exp document in the collection let user_exp_collection = self.db.collection("user_exp"); // add doc with address ,experience and timestamp - let timestamp: f64 = Utc::now().timestamp_millis() as f64; let document = doc! { "address": addr.to_string(), "experience":experience, "timestamp":timestamp}; user_exp_collection.insert_one(document, None).await?; let view_collection: Collection = @@ -240,7 +240,7 @@ impl CompletedTasksTrait for AppState { experience.into(), timestamp, ) - .await; + .await; } Err(_e) => { get_error("Error querying quests".to_string()); @@ -293,8 +293,9 @@ impl AchievementsTrait for AppState { ) -> Result { let achieved_collection: Collection = self.db.collection("achieved"); let filter = doc! { "addr": addr.to_string(), "achievement_id": achievement_id }; + let timestamp = Utc::now().timestamp_millis() as f64; let update = - doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id } }; + doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id , "timestamp":timestamp } }; let options = UpdateOptions::builder().upsert(true).build(); let result = achieved_collection @@ -318,7 +319,6 @@ impl AchievementsTrait for AppState { let user_exp_collection = self.db.collection("user_exp"); // add doc with address ,experience and timestamp - let timestamp: f64 = Utc::now().timestamp_millis() as f64; let document = doc! { "address": addr.to_string(), "experience":experience, "timestamp":timestamp}; user_exp_collection.insert_one(document, None).await?; let view_collection: Collection = @@ -329,7 +329,7 @@ impl AchievementsTrait for AppState { experience.into(), timestamp, ) - .await; + .await; } None => {} } From feb69ec175301e92144645c1fc5938ef059f1f41 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Tue, 5 Mar 2024 13:54:20 +0530 Subject: [PATCH 03/14] feat: add timestamps --- src/models.rs | 3 +++ src/utils.rs | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/models.rs b/src/models.rs index 652d8852..226a2145 100644 --- a/src/models.rs +++ b/src/models.rs @@ -46,12 +46,14 @@ pub_struct!(Debug, Serialize, Deserialize; QuestDocument { pub_struct!(Deserialize; CompletedTasks { address: String, task_id: u32, + timestamp: i64, }); #[derive(Debug, Serialize, Deserialize)] pub struct CompletedTaskDocument { address: String, task_id: u32, + timestamp: i64, } pub_struct!(Serialize; Reward { @@ -92,6 +94,7 @@ pub_struct!(Deserialize; VerifyAchievementQuery { pub_struct!(Debug, Serialize, Deserialize; AchievedDocument { addr: String, achievement_id: u32, + timestamp: i64, }); pub_struct!(Debug, Serialize, Deserialize; AchievementDocument { diff --git a/src/utils.rs b/src/utils.rs index 059cea95..b395f269 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -125,8 +125,9 @@ impl CompletedTasksTrait for AppState { ) -> Result { let completed_tasks_collection: Collection = self.db.collection("completed_tasks"); + let created_at = Utc::now().timestamp_millis(); let filter = doc! { "address": addr.to_string(), "task_id": task_id }; - let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id } }; + let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id,"timestamp":created_at } }; let options = UpdateOptions::builder().upsert(true).build(); let result = completed_tasks_collection @@ -292,9 +293,10 @@ impl AchievementsTrait for AppState { achievement_id: u32, ) -> Result { let achieved_collection: Collection = self.db.collection("achieved"); + let created_at = Utc::now().timestamp_millis(); let filter = doc! { "addr": addr.to_string(), "achievement_id": achievement_id }; let update = - doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id } }; + doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id,"timestamp":created_at } }; let options = UpdateOptions::builder().upsert(true).build(); let result = achieved_collection From a837489cb2f7259242766483a534b6723d4b21ee Mon Sep 17 00:00:00 2001 From: ayushtom Date: Tue, 5 Mar 2024 21:18:32 +0530 Subject: [PATCH 04/14] feat: add graphic data --- src/endpoints/analytics/get_quest_activity.rs | 97 +++++++++++++++++++ src/endpoints/analytics/mod.rs | 1 + src/endpoints/mod.rs | 1 + src/models.rs | 15 +++ 4 files changed, 114 insertions(+) create mode 100644 src/endpoints/analytics/get_quest_activity.rs create mode 100644 src/endpoints/analytics/mod.rs diff --git a/src/endpoints/analytics/get_quest_activity.rs b/src/endpoints/analytics/get_quest_activity.rs new file mode 100644 index 00000000..67dd37e0 --- /dev/null +++ b/src/endpoints/analytics/get_quest_activity.rs @@ -0,0 +1,97 @@ +use crate::models::{QuestTaskDocument}; +use crate::{models::AppState, utils::get_error}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::{IntoResponse, Json}, +}; +use axum_auto_routes::route; +use futures::StreamExt; +use mongodb::bson::doc; +use std::sync::Arc; +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct GetQuestsQuery { + id: u32, +} + + +#[route(get, "/analytics/get_quest_activity", crate::endpoints::analytics::get_quest_activity)] +pub async fn handler(State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let quest_id = query.id; + let day_wise_distribution = vec![ + doc! { + "$match": doc! { + "quest_id": quest_id + } + }, + doc! { + "$group": doc! { + "_id": null, + "ids": doc! { + "$push": "$id" + } + } + }, + doc! { + "$lookup": doc! { + "from": "completed_tasks", + "localField": "ids", + "foreignField": "task_id", + "as": "matching_documents" + } + }, + doc! { + "$unwind": "$matching_documents" + }, + doc! { + "$replaceRoot": doc! { + "newRoot": "$matching_documents" + } + }, + doc! { + "$addFields": doc! { + "createdDate": doc! { + "$toDate": "$timestamp" + } + } + }, + doc! { + "$group": doc! { + "_id": doc! { + "$dateToString": doc! { + "format": "%Y-%m-%d %d", + "date": "$createdDate" + } + }, + "count": doc! { + "$sum": 1 + } + } + }, + doc! { + "$sort": doc! { + "_id": 1 + } + }, + ]; + + match state.db.collection::("tasks").aggregate(day_wise_distribution, None).await { + Ok(mut cursor) => { + let mut day_wise_distribution = Vec::new(); + while let Some(result) = cursor.next().await { + match result { + Ok(document) => { + day_wise_distribution.push(document); + } + _ => continue, + } + } + return (StatusCode::OK, Json(day_wise_distribution)).into_response(); + } + Err(_) => get_error("Error querying quest".to_string()), + } +} diff --git a/src/endpoints/analytics/mod.rs b/src/endpoints/analytics/mod.rs new file mode 100644 index 00000000..09a93a0b --- /dev/null +++ b/src/endpoints/analytics/mod.rs @@ -0,0 +1 @@ +pub mod get_quest_activity; \ No newline at end of file diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 187e827d..b8a1776c 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -13,3 +13,4 @@ pub mod leaderboard; pub mod quest_boost; pub mod quests; pub mod get_boosted_quests; +pub mod analytics; diff --git a/src/models.rs b/src/models.rs index 226a2145..acd56247 100644 --- a/src/models.rs +++ b/src/models.rs @@ -56,6 +56,21 @@ pub struct CompletedTaskDocument { timestamp: i64, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct QuestTaskDocument { + id: u32, + quest_id: u32, + name: String, + desc: String, + cta: String, + verify_endpoint: String, + verify_endpoint_type: String, + verify_redirect: Option, + href: String, + quiz_name: Option, +} + pub_struct!(Serialize; Reward { task_id: u32, nft_contract: String, From 1c92fab0caea7fddbd30db55fb25ba1ee7cc183c Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 11:51:21 +0530 Subject: [PATCH 05/14] feat: add quest participation details --- .../analytics/get_quest_participation.rs | 136 ++++++++++++++++++ src/endpoints/analytics/mod.rs | 3 +- 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/endpoints/analytics/get_quest_participation.rs diff --git a/src/endpoints/analytics/get_quest_participation.rs b/src/endpoints/analytics/get_quest_participation.rs new file mode 100644 index 00000000..da627763 --- /dev/null +++ b/src/endpoints/analytics/get_quest_participation.rs @@ -0,0 +1,136 @@ +use crate::models::QuestTaskDocument; +use crate::{models::AppState, utils::get_error}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::{IntoResponse, Json}, +}; +use axum_auto_routes::route; +use futures::StreamExt; +use mongodb::bson::doc; +use serde::Deserialize; +use std::sync::Arc; + +#[derive(Deserialize)] +pub struct GetQuestsQuery { + id: u32, +} + +#[route( +get, +"/analytics/get_quest_participation", +crate::endpoints::analytics::get_quest_participation +)] +pub async fn handler( + State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let quest_id = query.id; + let day_wise_distribution = vec![ + doc! { + "$match": doc! { + "quest_id": quest_id + } + }, + doc! { + "$group": doc! { + "_id": null, + "ids": doc! { + "$push": "$id" + }, + "otherDetails": doc! { + "$push": "$$ROOT" + } + } + }, + doc! { + "$lookup": doc! { + "from": "completed_tasks", + "localField": "ids", + "foreignField": "task_id", + "as": "matching_documents" + } + }, + doc! { + "$unwind": "$matching_documents" + }, + doc! { + "$group": doc! { + "_id": "$matching_documents.task_id", + "count": doc! { + "$sum": 1 + }, + "details": doc! { + "$first": "$otherDetails" + } + } + }, + doc! { + "$project": doc! { + "_id": 1, + "count": 1, + "otherDetails": doc! { + "$filter": doc! { + "input": "$details", + "as": "detail", + "cond": doc! { + "$eq": [ + "$$detail.id", + "$_id" + ] + } + } + } + } + }, + doc! { + "$unwind": "$otherDetails" + }, + doc! { + "$replaceRoot": doc! { + "newRoot": doc! { + "$mergeObjects": [ + "$matching_documents", + "$otherDetails", + doc! { + "participants": "$count" + } + ] + } + } + }, + doc! { + "$project": doc! { + "otherDetails": 0, + "_id":0, + "verify_endpoint": 0, + "verify_endpoint_type": 0, + "verify_redirect":0, + "href": 0, + "cta": 0, + + } + }, + ]; + + match state + .db + .collection::("tasks") + .aggregate(day_wise_distribution, None) + .await + { + Ok(mut cursor) => { + let mut task_activity = Vec::new(); + while let Some(result) = cursor.next().await { + match result { + Ok(document) => { + task_activity.push(document); + } + _ => continue, + } + } + return (StatusCode::OK, Json(task_activity)).into_response(); + } + Err(_) => get_error("Error querying tasks".to_string()), + } +} diff --git a/src/endpoints/analytics/mod.rs b/src/endpoints/analytics/mod.rs index 09a93a0b..49a37a18 100644 --- a/src/endpoints/analytics/mod.rs +++ b/src/endpoints/analytics/mod.rs @@ -1 +1,2 @@ -pub mod get_quest_activity; \ No newline at end of file +pub mod get_quest_activity; +pub mod get_quest_participation; \ No newline at end of file From d43ee11a5e4ece6d5aad5e1bdcc73b0e4b575f1a Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 14:32:50 +0530 Subject: [PATCH 06/14] feat: update response variable naming --- src/endpoints/analytics/get_quest_activity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoints/analytics/get_quest_activity.rs b/src/endpoints/analytics/get_quest_activity.rs index 67dd37e0..c04e0a5d 100644 --- a/src/endpoints/analytics/get_quest_activity.rs +++ b/src/endpoints/analytics/get_quest_activity.rs @@ -67,7 +67,7 @@ pub async fn handler(State(state): State>, "date": "$createdDate" } }, - "count": doc! { + "participants": doc! { "$sum": 1 } } From e68b5cba3fbd7880fbca405490c79270a88ab235 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 16:27:08 +0530 Subject: [PATCH 07/14] feat: update types --- src/models.rs | 5 ++--- src/utils.rs | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/models.rs b/src/models.rs index a5df0fe4..1b5088d5 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,4 @@ use mongodb::{bson, Database}; -use mongodb::bson::DateTime; use serde::{Deserialize, Serialize}; use serde_json::Value; use starknet::{ @@ -54,7 +53,7 @@ pub_struct!(Deserialize; CompletedTasks { pub struct CompletedTaskDocument { address: String, task_id: u32, - timestamp: DateTime, + timestamp: i64, } pub_struct!(Serialize; Reward { @@ -95,7 +94,7 @@ pub_struct!(Deserialize; VerifyAchievementQuery { pub_struct!(Debug, Serialize, Deserialize; AchievedDocument { addr: String, achievement_id: u32, - timestamp:DateTime, + timestamp:i64, }); pub_struct!(Debug, Serialize, Deserialize; AchievementDocument { diff --git a/src/utils.rs b/src/utils.rs index be4a14ae..b7920948 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -125,9 +125,9 @@ impl CompletedTasksTrait for AppState { ) -> Result { let completed_tasks_collection: Collection = self.db.collection("completed_tasks"); - let timestamp = Utc::now().timestamp_millis() as f64; + let created_at = Utc::now().timestamp_millis(); let filter = doc! { "address": addr.to_string(), "task_id": task_id }; - let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id , "timestamp":timestamp} }; + let update = doc! { "$setOnInsert": { "address": addr.to_string(), "task_id": task_id , "timestamp":created_at} }; let options = UpdateOptions::builder().upsert(true).build(); let result = completed_tasks_collection @@ -292,10 +292,11 @@ impl AchievementsTrait for AppState { achievement_id: u32, ) -> Result { let achieved_collection: Collection = self.db.collection("achieved"); + let created_at = Utc::now().timestamp_millis(); let filter = doc! { "addr": addr.to_string(), "achievement_id": achievement_id }; let timestamp = Utc::now().timestamp_millis() as f64; let update = - doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id , "timestamp":timestamp } }; + doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id , "timestamp":created_at } }; let options = UpdateOptions::builder().upsert(true).build(); let result = achieved_collection From 880ebeba038e3c2fb0eb77bd237e7a97aaa9ad5c Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 16:46:25 +0530 Subject: [PATCH 08/14] feat: add unique visitors fetch endpoint --- .../analytics/get_quest_participation.rs | 2 + .../analytics/get_unique_visitors.rs | 60 +++++++++++++++++++ src/endpoints/analytics/mod.rs | 3 +- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/endpoints/analytics/get_unique_visitors.rs diff --git a/src/endpoints/analytics/get_quest_participation.rs b/src/endpoints/analytics/get_quest_participation.rs index da627763..825e8a4b 100644 --- a/src/endpoints/analytics/get_quest_participation.rs +++ b/src/endpoints/analytics/get_quest_participation.rs @@ -108,6 +108,8 @@ pub async fn handler( "verify_redirect":0, "href": 0, "cta": 0, + "id": 0, + "quest_id": 0, } }, diff --git a/src/endpoints/analytics/get_unique_visitors.rs b/src/endpoints/analytics/get_unique_visitors.rs new file mode 100644 index 00000000..9c508c3d --- /dev/null +++ b/src/endpoints/analytics/get_unique_visitors.rs @@ -0,0 +1,60 @@ +use crate::models::QuestTaskDocument; +use crate::{models::AppState, utils::get_error}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::{IntoResponse, Json}, +}; +use axum_auto_routes::route; +use futures::TryStreamExt; +use mongodb::bson::doc; +use serde::Deserialize; +use std::sync::Arc; + +#[derive(Deserialize)] +pub struct GetQuestsQuery { + id: u32, +} + +#[route( +get, +"/analytics/get_unique_visitors", +crate::endpoints::analytics::get_unique_visitors +)] +pub async fn handler( + State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let quest_id = query.id; + let page_id = "quest_".to_owned() + quest_id.to_string().as_str(); + let total_viewers_pipeline = vec![ + doc! { + "$match": doc! { + "viewed_page_id": page_id + } + }, + doc! { + "$count":"total_viewers" + }, + ]; + + match state + .db + .collection::("unique_viewers") + .aggregate(total_viewers_pipeline, None) + .await + { + Ok(mut cursor) => { + let mut result = 0; + return match cursor.try_next().await { + Ok(Some(doc)) => { + result = doc.get("total_viewers").unwrap().as_i32().unwrap(); + (StatusCode::OK, Json(result)).into_response() + } + Ok(None) => (StatusCode::OK, Json(result)).into_response(), + Err(_) => get_error("Error querying quest".to_string()), + }; + } + Err(_) => get_error("Error querying quest".to_string()), + } +} diff --git a/src/endpoints/analytics/mod.rs b/src/endpoints/analytics/mod.rs index 49a37a18..e809e03e 100644 --- a/src/endpoints/analytics/mod.rs +++ b/src/endpoints/analytics/mod.rs @@ -1,2 +1,3 @@ pub mod get_quest_activity; -pub mod get_quest_participation; \ No newline at end of file +pub mod get_quest_participation; +pub mod get_unique_visitors; \ No newline at end of file From 03c73fa89f9e477f07c1159d7335a41947e39794 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 16:49:00 +0530 Subject: [PATCH 09/14] feat: add timestamp --- src/utils.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils.rs b/src/utils.rs index b7920948..7ba87258 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -230,6 +230,7 @@ impl CompletedTasksTrait for AppState { // save the user_exp document in the collection let user_exp_collection = self.db.collection("user_exp"); // add doc with address ,experience and timestamp + let timestamp: f64 = Utc::now().timestamp_millis() as f64; let document = doc! { "address": addr.to_string(), "experience":experience, "timestamp":timestamp}; user_exp_collection.insert_one(document, None).await?; let view_collection: Collection = @@ -320,6 +321,7 @@ impl AchievementsTrait for AppState { let user_exp_collection = self.db.collection("user_exp"); // add doc with address ,experience and timestamp + let timestamp: f64 = Utc::now().timestamp_millis() as f64; let document = doc! { "address": addr.to_string(), "experience":experience, "timestamp":timestamp}; user_exp_collection.insert_one(document, None).await?; let view_collection: Collection = From 2bbe1b0b460a0f4f274031f4a620c6355dc931b2 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 16:17:02 +0530 Subject: [PATCH 10/14] feat: add unique visits endpoint --- src/endpoints/mod.rs | 1 + src/endpoints/unique_page_visit.rs | 47 ++++++++++++++++++++++++++++++ src/main.rs | 1 + src/models.rs | 6 ++++ 4 files changed, 55 insertions(+) create mode 100644 src/endpoints/unique_page_visit.rs diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 187e827d..97578aea 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -13,3 +13,4 @@ pub mod leaderboard; pub mod quest_boost; pub mod quests; pub mod get_boosted_quests; +pub mod unique_page_visit; \ No newline at end of file diff --git a/src/endpoints/unique_page_visit.rs b/src/endpoints/unique_page_visit.rs new file mode 100644 index 00000000..24be6227 --- /dev/null +++ b/src/endpoints/unique_page_visit.rs @@ -0,0 +1,47 @@ +use std::net::SocketAddr; +use crate::{ + models::{AppState}, + utils::get_error, +}; +use axum::{ + extract::{Query, State, ConnectInfo}, + http::StatusCode, + response::IntoResponse, + Json, +}; +use axum_auto_routes::route; +use mongodb::bson::doc; +use serde::Deserialize; +use std::sync::Arc; +use chrono::Utc; +use mongodb::Collection; +use mongodb::options::UpdateOptions; +use serde_json::json; +use crate::models::UniquePageVisit; + +#[derive(Deserialize)] +pub struct GetQuestsQuery { + id: u32, +} + +#[route(post, "/unique_page_visit", crate::endpoints::unique_page_visit)] +pub async fn handler( + State(state): State>, + Query(query): Query, + ConnectInfo(addr): ConnectInfo, +) -> impl IntoResponse { + let id = query.id; + let page_id = "quest_".to_owned() + id.to_string().as_str(); + let unique_viewers_collection: Collection = + state.db.collection("unique_viewers"); + let created_at = Utc::now().timestamp_millis(); + let filter = doc! { "viewer_ip": addr.to_string(), "viewed_page_id": &page_id }; + let update = doc! { "$setOnInsert": { "viewer_ip": addr.to_string(), "viewed_page_id": &page_id,"timestamp":created_at } }; + let options = UpdateOptions::builder().upsert(true).build(); + + match unique_viewers_collection.update_one(filter, update, options) + .await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(_) => get_error("You don't own a stark domain".to_string()), + } +} diff --git a/src/main.rs b/src/main.rs index ac2ac576..9aac0b64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,6 +64,7 @@ async fn main() { acc.merge(r.to_router(shared_state.clone())) }) .layer(cors); + let addr = SocketAddr::from(([0, 0, 0, 0], conf.server.port)); println!("server: listening on http://0.0.0.0:{}", conf.server.port); axum::Server::bind(&addr) diff --git a/src/models.rs b/src/models.rs index 1b5088d5..db7baa82 100644 --- a/src/models.rs +++ b/src/models.rs @@ -82,6 +82,12 @@ pub_struct!(Deserialize; VerifyQuizQuery { user_answers_list: Vec>, }); +pub_struct!(Deserialize; UniquePageVisit { + viewer_ip: String, + viewed_page_id: String, + timestamp: i64, +}); + pub_struct!(Deserialize; AchievementQuery { addr: FieldElement, }); From 6c8ad97f4683caa64a3991ef891f8bbe0c448bc2 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 21:04:44 +0530 Subject: [PATCH 11/14] chore: update error message and remove warnings --- src/endpoints/unique_page_visit.rs | 2 +- src/utils.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/endpoints/unique_page_visit.rs b/src/endpoints/unique_page_visit.rs index 24be6227..ddf06259 100644 --- a/src/endpoints/unique_page_visit.rs +++ b/src/endpoints/unique_page_visit.rs @@ -42,6 +42,6 @@ pub async fn handler( match unique_viewers_collection.update_one(filter, update, options) .await { Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), - Err(_) => get_error("You don't own a stark domain".to_string()), + Err(_) => get_error("unable to detect page visit status".to_string()), } } diff --git a/src/utils.rs b/src/utils.rs index 7ba87258..5f9f4ae3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -295,7 +295,6 @@ impl AchievementsTrait for AppState { let achieved_collection: Collection = self.db.collection("achieved"); let created_at = Utc::now().timestamp_millis(); let filter = doc! { "addr": addr.to_string(), "achievement_id": achievement_id }; - let timestamp = Utc::now().timestamp_millis() as f64; let update = doc! { "$setOnInsert": { "addr": addr.to_string(), "achievement_id": achievement_id , "timestamp":created_at } }; let options = UpdateOptions::builder().upsert(true).build(); From 8bb672b1f3f1082f200fa3042b8f54f5a97e762d Mon Sep 17 00:00:00 2001 From: ayushtom Date: Wed, 6 Mar 2024 21:34:13 +0530 Subject: [PATCH 12/14] feat: update param --- src/endpoints/unique_page_visit.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/endpoints/unique_page_visit.rs b/src/endpoints/unique_page_visit.rs index ddf06259..a785f768 100644 --- a/src/endpoints/unique_page_visit.rs +++ b/src/endpoints/unique_page_visit.rs @@ -21,22 +21,21 @@ use crate::models::UniquePageVisit; #[derive(Deserialize)] pub struct GetQuestsQuery { - id: u32, + page_id: String, } -#[route(post, "/unique_page_visit", crate::endpoints::unique_page_visit)] +#[route(get, "/unique_page_visit", crate::endpoints::unique_page_visit)] pub async fn handler( State(state): State>, Query(query): Query, ConnectInfo(addr): ConnectInfo, ) -> impl IntoResponse { - let id = query.id; - let page_id = "quest_".to_owned() + id.to_string().as_str(); + let id = query.page_id; let unique_viewers_collection: Collection = state.db.collection("unique_viewers"); let created_at = Utc::now().timestamp_millis(); - let filter = doc! { "viewer_ip": addr.to_string(), "viewed_page_id": &page_id }; - let update = doc! { "$setOnInsert": { "viewer_ip": addr.to_string(), "viewed_page_id": &page_id,"timestamp":created_at } }; + let filter = doc! { "viewer_ip": addr.to_string(), "viewed_page_id": &id }; + let update = doc! { "$setOnInsert": { "viewer_ip": addr.to_string(), "viewed_page_id": &id,"timestamp":created_at } }; let options = UpdateOptions::builder().upsert(true).build(); match unique_viewers_collection.update_one(filter, update, options) From 4b3956ef9c97e242d5e7d77922efaac06906b11f Mon Sep 17 00:00:00 2001 From: ayushtom Date: Thu, 7 Mar 2024 18:40:18 +0530 Subject: [PATCH 13/14] feat: remove unique page visit endpoint --- src/endpoints/mod.rs | 4 +++ src/endpoints/unique_page_visit.rs | 46 ------------------------------ 2 files changed, 4 insertions(+), 46 deletions(-) delete mode 100644 src/endpoints/unique_page_visit.rs diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index d39c7001..75633381 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -12,6 +12,10 @@ pub mod has_completed_quest; pub mod leaderboard; pub mod quest_boost; pub mod quests; +<<<<<<< Updated upstream pub mod get_boosted_quests; pub mod analytics; pub mod unique_page_visit; +======= +pub mod get_boosted_quests; +>>>>>>> Stashed changes diff --git a/src/endpoints/unique_page_visit.rs b/src/endpoints/unique_page_visit.rs deleted file mode 100644 index a785f768..00000000 --- a/src/endpoints/unique_page_visit.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::net::SocketAddr; -use crate::{ - models::{AppState}, - utils::get_error, -}; -use axum::{ - extract::{Query, State, ConnectInfo}, - http::StatusCode, - response::IntoResponse, - Json, -}; -use axum_auto_routes::route; -use mongodb::bson::doc; -use serde::Deserialize; -use std::sync::Arc; -use chrono::Utc; -use mongodb::Collection; -use mongodb::options::UpdateOptions; -use serde_json::json; -use crate::models::UniquePageVisit; - -#[derive(Deserialize)] -pub struct GetQuestsQuery { - page_id: String, -} - -#[route(get, "/unique_page_visit", crate::endpoints::unique_page_visit)] -pub async fn handler( - State(state): State>, - Query(query): Query, - ConnectInfo(addr): ConnectInfo, -) -> impl IntoResponse { - let id = query.page_id; - let unique_viewers_collection: Collection = - state.db.collection("unique_viewers"); - let created_at = Utc::now().timestamp_millis(); - let filter = doc! { "viewer_ip": addr.to_string(), "viewed_page_id": &id }; - let update = doc! { "$setOnInsert": { "viewer_ip": addr.to_string(), "viewed_page_id": &id,"timestamp":created_at } }; - let options = UpdateOptions::builder().upsert(true).build(); - - match unique_viewers_collection.update_one(filter, update, options) - .await { - Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), - Err(_) => get_error("unable to detect page visit status".to_string()), - } -} From b78f4ceb6e7d03d918bf908c846b0252eb87b393 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Thu, 7 Mar 2024 18:46:08 +0530 Subject: [PATCH 14/14] feat: remove conflicts --- src/endpoints/mod.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 75633381..a349eb6c 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -12,10 +12,5 @@ pub mod has_completed_quest; pub mod leaderboard; pub mod quest_boost; pub mod quests; -<<<<<<< Updated upstream pub mod get_boosted_quests; -pub mod analytics; -pub mod unique_page_visit; -======= -pub mod get_boosted_quests; ->>>>>>> Stashed changes +pub mod analytics; \ No newline at end of file