92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
package migrations
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/knadh/koanf/v2"
|
|
"github.com/knadh/stuffbin"
|
|
)
|
|
|
|
func V6_2_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf, lo *log.Logger) error {
|
|
// Add `msg_retry_delay` and `from_addresses` to each SMTP server entry in the `smtp`
|
|
// Idempotent: only updates rows where at least one entry is missing the key.
|
|
if _, err := db.Exec(`
|
|
UPDATE settings
|
|
SET value = (
|
|
SELECT JSONB_AGG(
|
|
JSONB_SET(
|
|
JSONB_SET(
|
|
v,
|
|
'{msg_retry_delay}',
|
|
COALESCE(v->'msg_retry_delay', '"10ms"'::JSONB)
|
|
),
|
|
'{from_addresses}',
|
|
COALESCE(v->'from_addresses', '[]'::JSONB)
|
|
)
|
|
ORDER BY ord
|
|
)
|
|
FROM JSONB_ARRAY_ELEMENTS(value) WITH ORDINALITY AS t(v, ord)
|
|
)
|
|
WHERE key = 'smtp'
|
|
AND EXISTS (
|
|
SELECT 1 FROM JSONB_ARRAY_ELEMENTS(value) AS v
|
|
WHERE NOT (v ? 'msg_retry_delay') OR NOT (v ? 'from_addresses')
|
|
);
|
|
`); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update app language settings that used incorrect locale codes.
|
|
if _, err := db.Exec(`
|
|
UPDATE settings SET value = langs.new_value
|
|
FROM (VALUES
|
|
('"cs-cz"'::JSONB, '"cs"'::JSONB),
|
|
('"jp"'::JSONB, '"ja"'::JSONB),
|
|
('"se"'::JSONB, '"sv"'::JSONB)
|
|
) AS langs(old_value, new_value)
|
|
WHERE key = 'app.lang' AND value = langs.old_value;
|
|
`); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add `bounce.azure` for ACS/Event Grid bounce handling; upsert if the row already exists.
|
|
if _, err := db.Exec(`
|
|
INSERT INTO settings (key, value) VALUES('bounce.azure', '{"enabled": false, "shared_secret": "", "shared_secret_header": ""}')
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = jsonb_build_object(
|
|
'enabled', COALESCE((settings.value->>'enabled')::boolean, false),
|
|
'shared_secret', COALESCE(settings.value->>'shared_secret', ''),
|
|
'shared_secret_header', COALESCE(settings.value->>'shared_secret_header', '')
|
|
);
|
|
`); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := db.Exec(`INSERT INTO settings (key, value) VALUES ('app.show_optin_page', 'true') ON CONFLICT (key) DO NOTHING `); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Rename `security.cors_origins` to `security.trusted_urls`.
|
|
if _, err := db.Exec(`UPDATE settings SET key = 'security.trusted_urls'
|
|
WHERE key = 'security.cors_origins'
|
|
AND NOT EXISTS (SELECT 1 FROM settings WHERE key = 'security.trusted_urls')`); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Hash existing API tokens. This is idempotent by skipping values that
|
|
// already look like lowercase SHA-256 hex digests.
|
|
if _, err := db.Exec(`
|
|
UPDATE users
|
|
SET password = ENCODE(DIGEST(password, 'sha256'), 'hex')
|
|
WHERE type = 'api'
|
|
AND password IS NOT NULL
|
|
AND password != ''
|
|
AND password !~ '^[a-f0-9]{64}$';
|
|
`); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|