Fix #112: Expose level progress percentage in profile API response #127

Open
typosaurus wants to merge 1 commits from typosaurus/ticket-112 into master
Collaborator

Resolves #112.

Plan

Implementation Plan: Expose Level Progress in Profile API

Objective
Add derived fields xp_progress_pct (integer percentage toward next level) and xp_next_level (total XP required for next level) to GET /profile and GET /profile/{username} responses.

1. Schema Change
File: devplacepy/schemas/profile.py

  • In class ProfileOut (line 29–82), add two optional integer fields:
    xp_progress_pct: Optional[int] = None
    xp_next_level: Optional[int] = None

These fields are optional to avoid breaking existing consumers and because the value is computed at request time.

2. Route Handler Computation
File: devplacepy/routers/profile/index.py
profile_page() function (starting line 128). Locate the respond() call at line 383–445. Before that call, compute:

LEVEL_XP = 100  # constant from devplacepy/utils/rewards.py
xp = user.xp or 0
xp_progress_pct = xp % LEVEL_XP
xp_next_level = ((xp // LEVEL_XP) + 1) * LEVEL_XP

Include these values in the context dict passed to respond(). For example:

context["xp_progress_pct"] = xp_progress_pct
context["xp_next_level"] = xp_next_level

If user.xp is None, default to 0 for the computation.

3. Test Addition
File: tests/api/profile/index.py (add a new test function, e.g., test_profile_contains_xp_progress)

  • Create a test user with known XP (e.g., 250).
  • Perform GET /profile and GET /profile/{username}.
  • Assert that the JSON response contains xp_progress_pct and xp_next_level.
  • Assert that the values match the formula:
    • xp_progress_pct = 250 % 100 = 50
    • xp_next_level = ((250 // 100) + 1) * 100 = 300

Use the existing test infrastructure (e.g., test_client fixture and auth_headers).

4. Verification

  • Run the profile-specific test file:
    pip install -e '.[dev]' -q && python -m pytest tests/api/profile/index.py -v
    
  • Confirm all tests pass (0 failures, 0 errors).
  • Optional: run a broader subset (e.g., tests/api/) to ensure no regressions, but the primary verification is the command above.

Definition of Done

  • ProfileOut schema includes xp_progress_pct and xp_next_level fields.
  • /profile and /profile/{username} responses contain xp_progress_pct (0–99 integer) and xp_next_level (total XP for next level).
  • The new test test_profile_contains_xp_progress (or equivalent) exists and verifies the fields for at least one known XP value.
  • The command pip install -e '.[dev]' -q && python -m pytest tests/api/profile/index.py exits with code 0 and shows all tests passing. (Pre-existing Playwright-related failures in other test directories are unrelated and ignored for this change’s validation.)

Opened automatically by Typosaurus.

Resolves #112. ## Plan **Implementation Plan: Expose Level Progress in Profile API** **Objective** Add derived fields `xp_progress_pct` (integer percentage toward next level) and `xp_next_level` (total XP required for next level) to `GET /profile` and `GET /profile/{username}` responses. **1. Schema Change** *File*: `devplacepy/schemas/profile.py` - In class `ProfileOut` (line 29–82), add two optional integer fields: `xp_progress_pct: Optional[int] = None` `xp_next_level: Optional[int] = None` These fields are optional to avoid breaking existing consumers and because the value is computed at request time. **2. Route Handler Computation** *File*: `devplacepy/routers/profile/index.py` `profile_page()` function (starting line 128). Locate the `respond()` call at line 383–445. Before that call, compute: ```python LEVEL_XP = 100 # constant from devplacepy/utils/rewards.py xp = user.xp or 0 xp_progress_pct = xp % LEVEL_XP xp_next_level = ((xp // LEVEL_XP) + 1) * LEVEL_XP ``` Include these values in the context dict passed to `respond()`. For example: ```python context["xp_progress_pct"] = xp_progress_pct context["xp_next_level"] = xp_next_level ``` If `user.xp` is `None`, default to `0` for the computation. **3. Test Addition** *File*: `tests/api/profile/index.py` (add a new test function, e.g., `test_profile_contains_xp_progress`) - Create a test user with known XP (e.g., 250). - Perform `GET /profile` and `GET /profile/{username}`. - Assert that the JSON response contains `xp_progress_pct` and `xp_next_level`. - Assert that the values match the formula: - `xp_progress_pct` = 250 % 100 = 50 - `xp_next_level` = ((250 // 100) + 1) * 100 = 300 Use the existing test infrastructure (e.g., `test_client` fixture and `auth_headers`). **4. Verification** - Run the profile-specific test file: ```bash pip install -e '.[dev]' -q && python -m pytest tests/api/profile/index.py -v ``` - Confirm all tests pass (0 failures, 0 errors). - Optional: run a broader subset (e.g., `tests/api/`) to ensure no regressions, but the primary verification is the command above. **Definition of Done** - [ ] `ProfileOut` schema includes `xp_progress_pct` and `xp_next_level` fields. - [ ] `/profile` and `/profile/{username}` responses contain `xp_progress_pct` (0–99 integer) and `xp_next_level` (total XP for next level). - [ ] The new test `test_profile_contains_xp_progress` (or equivalent) exists and verifies the fields for at least one known XP value. - [ ] The command `pip install -e '.[dev]' -q && python -m pytest tests/api/profile/index.py` exits with code 0 and shows all tests passing. (Pre-existing Playwright-related failures in other test directories are unrelated and ignored for this change’s validation.) Opened automatically by Typosaurus.
typosaurus added 1 commit 2026-07-23 05:08:42 +02:00
ticket #112 attempt 1
Some checks failed
DevPlace CI / test (pull_request) Failing after 11s
6a6e6716b1
Some checks failed
DevPlace CI / test (pull_request) Failing after 11s
This pull request has changes conflicting with the target branch.
  • .dpc/verify_cache.json

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin typosaurus/ticket-112:typosaurus/ticket-112
git checkout typosaurus/ticket-112
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: retoor/devplacepy#127
No description provided.