diff --git a/docs/administration/4_adminapi.md b/docs/administration/4_adminapi.md index c521cbc90..46cfac220 100644 --- a/docs/administration/4_adminapi.md +++ b/docs/administration/4_adminapi.md @@ -22,12 +22,12 @@ curl --header "Authorization: Bearer " -X `Help & About` -> `Advanced` -> `Access Token`. Be aware that an `access_token` allows a client to perform actions as an user and should be kept **secret**. -The user must be an administrator in the `account_accounts` table in order to use these endpoints. +The user must be an administrator in the `userapi_accounts` table in order to use these endpoints. -Existing user accounts can be set to administrative accounts by changing `account_type` to `3` in `account_accounts` +Existing user accounts can be set to administrative accounts by changing `account_type` to `3` in `userapi_accounts` ``` -UPDATE account_accounts SET account_type = 3 WHERE localpart = '$localpart'; +UPDATE userapi_accounts SET account_type = 3 WHERE localpart = '$localpart'; ``` Where `$localpart` is the username only (e.g. `alice`). @@ -38,6 +38,9 @@ This endpoint will instruct Dendrite to part all local users from the given `roo in the URL. It may take some time to complete. A JSON body will be returned containing the user IDs of all affected users. +If the room has an alias set (e.g. is published), the room's ID will not be visible in the URL, but it can +be found as the room's "internal ID" in Element Web (Settings -> Advanced) + ## GET `/_dendrite/admin/evacuateUser/{userID}` This endpoint will instruct Dendrite to part the given local `userID` in the URL from diff --git a/syncapi/storage/shared/storage_consumer.go b/syncapi/storage/shared/storage_consumer.go index aeeebb1d2..18802d0c4 100644 --- a/syncapi/storage/shared/storage_consumer.go +++ b/syncapi/storage/shared/storage_consumer.go @@ -567,9 +567,14 @@ func (d *Database) ReIndex(ctx context.Context, limit, afterID int64) (map[int64 } func (d *Database) UpdateRelations(ctx context.Context, event *gomatrixserverlib.HeaderedEvent) error { + // No need to unmarshal if the event is a redaction + if event.Type() == gomatrixserverlib.MRoomRedaction { + return nil + } var content gomatrixserverlib.RelationContent if err := json.Unmarshal(event.Content(), &content); err != nil { - return fmt.Errorf("json.Unmarshal: %w", err) + logrus.WithError(err).Error("unable to unmarshal relation content") + return nil } switch { case content.Relations == nil: @@ -578,8 +583,6 @@ func (d *Database) UpdateRelations(ctx context.Context, event *gomatrixserverlib return nil case content.Relations.RelationType == "": return nil - case event.Type() == gomatrixserverlib.MRoomRedaction: - return nil default: return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { return d.Relations.InsertRelation( diff --git a/syncapi/syncapi_test.go b/syncapi/syncapi_test.go index e748660f7..1cb82ce11 100644 --- a/syncapi/syncapi_test.go +++ b/syncapi/syncapi_test.go @@ -10,11 +10,13 @@ import ( "testing" "time" - "github.com/matrix-org/dendrite/syncapi/routing" "github.com/matrix-org/gomatrixserverlib" "github.com/nats-io/nats.go" "github.com/tidwall/gjson" + "github.com/matrix-org/dendrite/syncapi/routing" + "github.com/matrix-org/dendrite/syncapi/storage" + "github.com/matrix-org/dendrite/clientapi/producers" "github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver/api" @@ -1074,6 +1076,90 @@ func testContext(t *testing.T, dbType test.DBType) { } } +func TestUpdateRelations(t *testing.T) { + testCases := []struct { + name string + eventContent map[string]interface{} + eventType string + }{ + { + name: "empty event content should not error", + }, + { + name: "unable to unmarshal event should not error", + eventContent: map[string]interface{}{ + "m.relates_to": map[string]interface{}{ + "event_id": map[string]interface{}{}, // this should be a string and not struct + }, + }, + }, + { + name: "empty event ID is ignored", + eventContent: map[string]interface{}{ + "m.relates_to": map[string]interface{}{ + "event_id": "", + }, + }, + }, + { + name: "empty rel_type is ignored", + eventContent: map[string]interface{}{ + "m.relates_to": map[string]interface{}{ + "event_id": "$randomEventID", + "rel_type": "", + }, + }, + }, + { + name: "redactions are ignored", + eventType: gomatrixserverlib.MRoomRedaction, + eventContent: map[string]interface{}{ + "m.relates_to": map[string]interface{}{ + "event_id": "$randomEventID", + "rel_type": "m.replace", + }, + }, + }, + { + name: "valid event is correctly written", + eventContent: map[string]interface{}{ + "m.relates_to": map[string]interface{}{ + "event_id": "$randomEventID", + "rel_type": "m.replace", + }, + }, + }, + } + + ctx := context.Background() + + alice := test.NewUser(t) + room := test.NewRoom(t, alice) + + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + base, shutdownBase := testrig.CreateBaseDendrite(t, dbType) + t.Cleanup(shutdownBase) + db, err := storage.NewSyncServerDatasource(base, &base.Cfg.SyncAPI.Database) + if err != nil { + t.Fatal(err) + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + evType := "m.room.message" + if tc.eventType != "" { + evType = tc.eventType + } + ev := room.CreateEvent(t, alice, evType, tc.eventContent) + err = db.UpdateRelations(ctx, ev) + if err != nil { + t.Fatal(err) + } + }) + } + }) +} + func syncUntil(t *testing.T, base *base.BaseDendrite, accessToken string, skip bool,