public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v2] Introduce contributor badges
11+ messages / 3 participants
[nested] [flat]
* [PATCH v2] Introduce contributor badges
@ 2026-01-05 22:03 Christoph Berg <[email protected]>
0 siblings, 0 replies; 11+ messages in thread
From: Christoph Berg @ 2026-01-05 22:03 UTC (permalink / raw)
Previously only recognized contributors would be listed on the
contributor profiles page. In order to be able to recognize more people,
we introduce contributor badges. A badge is an award for a contribution
to PostgreSQL like "PostgreSQL 18 Contributor" (as per the contributor
list in the release notes), "PGConf.EU 2025 Speaker", "London PG Meetup
Organizer" or anything else that contributed to PostgreSQL in a positive
way. Ecosystem projects are invited to create badges, e.g. "Patroni
Contributor" or "Talking Postgres Guest".
Technically, we introduce a new "Badge" Django object in the
contributors namespace, to be administrated by the contributors team.
The existing "submit a new xxx" workflow is extended to include badges
which are tied to organisations like the existing other objects. New
badges are subject to moderation, but once approved, the submitting
organisation can edit the badge, most importantly to add more badge
holders.
Once an individual has been awarded a badge, they a can create a profile
page from their account page, and optionally supply a bio. This extends
the existing "Contributor" object in Django, but the page is put under
the /community/people/ tree to separate it from the existing
/community/contributors/ page which will be kept as the curated list of
recognized Major and Significant Contributors. (contributor.ctype is now
NULLable to prevent these entries from showing up on the contributors
page. If a user later contributes more, we can simply set the field to
the desired recognized contributors status.)
Badges are represented by pictures. These are currently stored
externally and will manually be added to the pgweb repo in media/badges/
(or be external URLs). We can move them into the database later if
manual management of them turns out to be too much work.
The badges workflow can be summarized as follows:
- An individual can submit the form to make an Organization
- A pgweb moderator can approve the organization
- An Organization manager can submit the form to make a new Badge
including contact info for requesting badge holder status
- A pgweb moderator can approve the new badge
- An Organization manager can add Badge holders (before or after
approval of the Badge but the holders won't show anywhere until
approved)
- The badge image is mailed to [email protected]
- The contributors team adds the image to git and updates the filename
stored in the Badge object
- A User can request a badge to become a Badge holder by emailing the
badge contact info on the Badge page
- A User who is a Badge holder can check a box to get a profile page
(makes a Contributor table entry, but we do not formally call them
contributors in the pages)
- The user can fill in their contributors bio to have it show up in
/community/people/<username>/.
New Pages introduced:
community/people/<username>/
-- profile page
community/people/
-- all badge holders and all badges
community/badge/<number>
-- badge info (image, description text, URL)
-- badge holders
-- badge request contact email address (hopefully if they added it)
Author: Melanie Plageman <[email protected]>
Author: Christoph Berg <[email protected]>
---
pgweb/account/urls.py | 2 +-
pgweb/account/views.py | 16 ++++-
pgweb/contributors/admin.py | 20 +++++-
pgweb/contributors/forms.py | 92 ++++++++++++++++++++++++++
pgweb/contributors/models.py | 48 ++++++++++++--
pgweb/contributors/views.py | 28 +++++++-
pgweb/core/forms.py | 2 +-
pgweb/urls.py | 5 +-
pgweb/util/contexts.py | 2 +
pgweb/util/moderation.py | 3 +-
templates/account/index.html | 7 +-
templates/account/userprofileform.html | 29 +++++++-
templates/contributors/badge.html | 45 +++++++++++++
templates/contributors/list.html | 27 ++++----
templates/contributors/people.html | 42 ++++++++++++
templates/contributors/profile.html | 64 ++++++++++++++++++
16 files changed, 402 insertions(+), 30 deletions(-)
create mode 100644 pgweb/contributors/forms.py
create mode 100644 templates/contributors/badge.html
create mode 100644 templates/contributors/people.html
create mode 100644 templates/contributors/profile.html
diff --git a/pgweb/account/urls.py b/pgweb/account/urls.py
index 12ad5955..a5621d22 100644
--- a/pgweb/account/urls.py
+++ b/pgweb/account/urls.py
@@ -26,7 +26,7 @@ urlpatterns = [
# Submitted items
re_path(r'^(?P<objtype>news)/(?P<item>\d+)/(?P<what>submit|withdraw)/$', pgweb.account.views.submitted_item_submitwithdraw),
- re_path(r'^(?P<objtype>news|events|products|organisations|services)/(?P<item>\d+|new)/$', pgweb.account.views.submitted_item_form),
+ re_path(r'^(?P<objtype>news|events|products|organisations|services|badges)/(?P<item>\d+|new)/$', pgweb.account.views.submitted_item_form),
re_path(r'^organisations/confirm/([0-9a-f]+)/$', pgweb.account.views.confirm_org_email),
# Markdown preview (silly to have in /account/, but that's where all the markdown forms are so meh)
diff --git a/pgweb/account/views.py b/pgweb/account/views.py
index 4f6cfa78..54fd7e3e 100644
--- a/pgweb/account/views.py
+++ b/pgweb/account/views.py
@@ -35,7 +35,7 @@ from pgweb.news.models import NewsArticle
from pgweb.events.models import Event
from pgweb.core.models import Organisation, UserProfile, ModerationNotification
from pgweb.core.models import OrganisationEmail
-from pgweb.contributors.models import Contributor
+from pgweb.contributors.models import Contributor, Badge
from pgweb.downloads.models import Product
from pgweb.profserv.models import ProfessionalService
@@ -126,6 +126,11 @@ objtypes = {
'submit_header': '<h3>Submit organisation</h3>Before submitting a new Organisation, please verify on the list of <a href="/account/orglist/">current organisations</a> if the organisation already exists. If it does, please contact the manager of the organisation to gain permissions.',
'editapproved': True,
},
+ 'badges': {
+ 'title': 'contributor badge',
+ 'objects': lambda u: Badge.objects.filter(org__managers=u),
+ 'editapproved': True,
+ },
}
@@ -143,11 +148,13 @@ def profile(request):
can_change_email = (request.user.password != OAUTH_PASSWORD_STORE)
# We may have a contributor record - and we only show that part of the
- # form if we have it for this user.
+ # form if we have it for this user. If the user has any badges awarded,
+ # offer them to create the contributor record.
try:
contrib = Contributor.objects.get(user=request.user.pk)
except Contributor.DoesNotExist:
contrib = None
+ badges = Badge.objects.filter(approved=True, holders=request.user.pk)
contribform = None
@@ -179,7 +186,9 @@ def profile(request):
log.info("User {} changed primary email from {} to {}".format(user.username, oldemail, user.email))
profileform.save()
- if contrib:
+ if badges and 'create_contributor_profile' in request.POST and request.POST['create_contributor_profile']:
+ contributor = Contributor.objects.create(user=user, firstname=user.first_name, lastname=user.last_name)
+ elif contrib:
contribform.save()
if secondaryemailform.cleaned_data.get('email1', ''):
sa = SecondaryEmail(user=request.user, email=secondaryemailform.cleaned_data['email1'], token=generate_random_token())
@@ -212,6 +221,7 @@ def profile(request):
'secondaryemailform': secondaryemailform,
'secondaryaddresses': secondaryaddresses,
'secondarypending': any(not a.confirmed for a in secondaryaddresses),
+ 'badges': badges,
'contribform': contribform,
})
diff --git a/pgweb/contributors/admin.py b/pgweb/contributors/admin.py
index cdb733b9..71024b36 100644
--- a/pgweb/contributors/admin.py
+++ b/pgweb/contributors/admin.py
@@ -1,7 +1,8 @@
from django import forms
from django.contrib import admin
+from django.db.models import Count
-from .models import Contributor, ContributorType
+from .models import Contributor, ContributorType, Badge
class ContributorAdminForm(forms.ModelForm):
@@ -18,9 +19,24 @@ class ContributorAdmin(admin.ModelAdmin):
autocomplete_fields = ['user', ]
list_display = ('__str__', 'user', 'ctype',)
list_filter = ('ctype',)
- ordering = ('firstname', 'lastname',)
+ ordering = ('ctype', 'lastname', 'firstname')
search_fields = ('firstname', 'lastname', 'user__username',)
+class BadgeAdmin(admin.ModelAdmin):
+ list_display = ('__str__', 'holders_count', 'approved', 'org',)
+ list_filter = ('approved', 'org',)
+ autocomplete_fields = ['holders', ]
+
+ def holders_count(self, obj):
+ return obj.holders_count
+
+ def get_queryset(self, request):
+ queryset = super().get_queryset(request)
+ queryset = queryset.annotate(holders_count=Count("holders"))
+ return queryset
+
+
admin.site.register(ContributorType)
admin.site.register(Contributor, ContributorAdmin)
+admin.site.register(Badge, BadgeAdmin)
diff --git a/pgweb/contributors/forms.py b/pgweb/contributors/forms.py
new file mode 100644
index 00000000..54dbdd23
--- /dev/null
+++ b/pgweb/contributors/forms.py
@@ -0,0 +1,92 @@
+from django import forms
+from django.forms import ValidationError
+from django.conf import settings
+
+from pgweb.core.models import Organisation
+from .models import Contributor, Badge
+from django.contrib.auth.models import User
+
+from pgweb.util.middleware import get_current_user
+from pgweb.mailqueue.util import send_simple_mail
+
+
+class UserModelMultipleChoiceField(forms.ModelMultipleChoiceField):
+ def label_from_instance(self, obj):
+ contributor = Contributor.objects.filter(user=obj.pk)
+ if contributor:
+ return f"{obj.first_name} {obj.last_name} ({obj.username}) <{obj.email}>"
+ else:
+ return f"{obj.first_name} {obj.last_name} ({obj.username}) <{obj.email}> (not a contributor yet)"
+
+
+class BadgeForm(forms.ModelForm):
+ form_intro = 'Contributor badges acknowledge people contributing time to the PostgreSQL project and the ecosystem around it. If you manage an organisation that gives people the opportunity to contribute (like volunteering or speaking at a conference, writing code for an extension, translating messages, helping others use PostgreSQL, organise the community, ...), you can issue a badge to acknowledge these contributions.'
+
+ remove_holder = UserModelMultipleChoiceField(required=False, queryset=None, label="Current badge holders", help_text="Select one or more users to remove")
+ add_holder = forms.CharField(required=False, help_text="Enter email addresses of postgresql.org user accounts to award the badge to. Separate multiple addresses with whitespace.")
+
+ fieldsets = [
+ {
+ 'id': 'general',
+ 'legend': 'Contributor Badge',
+ 'fields': ['org', 'badge', 'description', 'url', 'image', 'contact', ],
+ },
+ {
+ 'id': 'holders',
+ 'legend': 'Badge Holders',
+ 'fields': ['remove_holder', 'add_holder'],
+ },
+ ]
+
+ class Meta:
+ model = Badge
+ exclude = ('approved', 'sortorder', 'holders',)
+
+ def __init__(self, *args, **kwargs):
+ super(BadgeForm, self).__init__(*args, **kwargs)
+ if self.instance and self.instance.pk:
+ self.fields['remove_holder'].queryset = self.instance.holders
+ else:
+ del self.fields['remove_holder']
+ del self.fields['add_holder']
+ # remove the holders fieldset
+ self.fieldsets = [fs for fs in self.fieldsets if fs['id'] != 'holders']
+
+ def clean_add_holder(self):
+ if self.cleaned_data['add_holder']:
+ for u in self.cleaned_data['add_holder'].split():
+ # something was added - let's make sure the user exists
+ try:
+ User.objects.get(email=u.lower())
+ except User.DoesNotExist:
+ raise ValidationError("User with email %s not found" % u)
+
+ return self.cleaned_data['add_holder']
+
+ def save(self, commit=True):
+ model = super(BadgeForm, self).save(commit=False)
+
+ ops = []
+
+ if 'add_holder' in self.cleaned_data and self.cleaned_data['add_holder']:
+ for u in self.cleaned_data['add_holder'].split():
+ user = User.objects.get(email=u.lower())
+ model.holders.add(user)
+ ops.append('Added badge holder {}'.format(user.username))
+ if 'remove_holder' in self.cleaned_data and self.cleaned_data['remove_holder']:
+ for toremove in self.cleaned_data['remove_holder']:
+ model.holders.remove(toremove)
+ ops.append('Removed badge holder {}'.format(toremove.username))
+
+ if ops:
+ send_simple_mail(
+ settings.NOTIFICATION_FROM,
+ settings.NOTIFICATION_EMAIL,
+ "{0} modified {1}".format(get_current_user().username, model),
+ "The following changes were made to {}:\n\n{}".format(model, "\n".join(ops))
+ )
+
+ return model
+
+ def filter_by_user(self, user):
+ self.fields['org'].queryset = Organisation.objects.filter(managers=user, approved=True)
diff --git a/pgweb/contributors/models.py b/pgweb/contributors/models.py
index 342cddb2..f189a1a3 100644
--- a/pgweb/contributors/models.py
+++ b/pgweb/contributors/models.py
@@ -1,5 +1,8 @@
from django.db import models
from django.contrib.auth.models import User
+from pgweb.core.models import Organisation
+from pgweb.core.text import ORGANISATION_HINT_TEXT
+from pgweb.util.moderation import TwostateModerateModel
class ContributorType(models.Model):
@@ -19,22 +22,59 @@ class ContributorType(models.Model):
class Contributor(models.Model):
- ctype = models.ForeignKey(ContributorType, on_delete=models.CASCADE, verbose_name='Contributor Type')
- lastname = models.CharField(max_length=100, null=False, blank=False)
+ ctype = models.ForeignKey(ContributorType,
+ on_delete=models.CASCADE,
+ verbose_name='Contributor Type', null=True, blank=True)
firstname = models.CharField(max_length=100, null=False, blank=False)
+ lastname = models.CharField(max_length=100, null=False, blank=False)
email = models.EmailField(null=False, blank=True)
company = models.CharField(max_length=100, null=True, blank=True)
companyurl = models.URLField(max_length=100, null=True, blank=True, verbose_name='Company URL')
location = models.CharField(max_length=100, null=True, blank=True)
contribution = models.TextField(null=True, blank=True,
- help_text='This description is currently used for major contributors only')
+ help_text='Describe what you did in the PostgreSQL community')
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
send_notification = True
- purge_urls = ('/community/contributors/', )
+ purge_urls = ('/community/contributors/', '/community/people/', '/community/badge/')
def __str__(self):
return "%s %s" % (self.firstname, self.lastname)
class Meta:
ordering = ('lastname', 'firstname',)
+
+
+class Badge(TwostateModerateModel):
+ org = models.ForeignKey(Organisation, null=False, blank=False, verbose_name="Organisation", help_text=ORGANISATION_HINT_TEXT, on_delete=models.CASCADE)
+ badge = models.CharField(max_length=32, null=False, blank=False, unique=True, help_text='Title of this badge, e.g. "PGConf.EU 2025 Speaker".')
+ description = models.TextField(null=True, blank=True, help_text='What did the people do who contributed here?')
+ url = models.URLField(max_length=100, null=True, blank=True, verbose_name='Contribution URL', help_text='URL for this contribution, e.g. the conference homepage. (Leave blank when there is no URL.)')
+ image = models.CharField(max_length=100, verbose_name='Path to contribution image', null=True, blank=True, help_text="Badge images should be square (usually shown at 150x150 pixels). When left blank, the Slony logo will be used. External URLs work, but preferably the image should be hosted on postgresql.org. Mail the Contributors team to have your image added.")
+ contact = models.CharField(max_length=100, null=True, blank=True, verbose_name='Contact address', help_text='Contact address (email, URL, other) for people who want to be added as badge holder')
+ holders = models.ManyToManyField(User, blank=True)
+
+ sortorder = models.IntegerField(null=True, blank=True, default=100)
+
+ account_edit_suburl = 'badges'
+ moderation_fields = ['badge', 'description', 'url', 'image']
+
+ purge_urls = ('/community/people/', '/community/badge/')
+
+ def verify_submitter(self, user):
+ return (len(self.org.managers.filter(pk=user.pk)) == 1)
+
+ def __str__(self):
+ return self.badge
+
+ @property
+ def title(self):
+ return self.badge
+
+ class Meta:
+ ordering = ('sortorder', 'badge')
+
+ @classmethod
+ def get_formclass(self):
+ from pgweb.contributors.forms import BadgeForm
+ return BadgeForm
diff --git a/pgweb/contributors/views.py b/pgweb/contributors/views.py
index 45b8551e..4f920c38 100644
--- a/pgweb/contributors/views.py
+++ b/pgweb/contributors/views.py
@@ -1,6 +1,7 @@
+from django.shortcuts import get_object_or_404
from pgweb.util.contexts import render_pgweb
-from .models import ContributorType
+from .models import ContributorType, Contributor, Badge
def completelist(request):
@@ -8,3 +9,28 @@ def completelist(request):
return render_pgweb(request, 'community', 'contributors/list.html', {
'contributortypes': contributortypes,
})
+
+
+def peoplelist(request):
+ people = list(Contributor.objects.all())
+ badges = list(Badge.objects.filter(approved=True))
+ return render_pgweb(request, 'community', 'contributors/people.html', {
+ 'people': people,
+ 'badges': badges,
+ })
+
+
+def badge_view(request, badgeid):
+ badge = get_object_or_404(Badge, id=badgeid, approved=True)
+ return render_pgweb(request, 'community', 'contributors/badge.html', {
+ 'badge': badge,
+ })
+
+
+def profile(request, username):
+ contributor = get_object_or_404(Contributor, user__username=username)
+ badges = list(Badge.objects.filter(approved=True, holders=contributor.user))
+ return render_pgweb(request, 'community', 'contributors/profile.html', {
+ 'contributor': contributor,
+ 'badges': badges,
+ })
diff --git a/pgweb/core/forms.py b/pgweb/core/forms.py
index d73f3151..599f4bf7 100644
--- a/pgweb/core/forms.py
+++ b/pgweb/core/forms.py
@@ -13,7 +13,7 @@ from pgweb.util.misc import send_template_mail, generate_random_token
class OrganisationForm(forms.ModelForm):
new_form_intro = """<em>Note!</em> An organisation record is only needed to post news, events,
-products or professional services. In particular, it is <em>not</em> necessary to register an
+products, professional services or contributor badges. In particular, it is <em>not</em> necessary to register an
organisation in order to ask questions or otherwise participate on the PostgreSQL mailing lists, file a bug
report, or otherwise interact with the community."""
diff --git a/pgweb/urls.py b/pgweb/urls.py
index d9b81f75..2bb875f7 100644
--- a/pgweb/urls.py
+++ b/pgweb/urls.py
@@ -70,9 +70,12 @@ urlpatterns = [
re_path(r'^community/$', pgweb.core.views.community),
re_path(r'^community/contributors/$', pgweb.contributors.views.completelist),
+ re_path(r'^community/people/$', pgweb.contributors.views.peoplelist),
+ re_path(r'^community/people/([^/]+)/$', pgweb.contributors.views.profile),
+ re_path(r'^community/badge/(\d+)/$', pgweb.contributors.views.badge_view),
+
re_path(r'^community/lists/$', RedirectView.as_view(url='/list/', permanent=True)),
re_path(r'^community/lists/subscribe/$', RedirectView.as_view(url='https://lists.postgresql.org/';, permanent=True)),
-
re_path(r'^community/lists/listinfo/$', pgweb.lists.views.listinfo),
re_path(r'^community/recognition/$', RedirectView.as_view(url='/about/policies/', permanent=True)),
re_path(r'^community/survey/vote/(\d+)/$', pgweb.survey.views.vote),
diff --git a/pgweb/util/contexts.py b/pgweb/util/contexts.py
index 412b7b61..d4c00a25 100644
--- a/pgweb/util/contexts.py
+++ b/pgweb/util/contexts.py
@@ -45,6 +45,7 @@ sitenav = {
'community': [
{'title': 'Community', 'link': '/community/'},
{'title': 'Contributors', 'link': '/community/contributors/'},
+ {'title': 'People', 'link': '/community/people/'},
{'title': 'Mailing Lists', 'link': '/list/'},
{'title': 'IRC', 'link': '/community/irc/'},
# {'title': 'Slack', 'link': 'https://join.slack.com/t/postgresteam/shared_invite/zt-1qj14i9sj-E9WqIFlvcOiHsEk2yFEMjA';},
@@ -84,6 +85,7 @@ sitenav = {
{'title': 'Events', 'link': '/account/edit/events/'},
{'title': 'Products', 'link': '/account/edit/products/'},
{'title': 'Professional Services', 'link': '/account/edit/services/'},
+ {'title': 'Contributor Badges', 'link': '/account/edit/badges/'},
{'title': 'Organisations', 'link': '/account/edit/organisations/'},
]},
{'title': 'Change password', 'link': '/account/changepwd/'},
diff --git a/pgweb/util/moderation.py b/pgweb/util/moderation.py
index 45db593f..841908ae 100644
--- a/pgweb/util/moderation.py
+++ b/pgweb/util/moderation.py
@@ -156,7 +156,8 @@ def _modclasses():
from pgweb.core.models import Organisation
from pgweb.downloads.models import Product
from pgweb.profserv.models import ProfessionalService
- return [NewsArticle, Event, Organisation, Product, ProfessionalService]
+ from pgweb.contributors.models import Badge
+ return [NewsArticle, Event, Organisation, Product, ProfessionalService, Badge]
def get_all_pending_moderations():
diff --git a/templates/account/index.html b/templates/account/index.html
index 94761e00..4fb74a2e 100644
--- a/templates/account/index.html
+++ b/templates/account/index.html
@@ -5,8 +5,9 @@
<p>
From this section, you can manage all information on this site connected
to your PostgreSQL community account. Other than your basic profile
-information, this includes news and events, professional services and
-comments. Note that most of the data you submit to this site needs to be
+information, this includes news and events, professional services,
+comments and contributor badges.
+Note that most of the data you submit to this site needs to be
approved by a moderator before it's published.
</p>
<p>
@@ -16,7 +17,7 @@ type of record in the menu on the left.
<h2>Permissions model</h2>
<p>
-News, Events, Products and Professional Services are attached to an
+News, Events, Products, Professional Services and Contributor Badges are attached to an
Organisation. One or more persons can be given permissions to manage
the data for an organisation. If you do not have permissions for an
organisation and think you should have, you need to contact the current
diff --git a/templates/account/userprofileform.html b/templates/account/userprofileform.html
index 96ed2779..ab292476 100644
--- a/templates/account/userprofileform.html
+++ b/templates/account/userprofileform.html
@@ -94,9 +94,30 @@
</div>
{%endfor%}
+ {% if badges %}
+ <h2>Contributor badges</h2>
+ <table class="table">
+ <tbody>
+ {%for b in badges %}
+ {%if forloop.counter0|divisibleby:"4" %}
+ {%if not forloop.first%}</tr>{%endif%}
+ <tr>
+ {%endif%}
+ <td align="center">
+ <a href="/community/badge/{{b.id}}/">
+ <img src="{%if b.image %}{{b.image}}{%else%}/media/img/about/press/elephant.png{%endif%}" width="150"><br>
+ {{b}}
+ </a>
+ </td>
+ {%if forloop.last%}</tr>{%endif%}
+ {%endfor%}
+ </tbody>
+ </table>
+ {% endif %}
+
{% if contribform %}
<h2>Edit contributor information</h2>
- <p>You can edit the information that's shown on the <a href="/community/contributors/" target="_blank" rel="noopener">contributors</a> page. Please be careful as your changes will take effect immediately!
+ <p>You can edit the information that's shown on your <a href="/community/people/{{user.username}}/" target="_blank" rel="noopener">profile</a> page. Please be careful as your changes will take effect immediately!
</p>
{% for field in contribform %}
<div class="form-group row">
@@ -116,6 +137,12 @@
</div>
</div>
{% endfor %}
+ {% elif badges %}
+ <h2>Create contributor profile</h2>
+ <p>You have been awarded contributor badges. To have your name included in the public people and badge holder lists, you can create a publicly visible profile page.</p>
+ <div>
+ <input type="checkbox" name="create_contributor_profile"> Create publicly visible profile page
+ </div>
{% endif %}
<div class="submit-row">
diff --git a/templates/contributors/badge.html b/templates/contributors/badge.html
new file mode 100644
index 00000000..b35d6e3e
--- /dev/null
+++ b/templates/contributors/badge.html
@@ -0,0 +1,45 @@
+{%extends "base/page.html"%}
+{%load pgfilters%}
+{%block title%}{{badge}} - Contribution{%endblock%}
+{%block contents%}
+<h1>{{badge}} <i class="fa fa-code"></i></h1>
+<p><img src="{%if badge.image %}{{badge.image}}{%else%}/media/img/about/press/elephant.png{%endif%}" width="150"></p>
+
+{% if badge.description or badge.url %}
+<h2>Contribution</h2>
+{%endif%}
+{% if badge.description %}
+<p>{{badge.description}}</p>
+{%endif%}
+{% if badge.url %}
+<p><a href="{{badge.url}}">{{badge.url}}</a></p>
+{%endif%}
+
+{%if badge.holders%}
+<h2>Contributors</h2>
+<ul>
+ {%for u in badge.holders.all%}
+ {%for c in u.contributor_set.all%}
+ <li><a href="/community/people/{{u}}/">{{u.first_name}} {{u.last_name}}</a></li>
+ {%endfor%}
+ {%endfor%}
+</ul>
+{%endif%}
+
+<h2>Getting added</h2>
+{% if badge.org %}
+<p>This badge is issued by <em>{{badge.org}}</em>.</p>
+{%endif%}
+
+<p>If you think you should be listed
+ here, check your <a href="/account/profile/">account profile</a> page if the
+ badge is present there and activate your contribution profile page. If not,
+ contact the badge issuing organisation and ask to be added.</p>
+
+{% if badge.contact %}
+<p>Contact information: <em>{{badge.contact}}</em>.</p>
+{%endif%}
+
+<p>People are listed in alphabetical order.</p>
+
+{%endblock%}
diff --git a/templates/contributors/list.html b/templates/contributors/list.html
index 068fc949..01659045 100644
--- a/templates/contributors/list.html
+++ b/templates/contributors/list.html
@@ -1,18 +1,18 @@
{%extends "base/page.html"%}
{%load pgfilters%}
-{%block title%}Contributor Profiles{%endblock%}
+{%block title%}Recognized Contributors{%endblock%}
{%block contents%}
<h1>PostgreSQL Contributor Profiles <i class="fa fa-users"></i></h1>
-<p>These are the fine people that make PostgreSQL what it is today!</p>
-
<p>
- For a list of all code contributions to a specific release, see the
- <a href="/docs/release/">Release Notes</a> for released versions of PostgreSQL.
+ These are the fine people that make PostgreSQL what it is today!
+ Contributors listed here have provided a sustained stream of notable contributions in recent years.
</p>
+
<p>
- Existing contributors can update their information in their
- <a href="/account/profile/">user profile</a>.
+ A separate page lists all
+ <a href="/community/people">people who have made contributions to PostgreSQL</a>
+ over the years.
</p>
{%for t in contributortypes%}
@@ -32,7 +32,7 @@
{%for c in t.contributor_set.all %}
{%if t.detailed%}
<tr>
- <td>{{c.firstname}} {{c.lastname}} {%if t.showemail and c.email%}({{c.email|hidemail}}){%endif%}
+ <td>{% if c.user %}<a href="/community/people/{{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 %}
@@ -41,21 +41,23 @@
{{c.company}}
{% endif %}
{% endif %}
- <br/>
- {{c.location}}
+ {%if c.location %}
+ <br/>
+ {{c.location}}
+ {% endif %}
</td>
<td>{{c.contribution}}</td>
</tr>
{%else%}
{%if forloop.counter0|divisibleby:"2" %}
<tr>
- <td>{{c.firstname}} {{c.lastname}}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
+ <td>{% if c.user %}<a href="/community/people/{{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>{{c.firstname}} {{c.lastname}}{%if t.showemail and c.email%} ({{c.email|hidemail}}){%endif%}</td>
+ <td>{% if c.user %}<a href="/community/people/{{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%}
@@ -65,6 +67,7 @@
{%endfor%}
<p>All contributors are listed in alphabetical order.
+ Existing contributors can update their information in their <a href="/account/profile/">user profile</a>.
To suggest additions or corrections to this list, please email the
<a href="/about/governance/contributors/">Contributors Committee</a> at
<a href="mailto:[email protected]">[email protected]</a>.
diff --git a/templates/contributors/people.html b/templates/contributors/people.html
new file mode 100644
index 00000000..79689ece
--- /dev/null
+++ b/templates/contributors/people.html
@@ -0,0 +1,42 @@
+{%extends "base/page.html"%}
+{%load pgfilters%}
+{%block title%}People in the PostgreSQL Community{%endblock%}
+{%block contents%}
+<h1>People in the PostgreSQL Community <i class="fa fa-users"></i></h1>
+<p>These are the fine people that have made contributions to PostgreSQL over the years.</p>
+
+<p>Recognized Significant and Major Contributors are listed on the
+ <a href="/community/contributors/">Contributors page</a>.
+</p>
+
+<p style="text-align: justify;">
+ {%for c in people %}
+ <nobr>{%if c.user%}<a href="/community/people/{{c.user.username}}/">{{c.firstname}} {{c.lastname}}</a>{%else%}{{c.firstname}} {{c.lastname}}{%endif%} {%if not forloop.last%}�{%endif%}</nobr>
+ {%endfor%}
+</p>
+
+<p>People are listed in alphabetical order.
+ If you are listed and want to claim your profile page, write a mail including your community account name to
+ <a href="mailto:[email protected]">[email protected]</a>.
+</p>
+
+<h1>Contribution Badges</h1>
+<table class="table">
+ <tbody>
+ {%for b in badges %}
+ {%if forloop.counter0|divisibleby:"4" %}
+ {%if not forloop.first%}</tr>{%endif%}
+ <tr>
+ {%endif%}
+ <td align="center">
+ <a href="/community/badge/{{b.id}}/">
+ <img src="{%if b.image %}{{b.image}}{%else%}/media/img/about/press/elephant.png{%endif%}" width="150"><br>
+ {{b}}
+ </a>
+ </td>
+ {%if forloop.last%}</tr>{%endif%}
+ {%endfor%}
+ </tbody>
+</table>
+
+{%endblock%}
diff --git a/templates/contributors/profile.html b/templates/contributors/profile.html
new file mode 100644
index 00000000..c7efaa44
--- /dev/null
+++ b/templates/contributors/profile.html
@@ -0,0 +1,64 @@
+{%extends "base/page.html"%}
+{%load pgfilters%}
+{%block title%}{{contributor.firstname}} {{contributor.lastname}} - Contributor Profile{%endblock%}
+{%block contents%}
+<h1>{{contributor.firstname}} {{contributor.lastname}} <i class="fa fa-user"></i></h1>
+
+<div class="row">
+ <div class="col-md-8">
+ {%if badges%}
+ <h2>Contribution Badges</h2>
+ <table class="table">
+ <tbody>
+ {%for b in badges %}
+ {%if forloop.counter0|divisibleby:"4" %}
+ {%if not forloop.first%}</tr>{%endif%}
+ <tr>
+ {%endif%}
+ <td align="center">
+ <a href="/community/badge/{{b.id}}/">
+ <img src="{%if b.image %}{{b.image}}{%else%}/media/img/about/press/elephant.png{%endif%}" width="150"><br>
+ {{b}}
+ </a>
+ </td>
+ {%if forloop.last%}</tr>{%endif%}
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+
+ {%if contributor.contribution%}
+ <h2>Contribution</h2>
+ <p>{{contributor.contribution}}</p>
+ {%endif%}
+
+ <h2>Information</h2>
+ <dl class="row">
+ <dt class="col-sm-3">Contributor Type</dt>
+ <dd class="col-sm-9">{%if contributor.ctype%}{{contributor.ctype.typename}}{%else%}Basic contributor, not recognized{%endif%}</dd>
+
+ {%if contributor.email%}
+ <dt class="col-sm-3">Email</dt>
+ <dd class="col-sm-9">{{contributor.email|hidemail}}</dd>
+ {%endif%}
+
+ {%if contributor.location%}
+ <dt class="col-sm-3">Location</dt>
+ <dd class="col-sm-9">{{contributor.location}}</dd>
+ {%endif%}
+
+ {%if contributor.company%}
+ <dt class="col-sm-3">Company</dt>
+ <dd class="col-sm-9">
+ {%if contributor.companyurl%}
+ <a href="{{contributor.companyurl}}" target="_blank" rel="noopener">{{contributor.company}}</a>
+ {%else%}
+ {{contributor.company}}
+ {%endif%}
+ </dd>
+ {%endif%}
+ </dl>
+ </div>
+</div>
+
+{%endblock%}
--
2.51.0
--5MSjHfPoqsxdXc0M--
^ permalink raw reply [nested|flat] 11+ messages in thread
* Introduce contributor badges
@ 2026-01-19 16:28 Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Christoph Berg @ 2026-01-19 16:28 UTC (permalink / raw)
To: Magnus Hagander <[email protected]>; +Cc: Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
Over the holidays, I used the time to implement the badges idea. We've
discussed in the team and we are happy with how it looks like now, and
I'm attaching the version with the changes from the last contributors
team meeting.
The technical description is in the commit message, so I'm not
duplicating that here. It's obviously a larger patch, but since the
badges are new, I'm not sure it's possible to split it up.
To make rollout less disruptive, we could deploy everything, but leave
out the part that creates links to the new parts
(pgweb/util/contexts.py, anything else?). That way we could test
everything, prefill some initial badges and badge holders, and put in
the links once everything is confirmed to work.
I also plan to present the design at the dev meeting in Brussels.
Re: Magnus Hagander
> If they are not based on the recognized contributors, they should probably
> not be part of that in the data model either. But in particular, we
> shouldn't start creating empty contributor profiles before we even *knoiw*
> that it would.
That part works like this in the patch:
- badges are awarded to users (not to contributors)
- users who have at least one badge are offered to create a profile
page (creates the contributors object)
- these users can then fill in the data fields
> So any user without any confirmation can just add themselves as a
> contributor, without even moderation, and publish data? That sounds like a
> *really* bad idea, tbh.
>
> If it's data published by users where we have at one point added them to
> the contributors list and therefore pre-moderated to some point that is
> reasonable. But allowing random people to add records and then edit them
> and then it turns out to be published is going to be a hard no -- we've
> spent many hundreds of hours dealing with that on the wiki for example, and
> we will definitely not open up another venue for that. If it's things that
> not-specifically-approved users can add, then it *must* be moderated.
The moderation part is that people have to convince a badge-issuing
organisation to add their pg.o account as badge holder. This is
possibly a lot of organisations and people, but everyone involved
should be a recognised community member. Also, the worst harm would be
that could publish a random text on a ..../username/ sub-page that is
easily deleted again if we monitor changes. (Afaict any changes to
contributor objects are mailed somewhere. Not sure if that includes
the bio part already, but it could certainly made to be.)
> The latest one that includes that field. Doing that makes the "manage.py
> makemigration" no longer think there are any changes and stop emitting
> anything for that object.
I haven't included the migrations in the patch yet, will do that after
review of the general feature.
> > As for the questions - I think we should absolutely do opt-in, and I do
> > think it makes sense to auto-opt-in the current major contributors since
> > "it's been like that forever and they haven't complained", but listing the
> > others and in a more visible way there are sure to be some who might not
> > want it. In particular, maybe we should make the listing of *email* a
> > separate opt-in/opt-out? That is you can opt-out of being listed
> > completely, or you can say "list me, but not my email"?
> >
> > So there would be a separate opt-in for being listed on the recognized
> > contributor page and for having a public individual contributor
> > profile? And we would only auto opt-in major contributors to the
> > public individual contributor profiles?
>
> When writing that I was not aware that you were intending to have both a
> "recognized contributor" and a "self-claimed contributor". That does change
> it a bit. If it's a self-claimed contributor then it doesn't make much
> sense to opt-out.
The listing is opt-in. If the user never clicks the "create a profile
page" button, their name is not shown. Not even in the list of badge
holders on the badge page.
Once we have this system, the expectation would be that anyone who
we'd want to promote to a recognized contributor would already have a
profile page created. (If not, we should ask them first why.)
> I think Christoph made a good point about this -- once the contributor
> profile requires an account, which it does in order to get published here,
> they can opt out by just changing their email to being empty. It's only for
> contributors that do not have an account connected that *we* need the email
> (so we can reach them), but with the discussed plan those wouldn't be
> listed anyway since a username is needed in order to get listed. So that
> should leave us without needing a separate opt-out.
Contributor.email is currently still "null=False, blank=True", should
probably change that to null=True.
> Per above, if it is a field that any user can directly edit and it goes to
> publication, it must be moderated. That's a hard requirement. Before we
> made the whole "make me an editor" requirement for the wiki, for examples,
> we had upwards of 10,000 new accounts signed up every day just to post spam
> when it hit the peak.
>
> We might need to add more moderators for it, but it needs to be moderated :)
(See above) Even if that's people who have already proven to have
contributed something useful?
> What does it mean that we would get notifications for them? Is "we"
> > the contributors committee?
>
> Right now, there's just the one moderation team and address that gets it
> for all types of objects. But it would probably be relatively easy to split
> that up so there could be multiple moderation-and-notification teams.
That might make sense. Or some of the contributors team members get an
extra job at pgweb moderation...
Christoph
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-01-20 11:56 ` Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Borodin @ 2026-01-20 11:56 UTC (permalink / raw)
To: Christoph Berg <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
> On 19 Jan 2026, at 21:28, Christoph Berg <[email protected]> wrote:
>
> Over the holidays, I used the time to implement the badges idea. We've
> discussed in the team and we are happy with how it looks like now, and
> I'm attaching the version with the changes from the last contributors
> team meeting.
Thanks for working on this! Looks great!
I've setup preview version to test how things will look like. There's some generated sample data.
http://89.169.141.31:8000/community/people/alice/
ogin:moderator pwd:moderator123
orgmanager1 manager123
orgmanager2 manager123
alice alice123 -- Has 3 badges + profile page
bob bob123 -- Has 2 bandges
charlie charlie123 -- 2 badges, without profile
I'm slightly worried that user does not approve their badges.
Also do we plan to add a page where user can claim a badge so org admin can approve their claim?
And I find it a bit oxymoron: "Basic contributor, not recognized"
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
@ 2026-01-20 12:11 ` Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Christoph Berg @ 2026-01-20 12:11 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
Re: Andrey Borodin
> Thanks for working on this! Looks great!
> I've setup preview version to test how things will look like. There's some generated sample data.
>
> http://89.169.141.31:8000/community/people/alice/
Thanks, that makes review a bit easier for everyone else I guess.
The "people" page there has a problem:
http://89.169.141.31:8000/community/people/
It's not happening here, so I can't say if that's a bug in the patch.
> I'm slightly worried that user does not approve their badges.
The idea is that the badge itself needs approval and then is trusted.
So I think the worst thing that could happen is that someone
legitimately creates a "PostgreSQL Conf Antarctica Speaker", awards it
to you, but you don't want to publicly admit that you've been there.
Anything I'm missing?
> Also do we plan to add a page where user can claim a badge so org admin can approve their claim?
I think the basic workflow is that people contribute, an organisation
creates a badge for it and awards it to these people. For example,
after the PG19 release, we would create a "PostgreSQL 19 Contributor"
badge and award it to everyone listed in the release notes. Similarly
for conference speakers.
Maybe the other way round shouldn't be too easy so badge issuers don't
get flooded with requests. That's why we put the email link there.
Perhaps we need to make sure all approved badges have clear criteria
for badge holders. For example, "Has said something useful on the
mailing list" would be very fuzzy and invite request spam too much.
> And I find it a bit oxymoron: "Basic contributor, not recognized"
That's there to make the distinction to recognized contributors clear.
Better suggestions welcome.
Christoph
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-01-20 12:52 ` Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Christoph Berg @ 2026-01-20 12:52 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
Re: To Andrey Borodin
> It's not happening here, so I can't say if that's a bug in the patch.
My mail client recoded the attachment as latin1. I'll replace the "·"
there by · , that's cleaner anyway.
Christoph
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-01-23 10:14 ` Christoph Berg <[email protected]>
2026-01-23 19:03 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Christoph Berg @ 2026-01-23 10:14 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
Re: To Andrey Borodin
> My mail client recoded the attachment as latin1. I'll replace the "·"
> there by · , that's cleaner anyway.
New version attached, with ^ this change and rebased.
Christoph
Attachments:
[application/gzip] v3-0001-Introduce-contributor-badges.patch.gz (9.5K, ../../[email protected]/2-v3-0001-Introduce-contributor-badges.patch.gz)
download
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-01-23 19:03 ` Christoph Berg <[email protected]>
2026-04-24 16:45 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
0 siblings, 1 reply; 11+ messages in thread
From: Christoph Berg @ 2026-01-23 19:03 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; [email protected]; PostgreSQL Contributors <[email protected]>
More polishing done, now including the database migration script.
Christoph
Attachments:
[application/gzip] v4-0001-Introduce-contributor-badges.patch.gz (10.6K, ../../[email protected]/2-v4-0001-Introduce-contributor-badges.patch.gz)
download
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 19:03 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-04-24 16:45 ` Christoph Berg <[email protected]>
2026-04-24 16:47 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-04-27 11:46 ` Re: Introduce contributor badges Magnus Hagander <[email protected]>
0 siblings, 2 replies; 11+ messages in thread
From: Christoph Berg @ 2026-04-24 16:45 UTC (permalink / raw)
To: [email protected]; +Cc: Andrey Borodin <[email protected]>; Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; PostgreSQL Contributors <[email protected]>
New version attached. Not much change, the biggest one is perhaps that
lists of badges are no longer rendered as html table, but in a CSS
grid. Everything seems to work as it should now.
My plan is to commit this, minus the menu change in
pgweb/util/contexts.py. That way, we can create the first badges and
check if everything really works without things already being visible
to users (unless they know the URLs).
Christoph
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 19:03 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-04-24 16:45 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-04-24 16:47 ` Christoph Berg <[email protected]>
1 sibling, 0 replies; 11+ messages in thread
From: Christoph Berg @ 2026-04-24 16:47 UTC (permalink / raw)
To: [email protected]; +Cc: Andrey Borodin <[email protected]>; Magnus Hagander <[email protected]>; Melanie Plageman <[email protected]>; PostgreSQL Contributors <[email protected]>
Re: To [email protected]
> New version attached. Not much change, the biggest one is perhaps that
> lists of badges are no longer rendered as html table, but in a CSS
> grid. Everything seems to work as it should now.
Well, attached now.
Christoph
Attachments:
[application/gzip] v5-0001-Introduce-contributor-badges.patch.gz (10.7K, ../../[email protected]/2-v5-0001-Introduce-contributor-badges.patch.gz)
download
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 19:03 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-04-24 16:45 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
@ 2026-04-27 11:46 ` Magnus Hagander <[email protected]>
2026-04-28 13:06 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
1 sibling, 1 reply; 11+ messages in thread
From: Magnus Hagander @ 2026-04-27 11:46 UTC (permalink / raw)
To: Christoph Berg <[email protected]>; +Cc: [email protected]; Andrey Borodin <[email protected]>; Melanie Plageman <[email protected]>; PostgreSQL Contributors <[email protected]>
On Fri, 24 Apr 2026 at 18:45, Christoph Berg <[email protected]> wrote:
> New version attached. Not much change, the biggest one is perhaps that
> lists of badges are no longer rendered as html table, but in a CSS
> grid. Everything seems to work as it should now.
>
> My plan is to commit this, minus the menu change in
> pgweb/util/contexts.py. That way, we can create the first badges and
> check if everything really works without things already being visible
> to users (unless they know the URLs).
>
>
Given the fairly substantial concerns raised ofer this during in-person
discussions at FOSDEM, please do *not* commit this until you have signoff
from those involved. (It might be that it's fine, but given the concerns
and discussions around it, let's make sure those are resolved).
//Magnus
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: Introduce contributor badges
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Re: Introduce contributor badges Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 12:52 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 10:14 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-01-23 19:03 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-04-24 16:45 ` Re: Introduce contributor badges Christoph Berg <[email protected]>
2026-04-27 11:46 ` Re: Introduce contributor badges Magnus Hagander <[email protected]>
@ 2026-04-28 13:06 ` Christoph Berg <[email protected]>
0 siblings, 0 replies; 11+ messages in thread
From: Christoph Berg @ 2026-04-28 13:06 UTC (permalink / raw)
To: Magnus Hagander <[email protected]>; +Cc: [email protected]; Andrey Borodin <[email protected]>; Melanie Plageman <[email protected]>; PostgreSQL Contributors <[email protected]>
Re: Magnus Hagander
> Given the fairly substantial concerns raised ofer this during in-person
> discussions at FOSDEM, please do *not* commit this until you have signoff
> from those involved. (It might be that it's fine, but given the concerns
> and discussions around it, let's make sure those are resolved).
I said in the other thread:
> The last result (from the lunch discussion in Brussels) was that we
> need handling of retired people from "permanent" badges like "Sysadmin
> Team". That's not included yet, but in the team, we concluded that
> instead of some complicated date range handling (perhaps that's what
> you remember as plenty?) we can just add a single boolean "retired"
> flag. We don't have that yet, but that's not a big blocker.
I've now implemented retiring from badges. Internally it's tracked by
filling in a date_retired field, but in order not to overcomplicate
the user interface, it's treated as a boolean. Retirees still show up
in badge listing, but are marked as retired.
Removing people from badges is now a two-stage process, retire them
and then remove them. To un-retire someone, add their email address
again (which NULLs the date_retired field).
I'm attaching that as a separate commit for better review. It would
get squashed before committing, of course.
I believe that addresses the concerns from Brussels, or was there
anything else?
Christoph
Attachments:
[application/gzip] v6-0001-Introduce-contributor-badges.patch.gz (10.8K, ../../[email protected]/2-v6-0001-Introduce-contributor-badges.patch.gz)
download
[application/gzip] v6-0002-Add-dates-on-badgeholders-so-people-can-be-retire.patch.gz (4.9K, ../../[email protected]/3-v6-0002-Add-dates-on-badgeholders-so-people-can-be-retire.patch.gz)
download
^ permalink raw reply [nested|flat] 11+ messages in thread
end of thread, other threads:[~2026-04-28 13:06 UTC | newest]
Thread overview: 11+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-01-05 22:03 [PATCH v2] Introduce contributor badges Christoph Berg <[email protected]>
2026-01-19 16:28 Introduce contributor badges Christoph Berg <[email protected]>
2026-01-20 11:56 ` Andrey Borodin <[email protected]>
2026-01-20 12:11 ` Christoph Berg <[email protected]>
2026-01-20 12:52 ` Christoph Berg <[email protected]>
2026-01-23 10:14 ` Christoph Berg <[email protected]>
2026-01-23 19:03 ` Christoph Berg <[email protected]>
2026-04-24 16:45 ` Christoph Berg <[email protected]>
2026-04-24 16:47 ` Christoph Berg <[email protected]>
2026-04-27 11:46 ` Magnus Hagander <[email protected]>
2026-04-28 13:06 ` Christoph Berg <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox