Yōten: A social tracker for your language learning journey built on the atproto.

feat: redirect user back to where they were after login redirect

Signed-off-by: brookjeynes <me@brookjeynes.dev>

authored by brookjeynes.dev and committed by

Tangled c85d9bbd 6f84a644

+24 -5
+13 -3
internal/server/middleware/middleware.go
··· 2 3 import ( 4 "context" 5 "log" 6 "net/http" 7 "slices" 8 "strings" 9 ··· 38 func AuthMiddleware(a *oauth.OAuth) middlewareFunc { 39 return func(next http.Handler) http.Handler { 40 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 - redirectFunc := func(w http.ResponseWriter, r *http.Request) { 42 - http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) 43 } 44 45 if r.Header.Get("HX-Request") == "true" { 46 redirectFunc = func(w http.ResponseWriter, _ *http.Request) { 47 - w.Header().Set("HX-Redirect", "/login") 48 w.WriteHeader(http.StatusOK) 49 } 50 } ··· 75 next.ServeHTTP(w, r) 76 return 77 } 78 79 id, err := mw.idResolver.ResolveIdent(r.Context(), didOrHandle) 80 if err != nil {
··· 2 3 import ( 4 "context" 5 + "fmt" 6 "log" 7 "net/http" 8 + "net/url" 9 "slices" 10 "strings" 11 ··· 40 func AuthMiddleware(a *oauth.OAuth) middlewareFunc { 41 return func(next http.Handler) http.Handler { 42 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 43 + returnURL := "/" 44 + if u, err := url.Parse(r.Header.Get("Referer")); err == nil { 45 + returnURL = u.RequestURI() 46 } 47 48 + loginURL := fmt.Sprintf("/login?return_url=%s", url.QueryEscape(returnURL)) 49 + 50 + redirectFunc := func(w http.ResponseWriter, r *http.Request) { 51 + http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect) 52 + } 53 if r.Header.Get("HX-Request") == "true" { 54 redirectFunc = func(w http.ResponseWriter, _ *http.Request) { 55 + w.Header().Set("HX-Redirect", loginURL) 56 w.WriteHeader(http.StatusOK) 57 } 58 } ··· 83 next.ServeHTTP(w, r) 84 return 85 } 86 + 87 + didOrHandle = strings.TrimPrefix(didOrHandle, "@") 88 89 id, err := mw.idResolver.ResolveIdent(r.Context(), didOrHandle) 90 if err != nil {
+9 -1
internal/server/views/login.templ
··· 28 </div> 29 <div class="flex flex-col gap-2"> 30 <label for="handle">Handle or DID</label> 31 - <input type="text" id="handle" name="handle" placeholder="username.bsky.social" class="input" autocomplete="username"/> 32 <p class="text-xs text-text-muted">Enter your Bluesky handle (e.g., alice.bsky.social) or full DID</p> 33 </div> 34 <button class="btn btn-primary" type="submit" id="login-button"> 35 <span>Log in with AT Protocol</span> 36 <i class="w-4 h-4" data-lucide="arrow-right"></i>
··· 28 </div> 29 <div class="flex flex-col gap-2"> 30 <label for="handle">Handle or DID</label> 31 + <input 32 + type="text" 33 + id="handle" 34 + name="handle" 35 + placeholder="username.bsky.social" 36 + class="input" 37 + autocomplete="username" 38 + /> 39 <p class="text-xs text-text-muted">Enter your Bluesky handle (e.g., alice.bsky.social) or full DID</p> 40 </div> 41 + <input type="hidden" name="return_url" value={ params.ReturnUrl }/> 42 <button class="btn btn-primary" type="submit" id="login-button"> 43 <span>Log in with AT Protocol</span> 44 <i class="w-4 h-4" data-lucide="arrow-right"></i>
+2 -1
internal/server/views/views.go
··· 18 19 type LoginPageParams struct { 20 // The current logged in user. 21 - User *types.User 22 } 23 24 type ProfilePageParams struct {
··· 18 19 type LoginPageParams struct { 20 // The current logged in user. 21 + User *types.User 22 + ReturnUrl string 23 } 24 25 type ProfilePageParams struct {