5fb7c6cfb0
- On boot, the app now checks if the DB version matches its expected version and refuses to start if there are pending migrations to be run. - The new `--upgrade` flag runs data migrations from the last recorded migration (in the settings table) to the latest one in the binary. - Migrations are DB/arbitrary logic functions in .go files in internal/migrations. - All migration functions are idempotent.
112 lines
4.2 KiB
Go
112 lines
4.2 KiB
Go
package migrations
|
|
|
|
import (
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/knadh/koanf"
|
|
"github.com/knadh/stuffbin"
|
|
)
|
|
|
|
// V0_7_0 performs the DB migrations for v.0.7.0.
|
|
func V0_7_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf) error {
|
|
// Check if the subscriber_status.blocklisted enum value exists. If not,
|
|
// it has to be created (for the change from blacklisted -> blocklisted).
|
|
var bl bool
|
|
if err := db.Get(&bl, `SELECT 'blocklisted' = ANY(ENUM_RANGE(NULL::subscriber_status)::TEXT[])`); err != nil {
|
|
return err
|
|
}
|
|
|
|
// If `blocklist` doesn't exist, add it to the subscriber_status enum,
|
|
// and update existing statuses to this value. Unfortunately, it's not possible
|
|
// to remove the enum value `blacklisted` (until PG10).
|
|
if !bl {
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
if _, err := tx.Exec(`
|
|
-- Change the status column to text.
|
|
ALTER TABLE subscribers ALTER COLUMN status TYPE TEXT;
|
|
|
|
-- Change all statuses from 'blacklisted' to 'blocklisted'.
|
|
UPDATE subscribers SET status='blocklisted' WHERE status='blacklisted';
|
|
|
|
-- Remove the old enum.
|
|
DROP TYPE subscriber_status CASCADE;
|
|
|
|
-- Create new enum with the new values.
|
|
CREATE TYPE subscriber_status AS ENUM ('enabled', 'disabled', 'blocklisted');
|
|
|
|
-- Change the text status column to the new enum.
|
|
ALTER TABLE subscribers ALTER COLUMN status TYPE subscriber_status
|
|
USING (status::subscriber_status);
|
|
`); err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
_, err := db.Exec(`
|
|
ALTER TABLE media DROP COLUMN IF EXISTS width,
|
|
DROP COLUMN IF EXISTS height,
|
|
ADD COLUMN IF NOT EXISTS provider TEXT NOT NULL DEFAULT '';
|
|
|
|
-- 'blacklisted' to 'blocklisted' ENUM rename is not possible (until pg10),
|
|
-- so just add the new value and ignore the old one.
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS settings (
|
|
key TEXT NOT NULL UNIQUE,
|
|
value JSONB NOT NULL DEFAULT '{}',
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_settings_key ON settings(key);
|
|
|
|
-- Insert default settings if the table is empty.
|
|
INSERT INTO settings (key, value) SELECT k, v::JSONB FROM (VALUES
|
|
('app.favicon_url', '""'),
|
|
('app.from_email', '"listmonk <noreply@listmonk.yoursite.com>"'),
|
|
('app.logo_url', '"http://localhost:9000/public/static/logo.png"'),
|
|
('app.concurrency', '10'),
|
|
('app.message_rate', '10'),
|
|
('app.batch_size', '1000'),
|
|
('app.max_send_errors', '1000'),
|
|
('app.notify_emails', '["admin1@mysite.com", "admin2@mysite.com"]'),
|
|
('privacy.allow_blocklist', 'true'),
|
|
('privacy.allow_export', 'true'),
|
|
('privacy.allow_wipe', 'true'),
|
|
('privacy.exportable', '["profile", "subscriptions", "campaign_views", "link_clicks"]'),
|
|
('upload.provider', '"filesystem"'),
|
|
('upload.filesystem.upload_path', '"uploads"'),
|
|
('upload.filesystem.upload_uri', '"/uploads"'),
|
|
('upload.s3.aws_access_key_id', '""'),
|
|
('upload.s3.aws_secret_access_key', '""'),
|
|
('upload.s3.aws_default_region', '"ap-south-b"'),
|
|
('upload.s3.bucket', '""'),
|
|
('upload.s3.bucket_domain', '""'),
|
|
('upload.s3.bucket_path', '"/"'),
|
|
('upload.s3.bucket_type', '"public"'),
|
|
('upload.s3.expiry', '"14d"'),
|
|
('smtp',
|
|
'[{"enabled":true, "host":"smtp.yoursite.com","port":25,"auth_protocol":"cram","username":"username","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_enabled":true,"tls_skip_verify":false,"email_headers":[]},
|
|
{"enabled":false, "host":"smtp2.yoursite.com","port":587,"auth_protocol":"plain","username":"username","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_enabled":false,"tls_skip_verify":false,"email_headers":[]}]'),
|
|
('messengers', '[]')) vals(k, v) WHERE NOT EXISTS(SELECT * FROM settings LIMIT 1);
|
|
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// `provider` in the media table is a new field. If there's provider config available
|
|
// and no provider value exists in the media table, set it.
|
|
prov := ko.String("upload.provider")
|
|
if prov != "" {
|
|
if _, err := db.Exec(`UPDATE media SET provider=$1 WHERE provider=''`, prov); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|