Skip to main content

tuitbot_server/routes/
activity.rs

1//! Activity feed endpoints.
2
3use std::sync::Arc;
4
5use axum::extract::{Query, State};
6use axum::Json;
7use serde::Deserialize;
8use serde_json::{json, Value};
9use tuitbot_core::storage::{action_log, rate_limits};
10
11use crate::error::ApiError;
12use crate::state::AppState;
13
14/// Query parameters for the activity endpoint.
15#[derive(Deserialize)]
16pub struct ActivityQuery {
17    /// Maximum number of actions to return (default: 50).
18    #[serde(default = "default_limit")]
19    pub limit: u32,
20    /// Offset for pagination (default: 0).
21    #[serde(default)]
22    pub offset: u32,
23    /// Filter by action type. Use "all" or omit for no filter.
24    #[serde(rename = "type")]
25    pub action_type: Option<String>,
26    /// Filter by status (e.g. "failure" for errors).
27    pub status: Option<String>,
28}
29
30fn default_limit() -> u32 {
31    50
32}
33
34/// `GET /api/activity` — paginated, filterable action log.
35pub async fn list_activity(
36    State(state): State<Arc<AppState>>,
37    Query(params): Query<ActivityQuery>,
38) -> Result<Json<Value>, ApiError> {
39    let type_filter =
40        params
41            .action_type
42            .as_deref()
43            .and_then(|t| if t == "all" { None } else { Some(t) });
44    let status_filter = params.status.as_deref();
45
46    let actions = action_log::get_actions_paginated(
47        &state.db,
48        params.limit,
49        params.offset,
50        type_filter,
51        status_filter,
52    )
53    .await?;
54
55    let total = action_log::get_actions_count(&state.db, type_filter, status_filter).await?;
56
57    Ok(Json(json!({
58        "actions": actions,
59        "total": total,
60        "limit": params.limit,
61        "offset": params.offset,
62    })))
63}
64
65/// `GET /api/activity/rate-limits` — current daily rate limit usage.
66pub async fn rate_limit_usage(State(state): State<Arc<AppState>>) -> Result<Json<Value>, ApiError> {
67    let usage = rate_limits::get_daily_usage(&state.db).await?;
68    Ok(Json(json!(usage)))
69}