"""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. """