Skip to content

feat(activity): allow showing private contributions on public profile#38391

Open
m5r wants to merge 7 commits into
go-gitea:mainfrom
m5r:show-private-activity
Open

feat(activity): allow showing private contributions on public profile#38391
m5r wants to merge 7 commits into
go-gitea:mainfrom
m5r:show-private-activity

Conversation

@m5r

@m5r m5r commented Jul 9, 2026

Copy link
Copy Markdown

Fixes #21585

Adds an opt-in user setting (defaults to off): "Include private contributions on my profile". When enabled:

  • The profile heatmap counts the user's private-repo activity for all viewers (web /{username}/-/heatmap and API /api/v1/users/{user}/heatmap, both go through GetUserHeatmapDataByUser), so the heatmap looks the same to the owner and to visitors.
  • The profile activity feed (general and day-filtered) shows per-day rollup rows ("5 contributions in private repositories Jul 9, 2026") for viewers who cannot see the underlying actions, placed at the bottom of each day's entries. Owners and admins keep seeing the real actions.
  • The flag is exposed in GET/PATCH /api/v1/user/settings as show_private_activity, next to hide_activity.

This is similar to GitHub's "Include private contributions on my profile" toggle, with per-day rollups instead of GitHub's per-month timeline summaries.

Design

  • For any viewer, a day's heatmap count equals its visible feed entries plus its rollup count for private-repository contributions within the heatmap window.
  • A viewer learns nothing beyond per-day counts, which the heatmap already exposes:
    • Rollup rows render a date only. No time of day, no tooltip.
    • Feed page spans snap to whole days, so pagination boundaries cannot reveal how private actions interleave with public ones within a day. A day's hidden actions all surface on the page showing that day's oldest visible action; consecutive pages decide their shared edge day with the same query, so per-page rollups still sum to the totals within the heatmap window.
  • Each rollup sorts by its day's midnight (server timezone, DST-safe) so it lands below the day's visible entries, and displays its day's noon so browser-local date rendering stays on the correct day for viewers within 12h of the server timezone.
  • Rollups count the user's private-repository actions within the heatmap's one-year window, aggregated in SQL with the same 15-minute bucket grouping the heatmap uses, so per-request work stays bounded regardless of how much activity a user has. Feed pages older than the window show no rollups, matching the heatmap they mirror. Rollups are also only shown while the heatmap is enabled (ENABLE_USER_HEATMAP).
  • keep_activity_private wins: with activity fully hidden, this setting has no effect (ActivityReadable short-circuits). Users with limited/private visibility stay hidden from viewers who cannot see their profile at all (IsUserVisibleToViewer).
  • Setting off (the default): behavior is byte-for-byte unchanged; nothing differs for any user until they opt in.
  • Prior art: Add activity visibility options #29306 attempted this with an All/None/Public visibility enum and was abandoned. This PR uses a plain boolean plus per-day rollups instead. Since the profile feed hides all private-repository actions from other viewers (collaborators and org teammates included), a plain per-day count of private actions matches what any viewer is missing, which resolves the partial-access edge case that stalled that PR.

Known limitation

The heatmap buckets days in the browser's timezone while the ?date= filter and the rollups use the server's, but this is a pre-existing mismatch (clicking a heatmap square near a day boundary can already show a feed that doesn't match the square). Rollup dates follow the existing browser-local display convention; viewers offset more than 12h from the server timezone can see an adjacent date.

Testing

  • Unit (models/activities/user_heatmap_test.go): heatmap visibility matrix including opted-in cases and the collaborator invariant; rollup partition tests (mid-day page boundaries, hidden actions interleaving visible ones, timestamp ties, out-of-range pages, day bucketing).
  • Integration (tests/integration/showprivateactivity_test.go): setting off/on, heatmap counts via web + API, rollup rows without leaking repo links, invalid dates, pages beyond the feed, owner's own view, keep_activity_private precedence, API settings round-trip including a null-field PATCH.
  • Manual: screenshots below.

Screenshots

  1. Settings toggle
1-settings-toggle
  1. anonymous profile with heatmap + rollups
2-heatmap-anon
  1. anonymous day view
3-day-placeholder
  1. logged-in owner view
4-owner-view

m5r added 4 commits July 9, 2026 21:24
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: m5r <mokhtar@mial.net>
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: m5r <mokhtar@mial.net>
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: m5r <mokhtar@mial.net>
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: m5r <mokhtar@mial.net>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 9, 2026
@github-actions github-actions Bot added the type/feature Completely new functionality. Can only be merged if feature freeze is not active. label Jul 9, 2026
@bircni

bircni commented Jul 12, 2026

Copy link
Copy Markdown
Member

did some cleanups

…ivate-activity

Signed-off-by: m5r <mokhtar@mial.net>
@m5r

m5r commented Jul 13, 2026

Copy link
Copy Markdown
Author

Thanks, I resolved the conflict that was present on routers/web/user/profile.go and updated the PR description to match your changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. type/feature Completely new functionality. Can only be merged if feature freeze is not active.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option for private contibutions to contribute to the public heatmap

3 participants