appview: diet the reporesolver #808

merged
opened by boltless.me targeting master from sl/yurolxtlpsmz

Ideally we should completely remove it.

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

Changed files
+98 -99
appview
db
issues
pulls
repo
reporesolver
state
rbac
+11
appview/db/repos.go
···
return nullableSource.String, nil
}
+
func GetRepoSourceRepo(e Execer, repoAt syntax.ATURI) (*models.Repo, error) {
+
source, err := GetRepoSource(e, repoAt)
+
if source == "" || errors.Is(err, sql.ErrNoRows) {
+
return nil, nil
+
}
+
if err != nil {
+
return nil, err
+
}
+
return GetRepoByAtUri(e, source)
+
}
+
func GetForksByDid(e Execer, did string) ([]models.Repo, error) {
var repos []models.Repo
+8 -17
appview/issues/issues.go
···
"fmt"
"log/slog"
"net/http"
-
"slices"
"time"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
return
}
-
collaborators, err := f.Collaborators(r.Context())
-
if err != nil {
-
l.Error("failed to fetch repo collaborators", "err", err)
-
}
-
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
-
return user.Did == collab.Did
-
})
+
roles := f.RolesInRepo(user)
+
isRepoOwner := roles.IsOwner()
+
isCollaborator := roles.IsCollaborator()
isIssueOwner := user.Did == issue.Did
// TODO: make this more granular
-
if isIssueOwner || isCollaborator {
+
if isIssueOwner || isRepoOwner || isCollaborator {
err = db.CloseIssues(
rp.db,
db.FilterEq("id", issue.Id),
···
return
}
-
collaborators, err := f.Collaborators(r.Context())
-
if err != nil {
-
l.Error("failed to fetch repo collaborators", "err", err)
-
}
-
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
-
return user.Did == collab.Did
-
})
+
roles := f.RolesInRepo(user)
+
isRepoOwner := roles.IsOwner()
+
isCollaborator := roles.IsCollaborator()
isIssueOwner := user.Did == issue.Did
-
if isCollaborator || isIssueOwner {
+
if isCollaborator || isRepoOwner || isIssueOwner {
err := db.ReopenIssues(
rp.db,
db.FilterEq("id", issue.Id),
+4 -2
appview/pulls/pulls.go
···
}
// Determine PR type based on input parameters
-
isPushAllowed := f.RepoInfo(user).Roles.IsPushAllowed()
+
roles := f.RolesInRepo(user)
+
isPushAllowed := roles.IsPushAllowed()
isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
isForkBased := fromFork != "" && sourceBranch != ""
isPatchBased := patch != "" && !isBranchBased && !isForkBased
···
return
-
if !f.RepoInfo(user).Roles.IsPushAllowed() {
+
roles := f.RolesInRepo(user)
+
if !roles.IsPushAllowed() {
log.Println("unauthorized user")
w.WriteHeader(http.StatusUnauthorized)
return
+30 -2
appview/repo/settings.go
···
"tangled.org/core/api/tangled"
"tangled.org/core/appview/db"
+
"tangled.org/core/appview/models"
"tangled.org/core/appview/oauth"
"tangled.org/core/appview/pages"
xrpcclient "tangled.org/core/appview/xrpcclient"
···
f, err := rp.repoResolver.Resolve(r)
user := rp.oauth.GetUser(r)
-
repoCollaborators, err := f.Collaborators(r.Context())
+
collaborators, err := func(repo *models.Repo) ([]pages.Collaborator, error) {
+
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.DidSlashRepo(), repo.Knot)
+
if err != nil {
+
return nil, err
+
}
+
var collaborators []pages.Collaborator
+
for _, item := range repoCollaborators {
+
// currently only two roles: owner and member
+
var role string
+
switch item[3] {
+
case "repo:owner":
+
role = "owner"
+
case "repo:collaborator":
+
role = "collaborator"
+
default:
+
continue
+
}
+
+
did := item[0]
+
+
c := pages.Collaborator{
+
Did: did,
+
Role: role,
+
}
+
collaborators = append(collaborators, c)
+
}
+
return collaborators, nil
+
}(&f.Repo)
if err != nil {
l.Error("failed to get collaborators", "err", err)
}
···
RepoInfo: f.RepoInfo(user),
Tabs: settingsTabs,
Tab: "access",
-
Collaborators: repoCollaborators,
+
Collaborators: collaborators,
})
}
+36 -77
appview/reporesolver/resolver.go
···
package reporesolver
import (
-
"context"
-
"database/sql"
-
"errors"
"fmt"
"log"
"net/http"
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/oauth"
-
"tangled.org/core/appview/pages"
"tangled.org/core/appview/pages/repoinfo"
-
"tangled.org/core/idresolver"
"tangled.org/core/rbac"
)
···
}
type RepoResolver struct {
-
config *config.Config
-
enforcer *rbac.Enforcer
-
idResolver *idresolver.Resolver
-
execer db.Execer
+
config *config.Config
+
enforcer *rbac.Enforcer
+
execer db.Execer
}
-
func New(config *config.Config, enforcer *rbac.Enforcer, resolver *idresolver.Resolver, execer db.Execer) *RepoResolver {
-
return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer}
+
func New(config *config.Config, enforcer *rbac.Enforcer, execer db.Execer) *RepoResolver {
+
return &RepoResolver{config: config, enforcer: enforcer, execer: execer}
}
// NOTE: this... should not even be here. the entire package will be removed in future refactor
···
}, nil
}
-
func (f *ResolvedRepo) Collaborators(ctx context.Context) ([]pages.Collaborator, error) {
-
repoCollaborators, err := f.rr.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot)
-
if err != nil {
-
return nil, err
-
}
-
-
var collaborators []pages.Collaborator
-
for _, item := range repoCollaborators {
-
// currently only two roles: owner and member
-
var role string
-
switch item[3] {
-
case "repo:owner":
-
role = "owner"
-
case "repo:collaborator":
-
role = "collaborator"
-
default:
-
continue
-
}
-
-
did := item[0]
-
-
c := pages.Collaborator{
-
Did: did,
-
Role: role,
-
}
-
collaborators = append(collaborators, c)
-
}
-
-
return collaborators, nil
-
}
-
// this function is a bit weird since it now returns RepoInfo from an entirely different
// package. we should refactor this or get rid of RepoInfo entirely.
func (f *ResolvedRepo) RepoInfo(user *oauth.User) repoinfo.RepoInfo {
···
isStarred = db.GetStarStatus(f.rr.execer, user.Did, repoAt)
}
-
starCount, err := db.GetStarCount(f.rr.execer, repoAt)
-
if err != nil {
-
log.Println("failed to get star count for ", repoAt)
-
}
-
issueCount, err := db.GetIssueCount(f.rr.execer, repoAt)
-
if err != nil {
-
log.Println("failed to get issue count for ", repoAt)
-
}
-
pullCount, err := db.GetPullCount(f.rr.execer, repoAt)
-
if err != nil {
-
log.Println("failed to get issue count for ", repoAt)
-
}
-
source, err := db.GetRepoSource(f.rr.execer, repoAt)
-
if errors.Is(err, sql.ErrNoRows) {
-
source = ""
-
} else if err != nil {
-
log.Println("failed to get repo source for ", repoAt, err)
-
}
-
-
var sourceRepo *models.Repo
-
if source != "" {
-
sourceRepo, err = db.GetRepoByAtUri(f.rr.execer, source)
+
stats := f.RepoStats
+
if stats == nil {
+
starCount, err := db.GetStarCount(f.rr.execer, repoAt)
+
if err != nil {
+
log.Println("failed to get star count for ", repoAt)
+
}
+
issueCount, err := db.GetIssueCount(f.rr.execer, repoAt)
+
if err != nil {
+
log.Println("failed to get issue count for ", repoAt)
+
}
+
pullCount, err := db.GetPullCount(f.rr.execer, repoAt)
if err != nil {
-
log.Println("failed to get repo by at uri", err)
+
log.Println("failed to get pull count for ", repoAt)
+
}
+
stats = &models.RepoStats{
+
StarCount: starCount,
+
IssueCount: issueCount,
+
PullCount: pullCount,
}
}
-
knot := f.Knot
+
sourceRepo, err := db.GetRepoSourceRepo(f.rr.execer, repoAt)
+
if err != nil {
+
log.Println("failed to get repo by at uri", err)
+
}
repoInfo := repoinfo.RepoInfo{
+
// this is basically a models.Repo
OwnerDid: f.OwnerId.DID.String(),
OwnerHandle: f.OwnerId.Handle.String(),
Name: f.Name,
···
Description: f.Description,
Website: f.Website,
Topics: f.Topics,
-
IsStarred: isStarred,
-
Knot: knot,
+
Knot: f.Knot,
Spindle: f.Spindle,
-
Roles: f.RolesInRepo(user),
-
Stats: models.RepoStats{
-
StarCount: starCount,
-
IssueCount: issueCount,
-
PullCount: pullCount,
-
},
+
Stats: *stats,
+
+
// fork repo upstream
+
Source: sourceRepo,
+
CurrentDir: f.CurrentDir,
Ref: f.Ref,
-
}
-
if sourceRepo != nil {
-
repoInfo.Source = sourceRepo
+
// info related to the session
+
IsStarred: isStarred,
+
Roles: f.RolesInRepo(user),
}
return repoInfo
+1 -1
appview/state/state.go
···
}
validator := validator.New(d, res, enforcer)
-
repoResolver := reporesolver.New(config, enforcer, res, d)
+
repoResolver := reporesolver.New(config, enforcer, d)
wrapper := db.DbWrapper{Execer: d}
jc, err := jetstream.NewJetstreamClient(
+8
rbac/rbac.go
···
return e.E.Enforce(user, domain, repo, "repo:delete")
}
+
func (e *Enforcer) IsRepoOwner(user, domain, repo string) (bool, error) {
+
return e.E.Enforce(user, domain, repo, "repo:owner")
+
}
+
+
func (e *Enforcer) IsRepoCollaborator(user, domain, repo string) (bool, error) {
+
return e.E.Enforce(user, domain, repo, "repo:collaborator")
+
}
+
func (e *Enforcer) IsPushAllowed(user, domain, repo string) (bool, error) {
return e.E.Enforce(user, domain, repo, "repo:push")
}