forked from tangled.org/core
Monorepo for Tangled

appview: diet the reporesolver

Ideally we should completely remove it.

Signed-off-by: Seongmin Lee <git@boltless.me>

authored by boltless.me and committed by Tangled e4fc543c a6290643

Changed files
+98 -99
appview
db
issues
pulls
repo
reporesolver
state
rbac
+11
appview/db/repos.go
··· 411 411 return nullableSource.String, nil 412 412 } 413 413 414 + func GetRepoSourceRepo(e Execer, repoAt syntax.ATURI) (*models.Repo, error) { 415 + source, err := GetRepoSource(e, repoAt) 416 + if source == "" || errors.Is(err, sql.ErrNoRows) { 417 + return nil, nil 418 + } 419 + if err != nil { 420 + return nil, err 421 + } 422 + return GetRepoByAtUri(e, source) 423 + } 424 + 414 425 func GetForksByDid(e Execer, did string) ([]models.Repo, error) { 415 426 var repos []models.Repo 416 427
+8 -17
appview/issues/issues.go
··· 7 7 "fmt" 8 8 "log/slog" 9 9 "net/http" 10 - "slices" 11 10 "time" 12 11 13 12 comatproto "github.com/bluesky-social/indigo/api/atproto" ··· 286 285 return 287 286 } 288 287 289 - collaborators, err := f.Collaborators(r.Context()) 290 - if err != nil { 291 - l.Error("failed to fetch repo collaborators", "err", err) 292 - } 293 - isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 294 - return user.Did == collab.Did 295 - }) 288 + roles := f.RolesInRepo(user) 289 + isRepoOwner := roles.IsOwner() 290 + isCollaborator := roles.IsCollaborator() 296 291 isIssueOwner := user.Did == issue.Did 297 292 298 293 // TODO: make this more granular 299 - if isIssueOwner || isCollaborator { 294 + if isIssueOwner || isRepoOwner || isCollaborator { 300 295 err = db.CloseIssues( 301 296 rp.db, 302 297 db.FilterEq("id", issue.Id), ··· 338 333 return 339 334 } 340 335 341 - collaborators, err := f.Collaborators(r.Context()) 342 - if err != nil { 343 - l.Error("failed to fetch repo collaborators", "err", err) 344 - } 345 - isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { 346 - return user.Did == collab.Did 347 - }) 336 + roles := f.RolesInRepo(user) 337 + isRepoOwner := roles.IsOwner() 338 + isCollaborator := roles.IsCollaborator() 348 339 isIssueOwner := user.Did == issue.Did 349 340 350 - if isCollaborator || isIssueOwner { 341 + if isCollaborator || isRepoOwner || isIssueOwner { 351 342 err := db.ReopenIssues( 352 343 rp.db, 353 344 db.FilterEq("id", issue.Id),
+4 -2
appview/pulls/pulls.go
··· 877 877 } 878 878 879 879 // Determine PR type based on input parameters 880 - isPushAllowed := f.RepoInfo(user).Roles.IsPushAllowed() 880 + roles := f.RolesInRepo(user) 881 + isPushAllowed := roles.IsPushAllowed() 881 882 isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == "" 882 883 isForkBased := fromFork != "" && sourceBranch != "" 883 884 isPatchBased := patch != "" && !isBranchBased && !isForkBased ··· 1673 1674 return 1674 1675 } 1675 1676 1676 - if !f.RepoInfo(user).Roles.IsPushAllowed() { 1677 + roles := f.RolesInRepo(user) 1678 + if !roles.IsPushAllowed() { 1677 1679 log.Println("unauthorized user") 1678 1680 w.WriteHeader(http.StatusUnauthorized) 1679 1681 return
+30 -2
appview/repo/settings.go
··· 10 10 11 11 "tangled.org/core/api/tangled" 12 12 "tangled.org/core/appview/db" 13 + "tangled.org/core/appview/models" 13 14 "tangled.org/core/appview/oauth" 14 15 "tangled.org/core/appview/pages" 15 16 xrpcclient "tangled.org/core/appview/xrpcclient" ··· 271 272 f, err := rp.repoResolver.Resolve(r) 272 273 user := rp.oauth.GetUser(r) 273 274 274 - repoCollaborators, err := f.Collaborators(r.Context()) 275 + collaborators, err := func(repo *models.Repo) ([]pages.Collaborator, error) { 276 + repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.DidSlashRepo(), repo.Knot) 277 + if err != nil { 278 + return nil, err 279 + } 280 + var collaborators []pages.Collaborator 281 + for _, item := range repoCollaborators { 282 + // currently only two roles: owner and member 283 + var role string 284 + switch item[3] { 285 + case "repo:owner": 286 + role = "owner" 287 + case "repo:collaborator": 288 + role = "collaborator" 289 + default: 290 + continue 291 + } 292 + 293 + did := item[0] 294 + 295 + c := pages.Collaborator{ 296 + Did: did, 297 + Role: role, 298 + } 299 + collaborators = append(collaborators, c) 300 + } 301 + return collaborators, nil 302 + }(&f.Repo) 275 303 if err != nil { 276 304 l.Error("failed to get collaborators", "err", err) 277 305 } ··· 281 309 RepoInfo: f.RepoInfo(user), 282 310 Tabs: settingsTabs, 283 311 Tab: "access", 284 - Collaborators: repoCollaborators, 312 + Collaborators: collaborators, 285 313 }) 286 314 } 287 315
+36 -77
appview/reporesolver/resolver.go
··· 1 1 package reporesolver 2 2 3 3 import ( 4 - "context" 5 - "database/sql" 6 - "errors" 7 4 "fmt" 8 5 "log" 9 6 "net/http" ··· 17 14 "tangled.org/core/appview/db" 18 15 "tangled.org/core/appview/models" 19 16 "tangled.org/core/appview/oauth" 20 - "tangled.org/core/appview/pages" 21 17 "tangled.org/core/appview/pages/repoinfo" 22 - "tangled.org/core/idresolver" 23 18 "tangled.org/core/rbac" 24 19 ) 25 20 ··· 33 28 } 34 29 35 30 type RepoResolver struct { 36 - config *config.Config 37 - enforcer *rbac.Enforcer 38 - idResolver *idresolver.Resolver 39 - execer db.Execer 31 + config *config.Config 32 + enforcer *rbac.Enforcer 33 + execer db.Execer 40 34 } 41 35 42 - func New(config *config.Config, enforcer *rbac.Enforcer, resolver *idresolver.Resolver, execer db.Execer) *RepoResolver { 43 - return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer} 36 + func New(config *config.Config, enforcer *rbac.Enforcer, execer db.Execer) *RepoResolver { 37 + return &RepoResolver{config: config, enforcer: enforcer, execer: execer} 44 38 } 45 39 46 40 // NOTE: this... should not even be here. the entire package will be removed in future refactor ··· 80 74 }, nil 81 75 } 82 76 83 - func (f *ResolvedRepo) Collaborators(ctx context.Context) ([]pages.Collaborator, error) { 84 - repoCollaborators, err := f.rr.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot) 85 - if err != nil { 86 - return nil, err 87 - } 88 - 89 - var collaborators []pages.Collaborator 90 - for _, item := range repoCollaborators { 91 - // currently only two roles: owner and member 92 - var role string 93 - switch item[3] { 94 - case "repo:owner": 95 - role = "owner" 96 - case "repo:collaborator": 97 - role = "collaborator" 98 - default: 99 - continue 100 - } 101 - 102 - did := item[0] 103 - 104 - c := pages.Collaborator{ 105 - Did: did, 106 - Role: role, 107 - } 108 - collaborators = append(collaborators, c) 109 - } 110 - 111 - return collaborators, nil 112 - } 113 - 114 77 // this function is a bit weird since it now returns RepoInfo from an entirely different 115 78 // package. we should refactor this or get rid of RepoInfo entirely. 116 79 func (f *ResolvedRepo) RepoInfo(user *oauth.User) repoinfo.RepoInfo { ··· 120 83 isStarred = db.GetStarStatus(f.rr.execer, user.Did, repoAt) 121 84 } 122 85 123 - starCount, err := db.GetStarCount(f.rr.execer, repoAt) 124 - if err != nil { 125 - log.Println("failed to get star count for ", repoAt) 126 - } 127 - issueCount, err := db.GetIssueCount(f.rr.execer, repoAt) 128 - if err != nil { 129 - log.Println("failed to get issue count for ", repoAt) 130 - } 131 - pullCount, err := db.GetPullCount(f.rr.execer, repoAt) 132 - if err != nil { 133 - log.Println("failed to get issue count for ", repoAt) 134 - } 135 - source, err := db.GetRepoSource(f.rr.execer, repoAt) 136 - if errors.Is(err, sql.ErrNoRows) { 137 - source = "" 138 - } else if err != nil { 139 - log.Println("failed to get repo source for ", repoAt, err) 140 - } 141 - 142 - var sourceRepo *models.Repo 143 - if source != "" { 144 - sourceRepo, err = db.GetRepoByAtUri(f.rr.execer, source) 86 + stats := f.RepoStats 87 + if stats == nil { 88 + starCount, err := db.GetStarCount(f.rr.execer, repoAt) 89 + if err != nil { 90 + log.Println("failed to get star count for ", repoAt) 91 + } 92 + issueCount, err := db.GetIssueCount(f.rr.execer, repoAt) 93 + if err != nil { 94 + log.Println("failed to get issue count for ", repoAt) 95 + } 96 + pullCount, err := db.GetPullCount(f.rr.execer, repoAt) 145 97 if err != nil { 146 - log.Println("failed to get repo by at uri", err) 98 + log.Println("failed to get pull count for ", repoAt) 99 + } 100 + stats = &models.RepoStats{ 101 + StarCount: starCount, 102 + IssueCount: issueCount, 103 + PullCount: pullCount, 147 104 } 148 105 } 149 106 150 - knot := f.Knot 107 + sourceRepo, err := db.GetRepoSourceRepo(f.rr.execer, repoAt) 108 + if err != nil { 109 + log.Println("failed to get repo by at uri", err) 110 + } 151 111 152 112 repoInfo := repoinfo.RepoInfo{ 113 + // this is basically a models.Repo 153 114 OwnerDid: f.OwnerId.DID.String(), 154 115 OwnerHandle: f.OwnerId.Handle.String(), 155 116 Name: f.Name, ··· 157 118 Description: f.Description, 158 119 Website: f.Website, 159 120 Topics: f.Topics, 160 - IsStarred: isStarred, 161 - Knot: knot, 121 + Knot: f.Knot, 162 122 Spindle: f.Spindle, 163 - Roles: f.RolesInRepo(user), 164 - Stats: models.RepoStats{ 165 - StarCount: starCount, 166 - IssueCount: issueCount, 167 - PullCount: pullCount, 168 - }, 123 + Stats: *stats, 124 + 125 + // fork repo upstream 126 + Source: sourceRepo, 127 + 169 128 CurrentDir: f.CurrentDir, 170 129 Ref: f.Ref, 171 - } 172 130 173 - if sourceRepo != nil { 174 - repoInfo.Source = sourceRepo 131 + // info related to the session 132 + IsStarred: isStarred, 133 + Roles: f.RolesInRepo(user), 175 134 } 176 135 177 136 return repoInfo
+1 -1
appview/state/state.go
··· 96 96 } 97 97 validator := validator.New(d, res, enforcer) 98 98 99 - repoResolver := reporesolver.New(config, enforcer, res, d) 99 + repoResolver := reporesolver.New(config, enforcer, d) 100 100 101 101 wrapper := db.DbWrapper{Execer: d} 102 102 jc, err := jetstream.NewJetstreamClient(
+8
rbac/rbac.go
··· 285 285 return e.E.Enforce(user, domain, repo, "repo:delete") 286 286 } 287 287 288 + func (e *Enforcer) IsRepoOwner(user, domain, repo string) (bool, error) { 289 + return e.E.Enforce(user, domain, repo, "repo:owner") 290 + } 291 + 292 + func (e *Enforcer) IsRepoCollaborator(user, domain, repo string) (bool, error) { 293 + return e.E.Enforce(user, domain, repo, "repo:collaborator") 294 + } 295 + 288 296 func (e *Enforcer) IsPushAllowed(user, domain, repo string) (bool, error) { 289 297 return e.E.Enforce(user, domain, repo, "repo:push") 290 298 }