From baed73657db02c015b765ca3f91f419922d5ee44 Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Fri, 13 Feb 2026 15:45:11 +0000 Subject: [PATCH 1/7] added column to template_email_files and template_email_files_history, pending we need a way of storing the data associated with a file that a user is currently editing, but has not yet added to a template --- app/models.py | 2 + app/models_types.py | 1 + migrations/.current-alembic-head | 2 +- .../versions/0545_add_pending_column.py | 44 +++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/0545_add_pending_column.py diff --git a/app/models.py b/app/models.py index 407d3952ce..d8aea10b79 100644 --- a/app/models.py +++ b/app/models.py @@ -1301,6 +1301,7 @@ class TemplateEmailFileBase(db.Model): created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow) archived_at = db.Column(db.DateTime, nullable=True) + pending = db.Column(db.Boolean, default=False, nullable=True) def serialize(self) -> SerializedTemplateEmailFile: return SerializedTemplateEmailFile( @@ -1309,6 +1310,7 @@ def serialize(self) -> SerializedTemplateEmailFile: link_text=self.link_text, retention_period=self.retention_period, validate_users_email=self.validate_users_email, + pending=self.pending, ) @declared_attr diff --git a/app/models_types.py b/app/models_types.py index 270d10a5fb..c81a43a8df 100644 --- a/app/models_types.py +++ b/app/models_types.py @@ -359,3 +359,4 @@ class SerializedTemplateEmailFile(TypedDict): link_text: str retention_period: int validate_users_email: bool + pending: bool diff --git a/migrations/.current-alembic-head b/migrations/.current-alembic-head index 0a7343dac7..c0886edf40 100644 --- a/migrations/.current-alembic-head +++ b/migrations/.current-alembic-head @@ -1 +1 @@ -0544_email_file_retention_fix +0545_add_pending_column diff --git a/migrations/versions/0545_add_pending_column.py b/migrations/versions/0545_add_pending_column.py new file mode 100644 index 0000000000..584e351e4b --- /dev/null +++ b/migrations/versions/0545_add_pending_column.py @@ -0,0 +1,44 @@ +""" + +Create Date: 2025-02-10 17:07:41.828494 +Revision ID: 0544_email_file_retention_fix +Revises: 0543_letter_rates_from_5_01_26 + +""" + +revision = "0545_add_pending_column" +down_revision = "0544_email_file_retention_fix" + + +from alembic import op +from sqlalchemy import text + + +def upgrade(): + conn = op.get_bind() + conn.execute(text("ALTER TABLE template_email_files ADD COLUMN pending boolean")) + conn.execute(text("ALTER TABLE template_email_files_history ADD COLUMN pending boolean")) + conn.execute(text(""" + ALTER TABLE + template_email_files + ALTER COLUMN + pending + SET DEFAULT + false + """)) + conn.execute(text(""" + ALTER TABLE + template_email_files_history + ALTER COLUMN + pending + SET DEFAULT + false + """)) + conn.execute(text("UPDATE template_email_files SET pending = false")) + conn.execute(text("UPDATE template_email_files_history SET pending = false")) + + +def downgrade(): + conn = op.get_bind() + conn.execute("ALTER TABLE template_email_files DROP COLUMN pending") + conn.execute("ALTER TABLE template_email_files_history DROP COLUMN pending") From 0baf21d36b91633cae2be1660b9e733514c5a10e Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Sun, 15 Feb 2026 21:19:28 +0000 Subject: [PATCH 2/7] WIP --- tests/app/db.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/app/db.py b/tests/app/db.py index 90407d4731..7327377f43 100644 --- a/tests/app/db.py +++ b/tests/app/db.py @@ -199,6 +199,7 @@ def create_template_email_file( link_text="follow this link", retention_period=90, validate_users_email=True, + pending=False, ): data = { "filename": filename, @@ -207,6 +208,7 @@ def create_template_email_file( "validate_users_email": validate_users_email, "template_id": template_id, "created_by_id": created_by_id, + "pending": pending, } template_email_file = TemplateEmailFile(**data) dao_create_template_email_file(template_email_file) From 078c843b2670e8229382c48b040663bb79bfa517 Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Sun, 15 Feb 2026 21:26:48 +0000 Subject: [PATCH 3/7] wio --- app/dao/template_email_files_dao.py | 35 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/app/dao/template_email_files_dao.py b/app/dao/template_email_files_dao.py index 8a70726ded..0bcb9ccc08 100644 --- a/app/dao/template_email_files_dao.py +++ b/app/dao/template_email_files_dao.py @@ -21,24 +21,39 @@ def dao_create_template_email_file(template_email_file: TemplateEmailFile): @autocommit -def dao_get_template_email_files_by_template_id(template_id, template_version=None): +def dao_get_template_email_files_by_template_id(template_id, template_version=None, get_pending=False): if template_version: - query = ( - select(TemplateEmailFileHistory) - .where(TemplateEmailFileHistory.template_id == template_id) - .where(TemplateEmailFileHistory.template_version <= template_version) - # .where(TemplateEmailFileHistory.archived_at.is_(None)) - .order_by(TemplateEmailFileHistory.id) - .order_by(TemplateEmailFileHistory.version.desc()) - .distinct(TemplateEmailFileHistory.id) - ) + if get_pending: + query = ( + select(TemplateEmailFileHistory) + .where(TemplateEmailFileHistory.template_id == template_id) + .where(TemplateEmailFileHistory.template_version <= template_version) + .order_by(TemplateEmailFileHistory.id) + .order_by(TemplateEmailFileHistory.version.desc()) + .distinct(TemplateEmailFileHistory.id) + ) + else: + query = ( + select(TemplateEmailFileHistory) + .where(TemplateEmailFileHistory.template_id == template_id) + .where(TemplateEmailFileHistory.template_version <= template_version) + .where(not TemplateEmailFileHistory.pending) + .order_by(TemplateEmailFileHistory.id) + .order_by(TemplateEmailFileHistory.version.desc()) + .distinct(TemplateEmailFileHistory.id) + ) # prune archived after the fact # return db.session.execute(query).all() return list(filter(lambda x: not x.archived_at, list(chain.from_iterable(db.session.execute(query).all())))) + if get_pending: + return TemplateEmailFile.query.filter( + TemplateEmailFile.template_id == template_id, TemplateEmailFile.archived_at.is_(None) + ).all() return TemplateEmailFile.query.filter( TemplateEmailFile.template_id == template_id, TemplateEmailFile.archived_at.is_(None), + TemplateEmailFile.pending == False, ).all() From 64482134f71b4f7a928ffb30acd86f446c42e9dd Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Sun, 15 Feb 2026 21:27:01 +0000 Subject: [PATCH 4/7] STASH --- app/dao/template_email_files_dao.py | 5 +++ app/template_email_files/rest.py | 10 ++++++ .../app/dao/test_template_email_files_dao.py | 31 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/app/dao/template_email_files_dao.py b/app/dao/template_email_files_dao.py index 0bcb9ccc08..1ec5909f2d 100644 --- a/app/dao/template_email_files_dao.py +++ b/app/dao/template_email_files_dao.py @@ -75,6 +75,11 @@ def dao_update_template_email_file(template_email_file: TemplateEmailFile): db.session.add(template) +@autocommit +def dao_update_pending_template_email_file(template_email_file: TemplateEmailFile): + db.session.add(template_email_file) + + @autocommit @version_class( VersionOptions(TemplateEmailFile, history_class=TemplateEmailFileHistory), diff --git a/app/template_email_files/rest.py b/app/template_email_files/rest.py index bd6a437d8b..a120cd1319 100644 --- a/app/template_email_files/rest.py +++ b/app/template_email_files/rest.py @@ -9,6 +9,7 @@ dao_create_template_email_file, dao_get_template_email_file_by_id, dao_get_template_email_files_by_template_id, + dao_update_pending_template_email_file, dao_update_template_email_file, ) from app.dao.templates_dao import dao_get_template_by_id_and_service_id @@ -73,13 +74,22 @@ def update_template_email_file(template_email_file_id, service_id, template_id): current_data = TemplateEmailFile.query.filter(TemplateEmailFile.id == template_email_file_id).one() current_data_json = template_email_files_schema.dump(current_data) updated_data_json = validate(request.get_json(), post_create_template_email_files_schema) + # make_live = updated_data_json.pop("make_live") updated_data_json = current_data_json | updated_data_json + # if updated_data_json == current_data_json and not make_live: if updated_data_json == current_data_json: return jsonify(data=updated_data_json), 200 updated_email_file = template_email_files_schema.load(updated_data_json) _check_if_filename_unique_for_email_files_within_one_template( updated_email_file.filename, template_id, template_email_file_id ) + # if make_live: + # updated_email_file.pending = False + # dao_update_pending_template_email_file(updated_email_file) + # if updated_email_file.pending: + # dao_update_pending_template_email_file(updated_email_file) + # else: + # dao_update_template_email_file(updated_email_file) dao_update_template_email_file(updated_email_file) return jsonify(data=template_email_files_schema.dump(updated_email_file)), 200 diff --git a/tests/app/dao/test_template_email_files_dao.py b/tests/app/dao/test_template_email_files_dao.py index 159f4ef213..d43a488cb7 100644 --- a/tests/app/dao/test_template_email_files_dao.py +++ b/tests/app/dao/test_template_email_files_dao.py @@ -27,6 +27,7 @@ def test_create_template_email_files_dao(sample_email_template, sample_service): "template_id": str(sample_email_template.id), "template_version": int(sample_email_template.version), "created_by_id": str(sample_service.users[0].id), + "pending": True, } template_email_file = TemplateEmailFile(**data) dao_create_template_email_file(template_email_file) @@ -40,6 +41,7 @@ def test_create_template_email_files_dao(sample_email_template, sample_service): assert template_email_file.validate_users_email assert template_email_file.version == 1 assert template_email_file.created_by_id == sample_service.users[0].id + assert template_email_file.pending def test_dao_get_template_email_file_by_id(sample_template_email_file, sample_service): @@ -59,6 +61,7 @@ def test_dao_get_template_email_file_by_id(sample_template_email_file, sample_se assert template_email_file_fetched.validate_users_email == sample_template_email_file.validate_users_email assert template_email_file_fetched.template_version == sample_template_email_file.template_version assert template_email_file_fetched.created_by_id == sample_template_email_file.created_by_id + assert not template_email_file_fetched.pending def test_dao_get_template_email_file_by_id_returns_none_when_not_found(): @@ -102,6 +105,34 @@ def test_dao_get_template_email_files_by_template_id(sample_template_email_file, assert fetched_file_list[0].created_by_id == sample_template_email_file.created_by_id +def test_dao_get_template_email_files_only_gets_pending_files_with_flag_set(sample_email_template): + create_template_email_file( + template_id=sample_email_template.id, created_by_id=sample_email_template.created_by_id, pending=True + ) + assert not dao_get_template_email_files_by_template_id(sample_email_template.id) + assert len(dao_get_template_email_files_by_template_id(sample_email_template.id, get_pending=True)) == 1 + # bump the template version + sample_email_template.content = "here is some new content" + dao_update_template(sample_email_template) + assert not dao_get_template_email_files_by_template_id(sample_email_template.id) + assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=1) + assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=2) + assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=3) + assert len(dao_get_template_email_files_by_template_id(sample_email_template.id, get_pending=True)) == 1 + assert ( + len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=1, get_pending=True)) + == 0 + ) + assert ( + len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=2, get_pending=True)) + == 1 + ) + assert ( + len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=3, get_pending=True)) + == 1 + ) + + def test_dao_get_template_email_files_by_template_id_does_not_return_archived_file(sample_template_email_file): sample_template_email_file.archived_at = datetime.datetime.now() sample_template_email_file.archived_by_id = sample_template_email_file.created_by_id From a582bb889d1b40f2cf117e2ab1374356f20362d2 Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Sun, 15 Feb 2026 21:32:36 +0000 Subject: [PATCH 5/7] Revert "STASH" This reverts commit 98c0cc9fee4ebd65efa1f87ceac462a89c5e5cbb. --- app/dao/template_email_files_dao.py | 5 --- app/template_email_files/rest.py | 10 ------ .../app/dao/test_template_email_files_dao.py | 31 ------------------- 3 files changed, 46 deletions(-) diff --git a/app/dao/template_email_files_dao.py b/app/dao/template_email_files_dao.py index 1ec5909f2d..0bcb9ccc08 100644 --- a/app/dao/template_email_files_dao.py +++ b/app/dao/template_email_files_dao.py @@ -75,11 +75,6 @@ def dao_update_template_email_file(template_email_file: TemplateEmailFile): db.session.add(template) -@autocommit -def dao_update_pending_template_email_file(template_email_file: TemplateEmailFile): - db.session.add(template_email_file) - - @autocommit @version_class( VersionOptions(TemplateEmailFile, history_class=TemplateEmailFileHistory), diff --git a/app/template_email_files/rest.py b/app/template_email_files/rest.py index a120cd1319..bd6a437d8b 100644 --- a/app/template_email_files/rest.py +++ b/app/template_email_files/rest.py @@ -9,7 +9,6 @@ dao_create_template_email_file, dao_get_template_email_file_by_id, dao_get_template_email_files_by_template_id, - dao_update_pending_template_email_file, dao_update_template_email_file, ) from app.dao.templates_dao import dao_get_template_by_id_and_service_id @@ -74,22 +73,13 @@ def update_template_email_file(template_email_file_id, service_id, template_id): current_data = TemplateEmailFile.query.filter(TemplateEmailFile.id == template_email_file_id).one() current_data_json = template_email_files_schema.dump(current_data) updated_data_json = validate(request.get_json(), post_create_template_email_files_schema) - # make_live = updated_data_json.pop("make_live") updated_data_json = current_data_json | updated_data_json - # if updated_data_json == current_data_json and not make_live: if updated_data_json == current_data_json: return jsonify(data=updated_data_json), 200 updated_email_file = template_email_files_schema.load(updated_data_json) _check_if_filename_unique_for_email_files_within_one_template( updated_email_file.filename, template_id, template_email_file_id ) - # if make_live: - # updated_email_file.pending = False - # dao_update_pending_template_email_file(updated_email_file) - # if updated_email_file.pending: - # dao_update_pending_template_email_file(updated_email_file) - # else: - # dao_update_template_email_file(updated_email_file) dao_update_template_email_file(updated_email_file) return jsonify(data=template_email_files_schema.dump(updated_email_file)), 200 diff --git a/tests/app/dao/test_template_email_files_dao.py b/tests/app/dao/test_template_email_files_dao.py index d43a488cb7..159f4ef213 100644 --- a/tests/app/dao/test_template_email_files_dao.py +++ b/tests/app/dao/test_template_email_files_dao.py @@ -27,7 +27,6 @@ def test_create_template_email_files_dao(sample_email_template, sample_service): "template_id": str(sample_email_template.id), "template_version": int(sample_email_template.version), "created_by_id": str(sample_service.users[0].id), - "pending": True, } template_email_file = TemplateEmailFile(**data) dao_create_template_email_file(template_email_file) @@ -41,7 +40,6 @@ def test_create_template_email_files_dao(sample_email_template, sample_service): assert template_email_file.validate_users_email assert template_email_file.version == 1 assert template_email_file.created_by_id == sample_service.users[0].id - assert template_email_file.pending def test_dao_get_template_email_file_by_id(sample_template_email_file, sample_service): @@ -61,7 +59,6 @@ def test_dao_get_template_email_file_by_id(sample_template_email_file, sample_se assert template_email_file_fetched.validate_users_email == sample_template_email_file.validate_users_email assert template_email_file_fetched.template_version == sample_template_email_file.template_version assert template_email_file_fetched.created_by_id == sample_template_email_file.created_by_id - assert not template_email_file_fetched.pending def test_dao_get_template_email_file_by_id_returns_none_when_not_found(): @@ -105,34 +102,6 @@ def test_dao_get_template_email_files_by_template_id(sample_template_email_file, assert fetched_file_list[0].created_by_id == sample_template_email_file.created_by_id -def test_dao_get_template_email_files_only_gets_pending_files_with_flag_set(sample_email_template): - create_template_email_file( - template_id=sample_email_template.id, created_by_id=sample_email_template.created_by_id, pending=True - ) - assert not dao_get_template_email_files_by_template_id(sample_email_template.id) - assert len(dao_get_template_email_files_by_template_id(sample_email_template.id, get_pending=True)) == 1 - # bump the template version - sample_email_template.content = "here is some new content" - dao_update_template(sample_email_template) - assert not dao_get_template_email_files_by_template_id(sample_email_template.id) - assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=1) - assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=2) - assert not dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=3) - assert len(dao_get_template_email_files_by_template_id(sample_email_template.id, get_pending=True)) == 1 - assert ( - len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=1, get_pending=True)) - == 0 - ) - assert ( - len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=2, get_pending=True)) - == 1 - ) - assert ( - len(dao_get_template_email_files_by_template_id(sample_email_template.id, template_version=3, get_pending=True)) - == 1 - ) - - def test_dao_get_template_email_files_by_template_id_does_not_return_archived_file(sample_template_email_file): sample_template_email_file.archived_at = datetime.datetime.now() sample_template_email_file.archived_by_id = sample_template_email_file.created_by_id From 3be22df7a9ede398832159fcc6344aada733116d Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Sun, 15 Feb 2026 21:57:41 +0000 Subject: [PATCH 6/7] WORKING --- app/dao/template_email_files_dao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dao/template_email_files_dao.py b/app/dao/template_email_files_dao.py index 0bcb9ccc08..f83bfa5f92 100644 --- a/app/dao/template_email_files_dao.py +++ b/app/dao/template_email_files_dao.py @@ -37,7 +37,7 @@ def dao_get_template_email_files_by_template_id(template_id, template_version=No select(TemplateEmailFileHistory) .where(TemplateEmailFileHistory.template_id == template_id) .where(TemplateEmailFileHistory.template_version <= template_version) - .where(not TemplateEmailFileHistory.pending) + .where(TemplateEmailFileHistory.pending.is_(False)) .order_by(TemplateEmailFileHistory.id) .order_by(TemplateEmailFileHistory.version.desc()) .distinct(TemplateEmailFileHistory.id) From c3e06d64ce60348435d683255ce289495d0330d3 Mon Sep 17 00:00:00 2001 From: Richard Parke Date: Tue, 24 Feb 2026 16:54:43 +0000 Subject: [PATCH 7/7] downgrade typo --- migrations/versions/0545_add_pending_column.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migrations/versions/0545_add_pending_column.py b/migrations/versions/0545_add_pending_column.py index 584e351e4b..e891947e28 100644 --- a/migrations/versions/0545_add_pending_column.py +++ b/migrations/versions/0545_add_pending_column.py @@ -40,5 +40,5 @@ def upgrade(): def downgrade(): conn = op.get_bind() - conn.execute("ALTER TABLE template_email_files DROP COLUMN pending") - conn.execute("ALTER TABLE template_email_files_history DROP COLUMN pending") + conn.execute(text("ALTER TABLE template_email_files DROP COLUMN pending")) + conn.execute(text("ALTER TABLE template_email_files_history DROP COLUMN pending"))