From cd32478c2bb49eed10eb56f2f21db9f10a34b989 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Tue, 16 Dec 2025 18:00:57 -0500
Subject: [PATCH v1 3/3] Make public contributor profile opt-in

I'm not really sure if this is the right way to do this at all, so I
made it a separate patch. Basically, we probably don't want to just
suddenly have everybody with a user account at postgresql.org have a
public profile page. But, I don't know how it should work exactly --
both from a feature specification perspective and an implementation
perspective.

For one, we can't have all existing contributors not be displayed on the
recognized contributor page just because they didn't opt-in (which is
what I did here). But do we want all of them to get profiles without
first opting in?
---
 pgweb/account/forms.py                         |  3 +++
 .../migrations/0005_add_hidden_field.py        | 18 ++++++++++++++++++
 pgweb/contributors/models.py                   |  3 +++
 pgweb/contributors/views.py                    |  7 ++++++-
 pgweb/core/models.py                           |  3 +++
 templates/contributors/list.html               |  6 +++---
 6 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 pgweb/contributors/migrations/0005_add_hidden_field.py

diff --git a/pgweb/account/forms.py b/pgweb/account/forms.py
index fb3641b0..5e8002ed 100644
--- a/pgweb/account/forms.py
+++ b/pgweb/account/forms.py
@@ -161,6 +161,9 @@ class ContributorForm(forms.ModelForm):
     class Meta:
         model = Contributor
         exclude = ('ctype', 'lastname', 'firstname', 'user', )
+        widgets = {
+            'hidden': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
+        }
 
 
 class AddEmailForm(forms.Form):
diff --git a/pgweb/contributors/migrations/0005_add_hidden_field.py b/pgweb/contributors/migrations/0005_add_hidden_field.py
new file mode 100644
index 00000000..ad5799da
--- /dev/null
+++ b/pgweb/contributors/migrations/0005_add_hidden_field.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.2.8 on 2025-12-16 23:47
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contributors', '0004_alter_contributor_ctype'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='contributor',
+            name='hidden',
+            field=models.BooleanField(default=True, help_text='Hide your contributor profile from /community/contributors/[username]/', verbose_name='Hide public profile'),
+        ),
+    ]
diff --git a/pgweb/contributors/models.py b/pgweb/contributors/models.py
index afecf2be..592227ec 100644
--- a/pgweb/contributors/models.py
+++ b/pgweb/contributors/models.py
@@ -31,6 +31,9 @@ class Contributor(models.Model):
     contribution = models.TextField(null=True, blank=True,
                                     help_text='Only displayed for Major Contributors')
     user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
+    hidden = models.BooleanField(null=False, blank=False, default=True,
+                                 verbose_name='Hide public profile',
+                                 help_text='Check to hide your contributor profile. Uncheck to make it publicly accessible at /community/contributors/[username]/')
 
     send_notification = True
     purge_urls = ('/community/contributors/', )
diff --git a/pgweb/contributors/views.py b/pgweb/contributors/views.py
index 60fadbd9..767e7624 100644
--- a/pgweb/contributors/views.py
+++ b/pgweb/contributors/views.py
@@ -12,7 +12,12 @@ def completelist(request):
 
 
 def contributor_profile(request, username):
-    contributor = get_object_or_404(Contributor, user__username=username)
+    # Only show profiles that are not hidden
+    contributor = get_object_or_404(
+        Contributor,
+        user__username=username,
+        hidden=False
+    )
     return render_pgweb(request, 'community', 'contributors/profile.html', {
         'contributor': contributor,
     })
diff --git a/pgweb/core/models.py b/pgweb/core/models.py
index 54185917..2e88c04f 100644
--- a/pgweb/core/models.py
+++ b/pgweb/core/models.py
@@ -272,6 +272,9 @@ class UserProfile(models.Model):
     block_oauth = models.BooleanField(null=False, blank=False, default=False,
                                       verbose_name="Block OAuth login",
                                       help_text="Disallow login to this account using OAuth providers like Google or Microsoft.")
+    show_contributor_profile = models.BooleanField(null=False, blank=False, default=False,
+                                                   verbose_name="Show public contributor profile",
+                                                   help_text="Allow others to view your contributor profile at /community/contributors/[username]/")
 
 
 class UserSubmission(models.Model):
diff --git a/templates/contributors/list.html b/templates/contributors/list.html
index e713cee2..ef324572 100644
--- a/templates/contributors/list.html
+++ b/templates/contributors/list.html
@@ -32,7 +32,7 @@
     {%for c in t.contributor_set.all %}
      {%if t.detailed%}
       <tr>
-       <td>{% if c.user %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %} {%if t.showemail and c.email%}({{c.email|hidemail}}){%endif%}
+       <td>{% if c.user and not c.hidden %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %} {%if t.showemail and c.email%}({{c.email|hidemail}}){%endif%}
           {%if c.company %}
           <br/>
             {% if c.companyurl %}
@@ -49,13 +49,13 @@
      {%else%}
       {%if forloop.counter0|divisibleby:"2" %}
        <tr>
-        <td>{% if c.user %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
+        <td>{% if c.user and not c.hidden %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
         {%if forloop.last%}
         <td></td>
        </tr>
         {%endif%}
       {%else%}
-        <td>{% if c.user %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
+        <td>{% if c.user and not c.hidden %}<a href="/community/contributors/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{% else %}{{c.firstname}} {{c.lastname}}{% endif %}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
        </tr>
       {%endif%}
      {%endif%}
-- 
2.51.2

