Files
shopdb-flask/migrations/versions/7d39_audit_retention_key_merge.py

96 lines
3.6 KiB
Python

"""Merge the second audit-retention setting into the one that is actually read.
Two keys existed for one setting. shopdb/core/services/auditretention.py reads
`audit_retentiondays` (seeded under category 'site', default 0). A second key
`audit_retention_days` was seeded under category 'audit' with a default of 90,
and the Audit & Logging settings page wrote to that one - so an administrator
set a retention period, reloaded, saw it persisted, and nothing ever consulted
it. Retention stayed off while the page said otherwise.
The page now writes the key that is read, and the duplicate is out of the seed
list. This handles the sites that already have it: if an operator set a real
value on the dead key and never set the live one, that intent is carried over
rather than dropped. Their intent was "keep 30 days", and the fix should not
silently discard it.
Not carried over when the live key already holds a non-default value - that one
was set through the page that worked, and it wins.
The dead key is then deleted. Leaving it would preserve the ambiguity that
caused this, and nothing reads it.
Revision ID: 7d39_audit_retention_key_merge
Revises: 7d38_widen_importbatch_status
"""
from alembic import op
import sqlalchemy as sa
revision = '7d39_audit_retention_key_merge'
down_revision = '7d38_widen_importbatch_status'
branch_labels = None
depends_on = None
DEAD = 'audit_retention_days'
LIVE = 'audit_retentiondays'
def _value(bind, key):
return bind.execute(
sa.text('SELECT value FROM settings WHERE `key` = :key'
if bind.dialect.name == 'mysql'
else 'SELECT value FROM settings WHERE "key" = :key'),
{'key': key}).scalar()
def upgrade():
bind = op.get_bind()
if not sa.inspect(bind).has_table('settings'):
return
dead = _value(bind, DEAD)
if dead is None:
return
live = _value(bind, LIVE)
# '90' was the dead key's seeded default, so it is not evidence of intent.
operator_set_dead = dead not in (None, '', '90')
live_is_default = live in (None, '', '0')
if operator_set_dead and live_is_default:
if live is None:
bind.execute(sa.text(
'INSERT INTO settings (`key`, value, valuetype, category, '
'description, createddate, modifieddate, isactive) VALUES '
'(:key, :value, :valuetype, :category, :description, '
'NOW(), NOW(), 1)'
if bind.dialect.name == 'mysql' else
'INSERT INTO settings ("key", value, valuetype, category, '
'description, createddate, modifieddate, isactive) VALUES '
'(:key, :value, :valuetype, :category, :description, '
"datetime('now'), datetime('now'), 1)"),
{'key': LIVE, 'value': dead, 'valuetype': 'integer',
'category': 'site',
'description': 'Delete audit log entries older than this many '
'days. 0 keeps everything forever.'})
else:
bind.execute(sa.text(
'UPDATE settings SET value = :value WHERE `key` = :key'
if bind.dialect.name == 'mysql' else
'UPDATE settings SET value = :value WHERE "key" = :key'),
{'value': dead, 'key': LIVE})
bind.execute(sa.text(
'DELETE FROM settings WHERE `key` = :key'
if bind.dialect.name == 'mysql' else
'DELETE FROM settings WHERE "key" = :key'), {'key': DEAD})
def downgrade():
"""Deliberately a no-op.
Re-creating a key that nothing reads, to sit beside the one that works,
would restore the defect. The live setting keeps whatever value it holds.
"""