Monorepo for Tangled
tangled.org
1package xrpc
2
3import (
4 "database/sql"
5 "encoding/json"
6 "net/http"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.org/core/api/tangled"
10 "tangled.org/core/knotserver/db"
11 "tangled.org/core/rbac"
12 xrpcerr "tangled.org/core/xrpc/errors"
13)
14
15func (h *Xrpc) RemoveMember(w http.ResponseWriter, r *http.Request) {
16 l := h.Logger.With("handler", "RemoveMember")
17 fail := func(e xrpcerr.XrpcError, status int) {
18 l.Error("failed", "kind", e.Tag, "error", e.Message)
19 writeError(w, e, status)
20 }
21
22 actorDid, ok := r.Context().Value(ActorDid).(syntax.DID)
23 if !ok {
24 fail(xrpcerr.MissingActorDidError, http.StatusForbidden)
25 return
26 }
27
28 allowed, err := h.Enforcer.IsKnotInviteAllowed(actorDid.String(), rbac.ThisServer)
29 if err != nil {
30 fail(xrpcerr.GenericError(err), http.StatusInternalServerError)
31 return
32 }
33 if !allowed {
34 fail(xrpcerr.AccessControlError(actorDid.String()), http.StatusForbidden)
35 return
36 }
37
38 var data tangled.KnotRemoveMember_Input
39 if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
40 fail(xrpcerr.GenericError(err), http.StatusBadRequest)
41 return
42 }
43
44 subject, err := syntax.ParseDID(data.Subject)
45 if err != nil {
46 fail(xrpcerr.GenericError(err), http.StatusBadRequest)
47 return
48 }
49
50 isOwner, err := h.Enforcer.IsKnotOwner(subject.String(), rbac.ThisServer)
51 if err != nil {
52 fail(xrpcerr.GenericError(err), http.StatusInternalServerError)
53 return
54 }
55 if isOwner {
56 fail(xrpcerr.NewXrpcError(
57 xrpcerr.WithTag("InvalidRequest"),
58 xrpcerr.WithMessage("cannot remove the knot owner"),
59 ), http.StatusBadRequest)
60 return
61 }
62
63 status, xerr := h.applyAclRevoke(r.Context(), l, aclRevoke{
64 role: "member",
65 subject: subject,
66 inAcl: func() (bool, error) {
67 return h.Enforcer.IsKnotMember(subject.String(), rbac.ThisServer)
68 },
69 inTable: func() (bool, error) {
70 n, err := db.CountKnotMembersBySubject(h.Db, subject.String())
71 return n > 0, err
72 },
73 removeAcl: func() (bool, error) {
74 return h.Enforcer.TryRemoveKnotMember(rbac.ThisServer, subject.String())
75 },
76 restoreAcl: func() error {
77 _, err := h.Enforcer.TryAddKnotMember(rbac.ThisServer, subject.String())
78 return err
79 },
80 deleteRow: func(tx *sql.Tx) error {
81 return db.RemoveKnotMemberBySubject(tx, subject)
82 },
83 emit: func() error {
84 return h.Db.EmitKnotMemberUpdate(h.Notifier, db.AclOpRemove, subject)
85 },
86 })
87 if xerr != nil {
88 fail(*xerr, status)
89 return
90 }
91 w.WriteHeader(status)
92}