|
5 | 5 | import smtplib
|
6 | 6 | import socket
|
7 | 7 | import uuid
|
| 8 | +from collections import defaultdict |
8 | 9 | from datetime import datetime, timezone
|
9 | 10 | from urllib.parse import urlparse
|
10 | 11 |
|
|
41 | 42 | from django.utils.decorators import method_decorator
|
42 | 43 | from django.utils.html import escape
|
43 | 44 | from django.utils.timezone import now
|
| 45 | +from django.views import View |
44 | 46 | from django.views.decorators.csrf import csrf_exempt
|
45 | 47 | from django.views.decorators.http import require_POST
|
46 | 48 | from django.views.generic import DetailView, ListView, TemplateView
|
|
79 | 81 | safe_redirect_request,
|
80 | 82 | )
|
81 | 83 |
|
| 84 | +from .constants import GSOC25_PROJECTS |
| 85 | + |
82 | 86 |
|
83 | 87 | @login_required(login_url="/accounts/login")
|
84 | 88 | def like_issue(request, issue_pk):
|
@@ -2008,3 +2012,71 @@ def page_vote(request):
|
2008 | 2012 | return JsonResponse({"status": "error", "message": "An error occurred while processing your vote"})
|
2009 | 2013 |
|
2010 | 2014 | return JsonResponse({"status": "error", "message": "Invalid request method"})
|
| 2015 | + |
| 2016 | + |
| 2017 | +class GsocView(View): |
| 2018 | + SINCE_DATE = datetime(2024, 11, 1, tzinfo=timezone.utc) |
| 2019 | + |
| 2020 | + def fetch_model_prs(self, repo_names): |
| 2021 | + contributors = defaultdict(lambda: {"count": 0, "github_url": ""}) |
| 2022 | + total_pr_count = 0 |
| 2023 | + |
| 2024 | + # Filter repos by name |
| 2025 | + repos = Repo.objects.filter(name__in=[name.split("/")[-1] for name in repo_names]) |
| 2026 | + |
| 2027 | + # Fetch merged PRs |
| 2028 | + prs = GitHubIssue.objects.filter( |
| 2029 | + repo__in=repos, type="pull_request", is_merged=True, merged_at__gte=self.SINCE_DATE |
| 2030 | + ).select_related("user_profile__user") |
| 2031 | + |
| 2032 | + for pr in prs: |
| 2033 | + total_pr_count += 1 |
| 2034 | + |
| 2035 | + user_profile = pr.user_profile |
| 2036 | + if user_profile: |
| 2037 | + github_url = user_profile.github_url |
| 2038 | + if github_url and not github_url.endswith("[bot]") and "bot" not in github_url.lower(): |
| 2039 | + contributors[github_url]["count"] += 1 |
| 2040 | + contributors[github_url]["github_url"] = github_url |
| 2041 | + |
| 2042 | + # Get top 10 contributors |
| 2043 | + top_contributors = sorted(contributors.items(), key=lambda item: item[1]["count"], reverse=True)[:10] |
| 2044 | + |
| 2045 | + # Format top contributors list |
| 2046 | + formatted_contributors = [ |
| 2047 | + {"url": url, "username": url.rstrip("/").split("/")[-1], "prs": data["count"]} |
| 2048 | + for url, data in top_contributors |
| 2049 | + ] |
| 2050 | + |
| 2051 | + return formatted_contributors, total_pr_count |
| 2052 | + |
| 2053 | + def get_repo_url(self, repo_names): |
| 2054 | + if not repo_names: |
| 2055 | + return "" |
| 2056 | + |
| 2057 | + repo_name = repo_names[0].split("/")[-1] |
| 2058 | + try: |
| 2059 | + repo = Repo.objects.filter(name=repo_name).first() |
| 2060 | + return repo.repo_url if repo else f"https://github.com/{repo_names[0]}" |
| 2061 | + except: |
| 2062 | + return f"https://github.com/{repo_names[0]}" |
| 2063 | + |
| 2064 | + def build_project_data(self, project, repo_names): |
| 2065 | + contributors, total_prs = self.fetch_model_prs(repo_names) |
| 2066 | + |
| 2067 | + return { |
| 2068 | + "contributors": contributors, |
| 2069 | + "total_prs": total_prs, |
| 2070 | + "repo_url": self.get_repo_url(repo_names), |
| 2071 | + } |
| 2072 | + |
| 2073 | + def get(self, request): |
| 2074 | + project_data = {} |
| 2075 | + |
| 2076 | + for project, repo_names in GSOC25_PROJECTS.items(): |
| 2077 | + project_data[project] = self.build_project_data(project, repo_names) |
| 2078 | + |
| 2079 | + # Sort projects by total PRs |
| 2080 | + sorted_project_data = dict(sorted(project_data.items(), key=lambda item: item[1]["total_prs"], reverse=True)) |
| 2081 | + |
| 2082 | + return render(request, "gsoc.html", {"projects": sorted_project_data}) |
0 commit comments