Fix #150: Show linked project on post details page and expose in API #151

Open
typosaurus wants to merge 2 commits from typosaurus/ticket-150 into master
Collaborator

Resolves #150.

Plan

Implementation Plan: Show Linked Project on Post Details Page & Expose in API

1. Add project_uid to PostOut schema

File: devplacepy/schemas/content.py (lines 75–85)

  • Add project_uid: Optional[int] = None field to PostOut class.
  • Ensure it is included in serialization (already part of _Out base if listed; add explicit field).

2. Create a project resolution helper

File: devplacepy/templating.py (or a new utility module)

  • Implement get_project_by_uid(project_uid: int) -> Optional[dict] that queries the projects table for uid, name, slug.
  • Return a dict with keys: uid, name, slug, url (constructed using existing project detail route, e.g., url_for('project.view', slug=slug)).
  • Register as a Jinja global if needed for templates, but primarily for backend context building.

3. Update PostDetailOut and FeedItemOut schemas

Files: devplacepy/schemas/listings.py

  • Add a nested project: Optional[dict] = None field to both PostDetailOut and FeedItemOut.
  • The nested dict should contain uid, name, url.

4. Wire project info into load_detail() and detail_context()

File: devplacepy/content.py

  • In load_detail (line ~654): after loading the post, if post.project_uid is set, call get_project_by_uid() and add project to the returned dict.
  • In detail_context (line ~492): pass the project dict from load_detail into the context.

5. Wire project info into feed enrich_items()

File: devplacepy/content.py (line ~697)

  • For each item in enrich_items, if the post has a non‑none project_uid, resolve the project info via the helper and attach it to the item’s project field (or to the PostOut equivalent in the feed item).
  • This ensures the feed API returns project data when requested.

6. Update post detail template

File: devplacepy/templates/posts/detail.html (or similar)

  • After the post content, add a conditional block:
    {% if project %}
      <a href="{{ project.url }}" class="project-link">Project: {{ project.name }}</a>
    {% endif %}
    

7. Update feed card template (optional but consistent)

File: devplacepy/templates/feed/_card.html or similar

  • Add the same conditional project link, placed near the topic or timestamp line.

8. Expose project in DevRant API

File: devplacepy/services/devrant/serializers.py (line ~46)

  • Modify serialize_rant to include project_uid and a project dict (uid, name, url) when the rant’s project_uid is set.
  • Also: update the create rant endpoint (routers/devrant/rants.py line 98) to respect the incoming project_uid from the request (currently hardcoded None). The form data already carries it; pass it through.

9. Add test coverage

Files:

  • tests/api/posts/create.py
  • tests/api/posts/detail.py (new or existing)
  • tests/api/devrant/rants.py
  • tests/e2e/posts/detail.py

Changes:

  • In post creation tests, modify some fixtures to pass a valid project_uid (create a project first or use a seeded one).
  • Add a test that verifies the post detail API response contains project info when the post has a linked project.
  • Add a test that verifies the post details page renders the project link (E2E test with Playwright).
  • Add a test that verifies the DevRant rant serialization includes project data.
  • Ensure all new tests pass and existing tests are not broken.

10. (Optional) Add project_uid to edit route

File: devplacepy/routers/posts.py line 231–235

  • If time permits, add project_uid to the list of updatable fields in edit_post. This fills a gap identified in the investigation but is not strictly required by the ticket.

Definition of Done

  • PostOut schema includes project_uid field.
  • PostDetailOut and FeedItemOut schemas include an optional project dict (uid, name, url).
  • A helper get_project_by_uid() exists and resolves project info correctly.
  • load_detail() returns project info and detail_context() passes it to the template.
  • Post details template shows a clickable project link when a project is linked.
  • serialize_rant includes project_uid and project dict.
  • DevRant create rant endpoint no longer hardcodes project_uid: None – it passes the incoming value.
  • At least one new test per layer (API, E2E, DevRant) exercises a post with a linked project and verifies the data is present.
  • Running pip install -e '.[dev]' -q && python -m pytest {test_files} passes (where {test_files} includes all relevant test files, e.g., tests/api/ tests/e2e/ tests/units/).
  • No regressions in existing test suite (all previous post, feed, and rant tests still pass).

Opened automatically by Typosaurus.

Resolves #150. ## Plan ## Implementation Plan: Show Linked Project on Post Details Page & Expose in API ### 1. Add `project_uid` to `PostOut` schema **File:** `devplacepy/schemas/content.py` (lines 75–85) - Add `project_uid: Optional[int] = None` field to `PostOut` class. - Ensure it is included in serialization (already part of `_Out` base if listed; add explicit field). ### 2. Create a project resolution helper **File:** `devplacepy/templating.py` (or a new utility module) - Implement `get_project_by_uid(project_uid: int) -> Optional[dict]` that queries the `projects` table for `uid`, `name`, `slug`. - Return a dict with keys: `uid`, `name`, `slug`, `url` (constructed using existing project detail route, e.g., `url_for('project.view', slug=slug)`). - Register as a Jinja global if needed for templates, but primarily for backend context building. ### 3. Update `PostDetailOut` and `FeedItemOut` schemas **Files:** `devplacepy/schemas/listings.py` - Add a nested `project: Optional[dict] = None` field to both `PostDetailOut` and `FeedItemOut`. - The nested dict should contain `uid`, `name`, `url`. ### 4. Wire project info into `load_detail()` and `detail_context()` **File:** `devplacepy/content.py` - In `load_detail` (line ~654): after loading the post, if `post.project_uid` is set, call `get_project_by_uid()` and add `project` to the returned dict. - In `detail_context` (line ~492): pass the `project` dict from `load_detail` into the context. ### 5. Wire project info into feed `enrich_items()` **File:** `devplacepy/content.py` (line ~697) - For each item in `enrich_items`, if the post has a non‑none `project_uid`, resolve the project info via the helper and attach it to the item’s `project` field (or to the `PostOut` equivalent in the feed item). - This ensures the feed API returns project data when requested. ### 6. Update post detail template **File:** `devplacepy/templates/posts/detail.html` (or similar) - After the post content, add a conditional block: ```html {% if project %} <a href="{{ project.url }}" class="project-link">Project: {{ project.name }}</a> {% endif %} ``` ### 7. Update feed card template (optional but consistent) **File:** `devplacepy/templates/feed/_card.html` or similar - Add the same conditional project link, placed near the topic or timestamp line. ### 8. Expose project in DevRant API **File:** `devplacepy/services/devrant/serializers.py` (line ~46) - Modify `serialize_rant` to include `project_uid` and a `project` dict (uid, name, url) when the rant’s `project_uid` is set. - **Also:** update the create rant endpoint (`routers/devrant/rants.py` line 98) to respect the incoming `project_uid` from the request (currently hardcoded `None`). The form data already carries it; pass it through. ### 9. Add test coverage **Files:** - `tests/api/posts/create.py` - `tests/api/posts/detail.py` (new or existing) - `tests/api/devrant/rants.py` - `tests/e2e/posts/detail.py` **Changes:** - In post creation tests, modify some fixtures to pass a valid `project_uid` (create a project first or use a seeded one). - Add a test that verifies the post detail API response contains `project` info when the post has a linked project. - Add a test that verifies the post details page renders the project link (E2E test with Playwright). - Add a test that verifies the DevRant rant serialization includes `project` data. - Ensure all new tests pass and existing tests are not broken. ### 10. (Optional) Add `project_uid` to edit route **File:** `devplacepy/routers/posts.py` line 231–235 - If time permits, add `project_uid` to the list of updatable fields in `edit_post`. This fills a gap identified in the investigation but is not strictly required by the ticket. --- ### Definition of Done - [ ] `PostOut` schema includes `project_uid` field. - [ ] `PostDetailOut` and `FeedItemOut` schemas include an optional `project` dict (`uid`, `name`, `url`). - [ ] A helper `get_project_by_uid()` exists and resolves project info correctly. - [ ] `load_detail()` returns project info and `detail_context()` passes it to the template. - [ ] Post details template shows a clickable project link when a project is linked. - [ ] `serialize_rant` includes `project_uid` and `project` dict. - [ ] DevRant create rant endpoint no longer hardcodes `project_uid: None` – it passes the incoming value. - [ ] At least one new test per layer (API, E2E, DevRant) exercises a post with a linked project and verifies the data is present. - [ ] Running `pip install -e '.[dev]' -q && python -m pytest {test_files}` passes (where `{test_files}` includes all relevant test files, e.g., `tests/api/ tests/e2e/ tests/units/`). - [ ] No regressions in existing test suite (all previous post, feed, and rant tests still pass). Opened automatically by Typosaurus.
typosaurus added 2 commits 2026-07-28 15:33:43 +02:00
ticket #150 attempt 2
Some checks failed
DevPlace CI / test (pull_request) Failing after 55m28s
f44e3d1db8
Some checks failed
DevPlace CI / test (pull_request) Failing after 55m28s
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin typosaurus/ticket-150:typosaurus/ticket-150
git checkout typosaurus/ticket-150
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#151
No description provided.