Skip to content

Paraf 445/max session files#38

Open
sgeulette wants to merge 5 commits into
mainfrom
PARAF-445/max_session_files
Open

Paraf 445/max session files#38
sgeulette wants to merge 5 commits into
mainfrom
PARAF-445/max_session_files

Conversation

@sgeulette
Copy link
Copy Markdown
Member

@sgeulette sgeulette commented May 15, 2026

Summary by CodeRabbit

  • New Features

    • Configurable max files per eSign session (default: 25).
    • Automatic splitting of large uploads across multiple sessions when file count/size limits are reached.
    • Success messages now show one or more session IDs.
  • Bug Fixes / Behavior

    • Sessions can reach a new "draft_full" state to prevent reuse when limits are hit.
  • Chores

    • Install/profile configuration reorganized and metadata version bumped; upgrade steps added.
  • UX

    • Minor table/tooltip formatting and action availability tweaks.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

Adds max files-per-session registry; refactors add_files_to_session to split batches by size and file-count and return multiple (session_id, session) tuples; moves ZCML profile/upgrade declarations to separate files; updates callers and tests to consume the new return shape.

Changes

Session file-count limit enforcement

Layer / File(s) Summary
Max files setting and registry accessors
src/imio/esign/browser/settings.py, src/imio/esign/config.py
New max_session_files integer schema field added to IImioEsignSettings (default 25, min 1). Added get_esign_registry_max_session_files() and set_esign_registry_max_session_files() registry helpers.
ZCML profile and upgrade configuration migration
src/imio/esign/configure.zcml, src/imio/esign/profiles.zcml, src/imio/esign/upgrades.zcml, src/imio/esign/profiles/default/metadata.xml
Extracted GenericSetup default/uninstall profile declarations and HiddenProfiles utility into profiles.zcml; moved upgrade steps into upgrades.zcml. Profile metadata version bumped to 1002.
Multi-session dispatch and file-count limits in utils
src/imio/esign/utils.py
add_files_to_session now dispatches files across sessions when no session_id is supplied, enforcing both max_session_size and max_session_files, inserting files per-context order, auditing per-file, marking drafts draft_full when limits reached, and returning a list of (session_id, session) tuples. discriminate_sessions gained files_count and file-count logic; get_state_description includes draft_full.
Browser view and test updates for [-1] tuple extraction
src/imio/esign/browser/actions.py, src/imio/esign/tests/test_browser_views.py, src/imio/esign/tests/test_services.py, src/imio/esign/tests/test_utils.py
AddToSessionView.index and many tests updated to extract the last (session_id, session) tuple from the list return with [-1]. Test setups and assertions adapted to multi-session dispatch behavior.
UI minor formatting and action gating
src/imio/esign/browser/table.py
Tooltip and signer-status formatting adjusted; admin actions for external session creation are allowed when session state is "draft" or "draft_full" (was only "draft").

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • IMIO/imio.esign#9: Overlaps on state description and tooltip usage related to get_state_description.
  • IMIO/imio.esign#8: Related session-splitting work around max_session_size and session discrimination.
  • IMIO/imio.esign#21: Overlaps in handling re-adding of file UIDs to sessions and session content updates.

Suggested reviewers

  • gbastien
  • chris-adam

"I hopped through code and counted each file,
Twenty-five per den — now sessions compile.
Batches split neatly, tests hunt the last pair,
ZCML moved houses, the profiles rest there.
A rabbit's small cheer for the tidy new flow!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Paraf 445/max session files' accurately reflects the primary change: implementation of maximum session files functionality, clearly referencing the feature and associated ticket identifier.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch PARAF-445/max_session_files

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/imio/esign/utils.py`:
- Around line 167-170: The code assumes session["files"][0]["scan_id"] is a
non-None string before slicing; guard that value first and handle the None case
to avoid TypeError: check scan_id = session["files"][0].get("scan_id") (or
similar), and if scan_id is truthy and a string use session["client_id"] =
scan_id[:7] else set session["client_id"] to a safe fallback (e.g. formatted
from session_id or a fixed sentinel) before constructing session["sign_id"] =
"{}{:05d}".format(session["client_id"], session_id); update references to
session["files"][0]["scan_id"][0:7] accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71d9ba18-3c36-4e9e-aeba-8ce4ba5cff85

📥 Commits

Reviewing files that changed from the base of the PR and between 563200d and 2401070.

📒 Files selected for processing (11)
  • src/imio/esign/browser/actions.py
  • src/imio/esign/browser/settings.py
  • src/imio/esign/config.py
  • src/imio/esign/configure.zcml
  • src/imio/esign/profiles.zcml
  • src/imio/esign/profiles/default/metadata.xml
  • src/imio/esign/tests/test_browser_views.py
  • src/imio/esign/tests/test_services.py
  • src/imio/esign/tests/test_utils.py
  • src/imio/esign/upgrades.zcml
  • src/imio/esign/utils.py

Comment thread src/imio/esign/utils.py
Comment on lines +167 to +170
if session["client_id"] is None:
# FIXME what if scan_id is None ?
session["client_id"] = session["files"][0]["scan_id"][0:7]
session["sign_id"] = "{}{:05d}".format(session["client_id"], session_id)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard scan_id before slicing to prevent dispatch crashes.

Line 169 assumes scan_id is always a string. If it is None, this raises TypeError and aborts the whole add flow.

Proposed fix
         if session["client_id"] is None:
-            # FIXME what if scan_id is None ?
-            session["client_id"] = session["files"][0]["scan_id"][0:7]
+            scan_id = session["files"][0].get("scan_id")
+            if not scan_id:
+                logger.error(
+                    "Missing scan_id for uid %s while initializing session %s client_id",
+                    uid,
+                    session_id,
+                )
+                scan_id = get_suid_from_uuid(uid).replace("-", "")
+            session["client_id"] = scan_id[0:7]
             session["sign_id"] = "{}{:05d}".format(session["client_id"], session_id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/imio/esign/utils.py` around lines 167 - 170, The code assumes
session["files"][0]["scan_id"] is a non-None string before slicing; guard that
value first and handle the None case to avoid TypeError: check scan_id =
session["files"][0].get("scan_id") (or similar), and if scan_id is truthy and a
string use session["client_id"] = scan_id[:7] else set session["client_id"] to a
safe fallback (e.g. formatted from session_id or a fixed sentinel) before
constructing session["sign_id"] = "{}{:05d}".format(session["client_id"],
session_id); update references to session["files"][0]["scan_id"][0:7]
accordingly.

@coveralls
Copy link
Copy Markdown

coveralls commented May 15, 2026

Coverage Report for CI Build 26155201448

Coverage increased (+0.2%) to 84.76%

Details

  • Coverage increased (+0.2%) from the base build.
  • Patch coverage: 5 uncovered changes across 3 files (56 of 61 lines covered, 91.8%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
src/imio/esign/browser/actions.py 3 0 0.0%
src/imio/esign/browser/table.py 2 1 50.0%
src/imio/esign/utils.py 51 50 98.04%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1273
Covered Lines: 1079
Line Coverage: 84.76%
Coverage Strength: 0.85 hits per line

💛 - Coveralls

@sgeulette sgeulette requested a review from gbastien May 17, 2026 15:54
Comment thread src/imio/esign/browser/actions.py Outdated
watchers=self.get_watchers(),
discriminators=self.get_discriminators(),
)
)[-1]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Salut @sgeulette
en regardant vite une première fois depuis le garage (changement de pneus ;-)) je vois ceci:

  • le [-1] systématique partout, pas plus simple d'avoir un paramètre genre "return_last_session=True" par défaut pour utils.add_files_to_session? Puisque c'est le comportement qu'on veut la plupart du temps...
  • le terme "complete" peut-être pas idéal, changer en "draft_complete" par exemple pour que ce soit plus clair et traduit en "en création (complet)"? à voir
    Pour le reste je vais tester vraiment le code cet aprem je te dirai (sauf si Alain B vient à l'atelier pour moi...)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/imio/esign/browser/actions.py`:
- Line 58: The success message is joining integer session_id values which raises
a TypeError; update the call to self._finished so the session_ids values are
converted to strings before joining (e.g. map/str conversion of [tup[0] for tup
in session_ids]) when building the mapping for the "session_ids" key so the u",
".join succeeds; locate the join in actions.py where
self._finished(mapping={"session_ids": u", ".join([tup[0] for tup in
session_ids])}) is used and cast each tup[0] to str.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f0188411-5eee-4c1a-bd3c-686f691bd75c

📥 Commits

Reviewing files that changed from the base of the PR and between 96a74e9 and f9d146d.

📒 Files selected for processing (4)
  • src/imio/esign/browser/actions.py
  • src/imio/esign/browser/table.py
  • src/imio/esign/tests/test_utils.py
  • src/imio/esign/utils.py

# audit("add_to_session", "session={} context={} files={} signers={}".format(
# session_id, self.context.UID(), ",".join(files_uids), len(signers)))
self._finished()
self._finished(mapping={"session_ids": u", ".join([tup[0] for tup in session_ids])})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix session ID join type mismatch in success message.

Line 58 joins integer session_id values directly; this raises TypeError (expected str instance) on Python 3 and breaks redirect flow after add.

Proposed fix
-        self._finished(mapping={"session_ids": u", ".join([tup[0] for tup in session_ids])})
+        self._finished(mapping={"session_ids": u", ".join([safe_unicode(tup[0]) for tup in session_ids])})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/imio/esign/browser/actions.py` at line 58, The success message is joining
integer session_id values which raises a TypeError; update the call to
self._finished so the session_ids values are converted to strings before joining
(e.g. map/str conversion of [tup[0] for tup in session_ids]) when building the
mapping for the "session_ids" key so the u", ".join succeeds; locate the join in
actions.py where self._finished(mapping={"session_ids": u", ".join([tup[0] for
tup in session_ids])}) is used and cast each tup[0] to str.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants