diff --git a/CHANGES.rst b/CHANGES.rst index 1e1cc21..8532d0e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,8 @@ Changelog - Do not let `Recreate session` when it is `sent` or `signed`. [gbastien] +- Formalised the sent filename generation in `ISignable.get_filename` (PARAF-550). + [chris-adam] 1.0.2 (2026-08-24) ------------------ diff --git a/src/imio/esign/adapters.py b/src/imio/esign/adapters.py index 5cc9646..08bd080 100644 --- a/src/imio/esign/adapters.py +++ b/src/imio/esign/adapters.py @@ -2,6 +2,8 @@ from imio.esign.utils import get_session_annotation from imio.esign.utils import get_session_info +from imio.helpers.transmogrifier import get_correct_id +from os import path from plone.memoize import ram from zope.interface import Interface @@ -80,6 +82,10 @@ def get_discriminators(self): def get_create_session_custom_data(self): return {} + def get_filename(self, annex, existing_files=()): + filename, ext = path.splitext(annex.file.filename or u"no_filename.pdf") + return get_correct_id(existing_files, filename) + ext + class ISignable(Interface): def get_signers(self): @@ -118,3 +124,12 @@ def get_create_session_custom_data(self): in the annotation. """ return {} + + def get_filename(self, annex, existing_files=()): + """ + Return the filename to use for that element in the session. + + `existing_files` holds the names (without extension) already used in the + session, to keep them unique. + """ + return u"" diff --git a/src/imio/esign/configure.zcml b/src/imio/esign/configure.zcml index de4a599..761425e 100644 --- a/src/imio/esign/configure.zcml +++ b/src/imio/esign/configure.zcml @@ -18,6 +18,11 @@ + + - - diff --git a/src/imio/esign/tests/test_adapters.py b/src/imio/esign/tests/test_adapters.py index b84ac6a..e9328e5 100644 --- a/src/imio/esign/tests/test_adapters.py +++ b/src/imio/esign/tests/test_adapters.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from imio.esign.adapters import DefaultContextUidProvider +from imio.esign.adapters import ISignable +from imio.esign.adapters import SignableAdapter from imio.esign.interfaces import IContextUidProvider from imio.esign.interfaces import IItemOrderProvider from imio.esign.tests.base import BaseEsignTest @@ -35,3 +37,25 @@ def test_get_item_order(self): empty = api.content.create(container=self.portal, type="Folder", id="empty-folder") provider = getAdapter(empty, IItemOrderProvider) self.assertEqual(provider.get_item_order(), {}) + + +class TestSignableAdapter(BaseEsignTest): + + def test_get_filename(self): + annex = self.portal["folder0"]["annex0"] + adapter = getAdapter(annex.aq_parent, ISignable) + self.assertIsInstance(adapter, SignableAdapter) + self.assertEqual(adapter.get_filename(annex), u"annex0.pdf") + # a name already used in the session gets a numbered suffix + self.assertEqual(adapter.get_filename(annex, existing_files=["annex0"]), u"annex0-1.pdf") + self.assertEqual(adapter.get_filename(annex, existing_files=["annex0", "annex0-1"]), u"annex0-2.pdf") + # a __ suffix is kept: imio.zamqp parses it back + annex.file.filename = u"Rapport__{}.pdf".format(annex.UID()) + self.assertEqual(adapter.get_filename(annex), u"Rapport__{}.pdf".format(annex.UID())) + # and it survives deduplication, the suffix landing after the uid + self.assertEqual( + adapter.get_filename(annex, existing_files=["Rapport__{}".format(annex.UID())]), + u"Rapport__{}-1.pdf".format(annex.UID()), + ) + annex.file.filename = None + self.assertEqual(adapter.get_filename(annex), u"no_filename.pdf") diff --git a/src/imio/esign/tests/test_events.py b/src/imio/esign/tests/test_events.py new file mode 100644 index 0000000..da1699e --- /dev/null +++ b/src/imio/esign/tests/test_events.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +"""events tests for this package.""" +from imio.esign.tests.base import BaseEsignTest +from imio.esign.utils import add_files_to_session +from zope.event import notify +from zope.lifecycleevent import ObjectModifiedEvent + + +class TestEvents(BaseEsignTest): + def test_on_categorized_annex_updated(self): + """Renaming an annex keeps its session filename unique, without conflicting with itself.""" + signers = [("user1", "user1@sign.com", "User 1", "Position 1")] + annex0 = self.portal["folder0"]["annex0"] + annex2 = self.portal["folder0"]["annex2"] + sid, session = add_files_to_session(signers, (annex0.UID(), annex2.UID()))[-1] + self.assertEqual([f["filename"] for f in session["files"]], [u"annex0.pdf", u"annex2.pdf"]) + # renamed to a name already used in the session: deduplicated + annex2.file.filename = u"annex0.pdf" + notify(ObjectModifiedEvent(annex2)) + self.assertEqual([f["filename"] for f in session["files"]], [u"annex0.pdf", u"annex0-1.pdf"]) + # updated again: the generated name is the one it already has, it must not drift to annex0-2.pdf + annex2.setTitle("New Annex 2") + notify(ObjectModifiedEvent(annex2)) + self.assertEqual([f["filename"] for f in session["files"]], [u"annex0.pdf", u"annex0-1.pdf"]) + self.assertEqual(session["files"][1]["title"], "New Annex 2") diff --git a/src/imio/esign/utils.py b/src/imio/esign/utils.py index ea1baa4..e107f16 100644 --- a/src/imio/esign/utils.py +++ b/src/imio/esign/utils.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from Acquisition import aq_parent from collections import OrderedDict from copy import deepcopy from datetime import datetime @@ -19,7 +20,6 @@ from imio.esign.interfaces import IContextUidProvider from imio.esign.interfaces import IItemOrderProvider from imio.helpers.content import uuidToObject -from imio.helpers.transmogrifier import get_correct_id from imio.helpers.ws import get_auth_token # from imio.pyutils.system import post_request from imio.pyutils.utils import shortuid_encode_id @@ -101,6 +101,7 @@ def add_files_to_session( # noqa C901 session = annot["sessions"][session_id] dispatch = session_id is None sessions_used = [] + from imio.esign.adapters import ISignable # avoid circular import for uid in files_uids: file_size = get_filesize(uid) @@ -135,13 +136,11 @@ def add_files_to_session( # noqa C901 logger.info("File with UID %s is already in session_id %s and data were updated!", uid, session_id) remove_files_from_session([uid], remove_empty_session=False) - existing_files = [path.splitext(f["filename"])[0] for f in session["files"]] - filename, ext = path.splitext(annex.file.filename or "no_filename.pdf") - new_filename = get_correct_id(existing_files, filename) + existing_files = [path.splitext(f["filename"])[0] for f in session["files"] if f["uid"] != uid] file_dict = PersistentMapping( { "scan_id": annex.scan_id, - "filename": new_filename + ext, + "filename": ISignable(aq_parent(annex)).get_filename(annex, existing_files=existing_files), "title": annex.title or "no_title", "uid": uid, "context_uid": context_uid,