steid

@jamesgill /

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