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.
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Resolves #150.
Plan
Implementation Plan: Show Linked Project on Post Details Page & Expose in API
1. Add
project_uidtoPostOutschemaFile:
devplacepy/schemas/content.py(lines 75–85)project_uid: Optional[int] = Nonefield toPostOutclass._Outbase if listed; add explicit field).2. Create a project resolution helper
File:
devplacepy/templating.py(or a new utility module)get_project_by_uid(project_uid: int) -> Optional[dict]that queries theprojectstable foruid,name,slug.uid,name,slug,url(constructed using existing project detail route, e.g.,url_for('project.view', slug=slug)).3. Update
PostDetailOutandFeedItemOutschemasFiles:
devplacepy/schemas/listings.pyproject: Optional[dict] = Nonefield to bothPostDetailOutandFeedItemOut.uid,name,url.4. Wire project info into
load_detail()anddetail_context()File:
devplacepy/content.pyload_detail(line ~654): after loading the post, ifpost.project_uidis set, callget_project_by_uid()and addprojectto the returned dict.detail_context(line ~492): pass theprojectdict fromload_detailinto the context.5. Wire project info into feed
enrich_items()File:
devplacepy/content.py(line ~697)enrich_items, if the post has a non‑noneproject_uid, resolve the project info via the helper and attach it to the item’sprojectfield (or to thePostOutequivalent in the feed item).6. Update post detail template
File:
devplacepy/templates/posts/detail.html(or similar)7. Update feed card template (optional but consistent)
File:
devplacepy/templates/feed/_card.htmlor similar8. Expose project in DevRant API
File:
devplacepy/services/devrant/serializers.py(line ~46)serialize_rantto includeproject_uidand aprojectdict (uid, name, url) when the rant’sproject_uidis set.routers/devrant/rants.pyline 98) to respect the incomingproject_uidfrom the request (currently hardcodedNone). The form data already carries it; pass it through.9. Add test coverage
Files:
tests/api/posts/create.pytests/api/posts/detail.py(new or existing)tests/api/devrant/rants.pytests/e2e/posts/detail.pyChanges:
project_uid(create a project first or use a seeded one).projectinfo when the post has a linked project.projectdata.10. (Optional) Add
project_uidto edit routeFile:
devplacepy/routers/posts.pyline 231–235project_uidto the list of updatable fields inedit_post. This fills a gap identified in the investigation but is not strictly required by the ticket.Definition of Done
PostOutschema includesproject_uidfield.PostDetailOutandFeedItemOutschemas include an optionalprojectdict (uid,name,url).get_project_by_uid()exists and resolves project info correctly.load_detail()returns project info anddetail_context()passes it to the template.serialize_rantincludesproject_uidandprojectdict.project_uid: None– it passes the incoming value.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/).Opened automatically by Typosaurus.