This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / reporesolver / resolver.go
4.5 kB 168 lines
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 21var ( 22 blobPattern = regexp.MustCompile(`blob/[^/]+/(.*)$`) 23 treePattern = regexp.MustCompile(`tree/[^/]+/(.*)$`) 24) 25 26type RepoResolver struct { 27 config *config.Config 28 enforcer *rbac.Enforcer 29 execer db.Execer 30} 31 32func New(config *config.Config, enforcer *rbac.Enforcer, execer db.Execer) *RepoResolver { 33 return &RepoResolver{config: config, enforcer: enforcer, execer: execer} 34} 35 36// NOTE: this... should not even be here. the entire package will be removed in future refactor 37func GetBaseRepoPath(r *http.Request, repo *models.Repo) string { 38 if repo.RepoDid != "" { 39 return repo.RepoDid 40 } 41 var ( 42 user = chi.URLParam(r, "user") 43 name = chi.URLParam(r, "repo") 44 ) 45 if user == "" || name == "" { 46 return repo.RepoIdentifier() 47 } 48 return path.Join(user, name) 49} 50 51// TODO: move this out of `RepoResolver` struct 52func (rr *RepoResolver) Resolve(r *http.Request) (*models.Repo, 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 59 return repo, nil 60} 61 62// 1. [x] replace `RepoInfo` to `reporesolver.GetRepoInfo(r *http.Request, repo, user)` 63// 2. [x] remove `rr`, `CurrentDir`, `Ref` fields from `ResolvedRepo` 64// 3. [x] remove `ResolvedRepo` 65// 4. [ ] replace reporesolver to reposervice 66func (rr *RepoResolver) GetRepoInfo(r *http.Request, user *oauth.MultiAccountUser) repoinfo.RepoInfo { 67 ownerId, ook := r.Context().Value("resolvedId").(identity.Identity) 68 repo, rok := r.Context().Value("repo").(*models.Repo) 69 if !ook || !rok { 70 log.Println("malformed request, failed to get repo from context") 71 } 72 73 // get dir/ref 74 currentDir := extractCurrentDir(r.URL.EscapedPath()) 75 ref := chi.URLParam(r, "ref") 76 77 repoAt := repo.RepoAt() 78 isStarred := false 79 roles := repoinfo.RolesInRepo{} 80 if user != nil { 81 isStarred = db.GetStarStatus(rr.execer, user.Active.Did, repoAt) 82 roles.Roles = rr.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.RepoIdentifier()) 83 } 84 85 stats := repo.RepoStats 86 if stats == nil { 87 starCount, starErr := db.GetStarCount(rr.execer, repoAt) 88 if starErr != nil { 89 log.Println("failed to get star count for ", repoAt) 90 } 91 issueCount, err := db.GetIssueCount(rr.execer, repoAt) 92 if err != nil { 93 log.Println("failed to get issue count for ", repoAt) 94 } 95 pullCount, err := db.GetPullCount(rr.execer, repoAt) 96 if err != nil { 97 log.Println("failed to get pull count for ", repoAt) 98 } 99 stats = &models.RepoStats{ 100 StarCount: starCount, 101 IssueCount: issueCount, 102 PullCount: pullCount, 103 } 104 } 105 106 var sourceRepo *models.Repo 107 var err error 108 if repo.Source != "" { 109 if strings.HasPrefix(repo.Source, "did:") { 110 sourceRepo, err = db.GetRepoByDid(rr.execer, repo.Source) 111 } else { 112 sourceRepo, err = db.GetRepoByAtUri(rr.execer, repo.Source) 113 } 114 if err != nil { 115 log.Println("failed to get source repo", err) 116 } 117 } 118 119 repoInfo := repoinfo.RepoInfo{ 120 // this is basically a models.Repo 121 OwnerDid: ownerId.DID.String(), 122 OwnerHandle: ownerId.Handle.String(), 123 Name: repo.Name, 124 Rkey: repo.Rkey, 125 Description: repo.Description, 126 Website: repo.Website, 127 Topics: repo.Topics, 128 Knot: repo.Knot, 129 Spindle: repo.Spindle, 130 Stats: *stats, 131 132 // fork repo upstream 133 Source: sourceRepo, 134 135 // page context 136 CurrentDir: currentDir, 137 Ref: ref, 138 139 // info related to the session 140 IsStarred: isStarred, 141 Roles: roles, 142 } 143 144 return repoInfo 145} 146 147// extractCurrentDir gets the current directory for markdown link resolution. 148// for blob paths, returns the parent dir. for tree paths, returns the path itself. 149// 150// /@user/repo/blob/main/docs/README.md => docs 151// /@user/repo/tree/main/docs => docs 152func extractCurrentDir(fullPath string) string { 153 fullPath = strings.TrimPrefix(fullPath, "/") 154 155 if matches := blobPattern.FindStringSubmatch(fullPath); len(matches) > 1 { 156 return path.Dir(matches[1]) 157 } 158 159 if matches := treePattern.FindStringSubmatch(fullPath); len(matches) > 1 { 160 dir := strings.TrimSuffix(matches[1], "/") 161 if dir == "" { 162 return "." 163 } 164 return dir 165 } 166 167 return "." 168}