@jpgilldev / steid

1use topcoat::{
2 Result,
3 context::Cx,
4 router::{error::redirect, page},
5 view::view,
6};
7
8use crate::application::sole_owner_handle;
9
10use super::context::{claimed, identity, orgs, server_error, users};
11
12/// The root.
13///
14/// The profile is the product, so the root is a signpost rather than a page of its own.
15/// Unclaimed, it sends you to `/auth/setup`. Otherwise it forwards to a profile: your
16/// own if you are signed in, and **the owner's if you are not**.
17///
18/// That last case is what makes a personal instance's front door work. Steid is meant to
19/// be someone's site, reached at their own domain, so a stranger arriving at the root
20/// must land on the owner rather than on a sign-in prompt — the thing they came for is
21/// the profile, and they will never sign in.
22///
23/// Only when the owner is unambiguous. A multi-user instance has no single profile to
24/// show, so it falls back to the generic landing rather than electing someone.
25#[page("/")]
26async fn home(cx: &Cx) -> Result {
27 if !claimed(cx).await? {
28 return Err(redirect("/auth/setup").into());
29 }
30
31 if let Some(identity) = identity(cx).await? {
32 return Err(redirect(&format!("/{}", identity.handle)).into());
33 }
34
35 if let Some(owner) = sole_owner_handle(&users(cx), &orgs(cx))
36 .await
37 .map_err(server_error)?
38 {
39 return Err(redirect(&format!("/{owner}")).into());
40 }
41
42 view! {
43 <h1>"steid"</h1>
44 <p><a href="/auth/login">"Sign in"</a></p>
45 }
46}