mirror of
https://github.com/matrix-org/dendrite.git
synced 2024-11-22 06:11:55 -06:00
Add getting/deleting single event report (#3344)
Based on https://github.com/matrix-org/dendrite/pull/3342 Adds `GET /_synapse/admin/v1/event_reports/{reportID}` and `DELETE /_synapse/admin/v1/event_reports/{reportID}`
This commit is contained in:
parent
81f73c9f8d
commit
ad0a7d09e8
|
@ -1336,3 +1336,140 @@ func TestAdminQueryEventReports(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventReportsGetDelete(t *testing.T) {
|
||||||
|
alice := test.NewUser(t, test.WithAccountType(uapi.AccountTypeAdmin))
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
room := test.NewRoom(t, alice)
|
||||||
|
|
||||||
|
// Add a name and alias
|
||||||
|
roomName := "Testing"
|
||||||
|
alias := "#testing"
|
||||||
|
room.CreateAndInsert(t, alice, spec.MRoomName, map[string]string{"name": roomName}, test.WithStateKey(""))
|
||||||
|
room.CreateAndInsert(t, alice, spec.MRoomCanonicalAlias, map[string]string{"alias": alias}, test.WithStateKey(""))
|
||||||
|
|
||||||
|
// Join the rooms with Bob
|
||||||
|
room.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
// Create a few events to report
|
||||||
|
|
||||||
|
eventIDToReport := room.CreateAndInsert(t, alice, "m.room.message", map[string]interface{}{"body": "hello world"})
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
defer close()
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
|
||||||
|
defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
|
||||||
|
|
||||||
|
// Use an actual roomserver for this
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
|
|
||||||
|
if err := api.SendEvents(context.Background(), rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
alice: {},
|
||||||
|
bob: {},
|
||||||
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers)
|
||||||
|
|
||||||
|
reqBody := map[string]any{
|
||||||
|
"reason": "baaad",
|
||||||
|
"score": -100,
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(reqBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var req *http.Request
|
||||||
|
// Report the event
|
||||||
|
req = httptest.NewRequest(http.MethodPost, fmt.Sprintf("/_matrix/client/v3/rooms/%s/report/%s", room.ID, eventIDToReport.EventID()), strings.NewReader(string(body)))
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[bob].accessToken)
|
||||||
|
|
||||||
|
routers.Client.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected report to succeed, got HTTP %d instead: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Can not query with invalid ID", func(t *testing.T) {
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodGet, "/_synapse/admin/v1/event_reports/abc", strings.NewReader(string(body)))
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken)
|
||||||
|
|
||||||
|
routers.SynapseAdmin.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Fatalf("expected getting report to fail, got HTTP %d instead: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Can query with valid ID", func(t *testing.T) {
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodGet, "/_synapse/admin/v1/event_reports/1", strings.NewReader(string(body)))
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken)
|
||||||
|
|
||||||
|
routers.SynapseAdmin.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected getting report to fail, got HTTP %d instead: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
resp := api.QueryAdminEventReportResponse{}
|
||||||
|
if err = json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// test a few things
|
||||||
|
if resp.EventID != eventIDToReport.EventID() {
|
||||||
|
t.Fatalf("expected eventID to be %s, got %s instead", eventIDToReport.EventID(), resp.EventID)
|
||||||
|
}
|
||||||
|
if resp.RoomName != roomName {
|
||||||
|
t.Fatalf("expected roomName to be %s, got %s instead", roomName, resp.RoomName)
|
||||||
|
}
|
||||||
|
if resp.CanonicalAlias != alias {
|
||||||
|
t.Fatalf("expected alias to be %s, got %s instead", alias, resp.CanonicalAlias)
|
||||||
|
}
|
||||||
|
if reflect.DeepEqual(resp.EventJSON, eventIDToReport.JSON()) {
|
||||||
|
t.Fatal("mismatching eventJSON")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Can delete with a valid ID", func(t *testing.T) {
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodDelete, "/_synapse/admin/v1/event_reports/1", strings.NewReader(string(body)))
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken)
|
||||||
|
|
||||||
|
routers.SynapseAdmin.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected getting report to fail, got HTTP %d instead: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Can not query deleted report", func(t *testing.T) {
|
||||||
|
w = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest(http.MethodGet, "/_synapse/admin/v1/event_reports/1", strings.NewReader(string(body)))
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken)
|
||||||
|
|
||||||
|
routers.SynapseAdmin.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code == http.StatusOK {
|
||||||
|
t.Fatalf("expected getting report to fail, got HTTP %d instead: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -530,6 +530,54 @@ func GetEventReports(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetEventReport(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI, reportID string) util.JSONResponse {
|
||||||
|
parsedReportID, err := strconv.ParseUint(reportID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
// Given this is an admin endpoint, let them know what didn't work.
|
||||||
|
JSON: spec.InvalidParam(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
report, err := rsAPI.QueryAdminEventReport(req.Context(), parsedReportID)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: report,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteEventReport(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI, reportID string) util.JSONResponse {
|
||||||
|
parsedReportID, err := strconv.ParseUint(reportID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
// Given this is an admin endpoint, let them know what didn't work.
|
||||||
|
JSON: spec.InvalidParam(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rsAPI.PerformAdminDeleteEventReport(req.Context(), parsedReportID)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func parseUint64OrDefault(input string, defaultValue uint64) uint64 {
|
func parseUint64OrDefault(input string, defaultValue uint64) uint64 {
|
||||||
v, err := strconv.ParseUint(input, 10, 64)
|
v, err := strconv.ParseUint(input, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1535,7 +1535,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/event_reports",
|
synapseAdminRouter.Handle("/admin/v1/event_reports",
|
||||||
httputil.MakeAdminAPI("admin_report_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_report_events", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
from := parseUint64OrDefault(req.URL.Query().Get("from"), 0)
|
from := parseUint64OrDefault(req.URL.Query().Get("from"), 0)
|
||||||
limit := parseUint64OrDefault(req.URL.Query().Get("limit"), 100)
|
limit := parseUint64OrDefault(req.URL.Query().Get("limit"), 100)
|
||||||
dir := req.URL.Query().Get("dir")
|
dir := req.URL.Query().Get("dir")
|
||||||
|
@ -1547,4 +1547,24 @@ func Setup(
|
||||||
return GetEventReports(req, rsAPI, from, limit, backwards, userID, roomID)
|
return GetEventReports(req, rsAPI, from, limit, backwards, userID, roomID)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
||||||
|
httputil.MakeAdminAPI("admin_report_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return GetEventReport(req, rsAPI, vars["reportID"])
|
||||||
|
}),
|
||||||
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
||||||
|
httputil.MakeAdminAPI("admin_report_event_delete", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return DeleteEventReport(req, rsAPI, vars["reportID"])
|
||||||
|
}),
|
||||||
|
).Methods(http.MethodDelete, http.MethodOptions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,8 @@ type ClientRoomserverAPI interface {
|
||||||
score int64,
|
score int64,
|
||||||
) (int64, error)
|
) (int64, error)
|
||||||
QueryAdminEventReports(ctx context.Context, from, limit uint64, backwards bool, userID, roomID string) ([]QueryAdminEventReportsResponse, int64, error)
|
QueryAdminEventReports(ctx context.Context, from, limit uint64, backwards bool, userID, roomID string) ([]QueryAdminEventReportsResponse, int64, error)
|
||||||
|
QueryAdminEventReport(ctx context.Context, reportID uint64) (QueryAdminEventReportResponse, error)
|
||||||
|
PerformAdminDeleteEventReport(ctx context.Context, reportID uint64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserRoomserverAPI interface {
|
type UserRoomserverAPI interface {
|
||||||
|
|
|
@ -363,6 +363,11 @@ type QueryAdminEventReportsResponse struct {
|
||||||
ReceivedTS spec.Timestamp `json:"received_ts"`
|
ReceivedTS spec.Timestamp `json:"received_ts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryAdminEventReportResponse struct {
|
||||||
|
QueryAdminEventReportsResponse
|
||||||
|
EventJSON json.RawMessage `json:"event_json"`
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON stringifies the room ID and StateKeyTuple keys so they can be sent over the wire in HTTP API mode.
|
// MarshalJSON stringifies the room ID and StateKeyTuple keys so they can be sent over the wire in HTTP API mode.
|
||||||
func (r *QueryBulkStateContentResponse) MarshalJSON() ([]byte, error) {
|
func (r *QueryBulkStateContentResponse) MarshalJSON() ([]byte, error) {
|
||||||
se := make(map[string]string)
|
se := make(map[string]string)
|
||||||
|
|
|
@ -354,3 +354,7 @@ func (r *Admin) PerformAdminDownloadState(
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Admin) PerformAdminDeleteEventReport(ctx context.Context, reportID uint64) error {
|
||||||
|
return r.DB.AdminDeleteEventReport(ctx, reportID)
|
||||||
|
}
|
||||||
|
|
|
@ -1109,3 +1109,8 @@ func (r *Queryer) RoomsWithACLs(ctx context.Context) ([]string, error) {
|
||||||
func (r *Queryer) QueryAdminEventReports(ctx context.Context, from uint64, limit uint64, backwards bool, userID, roomID string) ([]api.QueryAdminEventReportsResponse, int64, error) {
|
func (r *Queryer) QueryAdminEventReports(ctx context.Context, from uint64, limit uint64, backwards bool, userID, roomID string) ([]api.QueryAdminEventReportsResponse, int64, error) {
|
||||||
return r.DB.QueryAdminEventReports(ctx, from, limit, backwards, userID, roomID)
|
return r.DB.QueryAdminEventReports(ctx, from, limit, backwards, userID, roomID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryAdminEventReport returns a single event report.
|
||||||
|
func (r *Queryer) QueryAdminEventReport(ctx context.Context, reportID uint64) (api.QueryAdminEventReportResponse, error) {
|
||||||
|
return r.DB.QueryAdminEventReport(ctx, reportID)
|
||||||
|
}
|
||||||
|
|
|
@ -196,6 +196,8 @@ type Database interface {
|
||||||
// RoomsWithACLs returns all room IDs for rooms with ACLs
|
// RoomsWithACLs returns all room IDs for rooms with ACLs
|
||||||
RoomsWithACLs(ctx context.Context) ([]string, error)
|
RoomsWithACLs(ctx context.Context) ([]string, error)
|
||||||
QueryAdminEventReports(ctx context.Context, from uint64, limit uint64, backwards bool, userID string, roomID string) ([]api.QueryAdminEventReportsResponse, int64, error)
|
QueryAdminEventReports(ctx context.Context, from uint64, limit uint64, backwards bool, userID string, roomID string) ([]api.QueryAdminEventReportsResponse, int64, error)
|
||||||
|
QueryAdminEventReport(ctx context.Context, reportID uint64) (api.QueryAdminEventReportResponse, error)
|
||||||
|
AdminDeleteEventReport(ctx context.Context, reportID uint64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserRoomKeys interface {
|
type UserRoomKeys interface {
|
||||||
|
|
|
@ -75,10 +75,20 @@ OFFSET $3
|
||||||
LIMIT $4
|
LIMIT $4
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const selectReportedEventSQL = `
|
||||||
|
SELECT id, room_nid, event_nid, reporting_user_nid, event_sender_nid, reason, score, received_ts
|
||||||
|
FROM roomserver_reported_events
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
const deleteReportedEventSQL = `DELETE FROM roomserver_reported_events WHERE id = $1`
|
||||||
|
|
||||||
type reportedEventsStatements struct {
|
type reportedEventsStatements struct {
|
||||||
insertReportedEventsStmt *sql.Stmt
|
insertReportedEventsStmt *sql.Stmt
|
||||||
selectReportedEventsDescStmt *sql.Stmt
|
selectReportedEventsDescStmt *sql.Stmt
|
||||||
selectReportedEventsAscStmt *sql.Stmt
|
selectReportedEventsAscStmt *sql.Stmt
|
||||||
|
selectReportedEventStmt *sql.Stmt
|
||||||
|
deleteReportedEventStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateReportedEventsTable(db *sql.DB) error {
|
func CreateReportedEventsTable(db *sql.DB) error {
|
||||||
|
@ -93,6 +103,8 @@ func PrepareReportedEventsTable(db *sql.DB) (tables.ReportedEvents, error) {
|
||||||
{&s.insertReportedEventsStmt, insertReportedEventSQL},
|
{&s.insertReportedEventsStmt, insertReportedEventSQL},
|
||||||
{&s.selectReportedEventsDescStmt, selectReportedEventsDescSQL},
|
{&s.selectReportedEventsDescStmt, selectReportedEventsDescSQL},
|
||||||
{&s.selectReportedEventsAscStmt, selectReportedEventsAscSQL},
|
{&s.selectReportedEventsAscStmt, selectReportedEventsAscSQL},
|
||||||
|
{&s.selectReportedEventStmt, selectReportedEventSQL},
|
||||||
|
{&s.deleteReportedEventStmt, deleteReportedEventSQL},
|
||||||
}.Prepare(db)
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,3 +190,32 @@ func (r *reportedEventsStatements) SelectReportedEvents(
|
||||||
|
|
||||||
return result, count, rows.Err()
|
return result, count, rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *reportedEventsStatements) SelectReportedEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
txn *sql.Tx,
|
||||||
|
reportID uint64,
|
||||||
|
) (api.QueryAdminEventReportResponse, error) {
|
||||||
|
stmt := sqlutil.TxStmt(txn, r.selectReportedEventStmt)
|
||||||
|
|
||||||
|
var row api.QueryAdminEventReportResponse
|
||||||
|
if err := stmt.QueryRowContext(ctx, reportID).Scan(
|
||||||
|
&row.ID,
|
||||||
|
&row.RoomNID,
|
||||||
|
&row.EventNID,
|
||||||
|
&row.ReportingUserNID,
|
||||||
|
&row.SenderNID,
|
||||||
|
&row.Reason,
|
||||||
|
&row.Score,
|
||||||
|
&row.ReceivedTS,
|
||||||
|
); err != nil {
|
||||||
|
return api.QueryAdminEventReportResponse{}, err
|
||||||
|
}
|
||||||
|
return row, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reportedEventsStatements) DeleteReportedEvent(ctx context.Context, txn *sql.Tx, reportID uint64) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, r.deleteReportedEventStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, reportID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -2040,6 +2040,74 @@ func (d *Database) QueryAdminEventReports(ctx context.Context, from uint64, limi
|
||||||
return reports, count, nil
|
return reports, count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Database) QueryAdminEventReport(ctx context.Context, reportID uint64) (api.QueryAdminEventReportResponse, error) {
|
||||||
|
|
||||||
|
report, err := d.ReportedEventsTable.SelectReportedEvent(ctx, nil, reportID)
|
||||||
|
if err != nil {
|
||||||
|
return api.QueryAdminEventReportResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a map from EventStateKeyNID to userID
|
||||||
|
userNIDMap, err := d.EventStateKeys(ctx, []types.EventStateKeyNID{report.ReportingUserNID, report.SenderNID})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("unable to map userNIDs to userIDs")
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
|
roomIDs, err := d.RoomsTable.BulkSelectRoomIDs(ctx, nil, []types.RoomNID{report.RoomNID})
|
||||||
|
if err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(roomIDs) != 1 {
|
||||||
|
return report, fmt.Errorf("expected one roomID, got %d", len(roomIDs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace this with something more efficient, as it loads the entire state snapshot.
|
||||||
|
stateContent, err := d.GetBulkStateContent(ctx, roomIDs, []gomatrixserverlib.StateKeyTuple{
|
||||||
|
{EventType: spec.MRoomName, StateKey: ""},
|
||||||
|
{EventType: spec.MRoomCanonicalAlias, StateKey: ""},
|
||||||
|
}, false)
|
||||||
|
if err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eventIDMap, err := d.EventIDs(ctx, []types.EventNID{report.EventNID})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("unable to map eventNIDs to eventIDs")
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
if len(eventIDMap) != 1 {
|
||||||
|
return report, fmt.Errorf("expected %d eventIDs, got %d", 1, len(eventIDMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
eventJSONs, err := d.EventJSONTable.BulkSelectEventJSON(ctx, nil, []types.EventNID{report.EventNID})
|
||||||
|
if err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
if len(eventJSONs) != 1 {
|
||||||
|
return report, fmt.Errorf("expected %d eventJSONs, got %d", 1, len(eventJSONs))
|
||||||
|
}
|
||||||
|
|
||||||
|
roomName, canonicalAlias := findRoomNameAndCanonicalAlias(stateContent, roomIDs[0])
|
||||||
|
|
||||||
|
report.Sender = userNIDMap[report.SenderNID]
|
||||||
|
report.UserID = userNIDMap[report.ReportingUserNID]
|
||||||
|
report.RoomID = roomIDs[0]
|
||||||
|
report.RoomName = roomName
|
||||||
|
report.CanonicalAlias = canonicalAlias
|
||||||
|
report.EventID = eventIDMap[report.EventNID]
|
||||||
|
report.EventJSON = eventJSONs[0].EventJSON
|
||||||
|
|
||||||
|
return report, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) AdminDeleteEventReport(ctx context.Context, reportID uint64) error {
|
||||||
|
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
||||||
|
return d.ReportedEventsTable.DeleteReportedEvent(ctx, txn, reportID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// findRoomNameAndCanonicalAlias loops over events to find the corresponding room name and canonicalAlias
|
// findRoomNameAndCanonicalAlias loops over events to find the corresponding room name and canonicalAlias
|
||||||
// for a given roomID.
|
// for a given roomID.
|
||||||
func findRoomNameAndCanonicalAlias(events []tables.StrippedEvent, roomID string) (name, canonicalAlias string) {
|
func findRoomNameAndCanonicalAlias(events []tables.StrippedEvent, roomID string) (name, canonicalAlias string) {
|
||||||
|
|
|
@ -74,10 +74,20 @@ LIMIT $3
|
||||||
OFFSET $4
|
OFFSET $4
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const selectReportedEventSQL = `
|
||||||
|
SELECT id, room_nid, event_nid, reporting_user_nid, event_sender_nid, reason, score, received_ts
|
||||||
|
FROM roomserver_reported_events
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
const deleteReportedEventSQL = `DELETE FROM roomserver_reported_events WHERE id = $1`
|
||||||
|
|
||||||
type reportedEventsStatements struct {
|
type reportedEventsStatements struct {
|
||||||
insertReportedEventsStmt *sql.Stmt
|
insertReportedEventsStmt *sql.Stmt
|
||||||
selectReportedEventsDescStmt *sql.Stmt
|
selectReportedEventsDescStmt *sql.Stmt
|
||||||
selectReportedEventsAscStmt *sql.Stmt
|
selectReportedEventsAscStmt *sql.Stmt
|
||||||
|
selectReportedEventStmt *sql.Stmt
|
||||||
|
deleteReportedEventStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateReportedEventsTable(db *sql.DB) error {
|
func CreateReportedEventsTable(db *sql.DB) error {
|
||||||
|
@ -92,6 +102,8 @@ func PrepareReportedEventsTable(db *sql.DB) (tables.ReportedEvents, error) {
|
||||||
{&s.insertReportedEventsStmt, insertReportedEventSQL},
|
{&s.insertReportedEventsStmt, insertReportedEventSQL},
|
||||||
{&s.selectReportedEventsDescStmt, selectReportedEventsDescSQL},
|
{&s.selectReportedEventsDescStmt, selectReportedEventsDescSQL},
|
||||||
{&s.selectReportedEventsAscStmt, selectReportedEventsAscSQL},
|
{&s.selectReportedEventsAscStmt, selectReportedEventsAscSQL},
|
||||||
|
{&s.selectReportedEventStmt, selectReportedEventSQL},
|
||||||
|
{&s.deleteReportedEventStmt, deleteReportedEventSQL},
|
||||||
}.Prepare(db)
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,3 +190,32 @@ func (r *reportedEventsStatements) SelectReportedEvents(
|
||||||
|
|
||||||
return result, count, rows.Err()
|
return result, count, rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *reportedEventsStatements) SelectReportedEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
txn *sql.Tx,
|
||||||
|
reportID uint64,
|
||||||
|
) (api.QueryAdminEventReportResponse, error) {
|
||||||
|
stmt := sqlutil.TxStmt(txn, r.selectReportedEventStmt)
|
||||||
|
|
||||||
|
var row api.QueryAdminEventReportResponse
|
||||||
|
if err := stmt.QueryRowContext(ctx, reportID).Scan(
|
||||||
|
&row.ID,
|
||||||
|
&row.RoomNID,
|
||||||
|
&row.EventNID,
|
||||||
|
&row.ReportingUserNID,
|
||||||
|
&row.SenderNID,
|
||||||
|
&row.Reason,
|
||||||
|
&row.Score,
|
||||||
|
&row.ReceivedTS,
|
||||||
|
); err != nil {
|
||||||
|
return api.QueryAdminEventReportResponse{}, err
|
||||||
|
}
|
||||||
|
return row, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reportedEventsStatements) DeleteReportedEvent(ctx context.Context, txn *sql.Tx, reportID uint64) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, r.deleteReportedEventStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, reportID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -147,6 +147,12 @@ type ReportedEvents interface {
|
||||||
reportingUserID types.EventStateKeyNID,
|
reportingUserID types.EventStateKeyNID,
|
||||||
roomNID types.RoomNID,
|
roomNID types.RoomNID,
|
||||||
) ([]api.QueryAdminEventReportsResponse, int64, error)
|
) ([]api.QueryAdminEventReportsResponse, int64, error)
|
||||||
|
SelectReportedEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
txn *sql.Tx,
|
||||||
|
reportID uint64,
|
||||||
|
) (api.QueryAdminEventReportResponse, error)
|
||||||
|
DeleteReportedEvent(ctx context.Context, txn *sql.Tx, reportID uint64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type MembershipState int64
|
type MembershipState int64
|
||||||
|
|
Loading…
Reference in a new issue