| 1 | package sheets |
| 2 | |
| 3 | import ( |
| 4 | "net/http" |
| 5 | |
| 6 | "amadan.net/oficina/home/connect" |
| 7 | ) |
| 8 | |
| 9 | // The root page is the anonymous entry page, and nothing else. |
| 10 | // |
| 11 | // It used to have a signed-in state too, and that state was the whole |
| 12 | // point of it: a magic link lands here, so if the page could not say |
| 13 | // "you are signed in, as this address", then a successful sign-in and a |
| 14 | // silently failed one looked identical to the person who clicked. That |
| 15 | // is exactly what happened the first time a link was clicked here — |
| 16 | // auth's SignedInPath defaults to "/", and this page told the arriving |
| 17 | // user there was nothing to reach at this address. |
| 18 | // |
| 19 | // The fix at the time was a line naming you and a button reading "Open |
| 20 | // your sheets", because /sheets did not exist yet. Once it did, that |
| 21 | // state was a page whose entire content was a link to the next page, |
| 22 | // and the layout's account menu names you on every screen anyway. So |
| 23 | // the signed-in half is a redirect now, and the original requirement is |
| 24 | // met better: you land on your sheets, which could not be mistaken for |
| 25 | // a failed sign-in. |
| 26 | // |
| 27 | // Both halves of the hop are closed — auth is configured with |
| 28 | // SignedInPath "/sheets" so a fresh click never comes through here at |
| 29 | // all, and this redirect covers somebody who later types the bare |
| 30 | // address. Neither alone is enough. |
| 31 | // |
| 32 | // With Home configured the signed-out half goes too: "/" 303s to |
| 33 | // /signin, which starts the Home exchange (Home #74, decision 2). That is |
| 34 | // what the app switcher's single-team hop now lands on — Home sends a |
| 35 | // person to the team instance's root rather than to /auth/start — and a |
| 36 | // landing page there would leave them one click short of the sign-in the |
| 37 | // hop used to run for them. Docs and Calendar already answer their root |
| 38 | // this way. Standalone keeps the landing page: there is no Home to hand |
| 39 | // off to, and it is where a stranger learns what this instance is. |
| 40 | // |
| 41 | // With Home, "/" goes through homeRequire, the guard every signed-in page |
| 42 | // uses, rather than a bare identity check. A Home session whose member |
| 43 | // lost admission is refused by identity but is still a live cookie, and |
| 44 | // connect's /signin skips the form for a live cookie: redirecting such a |
| 45 | // person straight to /signin sent them back here, forever (Astra, #39). |
| 46 | // The guard ends that session first, keeps its 503 for a storage failure, |
| 47 | // and sends a signed-out visitor to /signin?return_to=%2F. |
| 48 | func (a *App) handleIndex(w http.ResponseWriter, r *http.Request) { |
| 49 | if a.home != nil { |
| 50 | a.homeRequire(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 51 | http.Redirect(w, r, "/sheets", http.StatusSeeOther) |
| 52 | })).ServeHTTP(w, r) |
| 53 | return |
| 54 | } |
| 55 | if _, ok := a.identity(r); ok { |
| 56 | http.Redirect(w, r, "/sheets", http.StatusSeeOther) |
| 57 | return |
| 58 | } |
| 59 | a.render(w, r, "index", frame{}, http.StatusOK, nil) |
| 60 | } |
| 61 | |
| 62 | // identity returns the signed-in address, if any. A nil auth (tests) |
| 63 | // simply has no session. |
| 64 | func (a *App) identity(r *http.Request) (string, bool) { |
| 65 | if a.home != nil { |
| 66 | s, ok := a.homeSessions.From(r) |
| 67 | if !ok { |
| 68 | return "", false |
| 69 | } |
| 70 | if s.Method == connect.HomeMethod { |
| 71 | p, err := a.home.ResolveSession(r) |
| 72 | return p.Label, err == nil |
| 73 | } |
| 74 | } |
| 75 | if a.auth == nil { |
| 76 | return "", false |
| 77 | } |
| 78 | id, ok := a.auth.SessionFrom(r) |
| 79 | if !ok || string(id.Method) == connect.HomeMethod { |
| 80 | return "", false |
| 81 | } |
| 82 | return id.Address, true |
| 83 | } |
| 84 | |