Skip to content

Commit

Permalink
Update project URLs to use 'project_view' and adjust related templates
Browse files Browse the repository at this point in the history
  • Loading branch information
JisanAR03 committed Jan 1, 2025
1 parent c41eb3f commit 396f36a
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 27 deletions.
8 changes: 6 additions & 2 deletions blt/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@
)
from website.views.project import (
ProjectBadgeView,
ProjectDetailView,
ProjectListView,
ProjectsDetailView,
ProjectView,
RepoDetailView,
Expand Down Expand Up @@ -537,7 +539,8 @@
TemplateView.as_view(template_name="coming_soon.html"),
name="googleplayapp",
),
re_path(r"^projects/$", ProjectView.as_view(), name="project_view"),
re_path(r"^projects/$", ProjectListView.as_view(), name="project_list"),
re_path(r"^allprojects/$", ProjectView.as_view(), name="project_view"),
re_path(r"^apps/$", TemplateView.as_view(template_name="apps.html"), name="apps"),
re_path(
r"^deletions/$",
Expand Down Expand Up @@ -587,6 +590,7 @@
re_path(r"^api/v1/createwallet/$", create_wallet, name="create_wallet"),
re_path(r"^api/v1/count/$", issue_count, name="api_count"),
re_path(r"^api/v1/contributors/$", contributors, name="api_contributor"),
path("project/<slug:slug>/", ProjectDetailView.as_view(), name="project_view"),
path("projects/<slug:slug>/badge/", ProjectBadgeView.as_view(), name="project-badge"),
path("repository/<slug:slug>/", RepoDetailView.as_view(), name="repo_detail"),
re_path(r"^report-ip/$", ReportIpView.as_view(), name="report_ip"),
Expand Down Expand Up @@ -798,7 +802,7 @@
name="similarity_scan",
),
path("projects/create/", create_project, name="create_project"),
path("project/<slug:slug>/", ProjectsDetailView.as_view(), name="projects_detail"),
path("projects/<slug:slug>/", ProjectsDetailView.as_view(), name="projects_detail"),
]

if settings.DEBUG:
Expand Down
2 changes: 1 addition & 1 deletion website/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ <h2 class="text-3xl font-bold mb-6">Get Involved</h2>
class="bg-green-500 text-white font-semibold py-3 px-6 rounded-full">
<i class="fas fa-users"></i> Join the Community
</a>
<a href="{% url 'project_view' %}"
<a href="{% url 'project_list' %}"
class="bg-blue-500 text-white font-semibold py-3 px-6 rounded-full">
<i class="fas fa-project-diagram"></i> Explore Projects
</a>
Expand Down
2 changes: 1 addition & 1 deletion website/templates/includes/sidenav.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
<div class="my-4 border-t border-gray-300"></div>
<!-- Projects Header Link -->
<li class="mb-2 {% if request.path == '/projects/' %}bg-gray-200{% endif %}">
<a href="{% url 'project_view' %}"
<a href="{% url 'project_list' %}"
class="flex items-center w-full no-underline p-2 {% if '/projects/' in request.path %} text-black {% else %} hover:text-red-500 text-black {% endif %}">
<div class="icon text-orange-500">
<i class="fas fa-box fa-lg"></i>
Expand Down
2 changes: 1 addition & 1 deletion website/templates/sitemap.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ <h2 class="text-6xl text-black font-bold">Sitemap</h2>
</li>
<li class="flex items-center space-x-3 text-black hover:text-red-600 hover:translate-x-1 transition duration-200 cursor-pointer">
<i class="fas fa-folder w-5 h-5 mr-1 align-middle"></i>
<a href="{% url 'project_view' %}">Projects</a>
<a href="{% url 'project_list' %}">Projects</a>
</li>
<li class="flex items-center space-x-3 text-black hover:text-red-600 hover:translate-x-1 transition duration-200 cursor-pointer">
<i class="fas fa-mobile-alt w-5 h-5 mr-1 align-middle"></i>
Expand Down
219 changes: 197 additions & 22 deletions website/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import socket
import time
from datetime import datetime, timedelta
from io import BytesIO
from pathlib import Path
from urllib.parse import urlparse
Expand All @@ -23,13 +24,14 @@
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.dateparse import parse_datetime
from django.utils.text import slugify
from django.utils.timezone import localtime
from django.utils.timezone import localtime, now
from django.views.decorators.http import require_http_methods
from django.views.generic import DetailView
from django.views.generic import DetailView, ListView
from django_filters.views import FilterView
from rest_framework.views import APIView

from website.bitcoin_utils import create_bacon_token
from website.forms import GitHubURLForm
from website.models import IP, BaconToken, Contribution, Organization, Project, Repo
from website.utils import admin_required

Expand Down Expand Up @@ -83,6 +85,105 @@ def distribute_bacon(request, contribution_id):
return render(request, "select_contribution.html", {"contributions": contributions})


class ProjectDetailView(DetailView):
model = Project
period = None
selected_year = None

def post(self, request, *args, **kwargs):
from django.core.management import call_command

project = self.get_object()

if "refresh_stats" in request.POST:
call_command("update_projects", "--project_id", project.pk)
messages.success(request, f"Refreshing stats for {project.name}")

elif "refresh_contributor_stats" in request.POST:
owner_repo = project.github_url.rstrip("/").split("/")[-2:]
repo = f"{owner_repo[0]}/{owner_repo[1]}"
call_command("fetch_contributor_stats", "--repo", repo)
messages.success(request, f"Refreshing contributor stats for {project.name}")

elif "refresh_contributors" in request.POST:
call_command("fetch_contributors", "--project_id", project.pk)
return redirect("project_view", slug=project.slug)

def get(self, request, *args, **kwargs):
project = self.get_object()
project.project_visit_count += 1
project.save()
return super().get(request, *args, **kwargs)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
end_date = now()
display_end_date = end_date.date()
selected_year = self.request.GET.get("year", None)
if selected_year:
start_date = datetime(int(selected_year), 1, 1)
display_end_date = datetime(int(selected_year), 12, 31)
else:
self.period = self.request.GET.get("period", "30")
days = int(self.period)
start_date = end_date - timedelta(days=days)
start_date = start_date.date()

contributions = Contribution.objects.filter(
created__date__gte=start_date,
created__date__lte=display_end_date,
repository=self.get_object(),
)

user_stats = {}
for contribution in contributions:
username = contribution.github_username
if username not in user_stats:
user_stats[username] = {
"commits": 0,
"issues_opened": 0,
"issues_closed": 0,
"prs": 0,
"comments": 0,
"total": 0,
}
if contribution.contribution_type == "commit":
user_stats[username]["commits"] += 1
elif contribution.contribution_type == "issue_opened":
user_stats[username]["issues_opened"] += 1
elif contribution.contribution_type == "issue_closed":
user_stats[username]["issues_closed"] += 1
elif contribution.contribution_type == "pull_request":
user_stats[username]["prs"] += 1
elif contribution.contribution_type == "comment":
user_stats[username]["comments"] += 1
total = (
user_stats[username]["commits"] * 5
+ user_stats[username]["prs"] * 3
+ user_stats[username]["issues_opened"] * 2
+ user_stats[username]["issues_closed"] * 2
+ user_stats[username]["comments"]
)
user_stats[username]["total"] = total

user_stats = dict(sorted(user_stats.items(), key=lambda x: x[1]["total"], reverse=True))

current_year = now().year
year_list = list(range(current_year, current_year - 10, -1))

context.update(
{
"user_stats": user_stats,
"period": self.period,
"start_date": start_date.strftime("%Y-%m-%d"),
"end_date": display_end_date.strftime("%Y-%m-%d"),
"year_list": year_list,
"selected_year": selected_year,
}
)
return context


class ProjectBadgeView(APIView):
def get(self, request, slug):
# Retrieve the project or return 404
Expand Down Expand Up @@ -138,6 +239,94 @@ def get(self, request, slug):
return response


class ProjectListView(ListView):
model = Project
context_object_name = "projects"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = GitHubURLForm()
context["sort_by"] = self.request.GET.get("sort_by", "-created")
context["order"] = self.request.GET.get("order", "desc")
return context

def post(self, request, *args, **kwargs):
if "refresh_stats" in request.POST:
from django.core.management import call_command

call_command("update_projects")
messages.success(request, "Refreshing project statistics...")
return redirect("project_list")

if "refresh_contributors" in request.POST:
from django.core.management import call_command

projects = Project.objects.all()
for project in projects:
owner_repo = project.github_url.rstrip("/").split("/")[-2:]
repo = f"{owner_repo[0]}/{owner_repo[1]}"
call_command("fetch_contributor_stats", "--repo", repo)
messages.success(request, "Refreshing contributor data...")
return redirect("project_list")

form = GitHubURLForm(request.POST)
if form.is_valid():
github_url = form.cleaned_data["github_url"]
# Extract the repository part of the URL
match = re.match(r"https://github.com/([^/]+/[^/]+)", github_url)
if match:
repo_path = match.group(1)
api_url = f"https://api.github.com/repos/{repo_path}"
response = requests.get(api_url)
if response.status_code == 200:
data = response.json()
# if the description is empty, use the name as the description
if not data["description"]:
data["description"] = data["name"]

# Check if a project with the same slug already exists
slug = data["name"].lower()
if Project.objects.filter(slug=slug).exists():
messages.error(request, "A project with this slug already exists.")
return redirect("project_list")

project, created = Project.objects.get_or_create(
github_url=github_url,
defaults={
"name": data["name"],
"slug": slug,
"description": data["description"],
"wiki_url": data["html_url"],
"homepage_url": data.get("homepage", ""),
"logo_url": data["owner"]["avatar_url"],
},
)
if created:
messages.success(request, "Project added successfully.")
else:
messages.info(request, "Project already exists.")
else:
messages.error(request, "Failed to fetch project from GitHub.")
else:
messages.error(request, "Invalid GitHub URL.")
return redirect("project_list")
context = self.get_context_data()
context["form"] = form
return self.render_to_response(context)

def get_queryset(self):
queryset = super().get_queryset()
sort_by = self.request.GET.get("sort_by", "-created")
order = self.request.GET.get("order", "desc")

if order == "asc" and sort_by.startswith("-"):
sort_by = sort_by[1:]
elif order == "desc" and not sort_by.startswith("-"):
sort_by = f"-{sort_by}"

return queryset.order_by(sort_by)


class ProjectRepoFilter(django_filters.FilterSet):
search = django_filters.CharFilter(method="filter_search", label="Search")
repo_type = django_filters.ChoiceFilter(
Expand Down Expand Up @@ -810,18 +999,11 @@ def get_issue_count(full_name, query, headers):
)

except requests.RequestException as e:
return JsonResponse(
{"status": "error", "message": f"Network error: {str(e)}"}, status=503
)
return JsonResponse({"status": "error", "message": f"Network error: {str(e)}"}, status=503)
except requests.HTTPError as e:
return JsonResponse(
{"status": "error", "message": f"GitHub API error: {str(e)}"},
status=e.response.status_code,
)
return JsonResponse({"status": "error", "message": f"GitHub API error: {str(e)}"}, status=e.response.status_code)
except ValueError as e:
return JsonResponse(
{"status": "error", "message": f"Data parsing error: {str(e)}"}, status=400
)
return JsonResponse({"status": "error", "message": f"Data parsing error: {str(e)}"}, status=400)

elif section == "metrics":
try:
Expand Down Expand Up @@ -929,17 +1111,10 @@ def get_issue_count(full_name, query, headers):
)

except requests.RequestException as e:
return JsonResponse(
{"status": "error", "message": f"Network error: {str(e)}"}, status=503
)
return JsonResponse({"status": "error", "message": f"Network error: {str(e)}"}, status=503)
except requests.HTTPError as e:
return JsonResponse(
{"status": "error", "message": f"GitHub API error: {str(e)}"},
status=e.response.status_code,
)
return JsonResponse({"status": "error", "message": f"GitHub API error: {str(e)}"}, status=e.response.status_code)
except ValueError as e:
return JsonResponse(
{"status": "error", "message": f"Data parsing error: {str(e)}"}, status=400
)
return JsonResponse({"status": "error", "message": f"Data parsing error: {str(e)}"}, status=400)

return super().post(request, *args, **kwargs)

0 comments on commit 396f36a

Please sign in to comment.