this repo has no description
1package reporesolver
2
3import (
4 "fmt"
5 "log"
6 "net/http"
7 "path"
8 "regexp"
9 "strings"
10
11 "github.com/bluesky-social/indigo/atproto/identity"
12 "github.com/go-chi/chi/v5"
13 "tangled.org/core/appview/config"
14 "tangled.org/core/appview/db"
15 "tangled.org/core/appview/models"
16 "tangled.org/core/appview/oauth"
17 "tangled.org/core/appview/pages/repoinfo"
18 "tangled.org/core/rbac"
19)
20
21type ResolvedRepo struct {
22 models.Repo
23 OwnerId identity.Identity
24 CurrentDir string
25 Ref string
26
27 rr *RepoResolver
28}
29
30type RepoResolver struct {
31 config *config.Config
32 enforcer *rbac.Enforcer
33 execer db.Execer
34}
35
36func New(config *config.Config, enforcer *rbac.Enforcer, execer db.Execer) *RepoResolver {
37 return &RepoResolver{config: config, enforcer: enforcer, execer: execer}
38}
39
40// NOTE: this... should not even be here. the entire package will be removed in future refactor
41func GetBaseRepoPath(r *http.Request, repo *models.Repo) string {
42 var (
43 user = chi.URLParam(r, "user")
44 name = chi.URLParam(r, "repo")
45 )
46 if user == "" || name == "" {
47 return repo.DidSlashRepo()
48 }
49 return path.Join(user, name)
50}
51
52func (rr *RepoResolver) Resolve(r *http.Request) (*ResolvedRepo, error) {
53 repo, ok := r.Context().Value("repo").(*models.Repo)
54 if !ok {
55 log.Println("malformed middleware: `repo` not exist in context")
56 return nil, fmt.Errorf("malformed middleware")
57 }
58 id, ok := r.Context().Value("resolvedId").(identity.Identity)
59 if !ok {
60 log.Println("malformed middleware")
61 return nil, fmt.Errorf("malformed middleware")
62 }
63
64 currentDir := path.Dir(extractPathAfterRef(r.URL.EscapedPath()))
65 ref := chi.URLParam(r, "ref")
66
67 return &ResolvedRepo{
68 Repo: *repo,
69 OwnerId: id,
70 CurrentDir: currentDir,
71 Ref: ref,
72
73 rr: rr,
74 }, nil
75}
76
77// this function is a bit weird since it now returns RepoInfo from an entirely different
78// package. we should refactor this or get rid of RepoInfo entirely.
79func (f *ResolvedRepo) RepoInfo(user *oauth.User) repoinfo.RepoInfo {
80 repoAt := f.RepoAt()
81 isStarred := false
82 roles := repoinfo.RolesInRepo{}
83 if user != nil {
84 isStarred = db.GetStarStatus(f.rr.execer, user.Did, repoAt)
85 roles.Roles = f.rr.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())
86 }
87
88 stats := f.RepoStats
89 if stats == nil {
90 starCount, err := db.GetStarCount(f.rr.execer, repoAt)
91 if err != nil {
92 log.Println("failed to get star count for ", repoAt)
93 }
94 issueCount, err := db.GetIssueCount(f.rr.execer, repoAt)
95 if err != nil {
96 log.Println("failed to get issue count for ", repoAt)
97 }
98 pullCount, err := db.GetPullCount(f.rr.execer, repoAt)
99 if err != nil {
100 log.Println("failed to get pull count for ", repoAt)
101 }
102 stats = &models.RepoStats{
103 StarCount: starCount,
104 IssueCount: issueCount,
105 PullCount: pullCount,
106 }
107 }
108
109 sourceRepo, err := db.GetRepoSourceRepo(f.rr.execer, repoAt)
110 if err != nil {
111 log.Println("failed to get repo by at uri", err)
112 }
113
114 repoInfo := repoinfo.RepoInfo{
115 // this is basically a models.Repo
116 OwnerDid: f.OwnerId.DID.String(),
117 OwnerHandle: f.OwnerId.Handle.String(),
118 Name: f.Name,
119 Rkey: f.Rkey,
120 Description: f.Description,
121 Website: f.Website,
122 Topics: f.Topics,
123 Knot: f.Knot,
124 Spindle: f.Spindle,
125 Stats: *stats,
126
127 // fork repo upstream
128 Source: sourceRepo,
129
130 CurrentDir: f.CurrentDir,
131 Ref: f.Ref,
132
133 // info related to the session
134 IsStarred: isStarred,
135 Roles: roles,
136 }
137
138 return repoInfo
139}
140
141// extractPathAfterRef gets the actual repository path
142// after the ref. for example:
143//
144// /@icyphox.sh/foorepo/blob/main/abc/xyz/ => abc/xyz/
145func extractPathAfterRef(fullPath string) string {
146 fullPath = strings.TrimPrefix(fullPath, "/")
147
148 // match blob/, tree/, or raw/ followed by any ref and then a slash
149 //
150 // captures everything after the final slash
151 pattern := `(?:blob|tree|raw)/[^/]+/(.*)$`
152
153 re := regexp.MustCompile(pattern)
154 matches := re.FindStringSubmatch(fullPath)
155
156 if len(matches) > 1 {
157 return matches[1]
158 }
159
160 return ""
161}