From a4193f830fe39a6aceec0c361d6d88447022ac63 Mon Sep 17 00:00:00 2001 From: Shav Kinderlehrer Date: Mon, 8 Apr 2024 06:55:05 -0400 Subject: Add basic analytics --- src/get.rs | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) (limited to 'src/get.rs') diff --git a/src/get.rs b/src/get.rs index a00ac48..1e364be 100644 --- a/src/get.rs +++ b/src/get.rs @@ -1,3 +1,4 @@ +use std::collections::hash_map::HashMap; use std::net::SocketAddr; use axum::extract::{ConnectInfo, Path}; @@ -9,9 +10,16 @@ use axum::Extension; use info_utils::prelude::*; use crate::ServerState; +use crate::TrackingRow; use crate::UdsConnectInfo; use crate::UrlRow; +enum TrackingParameter { + Ip, + Referrer, + UserAgent, +} + pub async fn index(Extension(state): Extension) -> impl IntoResponse { if let Some(redirect) = state.main_page_redirect { return Redirect::temporary(redirect.as_str()).into_response(); @@ -212,3 +220,250 @@ pub async fn create_id(Extension(state): Extension) -> Html state.host )) } + +pub async fn tracking(Extension(state): Extension) -> impl IntoResponse { + let url_rows: Vec = sqlx::query_as("SELECT * FROM chela.urls") + .fetch_all(&state.db_pool) + .await + .unwrap(); + let html = format!( + r#" + + + + {} Tracking + + + + {} + + + "#, + state.host, + table_css(), + make_table_from_urls(&url_rows) + ); + + return Html(html).into_response(); +} + +pub async fn tracking_id( + Extension(state): Extension, + Path(id): Path, +) -> impl IntoResponse { + let tracking_rows: Vec = + sqlx::query_as("SELECT * FROM chela.tracking WHERE id = $1") + .bind(id.clone()) + .fetch_all(&state.db_pool) + .await + .unwrap(); + let url: UrlRow = sqlx::query_as("SELECT * FROM chela.urls WHERE id = $1") + .bind(id.clone()) + .fetch_one(&state.db_pool) + .await + .unwrap(); + + let html = format!( + r#" + + + + {} Tracking {} + + + +

Tracking for {} from ID '{}'

+

Visited {} times

+ {} + +

By IP

+ {} +

By Referrer

+ {} +

By User Agent

+ {} + + + "#, + state.host, + id, + table_css(), + url.url, + url.url, + url.id, + tracking_rows.len(), + make_table_from_tracking(&tracking_rows), + make_grouped_table_from_tracking(&tracking_rows, TrackingParameter::Ip), + make_grouped_table_from_tracking(&tracking_rows, TrackingParameter::Referrer), + make_grouped_table_from_tracking(&tracking_rows, TrackingParameter::UserAgent) + ); + + return Html(html).into_response(); +} + +fn make_table_from_tracking(rows: &Vec) -> String { + let mut html = r#" + + + + + + + + + + + + + + + "# + .to_string(); + + for row in rows { + html += &format!( + r#" + + + + + + + + "#, + row.timestamp, + row.id, + row.ip.as_ref().unwrap_or(&String::default()), + row.referrer.as_ref().unwrap_or(&String::default()), + row.user_agent.as_ref().unwrap_or(&String::default()) + ); + } + + html += r#" +
TimestampIDIPReferrerUser Agent
{}{}{}{}{}
+ "#; + + html +} + +fn make_grouped_table_from_tracking(rows: &Vec, group: TrackingParameter) -> String { + let column_name = match group { + TrackingParameter::Ip => "IP", + TrackingParameter::Referrer => "Referrer", + TrackingParameter::UserAgent => "User Agent", + } + .to_string(); + + let mut html = format!( + r#" + + + + + + + + + + "#, + column_name + ); + + let mut aggregate: HashMap = HashMap::new(); + + for row in rows { + let tracker = match group { + TrackingParameter::Ip => { + let v = match &row.ip { + Some(val) => val, + None => continue, + }; + v + } + TrackingParameter::Referrer => { + let v = match &row.referrer { + Some(val) => val, + None => continue, + }; + v + } + TrackingParameter::UserAgent => { + let v = match &row.user_agent { + Some(val) => val, + None => continue, + }; + v + } + }; + let count = aggregate.get(tracker).unwrap_or(&0); + aggregate.insert(tracker.to_string(), count + 1); + } + + for (key, val) in aggregate { + html += &format!( + r#" + + + + + "#, + val, key + ); + } + + html += r#" +
Occurrences{}
{}{}
+ "#; + + html +} + +fn make_table_from_urls(urls: &Vec) -> String { + let mut html = r#" + + + + + + + + + + + + + "# + .to_string(); + + for url in urls { + html += &format!( + r#" + + + + + + + "#, + url.index, url.id, url.id, url.url, url.url, url.custom_id + ); + } + html += r#" +
IndexIDURLCustom ID
{}{}{}{}
+ "#; + + html +} + +fn table_css() -> String { + r#" + tr:nth-child(even) { + background: #f2f2f2; + } + + table, th, td { + border: 1px solid black; + } + "# + .to_string() +} -- cgit v1.2.3