Go · 1712 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package repo
4
5 import (
6 "net/http"
7 "strings"
8
9 "github.com/jackc/pgx/v5/pgtype"
10
11 reposdb "github.com/tenseleyFlow/shithub/internal/repos/sqlc"
12 )
13
14 // tryRedirect resolves a (stale_owner, stale_name) URL to its current
15 // canonical form via repo_redirects. Returns "" when no redirect row
16 // matches, in which case the caller should 404. The returned URL
17 // preserves the request's RemainingPath so e.g. /old/repo/blob/x
18 // becomes /new/repo/blob/x — handy when more granular routes ship.
19 func (h *Handlers) tryRedirect(r *http.Request, ownerName, repoName string) string {
20 owner, err := h.uq.GetUserByUsername(r.Context(), h.d.Pool, ownerName)
21 if err != nil {
22 return ""
23 }
24 repoID, err := h.rq.LookupRedirectByUserOwner(r.Context(), h.d.Pool, reposdb.LookupRedirectByUserOwnerParams{
25 OldOwnerUserID: pgtype.Int8{Int64: owner.ID, Valid: true},
26 OldName: repoName,
27 })
28 if err != nil {
29 return ""
30 }
31 row, err := h.rq.GetRepoByID(r.Context(), h.d.Pool, repoID)
32 if err != nil || row.DeletedAt.Valid {
33 // Repo gone for real; let the caller serve a clean 404 instead
34 // of redirecting into a 404. This keeps user agents from
35 // chasing dead links via a 301.
36 return ""
37 }
38 currentOwner := ""
39 if row.OwnerUserID.Valid {
40 if u, err := h.uq.GetUserByID(r.Context(), h.d.Pool, row.OwnerUserID.Int64); err == nil {
41 currentOwner = u.Username
42 }
43 }
44 if currentOwner == "" || row.Name == "" {
45 return ""
46 }
47 // Preserve any path tail beyond /{owner}/{repo} (rare today; will
48 // matter when blob/tree/issues subpaths land).
49 tail := strings.TrimPrefix(r.URL.Path, "/"+ownerName+"/"+repoName)
50 return "/" + currentOwner + "/" + row.Name + tail
51 }
52