Namespace user API tables (#2806)
This migrates all the various user API tables, indices and sequences to be `userapi_`-namespaced, rather than the mess they are all now.
This commit is contained in:
parent
9c189b1b80
commit
3aa92efaa3
|
@ -10,19 +10,24 @@ import (
|
||||||
"github.com/matrix-org/dendrite/internal/pushrules"
|
"github.com/matrix-org/dendrite/internal/pushrules"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/dendrite/userapi/storage"
|
"github.com/matrix-org/dendrite/userapi/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
||||||
|
base, baseclose := testrig.CreateBaseDendrite(t, dbType)
|
||||||
t.Helper()
|
t.Helper()
|
||||||
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
||||||
db, err := storage.NewUserAPIDatabase(nil, &config.DatabaseOptions{
|
db, err := storage.NewUserAPIDatabase(base, &config.DatabaseOptions{
|
||||||
ConnectionString: config.DataSource(connStr),
|
ConnectionString: config.DataSource(connStr),
|
||||||
}, "", 4, 0, 0, "")
|
}, "", 4, 0, 0, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new user db: %v", err)
|
t.Fatalf("failed to create new user db: %v", err)
|
||||||
}
|
}
|
||||||
return db, close
|
return db, func() {
|
||||||
|
close()
|
||||||
|
baseclose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustCreateEvent(t *testing.T, content string) *gomatrixserverlib.HeaderedEvent {
|
func mustCreateEvent(t *testing.T, content string) *gomatrixserverlib.HeaderedEvent {
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
|
|
||||||
const accountDataSchema = `
|
const accountDataSchema = `
|
||||||
-- Stores data about accounts data.
|
-- Stores data about accounts data.
|
||||||
CREATE TABLE IF NOT EXISTS account_data (
|
CREATE TABLE IF NOT EXISTS userapi_account_datas (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL,
|
localpart TEXT NOT NULL,
|
||||||
-- The room ID for this data (empty string if not specific to a room)
|
-- The room ID for this data (empty string if not specific to a room)
|
||||||
|
@ -41,15 +41,15 @@ CREATE TABLE IF NOT EXISTS account_data (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertAccountDataSQL = `
|
const insertAccountDataSQL = `
|
||||||
INSERT INTO account_data(localpart, room_id, type, content) VALUES($1, $2, $3, $4)
|
INSERT INTO userapi_account_datas(localpart, room_id, type, content) VALUES($1, $2, $3, $4)
|
||||||
ON CONFLICT (localpart, room_id, type) DO UPDATE SET content = EXCLUDED.content
|
ON CONFLICT (localpart, room_id, type) DO UPDATE SET content = EXCLUDED.content
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectAccountDataSQL = "" +
|
const selectAccountDataSQL = "" +
|
||||||
"SELECT room_id, type, content FROM account_data WHERE localpart = $1"
|
"SELECT room_id, type, content FROM userapi_account_datas WHERE localpart = $1"
|
||||||
|
|
||||||
const selectAccountDataByTypeSQL = "" +
|
const selectAccountDataByTypeSQL = "" +
|
||||||
"SELECT content FROM account_data WHERE localpart = $1 AND room_id = $2 AND type = $3"
|
"SELECT content FROM userapi_account_datas WHERE localpart = $1 AND room_id = $2 AND type = $3"
|
||||||
|
|
||||||
type accountDataStatements struct {
|
type accountDataStatements struct {
|
||||||
insertAccountDataStmt *sql.Stmt
|
insertAccountDataStmt *sql.Stmt
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
|
|
||||||
const accountsSchema = `
|
const accountsSchema = `
|
||||||
-- Stores data about accounts.
|
-- Stores data about accounts.
|
||||||
CREATE TABLE IF NOT EXISTS account_accounts (
|
CREATE TABLE IF NOT EXISTS userapi_accounts (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
-- When this account was first created, as a unix timestamp (ms resolution).
|
-- When this account was first created, as a unix timestamp (ms resolution).
|
||||||
|
@ -51,22 +51,22 @@ CREATE TABLE IF NOT EXISTS account_accounts (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertAccountSQL = "" +
|
const insertAccountSQL = "" +
|
||||||
"INSERT INTO account_accounts(localpart, created_ts, password_hash, appservice_id, account_type) VALUES ($1, $2, $3, $4, $5)"
|
"INSERT INTO userapi_accounts(localpart, created_ts, password_hash, appservice_id, account_type) VALUES ($1, $2, $3, $4, $5)"
|
||||||
|
|
||||||
const updatePasswordSQL = "" +
|
const updatePasswordSQL = "" +
|
||||||
"UPDATE account_accounts SET password_hash = $1 WHERE localpart = $2"
|
"UPDATE userapi_accounts SET password_hash = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const deactivateAccountSQL = "" +
|
const deactivateAccountSQL = "" +
|
||||||
"UPDATE account_accounts SET is_deactivated = TRUE WHERE localpart = $1"
|
"UPDATE userapi_accounts SET is_deactivated = TRUE WHERE localpart = $1"
|
||||||
|
|
||||||
const selectAccountByLocalpartSQL = "" +
|
const selectAccountByLocalpartSQL = "" +
|
||||||
"SELECT localpart, appservice_id, account_type FROM account_accounts WHERE localpart = $1"
|
"SELECT localpart, appservice_id, account_type FROM userapi_accounts WHERE localpart = $1"
|
||||||
|
|
||||||
const selectPasswordHashSQL = "" +
|
const selectPasswordHashSQL = "" +
|
||||||
"SELECT password_hash FROM account_accounts WHERE localpart = $1 AND is_deactivated = FALSE"
|
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND is_deactivated = FALSE"
|
||||||
|
|
||||||
const selectNewNumericLocalpartSQL = "" +
|
const selectNewNumericLocalpartSQL = "" +
|
||||||
"SELECT COALESCE(MAX(localpart::bigint), 0) FROM account_accounts WHERE localpart ~ '^[0-9]{1,}$'"
|
"SELECT COALESCE(MAX(localpart::bigint), 0) FROM userapi_accounts WHERE localpart ~ '^[0-9]{1,}$'"
|
||||||
|
|
||||||
type accountsStatements struct {
|
type accountsStatements struct {
|
||||||
insertAccountStmt *sql.Stmt
|
insertAccountStmt *sql.Stmt
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func UpIsActive(ctx context.Context, tx *sql.Tx) error {
|
func UpIsActive(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, "ALTER TABLE account_accounts ADD COLUMN IF NOT EXISTS is_deactivated BOOLEAN DEFAULT FALSE;")
|
_, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts ADD COLUMN IF NOT EXISTS is_deactivated BOOLEAN DEFAULT FALSE;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func UpIsActive(ctx context.Context, tx *sql.Tx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownIsActive(ctx context.Context, tx *sql.Tx) error {
|
func DownIsActive(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, "ALTER TABLE account_accounts DROP COLUMN is_deactivated;")
|
_, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts DROP COLUMN is_deactivated;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
|
|
||||||
func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE device_devices ADD COLUMN IF NOT EXISTS last_seen_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)*1000;
|
ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS last_seen_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)*1000;
|
||||||
ALTER TABLE device_devices ADD COLUMN IF NOT EXISTS ip TEXT;
|
ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS ip TEXT;
|
||||||
ALTER TABLE device_devices ADD COLUMN IF NOT EXISTS user_agent TEXT;`)
|
ALTER TABLE userapi_devices ADD COLUMN IF NOT EXISTS user_agent TEXT;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ ALTER TABLE device_devices ADD COLUMN IF NOT EXISTS user_agent TEXT;`)
|
||||||
|
|
||||||
func DownLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
func DownLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE device_devices DROP COLUMN last_seen_ts;
|
ALTER TABLE userapi_devices DROP COLUMN last_seen_ts;
|
||||||
ALTER TABLE device_devices DROP COLUMN ip;
|
ALTER TABLE userapi_devices DROP COLUMN ip;
|
||||||
ALTER TABLE device_devices DROP COLUMN user_agent;`)
|
ALTER TABLE userapi_devices DROP COLUMN user_agent;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ import (
|
||||||
func UpAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
func UpAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
||||||
// initially set every account to useraccount, change appservice and guest accounts afterwards
|
// initially set every account to useraccount, change appservice and guest accounts afterwards
|
||||||
// (user = 1, guest = 2, admin = 3, appservice = 4)
|
// (user = 1, guest = 2, admin = 3, appservice = 4)
|
||||||
_, err := tx.ExecContext(ctx, `ALTER TABLE account_accounts ADD COLUMN IF NOT EXISTS account_type SMALLINT NOT NULL DEFAULT 1;
|
_, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts ADD COLUMN IF NOT EXISTS account_type SMALLINT NOT NULL DEFAULT 1;
|
||||||
UPDATE account_accounts SET account_type = 4 WHERE appservice_id <> '';
|
UPDATE userapi_accounts SET account_type = 4 WHERE appservice_id <> '';
|
||||||
UPDATE account_accounts SET account_type = 2 WHERE localpart ~ '^[0-9]+$';
|
UPDATE userapi_accounts SET account_type = 2 WHERE localpart ~ '^[0-9]+$';
|
||||||
ALTER TABLE account_accounts ALTER COLUMN account_type DROP DEFAULT;`,
|
ALTER TABLE userapi_accounts ALTER COLUMN account_type DROP DEFAULT;`,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
|
@ -21,7 +21,7 @@ ALTER TABLE account_accounts ALTER COLUMN account_type DROP DEFAULT;`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
func DownAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, "ALTER TABLE account_accounts DROP COLUMN account_type;")
|
_, err := tx.ExecContext(ctx, "ALTER TABLE userapi_accounts DROP COLUMN account_type;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package deltas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
var renameTableMappings = map[string]string{
|
||||||
|
"account_accounts": "userapi_accounts",
|
||||||
|
"account_data": "userapi_account_datas",
|
||||||
|
"device_devices": "userapi_devices",
|
||||||
|
"account_e2e_room_keys": "userapi_key_backups",
|
||||||
|
"account_e2e_room_keys_versions": "userapi_key_backup_versions",
|
||||||
|
"login_tokens": "userapi_login_tokens",
|
||||||
|
"open_id_tokens": "userapi_openid_tokens",
|
||||||
|
"account_profiles": "userapi_profiles",
|
||||||
|
"account_threepid": "userapi_threepids",
|
||||||
|
}
|
||||||
|
|
||||||
|
var renameSequenceMappings = map[string]string{
|
||||||
|
"device_session_id_seq": "userapi_device_session_id_seq",
|
||||||
|
"account_e2e_room_keys_versions_seq": "userapi_key_backup_versions_seq",
|
||||||
|
}
|
||||||
|
|
||||||
|
var renameIndicesMappings = map[string]string{
|
||||||
|
"device_localpart_id_idx": "userapi_device_localpart_id_idx",
|
||||||
|
"e2e_room_keys_idx": "userapi_key_backups_idx",
|
||||||
|
"e2e_room_keys_versions_idx": "userapi_key_backups_versions_idx",
|
||||||
|
"account_e2e_room_keys_versions_idx": "userapi_key_backup_versions_idx",
|
||||||
|
"login_tokens_expiration_idx": "userapi_login_tokens_expiration_idx",
|
||||||
|
"account_threepid_localpart": "userapi_threepid_idx",
|
||||||
|
}
|
||||||
|
|
||||||
|
// I know what you're thinking: you're wondering "why doesn't this use $1
|
||||||
|
// and pass variadic parameters to ExecContext?" — the answer is because
|
||||||
|
// PostgreSQL doesn't expect the table name to be specified as a substituted
|
||||||
|
// argument in that way so it results in a syntax error in the query.
|
||||||
|
|
||||||
|
func UpRenameTables(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
for old, new := range renameTableMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER TABLE IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(old), pq.QuoteIdentifier(new),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameSequenceMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER SEQUENCE IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(old), pq.QuoteIdentifier(new),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameIndicesMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER INDEX IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(old), pq.QuoteIdentifier(new),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownRenameTables(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
for old, new := range renameTableMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER TABLE IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(new), pq.QuoteIdentifier(old),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameSequenceMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER SEQUENCE IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(new), pq.QuoteIdentifier(old),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameIndicesMappings {
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER INDEX IF EXISTS %s RENAME TO %s;",
|
||||||
|
pq.QuoteIdentifier(new), pq.QuoteIdentifier(old),
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -31,10 +31,10 @@ import (
|
||||||
|
|
||||||
const devicesSchema = `
|
const devicesSchema = `
|
||||||
-- This sequence is used for automatic allocation of session_id.
|
-- This sequence is used for automatic allocation of session_id.
|
||||||
CREATE SEQUENCE IF NOT EXISTS device_session_id_seq START 1;
|
CREATE SEQUENCE IF NOT EXISTS userapi_device_session_id_seq START 1;
|
||||||
|
|
||||||
-- Stores data about devices.
|
-- Stores data about devices.
|
||||||
CREATE TABLE IF NOT EXISTS device_devices (
|
CREATE TABLE IF NOT EXISTS userapi_devices (
|
||||||
-- The access token granted to this device. This has to be the primary key
|
-- The access token granted to this device. This has to be the primary key
|
||||||
-- so we can distinguish which device is making a given request.
|
-- so we can distinguish which device is making a given request.
|
||||||
access_token TEXT NOT NULL PRIMARY KEY,
|
access_token TEXT NOT NULL PRIMARY KEY,
|
||||||
|
@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS device_devices (
|
||||||
-- This can be used as a secure substitution of the access token in situations
|
-- This can be used as a secure substitution of the access token in situations
|
||||||
-- where data is associated with access tokens (e.g. transaction storage),
|
-- where data is associated with access tokens (e.g. transaction storage),
|
||||||
-- so we don't have to store users' access tokens everywhere.
|
-- so we don't have to store users' access tokens everywhere.
|
||||||
session_id BIGINT NOT NULL DEFAULT nextval('device_session_id_seq'),
|
session_id BIGINT NOT NULL DEFAULT nextval('userapi_device_session_id_seq'),
|
||||||
-- The device identifier. This only needs to uniquely identify a device for a given user, not globally.
|
-- The device identifier. This only needs to uniquely identify a device for a given user, not globally.
|
||||||
-- access_tokens will be clobbered based on the device ID for a user.
|
-- access_tokens will be clobbered based on the device ID for a user.
|
||||||
device_id TEXT NOT NULL,
|
device_id TEXT NOT NULL,
|
||||||
|
@ -65,39 +65,39 @@ CREATE TABLE IF NOT EXISTS device_devices (
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Device IDs must be unique for a given user.
|
-- Device IDs must be unique for a given user.
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS device_localpart_id_idx ON device_devices(localpart, device_id);
|
CREATE UNIQUE INDEX IF NOT EXISTS userapi_device_localpart_id_idx ON userapi_devices(localpart, device_id);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertDeviceSQL = "" +
|
const insertDeviceSQL = "" +
|
||||||
"INSERT INTO device_devices(device_id, localpart, access_token, created_ts, display_name, last_seen_ts, ip, user_agent) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)" +
|
"INSERT INTO userapi_devices(device_id, localpart, access_token, created_ts, display_name, last_seen_ts, ip, user_agent) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)" +
|
||||||
" RETURNING session_id"
|
" RETURNING session_id"
|
||||||
|
|
||||||
const selectDeviceByTokenSQL = "" +
|
const selectDeviceByTokenSQL = "" +
|
||||||
"SELECT session_id, device_id, localpart FROM device_devices WHERE access_token = $1"
|
"SELECT session_id, device_id, localpart FROM userapi_devices WHERE access_token = $1"
|
||||||
|
|
||||||
const selectDeviceByIDSQL = "" +
|
const selectDeviceByIDSQL = "" +
|
||||||
"SELECT display_name, last_seen_ts, ip FROM device_devices WHERE localpart = $1 and device_id = $2"
|
"SELECT display_name, last_seen_ts, ip FROM userapi_devices WHERE localpart = $1 and device_id = $2"
|
||||||
|
|
||||||
const selectDevicesByLocalpartSQL = "" +
|
const selectDevicesByLocalpartSQL = "" +
|
||||||
"SELECT device_id, display_name, last_seen_ts, ip, user_agent FROM device_devices WHERE localpart = $1 AND device_id != $2 ORDER BY last_seen_ts DESC"
|
"SELECT device_id, display_name, last_seen_ts, ip, user_agent FROM userapi_devices WHERE localpart = $1 AND device_id != $2 ORDER BY last_seen_ts DESC"
|
||||||
|
|
||||||
const updateDeviceNameSQL = "" +
|
const updateDeviceNameSQL = "" +
|
||||||
"UPDATE device_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
"UPDATE userapi_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
||||||
|
|
||||||
const deleteDeviceSQL = "" +
|
const deleteDeviceSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE device_id = $1 AND localpart = $2"
|
"DELETE FROM userapi_devices WHERE device_id = $1 AND localpart = $2"
|
||||||
|
|
||||||
const deleteDevicesByLocalpartSQL = "" +
|
const deleteDevicesByLocalpartSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE localpart = $1 AND device_id != $2"
|
"DELETE FROM userapi_devices WHERE localpart = $1 AND device_id != $2"
|
||||||
|
|
||||||
const deleteDevicesSQL = "" +
|
const deleteDevicesSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE localpart = $1 AND device_id = ANY($2)"
|
"DELETE FROM userapi_devices WHERE localpart = $1 AND device_id = ANY($2)"
|
||||||
|
|
||||||
const selectDevicesByIDSQL = "" +
|
const selectDevicesByIDSQL = "" +
|
||||||
"SELECT device_id, localpart, display_name, last_seen_ts FROM device_devices WHERE device_id = ANY($1) ORDER BY last_seen_ts DESC"
|
"SELECT device_id, localpart, display_name, last_seen_ts FROM userapi_devices WHERE device_id = ANY($1) ORDER BY last_seen_ts DESC"
|
||||||
|
|
||||||
const updateDeviceLastSeen = "" +
|
const updateDeviceLastSeen = "" +
|
||||||
"UPDATE device_devices SET last_seen_ts = $1, ip = $2, user_agent = $3 WHERE localpart = $4 AND device_id = $5"
|
"UPDATE userapi_devices SET last_seen_ts = $1, ip = $2, user_agent = $3 WHERE localpart = $4 AND device_id = $5"
|
||||||
|
|
||||||
type devicesStatements struct {
|
type devicesStatements struct {
|
||||||
insertDeviceStmt *sql.Stmt
|
insertDeviceStmt *sql.Stmt
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const keyBackupTableSchema = `
|
const keyBackupTableSchema = `
|
||||||
CREATE TABLE IF NOT EXISTS account_e2e_room_keys (
|
CREATE TABLE IF NOT EXISTS userapi_key_backups (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
room_id TEXT NOT NULL,
|
room_id TEXT NOT NULL,
|
||||||
session_id TEXT NOT NULL,
|
session_id TEXT NOT NULL,
|
||||||
|
@ -37,31 +37,31 @@ CREATE TABLE IF NOT EXISTS account_e2e_room_keys (
|
||||||
is_verified BOOLEAN NOT NULL,
|
is_verified BOOLEAN NOT NULL,
|
||||||
session_data TEXT NOT NULL
|
session_data TEXT NOT NULL
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS e2e_room_keys_idx ON account_e2e_room_keys(user_id, room_id, session_id, version);
|
CREATE UNIQUE INDEX IF NOT EXISTS userapi_key_backups_idx ON userapi_key_backups(user_id, room_id, session_id, version);
|
||||||
CREATE INDEX IF NOT EXISTS e2e_room_keys_versions_idx ON account_e2e_room_keys(user_id, version);
|
CREATE INDEX IF NOT EXISTS userapi_key_backups_versions_idx ON userapi_key_backups(user_id, version);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertBackupKeySQL = "" +
|
const insertBackupKeySQL = "" +
|
||||||
"INSERT INTO account_e2e_room_keys(user_id, room_id, session_id, version, first_message_index, forwarded_count, is_verified, session_data) " +
|
"INSERT INTO userapi_key_backups(user_id, room_id, session_id, version, first_message_index, forwarded_count, is_verified, session_data) " +
|
||||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
||||||
|
|
||||||
const updateBackupKeySQL = "" +
|
const updateBackupKeySQL = "" +
|
||||||
"UPDATE account_e2e_room_keys SET first_message_index=$1, forwarded_count=$2, is_verified=$3, session_data=$4 " +
|
"UPDATE userapi_key_backups SET first_message_index=$1, forwarded_count=$2, is_verified=$3, session_data=$4 " +
|
||||||
"WHERE user_id=$5 AND room_id=$6 AND session_id=$7 AND version=$8"
|
"WHERE user_id=$5 AND room_id=$6 AND session_id=$7 AND version=$8"
|
||||||
|
|
||||||
const countKeysSQL = "" +
|
const countKeysSQL = "" +
|
||||||
"SELECT COUNT(*) FROM account_e2e_room_keys WHERE user_id = $1 AND version = $2"
|
"SELECT COUNT(*) FROM userapi_key_backups WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeysSQL = "" +
|
const selectKeysSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2"
|
"WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeysByRoomIDSQL = "" +
|
const selectKeysByRoomIDSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2 AND room_id = $3"
|
"WHERE user_id = $1 AND version = $2 AND room_id = $3"
|
||||||
|
|
||||||
const selectKeysByRoomIDAndSessionIDSQL = "" +
|
const selectKeysByRoomIDAndSessionIDSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2 AND room_id = $3 AND session_id = $4"
|
"WHERE user_id = $1 AND version = $2 AND room_id = $3 AND session_id = $4"
|
||||||
|
|
||||||
type keyBackupStatements struct {
|
type keyBackupStatements struct {
|
||||||
|
|
|
@ -26,40 +26,40 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const keyBackupVersionTableSchema = `
|
const keyBackupVersionTableSchema = `
|
||||||
CREATE SEQUENCE IF NOT EXISTS account_e2e_room_keys_versions_seq;
|
CREATE SEQUENCE IF NOT EXISTS userapi_key_backup_versions_seq;
|
||||||
|
|
||||||
-- the metadata for each generation of encrypted e2e session backups
|
-- the metadata for each generation of encrypted e2e session backups
|
||||||
CREATE TABLE IF NOT EXISTS account_e2e_room_keys_versions (
|
CREATE TABLE IF NOT EXISTS userapi_key_backup_versions (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
-- this means no 2 users will ever have the same version of e2e session backups which strictly
|
-- this means no 2 users will ever have the same version of e2e session backups which strictly
|
||||||
-- isn't necessary, but this is easy to do rather than SELECT MAX(version)+1.
|
-- isn't necessary, but this is easy to do rather than SELECT MAX(version)+1.
|
||||||
version BIGINT DEFAULT nextval('account_e2e_room_keys_versions_seq'),
|
version BIGINT DEFAULT nextval('userapi_key_backup_versions_seq'),
|
||||||
algorithm TEXT NOT NULL,
|
algorithm TEXT NOT NULL,
|
||||||
auth_data TEXT NOT NULL,
|
auth_data TEXT NOT NULL,
|
||||||
etag TEXT NOT NULL,
|
etag TEXT NOT NULL,
|
||||||
deleted SMALLINT DEFAULT 0 NOT NULL
|
deleted SMALLINT DEFAULT 0 NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS account_e2e_room_keys_versions_idx ON account_e2e_room_keys_versions(user_id, version);
|
CREATE UNIQUE INDEX IF NOT EXISTS userapi_key_backup_versions_idx ON userapi_key_backup_versions(user_id, version);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertKeyBackupSQL = "" +
|
const insertKeyBackupSQL = "" +
|
||||||
"INSERT INTO account_e2e_room_keys_versions(user_id, algorithm, auth_data, etag) VALUES ($1, $2, $3, $4) RETURNING version"
|
"INSERT INTO userapi_key_backup_versions(user_id, algorithm, auth_data, etag) VALUES ($1, $2, $3, $4) RETURNING version"
|
||||||
|
|
||||||
const updateKeyBackupAuthDataSQL = "" +
|
const updateKeyBackupAuthDataSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET auth_data = $1 WHERE user_id = $2 AND version = $3"
|
"UPDATE userapi_key_backup_versions SET auth_data = $1 WHERE user_id = $2 AND version = $3"
|
||||||
|
|
||||||
const updateKeyBackupETagSQL = "" +
|
const updateKeyBackupETagSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET etag = $1 WHERE user_id = $2 AND version = $3"
|
"UPDATE userapi_key_backup_versions SET etag = $1 WHERE user_id = $2 AND version = $3"
|
||||||
|
|
||||||
const deleteKeyBackupSQL = "" +
|
const deleteKeyBackupSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET deleted=1 WHERE user_id = $1 AND version = $2"
|
"UPDATE userapi_key_backup_versions SET deleted=1 WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeyBackupSQL = "" +
|
const selectKeyBackupSQL = "" +
|
||||||
"SELECT algorithm, auth_data, etag, deleted FROM account_e2e_room_keys_versions WHERE user_id = $1 AND version = $2"
|
"SELECT algorithm, auth_data, etag, deleted FROM userapi_key_backup_versions WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectLatestVersionSQL = "" +
|
const selectLatestVersionSQL = "" +
|
||||||
"SELECT MAX(version) FROM account_e2e_room_keys_versions WHERE user_id = $1"
|
"SELECT MAX(version) FROM userapi_key_backup_versions WHERE user_id = $1"
|
||||||
|
|
||||||
type keyBackupVersionStatements struct {
|
type keyBackupVersionStatements struct {
|
||||||
insertKeyBackupStmt *sql.Stmt
|
insertKeyBackupStmt *sql.Stmt
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const loginTokenSchema = `
|
const loginTokenSchema = `
|
||||||
CREATE TABLE IF NOT EXISTS login_tokens (
|
CREATE TABLE IF NOT EXISTS userapi_login_tokens (
|
||||||
-- The random value of the token issued to a user
|
-- The random value of the token issued to a user
|
||||||
token TEXT NOT NULL PRIMARY KEY,
|
token TEXT NOT NULL PRIMARY KEY,
|
||||||
-- When the token expires
|
-- When the token expires
|
||||||
|
@ -37,17 +37,17 @@ CREATE TABLE IF NOT EXISTS login_tokens (
|
||||||
);
|
);
|
||||||
|
|
||||||
-- This index allows efficient garbage collection of expired tokens.
|
-- This index allows efficient garbage collection of expired tokens.
|
||||||
CREATE INDEX IF NOT EXISTS login_tokens_expiration_idx ON login_tokens(token_expires_at);
|
CREATE INDEX IF NOT EXISTS userapi_login_tokens_expiration_idx ON userapi_login_tokens(token_expires_at);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertLoginTokenSQL = "" +
|
const insertLoginTokenSQL = "" +
|
||||||
"INSERT INTO login_tokens(token, token_expires_at, user_id) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_login_tokens(token, token_expires_at, user_id) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const deleteLoginTokenSQL = "" +
|
const deleteLoginTokenSQL = "" +
|
||||||
"DELETE FROM login_tokens WHERE token = $1 OR token_expires_at <= $2"
|
"DELETE FROM userapi_login_tokens WHERE token = $1 OR token_expires_at <= $2"
|
||||||
|
|
||||||
const selectLoginTokenSQL = "" +
|
const selectLoginTokenSQL = "" +
|
||||||
"SELECT user_id FROM login_tokens WHERE token = $1 AND token_expires_at > $2"
|
"SELECT user_id FROM userapi_login_tokens WHERE token = $1 AND token_expires_at > $2"
|
||||||
|
|
||||||
type loginTokenStatements struct {
|
type loginTokenStatements struct {
|
||||||
insertStmt *sql.Stmt
|
insertStmt *sql.Stmt
|
||||||
|
@ -78,7 +78,7 @@ func (s *loginTokenStatements) InsertLoginToken(ctx context.Context, txn *sql.Tx
|
||||||
// deleteByToken removes the named token.
|
// deleteByToken removes the named token.
|
||||||
//
|
//
|
||||||
// As a simple way to garbage-collect stale tokens, we also remove all expired tokens.
|
// As a simple way to garbage-collect stale tokens, we also remove all expired tokens.
|
||||||
// The login_tokens_expiration_idx index should make that efficient.
|
// The userapi_login_tokens_expiration_idx index should make that efficient.
|
||||||
func (s *loginTokenStatements) DeleteLoginToken(ctx context.Context, txn *sql.Tx, token string) error {
|
func (s *loginTokenStatements) DeleteLoginToken(ctx context.Context, txn *sql.Tx, token string) error {
|
||||||
stmt := sqlutil.TxStmt(txn, s.deleteStmt)
|
stmt := sqlutil.TxStmt(txn, s.deleteStmt)
|
||||||
res, err := stmt.ExecContext(ctx, token, time.Now().UTC())
|
res, err := stmt.ExecContext(ctx, token, time.Now().UTC())
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
const openIDTokenSchema = `
|
const openIDTokenSchema = `
|
||||||
-- Stores data about openid tokens issued for accounts.
|
-- Stores data about openid tokens issued for accounts.
|
||||||
CREATE TABLE IF NOT EXISTS open_id_tokens (
|
CREATE TABLE IF NOT EXISTS userapi_openid_tokens (
|
||||||
-- The value of the token issued to a user
|
-- The value of the token issued to a user
|
||||||
token TEXT NOT NULL PRIMARY KEY,
|
token TEXT NOT NULL PRIMARY KEY,
|
||||||
-- The Matrix user ID for this account
|
-- The Matrix user ID for this account
|
||||||
|
@ -24,10 +24,10 @@ CREATE TABLE IF NOT EXISTS open_id_tokens (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertOpenIDTokenSQL = "" +
|
const insertOpenIDTokenSQL = "" +
|
||||||
"INSERT INTO open_id_tokens(token, localpart, token_expires_at_ms) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_openid_tokens(token, localpart, token_expires_at_ms) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const selectOpenIDTokenSQL = "" +
|
const selectOpenIDTokenSQL = "" +
|
||||||
"SELECT localpart, token_expires_at_ms FROM open_id_tokens WHERE token = $1"
|
"SELECT localpart, token_expires_at_ms FROM userapi_openid_tokens WHERE token = $1"
|
||||||
|
|
||||||
type openIDTokenStatements struct {
|
type openIDTokenStatements struct {
|
||||||
insertTokenStmt *sql.Stmt
|
insertTokenStmt *sql.Stmt
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
|
|
||||||
const profilesSchema = `
|
const profilesSchema = `
|
||||||
-- Stores data about accounts profiles.
|
-- Stores data about accounts profiles.
|
||||||
CREATE TABLE IF NOT EXISTS account_profiles (
|
CREATE TABLE IF NOT EXISTS userapi_profiles (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
-- The display name for this account
|
-- The display name for this account
|
||||||
|
@ -38,19 +38,19 @@ CREATE TABLE IF NOT EXISTS account_profiles (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertProfileSQL = "" +
|
const insertProfileSQL = "" +
|
||||||
"INSERT INTO account_profiles(localpart, display_name, avatar_url) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_profiles(localpart, display_name, avatar_url) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const selectProfileByLocalpartSQL = "" +
|
const selectProfileByLocalpartSQL = "" +
|
||||||
"SELECT localpart, display_name, avatar_url FROM account_profiles WHERE localpart = $1"
|
"SELECT localpart, display_name, avatar_url FROM userapi_profiles WHERE localpart = $1"
|
||||||
|
|
||||||
const setAvatarURLSQL = "" +
|
const setAvatarURLSQL = "" +
|
||||||
"UPDATE account_profiles SET avatar_url = $1 WHERE localpart = $2"
|
"UPDATE userapi_profiles SET avatar_url = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const setDisplayNameSQL = "" +
|
const setDisplayNameSQL = "" +
|
||||||
"UPDATE account_profiles SET display_name = $1 WHERE localpart = $2"
|
"UPDATE userapi_profiles SET display_name = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const selectProfilesBySearchSQL = "" +
|
const selectProfilesBySearchSQL = "" +
|
||||||
"SELECT localpart, display_name, avatar_url FROM account_profiles WHERE localpart LIKE $1 OR display_name LIKE $1 LIMIT $2"
|
"SELECT localpart, display_name, avatar_url FROM userapi_profiles WHERE localpart LIKE $1 OR display_name LIKE $1 LIMIT $2"
|
||||||
|
|
||||||
type profilesStatements struct {
|
type profilesStatements struct {
|
||||||
serverNoticesLocalpart string
|
serverNoticesLocalpart string
|
||||||
|
|
|
@ -45,7 +45,7 @@ CREATE INDEX IF NOT EXISTS userapi_daily_visits_localpart_timestamp_idx ON usera
|
||||||
|
|
||||||
const countUsersLastSeenAfterSQL = "" +
|
const countUsersLastSeenAfterSQL = "" +
|
||||||
"SELECT COUNT(*) FROM (" +
|
"SELECT COUNT(*) FROM (" +
|
||||||
" SELECT localpart FROM device_devices WHERE last_seen_ts > $1 " +
|
" SELECT localpart FROM userapi_devices WHERE last_seen_ts > $1 " +
|
||||||
" GROUP BY localpart" +
|
" GROUP BY localpart" +
|
||||||
" ) u"
|
" ) u"
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ R30Users counts the number of 30 day retained users, defined as:
|
||||||
const countR30UsersSQL = `
|
const countR30UsersSQL = `
|
||||||
SELECT platform, COUNT(*) FROM (
|
SELECT platform, COUNT(*) FROM (
|
||||||
SELECT users.localpart, platform, users.created_ts, MAX(uip.last_seen_ts)
|
SELECT users.localpart, platform, users.created_ts, MAX(uip.last_seen_ts)
|
||||||
FROM account_accounts users
|
FROM userapi_accounts users
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
(SELECT
|
(SELECT
|
||||||
localpart, last_seen_ts,
|
localpart, last_seen_ts,
|
||||||
|
@ -75,7 +75,7 @@ SELECT platform, COUNT(*) FROM (
|
||||||
ELSE 'unknown'
|
ELSE 'unknown'
|
||||||
END
|
END
|
||||||
AS platform
|
AS platform
|
||||||
FROM device_devices
|
FROM userapi_devices
|
||||||
) uip
|
) uip
|
||||||
ON users.localpart = uip.localpart
|
ON users.localpart = uip.localpart
|
||||||
AND users.account_type <> 4
|
AND users.account_type <> 4
|
||||||
|
@ -121,7 +121,7 @@ GROUP BY client_type
|
||||||
`
|
`
|
||||||
|
|
||||||
const countUserByAccountTypeSQL = `
|
const countUserByAccountTypeSQL = `
|
||||||
SELECT COUNT(*) FROM account_accounts WHERE account_type = ANY($1)
|
SELECT COUNT(*) FROM userapi_accounts WHERE account_type = ANY($1)
|
||||||
`
|
`
|
||||||
|
|
||||||
// $1 = All non guest AccountType IDs
|
// $1 = All non guest AccountType IDs
|
||||||
|
@ -134,7 +134,7 @@ SELECT user_type, COUNT(*) AS count FROM (
|
||||||
WHEN account_type = $2 AND appservice_id IS NULL THEN 'guest'
|
WHEN account_type = $2 AND appservice_id IS NULL THEN 'guest'
|
||||||
WHEN account_type = ANY($1) AND appservice_id IS NOT NULL THEN 'bridged'
|
WHEN account_type = ANY($1) AND appservice_id IS NOT NULL THEN 'bridged'
|
||||||
END AS user_type
|
END AS user_type
|
||||||
FROM account_accounts
|
FROM userapi_accounts
|
||||||
WHERE created_ts > $3
|
WHERE created_ts > $3
|
||||||
) AS t GROUP BY user_type
|
) AS t GROUP BY user_type
|
||||||
`
|
`
|
||||||
|
@ -143,14 +143,14 @@ SELECT user_type, COUNT(*) AS count FROM (
|
||||||
const updateUserDailyVisitsSQL = `
|
const updateUserDailyVisitsSQL = `
|
||||||
INSERT INTO userapi_daily_visits(localpart, device_id, timestamp, user_agent)
|
INSERT INTO userapi_daily_visits(localpart, device_id, timestamp, user_agent)
|
||||||
SELECT u.localpart, u.device_id, $1, MAX(u.user_agent)
|
SELECT u.localpart, u.device_id, $1, MAX(u.user_agent)
|
||||||
FROM device_devices AS u
|
FROM userapi_devices AS u
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT localpart, device_id, timestamp FROM userapi_daily_visits
|
SELECT localpart, device_id, timestamp FROM userapi_daily_visits
|
||||||
WHERE timestamp = $1
|
WHERE timestamp = $1
|
||||||
) udv
|
) udv
|
||||||
ON u.localpart = udv.localpart AND u.device_id = udv.device_id
|
ON u.localpart = udv.localpart AND u.device_id = udv.device_id
|
||||||
INNER JOIN device_devices d ON d.localpart = u.localpart
|
INNER JOIN userapi_devices d ON d.localpart = u.localpart
|
||||||
INNER JOIN account_accounts a ON a.localpart = u.localpart
|
INNER JOIN userapi_accounts a ON a.localpart = u.localpart
|
||||||
WHERE $2 <= d.last_seen_ts AND d.last_seen_ts < $3
|
WHERE $2 <= d.last_seen_ts AND d.last_seen_ts < $3
|
||||||
AND a.account_type in (1, 3)
|
AND a.account_type in (1, 3)
|
||||||
GROUP BY u.localpart, u.device_id
|
GROUP BY u.localpart, u.device_id
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/userapi/storage/postgres/deltas"
|
||||||
"github.com/matrix-org/dendrite/userapi/storage/shared"
|
"github.com/matrix-org/dendrite/userapi/storage/shared"
|
||||||
|
|
||||||
// Import the postgres database driver.
|
// Import the postgres database driver.
|
||||||
|
@ -36,6 +37,16 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "userapi: rename tables",
|
||||||
|
Up: deltas.UpRenameTables,
|
||||||
|
Down: deltas.DownRenameTables,
|
||||||
|
})
|
||||||
|
if err = m.Up(base.Context()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
accountDataTable, err := NewPostgresAccountDataTable(db)
|
accountDataTable, err := NewPostgresAccountDataTable(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewPostgresAccountDataTable: %w", err)
|
return nil, fmt.Errorf("NewPostgresAccountDataTable: %w", err)
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
|
|
||||||
const threepidSchema = `
|
const threepidSchema = `
|
||||||
-- Stores data about third party identifiers
|
-- Stores data about third party identifiers
|
||||||
CREATE TABLE IF NOT EXISTS account_threepid (
|
CREATE TABLE IF NOT EXISTS userapi_threepids (
|
||||||
-- The third party identifier
|
-- The third party identifier
|
||||||
threepid TEXT NOT NULL,
|
threepid TEXT NOT NULL,
|
||||||
-- The 3PID medium
|
-- The 3PID medium
|
||||||
|
@ -37,20 +37,20 @@ CREATE TABLE IF NOT EXISTS account_threepid (
|
||||||
PRIMARY KEY(threepid, medium)
|
PRIMARY KEY(threepid, medium)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS account_threepid_localpart ON account_threepid(localpart);
|
CREATE INDEX IF NOT EXISTS userapi_threepid_idx ON userapi_threepids(localpart);
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectLocalpartForThreePIDSQL = "" +
|
const selectLocalpartForThreePIDSQL = "" +
|
||||||
"SELECT localpart FROM account_threepid WHERE threepid = $1 AND medium = $2"
|
"SELECT localpart FROM userapi_threepids WHERE threepid = $1 AND medium = $2"
|
||||||
|
|
||||||
const selectThreePIDsForLocalpartSQL = "" +
|
const selectThreePIDsForLocalpartSQL = "" +
|
||||||
"SELECT threepid, medium FROM account_threepid WHERE localpart = $1"
|
"SELECT threepid, medium FROM userapi_threepids WHERE localpart = $1"
|
||||||
|
|
||||||
const insertThreePIDSQL = "" +
|
const insertThreePIDSQL = "" +
|
||||||
"INSERT INTO account_threepid (threepid, medium, localpart) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_threepids (threepid, medium, localpart) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const deleteThreePIDSQL = "" +
|
const deleteThreePIDSQL = "" +
|
||||||
"DELETE FROM account_threepid WHERE threepid = $1 AND medium = $2"
|
"DELETE FROM userapi_threepids WHERE threepid = $1 AND medium = $2"
|
||||||
|
|
||||||
type threepidStatements struct {
|
type threepidStatements struct {
|
||||||
selectLocalpartForThreePIDStmt *sql.Stmt
|
selectLocalpartForThreePIDStmt *sql.Stmt
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
const accountDataSchema = `
|
const accountDataSchema = `
|
||||||
-- Stores data about accounts data.
|
-- Stores data about accounts data.
|
||||||
CREATE TABLE IF NOT EXISTS account_data (
|
CREATE TABLE IF NOT EXISTS userapi_account_datas (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL,
|
localpart TEXT NOT NULL,
|
||||||
-- The room ID for this data (empty string if not specific to a room)
|
-- The room ID for this data (empty string if not specific to a room)
|
||||||
|
@ -40,15 +40,15 @@ CREATE TABLE IF NOT EXISTS account_data (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertAccountDataSQL = `
|
const insertAccountDataSQL = `
|
||||||
INSERT INTO account_data(localpart, room_id, type, content) VALUES($1, $2, $3, $4)
|
INSERT INTO userapi_account_datas(localpart, room_id, type, content) VALUES($1, $2, $3, $4)
|
||||||
ON CONFLICT (localpart, room_id, type) DO UPDATE SET content = $4
|
ON CONFLICT (localpart, room_id, type) DO UPDATE SET content = $4
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectAccountDataSQL = "" +
|
const selectAccountDataSQL = "" +
|
||||||
"SELECT room_id, type, content FROM account_data WHERE localpart = $1"
|
"SELECT room_id, type, content FROM userapi_account_datas WHERE localpart = $1"
|
||||||
|
|
||||||
const selectAccountDataByTypeSQL = "" +
|
const selectAccountDataByTypeSQL = "" +
|
||||||
"SELECT content FROM account_data WHERE localpart = $1 AND room_id = $2 AND type = $3"
|
"SELECT content FROM userapi_account_datas WHERE localpart = $1 AND room_id = $2 AND type = $3"
|
||||||
|
|
||||||
type accountDataStatements struct {
|
type accountDataStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
|
|
||||||
const accountsSchema = `
|
const accountsSchema = `
|
||||||
-- Stores data about accounts.
|
-- Stores data about accounts.
|
||||||
CREATE TABLE IF NOT EXISTS account_accounts (
|
CREATE TABLE IF NOT EXISTS userapi_accounts (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
-- When this account was first created, as a unix timestamp (ms resolution).
|
-- When this account was first created, as a unix timestamp (ms resolution).
|
||||||
|
@ -51,22 +51,22 @@ CREATE TABLE IF NOT EXISTS account_accounts (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertAccountSQL = "" +
|
const insertAccountSQL = "" +
|
||||||
"INSERT INTO account_accounts(localpart, created_ts, password_hash, appservice_id, account_type) VALUES ($1, $2, $3, $4, $5)"
|
"INSERT INTO userapi_accounts(localpart, created_ts, password_hash, appservice_id, account_type) VALUES ($1, $2, $3, $4, $5)"
|
||||||
|
|
||||||
const updatePasswordSQL = "" +
|
const updatePasswordSQL = "" +
|
||||||
"UPDATE account_accounts SET password_hash = $1 WHERE localpart = $2"
|
"UPDATE userapi_accounts SET password_hash = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const deactivateAccountSQL = "" +
|
const deactivateAccountSQL = "" +
|
||||||
"UPDATE account_accounts SET is_deactivated = 1 WHERE localpart = $1"
|
"UPDATE userapi_accounts SET is_deactivated = 1 WHERE localpart = $1"
|
||||||
|
|
||||||
const selectAccountByLocalpartSQL = "" +
|
const selectAccountByLocalpartSQL = "" +
|
||||||
"SELECT localpart, appservice_id, account_type FROM account_accounts WHERE localpart = $1"
|
"SELECT localpart, appservice_id, account_type FROM userapi_accounts WHERE localpart = $1"
|
||||||
|
|
||||||
const selectPasswordHashSQL = "" +
|
const selectPasswordHashSQL = "" +
|
||||||
"SELECT password_hash FROM account_accounts WHERE localpart = $1 AND is_deactivated = 0"
|
"SELECT password_hash FROM userapi_accounts WHERE localpart = $1 AND is_deactivated = 0"
|
||||||
|
|
||||||
const selectNewNumericLocalpartSQL = "" +
|
const selectNewNumericLocalpartSQL = "" +
|
||||||
"SELECT COALESCE(MAX(CAST(localpart AS INT)), 0) FROM account_accounts WHERE CAST(localpart AS INT) <> 0"
|
"SELECT COALESCE(MAX(CAST(localpart AS INT)), 0) FROM userapi_accounts WHERE CAST(localpart AS INT) <> 0"
|
||||||
|
|
||||||
type accountsStatements struct {
|
type accountsStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
|
|
||||||
func UpIsActive(ctx context.Context, tx *sql.Tx) error {
|
func UpIsActive(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE account_accounts RENAME TO account_accounts_tmp;
|
ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp;
|
||||||
CREATE TABLE account_accounts (
|
CREATE TABLE userapi_accounts (
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
created_ts BIGINT NOT NULL,
|
created_ts BIGINT NOT NULL,
|
||||||
password_hash TEXT,
|
password_hash TEXT,
|
||||||
|
@ -17,13 +17,13 @@ CREATE TABLE account_accounts (
|
||||||
is_deactivated BOOLEAN DEFAULT 0
|
is_deactivated BOOLEAN DEFAULT 0
|
||||||
);
|
);
|
||||||
INSERT
|
INSERT
|
||||||
INTO account_accounts (
|
INTO userapi_accounts (
|
||||||
localpart, created_ts, password_hash, appservice_id
|
localpart, created_ts, password_hash, appservice_id
|
||||||
) SELECT
|
) SELECT
|
||||||
localpart, created_ts, password_hash, appservice_id
|
localpart, created_ts, password_hash, appservice_id
|
||||||
FROM account_accounts_tmp
|
FROM userapi_accounts_tmp
|
||||||
;
|
;
|
||||||
DROP TABLE account_accounts_tmp;`)
|
DROP TABLE userapi_accounts_tmp;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -32,21 +32,21 @@ DROP TABLE account_accounts_tmp;`)
|
||||||
|
|
||||||
func DownIsActive(ctx context.Context, tx *sql.Tx) error {
|
func DownIsActive(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE account_accounts RENAME TO account_accounts_tmp;
|
ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp;
|
||||||
CREATE TABLE account_accounts (
|
CREATE TABLE userapi_accounts (
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
created_ts BIGINT NOT NULL,
|
created_ts BIGINT NOT NULL,
|
||||||
password_hash TEXT,
|
password_hash TEXT,
|
||||||
appservice_id TEXT
|
appservice_id TEXT
|
||||||
);
|
);
|
||||||
INSERT
|
INSERT
|
||||||
INTO account_accounts (
|
INTO userapi_accounts (
|
||||||
localpart, created_ts, password_hash, appservice_id
|
localpart, created_ts, password_hash, appservice_id
|
||||||
) SELECT
|
) SELECT
|
||||||
localpart, created_ts, password_hash, appservice_id
|
localpart, created_ts, password_hash, appservice_id
|
||||||
FROM account_accounts_tmp
|
FROM userapi_accounts_tmp
|
||||||
;
|
;
|
||||||
DROP TABLE account_accounts_tmp;`)
|
DROP TABLE userapi_accounts_tmp;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
|
|
||||||
func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE device_devices RENAME TO device_devices_tmp;
|
ALTER TABLE userapi_devices RENAME TO userapi_devices_tmp;
|
||||||
CREATE TABLE device_devices (
|
CREATE TABLE userapi_devices (
|
||||||
access_token TEXT PRIMARY KEY,
|
access_token TEXT PRIMARY KEY,
|
||||||
session_id INTEGER,
|
session_id INTEGER,
|
||||||
device_id TEXT ,
|
device_id TEXT ,
|
||||||
|
@ -22,12 +22,12 @@ func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
UNIQUE (localpart, device_id)
|
UNIQUE (localpart, device_id)
|
||||||
);
|
);
|
||||||
INSERT
|
INSERT
|
||||||
INTO device_devices (
|
INTO userapi_devices (
|
||||||
access_token, session_id, device_id, localpart, created_ts, display_name, last_seen_ts, ip, user_agent
|
access_token, session_id, device_id, localpart, created_ts, display_name, last_seen_ts, ip, user_agent
|
||||||
) SELECT
|
) SELECT
|
||||||
access_token, session_id, device_id, localpart, created_ts, display_name, created_ts, '', ''
|
access_token, session_id, device_id, localpart, created_ts, display_name, created_ts, '', ''
|
||||||
FROM device_devices_tmp;
|
FROM userapi_devices_tmp;
|
||||||
DROP TABLE device_devices_tmp;`)
|
DROP TABLE userapi_devices_tmp;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ func UpLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
|
||||||
func DownLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
func DownLastSeenTSIP(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE device_devices RENAME TO device_devices_tmp;
|
ALTER TABLE userapi_devices RENAME TO userapi_devices_tmp;
|
||||||
CREATE TABLE IF NOT EXISTS device_devices (
|
CREATE TABLE IF NOT EXISTS userapi_devices (
|
||||||
access_token TEXT PRIMARY KEY,
|
access_token TEXT PRIMARY KEY,
|
||||||
session_id INTEGER,
|
session_id INTEGER,
|
||||||
device_id TEXT ,
|
device_id TEXT ,
|
||||||
|
@ -47,12 +47,12 @@ CREATE TABLE IF NOT EXISTS device_devices (
|
||||||
UNIQUE (localpart, device_id)
|
UNIQUE (localpart, device_id)
|
||||||
);
|
);
|
||||||
INSERT
|
INSERT
|
||||||
INTO device_devices (
|
INTO userapi_devices (
|
||||||
access_token, session_id, device_id, localpart, created_ts, display_name
|
access_token, session_id, device_id, localpart, created_ts, display_name
|
||||||
) SELECT
|
) SELECT
|
||||||
access_token, session_id, device_id, localpart, created_ts, display_name
|
access_token, session_id, device_id, localpart, created_ts, display_name
|
||||||
FROM device_devices_tmp;
|
FROM userapi_devices_tmp;
|
||||||
DROP TABLE device_devices_tmp;`)
|
DROP TABLE userapi_devices_tmp;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
func UpAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
func UpAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
||||||
// initially set every account to useraccount, change appservice and guest accounts afterwards
|
// initially set every account to useraccount, change appservice and guest accounts afterwards
|
||||||
// (user = 1, guest = 2, admin = 3, appservice = 4)
|
// (user = 1, guest = 2, admin = 3, appservice = 4)
|
||||||
_, err := tx.ExecContext(ctx, `ALTER TABLE account_accounts RENAME TO account_accounts_tmp;
|
_, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts RENAME TO userapi_accounts_tmp;
|
||||||
CREATE TABLE account_accounts (
|
CREATE TABLE userapi_accounts (
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
created_ts BIGINT NOT NULL,
|
created_ts BIGINT NOT NULL,
|
||||||
password_hash TEXT,
|
password_hash TEXT,
|
||||||
|
@ -19,15 +19,15 @@ CREATE TABLE account_accounts (
|
||||||
account_type INTEGER NOT NULL
|
account_type INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
INSERT
|
INSERT
|
||||||
INTO account_accounts (
|
INTO userapi_accounts (
|
||||||
localpart, created_ts, password_hash, appservice_id, account_type
|
localpart, created_ts, password_hash, appservice_id, account_type
|
||||||
) SELECT
|
) SELECT
|
||||||
localpart, created_ts, password_hash, appservice_id, 1
|
localpart, created_ts, password_hash, appservice_id, 1
|
||||||
FROM account_accounts_tmp
|
FROM userapi_accounts_tmp
|
||||||
;
|
;
|
||||||
UPDATE account_accounts SET account_type = 4 WHERE appservice_id <> '';
|
UPDATE userapi_accounts SET account_type = 4 WHERE appservice_id <> '';
|
||||||
UPDATE account_accounts SET account_type = 2 WHERE localpart GLOB '[0-9]*';
|
UPDATE userapi_accounts SET account_type = 2 WHERE localpart GLOB '[0-9]*';
|
||||||
DROP TABLE account_accounts_tmp;`)
|
DROP TABLE userapi_accounts_tmp;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to add column: %w", err)
|
return fmt.Errorf("failed to add column: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ DROP TABLE account_accounts_tmp;`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
func DownAddAccountType(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.ExecContext(ctx, `ALTER TABLE account_accounts DROP COLUMN account_type;`)
|
_, err := tx.ExecContext(ctx, `ALTER TABLE userapi_accounts DROP COLUMN account_type;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
109
userapi/storage/sqlite3/deltas/2022101711000000_rename_tables.go
Normal file
109
userapi/storage/sqlite3/deltas/2022101711000000_rename_tables.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package deltas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var renameTableMappings = map[string]string{
|
||||||
|
"account_accounts": "userapi_accounts",
|
||||||
|
"account_data": "userapi_account_datas",
|
||||||
|
"device_devices": "userapi_devices",
|
||||||
|
"account_e2e_room_keys": "userapi_key_backups",
|
||||||
|
"account_e2e_room_keys_versions": "userapi_key_backup_versions",
|
||||||
|
"login_tokens": "userapi_login_tokens",
|
||||||
|
"open_id_tokens": "userapi_openid_tokens",
|
||||||
|
"account_profiles": "userapi_profiles",
|
||||||
|
"account_threepid": "userapi_threepids",
|
||||||
|
}
|
||||||
|
|
||||||
|
var renameIndicesMappings = map[string]string{
|
||||||
|
"device_localpart_id_idx": "userapi_device_localpart_id_idx",
|
||||||
|
"e2e_room_keys_idx": "userapi_key_backups_idx",
|
||||||
|
"e2e_room_keys_versions_idx": "userapi_key_backups_versions_idx",
|
||||||
|
"account_e2e_room_keys_versions_idx": "userapi_key_backup_versions_idx",
|
||||||
|
"login_tokens_expiration_idx": "userapi_login_tokens_expiration_idx",
|
||||||
|
"account_threepid_localpart": "userapi_threepid_idx",
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpRenameTables(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
for old, new := range renameTableMappings {
|
||||||
|
// SQLite has no "IF EXISTS" so check if the table exists.
|
||||||
|
var name string
|
||||||
|
if err := tx.QueryRowContext(
|
||||||
|
ctx, "SELECT name FROM sqlite_schema WHERE type = 'table' AND name = $1;", old,
|
||||||
|
).Scan(&name); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER TABLE %s RENAME TO %s;", old, new,
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameIndicesMappings {
|
||||||
|
var query string
|
||||||
|
if err := tx.QueryRowContext(
|
||||||
|
ctx, "SELECT sql FROM sqlite_schema WHERE type = 'index' AND name = $1;", old,
|
||||||
|
).Scan(&query); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
query = strings.Replace(query, old, new, 1)
|
||||||
|
if _, err := tx.ExecContext(ctx, fmt.Sprintf("DROP INDEX %s;", old)); err != nil {
|
||||||
|
return fmt.Errorf("drop index %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
if _, err := tx.ExecContext(ctx, query); err != nil {
|
||||||
|
return fmt.Errorf("recreate index %q to %q error: %w", old, new, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownRenameTables(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
for old, new := range renameTableMappings {
|
||||||
|
// SQLite has no "IF EXISTS" so check if the table exists.
|
||||||
|
var name string
|
||||||
|
if err := tx.QueryRowContext(
|
||||||
|
ctx, "SELECT name FROM sqlite_schema WHERE type = 'table' AND name = $1;", new,
|
||||||
|
).Scan(&name); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
q := fmt.Sprintf(
|
||||||
|
"ALTER TABLE %s RENAME TO %s;", new, old,
|
||||||
|
)
|
||||||
|
if _, err := tx.ExecContext(ctx, q); err != nil {
|
||||||
|
return fmt.Errorf("rename table %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for old, new := range renameIndicesMappings {
|
||||||
|
var query string
|
||||||
|
if err := tx.QueryRowContext(
|
||||||
|
ctx, "SELECT sql FROM sqlite_schema WHERE type = 'index' AND name = $1;", new,
|
||||||
|
).Scan(&query); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
query = strings.Replace(query, new, old, 1)
|
||||||
|
if _, err := tx.ExecContext(ctx, fmt.Sprintf("DROP INDEX %s;", new)); err != nil {
|
||||||
|
return fmt.Errorf("drop index %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
if _, err := tx.ExecContext(ctx, query); err != nil {
|
||||||
|
return fmt.Errorf("recreate index %q to %q error: %w", new, old, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ const devicesSchema = `
|
||||||
-- CREATE SEQUENCE IF NOT EXISTS device_session_id_seq START 1;
|
-- CREATE SEQUENCE IF NOT EXISTS device_session_id_seq START 1;
|
||||||
|
|
||||||
-- Stores data about devices.
|
-- Stores data about devices.
|
||||||
CREATE TABLE IF NOT EXISTS device_devices (
|
CREATE TABLE IF NOT EXISTS userapi_devices (
|
||||||
access_token TEXT PRIMARY KEY,
|
access_token TEXT PRIMARY KEY,
|
||||||
session_id INTEGER,
|
session_id INTEGER,
|
||||||
device_id TEXT ,
|
device_id TEXT ,
|
||||||
|
@ -51,38 +51,38 @@ CREATE TABLE IF NOT EXISTS device_devices (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertDeviceSQL = "" +
|
const insertDeviceSQL = "" +
|
||||||
"INSERT INTO device_devices (device_id, localpart, access_token, created_ts, display_name, session_id, last_seen_ts, ip, user_agent)" +
|
"INSERT INTO userapi_devices (device_id, localpart, access_token, created_ts, display_name, session_id, last_seen_ts, ip, user_agent)" +
|
||||||
" VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"
|
" VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"
|
||||||
|
|
||||||
const selectDevicesCountSQL = "" +
|
const selectDevicesCountSQL = "" +
|
||||||
"SELECT COUNT(access_token) FROM device_devices"
|
"SELECT COUNT(access_token) FROM userapi_devices"
|
||||||
|
|
||||||
const selectDeviceByTokenSQL = "" +
|
const selectDeviceByTokenSQL = "" +
|
||||||
"SELECT session_id, device_id, localpart FROM device_devices WHERE access_token = $1"
|
"SELECT session_id, device_id, localpart FROM userapi_devices WHERE access_token = $1"
|
||||||
|
|
||||||
const selectDeviceByIDSQL = "" +
|
const selectDeviceByIDSQL = "" +
|
||||||
"SELECT display_name, last_seen_ts, ip FROM device_devices WHERE localpart = $1 and device_id = $2"
|
"SELECT display_name, last_seen_ts, ip FROM userapi_devices WHERE localpart = $1 and device_id = $2"
|
||||||
|
|
||||||
const selectDevicesByLocalpartSQL = "" +
|
const selectDevicesByLocalpartSQL = "" +
|
||||||
"SELECT device_id, display_name, last_seen_ts, ip, user_agent FROM device_devices WHERE localpart = $1 AND device_id != $2 ORDER BY last_seen_ts DESC"
|
"SELECT device_id, display_name, last_seen_ts, ip, user_agent FROM userapi_devices WHERE localpart = $1 AND device_id != $2 ORDER BY last_seen_ts DESC"
|
||||||
|
|
||||||
const updateDeviceNameSQL = "" +
|
const updateDeviceNameSQL = "" +
|
||||||
"UPDATE device_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
"UPDATE userapi_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
||||||
|
|
||||||
const deleteDeviceSQL = "" +
|
const deleteDeviceSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE device_id = $1 AND localpart = $2"
|
"DELETE FROM userapi_devices WHERE device_id = $1 AND localpart = $2"
|
||||||
|
|
||||||
const deleteDevicesByLocalpartSQL = "" +
|
const deleteDevicesByLocalpartSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE localpart = $1 AND device_id != $2"
|
"DELETE FROM userapi_devices WHERE localpart = $1 AND device_id != $2"
|
||||||
|
|
||||||
const deleteDevicesSQL = "" +
|
const deleteDevicesSQL = "" +
|
||||||
"DELETE FROM device_devices WHERE localpart = $1 AND device_id IN ($2)"
|
"DELETE FROM userapi_devices WHERE localpart = $1 AND device_id IN ($2)"
|
||||||
|
|
||||||
const selectDevicesByIDSQL = "" +
|
const selectDevicesByIDSQL = "" +
|
||||||
"SELECT device_id, localpart, display_name, last_seen_ts FROM device_devices WHERE device_id IN ($1) ORDER BY last_seen_ts DESC"
|
"SELECT device_id, localpart, display_name, last_seen_ts FROM userapi_devices WHERE device_id IN ($1) ORDER BY last_seen_ts DESC"
|
||||||
|
|
||||||
const updateDeviceLastSeen = "" +
|
const updateDeviceLastSeen = "" +
|
||||||
"UPDATE device_devices SET last_seen_ts = $1, ip = $2, user_agent = $3 WHERE localpart = $4 AND device_id = $5"
|
"UPDATE userapi_devices SET last_seen_ts = $1, ip = $2, user_agent = $3 WHERE localpart = $4 AND device_id = $5"
|
||||||
|
|
||||||
type devicesStatements struct {
|
type devicesStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const keyBackupTableSchema = `
|
const keyBackupTableSchema = `
|
||||||
CREATE TABLE IF NOT EXISTS account_e2e_room_keys (
|
CREATE TABLE IF NOT EXISTS userapi_key_backups (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
room_id TEXT NOT NULL,
|
room_id TEXT NOT NULL,
|
||||||
session_id TEXT NOT NULL,
|
session_id TEXT NOT NULL,
|
||||||
|
@ -37,31 +37,31 @@ CREATE TABLE IF NOT EXISTS account_e2e_room_keys (
|
||||||
is_verified BOOLEAN NOT NULL,
|
is_verified BOOLEAN NOT NULL,
|
||||||
session_data TEXT NOT NULL
|
session_data TEXT NOT NULL
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS e2e_room_keys_idx ON account_e2e_room_keys(user_id, room_id, session_id, version);
|
CREATE UNIQUE INDEX IF NOT EXISTS e2e_room_keys_idx ON userapi_key_backups(user_id, room_id, session_id, version);
|
||||||
CREATE INDEX IF NOT EXISTS e2e_room_keys_versions_idx ON account_e2e_room_keys(user_id, version);
|
CREATE INDEX IF NOT EXISTS e2e_room_keys_versions_idx ON userapi_key_backups(user_id, version);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertBackupKeySQL = "" +
|
const insertBackupKeySQL = "" +
|
||||||
"INSERT INTO account_e2e_room_keys(user_id, room_id, session_id, version, first_message_index, forwarded_count, is_verified, session_data) " +
|
"INSERT INTO userapi_key_backups(user_id, room_id, session_id, version, first_message_index, forwarded_count, is_verified, session_data) " +
|
||||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
||||||
|
|
||||||
const updateBackupKeySQL = "" +
|
const updateBackupKeySQL = "" +
|
||||||
"UPDATE account_e2e_room_keys SET first_message_index=$1, forwarded_count=$2, is_verified=$3, session_data=$4 " +
|
"UPDATE userapi_key_backups SET first_message_index=$1, forwarded_count=$2, is_verified=$3, session_data=$4 " +
|
||||||
"WHERE user_id=$5 AND room_id=$6 AND session_id=$7 AND version=$8"
|
"WHERE user_id=$5 AND room_id=$6 AND session_id=$7 AND version=$8"
|
||||||
|
|
||||||
const countKeysSQL = "" +
|
const countKeysSQL = "" +
|
||||||
"SELECT COUNT(*) FROM account_e2e_room_keys WHERE user_id = $1 AND version = $2"
|
"SELECT COUNT(*) FROM userapi_key_backups WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeysSQL = "" +
|
const selectKeysSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2"
|
"WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeysByRoomIDSQL = "" +
|
const selectKeysByRoomIDSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2 AND room_id = $3"
|
"WHERE user_id = $1 AND version = $2 AND room_id = $3"
|
||||||
|
|
||||||
const selectKeysByRoomIDAndSessionIDSQL = "" +
|
const selectKeysByRoomIDAndSessionIDSQL = "" +
|
||||||
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM account_e2e_room_keys " +
|
"SELECT room_id, session_id, first_message_index, forwarded_count, is_verified, session_data FROM userapi_key_backups " +
|
||||||
"WHERE user_id = $1 AND version = $2 AND room_id = $3 AND session_id = $4"
|
"WHERE user_id = $1 AND version = $2 AND room_id = $3 AND session_id = $4"
|
||||||
|
|
||||||
type keyBackupStatements struct {
|
type keyBackupStatements struct {
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
|
|
||||||
const keyBackupVersionTableSchema = `
|
const keyBackupVersionTableSchema = `
|
||||||
-- the metadata for each generation of encrypted e2e session backups
|
-- the metadata for each generation of encrypted e2e session backups
|
||||||
CREATE TABLE IF NOT EXISTS account_e2e_room_keys_versions (
|
CREATE TABLE IF NOT EXISTS userapi_key_backup_versions (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
-- this means no 2 users will ever have the same version of e2e session backups which strictly
|
-- this means no 2 users will ever have the same version of e2e session backups which strictly
|
||||||
-- isn't necessary, but this is easy to do rather than SELECT MAX(version)+1.
|
-- isn't necessary, but this is easy to do rather than SELECT MAX(version)+1.
|
||||||
|
@ -38,26 +38,26 @@ CREATE TABLE IF NOT EXISTS account_e2e_room_keys_versions (
|
||||||
deleted INTEGER DEFAULT 0 NOT NULL
|
deleted INTEGER DEFAULT 0 NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS account_e2e_room_keys_versions_idx ON account_e2e_room_keys_versions(user_id, version);
|
CREATE UNIQUE INDEX IF NOT EXISTS userapi_key_backup_versions_idx ON userapi_key_backup_versions(user_id, version);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertKeyBackupSQL = "" +
|
const insertKeyBackupSQL = "" +
|
||||||
"INSERT INTO account_e2e_room_keys_versions(user_id, algorithm, auth_data, etag) VALUES ($1, $2, $3, $4) RETURNING version"
|
"INSERT INTO userapi_key_backup_versions(user_id, algorithm, auth_data, etag) VALUES ($1, $2, $3, $4) RETURNING version"
|
||||||
|
|
||||||
const updateKeyBackupAuthDataSQL = "" +
|
const updateKeyBackupAuthDataSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET auth_data = $1 WHERE user_id = $2 AND version = $3"
|
"UPDATE userapi_key_backup_versions SET auth_data = $1 WHERE user_id = $2 AND version = $3"
|
||||||
|
|
||||||
const updateKeyBackupETagSQL = "" +
|
const updateKeyBackupETagSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET etag = $1 WHERE user_id = $2 AND version = $3"
|
"UPDATE userapi_key_backup_versions SET etag = $1 WHERE user_id = $2 AND version = $3"
|
||||||
|
|
||||||
const deleteKeyBackupSQL = "" +
|
const deleteKeyBackupSQL = "" +
|
||||||
"UPDATE account_e2e_room_keys_versions SET deleted=1 WHERE user_id = $1 AND version = $2"
|
"UPDATE userapi_key_backup_versions SET deleted=1 WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectKeyBackupSQL = "" +
|
const selectKeyBackupSQL = "" +
|
||||||
"SELECT algorithm, auth_data, etag, deleted FROM account_e2e_room_keys_versions WHERE user_id = $1 AND version = $2"
|
"SELECT algorithm, auth_data, etag, deleted FROM userapi_key_backup_versions WHERE user_id = $1 AND version = $2"
|
||||||
|
|
||||||
const selectLatestVersionSQL = "" +
|
const selectLatestVersionSQL = "" +
|
||||||
"SELECT MAX(version) FROM account_e2e_room_keys_versions WHERE user_id = $1"
|
"SELECT MAX(version) FROM userapi_key_backup_versions WHERE user_id = $1"
|
||||||
|
|
||||||
type keyBackupVersionStatements struct {
|
type keyBackupVersionStatements struct {
|
||||||
insertKeyBackupStmt *sql.Stmt
|
insertKeyBackupStmt *sql.Stmt
|
||||||
|
|
|
@ -32,7 +32,7 @@ type loginTokenStatements struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginTokenSchema = `
|
const loginTokenSchema = `
|
||||||
CREATE TABLE IF NOT EXISTS login_tokens (
|
CREATE TABLE IF NOT EXISTS userapi_login_tokens (
|
||||||
-- The random value of the token issued to a user
|
-- The random value of the token issued to a user
|
||||||
token TEXT NOT NULL PRIMARY KEY,
|
token TEXT NOT NULL PRIMARY KEY,
|
||||||
-- When the token expires
|
-- When the token expires
|
||||||
|
@ -43,17 +43,17 @@ CREATE TABLE IF NOT EXISTS login_tokens (
|
||||||
);
|
);
|
||||||
|
|
||||||
-- This index allows efficient garbage collection of expired tokens.
|
-- This index allows efficient garbage collection of expired tokens.
|
||||||
CREATE INDEX IF NOT EXISTS login_tokens_expiration_idx ON login_tokens(token_expires_at);
|
CREATE INDEX IF NOT EXISTS login_tokens_expiration_idx ON userapi_login_tokens(token_expires_at);
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertLoginTokenSQL = "" +
|
const insertLoginTokenSQL = "" +
|
||||||
"INSERT INTO login_tokens(token, token_expires_at, user_id) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_login_tokens(token, token_expires_at, user_id) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const deleteLoginTokenSQL = "" +
|
const deleteLoginTokenSQL = "" +
|
||||||
"DELETE FROM login_tokens WHERE token = $1 OR token_expires_at <= $2"
|
"DELETE FROM userapi_login_tokens WHERE token = $1 OR token_expires_at <= $2"
|
||||||
|
|
||||||
const selectLoginTokenSQL = "" +
|
const selectLoginTokenSQL = "" +
|
||||||
"SELECT user_id FROM login_tokens WHERE token = $1 AND token_expires_at > $2"
|
"SELECT user_id FROM userapi_login_tokens WHERE token = $1 AND token_expires_at > $2"
|
||||||
|
|
||||||
func NewSQLiteLoginTokenTable(db *sql.DB) (tables.LoginTokenTable, error) {
|
func NewSQLiteLoginTokenTable(db *sql.DB) (tables.LoginTokenTable, error) {
|
||||||
s := &loginTokenStatements{}
|
s := &loginTokenStatements{}
|
||||||
|
@ -78,7 +78,7 @@ func (s *loginTokenStatements) InsertLoginToken(ctx context.Context, txn *sql.Tx
|
||||||
// deleteByToken removes the named token.
|
// deleteByToken removes the named token.
|
||||||
//
|
//
|
||||||
// As a simple way to garbage-collect stale tokens, we also remove all expired tokens.
|
// As a simple way to garbage-collect stale tokens, we also remove all expired tokens.
|
||||||
// The login_tokens_expiration_idx index should make that efficient.
|
// The userapi_login_tokens_expiration_idx index should make that efficient.
|
||||||
func (s *loginTokenStatements) DeleteLoginToken(ctx context.Context, txn *sql.Tx, token string) error {
|
func (s *loginTokenStatements) DeleteLoginToken(ctx context.Context, txn *sql.Tx, token string) error {
|
||||||
stmt := sqlutil.TxStmt(txn, s.deleteStmt)
|
stmt := sqlutil.TxStmt(txn, s.deleteStmt)
|
||||||
res, err := stmt.ExecContext(ctx, token, time.Now().UTC())
|
res, err := stmt.ExecContext(ctx, token, time.Now().UTC())
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
const openIDTokenSchema = `
|
const openIDTokenSchema = `
|
||||||
-- Stores data about accounts.
|
-- Stores data about accounts.
|
||||||
CREATE TABLE IF NOT EXISTS open_id_tokens (
|
CREATE TABLE IF NOT EXISTS userapi_openid_tokens (
|
||||||
-- The value of the token issued to a user
|
-- The value of the token issued to a user
|
||||||
token TEXT NOT NULL PRIMARY KEY,
|
token TEXT NOT NULL PRIMARY KEY,
|
||||||
-- The Matrix user ID for this account
|
-- The Matrix user ID for this account
|
||||||
|
@ -24,10 +24,10 @@ CREATE TABLE IF NOT EXISTS open_id_tokens (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertOpenIDTokenSQL = "" +
|
const insertOpenIDTokenSQL = "" +
|
||||||
"INSERT INTO open_id_tokens(token, localpart, token_expires_at_ms) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_openid_tokens(token, localpart, token_expires_at_ms) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const selectOpenIDTokenSQL = "" +
|
const selectOpenIDTokenSQL = "" +
|
||||||
"SELECT localpart, token_expires_at_ms FROM open_id_tokens WHERE token = $1"
|
"SELECT localpart, token_expires_at_ms FROM userapi_openid_tokens WHERE token = $1"
|
||||||
|
|
||||||
type openIDTokenStatements struct {
|
type openIDTokenStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
|
|
||||||
const profilesSchema = `
|
const profilesSchema = `
|
||||||
-- Stores data about accounts profiles.
|
-- Stores data about accounts profiles.
|
||||||
CREATE TABLE IF NOT EXISTS account_profiles (
|
CREATE TABLE IF NOT EXISTS userapi_profiles (
|
||||||
-- The Matrix user ID localpart for this account
|
-- The Matrix user ID localpart for this account
|
||||||
localpart TEXT NOT NULL PRIMARY KEY,
|
localpart TEXT NOT NULL PRIMARY KEY,
|
||||||
-- The display name for this account
|
-- The display name for this account
|
||||||
|
@ -38,19 +38,19 @@ CREATE TABLE IF NOT EXISTS account_profiles (
|
||||||
`
|
`
|
||||||
|
|
||||||
const insertProfileSQL = "" +
|
const insertProfileSQL = "" +
|
||||||
"INSERT INTO account_profiles(localpart, display_name, avatar_url) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_profiles(localpart, display_name, avatar_url) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const selectProfileByLocalpartSQL = "" +
|
const selectProfileByLocalpartSQL = "" +
|
||||||
"SELECT localpart, display_name, avatar_url FROM account_profiles WHERE localpart = $1"
|
"SELECT localpart, display_name, avatar_url FROM userapi_profiles WHERE localpart = $1"
|
||||||
|
|
||||||
const setAvatarURLSQL = "" +
|
const setAvatarURLSQL = "" +
|
||||||
"UPDATE account_profiles SET avatar_url = $1 WHERE localpart = $2"
|
"UPDATE userapi_profiles SET avatar_url = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const setDisplayNameSQL = "" +
|
const setDisplayNameSQL = "" +
|
||||||
"UPDATE account_profiles SET display_name = $1 WHERE localpart = $2"
|
"UPDATE userapi_profiles SET display_name = $1 WHERE localpart = $2"
|
||||||
|
|
||||||
const selectProfilesBySearchSQL = "" +
|
const selectProfilesBySearchSQL = "" +
|
||||||
"SELECT localpart, display_name, avatar_url FROM account_profiles WHERE localpart LIKE $1 OR display_name LIKE $1 LIMIT $2"
|
"SELECT localpart, display_name, avatar_url FROM userapi_profiles WHERE localpart LIKE $1 OR display_name LIKE $1 LIMIT $2"
|
||||||
|
|
||||||
type profilesStatements struct {
|
type profilesStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -46,7 +46,7 @@ CREATE INDEX IF NOT EXISTS userapi_daily_visits_localpart_timestamp_idx ON usera
|
||||||
|
|
||||||
const countUsersLastSeenAfterSQL = "" +
|
const countUsersLastSeenAfterSQL = "" +
|
||||||
"SELECT COUNT(*) FROM (" +
|
"SELECT COUNT(*) FROM (" +
|
||||||
" SELECT localpart FROM device_devices WHERE last_seen_ts > $1 " +
|
" SELECT localpart FROM userapi_devices WHERE last_seen_ts > $1 " +
|
||||||
" GROUP BY localpart" +
|
" GROUP BY localpart" +
|
||||||
" ) u"
|
" ) u"
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ R30Users counts the number of 30 day retained users, defined as:
|
||||||
const countR30UsersSQL = `
|
const countR30UsersSQL = `
|
||||||
SELECT platform, COUNT(*) FROM (
|
SELECT platform, COUNT(*) FROM (
|
||||||
SELECT users.localpart, platform, users.created_ts, MAX(uip.last_seen_ts)
|
SELECT users.localpart, platform, users.created_ts, MAX(uip.last_seen_ts)
|
||||||
FROM account_accounts users
|
FROM userapi_accounts users
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
(SELECT
|
(SELECT
|
||||||
localpart, last_seen_ts,
|
localpart, last_seen_ts,
|
||||||
|
@ -76,7 +76,7 @@ SELECT platform, COUNT(*) FROM (
|
||||||
ELSE 'unknown'
|
ELSE 'unknown'
|
||||||
END
|
END
|
||||||
AS platform
|
AS platform
|
||||||
FROM device_devices
|
FROM userapi_devices
|
||||||
) uip
|
) uip
|
||||||
ON users.localpart = uip.localpart
|
ON users.localpart = uip.localpart
|
||||||
AND users.account_type <> 4
|
AND users.account_type <> 4
|
||||||
|
@ -126,7 +126,7 @@ GROUP BY client_type
|
||||||
`
|
`
|
||||||
|
|
||||||
const countUserByAccountTypeSQL = `
|
const countUserByAccountTypeSQL = `
|
||||||
SELECT COUNT(*) FROM account_accounts WHERE account_type IN ($1)
|
SELECT COUNT(*) FROM userapi_accounts WHERE account_type IN ($1)
|
||||||
`
|
`
|
||||||
|
|
||||||
// $1 = Guest AccountType
|
// $1 = Guest AccountType
|
||||||
|
@ -139,7 +139,7 @@ SELECT user_type, COUNT(*) AS count FROM (
|
||||||
WHEN account_type = $4 AND appservice_id IS NULL THEN 'guest'
|
WHEN account_type = $4 AND appservice_id IS NULL THEN 'guest'
|
||||||
WHEN account_type IN ($5) AND appservice_id IS NOT NULL THEN 'bridged'
|
WHEN account_type IN ($5) AND appservice_id IS NOT NULL THEN 'bridged'
|
||||||
END AS user_type
|
END AS user_type
|
||||||
FROM account_accounts
|
FROM userapi_accounts
|
||||||
WHERE created_ts > $8
|
WHERE created_ts > $8
|
||||||
) AS t GROUP BY user_type
|
) AS t GROUP BY user_type
|
||||||
`
|
`
|
||||||
|
@ -148,14 +148,14 @@ SELECT user_type, COUNT(*) AS count FROM (
|
||||||
const updateUserDailyVisitsSQL = `
|
const updateUserDailyVisitsSQL = `
|
||||||
INSERT INTO userapi_daily_visits(localpart, device_id, timestamp, user_agent)
|
INSERT INTO userapi_daily_visits(localpart, device_id, timestamp, user_agent)
|
||||||
SELECT u.localpart, u.device_id, $1, MAX(u.user_agent)
|
SELECT u.localpart, u.device_id, $1, MAX(u.user_agent)
|
||||||
FROM device_devices AS u
|
FROM userapi_devices AS u
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT localpart, device_id, timestamp FROM userapi_daily_visits
|
SELECT localpart, device_id, timestamp FROM userapi_daily_visits
|
||||||
WHERE timestamp = $1
|
WHERE timestamp = $1
|
||||||
) udv
|
) udv
|
||||||
ON u.localpart = udv.localpart AND u.device_id = udv.device_id
|
ON u.localpart = udv.localpart AND u.device_id = udv.device_id
|
||||||
INNER JOIN device_devices d ON d.localpart = u.localpart
|
INNER JOIN userapi_devices d ON d.localpart = u.localpart
|
||||||
INNER JOIN account_accounts a ON a.localpart = u.localpart
|
INNER JOIN userapi_accounts a ON a.localpart = u.localpart
|
||||||
WHERE $2 <= d.last_seen_ts AND d.last_seen_ts < $3
|
WHERE $2 <= d.last_seen_ts AND d.last_seen_ts < $3
|
||||||
AND a.account_type in (1, 3)
|
AND a.account_type in (1, 3)
|
||||||
GROUP BY u.localpart, u.device_id
|
GROUP BY u.localpart, u.device_id
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/userapi/storage/shared"
|
"github.com/matrix-org/dendrite/userapi/storage/shared"
|
||||||
|
"github.com/matrix-org/dendrite/userapi/storage/sqlite3/deltas"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDatabase creates a new accounts and profiles database
|
// NewDatabase creates a new accounts and profiles database
|
||||||
|
@ -34,6 +35,16 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "userapi: rename tables",
|
||||||
|
Up: deltas.UpRenameTables,
|
||||||
|
Down: deltas.DownRenameTables,
|
||||||
|
})
|
||||||
|
if err = m.Up(base.Context()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
accountDataTable, err := NewSQLiteAccountDataTable(db)
|
accountDataTable, err := NewSQLiteAccountDataTable(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewSQLiteAccountDataTable: %w", err)
|
return nil, fmt.Errorf("NewSQLiteAccountDataTable: %w", err)
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
|
|
||||||
const threepidSchema = `
|
const threepidSchema = `
|
||||||
-- Stores data about third party identifiers
|
-- Stores data about third party identifiers
|
||||||
CREATE TABLE IF NOT EXISTS account_threepid (
|
CREATE TABLE IF NOT EXISTS userapi_threepids (
|
||||||
-- The third party identifier
|
-- The third party identifier
|
||||||
threepid TEXT NOT NULL,
|
threepid TEXT NOT NULL,
|
||||||
-- The 3PID medium
|
-- The 3PID medium
|
||||||
|
@ -38,20 +38,20 @@ CREATE TABLE IF NOT EXISTS account_threepid (
|
||||||
PRIMARY KEY(threepid, medium)
|
PRIMARY KEY(threepid, medium)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS account_threepid_localpart ON account_threepid(localpart);
|
CREATE INDEX IF NOT EXISTS account_threepid_localpart ON userapi_threepids(localpart);
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectLocalpartForThreePIDSQL = "" +
|
const selectLocalpartForThreePIDSQL = "" +
|
||||||
"SELECT localpart FROM account_threepid WHERE threepid = $1 AND medium = $2"
|
"SELECT localpart FROM userapi_threepids WHERE threepid = $1 AND medium = $2"
|
||||||
|
|
||||||
const selectThreePIDsForLocalpartSQL = "" +
|
const selectThreePIDsForLocalpartSQL = "" +
|
||||||
"SELECT threepid, medium FROM account_threepid WHERE localpart = $1"
|
"SELECT threepid, medium FROM userapi_threepids WHERE localpart = $1"
|
||||||
|
|
||||||
const insertThreePIDSQL = "" +
|
const insertThreePIDSQL = "" +
|
||||||
"INSERT INTO account_threepid (threepid, medium, localpart) VALUES ($1, $2, $3)"
|
"INSERT INTO userapi_threepids (threepid, medium, localpart) VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
const deleteThreePIDSQL = "" +
|
const deleteThreePIDSQL = "" +
|
||||||
"DELETE FROM account_threepid WHERE threepid = $1 AND medium = $2"
|
"DELETE FROM userapi_threepids WHERE threepid = $1 AND medium = $2"
|
||||||
|
|
||||||
type threepidStatements struct {
|
type threepidStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/internal/pushrules"
|
"github.com/matrix-org/dendrite/internal/pushrules"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/dendrite/userapi/storage"
|
"github.com/matrix-org/dendrite/userapi/storage"
|
||||||
"github.com/matrix-org/dendrite/userapi/storage/tables"
|
"github.com/matrix-org/dendrite/userapi/storage/tables"
|
||||||
|
@ -29,14 +30,18 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
||||||
|
base, baseclose := testrig.CreateBaseDendrite(t, dbType)
|
||||||
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
||||||
db, err := storage.NewUserAPIDatabase(nil, &config.DatabaseOptions{
|
db, err := storage.NewUserAPIDatabase(base, &config.DatabaseOptions{
|
||||||
ConnectionString: config.DataSource(connStr),
|
ConnectionString: config.DataSource(connStr),
|
||||||
}, "localhost", bcrypt.MinCost, openIDLifetimeMS, loginTokenLifetime, "_server")
|
}, "localhost", bcrypt.MinCost, openIDLifetimeMS, loginTokenLifetime, "_server")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewUserAPIDatabase returned %s", err)
|
t.Fatalf("NewUserAPIDatabase returned %s", err)
|
||||||
}
|
}
|
||||||
return db, close
|
return db, func() {
|
||||||
|
close()
|
||||||
|
baseclose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests storing and getting account data
|
// Tests storing and getting account data
|
||||||
|
|
|
@ -106,7 +106,7 @@ func mustUpdateDeviceLastSeen(
|
||||||
timestamp time.Time,
|
timestamp time.Time,
|
||||||
) {
|
) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
_, err := db.ExecContext(ctx, "UPDATE device_devices SET last_seen_ts = $1 WHERE localpart = $2", gomatrixserverlib.AsTimestamp(timestamp), localpart)
|
_, err := db.ExecContext(ctx, "UPDATE userapi_devices SET last_seen_ts = $1 WHERE localpart = $2", gomatrixserverlib.AsTimestamp(timestamp), localpart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to update device last seen")
|
t.Fatalf("unable to update device last seen")
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func mustUserUpdateRegistered(
|
||||||
localpart string,
|
localpart string,
|
||||||
timestamp time.Time,
|
timestamp time.Time,
|
||||||
) {
|
) {
|
||||||
_, err := db.ExecContext(ctx, "UPDATE account_accounts SET created_ts = $1 WHERE localpart = $2", gomatrixserverlib.AsTimestamp(timestamp), localpart)
|
_, err := db.ExecContext(ctx, "UPDATE userapi_accounts SET created_ts = $1 WHERE localpart = $2", gomatrixserverlib.AsTimestamp(timestamp), localpart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to update device last seen")
|
t.Fatalf("unable to update device last seen")
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/dendrite/userapi"
|
"github.com/matrix-org/dendrite/userapi"
|
||||||
"github.com/matrix-org/dendrite/userapi/inthttp"
|
"github.com/matrix-org/dendrite/userapi/inthttp"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
@ -48,9 +49,9 @@ func MustMakeInternalAPI(t *testing.T, opts apiTestOpts, dbType test.DBType) (ap
|
||||||
if opts.loginTokenLifetime == 0 {
|
if opts.loginTokenLifetime == 0 {
|
||||||
opts.loginTokenLifetime = api.DefaultLoginTokenLifetime * time.Millisecond
|
opts.loginTokenLifetime = api.DefaultLoginTokenLifetime * time.Millisecond
|
||||||
}
|
}
|
||||||
|
base, baseclose := testrig.CreateBaseDendrite(t, dbType)
|
||||||
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
connStr, close := test.PrepareDBConnectionString(t, dbType)
|
||||||
|
accountDB, err := storage.NewUserAPIDatabase(base, &config.DatabaseOptions{
|
||||||
accountDB, err := storage.NewUserAPIDatabase(nil, &config.DatabaseOptions{
|
|
||||||
ConnectionString: config.DataSource(connStr),
|
ConnectionString: config.DataSource(connStr),
|
||||||
}, serverName, bcrypt.MinCost, config.DefaultOpenIDTokenLifetimeMS, opts.loginTokenLifetime, "")
|
}, serverName, bcrypt.MinCost, config.DefaultOpenIDTokenLifetimeMS, opts.loginTokenLifetime, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -64,9 +65,12 @@ func MustMakeInternalAPI(t *testing.T, opts apiTestOpts, dbType test.DBType) (ap
|
||||||
}
|
}
|
||||||
|
|
||||||
return &internal.UserInternalAPI{
|
return &internal.UserInternalAPI{
|
||||||
DB: accountDB,
|
DB: accountDB,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
ServerName: cfg.Matrix.ServerName,
|
||||||
}, accountDB, close
|
}, accountDB, func() {
|
||||||
|
close()
|
||||||
|
baseclose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryProfile(t *testing.T) {
|
func TestQueryProfile(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue