Skip to content

feat(2492): wire public profile to real user data - #2536

Open
ycanales wants to merge 2 commits into
julia/contribution-bio-contentfrom
cy/2492-user-profile-public-view
Open

feat(2492): wire public profile to real user data#2536
ycanales wants to merge 2 commits into
julia/contribution-bio-contentfrom
cy/2492-user-profile-public-view

Conversation

@ycanales

@ycanales ycanales commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Issue: #2492

Summary & Context

Wires the public-facing v3 profile page (/users/me/) to real user data instead of the demo scaffolding: renders the header (name, avatar, member-since, role, country flag), the profile-link buttons, the Bio card, and the Achievements / Badges empty-state cards, matching the Figma. Sections with no data are hidden.

This PR stacks on cy/2447-profile-visibility (#2517) and contains only the public-view commit. Will be retargeted to develop once #2517 merges.

Changes

  • Replace the demo-data get_v3_context_data with get_v3_public_context + get_v3_profile_link_buttons: the header is built from real user data (display name, avatar, year_joined, role, country flag).
  • Profile-link buttons are built from user.profile_links: only populated links render, email becomes a mailto:, the row ends with Share, and there is no Edit Profile in the public view.
  • Restrict link hrefs to http(s) via _safe_web_url (scheme-less becomes https; javascript: / data: dropped) to avoid stored XSS from unvalidated link values.
  • Bio card renders an empty state ("This user hasn't added a bio yet."); the view reads getattr(user, "biography", ""), so it shows the bio automatically once Story 2458: Webpage Integration: Edit User Profile - Bio and tagline #2502 lands. Updated, bio card renders saved bio and empty state if applicable.
  • Achievements and Badges always render as minimal empty-state cards ("No achievements earned yet." / "No badges unlocked yet." + a Learn CTA) via a new _empty_state_card.html.
  • Hide the GitHub activity, mailing-list, and posts sections when they have no data.
  • Tests: users/tests/test_v3_profile_public.py (header, links, unsafe-scheme, empty bio, always-on achievements/badges).

Update:

  • Added separate views for /users/me/ and a simple /users/:id/ for the public view, which will be improved in Webpage Integration: Public Profile Routing #2548
  • There are subtle differences between this (the public view) and the non-editable view of my own profile (/users/me), this issue is focused on the public profile view.

How to test

Covers the public profile page at /users/<id>/: what a visitor (logged in
or anonymous) sees when they look at someone else's profile.

The v3 flag needs to be on. Django admin → Waffle → Flagsv3
tick Everyone, save.

You need at least two accounts:

  • Owner — the profile you'll be viewing.
  • Visitor — a second account to check the logged-in-but-not-you case. Anonymous (logged out) covers the main case.

Where to set profile data

Most of what's on the page is self-service — log in as the Owner and go
to /users/me/?edit=true:

Field Where
Display name, tagline, bio, avatar Edit profile form
Country (flag) Edit profile form
GitHub / Website / Email / Slack links Edit profile form, "Profile Links" section
Role dropdown + "No Public Role" opt-out Edit profile form — only shown if the account already holds a library role (see below)

A few things are staff-only, set from Django admin on the user's own
change page (/admin/users/user/<id>/change/):

Field Admin field Notes
C++ Alliance title (CEO, CTO, Board Member, etc.) "C++ Alliance title" (internal_role), under Personal info Users can never self-assign this
Avatar (alternate to self-service upload) "Profile image"
Deactivate an account uncheck "Active" used for the 404 case below

Test cases

Open profiles anonymously (logged out) unless a step says otherwise.

  1. Header renders real data
  2. Role badge
  • Set a C++ Alliance title (admin) or a library role (self-service, once
    eligible) → the badge appears in the header with that label.
  • No role set → no badge element at all (not an empty one).
  • Opt-out asymmetry: on the Owner's edit page, select "No Public
    Role"
    and save.
    • Visiting the Owner's own /users/<id>/ (as the owner or anonymously)
      still shows their role — the profile page is exempt from the opt-out.
    • The role should be hidden everywhere else the app shows it (e.g. the
      news feed's user card), if that surface is reachable in this
      environment.

3. Bio

  • Rich text: set a bio with bold, italic, a list, and a link → all
    render as real HTML (not literal **/*/- characters).
  • No bio set → the section still renders, showing the empty-state message
    "This user hasn't added a bio yet." rather than nothing.
  • Underline is not expected to work — bio is Markdown, which has no
    underline syntax. Not a bug if it's missing.

4. Profile links

  • Set all four (GitHub, Website, Email, Slack) → four buttons render, plus
    Share, in that order.
  • Leave one or more unset → only the set ones render (no empty/placeholder
    buttons). Email link should be a mailto: link.

5. Sections with no data are hidden

  • On an account with no bio, links, avatar, country, role, or library
    contributions: the page shows the bio card (with its empty state) and
    nothing else — no empty panels, headings, or placeholder cards for
    GitHub activity, badges, achievements, or posts.
  • Same check for library contributions specifically: an account with no
    library role shows no Author/Maintainer/Contributor rows in the bio card.

6. Share vs. Edit Profile

  • Anonymous visitor on anyone's profile → header button is Share (not
    Edit Profile).
  • Logged in as Visitor, looking at Owner's profile → still Share.
  • Logged in as Owner, looking at their own /users/<id>/ URL → button
    is Edit Profile instead. (This is the one case where the button
    depends on who's looking, not just which URL.)

7. Nothing owner-facing leaks to the public

On any profile you don't own (anonymous or as Visitor), confirm none of the
following appear anywhere on the page: Edit Profile, Account
connections
, Save Changes, Delete Account, Commit Email,
Email Preferences — and there's no form, input, or dropdown anywhere on
the page. It should read as a static page.

8. No-JS rendering

  • Disable JavaScript in the browser (or use a reader/inspection mode that
    doesn't execute it) and reload a populated profile.
  • Header, role, bio formatting, and the link buttons should all still be
    present — this page is server-rendered, not client-assembled.

9. Unknown / deactivated account

  • Visit a profile URL for an id that doesn't exist (e.g. a very large
    number) → 404, not a blank or broken page.
  • Deactivate an account from Django admin (uncheck "Active") → its profile
    URL also 404s.

Out of scope for this ticket

  • Badge-awarding logic and achievement notifications
  • GitHub activity feed showing real data (only the UI shell is in scope
    here; needs an OAuth scope spike)
  • Bio moderation queue/UI
  • Mailing list preferences
  • Delete account / danger zone

PRs that should land first (so the public view can show complete data)

This PR renders today (with empty/stub states) but depends on fields owned by other pending PRs. Recommended order:

  1. feat(2447): implement profile edit (visibility, acc. details, email prefs) #2517 feat(2447): implement profile edit (visibility, acc. details, email prefs). The direct stack base of this PR.
  2. Story 2458: Webpage Integration: Edit User Profile - Bio and tagline #2502 Story 2458: Edit User Profile - Bio and tagline. Adds User.biography; required for the Bio to render (empty state until then).
  3. ✅ (open, rebased) Story 2443: User Profile Integration – User Roles  #2527 Story 2443: User Profile - User Roles. Adds the real role model; the header shows the User.role stub ("Contributor") until then.
  4. ✅ (open, rebased) Story 2452: User Profile Integration – Contribution Bio #2533 Story 2452: User Profile - Contribution Bio. Adds User.get_contributor_data() for the Bio card's contributor section (needs a one-line wiring here once merged).
  5. Story 2448 - Webpage Integration Edit User Profile Avatar #2523 Story 2448: Edit User Profile Avatar.

Risks & Considerations

Screenshots

Empty

image

With Bio, Profile links and Country

image

With library contributions

image

With avatar

image

Self-review Checklist

  • Tag at least one team member from each team to review this PR
  • Link this PR to the related GitHub Project ticket

Frontend

  • UI implementation matches Figma design
  • Tested in light and dark mode (light verified; design tokens used, dark not explicitly checked)
  • Responsive / mobile verified
  • Accessibility checked (keyboard navigation, etc.)
  • Ensure design tokens are used for colors, spacing, typography, etc. - No hardcoded values
  • Test without JavaScript (the public view is server-rendered; verified it renders with JS disabled)
  • No console errors or warnings

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e86e4ad-3c52-4893-a213-36ee96a4c8eb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cy/2492-user-profile-public-view

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@julhoang julhoang linked an issue Jul 21, 2026 that may be closed by this pull request
7 tasks
@ycanales
ycanales marked this pull request as draft July 23, 2026 18:25
@ycanales

Copy link
Copy Markdown
Collaborator Author

Marked as draft until updated with all the changes from the related PRs.

@ycanales

ycanales commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Merged latest changes from develop through cy/2447-profile-visibility branch.
You might encounter a problem with the migrations due to the renaming after merging, for a quick fix try:

UPDATE django_migrations SET name='0024_user_country_user_hide_badges_and_more'
WHERE app='users' AND name='0023_user_country_user_hide_badges_and_more';

This brings the bio and tagline, however, I'm not sure where the tagline it should appear by looking at the figma design @henryajisegiri :

Image

(This is how it looks in the edit page:)

Image

Update: as discussed in a recent daily, this is shown currently in the homepage for library authors, not in the public profile.

Base automatically changed from cy/2447-profile-visibility to develop July 28, 2026 17:27
@ycanales
ycanales force-pushed the cy/2492-user-profile-public-view branch from 001bae0 to 12070f8 Compare July 29, 2026 01:05
@ycanales
ycanales changed the base branch from develop to julia/contribution-bio-content July 29, 2026 13:58
@ycanales
ycanales marked this pull request as ready for review July 29, 2026 14:22
@julhoang
julhoang self-requested a review July 29, 2026 17:06
Extract V3UserProfileContextMixin out of CurrentUserProfileView so the new
public route and /users/me/ share the same read-only profile context; the
only difference is the trailing header button (Edit Profile for the owner,
Share for a visitor). Wire up PublicUserProfileView, the route, and
User.get_absolute_url(); deactivated accounts 404 instead of staying
reachable.

Serve `role` instead of `public_role` to visitors: `public_role`
deliberately ignores the hide-public-role opt-out so owners still see their
own role, which meant the public route was leaking a role a user had
explicitly hidden.

Hide the achievements/badges cards (and their empty-state include) when
there's no data, matching the "no empty/null UI rendered" acceptance
criteria over the Figma empty-panels comp. Drop the whole right column
when it would otherwise be empty, so the bio card takes full width instead
of sitting next to a blank gap.

Normalize edit_profile_url() to "?edit=true" for consistent querystring
casing.
@jlchilders11
jlchilders11 self-requested a review July 31, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Webpage Integration: User Profile (Public View)

1 participant