Skip to content

feat: allow non-ASCII characters in schedule comments - #15

Merged
boulch merged 4 commits into
mainfrom
CITIBDC-568
Apr 8, 2026
Merged

feat: allow non-ASCII characters in schedule comments#15
boulch merged 4 commits into
mainfrom
CITIBDC-568

Conversation

@remdub

@remdub remdub commented Apr 7, 2026

Copy link
Copy Markdown
Member

CITIBDC-568

Summary by CodeRabbit

  • New Features

    • Schedule comments now accept non‑ASCII characters.
  • Bug Fixes

    • API accepts schedule payloads provided as JSON‑encoded strings.
    • Empty schedule payloads are handled gracefully (PATCH returns 204).
    • Invalid time formats in schedule fields correctly return 400.
  • Tests

    • Added REST tests verifying schedule comment persistence, JSON string input handling, empty payloads, and invalid-time validation.

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f77338aa-66e0-480f-a923-1cfba6fc95be

📥 Commits

Reviewing files that changed from the base of the PR and between 465c51e and 966ade0.

📒 Files selected for processing (1)
  • src/imio/directory/core/tests/test_contact.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/imio/directory/core/tests/test_contact.py

📝 Walkthrough

Walkthrough

Adds a ScheduleFieldDeserializer, its ZCML adapter registration, tests, and a changelog entry to allow JSON (including non‑ASCII) input for ISchedule fields; the deserializer decodes JSON strings, validates via the schedule field, and returns the validated value.

Changes

Cohort / File(s) Summary
Changelog Documentation
CHANGES.rst
Added 1.2.27 (unreleased) entry for CITIBDC-568 describing support for non‑ASCII schedule comments via a field deserializer override.
Component Registration
src/imio/directory/core/contents/contact/configure.zcml
Registered new ZCML adapter factory deserializer.ScheduleFieldDeserializer for field deserializer lookup.
Deserializer Implementation
src/imio/directory/core/contents/contact/deserializer.py
Added ScheduleFieldDeserializer adapter for (ISchedule, IDexterityContent, IBrowserRequest). If input is a string, JSON-decodes it (raises ValueError on invalid JSON), validates via self.field.validate(...), and returns the validated schedule.
Tests
src/imio/directory/core/tests/test_contact.py
Added _make_schedule helper and tests: PATCH updates with non‑ASCII and ASCII comments, empty schedule payload, JSON-encoded string payload, and a negative test for invalid time value returning 400.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant REST_API as REST API
    participant Deserializer as ScheduleFieldDeserializer
    participant Field as ISchedule_Field
    participant Content as Dexterity_Content

    Client->>REST_API: PATCH /contact {"schedule": ...}
    REST_API->>Deserializer: IFieldDeserializer.__call__(value)
    Deserializer->>Deserializer: if string -> json.loads(value)
    Deserializer->>Field: field.validate(parsed_value)
    Field-->>Deserializer: validated_value
    Deserializer-->>REST_API: return validated_value
    REST_API->>Content: set schedule = validated_value
    REST_API-->>Client: 204 No Content
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I munch on JSON, nudge comments right,

Accents find home in schedule's light,
I hop through fields, validate with care,
Strings become structure, handled fair,
A tiny joyous bound — all set to write!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: allow non-ASCII characters in schedule comments' directly and clearly summarizes the main change—enabling non-ASCII character support in schedule comments.

✏️ 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 CITIBDC-568

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 the current code and only fix it if needed.

Inline comments:
In `@src/imio/directory/core/contents/contact/deserializer.py`:
- Around line 23-25: The deserializer currently calls json.loads(value) without
handling malformed JSON, which causes a 500 instead of a 400; update the block
around json.loads in the deserializer (the code that precedes
self.field.validate(value)) to catch json.JSONDecodeError and re-raise a
ValueError (or raise a new ValueError with a clear message) so the Dexterity
deserializer treats it as a field validation error and returns HTTP 400.
🪄 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: 3e78daaa-ceb6-4912-890d-d49949709060

📥 Commits

Reviewing files that changed from the base of the PR and between 1350aaa and 661cc9d.

📒 Files selected for processing (3)
  • CHANGES.rst
  • src/imio/directory/core/contents/contact/configure.zcml
  • src/imio/directory/core/contents/contact/deserializer.py

Comment thread src/imio/directory/core/contents/contact/deserializer.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/imio/directory/core/tests/test_contact.py (1)

334-345: Consider adding an assertion to verify the resulting schedule state.

The test confirms the endpoint accepts an empty schedule payload with a 204 response, but doesn't verify the resulting state. Adding a GET and assertion would clarify the expected behavior (whether the schedule is cleared, left unchanged, or set to an empty dict).

💡 Suggested improvement
     def test_schedule_patch_with_empty_value(self):
         contact = api.content.create(
             container=self.entity,
             type="imio.directory.Contact",
             title="contact",
         )
         transaction.commit()
         response = self.api_session.patch(
             contact.absolute_url(),
             json={"schedule": {}},
         )
         self.assertEqual(response.status_code, 204)
+        result = self.api_session.get(contact.absolute_url()).json()
+        self.assertEqual(result["schedule"], {})  # or expected default state
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/imio/directory/core/tests/test_contact.py` around lines 334 - 345, Update
the test_schedule_patch_with_empty_value test to verify the contact's schedule
after the PATCH: after calling self.api_session.patch(contact.absolute_url(),
json={"schedule": {}}) perform a GET (e.g.,
self.api_session.get(contact.absolute_url())) and assert the schedule field in
the returned JSON matches the expected behavior (cleared, unchanged, or empty
dict) so the test both checks the 204 response and the resulting schedule state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/imio/directory/core/tests/test_contact.py`:
- Around line 334-345: Update the test_schedule_patch_with_empty_value test to
verify the contact's schedule after the PATCH: after calling
self.api_session.patch(contact.absolute_url(), json={"schedule": {}}) perform a
GET (e.g., self.api_session.get(contact.absolute_url())) and assert the schedule
field in the returned JSON matches the expected behavior (cleared, unchanged, or
empty dict) so the test both checks the 204 response and the resulting schedule
state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6dcc3c5d-dc60-4e34-ad72-b8b67e2b320a

📥 Commits

Reviewing files that changed from the base of the PR and between 661cc9d and b9f5037.

📒 Files selected for processing (2)
  • src/imio/directory/core/contents/contact/deserializer.py
  • src/imio/directory/core/tests/test_contact.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/imio/directory/core/contents/contact/deserializer.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/imio/directory/core/tests/test_contact.py (1)

342-353: Please assert the persisted contract for empty payloads.

Line 353 checks only HTTP status. Add a GET assertion so behavior for {"schedule": {}} is explicitly pinned (stored as {}, normalized value, or cleared), preventing silent regressions.

Suggested test hardening
     response = self.api_session.patch(
         contact.absolute_url(),
         json={"schedule": {}},
     )
     self.assertEqual(response.status_code, 204)
+    result = self.api_session.get(contact.absolute_url()).json()
+    self.assertIn("schedule", result)
+    # Assert the expected normalization contract explicitly (adapt value as intended):
+    # self.assertEqual(result["schedule"], {})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/imio/directory/core/tests/test_contact.py` around lines 342 - 353, The
test test_schedule_patch_with_empty_value only asserts the PATCH returned 204
but does not verify the persisted state; after the api_session.patch call (and
existing response.status_code assertion) perform a GET using
api_session.get(contact.absolute_url()) and assert the returned JSON body
contains the expected representation of the schedule (e.g. schedule equals {} or
normalized/cleared value your model uses) to lock down behavior; reference the
contact object, api_session.patch and api_session.get to locate where to add the
additional assertion and ensure transaction.commit() or any necessary refresh is
done before the GET if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/imio/directory/core/tests/test_contact.py`:
- Around line 342-353: The test test_schedule_patch_with_empty_value only
asserts the PATCH returned 204 but does not verify the persisted state; after
the api_session.patch call (and existing response.status_code assertion) perform
a GET using api_session.get(contact.absolute_url()) and assert the returned JSON
body contains the expected representation of the schedule (e.g. schedule equals
{} or normalized/cleared value your model uses) to lock down behavior; reference
the contact object, api_session.patch and api_session.get to locate where to add
the additional assertion and ensure transaction.commit() or any necessary
refresh is done before the GET if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f53f0141-7d83-4496-9151-9e19b15a8e6f

📥 Commits

Reviewing files that changed from the base of the PR and between b9f5037 and 465c51e.

📒 Files selected for processing (1)
  • src/imio/directory/core/tests/test_contact.py

@remdub
remdub requested a review from boulch April 8, 2026 06:20
@boulch
boulch merged commit 3156e06 into main Apr 8, 2026
9 checks passed
@remdub
remdub deleted the CITIBDC-568 branch April 8, 2026 10:45
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.

2 participants