forked from retoor/devplacepy
feat: add reactions, bookmarks, polls modules with session remember config
Add three new feature modules (reactions, bookmarks, polls) with corresponding database tables, indexes, and router registrations. Introduce `SESSION_MAX_AGE_REMEMBER` config for extended session duration, add `get_unread_messages` template global, and include operational defaults for rate limiting and session settings in `site_settings`.
This commit is contained in:
@@ -59,8 +59,11 @@ devplacepy/
|
||||
| `/projects` | Project listing, creation |
|
||||
| `/profile` | Profile view, editing |
|
||||
| `/messages` | Direct messaging |
|
||||
| `/notifications` | Notification list, mark read |
|
||||
| `/notifications` | Notification list, mark read, live unread counts (`/notifications/counts`) |
|
||||
| `/votes` | Upvote/downvote on posts, comments, projects |
|
||||
| `/reactions` | Emoji reactions on posts, comments, gists, projects |
|
||||
| `/bookmarks` | Save/unsave content; `/bookmarks/saved` personal list |
|
||||
| `/polls` | Vote on post-attached polls |
|
||||
| `/follow` | Follow/unfollow users |
|
||||
| `/leaderboard` | Contributor ranking by total stars earned |
|
||||
| `/avatar` | Multiavatar proxy with in-memory cache |
|
||||
@@ -76,10 +79,17 @@ Member progression is driven by activity and peer recognition.
|
||||
|
||||
- **Stars** are the net vote score (`upvotes - downvotes`) on a post, project, or gist. A member's total stars is the sum across all their content and is the basis for ranking.
|
||||
- **XP and levels.** Members earn XP for contributing: posting (10), commenting (2), publishing a project (15) or gist (5), receiving an upvote (5), and gaining a follower (5). Each level requires 100 XP (`level = 1 + xp // 100`). The profile shows the current level and progress to the next.
|
||||
- **Badges** are awarded once per milestone: first post/comment/project/gist, 10 posts (Prolific), 25 stars (Rising Star), 100 stars (Star Author), 10 followers (Popular), and reaching levels 5 and 10. Badges render with an icon and description on the profile.
|
||||
- **Badges** are awarded once per milestone: first post/comment/project/gist, 10 posts (Prolific), 25 stars (Rising Star), 100 stars (Star Author), 10 followers (Popular), a 7-day activity streak (On Fire), and reaching levels 5 and 10. Badges render with an icon and description on the profile.
|
||||
- **Leaderboard** (`/leaderboard`) ranks the top 50 members by total stars (single page, no pagination); a member's own rank is shown on their profile.
|
||||
- **Contribution heatmap and streaks.** Each profile shows a 12-month activity heatmap and the current/longest daily streak, derived from post/comment/gist/project timestamps (no extra storage).
|
||||
- **Reward notifications** fire when a member levels up or earns a badge.
|
||||
|
||||
## Engagement
|
||||
|
||||
- **Emoji reactions** — a fixed palette of reactions on posts, comments, gists, and projects, separate from voting and carrying no ranking weight.
|
||||
- **Polls** — a post can carry a poll (question plus up to six options); results appear as live bars once the viewer votes, one vote per member.
|
||||
- **Bookmarks** — save posts, gists, projects, and news to a personal list at `/bookmarks/saved`.
|
||||
|
||||
XP awards are wired at the existing content-creation, vote, and follow hook points in the routers and centralized in `award_xp()` / `check_milestone_badges()` (`devplacepy/utils.py`). Existing accounts have their XP and levels backfilled once from prior activity at startup (`init_db()`).
|
||||
|
||||
## Configuration
|
||||
@@ -90,6 +100,23 @@ XP awards are wired at the existing content-creation, vote, and follow hook poin
|
||||
| `SECRET_KEY` | hardcoded fallback | Session signing key |
|
||||
| `DEVPLACE_VAPID_SUB` | `mailto:retoor@molodetz.nl` | Contact address in the VAPID JWT `sub` claim |
|
||||
|
||||
### Runtime settings
|
||||
|
||||
Operational behavior is tunable live from `/admin/settings` (stored in `site_settings`, no redeploy). The Operational group covers:
|
||||
|
||||
| Setting | Default | Effect |
|
||||
|---------|---------|--------|
|
||||
| `rate_limit_per_minute` | `60` | Mutating requests allowed per IP per window |
|
||||
| `rate_limit_window_seconds` | `60` | Rolling window for the request limit |
|
||||
| `news_service_interval` | `3600` | Seconds between news fetch cycles (min 60) |
|
||||
| `session_max_age_days` | `7` | Standard session cookie lifetime |
|
||||
| `session_remember_days` | `30` | Remember-me session cookie lifetime |
|
||||
| `registration_open` | `1` | When `0`, new sign-ups are rejected |
|
||||
| `maintenance_mode` | `0` | When `1`, non-admins see the maintenance page; admins retain access |
|
||||
| `maintenance_message` | scheduled-maintenance text | Message shown during maintenance |
|
||||
|
||||
Numeric values are floored to safe minimums so an invalid entry cannot lock out writes or stall services. Consumers read via `get_setting`/`get_int_setting`, which fall back to these defaults when a row is absent.
|
||||
|
||||
## Background Services
|
||||
|
||||
`devplacepy/services/` provides a generic async service framework. Services start on server boot, run at configurable intervals, and are gracefully cancelled on shutdown.
|
||||
@@ -202,7 +229,7 @@ All indexes are created via `CREATE INDEX IF NOT EXISTS` wrapped in try/except -
|
||||
|
||||
## Testing
|
||||
|
||||
- **274 tests** across 23 files: Playwright integration + unit tests
|
||||
- **419 tests** across 34 files: Playwright integration + in-process unit tests
|
||||
- Playwright (NOT pytest-playwright plugin - conflicts, uninstall it)
|
||||
- Server starts as subprocess on port 10501 with isolated temp database
|
||||
- Test users `alice_test` / `bob_test` seeded via HTTP at session start
|
||||
|
||||
Reference in New Issue
Block a user