diff --git a/backend/src/zimfarm_backend/common/schemas/orms.py b/backend/src/zimfarm_backend/common/schemas/orms.py index 4e7e902e2..d5a223e31 100644 --- a/backend/src/zimfarm_backend/common/schemas/orms.py +++ b/backend/src/zimfarm_backend/common/schemas/orms.py @@ -290,6 +290,7 @@ class ScheduleHistorySchema(BaseModel): periodicity: str context: str archived: bool + offliner_definition_version: str | None = None # entries are serialized as dict[str, Any] instead of ScheduleConfigSchema # because the entry is possibly outdated and would fail validation as the # offliner schema evolves diff --git a/backend/src/zimfarm_backend/db/models.py b/backend/src/zimfarm_backend/db/models.py index a98740467..b0edb3b2d 100644 --- a/backend/src/zimfarm_backend/db/models.py +++ b/backend/src/zimfarm_backend/db/models.py @@ -310,6 +310,7 @@ class ScheduleHistory(Base): language_code: Mapped[str] tags: Mapped[list[str]] periodicity: Mapped[str] + offliner_definition_version: Mapped[str | None] context: Mapped[str] = mapped_column(default="", server_default="") archived: Mapped[bool] = mapped_column(default=False, server_default=false()) diff --git a/backend/src/zimfarm_backend/db/schedule.py b/backend/src/zimfarm_backend/db/schedule.py index ba8f29eb6..6a500183f 100644 --- a/backend/src/zimfarm_backend/db/schedule.py +++ b/backend/src/zimfarm_backend/db/schedule.py @@ -399,6 +399,7 @@ def create_schedule( tags=schedule.tags, periodicity=schedule.periodicity, context=schedule.context, + offliner_definition_version=offliner_definition.version, ) schedule.history_entries.append(history_entry) @@ -531,6 +532,7 @@ def toggle_archive_status( periodicity=schedule.periodicity, context=schedule.context, archived=schedule.archived, + offliner_definition_version=schedule.offliner_definition.version, ) schedule.history_entries.append(history_entry) session.add(schedule) @@ -599,6 +601,7 @@ def update_schedule( periodicity=schedule.periodicity, context=schedule.context, archived=schedule.archived, + offliner_definition_version=offliner_definition.version, ) schedule.history_entries.append(history_entry) @@ -642,6 +645,7 @@ def create_schedule_history_schema( context=history_entry.context, config=history_entry.config, archived=history_entry.archived, + offliner_definition_version=history_entry.offliner_definition_version, ) diff --git a/backend/src/zimfarm_backend/migrations/versions/8b0210f9d9ab_store_offliner_definition_version_in_.py b/backend/src/zimfarm_backend/migrations/versions/8b0210f9d9ab_store_offliner_definition_version_in_.py new file mode 100644 index 000000000..6e5238f19 --- /dev/null +++ b/backend/src/zimfarm_backend/migrations/versions/8b0210f9d9ab_store_offliner_definition_version_in_.py @@ -0,0 +1,59 @@ +"""store offliner definition version in schedule history + +Revision ID: 8b0210f9d9ab +Revises: b298a5831211 +Create Date: 2025-11-25 09:57:58.062755 + +""" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.orm import Session + +# revision identifiers, used by Alembic. +revision = "8b0210f9d9ab" +down_revision = "b298a5831211" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "schedule_history", + sa.Column("offliner_definition_version", sa.String(), nullable=True), + ) + # ### end Alembic commands ### + + # Populate offliner_definition_version for latest schedule_history of each schedule + bind = op.get_bind() + session = Session(bind=bind) + session.execute( + sa.text( + """ + WITH latest AS ( + SELECT DISTINCT ON (schedule_id) + id AS history_id, + schedule_id + FROM schedule_history + ORDER BY schedule_id, created_at DESC + ) + + UPDATE schedule_history AS sh + SET offliner_definition_version = od.version + FROM schedule AS s + JOIN offliner_definition AS od + ON s.offliner_definition_id = od.id + JOIN latest + ON latest.schedule_id = s.id + WHERE sh.schedule_id = s.id + AND sh.id = latest.history_id + """ + ) + ) + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("schedule_history", "offliner_definition_version") + # ### end Alembic commands ### diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index 9ef7d405f..cf30377f1 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -944,6 +944,7 @@ def _create_schedule( tags=schedule.tags, periodicity=schedule.periodicity, context=schedule.context, + offliner_definition_version=mwoffliner_definition.version, ) schedule.history_entries.append(history_entry) diff --git a/frontend-ui/src/types/schedule.ts b/frontend-ui/src/types/schedule.ts index 9fa1df5e8..15debcce5 100644 --- a/frontend-ui/src/types/schedule.ts +++ b/frontend-ui/src/types/schedule.ts @@ -33,6 +33,7 @@ export interface BaseScheduleHistorySchema { periodicity: string context: string archived: boolean + offliner_definition_version?: string } export interface ScheduleHistorySchema extends BaseScheduleHistorySchema {