Skip to main content

codoseo_web/routes/
mod.rs

1//! Signed-in screens. Each module owns its routes and merges them in here.
2
3pub mod account;
4pub mod admin;
5pub mod api;
6pub mod audit;
7pub mod billing;
8pub mod bot;
9pub mod changes;
10pub mod crawls;
11pub mod explorer;
12pub mod export;
13pub mod landing;
14pub mod mcp;
15pub mod monitoring;
16pub mod quick;
17pub mod rankorg;
18pub mod search;
19pub mod seo;
20pub mod settings_alerts;
21pub mod settings_keys;
22pub mod sites;
23
24use axum::Router;
25use axum::extract::State;
26use axum::response::{IntoResponse, Redirect, Response};
27use axum::routing::get;
28
29use crate::auth::CurrentUser;
30use crate::config::Mode;
31use crate::error::AppError;
32use crate::state::AppState;
33
34pub fn router() -> Router<AppState> {
35    Router::new()
36        .route("/", get(home))
37        .merge(account::routes())
38        .merge(sites::routes())
39        .merge(crawls::routes())
40        .merge(explorer::routes())
41        .merge(audit::routes())
42        .merge(changes::routes())
43        .merge(export::routes())
44        .merge(search::routes())
45        .merge(quick::routes())
46        .merge(monitoring::routes())
47        .merge(settings_alerts::routes())
48        .merge(settings_keys::routes())
49        .merge(api::routes())
50        .merge(billing::routes())
51        .merge(admin::routes())
52        .merge(rankorg::routes())
53        .route("/bot", get(bot::page))
54        .route("/robots.txt", get(seo::robots))
55        .route("/llms.txt", get(seo::llms))
56        .route("/sitemap.xml", get(seo::sitemap))
57}
58
59/// `/`: the first site's audit, or onboarding when there is no site yet. A signed-out visitor
60/// gets the landing page on the cloud and the login page everywhere else.
61async fn home(
62    State(state): State<AppState>,
63    user: Option<CurrentUser>,
64) -> Result<Response, AppError> {
65    let Some(user) = user else {
66        return if state.config.mode == Mode::Cloud {
67            landing::page(&state)
68        } else {
69            Ok(Redirect::to("/login?next=%2F").into_response())
70        };
71    };
72    let sites = codoseo_store::sites::list_for_account(&state.pool, user.id()).await?;
73    Ok(match sites.first() {
74        Some(s) => Redirect::to(&format!("/s/{}/audit", s.id)).into_response(),
75        None => Redirect::to("/sites").into_response(),
76    })
77}