CommunityPro / CommunityPro/community-pro-api

Content: author endpoints + server-side HTML sanitization (Phase 4.2)

Open
#3 0 comments 0 reactions 0 assignees View on GitHub
content
Dominant language
C#
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Scope
Author-facing endpoints on the Content module. Any **active** member can write; authors can only touch their own posts.

| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | `/posts/mine` | active member | paginated, all statuses, author only |
| POST | `/posts/mine` | active member | create draft |
| PUT | `/posts/{id}` | active member | edit own Draft/Rejected post (autosave target — must be cheap) |
| POST | `/posts/{id}/submit` | active member | Draft → Submitted |

## Sanitization
On submit, produce `ContentHtml` from the TipTap payload server-side using [HtmlSanitizer](https://github.com/mganss/HtmlSanitizer). Store both: `ContentJson` for re-editing, sanitized `ContentHtml` as the only thing public pages ever render. **Never trust or render raw author HTML.**

## Validation
Title/excerpt length caps, tag whitelist + max count, cover image URL must be an allowed image host (see `MemberProfileService.IsAllowedAvatarHttpsUrl` for the pattern and host list).

## Error codes
`content.not_found`, `content.not_author`, `content.invalid_state`, `content.invalid_post`

## Dependencies
Blocked by #2 (Post entity + workflow).

## Acceptance criteria
- [ ] Non-author gets `content.not_author` (404-shaped, no existence leak, matching project convention)
- [ ] Editing a Submitted/Published post fails with `content.invalid_state`
- [ ] Submit sanitizes: script tags, event handlers, javascript: URLs stripped (tests with hostile payloads)
- [ ] Pending (non-active) members are rejected by the policy
- [ ] xUnit coverage per endpoint

### Conventions (project-wide, non-negotiable)
- .NET 9, records for immutable shapes, file-scoped namespaces, primary constructors where they read well. Minimal-API endpoints grouped per module via `IEndpointModule.MapEndpoints`.
- `Result` (SharedKernel) instead of exception-driven control flow. Endpoint results map failures to ProblemDetails with the stable error codes listed above — the frontend keys off them.
- Module owns its EF Core `DbContext` mapped to its own Postgres schema. Modules never reference each other's internals — cross-module needs go through a public contract interface or an in-process domain event (`IEventPublisher`).
- All external calls (GitHub, Stripe, Brevo, Cloudinary, Meilisearch) behind interfaces owned by the consuming module.
- Every list endpoint paginated (offset is fine). xUnit tests in `tests/CommunityPro.Tests//` following the existing harness patterns (see `Members/MembersTestHarness.cs`).

Contributor guide

No contributing guide indexed for this repository

Research direction

First inspect the Content module's existing endpoint and workflow patterns, then the Post entity and workflow from dependency #2. Use the Members test harness at tests/CommunityPro.Tests/Members/MembersTestHarness.cs as the named testing reference and add xUnit coverage for each endpoint, including hostile TipTap payloads. Done means the listed authorization, state, validation, sanitization, error-code, and pagination criteria pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, html, postgresql
Domain
api, backend, security, testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
56/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.