tangled
alpha
login
or
join now
back
round
2
view raw
appview: diet the reporesolver
#808
merged
opened by
boltless.me
1 month ago
targeting
master
from
sl/yurolxtlpsmz
Ideally we should completely remove it.
Signed-off-by: Seongmin Lee
git@boltless.me
options
unified
split
Changed files
+98
-99
appview
db
repos.go
issues
issues.go
pulls
pulls.go
repo
settings.go
reporesolver
resolver.go
state
state.go
rbac
rbac.go
+11
appview/db/repos.go
···
411
411
return nullableSource.String, nil
412
412
}
413
413
414
414
+
func GetRepoSourceRepo(e Execer, repoAt syntax.ATURI) (*models.Repo, error) {
415
415
+
source, err := GetRepoSource(e, repoAt)
416
416
+
if source == "" || errors.Is(err, sql.ErrNoRows) {
417
417
+
return nil, nil
418
418
+
}
419
419
+
if err != nil {
420
420
+
return nil, err
421
421
+
}
422
422
+
return GetRepoByAtUri(e, source)
423
423
+
}
424
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
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
289
-
collaborators, err := f.Collaborators(r.Context())
290
290
-
if err != nil {
291
291
-
l.Error("failed to fetch repo collaborators", "err", err)
292
292
-
}
293
293
-
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
294
294
-
return user.Did == collab.Did
295
295
-
})
288
288
+
roles := f.RolesInRepo(user)
289
289
+
isRepoOwner := roles.IsOwner()
290
290
+
isCollaborator := roles.IsCollaborator()
296
291
isIssueOwner := user.Did == issue.Did
297
292
298
293
// TODO: make this more granular
299
299
-
if isIssueOwner || isCollaborator {
294
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
341
-
collaborators, err := f.Collaborators(r.Context())
342
342
-
if err != nil {
343
343
-
l.Error("failed to fetch repo collaborators", "err", err)
344
344
-
}
345
345
-
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
346
346
-
return user.Did == collab.Did
347
347
-
})
336
336
+
roles := f.RolesInRepo(user)
337
337
+
isRepoOwner := roles.IsOwner()
338
338
+
isCollaborator := roles.IsCollaborator()
348
339
isIssueOwner := user.Did == issue.Did
349
340
350
350
-
if isCollaborator || isIssueOwner {
341
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
···
875
875
}
876
876
877
877
// Determine PR type based on input parameters
878
878
-
isPushAllowed := f.RepoInfo(user).Roles.IsPushAllowed()
878
878
+
roles := f.RolesInRepo(user)
879
879
+
isPushAllowed := roles.IsPushAllowed()
879
880
isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
880
881
isForkBased := fromFork != "" && sourceBranch != ""
881
882
isPatchBased := patch != "" && !isBranchBased && !isForkBased
···
1671
1672
return
1672
1673
}
1673
1674
1674
1674
-
if !f.RepoInfo(user).Roles.IsPushAllowed() {
1675
1675
+
roles := f.RolesInRepo(user)
1676
1676
+
if !roles.IsPushAllowed() {
1675
1677
log.Println("unauthorized user")
1676
1678
w.WriteHeader(http.StatusUnauthorized)
1677
1679
return
+30
-2
appview/repo/settings.go
···
10
10
11
11
"tangled.org/core/api/tangled"
12
12
"tangled.org/core/appview/db"
13
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
274
-
repoCollaborators, err := f.Collaborators(r.Context())
275
275
+
collaborators, err := func(repo *models.Repo) ([]pages.Collaborator, error) {
276
276
+
repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.DidSlashRepo(), repo.Knot)
277
277
+
if err != nil {
278
278
+
return nil, err
279
279
+
}
280
280
+
var collaborators []pages.Collaborator
281
281
+
for _, item := range repoCollaborators {
282
282
+
// currently only two roles: owner and member
283
283
+
var role string
284
284
+
switch item[3] {
285
285
+
case "repo:owner":
286
286
+
role = "owner"
287
287
+
case "repo:collaborator":
288
288
+
role = "collaborator"
289
289
+
default:
290
290
+
continue
291
291
+
}
292
292
+
293
293
+
did := item[0]
294
294
+
295
295
+
c := pages.Collaborator{
296
296
+
Did: did,
297
297
+
Role: role,
298
298
+
}
299
299
+
collaborators = append(collaborators, c)
300
300
+
}
301
301
+
return collaborators, nil
302
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
284
-
Collaborators: repoCollaborators,
312
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
4
-
"context"
5
5
-
"database/sql"
6
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
20
-
"tangled.org/core/appview/pages"
21
17
"tangled.org/core/appview/pages/repoinfo"
22
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
36
-
config *config.Config
37
37
-
enforcer *rbac.Enforcer
38
38
-
idResolver *idresolver.Resolver
39
39
-
execer db.Execer
31
31
+
config *config.Config
32
32
+
enforcer *rbac.Enforcer
33
33
+
execer db.Execer
40
34
}
41
35
42
42
-
func New(config *config.Config, enforcer *rbac.Enforcer, resolver *idresolver.Resolver, execer db.Execer) *RepoResolver {
43
43
-
return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer}
36
36
+
func New(config *config.Config, enforcer *rbac.Enforcer, execer db.Execer) *RepoResolver {
37
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
83
-
func (f *ResolvedRepo) Collaborators(ctx context.Context) ([]pages.Collaborator, error) {
84
84
-
repoCollaborators, err := f.rr.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot)
85
85
-
if err != nil {
86
86
-
return nil, err
87
87
-
}
88
88
-
89
89
-
var collaborators []pages.Collaborator
90
90
-
for _, item := range repoCollaborators {
91
91
-
// currently only two roles: owner and member
92
92
-
var role string
93
93
-
switch item[3] {
94
94
-
case "repo:owner":
95
95
-
role = "owner"
96
96
-
case "repo:collaborator":
97
97
-
role = "collaborator"
98
98
-
default:
99
99
-
continue
100
100
-
}
101
101
-
102
102
-
did := item[0]
103
103
-
104
104
-
c := pages.Collaborator{
105
105
-
Did: did,
106
106
-
Role: role,
107
107
-
}
108
108
-
collaborators = append(collaborators, c)
109
109
-
}
110
110
-
111
111
-
return collaborators, nil
112
112
-
}
113
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
123
-
starCount, err := db.GetStarCount(f.rr.execer, repoAt)
124
124
-
if err != nil {
125
125
-
log.Println("failed to get star count for ", repoAt)
126
126
-
}
127
127
-
issueCount, err := db.GetIssueCount(f.rr.execer, repoAt)
128
128
-
if err != nil {
129
129
-
log.Println("failed to get issue count for ", repoAt)
130
130
-
}
131
131
-
pullCount, err := db.GetPullCount(f.rr.execer, repoAt)
132
132
-
if err != nil {
133
133
-
log.Println("failed to get issue count for ", repoAt)
134
134
-
}
135
135
-
source, err := db.GetRepoSource(f.rr.execer, repoAt)
136
136
-
if errors.Is(err, sql.ErrNoRows) {
137
137
-
source = ""
138
138
-
} else if err != nil {
139
139
-
log.Println("failed to get repo source for ", repoAt, err)
140
140
-
}
141
141
-
142
142
-
var sourceRepo *models.Repo
143
143
-
if source != "" {
144
144
-
sourceRepo, err = db.GetRepoByAtUri(f.rr.execer, source)
86
86
+
stats := f.RepoStats
87
87
+
if stats == nil {
88
88
+
starCount, err := db.GetStarCount(f.rr.execer, repoAt)
89
89
+
if err != nil {
90
90
+
log.Println("failed to get star count for ", repoAt)
91
91
+
}
92
92
+
issueCount, err := db.GetIssueCount(f.rr.execer, repoAt)
93
93
+
if err != nil {
94
94
+
log.Println("failed to get issue count for ", repoAt)
95
95
+
}
96
96
+
pullCount, err := db.GetPullCount(f.rr.execer, repoAt)
145
97
if err != nil {
146
146
-
log.Println("failed to get repo by at uri", err)
98
98
+
log.Println("failed to get pull count for ", repoAt)
99
99
+
}
100
100
+
stats = &models.RepoStats{
101
101
+
StarCount: starCount,
102
102
+
IssueCount: issueCount,
103
103
+
PullCount: pullCount,
147
104
}
148
105
}
149
106
150
150
-
knot := f.Knot
107
107
+
sourceRepo, err := db.GetRepoSourceRepo(f.rr.execer, repoAt)
108
108
+
if err != nil {
109
109
+
log.Println("failed to get repo by at uri", err)
110
110
+
}
151
111
152
112
repoInfo := repoinfo.RepoInfo{
113
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
160
-
IsStarred: isStarred,
161
161
-
Knot: knot,
121
121
+
Knot: f.Knot,
162
122
Spindle: f.Spindle,
163
163
-
Roles: f.RolesInRepo(user),
164
164
-
Stats: models.RepoStats{
165
165
-
StarCount: starCount,
166
166
-
IssueCount: issueCount,
167
167
-
PullCount: pullCount,
168
168
-
},
123
123
+
Stats: *stats,
124
124
+
125
125
+
// fork repo upstream
126
126
+
Source: sourceRepo,
127
127
+
169
128
CurrentDir: f.CurrentDir,
170
129
Ref: f.Ref,
171
171
-
}
172
130
173
173
-
if sourceRepo != nil {
174
174
-
repoInfo.Source = sourceRepo
131
131
+
// info related to the session
132
132
+
IsStarred: isStarred,
133
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
99
-
repoResolver := reporesolver.New(config, enforcer, res, d)
99
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
288
+
func (e *Enforcer) IsRepoOwner(user, domain, repo string) (bool, error) {
289
289
+
return e.E.Enforce(user, domain, repo, "repo:owner")
290
290
+
}
291
291
+
292
292
+
func (e *Enforcer) IsRepoCollaborator(user, domain, repo string) (bool, error) {
293
293
+
return e.E.Enforce(user, domain, repo, "repo:collaborator")
294
294
+
}
295
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
}