mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-04-17 12:28:32 -04:00
153 lines
4.6 KiB
Go
153 lines
4.6 KiB
Go
package user
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
)
|
|
|
|
// Initial PostgreSQL schema
|
|
const (
|
|
postgresCreateTablesQueries = `
|
|
CREATE TABLE IF NOT EXISTS tier (
|
|
id TEXT PRIMARY KEY,
|
|
code TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
messages_limit BIGINT NOT NULL,
|
|
messages_expiry_duration BIGINT NOT NULL,
|
|
emails_limit BIGINT NOT NULL,
|
|
calls_limit BIGINT NOT NULL,
|
|
reservations_limit BIGINT NOT NULL,
|
|
attachment_file_size_limit BIGINT NOT NULL,
|
|
attachment_total_size_limit BIGINT NOT NULL,
|
|
attachment_expiry_duration BIGINT NOT NULL,
|
|
attachment_bandwidth_limit BIGINT NOT NULL,
|
|
stripe_monthly_price_id TEXT,
|
|
stripe_yearly_price_id TEXT,
|
|
UNIQUE(code),
|
|
UNIQUE(stripe_monthly_price_id),
|
|
UNIQUE(stripe_yearly_price_id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS "user" (
|
|
id TEXT PRIMARY KEY,
|
|
tier_id TEXT REFERENCES tier(id),
|
|
user_name TEXT NOT NULL UNIQUE,
|
|
pass TEXT NOT NULL,
|
|
role TEXT NOT NULL CHECK (role IN ('anonymous', 'admin', 'user')),
|
|
prefs JSONB NOT NULL DEFAULT '{}',
|
|
sync_topic TEXT NOT NULL,
|
|
provisioned BOOLEAN NOT NULL,
|
|
stats_messages BIGINT NOT NULL DEFAULT 0,
|
|
stats_emails BIGINT NOT NULL DEFAULT 0,
|
|
stats_calls BIGINT NOT NULL DEFAULT 0,
|
|
stripe_customer_id TEXT UNIQUE,
|
|
stripe_subscription_id TEXT UNIQUE,
|
|
stripe_subscription_status TEXT,
|
|
stripe_subscription_interval TEXT,
|
|
stripe_subscription_paid_until BIGINT,
|
|
stripe_subscription_cancel_at BIGINT,
|
|
created BIGINT NOT NULL,
|
|
deleted BIGINT
|
|
);
|
|
CREATE TABLE IF NOT EXISTS user_access (
|
|
user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
topic TEXT NOT NULL,
|
|
read BOOLEAN NOT NULL,
|
|
write BOOLEAN NOT NULL,
|
|
owner_user_id TEXT REFERENCES "user"(id) ON DELETE CASCADE,
|
|
provisioned BOOLEAN NOT NULL,
|
|
PRIMARY KEY (user_id, topic)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS user_token (
|
|
user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
token TEXT NOT NULL UNIQUE,
|
|
label TEXT NOT NULL,
|
|
last_access BIGINT NOT NULL,
|
|
last_origin TEXT NOT NULL,
|
|
expires BIGINT NOT NULL,
|
|
provisioned BOOLEAN NOT NULL,
|
|
PRIMARY KEY (user_id, token)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS user_phone (
|
|
user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
phone_number TEXT NOT NULL,
|
|
PRIMARY KEY (user_id, phone_number)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS user_email (
|
|
user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
email TEXT NOT NULL,
|
|
PRIMARY KEY (user_id, email)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
store TEXT PRIMARY KEY,
|
|
version INT NOT NULL
|
|
);
|
|
INSERT INTO "user" (id, user_name, pass, role, sync_topic, provisioned, created)
|
|
VALUES ('` + everyoneID + `', '*', '', 'anonymous', '', false, EXTRACT(EPOCH FROM NOW())::BIGINT)
|
|
ON CONFLICT (id) DO NOTHING;
|
|
`
|
|
)
|
|
|
|
// Schema table management queries for Postgres
|
|
const (
|
|
postgresCurrentSchemaVersion = 7
|
|
postgresSelectSchemaVersionQuery = `SELECT version FROM schema_version WHERE store = 'user'`
|
|
postgresInsertSchemaVersionQuery = `INSERT INTO schema_version (store, version) VALUES ('user', $1)`
|
|
)
|
|
|
|
const (
|
|
postgresMigrate6To7UpdateQueries = `
|
|
CREATE TABLE IF NOT EXISTS user_email (
|
|
user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
email TEXT NOT NULL,
|
|
PRIMARY KEY (user_id, email)
|
|
);
|
|
`
|
|
postgresUpdateSchemaVersionQuery = `UPDATE schema_version SET version = $1 WHERE store = 'user'`
|
|
)
|
|
|
|
var postgresMigrations = map[int]func(db *sql.DB) error{
|
|
6: postgresMigrateFrom6,
|
|
}
|
|
|
|
func setupPostgres(db *sql.DB) error {
|
|
var schemaVersion int
|
|
err := db.QueryRow(postgresSelectSchemaVersionQuery).Scan(&schemaVersion)
|
|
if err != nil {
|
|
return setupNewPostgres(db)
|
|
}
|
|
if schemaVersion == postgresCurrentSchemaVersion {
|
|
return nil
|
|
} else if schemaVersion > postgresCurrentSchemaVersion {
|
|
return fmt.Errorf("unexpected schema version: version %d is higher than current version %d", schemaVersion, postgresCurrentSchemaVersion)
|
|
}
|
|
for i := schemaVersion; i < postgresCurrentSchemaVersion; i++ {
|
|
fn, ok := postgresMigrations[i]
|
|
if !ok {
|
|
return fmt.Errorf("cannot find migration step from schema version %d to %d", i, i+1)
|
|
} else if err := fn(db); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func postgresMigrateFrom6(db *sql.DB) error {
|
|
if _, err := db.Exec(postgresMigrate6To7UpdateQueries); err != nil {
|
|
return err
|
|
}
|
|
if _, err := db.Exec(postgresUpdateSchemaVersionQuery, 7); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setupNewPostgres(db *sql.DB) error {
|
|
if _, err := db.Exec(postgresCreateTablesQueries); err != nil {
|
|
return err
|
|
}
|
|
if _, err := db.Exec(postgresInsertSchemaVersionQuery, postgresCurrentSchemaVersion); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|