tuitbot_server/routes/
analytics.rs1use std::sync::Arc;
4
5use axum::extract::{Query, State};
6use axum::Json;
7use serde::Deserialize;
8use serde_json::{json, Value};
9use tuitbot_core::storage::analytics;
10
11use crate::error::ApiError;
12use crate::state::AppState;
13
14#[derive(Deserialize)]
16pub struct FollowersQuery {
17 #[serde(default = "default_days")]
19 pub days: u32,
20}
21
22fn default_days() -> u32 {
23 7
24}
25
26#[derive(Deserialize)]
28pub struct TopicsQuery {
29 #[serde(default = "default_topic_limit")]
31 pub limit: u32,
32}
33
34fn default_topic_limit() -> u32 {
35 20
36}
37
38#[derive(Deserialize)]
40pub struct RecentPerformanceQuery {
41 #[serde(default = "default_recent_limit")]
43 pub limit: u32,
44}
45
46fn default_recent_limit() -> u32 {
47 20
48}
49
50pub async fn followers(
52 State(state): State<Arc<AppState>>,
53 Query(params): Query<FollowersQuery>,
54) -> Result<Json<Value>, ApiError> {
55 let snapshots = analytics::get_follower_snapshots(&state.db, params.days).await?;
56 Ok(Json(json!(snapshots)))
57}
58
59pub async fn performance(State(state): State<Arc<AppState>>) -> Result<Json<Value>, ApiError> {
61 let avg_reply = analytics::get_avg_reply_engagement(&state.db).await?;
62 let avg_tweet = analytics::get_avg_tweet_engagement(&state.db).await?;
63 let (reply_count, tweet_count) = analytics::get_performance_counts(&state.db).await?;
64
65 Ok(Json(json!({
66 "avg_reply_engagement": avg_reply,
67 "avg_tweet_engagement": avg_tweet,
68 "measured_replies": reply_count,
69 "measured_tweets": tweet_count,
70 })))
71}
72
73pub async fn topics(
75 State(state): State<Arc<AppState>>,
76 Query(params): Query<TopicsQuery>,
77) -> Result<Json<Value>, ApiError> {
78 let scores = analytics::get_top_topics(&state.db, params.limit).await?;
79 Ok(Json(json!(scores)))
80}
81
82pub async fn summary(State(state): State<Arc<AppState>>) -> Result<Json<Value>, ApiError> {
84 let data = analytics::get_analytics_summary(&state.db).await?;
85 Ok(Json(json!(data)))
86}
87
88pub async fn recent_performance(
90 State(state): State<Arc<AppState>>,
91 Query(params): Query<RecentPerformanceQuery>,
92) -> Result<Json<Value>, ApiError> {
93 let items = analytics::get_recent_performance_items(&state.db, params.limit).await?;
94 Ok(Json(json!(items)))
95}