Add possibility to ignore users (#2329)

* Add ignore users

* Ignore users in pushrules
Add passing tests

* Update sytest lists

* Store ignore knowledge in the sync API

* Fix copyrights

Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com>
This commit is contained in:
Till 2022-04-07 16:08:19 +02:00 committed by GitHub
parent 99ef547295
commit 60ee7eef4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 307 additions and 20 deletions

View file

@ -150,6 +150,9 @@ type Database interface {
SelectContextAfterEvent(ctx context.Context, id int, roomID string, filter *gomatrixserverlib.RoomEventFilter) (int, []*gomatrixserverlib.HeaderedEvent, error)
StreamToTopologicalPosition(ctx context.Context, roomID string, streamPos types.StreamPosition, backwardOrdering bool) (types.TopologyToken, error)
IgnoresForUser(ctx context.Context, userID string) (*types.IgnoredUsers, error)
UpdateIgnoresForUser(ctx context.Context, userID string, ignores *types.IgnoredUsers) error
}
type Presence interface {

View file

@ -0,0 +1,87 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package postgres
import (
"context"
"database/sql"
"encoding/json"
"github.com/matrix-org/dendrite/syncapi/storage/tables"
"github.com/matrix-org/dendrite/syncapi/types"
)
const ignoresSchema = `
-- Stores data about ignoress
CREATE TABLE IF NOT EXISTS syncapi_ignores (
-- The user ID whose ignore list this belongs to.
user_id TEXT NOT NULL,
ignores_json TEXT NOT NULL,
PRIMARY KEY(user_id)
);
`
const selectIgnoresSQL = "" +
"SELECT ignores_json FROM syncapi_ignores WHERE user_id = $1"
const upsertIgnoresSQL = "" +
"INSERT INTO syncapi_ignores (user_id, ignores_json) VALUES ($1, $2)" +
" ON CONFLICT (user_id) DO UPDATE set ignores_json = $2"
type ignoresStatements struct {
selectIgnoresStmt *sql.Stmt
upsertIgnoresStmt *sql.Stmt
}
func NewPostgresIgnoresTable(db *sql.DB) (tables.Ignores, error) {
_, err := db.Exec(ignoresSchema)
if err != nil {
return nil, err
}
s := &ignoresStatements{}
if s.selectIgnoresStmt, err = db.Prepare(selectIgnoresSQL); err != nil {
return nil, err
}
if s.upsertIgnoresStmt, err = db.Prepare(upsertIgnoresSQL); err != nil {
return nil, err
}
return s, nil
}
func (s *ignoresStatements) SelectIgnores(
ctx context.Context, userID string,
) (*types.IgnoredUsers, error) {
var ignoresData []byte
err := s.selectIgnoresStmt.QueryRowContext(ctx, userID).Scan(&ignoresData)
if err != nil {
return nil, err
}
var ignores types.IgnoredUsers
if err = json.Unmarshal(ignoresData, &ignores); err != nil {
return nil, err
}
return &ignores, nil
}
func (s *ignoresStatements) UpsertIgnores(
ctx context.Context, userID string, ignores *types.IgnoredUsers,
) error {
ignoresJSON, err := json.Marshal(ignores)
if err != nil {
return err
}
_, err = s.upsertIgnoresStmt.ExecContext(ctx, userID, ignoresJSON)
return err
}

View file

@ -90,6 +90,10 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, e
if err != nil {
return nil, err
}
ignores, err := NewPostgresIgnoresTable(d.db)
if err != nil {
return nil, err
}
presence, err := NewPostgresPresenceTable(d.db)
if err != nil {
return nil, err
@ -115,6 +119,7 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, e
Receipts: receipts,
Memberships: memberships,
NotificationData: notificationData,
Ignores: ignores,
Presence: presence,
}
return &d, nil

View file

@ -48,6 +48,7 @@ type Database struct {
Receipts tables.Receipts
Memberships tables.Memberships
NotificationData tables.NotificationData
Ignores tables.Ignores
Presence tables.Presence
}
@ -1004,6 +1005,14 @@ func (s *Database) SelectContextAfterEvent(ctx context.Context, id int, roomID s
return s.OutputEvents.SelectContextAfterEvent(ctx, nil, id, roomID, filter)
}
func (s *Database) IgnoresForUser(ctx context.Context, userID string) (*types.IgnoredUsers, error) {
return s.Ignores.SelectIgnores(ctx, userID)
}
func (s *Database) UpdateIgnoresForUser(ctx context.Context, userID string, ignores *types.IgnoredUsers) error {
return s.Ignores.UpsertIgnores(ctx, userID, ignores)
}
func (s *Database) UpdatePresence(ctx context.Context, userID string, presence types.Presence, statusMsg *string, lastActiveTS gomatrixserverlib.Timestamp, fromSync bool) (types.StreamPosition, error) {
return s.Presence.UpsertPresence(ctx, nil, userID, statusMsg, presence, lastActiveTS, fromSync)
}

View file

@ -0,0 +1,87 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sqlite3
import (
"context"
"database/sql"
"encoding/json"
"github.com/matrix-org/dendrite/syncapi/storage/tables"
"github.com/matrix-org/dendrite/syncapi/types"
)
const ignoresSchema = `
-- Stores data about ignoress
CREATE TABLE IF NOT EXISTS syncapi_ignores (
-- The user ID whose ignore list this belongs to.
user_id TEXT NOT NULL,
ignores_json TEXT NOT NULL,
PRIMARY KEY(user_id)
);
`
const selectIgnoresSQL = "" +
"SELECT ignores_json FROM syncapi_ignores WHERE user_id = $1"
const upsertIgnoresSQL = "" +
"INSERT INTO syncapi_ignores (user_id, ignores_json) VALUES ($1, $2)" +
" ON CONFLICT DO UPDATE set ignores_json = $2"
type ignoresStatements struct {
selectIgnoresStmt *sql.Stmt
upsertIgnoresStmt *sql.Stmt
}
func NewSqliteIgnoresTable(db *sql.DB) (tables.Ignores, error) {
_, err := db.Exec(ignoresSchema)
if err != nil {
return nil, err
}
s := &ignoresStatements{}
if s.selectIgnoresStmt, err = db.Prepare(selectIgnoresSQL); err != nil {
return nil, err
}
if s.upsertIgnoresStmt, err = db.Prepare(upsertIgnoresSQL); err != nil {
return nil, err
}
return s, nil
}
func (s *ignoresStatements) SelectIgnores(
ctx context.Context, userID string,
) (*types.IgnoredUsers, error) {
var ignoresData []byte
err := s.selectIgnoresStmt.QueryRowContext(ctx, userID).Scan(&ignoresData)
if err != nil {
return nil, err
}
var ignores types.IgnoredUsers
if err = json.Unmarshal(ignoresData, &ignores); err != nil {
return nil, err
}
return &ignores, nil
}
func (s *ignoresStatements) UpsertIgnores(
ctx context.Context, userID string, ignores *types.IgnoredUsers,
) error {
ignoresJSON, err := json.Marshal(ignores)
if err != nil {
return err
}
_, err = s.upsertIgnoresStmt.ExecContext(ctx, userID, ignoresJSON)
return err
}

View file

@ -100,6 +100,10 @@ func (d *SyncServerDatasource) prepare(dbProperties *config.DatabaseOptions) (er
if err != nil {
return err
}
ignores, err := NewSqliteIgnoresTable(d.db)
if err != nil {
return err
}
presence, err := NewSqlitePresenceTable(d.db, &d.streamID)
if err != nil {
return err
@ -125,6 +129,7 @@ func (d *SyncServerDatasource) prepare(dbProperties *config.DatabaseOptions) (er
Receipts: receipts,
Memberships: memberships,
NotificationData: notificationData,
Ignores: ignores,
Presence: presence,
}
return nil

View file

@ -183,6 +183,11 @@ type NotificationData interface {
SelectMaxID(ctx context.Context) (int64, error)
}
type Ignores interface {
SelectIgnores(ctx context.Context, userID string) (*types.IgnoredUsers, error)
UpsertIgnores(ctx context.Context, userID string, ignores *types.IgnoredUsers) error
}
type Presence interface {
UpsertPresence(ctx context.Context, txn *sql.Tx, userID string, statusMsg *string, presence types.Presence, lastActiveTS gomatrixserverlib.Timestamp, fromSync bool) (pos types.StreamPosition, err error)
GetPresenceForUser(ctx context.Context, txn *sql.Tx, userID string) (presence *types.PresenceInternal, err error)