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