mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-28 23:57:58 +09:00
RestorePoint hand-rolled json.loads for payload/coverage — now reads through JsonColumnMixin._json_read like every other model, keeping the models-json ratchet green. test_restoring_the_last_domain_re_enables_the_site mocked create_site and counted enable_site calls, but since write_vhost became the one enabling door (enable=True re-links sites-enabled and create_site goes through it), write_app_vhost no longer calls enable_site separately — test_site_domain_writer_does_not_enable_twice pins that. The restore test now asserts through write_vhost's enable flag instead, still failing if a restore path ever opts out of enabling. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
63 lines
2.2 KiB
Python
63 lines
2.2 KiB
Python
"""Immutable checkpoints for panel-managed configuration surfaces."""
|
|
|
|
from app import db
|
|
from app.models.json_column_mixin import JsonColumnMixin
|
|
from app.models.mixins import SerializableMixin, TimestampMixin, uuid_pk
|
|
|
|
|
|
class RestorePoint(JsonColumnMixin, TimestampMixin, SerializableMixin, db.Model):
|
|
"""One point on a scope's linear configuration timeline."""
|
|
|
|
__tablename__ = 'restore_points'
|
|
|
|
id = uuid_pk()
|
|
server_id = db.Column(
|
|
db.String(36), db.ForeignKey('servers.id'), nullable=True, index=True,
|
|
)
|
|
scope_type = db.Column(db.String(32), nullable=False)
|
|
scope_id = db.Column(db.String(255), nullable=False)
|
|
trigger = db.Column(db.String(32), nullable=False)
|
|
label = db.Column(db.String(255), nullable=True)
|
|
payload_hash = db.Column(db.String(64), nullable=False)
|
|
payload_json = db.Column(db.Text, nullable=False)
|
|
coverage_json = db.Column(db.Text, nullable=False, default='[]')
|
|
actor_user_id = db.Column(
|
|
db.Integer, db.ForeignKey('users.id'), nullable=True, index=True,
|
|
)
|
|
expires_at = db.Column(db.DateTime, nullable=True, index=True)
|
|
keep = db.Column(db.Boolean, nullable=False, default=False)
|
|
|
|
server = db.relationship('Server')
|
|
actor = db.relationship('User', foreign_keys=[actor_user_id])
|
|
|
|
__table_args__ = (
|
|
db.Index('ix_restore_points_scope', 'scope_type', 'scope_id'),
|
|
db.Index(
|
|
'ix_restore_points_scope_timeline',
|
|
'server_id', 'scope_type', 'scope_id', 'created_at',
|
|
),
|
|
)
|
|
|
|
__serialize_exclude__ = ('payload_json', 'coverage_json')
|
|
|
|
def get_payload(self):
|
|
return self._json_read('payload_json', expect=dict)
|
|
|
|
def get_coverage(self):
|
|
return self._json_read('coverage_json', default=[], expect=list)
|
|
|
|
def serialize_extra(self):
|
|
return {
|
|
'payload': self.get_payload(),
|
|
'coverage': self.get_coverage(),
|
|
}
|
|
|
|
@classmethod
|
|
def latest_for_scope(cls, scope_type, scope_id, server_id=None):
|
|
query = cls.query.filter_by(
|
|
scope_type=str(scope_type),
|
|
scope_id=str(scope_id),
|
|
server_id=server_id,
|
|
)
|
|
return query.order_by(cls.created_at.desc(), cls.id.desc()).first()
|