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

feat: remove need for '@' for user urls #39

merged opened by brookjeynes.dev targeting master from push-vnlonnkwstkp
Labels

None yet.

Participants 1
AT URI
at://did:plc:4mj54vc4ha3lh32ksxwunnbh/sh.tangled.repo.pull/3mdlzvvxxiv22
+64 -19
Diff #0
+30 -5
internal/server/handlers/router.go
··· 10 10 "yoten.app/internal/server/log" 11 11 "yoten.app/internal/server/middleware" 12 12 "yoten.app/internal/server/views" 13 + "yoten.app/internal/utils" 13 14 ) 14 15 15 16 type Handler struct { ··· 29 30 log.SubLogger(h.Logger, "middleware"), 30 31 ) 31 32 33 + router.Get("/pwa-manifest.json", h.PWAManifest) 34 + 35 + userRouter := h.UserRouter(&middleware) 36 + standardRouter := h.StandardRouter(&middleware) 37 + 32 38 router.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { 33 39 pat := chi.URLParam(r, "*") 34 - if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") { 35 - h.UserRouter(&middleware).ServeHTTP(w, r) 36 - } else { 37 - h.StandardRouter(&middleware).ServeHTTP(w, r) 40 + pathParts := strings.SplitN(pat, "/", 2) 41 + 42 + if len(pathParts) > 0 { 43 + firstPart := pathParts[0] 44 + 45 + // if using a DID or handle, just continue as per usual 46 + if utils.IsDid(firstPart) || utils.IsHandle(firstPart) { 47 + userRouter.ServeHTTP(w, r) 48 + return 49 + } 50 + 51 + // if using a handle with @, rewrite to work without @ 52 + if normalized := strings.TrimPrefix(firstPart, "@"); utils.IsHandle(normalized) { 53 + redirectPath := strings.Join(append([]string{normalized}, pathParts[1:]...), "/") 54 + 55 + redirectURL := *r.URL 56 + redirectURL.Path = "/" + redirectPath 57 + 58 + http.Redirect(w, r, redirectURL.String(), http.StatusFound) 59 + return 60 + } 61 + 38 62 } 63 + 64 + standardRouter.ServeHTTP(w, r) 39 65 }) 40 66 41 67 return router ··· 48 74 r.Handle("/static/*", h.HandleStatic()) 49 75 r.Get("/favicon.svg", h.HandleFavicon) 50 76 r.Get("/favicon.ico", h.HandleFavicon) 51 - r.Get("/pwa-manifest.json", h.PWAManifest) 52 77 53 78 r.Get("/", h.HandleIndexPage) 54 79 r.Get("/feed", h.HandleStudySessionFeed)
+1 -1
internal/server/views/edit-profile.templ
··· 145 145 <i class="w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" data-lucide="loader-circle"></i> 146 146 </button> 147 147 <button id="cancel-button" type="button" class="w-full"> 148 - <a href={ templ.SafeURL(fmt.Sprintf("/@%s", params.User.Did)) } class="btn btn-secondary"> 148 + <a href={ templ.SafeURL(fmt.Sprintf("/%s", params.User.Did)) } class="btn btn-secondary"> 149 149 Cancel 150 150 </a> 151 151 </button>
+8 -8
internal/server/views/new-study-session.templ
··· 18 18 19 19 activityName := "Select an activity" 20 20 if params.QueryParams.ActivityId != "" { 21 - activityId, err := strconv.ParseInt(params.QueryParams.ActivityId, 10, 64) 22 - if err == nil { 23 - for _, a := range params.Activities { 24 - if int64(a.ID) == activityId { 25 - activityName = a.Name 26 - } 27 - } 28 - } 21 + activityId, err := strconv.ParseInt(params.QueryParams.ActivityId, 10, 64) 22 + if err == nil { 23 + for _, a := range params.Activities { 24 + if int64(a.ID) == activityId { 25 + activityName = a.Name 26 + } 27 + } 28 + } 29 29 } 30 30 }} 31 31 @layouts.Base(layouts.BaseParams{Title: "new study session"}) {
+1 -1
internal/server/views/partials/comment.templ
··· 16 16 } 17 17 <div> 18 18 <div class="flex items-center gap-2"> 19 - <a href={ templ.URL(fmt.Sprintf("/@%s", params.Comment.Did)) } class="font-semibold"> 19 + <a href={ templ.URL(fmt.Sprintf("/%s", params.Comment.Did)) } class="font-semibold"> 20 20 { params.Comment.ProfileDisplayName } 21 21 </a> 22 22 <p class="pill pill-secondary px-2 py-0.5 h-fit items-center justify-center gap-1 w-fit flex">
+1 -1
internal/server/views/partials/header.templ
··· 39 39 class="absolute flex flex-col right-0 mt-2 p-1 gap-1 rounded w-48 bg-bg-light border border-bg-dark" 40 40 > 41 41 <a 42 - href={ templ.URL(fmt.Sprintf("/@%s", params.User.BskyProfile.Handle)) } 42 + href={ templ.URL(fmt.Sprintf("/%s", params.User.BskyProfile.Handle)) } 43 43 class="flex items-center px-4 py-2 text-sm hover:bg-bg gap-2" 44 44 > 45 45 <i class="w-4 h-4" data-lucide="user"></i>
+1 -1
internal/server/views/partials/profile.templ
··· 18 18 } 19 19 <div> 20 20 <div class="flex items-center gap-2"> 21 - <a href={ templ.SafeURL(fmt.Sprintf("/@%s", params.Profile.Did)) } class="font-semibold"> 21 + <a href={ templ.SafeURL(fmt.Sprintf("/%s", params.Profile.Did)) } class="font-semibold"> 22 22 { params.Profile.DisplayName } 23 23 </a> 24 24 <p class="pill pill-secondary h-fit items-center justify-center gap-1 w-fit hidden sm:flex">
+1 -1
internal/server/views/partials/reply.templ
··· 16 16 } 17 17 <div> 18 18 <div class="flex items-center gap-2"> 19 - <a href={ templ.URL(fmt.Sprintf("/@%s", props.Reply.Did)) } class="font-semibold"> 19 + <a href={ templ.URL(fmt.Sprintf("/%s", props.Reply.Did)) } class="font-semibold"> 20 20 { props.Reply.ProfileDisplayName } 21 21 </a> 22 22 <p class="pill pill-secondary px-2 py-0.5 h-fit items-center justify-center gap-1 w-fit flex">
+1 -1
internal/server/views/partials/study-session.templ
··· 83 83 } 84 84 <div> 85 85 <div class="flex items-center gap-2"> 86 - <a href={ templ.URL(fmt.Sprintf("/@%s", params.StudySession.Did)) } class="font-semibold"> 86 + <a href={ templ.URL(fmt.Sprintf("/%s", params.StudySession.Did)) } class="font-semibold"> 87 87 { params.StudySession.ProfileDisplayName } 88 88 </a> 89 89 <p class="pill pill-secondary px-2 py-0.5 h-fit items-center justify-center gap-1 w-fit flex">
+20
internal/utils/userutil.go
··· 1 + package utils 2 + 3 + import ( 4 + "regexp" 5 + ) 6 + 7 + var ( 8 + // ref: https://atproto.com/specs/handle 9 + handleRegex = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`) 10 + // ref: https://atproto.com/specs/did 11 + didRegex = regexp.MustCompile(`^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$`) 12 + ) 13 + 14 + func IsHandle(s string) bool { 15 + return handleRegex.MatchString(s) 16 + } 17 + 18 + func IsDid(s string) bool { 19 + return didRegex.MatchString(s) 20 + }

History

1 round 0 comments
sign up or login to add to the discussion
brookjeynes.dev submitted #0
1 commit
expand
feat: remove need for '@' for user urls
expand 0 comments
pull request successfully merged