Skip to content

feat(auth): add timezone field to AbstractUser#439

Open
nossila wants to merge 6 commits into
masterfrom
feature/i18n
Open

feat(auth): add timezone field to AbstractUser#439
nossila wants to merge 6 commits into
masterfrom
feature/i18n

Conversation

@nossila

@nossila nossila commented Jun 18, 2026

Copy link
Copy Markdown
Member

What

Add a user timezone preference to baseapp_auth, alongside preferred_language.

  • AbstractUser.timezone — free-form CharField(max_length=64, blank=True, default="") (IANA name).
  • Exposed on UserBaseSerializer as an owner-private, writable field (added to fields + private_fields, kept out of read_only_fields) — mirrors preferred_language.
  • testproject migration for the concrete test user.
  • Tests: update via PATCH, owner-only visibility, and owner field-set assertion.

Also drops a git config --global --add safe.directory Docker step that aborted when the repo is built as a submodule.

Test plan

  • docker compose exec web pytest baseapp_auth/tests/integration/test_users.py → timezone update + field-set tests pass (the one unrelated failure is a Celery broker connection error — no broker in the isolated compose).
  • black / isort / flake8 clean on changed files.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a user timezone preference that can be set and updated via the user profile.
    • Included timezone in the authenticated user’s detail/update responses, while keeping it out of public user listings.
  • Validation & Reliability
    • Timezone input is now validated against IANA timezone names; invalid values are rejected and won’t be saved.
  • Admin Updates
    • Displayed timezone (and preferred language) in the admin user list and added timezone to the main user fields.

Add a writable, free-form `timezone` field (IANA name, blank default) to
AbstractUser alongside preferred_language, and expose it on UserBaseSerializer
as an owner-private field (in fields + private_fields, not read_only). Includes
the testproject migration and tests for updating it, owner-only visibility, and
the owner field-set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 18, 2026 00:33
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds an optional timezone CharField (IANA name, max 64 chars) to the AbstractUser model with validation against zoneinfo.available_timezones(), exposes it as a private field in UserBaseSerializer, includes it in Django admin display and filters, and ships a corresponding database migration. Integration tests verify it appears in the authenticated user detail response and can be patched; invalid values are rejected. The Dockerfile also updates its Git configuration to trust all repository paths using a wildcard, applied earlier in the build process.

Changes

timezone field on AbstractUser

Layer / File(s) Summary
Model field definition and validation
baseapp_auth/models.py
Imports zoneinfo and adds validate_timezone(value: str) function that allows blank values but validates non-empty timezone strings against zoneinfo.available_timezones(). AbstractUser gains an optional timezone CharField (max_length=64, blank=True, default="") with the validator and translated verbose name/help text.
Database migration
testproject/users/migrations/0007_user_timezone.py
New migration adds the timezone column to the user model with matching field configuration, validator, and help text.
Serializer exposure
baseapp_auth/rest_framework/users/serializers.py
UserBaseSerializer.Meta lists timezone in both fields and private_fields, hiding it from UserPublicSerializer.
Admin interface configuration
baseapp_auth/admin.py
AbstractUserAdmin adds timezone to the main fieldset and includes timezone and preferred_language in list_display; preferred_language is also added to list_filter.
Integration tests
baseapp_auth/tests/integration/test_users.py
Tests verify timezone appears in the authenticated user detail response, assert that a PATCH persists the value to the database, and confirm that invalid timezone values return a bad request without updating the stored value.

Dockerfile Git configuration

Layer / File(s) Summary
Git safe.directory configuration
Dockerfile
Changes Git safe.directory from a specific path (/usr/src/app, applied after COPY/WORKDIR) to a wildcard ('*') that trusts all repositories, and moves the git config step to run before copying the repository into the container.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐇 A timezone hops into the model with grace,
Validated through zoneinfo's vast, worldly space.
As private serialized, the admin shows all,
Migration and tests answer the call.
The Docker wild-trusts both near and afar—
This bunny's delighted! A feature star! ⭐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 accurately summarizes the primary change: adding a timezone field to AbstractUser. It is concise, specific, and clearly conveys the main objective of the PR.
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 feature/i18n

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a user “timezone” preference to baseapp_auth (similar to preferred_language) and wires it through the REST API and test suite, with a supporting migration in the testproject concrete user model.

Changes:

  • Add AbstractUser.timezone (CharField(max_length=64, blank=True, default="")) to baseapp_auth.
  • Expose timezone as an owner-private, writable field on the REST UserBaseSerializer.
  • Add testproject migration and integration tests covering owner visibility and PATCH updates.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
baseapp_auth/models.py Adds the timezone field to the abstract user model.
baseapp_auth/rest_framework/users/serializers.py Exposes timezone in REST serialization as an owner-private writable field.
baseapp_auth/tests/integration/test_users.py Extends integration tests to assert the field is present for self and writable via PATCH.
testproject/users/migrations/0007_user_timezone.py Adds the DB column for the testproject concrete User model.
Dockerfile Removes a git safe.directory step that could abort in submodule builds.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@baseapp_auth/models.py`:
- Around line 103-109: The timezone CharField in the model currently accepts any
arbitrary string value without validation against IANA timezone standards. Add a
field-level validator to the timezone field that validates the input against a
list of valid IANA timezone names and rejects invalid values like "foo/bar"
before they are persisted to the database. You can implement this by either
adding a validators parameter with a custom validator function that checks
against a known list of IANA timezones, or by using Django's choices parameter
to constrain the field to only valid timezone values.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dfd4462a-60d0-4048-8e8b-e7ad51c336d9

📥 Commits

Reviewing files that changed from the base of the PR and between 56b6f13 and b8645ee.

📒 Files selected for processing (5)
  • Dockerfile
  • baseapp_auth/models.py
  • baseapp_auth/rest_framework/users/serializers.py
  • baseapp_auth/tests/integration/test_users.py
  • testproject/users/migrations/0007_user_timezone.py
💤 Files with no reviewable changes (1)
  • Dockerfile

Comment thread baseapp_auth/models.py
nossila and others added 3 commits June 18, 2026 01:05
Reject values that aren't valid IANA timezone names (e.g. "foo/bar") via a
field-level validator backed by zoneinfo.available_timezones(); blank is still
allowed. Includes a regression test for invalid input.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add timezone to the user edit form beside preferred_language, surface both as
changelist columns, and add a preferred_language list filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run the git safe.directory step on a clean working dir (before COPY) and widen
it to '*'. When built as a submodule, /usr/src/app/.git is a gitlink file
pointing outside the build context, which made git abort repo discovery if the
step ran from /usr/src/app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nossila and others added 2 commits June 18, 2026 01:26
Fold the validator AlterField (0008) back into the field's AddField (0007) so
the testproject has a single timezone migration instead of two.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@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: 2

🤖 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 `@baseapp_auth/tests/integration/test_users.py`:
- Around line 155-160: The test test_cant_update_timezone_with_invalid_value has
a weak assertion that only verifies the timezone is not set to the invalid value
"foo/bar", but does not ensure it remains unchanged. Store the original timezone
value from user_client.user.timezone before making the PATCH request, then after
refresh_from_db() and the 400 response assertion, replace the current inequality
check with an equality assertion that confirms the timezone matches the original
stored value, ensuring complete persistence validation.

In `@Dockerfile`:
- Around line 44-48: The RUN git config --global --add safe.directory '*'
command uses a global wildcard pattern that weakens Git's repository ownership
protection for the entire image. Replace the global wildcard setting with either
removing the command entirely (if no post-copy Git operations require it) or
scope the safe.directory trust to the specific repository path `/usr/src/app`
only, using git config --global --add safe.directory /usr/src/app instead. This
maintains the functionality for the current repo while avoiding unnecessary
global security exposure.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 35ff1f24-ac08-423c-a26f-7a7ef18d121d

📥 Commits

Reviewing files that changed from the base of the PR and between b8645ee and f340efc.

📒 Files selected for processing (5)
  • Dockerfile
  • baseapp_auth/admin.py
  • baseapp_auth/models.py
  • baseapp_auth/tests/integration/test_users.py
  • testproject/users/migrations/0007_user_timezone.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • testproject/users/migrations/0007_user_timezone.py
  • baseapp_auth/models.py

Comment on lines +155 to +160
def test_cant_update_timezone_with_invalid_value(self, user_client):
data = {"timezone": "foo/bar"}
r = user_client.patch(self.reverse(kwargs={"pk": user_client.user.pk}), data)
h.responseBadRequest(r)
user_client.user.refresh_from_db()
assert user_client.user.timezone != "foo/bar"

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 | 🟡 Minor | ⚡ Quick win

Assert exact persistence on invalid timezone update.

Line 160 currently checks != "foo/bar", which can still pass if the value changes to something else. Capture the original value before PATCH and assert it is unchanged after the 400 response.

Suggested test hardening
 def test_cant_update_timezone_with_invalid_value(self, user_client):
+    previous_timezone = user_client.user.timezone
     data = {"timezone": "foo/bar"}
     r = user_client.patch(self.reverse(kwargs={"pk": user_client.user.pk}), data)
     h.responseBadRequest(r)
     user_client.user.refresh_from_db()
-    assert user_client.user.timezone != "foo/bar"
+    assert user_client.user.timezone == previous_timezone
🤖 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 `@baseapp_auth/tests/integration/test_users.py` around lines 155 - 160, The
test test_cant_update_timezone_with_invalid_value has a weak assertion that only
verifies the timezone is not set to the invalid value "foo/bar", but does not
ensure it remains unchanged. Store the original timezone value from
user_client.user.timezone before making the PATCH request, then after
refresh_from_db() and the 400 response assertion, replace the current inequality
check with an equality assertion that confirms the timezone matches the original
stored value, ensuring complete persistence validation.

Comment thread Dockerfile
Comment on lines +44 to +48
# Trust all repo paths for git, using '*' so it covers the submodule case. Run it BEFORE
# the COPY so it executes on a clean working dir: when this repo is built as a submodule,
# the copied /usr/src/app/.git is a gitlink file pointing outside the build context, which
# makes git abort repo discovery (even for `config --global`) if run from /usr/src/app.
RUN git config --global --add safe.directory '*'

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

Avoid global safe.directory='*'; scope trust to this repo path only.

On Line 48, trusting * globally weakens Git’s repository ownership protection for the entire image. Prefer either removing this setting (if no post-copy Git ops need it) or scoping to /usr/src/app only.

Suggested hardening
-RUN git config --global --add safe.directory '*'
+RUN git config --global --add safe.directory /usr/src/app
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Trust all repo paths for git, using '*' so it covers the submodule case. Run it BEFORE
# the COPY so it executes on a clean working dir: when this repo is built as a submodule,
# the copied /usr/src/app/.git is a gitlink file pointing outside the build context, which
# makes git abort repo discovery (even for `config --global`) if run from /usr/src/app.
RUN git config --global --add safe.directory '*'
# Trust all repo paths for git, using '*' so it covers the submodule case. Run it BEFORE
# the COPY so it executes on a clean working dir: when this repo is built as a submodule,
# the copied /usr/src/app/.git is a gitlink file pointing outside the build context, which
# makes git abort repo discovery (even for `config --global`) if run from /usr/src/app.
RUN git config --global --add safe.directory /usr/src/app
🤖 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 `@Dockerfile` around lines 44 - 48, The RUN git config --global --add
safe.directory '*' command uses a global wildcard pattern that weakens Git's
repository ownership protection for the entire image. Replace the global
wildcard setting with either removing the command entirely (if no post-copy Git
operations require it) or scope the safe.directory trust to the specific
repository path `/usr/src/app` only, using git config --global --add
safe.directory /usr/src/app instead. This maintains the functionality for the
current repo while avoiding unnecessary global security exposure.

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