- Add RemoveCollaborator handler: delete PDS record, RBAC policy, and DB row
- Add DELETE /settings/collaborator route (repo:owner)
- Load collaborator rkey from DB for removal
- Add trash icon remove button on access settings
+127
-8
Diff
round #0
+3
-2
appview/pages/pages.go
+3
-2
appview/pages/pages.go
+19
appview/pages/templates/repo/settings/access.html
+19
appview/pages/templates/repo/settings/access.html
···
13
13
14
14
{{ define "collaboratorSettings" }}
15
15
<div class="grid grid-cols-1 gap-4 items-center">
16
+
<div id="remove-collaborator-error" class="text-red-500 dark:text-red-400"></div>
16
17
<div class="col-span-1">
17
18
<h2 class="text-sm pb-2 uppercase font-bold">Collaborators</h2>
18
19
<p class="text-gray-500 dark:text-gray-400">
···
40
41
</a>
41
42
<p class="text-sm text-gray-500 dark:text-gray-400">{{ .Role }}</p>
42
43
</div>
44
+
{{ if and (eq .Role "collaborator") .Rkey $.RepoInfo.Roles.IsOwner }}
45
+
<form
46
+
method="post"
47
+
action="/{{ $.RepoInfo.FullName }}/settings/collaborator?subject_did={{ .Did }}"
48
+
hx-delete="/{{ $.RepoInfo.FullName }}/settings/collaborator?subject_did={{ .Did }}"
49
+
hx-swap="none"
50
+
hx-confirm="Remove {{ $handle }} from collaborators?"
51
+
class="inline"
52
+
>
53
+
<button
54
+
type="submit"
55
+
class="btn-ghost p-1 text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"
56
+
title="Remove collaborator"
57
+
>
58
+
{{ i "trash-2" "size-4" }}
59
+
</button>
60
+
</form>
61
+
{{ end }}
43
62
</div>
44
63
</div>
45
64
{{ end }}
+95
appview/repo/repo.go
+95
appview/repo/repo.go
···
821
821
rp.pages.HxRefresh(w)
822
822
}
823
823
824
+
func (rp *Repo) RemoveCollaborator(w http.ResponseWriter, r *http.Request) {
825
+
user := rp.oauth.GetMultiAccountUser(r)
826
+
l := rp.logger.With("handler", "RemoveCollaborator")
827
+
l = l.With("did", user.Active.Did)
828
+
829
+
f, err := rp.repoResolver.Resolve(r)
830
+
if err != nil {
831
+
l.Error("failed to get repo and knot", "err", err)
832
+
return
833
+
}
834
+
835
+
errorId := "remove-collaborator-error"
836
+
fail := func(msg string, err error) {
837
+
l.Error(msg, "err", err)
838
+
rp.pages.Notice(w, errorId, msg)
839
+
}
840
+
841
+
subjectDid := r.FormValue("subject_did")
842
+
if subjectDid == "" {
843
+
fail("Invalid form.", nil)
844
+
return
845
+
}
846
+
847
+
if subjectDid == user.Active.Did {
848
+
fail("You cannot remove yourself as owner.", nil)
849
+
return
850
+
}
851
+
852
+
// look up collaborator in db to get rkey (record lives on owner's PDS)
853
+
collabs, err := db.GetCollaborators(rp.db, orm.FilterEq("repo_at", f.RepoAt()), orm.FilterEq("subject_did", subjectDid))
854
+
if err != nil {
855
+
fail("Failed to remove collaborator.", err)
856
+
return
857
+
}
858
+
if len(collabs) == 0 {
859
+
fail("Collaborator not found.", nil)
860
+
return
861
+
}
862
+
collab := collabs[0]
863
+
864
+
client, err := rp.oauth.AuthorizedClient(r)
865
+
if err != nil {
866
+
fail("Failed to write to PDS.", err)
867
+
return
868
+
}
869
+
870
+
_, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
871
+
Collection: tangled.RepoCollaboratorNSID,
872
+
Repo: f.Did,
873
+
Rkey: collab.Rkey,
874
+
})
875
+
if err != nil {
876
+
fail("Failed to remove collaborator record from PDS.", err)
877
+
return
878
+
}
879
+
880
+
tx, err := rp.db.BeginTx(r.Context(), nil)
881
+
if err != nil {
882
+
fail("Failed to remove collaborator.", err)
883
+
return
884
+
}
885
+
886
+
rollback := func() {
887
+
tx.Rollback()
888
+
rp.enforcer.E.LoadPolicy()
889
+
}
890
+
defer rollback()
891
+
892
+
err = rp.enforcer.RemoveCollaborator(subjectDid, f.Knot, f.DidSlashRepo())
893
+
if err != nil {
894
+
fail("Failed to remove collaborator permissions.", err)
895
+
return
896
+
}
897
+
898
+
err = db.DeleteCollaborator(tx, orm.FilterEq("repo_at", f.RepoAt()), orm.FilterEq("subject_did", subjectDid))
899
+
if err != nil {
900
+
fail("Failed to remove collaborator.", err)
901
+
return
902
+
}
903
+
904
+
err = tx.Commit()
905
+
if err != nil {
906
+
fail("Failed to remove collaborator.", err)
907
+
return
908
+
}
909
+
910
+
err = rp.enforcer.E.SavePolicy()
911
+
if err != nil {
912
+
fail("Failed to update permissions.", err)
913
+
return
914
+
}
915
+
916
+
rp.pages.HxRefresh(w)
917
+
}
918
+
824
919
func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) {
825
920
user := rp.oauth.GetMultiAccountUser(r)
826
921
l := rp.logger.With("handler", "DeleteRepo")
+1
appview/repo/router.go
+1
appview/repo/router.go
···
83
83
r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/label/subscribe", rp.SubscribeLabel)
84
84
r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/label/unsubscribe", rp.UnsubscribeLabel)
85
85
r.With(mw.RepoPermissionMiddleware("repo:invite")).Put("/collaborator", rp.AddCollaborator)
86
+
r.With(mw.RepoPermissionMiddleware("repo:owner")).Delete("/collaborator", rp.RemoveCollaborator)
86
87
r.With(mw.RepoPermissionMiddleware("repo:delete")).Delete("/delete", rp.DeleteRepo)
87
88
r.Put("/branches/default", rp.SetDefaultBranch)
88
89
r.Put("/secrets", rp.Secrets)
+9
-6
appview/repo/settings.go
+9
-6
appview/repo/settings.go
···
264
264
if err != nil {
265
265
return nil, err
266
266
}
267
+
// load db collaborators for rkey (needed to remove via PDS delete)
268
+
dbCollabs, _ := db.GetCollaborators(rp.db, orm.FilterEq("repo_at", repo.RepoAt()))
269
+
rkeyByDid := make(map[string]string)
270
+
for _, c := range dbCollabs {
271
+
rkeyByDid[c.SubjectDid.String()] = c.Rkey
272
+
}
267
273
var collaborators []pages.Collaborator
268
274
for _, item := range repoCollaborators {
269
-
// currently only two roles: owner and member
270
275
var role string
271
276
switch item[3] {
272
277
case "repo:owner":
···
276
281
default:
277
282
continue
278
283
}
279
-
280
284
did := item[0]
281
-
282
-
c := pages.Collaborator{
283
-
Did: did,
284
-
Role: role,
285
+
c := pages.Collaborator{Did: did, Role: role}
286
+
if role == "collaborator" {
287
+
c.Rkey = rkeyByDid[did]
285
288
}
286
289
collaborators = append(collaborators, c)
287
290
}
History
1 round
1 comment
murex.tngl.sh
submitted
#0
1 commit
expand
collapse
feat(repo): add collaborator removal
- Add RemoveCollaborator handler: delete PDS record, RBAC policy, and DB row
- Add DELETE /settings/collaborator route (repo:owner)
- Load collaborator rkey from DB for removal
- Add trash icon remove button on access settings
Signed-off-by: Nupur Agrawal <nupur202000@gmail.com>
no conflicts, ready to merge
thanks for the contribution! this PR does not handle all the scenarios: