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::account::AccountContext;
12use crate::error::ApiError;
13use crate::state::AppState;
14
15#[derive(Deserialize)]
17pub struct FollowersQuery {
18 #[serde(default = "default_days")]
20 pub days: u32,
21}
22
23fn default_days() -> u32 {
24 7
25}
26
27#[derive(Deserialize)]
29pub struct TopicsQuery {
30 #[serde(default = "default_topic_limit")]
32 pub limit: u32,
33}
34
35fn default_topic_limit() -> u32 {
36 20
37}
38
39#[derive(Deserialize)]
41pub struct RecentPerformanceQuery {
42 #[serde(default = "default_recent_limit")]
44 pub limit: u32,
45}
46
47fn default_recent_limit() -> u32 {
48 20
49}
50
51pub async fn followers(
53 State(state): State<Arc<AppState>>,
54 ctx: AccountContext,
55 Query(params): Query<FollowersQuery>,
56) -> Result<Json<Value>, ApiError> {
57 let snapshots =
58 analytics::get_follower_snapshots_for(&state.db, &ctx.account_id, params.days).await?;
59 Ok(Json(json!(snapshots)))
60}
61
62pub async fn performance(
64 State(state): State<Arc<AppState>>,
65 ctx: AccountContext,
66) -> Result<Json<Value>, ApiError> {
67 let avg_reply = analytics::get_avg_reply_engagement_for(&state.db, &ctx.account_id).await?;
68 let avg_tweet = analytics::get_avg_tweet_engagement_for(&state.db, &ctx.account_id).await?;
69 let (reply_count, tweet_count) =
70 analytics::get_performance_counts_for(&state.db, &ctx.account_id).await?;
71
72 Ok(Json(json!({
73 "avg_reply_engagement": avg_reply,
74 "avg_tweet_engagement": avg_tweet,
75 "measured_replies": reply_count,
76 "measured_tweets": tweet_count,
77 })))
78}
79
80pub async fn topics(
82 State(state): State<Arc<AppState>>,
83 ctx: AccountContext,
84 Query(params): Query<TopicsQuery>,
85) -> Result<Json<Value>, ApiError> {
86 let scores = analytics::get_top_topics_for(&state.db, &ctx.account_id, params.limit).await?;
87 Ok(Json(json!(scores)))
88}
89
90pub async fn summary(
92 State(state): State<Arc<AppState>>,
93 ctx: AccountContext,
94) -> Result<Json<Value>, ApiError> {
95 let data = analytics::get_analytics_summary_for(&state.db, &ctx.account_id).await?;
96 Ok(Json(json!(data)))
97}
98
99pub async fn recent_performance(
101 State(state): State<Arc<AppState>>,
102 ctx: AccountContext,
103 Query(params): Query<RecentPerformanceQuery>,
104) -> Result<Json<Value>, ApiError> {
105 let items =
106 analytics::get_recent_performance_items_for(&state.db, &ctx.account_id, params.limit)
107 .await?;
108 Ok(Json(json!(items)))
109}