move the leaderboard from the gsoc page to the organization detail page have it only show on the owasp organization for now
/assign
Hello @rinkitadhana! You've been assigned to OWASP-BLT/BLT issue #4050. You have 24 hours to complete a pull request.
⏰ This issue has been automatically unassigned due to 24 hours of inactivity. The issue is now available for anyone to work on again.
@DonnieBLT Could you please explain a bit more about what you want? Maybe with an example? Also, do you want the leaderboard to be completely removed from the /gsoc page?
@rinkitadhana it's essentially to move the same logic on to the organization page you could make it work for all organizations now (no need to restrict it to owasp) and yes to remove it from the gsoc page.
@coderabbitai Could you please clarify the expected behavior for this issue and suggest a rough plan to approach it?
[!TIP] For best results, initiate chat on the files or code changes.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's fetch the issue description
gh issue view 4050 --repo OWASP-BLT/BLT
Length of output: 275
🏁 Script executed:
#!/bin/bash
# Look for files related to GSOC page
echo "Files related to GSOC page:"
rg -l "gsoc" --type-not=binary --type-not=lock
# Look for files related to organization detail page
echo -e "\nFiles related to organization detail page:"
rg -l "organization.*detail" --type-not=binary --type-not=lock
# Look for leaderboard implementations
echo -e "\nFiles related to leaderboard:"
rg -l "leaderboard" --type-not=binary --type-not=lock
Length of output: 499
🏁 Script executed:
#!/bin/bash
# Get an overview of the repository structure
ls -la
# Look for Python files since this appears to be a Django project
echo -e "\nPython files in the repository:"
find . -name "*.py" | grep -v "__pycache__" | sort
Length of output: 22706
🏁 Script executed:
#!/bin/bash
# Look for GSOC related views
echo "GSOC related view files:"
rg -l "gsoc" ./website/views
# Look for organization detail views
echo -e "\nOrganization detail view files:"
rg -l "organization" ./website/views | grep detail
# Look for leaderboard implementations in view files
echo -e "\nLeaderboard implementations in views:"
rg -l "leaderboard" ./website/views
# Look for template files related to GSOC
echo -e "\nTemplate files related to GSOC:"
find ./website -path "*/templates/*.html" -type f -exec grep -l "gsoc" {} \; 2>/dev/null || echo "No GSOC templates found"
# Look for template files related to organization detail
echo -e "\nTemplate files related to organization detail:"
find ./website -path "*/templates/*.html" -type f -exec grep -l "organization.*detail" {} \; 2>/dev/null || echo "No organization detail templates found"
# Look for template files with leaderboard
echo -e "\nTemplate files with leaderboard:"
find ./website -path "*/templates/*.html" -type f -exec grep -l "leaderboard" {} \; 2>/dev/null || echo "No leaderboard templates found"
Length of output: 2837
🏁 Script executed:
#!/bin/bash
# Check the GSOC template
echo "Content of GSOC template:"
cat ./website/templates/gsoc.html
# Check the implementation of the GSOC view in views
echo -e "\nGSOC view implementation:"
rg -A 20 "def gsoc" ./website/views/
# Check the organization detail template
echo -e "\nContent of organization detail template:"
cat ./website/templates/organization/organization_detail.html
# Check the organization view implementation
echo -e "\nOrganization detail view implementation:"
rg -A 20 "def organization_detail" ./website/views/
Length of output: 86109
🏁 Script executed:
#!/bin/bash
# Look for the implementation of gsoc view
echo "Looking for gsoc view implementation:"
rg -A 10 'def gsoc\b' ./website/views/
# Look for organization_detail view implementation
echo -e "\nLooking for organization_detail view implementation:"
rg -A 10 'def organization_detail\b' ./website/views/
# Look for any leaderboard related functions in views
echo -e "\nLooking for leaderboard related functions in views:"
rg -A 10 'leaderboard' ./website/views/ | grep "def"
Length of output: 1189
🏁 Script executed:
#!/bin/bash
# First let's find the GSOC view implementation
echo "Looking for view that renders the gsoc template:"
rg -A 5 "render.*gsoc\.html" ./website/views/
# Look for code that populates the projects variable for the GSOC template
echo -e "\nLooking for code that populates projects variable for GSOC template:"
rg -A 10 "projects.*=" ./website/views/
# Check for management commands related to gsoc
echo -e "\nGSOC management commands:"
find ./website/management/commands/ -name "*gsoc*" -type f -exec cat {} \;
# Check organization view implementation
echo -e "\nOrganization detail view implementation:"
rg -B 5 -A 20 "organization_detail" ./website/views/organization.py
Length of output: 40687
@rinkitadhana Based on my analysis of the codebase, I can clarify the requirements and suggest a plan for issue #4050:
Current Implementation
The GSOC page (/gsoc) currently has a leaderboard section titled "Top OWASP GSoC 2025 Contributors and Projects" that shows:
- Projects with their total PR counts
- Contributors for each project with their PR counts
- Visual representation with avatars and links to GitHub
Expected Behavior
- Move this leaderboard functionality from the GSOC page to the organization detail page
- Make it work for all organizations (not just OWASP)
- Remove the leaderboard section from the GSOC page entirely
Implementation Plan
-
Move Leaderboard Logic
- Identify the code in
website/views/issue.pythat populates the GSOC leaderboard data - Adapt this logic to work in
OrganizationDetailViewinwebsite/views/organization.py - Modify the code to filter projects and PRs based on the specific organization being viewed
- Identify the code in
-
Update Organization Detail Template
- Add a new section in
organization/organization_detail.htmlfor the leaderboard - Include similar styling and functionality as the GSOC leaderboard
- Ensure it works with the adapted view logic
- Add a new section in
-
Remove from GSOC Page
- Remove the leaderboard section from the
gsoc.htmltemplate
- Remove the leaderboard section from the
-
Add Management Commands (if needed)
- Adapt or create management commands to fetch PR data for all organizations, not just GSOC
This change will enhance the organization detail page by showing project contributions and top contributors in a more visual and interactive way, similar to how it's currently shown on the GSOC page.
@coderabbitai code this
[!TIP] For best results, initiate chat on the files or code changes.
A summary of the edits CodeRabbit can apply:
We will update website/views/organization.py to compute and pass leaderboard data (top_projects and top_contributors) for any organization.
We will modify organization_detail.html to make the leaderboard headings dynamic by including the organization's name.
We will remove the Top Contributors Leaderboard section from website/templates/gsoc.html.
We will enhance the organization_detail view in website/views/organization.py to compute and pass
projectsfor the new leaderboard.
We will insert the Top Contributors and Projects leaderboard section into website/templates/organization/organization_detail.html.
We will create a new module website/utils/leaderboard.py to encapsulate the leaderboard data computation for any organization.
We will modify website/views/organization.py to include the organization-specific leaderboard data in its view context.
We will remove the GSOC-specific leaderboard logic from website/views/issue.py.
We will remove the leaderboard section from website/templates/gsoc.html.
A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets):
✏️ website/views/organization.py
Add the necessary imports at the top of the file:
from django.db.models import Count
from website.models import PullRequest, Repository
Inside the organization_detail function, just before the return statement, insert the leaderboard computation logic adapted from the GSOC view:
# Leaderboard: top projects by PR count in this organization
org_projects = Repository.objects.filter(organization=organization)
org_projects = org_projects.annotate(pr_count=Count('pullrequest', distinct=True))
leaderboard_projects = org_projects.order_by('-pr_count')[:5]
# Leaderboard: top contributors across those projects
contributors_qs = PullRequest.objects.filter(repository__in=org_projects).values(
'user__login', 'user__avatar_url'
).annotate(contributions=Count('id')).order_by('-contributions')[:5]
leaderboard_contributors = [
{
'username': c['user__login'],
'avatar_url': c['user__avatar_url'],
'contributions': c['contributions'],
'github_url': f"https://github.com/{c['user__login']}"
}
for c in contributors_qs
]
context.update({
'top_projects': leaderboard_projects,
'top_contributors': leaderboard_contributors,
})
Save the file and restart the Django development server. Visit any organization detail page and verify the leaderboard appears correctly.
✏️ website/templates/organization/organization_detail.html
Replace the static Projects heading at line 455:
<h2 class="text-xl font-semibold text-gray-900">Top {{ organization.name }} Projects</h2>
Replace the static Contributors heading at line 508:
<h2 class="text-xl font-semibold text-gray-900 mb-4">Top {{ organization.name }} Contributors</h2>
Save the changes and reload the organization detail page to confirm the headings now reflect the current organization’s name.
➖ website/templates/gsoc.html
Open website/templates/gsoc.html and delete lines 244 through 306, which encompass the entire Top Contributors Leaderboard block.
✏️ website/views/organization.py
At the top of the file, ensure the following imports appear:
from django.db.models import Count
from .models import Project, PullRequest
Inside the organization_detail function, immediately after retrieving organization, insert:
# Build leaderboard data for this organization
projects = Project.objects.filter(organization=organization)
projects_data = {}
for project in projects:
prs = PullRequest.objects.filter(repository__project=project)
total_prs = prs.count()
contributors_data = prs.values('author__login', 'author__avatar_url')\
.annotate(prs=Count('id')).order_by('-prs')[:5]
projects_data[project.name] = {
'repo_url': project.repository_url,
'total_prs': total_prs,
'contributors': contributors_data
}
Update the render call to pass projects_data as projects:
return render(request, 'organization/organization_detail.html', {
'organization': organization,
'contributors': contributors,
'projects': projects_data,
})
➕ website/templates/organization/organization_detail.html
After line 49 (the comment <!-- End Existing Contributors Section -->), insert the following block:
<!-- Top Contributors and Projects Leaderboard -->
<div class="bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 p-8 mb-12 border-l-4 border-red-500">
<h2 class="text-3xl font-bold text-gray-900 mb-6">Top {{ organization.name }} Contributors and Projects</h2>
<p class="text-gray-700 mb-4">A glimpse of the top contributors and projects with the most PRs for {{ organization.name }}.</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
{% for project, data in projects.items %}
<div class="bg-gray-50 rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<a href="{{ data.repo_url }}" target="_blank" class="text-xl font-semibold text-gray-900">
{{ project }} - Total PRs:
<span class="text-red-600 font-bold">{{ data.total_prs }}</span>
</a>
</div>
<div class="space-y-3">
{% for contributor in data.contributors %}
<div class="flex items-center justify-between p-2 hover:bg-gray-100 rounded">
<div class="flex items-center">
<img src="{{ contributor.avatar_url }}" alt="{{ contributor.login }}" class="w-8 h-8 rounded-full mr-3" width="32" height="32">
<a href="https://github.com/{{ contributor.login }}" target="_blank" class="text-gray-700 hover:text-red-600">{{ contributor.login }}</a>
</div>
<span class="bg-red-100 text-red-800 text-sm font-medium px-2.5 py-0.5 rounded">
{{ contributor.prs }} PR{% if contributor.prs != 1 %}s{% endif %}
</span>
</div>
{% empty %}
<p class="text-gray-500 italic">No contributors in this period</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
Verify indentation matches surrounding HTML, and confirm that the projects variable is available thanks to the updated view.
📄 website/utils/leaderboard.py
Create the directory website/utils if it does not already exist.
In website/utils/leaderboard.py, write the following code:
from django.db.models import Count
from website.models import Project, PullRequest
def get_organization_leaderboard_data(org_slug, top_projects=5, top_contributors=5):
# Annotate projects with total pull request counts
projects = (
Project.objects
.filter(organization__slug=org_slug)
.annotate(pr_count=Count('pullrequest'))
.order_by('-pr_count')[:top_projects]
)
leaderboard = []
for project in projects:
# Annotate top contributors for each project
contributors_qs = (
PullRequest.objects
.filter(project=project)
.values('author__login')
.annotate(pr_count=Count('id'))
.order_by('-pr_count')[:top_contributors]
)
leaderboard.append({
'project': project,
'pr_count': project.pr_count,
'top_contributors': list(contributors_qs),
})
return leaderboard
✏️ website/views/organization.py
At the top of the file, add:
from website.utils.leaderboard import get_organization_leaderboard_data
Inside the get method, after setting context['projects'], insert:
# Compute and inject the leaderboard for this organization
leaderboard = get_organization_leaderboard_data(organization.slug)
context['leaderboard'] = leaderboard
Ensure the final render call is:
return render(request, 'organization/organization_detail.html', context)
✏️ website/views/issue.py
Delete or comment out:
# GSOC leaderboard logic
projects = Project.objects.filter(organization__slug='owasp').annotate(pr_count=Count('pullrequest')).order_by('-pr_count')
contributors = PullRequest.objects.filter(project__in=projects).values('author__login').annotate(pr_count=Count('id')).order_by('-pr_count')[:10]
return render(request, 'gsoc.html', {'projects': projects, 'contributors': contributors})
Replace it with:
return render(request, 'gsoc.html', context)
✏️ website/templates/gsoc.html
Delete the block:
<!-- Leaderboard Section -->
<section id="leaderboard">
<h2>Top OWASP GSoC 2025 Contributors and Projects</h2>
...
</section>
Verify the surrounding HTML remains valid and that the template still renders.
A summary of the context that CodeRabbit is considering across the codebase:
We need to extract the GSOC leaderboard logic so we can reuse it in the OrganizationDetailView for any organization.
We need to find the organization_detail view implementation so we know where to insert the leaderboard data.
We need to pinpoint the exact lines in the organization_detail template where the static headings appear, so we can make them dynamic.
Extract the GSOC view logic to see how the
projectscontext variable is built for the leaderboard.
Locate the
organization_detailview to extend it with the leaderboard logic.
Identify the lines in
gsoc.htmlthat render the Top Contributors Leaderboard so we can delete them.
Locate the insertion point in
organization_detail.htmlright after the existing Contributors section.
We need to locate the GSOC leaderboard logic in the GSOC view so we can extract it and then remove it from the GSOC page.
We need to find the leaderboard section in the GSOC template so we can remove the HTML block.
We need to identify where to inject the leaderboard in the organization detail view.
-
[ ] ✅ Create PR with these edits
-
[ ] 📋 Get copyable edits
-
[ ] 🔄 Try a different approach
-
[ ] ⏪ Go back to ordinary chat
@ explain what needs to be done
WIP /assign
⚠️ This issue is already assigned to @Copilot. Please pick another issue.