package xrpc import ( "encoding/json" "errors" "fmt" "github.com/bluesky-social/indigo/atproto/syntax" "net/http" "tangled.org/core/api/org_tangled" "tangled.org/core/spindle/db" xrpcerr "tangled.org/core/xrpc/errors" ) func (x *Xrpc) Ban(w http.ResponseWriter, r *http.Request) { l := x.Logger fail := func(e xrpcerr.XrpcError, status int) { l.ErrorContext(r.Context(), "ban add failed", "kind", e.Tag, "error", e.Message) writeError(w, e, status) } _, errObj, status := x.checkSpindleOwner(r) if errObj != nil { fail(*errObj, status) return } var data org_tangled.TempSpindleModerationBan_Input if err := json.NewDecoder(r.Body).Decode(&data); err != nil { fail(xrpcerr.GenericError(err), http.StatusBadRequest) return } did, err := syntax.ParseDID(data.Did) if err != nil { fail(xrpcerr.NewXrpcError( xrpcerr.WithTag("InvalidDid"), xrpcerr.WithMessage(fmt.Sprintf("invalid DID: %s", data.Did)), ), http.StatusBadRequest) return } ban := db.BanEntry{ SubjectDid: did, } if err := x.Db.PutBan(ban); err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } if x.Wiper == nil { fail(xrpcerr.GenericError(errors.New("purger unavailable")), http.StatusInternalServerError) return } // wipe both possible ban roles err = x.Wiper.WipeRepo(r.Context(), did, "banned") if oerr := x.Wiper.WipeOwner(r.Context(), did, "banned"); oerr != nil { err = errors.Join(err, oerr) } if err != nil { l.ErrorContext(r.Context(), "failed to wipe banned subject", "did", did.String(), "err", err) fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (x *Xrpc) Unban(w http.ResponseWriter, r *http.Request) { l := x.Logger fail := func(e xrpcerr.XrpcError, status int) { l.ErrorContext(r.Context(), "ban remove failed", "kind", e.Tag, "error", e.Message) writeError(w, e, status) } if _, errObj, status := x.checkSpindleOwner(r); errObj != nil { fail(*errObj, status) return } var data org_tangled.TempSpindleModerationUnban_Input if err := json.NewDecoder(r.Body).Decode(&data); err != nil { fail(xrpcerr.GenericError(err), http.StatusBadRequest) return } did, err := syntax.ParseDID(data.Did) if err != nil { fail(xrpcerr.NewXrpcError( xrpcerr.WithTag("InvalidDid"), xrpcerr.WithMessage(fmt.Sprintf("invalid DID: %s", data.Did)), ), http.StatusBadRequest) return } removed, err := x.Db.DeleteBan(did) if err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } if !removed { fail(xrpcerr.NewXrpcError( xrpcerr.WithTag("BanNotFound"), xrpcerr.WithMessage("ban not found"), ), http.StatusBadRequest) return } w.WriteHeader(http.StatusOK) } func (x *Xrpc) GetBan(w http.ResponseWriter, r *http.Request) { l := x.Logger fail := func(e xrpcerr.XrpcError, status int) { l.ErrorContext(r.Context(), "ban get failed", "kind", e.Tag, "error", e.Message) writeError(w, e, status) } if _, errObj, status := x.checkSpindleOwner(r); errObj != nil { fail(*errObj, status) return } did, err := syntax.ParseDID(r.URL.Query().Get("did")) if err != nil { fail(xrpcerr.NewXrpcError( xrpcerr.WithTag("InvalidDid"), xrpcerr.WithMessage(fmt.Sprintf("invalid DID: %s", r.URL.Query().Get("did"))), ), http.StatusBadRequest) return } ban, err := x.Db.GetBan(did) if err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } if ban == nil { fail(xrpcerr.NewXrpcError( xrpcerr.WithTag("BanNotFound"), xrpcerr.WithMessage("ban not found"), ), http.StatusNotFound) return } out := org_tangled.TempSpindleModerationGetBan_Output{ Ban: &org_tangled.TempSpindleModerationDefs_Ban{ Did: ban.SubjectDid.String(), CreatedAt: ban.CreatedAt, }, } if err := writeJson(w, http.StatusOK, out); err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } } func (x *Xrpc) ListBans(w http.ResponseWriter, r *http.Request) { l := x.Logger fail := func(e xrpcerr.XrpcError, status int) { l.ErrorContext(r.Context(), "ban list failed", "kind", e.Tag, "error", e.Message) writeError(w, e, status) } if _, errObj, status := x.checkSpindleOwner(r); errObj != nil { fail(*errObj, status) return } bans, err := x.Db.BanList() if err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } out := org_tangled.TempSpindleModerationListBans_Output{ Bans: make([]*org_tangled.TempSpindleModerationDefs_Ban, 0, len(bans)), } for _, b := range bans { out.Bans = append(out.Bans, &org_tangled.TempSpindleModerationDefs_Ban{ Did: b.SubjectDid.String(), CreatedAt: b.CreatedAt, }) } if err := writeJson(w, http.StatusOK, out); err != nil { fail(xrpcerr.GenericError(err), http.StatusInternalServerError) return } }