oficina / sheets Public

The Keymail continuation is the door's notice; test the door

Review finding: the page between the door and Keymail was still Home's
bare page. It keeps Home's head (the meta refresh) and wears the door's
card on the sky.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 91e7f8ca7daf93a6081b1be19f0a4f6607fed66c parent ca82a11
3 files changed, +58 −3
  • internal/sheets/home.go +17 −1
  • internal/sheets/signin_door_test.go +39 −0
  • internal/sheets/templates/home_oauth.html +2 −2
diff --git a/internal/sheets/home.go b/internal/sheets/home.go
index 1d869ff..219ab3a 100644
--- a/internal/sheets/home.go
+++ b/internal/sheets/home.go
@@ -1,6 +1,9 @@
package sheets
import (
+ "amadan.net/oficina/estilo.git/brand"
+ "amadan.net/oficina/estilo.git/chrome"
+ "amadan.net/oficina/estilo.git/sky"
"context"
"database/sql"
"errors"
@@ -159,7 +162,13 @@ func (a *App) homeLocalComplete(w http.ResponseWriter, r *http.Request) {
func (a *App) homeLocalBegin(w http.ResponseWriter, r *http.Request) {
connect.OAuthContinuation(a.origin, a.handleBegin, func(w http.ResponseWriter, r *http.Request, destination string) {
p := connect.OAuthPage(destination)
- a.render(w, r, "home_oauth", frame{parts: []string{p.Title}, signinPage: true}, http.StatusOK, p)
+ // The page between the door and Keymail is the same card: the
+ // refresh stays Home's (head), the body is the door's notice.
+ a.render(w, r, "home_oauth", frame{parts: []string{p.Title}, signinPage: true}, http.StatusOK, homeOAuthView{
+ Page: p,
+ Door: chrome.SignInNotice{Icon: brand.Path("sheets"), App: "Sheets", Sky: sky.For(r.Host), Heading: p.Title,
+ Link: &chrome.Link{Href: p.URL, Label: p.ActionLabel}},
+ })
})(w, r)
}
@@ -173,3 +182,10 @@ func (a *App) rejectDisabledHome(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
})
}
+
+// homeOAuthView is the Keymail continuation page's data: Home's page (for
+// its meta refresh) and the door card around the way on.
+type homeOAuthView struct {
+ Page connect.OAuthData
+ Door chrome.SignInNotice
+}
diff --git a/internal/sheets/signin_door_test.go b/internal/sheets/signin_door_test.go
new file mode 100644
index 0000000..f74dc0a
--- /dev/null
+++ b/internal/sheets/signin_door_test.go
@@ -0,0 +1,39 @@
+package sheets
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+// The sign-in page is the Oficina door (estilo chrome): a card on the
+// suite sky with this app's mark and name, its sky layers served signed
+// out by estilo's handler rather than shadowed by the app's /static/.
+func TestSignInPageIsTheDoor(t *testing.T) {
+ app := New(Config{})
+ GET := func(p string) *httptest.ResponseRecorder {
+ return do(t, app, httptest.NewRequest(http.MethodGet, p, nil))
+ }
+ rec := GET("/signin")
+ body := rec.Body.String()
+ for _, want := range []string{"estilo-door", "<span>Sheets</span>", `name="address"`, " autofocus"} {
+ if !strings.Contains(body, want) {
+ t.Errorf("sign-in page lacks %q", want)
+ }
+ }
+ if !regexp.MustCompile(`<img estilo-sky-layer="placeholder"[^>]*src="data:image/png;base64,`).MatchString(body) {
+ t.Error("sign-in page has no inline sky placeholder")
+ }
+ layer := regexp.MustCompile(`<img estilo-sky-layer="[a-z]+"[^>]*src="(/static/estilo/sky/v1/[^"]+)"`).FindStringSubmatch(body)
+ if layer == nil {
+ t.Fatal("sign-in page links no served sky layer")
+ }
+ if got := GET(layer[1]); got.Code != http.StatusOK || got.Header().Get("Content-Type") != "image/svg+xml" {
+ t.Errorf("GET %s signed out: %d %q, want 200 image/svg+xml", layer[1], got.Code, got.Header().Get("Content-Type"))
+ }
+ if !regexp.MustCompile(`/static/estilo/sky\.[0-9a-f]{16}\.css`).MatchString(body) {
+ t.Error("sign-in page does not link sky.css")
+ }
+}
diff --git a/internal/sheets/templates/home_oauth.html b/internal/sheets/templates/home_oauth.html
index ad744a9..0e4115a 100644
--- a/internal/sheets/templates/home_oauth.html
+++ b/internal/sheets/templates/home_oauth.html
@@ -1,2 +1,2 @@
-{{define "head"}}{{template "home-oauth-head" .Data}}{{end}}
-{{define "content"}}{{template "home-oauth" .Data}}{{end}}
+{{define "head"}}{{template "home-oauth-head" .Data.Page}}{{end}}
+{{define "content"}}{{template "estilo-signin-sent" .Data.Door}}{{end}}