diff --git a/website/templates/leaderboard_global.html b/website/templates/leaderboard_global.html index 8b2278040c..3bc1d6426c 100644 --- a/website/templates/leaderboard_global.html +++ b/website/templates/leaderboard_global.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load static %} +{% load string_filters %} {% block title %} Global Leaderboard {% endblock title %} @@ -25,11 +26,11 @@

Global Leaderboard

-
-
Points Leaderboard
+
+
Points Leaderboard
{% if not leaderboard %} -

No data for this month!

+

No data for this month!

{% else %}
{% for leader in leaderboard %} @@ -73,34 +74,48 @@

Global Leaderboard

{% endif %}
-
-
Pull Request Leaderboard
+
+
+ Pull Request Leaderboard +
{% if pr_leaderboard %}
{% for leader in pr_leaderboard %}
- {% if leader.user_profile__github_url %} - {{ leader.user_profile__user__username }} - {% else %} + {% elif leader.user_profile__user__email %} username + {% else %} + username + {% endif %} + {% if leader.user_profile__user__username %} + {{ leader.user_profile__user__username }} + {% else %} + Unknown User + {% endif %} + {% if leader.user_profile__github_url %} + + + {% endif %} - {{ leader.user_profile__user__username }} - - -
{{ leader.total_prs }} PRs
@@ -108,40 +123,50 @@

Global Leaderboard

{% endfor %}
{% else %} -

No pull request data available!

+

No pull request data available!

{% endif %}
-
-
Code Review Leaderboard
+
+
Code Review Leaderboard
{% if code_review_leaderboard %}
{% for leader in code_review_leaderboard %}
- {% if leader.reviews__reviewer__user__username %} - {{ leader.reviews__reviewer__user__username }} + {% elif leader.reviewer__user__email %} + username {% else %} - username {% endif %} - - {{ leader.reviews__reviewer__user__username }} - - - - + {% if leader.reviewer__user__username %} + + {{ leader.reviewer__user__username }} + + {% if leader.reviewer__github_url %} + + + + {% endif %} + {% else %} + Unknown User + {% endif %}
Reviews: {{ leader.total_reviews }}
@@ -149,14 +174,14 @@

Global Leaderboard

{% endfor %}
{% else %} -

No code review data available!

+

No code review data available!

{% endif %}
-
-
Top Visitors
+
+
Top Visitors
{% if top_visitors %}
@@ -165,13 +190,13 @@

Global Leaderboard

{% if profile.avatar %} {{ profile.user.username }} {% else %} {{ profile.user.username }} @@ -188,24 +213,24 @@

Global Leaderboard

{% endfor %}
{% else %} -

No visitor data available!

+

No visitor data available!

{% endif %}
-
-
Issue Bounties
+
+
Issue Bounties
{% if not issue_bounties %} -

No issue bounties data available!

+

No issue bounties data available!

{% else %} {% endif %}
-
-
Bug Bounties
+
+
Bug Bounties
{% if not bug_bounties %} -

No bug bounties data available!

+

No bug bounties data available!

{% else %} {% endif %}
diff --git a/website/templatetags/string_filters.py b/website/templatetags/string_filters.py new file mode 100644 index 0000000000..e2543a88db --- /dev/null +++ b/website/templatetags/string_filters.py @@ -0,0 +1,11 @@ +from django import template + +register = template.Library() + + +@register.filter +def split(value, arg): + """Split a string by the given separator.""" + if value: + return value.split(arg) + return [] diff --git a/website/views/user.py b/website/views/user.py index adc178e2f0..410777a1c8 100644 --- a/website/views/user.py +++ b/website/views/user.py @@ -58,6 +58,41 @@ logger = logging.getLogger(__name__) +def extract_github_username(github_url): + """ + Extract GitHub username from a GitHub URL for avatar display. + + Args: + github_url (str): GitHub URL like 'https://github.com/username' or 'https://github.com/apps/dependabot' + + Returns: + str or None: The username part of the URL, or None if invalid/empty + """ + if not github_url or not isinstance(github_url, str): + return None + + # Strip trailing slashes and whitespace + github_url = github_url.strip().rstrip("/") + + # Validate that this is a GitHub URL + if not github_url.startswith(("https://github.com/", "http://github.com/")): + return None + + # Ensure URL contains at least one slash after the domain + if "/" not in github_url: + return None + + # Split on "/" and get the last segment + segments = github_url.split("/") + username = segments[-1] if segments else None + + # Return username only if it's non-empty and not just domain parts + if username and username not in ["github.com", "www.github.com", ""]: + return username + + return None + + @receiver(user_signed_up) def handle_user_signup(request, user, **kwargs): referral_token = request.session.get("ref") @@ -480,9 +515,15 @@ def get_context_data(self, *args, **kwargs): context["leaderboard"] = self.get_leaderboard()[:10] # Limit to 10 entries - # Pull Request Leaderboard + # Pull Request Leaderboard - Only show PRs from tracked repositories pr_leaderboard = ( - GitHubIssue.objects.filter(type="pull_request", is_merged=True) + GitHubIssue.objects.filter( + type="pull_request", + is_merged=True, + repo__isnull=False, # Only include PRs from tracked repositories + ) + .exclude(user_profile__isnull=True) # Exclude PRs without user profiles + .select_related("user_profile__user", "repo") # Optimize database queries .values( "user_profile__user__username", "user_profile__user__email", @@ -491,11 +532,19 @@ def get_context_data(self, *args, **kwargs): .annotate(total_prs=Count("id")) .order_by("-total_prs")[:10] ) + # Extract GitHub username from URL for avatar display + # Note: Processing in a loop is acceptable here since we're limited to top 10 entries + # and URL parsing cannot be done efficiently in the database + for leader in pr_leaderboard: + github_username = extract_github_username(leader.get("user_profile__github_url")) + if github_username: + leader["github_username"] = github_username context["pr_leaderboard"] = pr_leaderboard # Reviewed PR Leaderboard - Fixed query to properly count reviews reviewed_pr_leaderboard = ( - GitHubReview.objects.values( + GitHubReview.objects.filter(reviewer__user__isnull=False) + .values( "reviewer__user__username", "reviewer__user__email", "reviewer__github_url", @@ -503,6 +552,13 @@ def get_context_data(self, *args, **kwargs): .annotate(total_reviews=Count("id")) .order_by("-total_reviews")[:10] ) + # Extract GitHub username from URL for avatar display + # Note: Processing in a loop is acceptable here since we're limited to top 10 entries + # and URL parsing cannot be done efficiently in the database + for leader in reviewed_pr_leaderboard: + github_username = extract_github_username(leader.get("reviewer__github_url")) + if github_username: + leader["github_username"] = github_username context["code_review_leaderboard"] = reviewed_pr_leaderboard # Top visitors leaderboard