From 4f76459edb7134503708c52a8284498eaa9eea98 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 16 Jan 2025 14:46:40 +0530 Subject: [PATCH 01/20] Added slack field in models.py and slack link display project_detail.html. Also a csv of slack project channels of OWASP is added. --- project_channels.csv | 114 ++++++++++ website/models.py | 2 + .../templates/projects/project_detail.html | 12 ++ website/views/project.py | 201 ++++++++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 project_channels.csv diff --git a/project_channels.csv b/project_channels.csv new file mode 100644 index 000000000..95d0d7af2 --- /dev/null +++ b/project_channels.csv @@ -0,0 +1,114 @@ +name,id,link +project-zap,C04SX2GAS,https://OWASP.slack.com/archives/C04SX2GAS +project-xenotix,C04T4HY7U,https://OWASP.slack.com/archives/C04T4HY7U +project-railsgoat,C04THC44W,https://OWASP.slack.com/archives/C04THC44W +project-o2,C04TJNC8M,https://OWASP.slack.com/archives/C04TJNC8M +project-nodegoat,C04TQK9UF,https://OWASP.slack.com/archives/C04TQK9UF +project-hackademic,C050BRC9M,https://OWASP.slack.com/archives/C050BRC9M +project-scg,C050V7CNL,https://OWASP.slack.com/archives/C050V7CNL +project-sec-shepherd,C051M1G3A,https://OWASP.slack.com/archives/C051M1G3A +project-dotnet,C053H58SK,https://OWASP.slack.com/archives/C053H58SK +project-zap-notify,C061VMC87,https://OWASP.slack.com/archives/C061VMC87 +project-asvs,C06MNF14M,https://OWASP.slack.com/archives/C06MNF14M +project-webgoat,C0948GVLM,https://OWASP.slack.com/archives/C0948GVLM +project-webgoat-notif,C09H06VFA,https://OWASP.slack.com/archives/C09H06VFA +project-zsc,C09HKQ0D7,https://OWASP.slack.com/archives/C09HKQ0D7 +project-devops,C09MLAY8P,https://OWASP.slack.com/archives/C09MLAY8P +project-wafec,C0BBA9FM0,https://OWASP.slack.com/archives/C0BBA9FM0 +project-hacakdemic,C0BR2NMUG,https://OWASP.slack.com/archives/C0BR2NMUG +project-skf,C0F7L9X6V,https://OWASP.slack.com/archives/C0F7L9X6V +project-csrfguard,C0H1KR347,https://OWASP.slack.com/archives/C0H1KR347 +project-glue,C0HVCFDP0,https://OWASP.slack.com/archives/C0HVCFDP0 +project-appsensor,C0KJ7JMCJ,https://OWASP.slack.com/archives/C0KJ7JMCJ +project-samm,C0VF1EJGH,https://OWASP.slack.com/archives/C0VF1EJGH +project-virtualvillag,C18A8EGKH,https://OWASP.slack.com/archives/C18A8EGKH +project-mobile-app-security,C1M6ZVC6S,https://OWASP.slack.com/archives/C1M6ZVC6S +project-vicnum,C1MAN1B08,https://OWASP.slack.com/archives/C1MAN1B08 +project-top-10,C1QBMGU69,https://OWASP.slack.com/archives/C1QBMGU69 +project-embeddedappsec,C1TJMUNG3,https://OWASP.slack.com/archives/C1TJMUNG3 +project-juiceshop,C255XSY04,https://OWASP.slack.com/archives/C255XSY04 +project-igoat,C2BKNP7DZ,https://OWASP.slack.com/archives/C2BKNP7DZ +project-blt,C2FF0UVHU,https://OWASP.slack.com/archives/C2FF0UVHU +project-olg-github,C3F2F9TMY,https://OWASP.slack.com/archives/C3F2F9TMY +project-riskrating,C56GPPD6Z,https://OWASP.slack.com/archives/C56GPPD6Z +project-riskrating_mp,C56GQ0ZHT,https://OWASP.slack.com/archives/C56GQ0ZHT +project-owtf,C5M114999,https://OWASP.slack.com/archives/C5M114999 +project-blt-github,C5QAK3Q9G,https://OWASP.slack.com/archives/C5QAK3Q9G +project-securityrat,C76U4TNFJ,https://OWASP.slack.com/archives/C76U4TNFJ +project-malware,C9G489878,https://OWASP.slack.com/archives/C9G489878 +project-securetea,C9GAF53NK,https://OWASP.slack.com/archives/C9GAF53NK +project-devslop,CA1PNFZSR,https://OWASP.slack.com/archives/CA1PNFZSR +project-mobile-app-security-dev,CCBAP0CGN,https://OWASP.slack.com/archives/CCBAP0CGN +project-sls-top-10,CD9D8J41E,https://OWASP.slack.com/archives/CD9D8J41E +project-scvs,CGH5X9NQ0,https://OWASP.slack.com/archives/CGH5X9NQ0 +project-packman,CHKT6HKTK,https://OWASP.slack.com/archives/CHKT6HKTK +project-security-bot,CLMA4F01J,https://OWASP.slack.com/archives/CLMA4F01J +project-mobile_tm,CLW9F9F0X,https://OWASP.slack.com/archives/CLW9F9F0X +project-integration,CPMEWT342,https://OWASP.slack.com/archives/CPMEWT342 +project-nettacker,CQZGG24FQ,https://OWASP.slack.com/archives/CQZGG24FQ +project-threat-dragon,CURE8PQ68,https://OWASP.slack.com/archives/CURE8PQ68 +project-pygoat,C013HSLMTFE,https://OWASP.slack.com/archives/C013HSLMTFE +project-blt-gsoc-standup,C0145BH2P70,https://OWASP.slack.com/archives/C0145BH2P70 +project-samuraiwtf,C01524KH43G,https://OWASP.slack.com/archives/C01524KH43G +project-isvs,C01600RMP9P,https://OWASP.slack.com/archives/C01600RMP9P +project-off,C016U8XQ95H,https://OWASP.slack.com/archives/C016U8XQ95H +project-curriculum,C017AC06QV7,https://OWASP.slack.com/archives/C017AC06QV7 +project-sponsorship,C018P1JUPUH,https://OWASP.slack.com/archives/C018P1JUPUH +project-committee,C01930CGW23,https://OWASP.slack.com/archives/C01930CGW23 +project-how-to-get-into-appsec,C01KF26B1UH,https://OWASP.slack.com/archives/C01KF26B1UH +project-purpleteam,C01LARX6WP8,https://OWASP.slack.com/archives/C01LARX6WP8 +project-html-sanitizer,C0250DKTFCP,https://OWASP.slack.com/archives/C0250DKTFCP +project-developeroutreach,C02CXL4USFM,https://OWASP.slack.com/archives/C02CXL4USFM +project-cre,C02EAS3MY84,https://OWASP.slack.com/archives/C02EAS3MY84 +project-snow,C02EX68P1UJ,https://OWASP.slack.com/archives/C02EX68P1UJ +project-wrongsecrets,C02KQ7D9XHR,https://OWASP.slack.com/archives/C02KQ7D9XHR +project-pytm,C02KRQ0CATB,https://OWASP.slack.com/archives/C02KRQ0CATB +project-secure-code-review-guide,C02QDREE0M7,https://OWASP.slack.com/archives/C02QDREE0M7 +project-podcast,C02U3MTA13K,https://OWASP.slack.com/archives/C02U3MTA13K +project-iot-top10,C034JK2BFGW,https://OWASP.slack.com/archives/C034JK2BFGW +project-wrongsecrets-dev,C039L78LSER,https://OWASP.slack.com/archives/C039L78LSER +project-wrongsecrets-callback,C03BCJ1BXNK,https://OWASP.slack.com/archives/C03BCJ1BXNK +project-security-culture,C03CHLJ1YLR,https://OWASP.slack.com/archives/C03CHLJ1YLR +project-k8s-top10,C03FV6MSRCM,https://OWASP.slack.com/archives/C03FV6MSRCM +project-safetypes,C0432Q430Q3,https://OWASP.slack.com/archives/C0432Q430Q3 +project-continuous-penetration-testing-framework,C0484CAPBE0,https://OWASP.slack.com/archives/C0484CAPBE0 +project-domain-protect,C04BPJ5B2P4,https://OWASP.slack.com/archives/C04BPJ5B2P4 +project-secure-coding-practices,C04DZ254HFG,https://OWASP.slack.com/archives/C04DZ254HFG +project-go-scp,C04FG14MN5B,https://OWASP.slack.com/archives/C04FG14MN5B +project-ai-community,C04FV0D1GES,https://OWASP.slack.com/archives/C04FV0D1GES +project-devsecops-verification-standard,C04HD8ES72M,https://OWASP.slack.com/archives/C04HD8ES72M +project-mlsec-top-10,C04PESBUWRZ,https://OWASP.slack.com/archives/C04PESBUWRZ +project-developer-guide,C04QN6CMNAC,https://OWASP.slack.com/archives/C04QN6CMNAC +project-vulnerability-maturity-sig,C04QWA7R3C7,https://OWASP.slack.com/archives/C04QWA7R3C7 +project-blt-flutter-github,C04SCC5Q3RT,https://OWASP.slack.com/archives/C04SCC5Q3RT +project-committee-github,C0506NPJ2EM,https://OWASP.slack.com/archives/C0506NPJ2EM +project-asvs-nuclei,C052939BZ43,https://OWASP.slack.com/archives/C052939BZ43 +project-blt-codemagic,C052AAELH3P,https://OWASP.slack.com/archives/C052AAELH3P +project-new-projects,C052TF4AA84,https://OWASP.slack.com/archives/C052TF4AA84 +project-raider,C053YNZNEFP,https://OWASP.slack.com/archives/C053YNZNEFP +project-api-top10,C0558AF1QQM,https://OWASP.slack.com/archives/C0558AF1QQM +project-top10-for-llm,C05956H7R8R,https://OWASP.slack.com/archives/C05956H7R8R +project-osib,C05DPB4M1Q8,https://OWASP.slack.com/archives/C05DPB4M1Q8 +project-blt-prs,C05FBSPALLS,https://OWASP.slack.com/archives/C05FBSPALLS +project-nightingale,C05JPRM5GP8,https://OWASP.slack.com/archives/C05JPRM5GP8 +project-sweeper,C0607RP8MS8,https://OWASP.slack.com/archives/C0607RP8MS8 +project-securecodebox,C062TQANH3N,https://OWASP.slack.com/archives/C062TQANH3N +project-modsecurity,C069PCXSW12,https://OWASP.slack.com/archives/C069PCXSW12 +project-blockchain-appsec-standard,C06A53BF0QY,https://OWASP.slack.com/archives/C06A53BF0QY +project-security-c4po,C06ECA5U8SY,https://OWASP.slack.com/archives/C06ECA5U8SY +project-common-lifecycle-enumeration,C06GUKY03NC,https://OWASP.slack.com/archives/C06GUKY03NC +project-pscf,C06HQQF04CU,https://OWASP.slack.com/archives/C06HQQF04CU +project-sdrf,C06J07ZG7DE,https://OWASP.slack.com/archives/C06J07ZG7DE +project-llmvs,C06MDJG0KBK,https://OWASP.slack.com/archives/C06MDJG0KBK +project-blt-lettuce,C06R1H90JKV,https://OWASP.slack.com/archives/C06R1H90JKV +project-blt-lettuce-deploys,C06RBJ779CH,https://OWASP.slack.com/archives/C06RBJ779CH +project-blt-bacon,C06RNAENB4P,https://OWASP.slack.com/archives/C06RNAENB4P +project-flop-10,C072N37N82Z,https://OWASP.slack.com/archives/C072N37N82Z +project-ai-masteraisecurity,C077YSV1D7C,https://OWASP.slack.com/archives/C077YSV1D7C +project-netryx,C07D6R13URM,https://OWASP.slack.com/archives/C07D6R13URM +project-ot-top-10,C07HDTYRA6R,https://OWASP.slack.com/archives/C07HDTYRA6R +project-nest,C07JLLG2GFQ,https://OWASP.slack.com/archives/C07JLLG2GFQ +project-top10-proactive-controls,C07KNHZAN1H,https://OWASP.slack.com/archives/C07KNHZAN1H +project-actions,C07PMR5RV1A,https://OWASP.slack.com/archives/C07PMR5RV1A +project-aibom-community,C07UZUAJTL4,https://OWASP.slack.com/archives/C07UZUAJTL4 +project-scstg,C083UNMMVMH,https://OWASP.slack.com/archives/C083UNMMVMH diff --git a/website/models.py b/website/models.py index 9172cabc6..6d5d28d7d 100644 --- a/website/models.py +++ b/website/models.py @@ -912,6 +912,8 @@ class Project(models.Model): ) # Made url nullable in case of no website project_visit_count = models.IntegerField(default=0) twitter = models.CharField(max_length=30, null=True, blank=True) + slack = models.URLField(null=True, blank=True) + facebook = models.URLField(null=True, blank=True) logo = models.ImageField(upload_to="project_logos", null=True, blank=True) created = models.DateTimeField(auto_now_add=True) # Standardized field name diff --git a/website/templates/projects/project_detail.html b/website/templates/projects/project_detail.html index d9b0126da..37ded010b 100644 --- a/website/templates/projects/project_detail.html +++ b/website/templates/projects/project_detail.html @@ -6,6 +6,7 @@ {% endblock title %} {% block content %} {% include "includes/sidenav.html" %} +

This is where you edited

diff --git a/website/views/project.py b/website/views/project.py index b8d6f2e28..ec4e5a844 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -128,6 +128,7 @@ def get(self, request, slug): address=user_ip, path=request.path, created__date=today ).last() +<<<<<<< HEAD if visited_data: # If the creation date is today if visited_data.created.date() == today: @@ -135,6 +136,206 @@ def get(self, request, slug): if visited_data.count == 1: project.project_visit_count = F("project_visit_count") + 1 project.save() +======= + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + project = self.get_object() + 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, + "slack_channel_url": project.slack, + } + ) + return context + + +# class ProjectBadgeView(APIView): +# def get(self, request, slug): +# # Retrieve the project or return 404 +# project = get_object_or_404(Project, slug=slug) + +# # Get unique visits, grouped by date +# visit_counts = ( +# IP.objects.filter(path=request.path) +# .annotate(date=TruncDate("created")) +# .values("date") +# .annotate(visit_count=Count("address")) +# .order_by("date") # Order from oldest to newest +# ) + +# # Update project visit count +# project.repo_visit_count += 1 +# project.save() + +# # Extract dates and counts +# dates = [entry["date"] for entry in visit_counts] +# counts = [entry["visit_count"] for entry in visit_counts] +# total_views = sum(counts) # Calculate total views + +# fig = plt.figure(figsize=(4, 1)) +# plt.bar(dates, counts, width=0.5, color="red") + +# plt.title( +# f"{total_views}", +# loc="left", +# x=-0.36, +# y=0.3, +# fontsize=15, +# fontweight="bold", +# color="red", +# ) + +# plt.gca().set_xticks([]) # Remove x-axis ticks +# plt.gca().set_yticks([]) +# plt.box(False) + +# # Save the plot to an in-memory file +# buffer = BytesIO() +# plt.savefig(buffer, format="png", bbox_inches="tight") +# plt.close() +# buffer.seek(0) + +# # Prepare the HTTP response with the bar graph image +# response = HttpResponse(buffer, content_type="image/png") +# response["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0" +# response["Pragma"] = "no-cache" +# response["Expires"] = "0" + +# 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...") + from django.template.loader import get_template + print(get_template('project_list').origin) + 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.") +>>>>>>> 56d95813 (Added slack field in models.py and slack link display project_detail.html. Also a csv of slack project channels of OWASP is added.) else: # If the creation date is not today, reset the creation date and count visited_data.created = now() From 3137c36b8d58774a2b4d01adfd1d7b691226fe85 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:04:19 +0530 Subject: [PATCH 02/20] Update project.py --- website/views/project.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/views/project.py b/website/views/project.py index ec4e5a844..f9781b3b4 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -128,7 +128,6 @@ def get(self, request, slug): address=user_ip, path=request.path, created__date=today ).last() -<<<<<<< HEAD if visited_data: # If the creation date is today if visited_data.created.date() == today: @@ -136,7 +135,7 @@ def get(self, request, slug): if visited_data.count == 1: project.project_visit_count = F("project_visit_count") + 1 project.save() -======= + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) project = self.get_object() @@ -335,7 +334,6 @@ def post(self, request, *args, **kwargs): messages.info(request, "Project already exists.") else: messages.error(request, "Failed to fetch project from GitHub.") ->>>>>>> 56d95813 (Added slack field in models.py and slack link display project_detail.html. Also a csv of slack project channels of OWASP is added.) else: # If the creation date is not today, reset the creation date and count visited_data.created = now() From 9a87fe12f119b97abe170f2d7f5c4db318fb1d4a Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:17:11 +0530 Subject: [PATCH 03/20] Update project.py --- website/views/project.py | 1 + 1 file changed, 1 insertion(+) diff --git a/website/views/project.py b/website/views/project.py index f9781b3b4..03a84007a 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -8,6 +8,7 @@ from io import BytesIO from pathlib import Path from urllib.parse import urlparse +from django.views.generic.list import ListView import django_filters import matplotlib.pyplot as plt From 35034ba2d7cc7b337d1325175f794d0cd07c534e Mon Sep 17 00:00:00 2001 From: DonnieBLT <128622481+DonnieBLT@users.noreply.github.com> Date: Thu, 16 Jan 2025 06:51:25 -0500 Subject: [PATCH 04/20] Fix typo in project-blt-gsoc-standup name --- project_channels.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project_channels.csv b/project_channels.csv index 95d0d7af2..960ae3f3a 100644 --- a/project_channels.csv +++ b/project_channels.csv @@ -48,7 +48,7 @@ project-integration,CPMEWT342,https://OWASP.slack.com/archives/CPMEWT342 project-nettacker,CQZGG24FQ,https://OWASP.slack.com/archives/CQZGG24FQ project-threat-dragon,CURE8PQ68,https://OWASP.slack.com/archives/CURE8PQ68 project-pygoat,C013HSLMTFE,https://OWASP.slack.com/archives/C013HSLMTFE -project-blt-gsoc-standup,C0145BH2P70,https://OWASP.slack.com/archives/C0145BH2P70 +project-blt-gsoc-rehndndup,C0145BH2P70,https://OWASP.slack.com/archives/C0145BH2P70 project-samuraiwtf,C01524KH43G,https://OWASP.slack.com/archives/C01524KH43G project-isvs,C01600RMP9P,https://OWASP.slack.com/archives/C01600RMP9P project-off,C016U8XQ95H,https://OWASP.slack.com/archives/C016U8XQ95H From 61b4b8925fd3fb3ab6d3689e1cd23d2b2aabb505 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sat, 18 Jan 2025 02:07:08 +0530 Subject: [PATCH 05/20] Update project.py --- website/views/project.py | 213 +++------------------------------------ 1 file changed, 13 insertions(+), 200 deletions(-) diff --git a/website/views/project.py b/website/views/project.py index 03a84007a..7c521bf7a 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -8,7 +8,6 @@ from io import BytesIO from pathlib import Path from urllib.parse import urlparse -from django.views.generic.list import ListView import django_filters import matplotlib.pyplot as plt @@ -136,205 +135,6 @@ def get(self, request, slug): if visited_data.count == 1: project.project_visit_count = F("project_visit_count") + 1 project.save() - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - project = self.get_object() - 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, - "slack_channel_url": project.slack, - } - ) - return context - - -# class ProjectBadgeView(APIView): -# def get(self, request, slug): -# # Retrieve the project or return 404 -# project = get_object_or_404(Project, slug=slug) - -# # Get unique visits, grouped by date -# visit_counts = ( -# IP.objects.filter(path=request.path) -# .annotate(date=TruncDate("created")) -# .values("date") -# .annotate(visit_count=Count("address")) -# .order_by("date") # Order from oldest to newest -# ) - -# # Update project visit count -# project.repo_visit_count += 1 -# project.save() - -# # Extract dates and counts -# dates = [entry["date"] for entry in visit_counts] -# counts = [entry["visit_count"] for entry in visit_counts] -# total_views = sum(counts) # Calculate total views - -# fig = plt.figure(figsize=(4, 1)) -# plt.bar(dates, counts, width=0.5, color="red") - -# plt.title( -# f"{total_views}", -# loc="left", -# x=-0.36, -# y=0.3, -# fontsize=15, -# fontweight="bold", -# color="red", -# ) - -# plt.gca().set_xticks([]) # Remove x-axis ticks -# plt.gca().set_yticks([]) -# plt.box(False) - -# # Save the plot to an in-memory file -# buffer = BytesIO() -# plt.savefig(buffer, format="png", bbox_inches="tight") -# plt.close() -# buffer.seek(0) - -# # Prepare the HTTP response with the bar graph image -# response = HttpResponse(buffer, content_type="image/png") -# response["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0" -# response["Pragma"] = "no-cache" -# response["Expires"] = "0" - -# 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...") - from django.template.loader import get_template - print(get_template('project_list').origin) - 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: # If the creation date is not today, reset the creation date and count visited_data.created = now() @@ -579,6 +379,18 @@ def validate_url(url): }, status=400, ) + slack = request.POST.get("slack") + if slack: + if slack.startswith(("http://", "https://")): + if not validate_url(slack): + return JsonResponse( + { + "error": "Slack URL is not accessible", + "code": "INVALID_SLACK_URL", + }, + status=400, + ) + # Validate repository URLs repo_urls = request.POST.getlist("repo_urls[]") @@ -658,6 +470,7 @@ def validate_url(url): "url": project_url, "twitter": request.POST.get("twitter"), "facebook": request.POST.get("facebook"), + "slack": request.POST.get("slack"), } # Handle logo file From 5d6b066adea37f5b0cb463a07e8346bfdcf875db Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Sat, 18 Jan 2025 02:06:19 +0530 Subject: [PATCH 06/20] Updates in the previous pr --- website/migrations/0180_project_slack.py | 18 ++++++++++++++++++ website/migrations/0181_alter_project_slack.py | 18 ++++++++++++++++++ website/migrations/0182_merge_20250116_0944.py | 13 +++++++++++++ website/templates/projects/project_list.html | 8 ++++++++ website/templates/projects/repo_detail.html | 9 +++++++++ website/views/project.py | 2 +- 6 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 website/migrations/0180_project_slack.py create mode 100644 website/migrations/0181_alter_project_slack.py create mode 100644 website/migrations/0182_merge_20250116_0944.py diff --git a/website/migrations/0180_project_slack.py b/website/migrations/0180_project_slack.py new file mode 100644 index 000000000..3d58f52b9 --- /dev/null +++ b/website/migrations/0180_project_slack.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-01-12 08:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0179_contributorstats"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="slack", + field=models.CharField(blank=True, max_length=30, null=True), + ), + ] diff --git a/website/migrations/0181_alter_project_slack.py b/website/migrations/0181_alter_project_slack.py new file mode 100644 index 000000000..63362c90e --- /dev/null +++ b/website/migrations/0181_alter_project_slack.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-01-15 15:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0180_project_slack"), + ] + + operations = [ + migrations.AlterField( + model_name="project", + name="slack", + field=models.URLField(blank=True, null=True), + ), + ] diff --git a/website/migrations/0182_merge_20250116_0944.py b/website/migrations/0182_merge_20250116_0944.py new file mode 100644 index 000000000..95888aa5b --- /dev/null +++ b/website/migrations/0182_merge_20250116_0944.py @@ -0,0 +1,13 @@ +# Generated by Django 5.1.4 on 2025-01-16 09:44 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0180_rename_project_visit_count_repo_repo_visit_count"), + ("website", "0181_alter_project_slack"), + ] + + operations = [] diff --git a/website/templates/projects/project_list.html b/website/templates/projects/project_list.html index 20707bc16..7095d2b86 100644 --- a/website/templates/projects/project_list.html +++ b/website/templates/projects/project_list.html @@ -358,6 +358,14 @@

Add New Project

class="mt-1 w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500" placeholder="https://facebook.com/..." /> + +
+ + +
diff --git a/website/templates/projects/repo_detail.html b/website/templates/projects/repo_detail.html index 95ef68032..c1ab349c4 100644 --- a/website/templates/projects/repo_detail.html +++ b/website/templates/projects/repo_detail.html @@ -62,6 +62,15 @@

{{ repo.name }}

Visit Homepage {% endif %} + {% if repo.slack%} + + + + + Join on Slack + + {% endif %} + diff --git a/website/views/project.py b/website/views/project.py index 7c521bf7a..c79628d9d 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -1413,4 +1413,4 @@ def get(self, request, slug): response["Pragma"] = "no-cache" response["Expires"] = "0" - return response + return response \ No newline at end of file From 5844ba61812ae2b014aefae096065aca83be5aeb Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sat, 18 Jan 2025 21:32:11 +0530 Subject: [PATCH 07/20] Update project_channels.csv --- project_channels.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project_channels.csv b/project_channels.csv index 960ae3f3a..05cf67336 100644 --- a/project_channels.csv +++ b/project_channels.csv @@ -48,7 +48,7 @@ project-integration,CPMEWT342,https://OWASP.slack.com/archives/CPMEWT342 project-nettacker,CQZGG24FQ,https://OWASP.slack.com/archives/CQZGG24FQ project-threat-dragon,CURE8PQ68,https://OWASP.slack.com/archives/CURE8PQ68 project-pygoat,C013HSLMTFE,https://OWASP.slack.com/archives/C013HSLMTFE -project-blt-gsoc-rehndndup,C0145BH2P70,https://OWASP.slack.com/archives/C0145BH2P70 +project-blt-gsoc-rehndndup,C0145BH2P70,https://OWASP.slack.com/archives/C0145BH2P70 project-samuraiwtf,C01524KH43G,https://OWASP.slack.com/archives/C01524KH43G project-isvs,C01600RMP9P,https://OWASP.slack.com/archives/C01600RMP9P project-off,C016U8XQ95H,https://OWASP.slack.com/archives/C016U8XQ95H From e1e95ef1b1ee0c54b5d010f82c02310d07cebe3f Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sun, 19 Jan 2025 15:20:36 +0530 Subject: [PATCH 08/20] Update project_channels.csv --- project_channels.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project_channels.csv b/project_channels.csv index 05cf67336..a1a11d354 100644 --- a/project_channels.csv +++ b/project_channels.csv @@ -1,4 +1,4 @@ -name,id,link +slack_channel,slack_id,slack_url project-zap,C04SX2GAS,https://OWASP.slack.com/archives/C04SX2GAS project-xenotix,C04T4HY7U,https://OWASP.slack.com/archives/C04T4HY7U project-railsgoat,C04THC44W,https://OWASP.slack.com/archives/C04THC44W From c9692da88f457aa2398f69bf84310e69a7ccc899 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sun, 19 Jan 2025 15:21:36 +0530 Subject: [PATCH 09/20] Update project_channels.csv From 44273ac06169da87c105fe95a5c217fd80a496c1 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:14:33 +0530 Subject: [PATCH 10/20] Update website/templates/projects/repo_detail.html Co-authored-by: DonnieBLT <128622481+DonnieBLT@users.noreply.github.com> --- website/templates/projects/repo_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/projects/repo_detail.html b/website/templates/projects/repo_detail.html index c1ab349c4..6632bdd48 100644 --- a/website/templates/projects/repo_detail.html +++ b/website/templates/projects/repo_detail.html @@ -62,7 +62,7 @@

{{ repo.name }}

Visit Homepage
{% endif %} - {% if repo.slack%} + {% if repo.slack %} From 955af6efc03067f42881c5fec6d40e7a62880e55 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:15:16 +0530 Subject: [PATCH 11/20] Update website/templates/projects/project_detail.html Co-authored-by: DonnieBLT <128622481+DonnieBLT@users.noreply.github.com> --- website/templates/projects/project_detail.html | 1 - 1 file changed, 1 deletion(-) diff --git a/website/templates/projects/project_detail.html b/website/templates/projects/project_detail.html index 37ded010b..6afc78a64 100644 --- a/website/templates/projects/project_detail.html +++ b/website/templates/projects/project_detail.html @@ -6,7 +6,6 @@ {% endblock title %} {% block content %} {% include "includes/sidenav.html" %} -

This is where you edited

diff --git a/website/templates/projects/repo_detail.html b/website/templates/projects/repo_detail.html index 6632bdd48..f5112de19 100644 --- a/website/templates/projects/repo_detail.html +++ b/website/templates/projects/repo_detail.html @@ -63,14 +63,18 @@

{{ repo.name }}

{% endif %} {% if repo.slack %} - - + + Join on Slack {% endif %} - diff --git a/website/views/project.py b/website/views/project.py index c79628d9d..3477afda7 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -391,7 +391,6 @@ def validate_url(url): status=400, ) - # Validate repository URLs repo_urls = request.POST.getlist("repo_urls[]") for url in repo_urls: @@ -1413,4 +1412,4 @@ def get(self, request, slug): response["Pragma"] = "no-cache" response["Expires"] = "0" - return response \ No newline at end of file + return response From 7c9849a9b49188c2a48a1d40cf95221c9505fa27 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Fri, 24 Jan 2025 13:52:44 +0530 Subject: [PATCH 13/20] update pr2 --- website/admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/website/admin.py b/website/admin.py index 991bfff79..15d59944f 100644 --- a/website/admin.py +++ b/website/admin.py @@ -31,7 +31,6 @@ PRAnalysisReport, Project, Repo, - SlackChannel, SlackIntegration, Subscription, Suggestion, From 71b7cc189585e537f2199a08649bc9673b8c25dc Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Fri, 24 Jan 2025 22:36:04 +0530 Subject: [PATCH 14/20] precommit work --- blt/middleware/ip_restrict.py | 8 +- blt/settings.py | 4 +- blt/urls.py | 8 +- comments/migrations/0001_initial.py | 4 +- comments/migrations/0002_comment_parentid.py | 4 +- .../migrations/0005_auto_20170727_1309.py | 4 +- comments/views.py | 12 +- website/api/views.py | 88 +++------ website/bitcoin_utils.py | 4 +- website/bot.py | 12 +- website/consumers.py | 33 +--- website/management/commands/check_keywords.py | 8 +- .../commands/check_owasp_projects.py | 111 +++--------- .../management/commands/check_trademarks.py | 8 +- .../commands/fetch_contributor_stats.py | 15 +- .../management/commands/fetch_contributors.py | 4 +- website/management/commands/initsuperuser.py | 4 +- .../commands/owasp_project_upload.py | 168 ++++-------------- .../commands/slack_daily_timelogs.py | 16 +- .../commands/update_contributor_stats.py | 66 ++----- website/management/commands/update_faiss.py | 4 +- .../management/commands/update_projects.py | 30 +--- website/migrations/0001_initial.py | 4 +- website/migrations/0002_auto_20160828_0116.py | 8 +- website/migrations/0003_auto_20160831_2326.py | 12 +- website/migrations/0004_auto_20160903_2344.py | 8 +- website/migrations/0006_auto_20160920_1713.py | 4 +- website/migrations/0014_auto_20161113_1417.py | 4 +- website/migrations/0023_invitefriend.py | 8 +- website/migrations/0024_userprofile.py | 4 +- website/migrations/0025_auto_20170605_1909.py | 8 +- website/migrations/0037_auto_20170813_0319.py | 4 +- website/migrations/0044_auto_20170907_1605.py | 4 +- website/migrations/0045_auto_20180314_2032.py | 4 +- website/migrations/0046_auto_20180630_0848.py | 4 +- website/migrations/0047_auto_20200613_0814.py | 12 +- website/migrations/0052_auto_20200619_0540.py | 4 +- website/migrations/0053_auto_20200619_0551.py | 4 +- website/migrations/0059_transaction_wallet.py | 16 +- website/migrations/0061_payment.py | 8 +- website/migrations/0066_auto_20200827_1733.py | 4 +- .../0070_alter_issue_label_issuescreenshot.py | 4 +- ...mpany_managers_domain_managers_and_more.py | 4 +- .../migrations/0077_hunt_banner_huntprize.py | 4 +- ...079_userprofile_crypto_address_and_more.py | 8 +- .../0080_alter_issue_team_members.py | 4 +- ...083_alter_invitefriend_options_and_more.py | 4 +- .../migrations/0090_alter_domain_managers.py | 4 +- .../0097_contributor_project_contributors.py | 4 +- website/migrations/0101_alter_bid_user.py | 4 +- ...move_bid_amount_bid_amount_bch_and_more.py | 4 +- .../0103_contribution_bacontoken.py | 4 +- ...userprofile_subscribed_domains_and_more.py | 4 +- .../0144_delete_contributorstats_and_more.py | 4 +- ...5_syning_contributors_tag_20241124_0457.py | 4 +- website/migrations/0157_badge_userbadge.py | 4 +- ...islike_count_activity_dislikes_and_more.py | 4 +- website/migrations/0165_add_badge_icons.py | 4 +- website/migrations/0168_add_streak_badges.py | 4 +- ...in_remove_company_integrations_and_more.py | 4 +- ...ributor_repo_contributor_count_and_more.py | 4 +- website/serializers.py | 6 +- website/signals.py | 18 +- website/test_api.py | 3 +- website/test_blog.py | 4 +- website/test_issues.py | 8 +- website/test_slack.py | 4 +- website/tests.py | 32 +--- website/tests_urls.py | 12 +- website/utils.py | 30 +--- website/views/company.py | 127 ++++--------- website/views/core.py | 47 ++--- website/views/issue.py | 158 +++++----------- website/views/organization.py | 162 +++++------------ website/views/project.py | 88 +++------ website/views/slackbot.py | 26 +-- website/views/teams.py | 25 +-- website/views/user.py | 70 ++------ 78 files changed, 406 insertions(+), 1237 deletions(-) diff --git a/blt/middleware/ip_restrict.py b/blt/middleware/ip_restrict.py index 783f6a31a..2c9118d6b 100644 --- a/blt/middleware/ip_restrict.py +++ b/blt/middleware/ip_restrict.py @@ -87,9 +87,7 @@ def increment_block_count(self, ip=None, network=None, user_agent=None): if ip: blocked_entry = Blocked.objects.select_for_update().filter(address=ip).first() elif network: - blocked_entry = ( - Blocked.objects.select_for_update().filter(ip_network=network).first() - ) + blocked_entry = Blocked.objects.select_for_update().filter(ip_network=network).first() elif user_agent: # Correct lookup: find if any user_agent_string is a substring of the user_agent blocked_entry = ( @@ -111,9 +109,7 @@ def increment_block_count(self, ip=None, network=None, user_agent=None): blocked_entry.save(update_fields=["count"]) def __call__(self, request): - ip = request.META.get("HTTP_X_FORWARDED_FOR", "").split(",")[0].strip() or request.META.get( - "REMOTE_ADDR", "" - ) + ip = request.META.get("HTTP_X_FORWARDED_FOR", "").split(",")[0].strip() or request.META.get("REMOTE_ADDR", "") agent = request.META.get("HTTP_USER_AGENT", "").strip() blocked_ips = self.blocked_ips() diff --git a/blt/settings.py b/blt/settings.py index ae9f8bf1e..dd9a6f914 100644 --- a/blt/settings.py +++ b/blt/settings.py @@ -244,9 +244,7 @@ if not GOOGLE_CREDENTIALS: raise Exception("GOOGLE_CREDENTIALS environment variable is not set.") - GS_CREDENTIALS = service_account.Credentials.from_service_account_info( - json.loads(GOOGLE_CREDENTIALS) - ) + GS_CREDENTIALS = service_account.Credentials.from_service_account_info(json.loads(GOOGLE_CREDENTIALS)) STORAGES = { "default": { diff --git a/blt/urls.py b/blt/urls.py index 4ede4e748..37cfdef7c 100644 --- a/blt/urls.py +++ b/blt/urls.py @@ -35,13 +35,7 @@ UserIssueViewSet, UserProfileViewSet, ) -from website.views.blog import ( - PostCreateView, - PostDeleteView, - PostDetailView, - PostListView, - PostUpdateView, -) +from website.views.blog import PostCreateView, PostDeleteView, PostDetailView, PostListView, PostUpdateView from website.views.company import ( AddDomainView, AddHuntView, diff --git a/comments/migrations/0001_initial.py b/comments/migrations/0001_initial.py index 40d5f807e..3a4517c10 100644 --- a/comments/migrations/0001_initial.py +++ b/comments/migrations/0001_initial.py @@ -19,9 +19,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("author", models.CharField(max_length=200)), ("author_url", models.CharField(max_length=200)), diff --git a/comments/migrations/0002_comment_parentid.py b/comments/migrations/0002_comment_parentid.py index 074746e89..dfc0b6b46 100644 --- a/comments/migrations/0002_comment_parentid.py +++ b/comments/migrations/0002_comment_parentid.py @@ -14,8 +14,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="comment", name="parentId", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="comments.Comment" - ), + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="comments.Comment"), ), ] diff --git a/comments/migrations/0005_auto_20170727_1309.py b/comments/migrations/0005_auto_20170727_1309.py index 72e1793ac..3e6e3209d 100644 --- a/comments/migrations/0005_auto_20170727_1309.py +++ b/comments/migrations/0005_auto_20170727_1309.py @@ -14,8 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="comment", name="parent", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="comments.Comment" - ), + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="comments.Comment"), ), ] diff --git a/comments/views.py b/comments/views.py index 5388781a0..c292a5bec 100644 --- a/comments/views.py +++ b/comments/views.py @@ -128,9 +128,7 @@ def reply_comment(request, pk): issue = Issue.objects.get(pk=request.GET["issue_pk"]) reply_text = request.GET.get("text_comment") reply_text = escape(reply_text) - comment = Comment( - author=author, author_url=author_url, issue=issue, text=reply_text, parent=parent_obj - ) + comment = Comment(author=author, author_url=author_url, issue=issue, text=reply_text, parent=parent_obj) comment.save() all_comment = Comment.objects.filter(issue=issue) return render( @@ -145,15 +143,11 @@ def autocomplete(request): q_string = request.GET.get("search", "") q_string = escape(q_string) if len(q_string) == 0: - return HttpResponse( - request.GET["callback"] + "(" + json.dumps([]) + ");", content_type="application/json" - ) + return HttpResponse(request.GET["callback"] + "(" + json.dumps([]) + ");", content_type="application/json") q_list = q_string.split(" ") q_s = q_list[len(q_list) - 1] if len(q_s) == 0 or q_s[0] != "@": - return HttpResponse( - request.GET["callback"] + "(" + json.dumps([]) + ");", content_type="application/json" - ) + return HttpResponse(request.GET["callback"] + "(" + json.dumps([]) + ");", content_type="application/json") q_s = q_s[1:] search_qs = User.objects.filter(username__startswith=q_s) diff --git a/website/api/views.py b/website/api/views.py index 48feb1c5b..f090191d8 100644 --- a/website/api/views.py +++ b/website/api/views.py @@ -166,15 +166,11 @@ def get_issue_info(self, request, issue): if issue.screenshot: # If an image exists in the Issue table, return it along with additional images from IssueScreenshot screenshots = [request.build_absolute_uri(issue.screenshot.url)] + [ - request.build_absolute_uri(screenshot.image.url) - for screenshot in issue.screenshots.all() + request.build_absolute_uri(screenshot.image.url) for screenshot in issue.screenshots.all() ] else: # If no image exists in the Issue table, return only the images from IssueScreenshot - screenshots = [ - request.build_absolute_uri(screenshot.image.url) - for screenshot in issue.screenshots.all() - ] + screenshots = [request.build_absolute_uri(screenshot.image.url) for screenshot in issue.screenshots.all()] is_upvoted = False is_flagged = False @@ -232,9 +228,7 @@ def create(self, request, *args, **kwargs): screenshot_count = len(self.request.FILES.getlist("screenshots")) if screenshot_count == 0: - return Response( - {"error": "Upload at least one image!"}, status=status.HTTP_400_BAD_REQUEST - ) + return Response({"error": "Upload at least one image!"}, status=status.HTTP_400_BAD_REQUEST) elif screenshot_count > 5: return Response({"error": "Max limit of 5 images!"}, status=status.HTTP_400_BAD_REQUEST) @@ -247,9 +241,7 @@ def create(self, request, *args, **kwargs): for screenshot in self.request.FILES.getlist("screenshots"): if image_validator(screenshot): filename = screenshot.name - screenshot.name = ( - f"{filename[:10]}{str(uuid.uuid4())[:40]}.{filename.split('.')[-1]}" - ) + screenshot.name = f"{filename[:10]}{str(uuid.uuid4())[:40]}.{filename.split('.')[-1]}" file_path = default_storage.save(f"screenshots/{screenshot.name}", screenshot) # Create the IssueScreenshot object and associate it with the issue @@ -387,19 +379,11 @@ def filter(self, request, *args, **kwargs): temp["rank"] = rank_user temp["id"] = each["id"] temp["User"] = each["username"] - temp["score"] = Points.objects.filter(user=each["id"]).aggregate( - total_score=Sum("score") - ) - temp["image"] = list(UserProfile.objects.filter(user=each["id"]).values("user_avatar"))[ - 0 - ] - temp["title_type"] = list(UserProfile.objects.filter(user=each["id"]).values("title"))[ - 0 - ] + temp["score"] = Points.objects.filter(user=each["id"]).aggregate(total_score=Sum("score")) + temp["image"] = list(UserProfile.objects.filter(user=each["id"]).values("user_avatar"))[0] + temp["title_type"] = list(UserProfile.objects.filter(user=each["id"]).values("title"))[0] temp["follows"] = list(UserProfile.objects.filter(user=each["id"]).values("follows"))[0] - temp["savedissue"] = list( - UserProfile.objects.filter(user=each["id"]).values("issue_saved") - )[0] + temp["savedissue"] = list(UserProfile.objects.filter(user=each["id"]).values("issue_saved"))[0] rank_user = rank_user + 1 users.append(temp) @@ -470,9 +454,7 @@ def get(self, request, format=None, *args, **kwargs): def organization_leaderboard(self, request, *args, **kwargs): paginator = PageNumberPagination() organizations = ( - Organization.objects.values() - .annotate(issue_count=Count("domain__issue")) - .order_by("-issue_count") + Organization.objects.values().annotate(issue_count=Count("domain__issue")).order_by("-issue_count") ) page = paginator.paginate_queryset(organizations, request) @@ -486,9 +468,7 @@ def get(self, request, *args, **kwargs): hunt_count = Hunt.objects.all().count() domain_count = Domain.objects.all().count() - return Response( - {"bugs": bug_count, "users": user_count, "hunts": hunt_count, "domains": domain_count} - ) + return Response({"bugs": bug_count, "users": user_count, "hunts": hunt_count, "domains": domain_count}) class UrlCheckApiViewset(APIView): @@ -503,9 +483,7 @@ def post(self, request, *args, **kwargs): domain = domain_url.replace("https://", "").replace("http://", "").replace("www.", "") issues = ( - Issue.objects.filter( - Q(Q(domain__name=domain) | Q(domain__url__icontains=domain)) & Q(is_hidden=False) - ) + Issue.objects.filter(Q(Q(domain__name=domain) | Q(domain__url__icontains=domain)) & Q(is_hidden=False)) .values( "id", "description", @@ -533,27 +511,17 @@ def get_active_hunts(self, request, fields, *args, **kwargs): return Response(hunts) def get_previous_hunts(self, request, fields, *args, **kwargs): - hunts = ( - Hunt.objects.values(*fields) - .filter(is_published=True, end_on__lte=datetime.now()) - .order_by("-end_on") - ) + hunts = Hunt.objects.values(*fields).filter(is_published=True, end_on__lte=datetime.now()).order_by("-end_on") return Response(hunts) def get_upcoming_hunts(self, request, fields, *args, **kwargs): hunts = ( - Hunt.objects.values(*fields) - .filter(is_published=True, starts_on__gte=datetime.now()) - .order_by("starts_on") + Hunt.objects.values(*fields).filter(is_published=True, starts_on__gte=datetime.now()).order_by("starts_on") ) return Response(hunts) def get_search_by_name(self, request, search_query, fields, *args, **kwargs): - hunts = ( - Hunt.objects.values(*fields) - .filter(is_published=True, name__icontains=search_query) - .order_by("end_on") - ) + hunts = Hunt.objects.values(*fields).filter(is_published=True, name__icontains=search_query).order_by("end_on") return Response(hunts) def get(self, request, *args, **kwargs): @@ -608,15 +576,11 @@ def get_active_hunts(self, request, *args, **kwargs): return Response(self.serialize_hunts(hunts)) def get_previous_hunts(self, request, *args, **kwargs): - hunts = Hunt.objects.filter(is_published=True, end_on__lte=datetime.now()).order_by( - "-end_on" - ) + hunts = Hunt.objects.filter(is_published=True, end_on__lte=datetime.now()).order_by("-end_on") return Response(self.serialize_hunts(hunts)) def get_upcoming_hunts(self, request, *args, **kwargs): - hunts = Hunt.objects.filter(is_published=True, starts_on__gte=datetime.now()).order_by( - "starts_on" - ) + hunts = Hunt.objects.filter(is_published=True, starts_on__gte=datetime.now()).order_by("starts_on") return Response(self.serialize_hunts(hunts)) def get(self, request, *args, **kwargs): @@ -626,23 +590,17 @@ def get(self, request, *args, **kwargs): previousHunt = request.query_params.get("previousHunt") upcomingHunt = request.query_params.get("upcomingHunt") if activeHunt: - page = paginator.paginate_queryset( - self.get_active_hunts(request, *args, **kwargs), request - ) + page = paginator.paginate_queryset(self.get_active_hunts(request, *args, **kwargs), request) return paginator.get_paginated_response(page) elif previousHunt: - page = paginator.paginate_queryset( - self.get_previous_hunts(request, *args, **kwargs), request - ) + page = paginator.paginate_queryset(self.get_previous_hunts(request, *args, **kwargs), request) return paginator.get_paginated_response(page) elif upcomingHunt: - page = paginator.paginate_queryset( - self.get_upcoming_hunts(request, *args, **kwargs), request - ) + page = paginator.paginate_queryset(self.get_upcoming_hunts(request, *args, **kwargs), request) return paginator.get_paginated_response(page) @@ -668,9 +626,7 @@ def post(self, request, *args, **kwargs): try: current_site = get_current_site(request) referral_code, created = InviteFriend.objects.get_or_create(sender=request.user) - referral_link = ( - f"https://{current_site.domain}/referral/?ref={referral_code.referral_code}" - ) + referral_link = f"https://{current_site.domain}/referral/?ref={referral_code.referral_code}" # Prepare email content subject = f"Join me on {current_site.name}!" @@ -703,9 +659,7 @@ def post(self, request, *args, **kwargs): } ) else: - return Response( - {"error": "Email failed to send", "email_status": "failed"}, status=500 - ) + return Response({"error": "Email failed to send", "email_status": "failed"}, status=500) except smtplib.SMTPException as e: return Response( diff --git a/website/bitcoin_utils.py b/website/bitcoin_utils.py index 986a5c0e2..ef4cf6972 100644 --- a/website/bitcoin_utils.py +++ b/website/bitcoin_utils.py @@ -25,9 +25,7 @@ def create_bacon_token(user, contribution): contribution.txid = txid contribution.save() - token = BaconToken.objects.create( - user=user, amount=amount, contribution=contribution, token_id=txid - ) + token = BaconToken.objects.create(user=user, amount=amount, contribution=contribution, token_id=txid) return token except JSONRPCException as e: diff --git a/website/bot.py b/website/bot.py index 97ce6d7c8..3b3295dd8 100644 --- a/website/bot.py +++ b/website/bot.py @@ -133,9 +133,7 @@ def embed_documents_and_save(embed_docs): if file.is_file(): with open(file, "rb") as f: content = f.read() - default_storage.save( - str(db_folder_path / file.relative_to(temp_db_path)), ContentFile(content) - ) + default_storage.save(str(db_folder_path / file.relative_to(temp_db_path)), ContentFile(content)) log_chat(f"Uploaded file {file.name} to storage") except Exception as e: log_chat(f"Error during FAISS index embedding and saving: {e}") @@ -156,9 +154,7 @@ def load_vector_store(): check_db_folder_str = db_folder_str + "/index.faiss" if not default_storage.exists(check_db_folder_str): temp_dir.cleanup() - ChatBotLog.objects.create( - question="Folder does not exist", answer=f"Folder Str: {str(db_folder_str)}" - ) + ChatBotLog.objects.create(question="Folder does not exist", answer=f"Folder Str: {str(db_folder_str)}") return None # Download all files from the storage folder to the temp directory @@ -193,9 +189,7 @@ def conversation_chain(vector_store): ) ) llm = ChatOpenAI(model_name="gpt-3.5-turbo-0125", temperature=0.5) - retriever = vector_store.as_retriever( - search_type="similarity", search_kwargs={"k": retrieval_search_results} - ) + retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": retrieval_search_results}) memory = ConversationSummaryMemory( llm=llm, return_messages=True, diff --git a/website/consumers.py b/website/consumers.py index 517544290..3c2cfb2e6 100644 --- a/website/consumers.py +++ b/website/consumers.py @@ -52,9 +52,7 @@ async def receive(self, text_data): branch2 = data.get("branch2") # Branch name for the second repository if not repo1 or not repo2 or not type1 or not type2: - await self.send( - json.dumps({"error": "Both repositories and their types are required."}) - ) + await self.send(json.dumps({"error": "Both repositories and their types are required."})) return if type1 not in ["github", "zip"] or type2 not in ["github", "zip"]: @@ -152,9 +150,7 @@ async def download_and_extract_zip(self, zip_url, temp_dir, repo_name): async with aiohttp.ClientSession() as session: async with session.get(zip_url) as response: if response.status != 200: - raise Exception( - f"Failed to download ZIP file. Status code: {response.status}" - ) + raise Exception(f"Failed to download ZIP file. Status code: {response.status}") # Extract the ZIP file zip_file_path = Path(temp_dir) / f"{repo_name}.zip" @@ -229,9 +225,7 @@ def process_similarity_analysis(self, repo1_path, repo2_path): if i % 5 == 0: # Ping the frontend every 5 iterations try: - asyncio.run( - self.send(json.dumps({"ping": "ping"})) - ) # Send ping from the worker thread + asyncio.run(self.send(json.dumps({"ping": "ping"}))) # Send ping from the worker thread except Exception as e: return None # Stop the analysis if the connection is lost i += 1 @@ -247,23 +241,14 @@ def process_similarity_analysis(self, repo1_path, repo2_path): for func1 in functions1: for func2 in functions2: name_similarity = ( - difflib.SequenceMatcher( - None, func1["signature"]["name"], func2["signature"]["name"] - ).ratio() - * 100 + difflib.SequenceMatcher(None, func1["signature"]["name"], func2["signature"]["name"]).ratio() * 100 ) # Signature similarity using difflib - signature1 = ( - f"{func1['signature']['name']}({', '.join(func1['signature']['args'])})" - ) - signature2 = ( - f"{func2['signature']['name']}({', '.join(func2['signature']['args'])})" - ) + signature1 = f"{func1['signature']['name']}({', '.join(func1['signature']['args'])})" + signature2 = f"{func2['signature']['name']}({', '.join(func2['signature']['args'])})" - signature_similarity = ( - difflib.SequenceMatcher(None, signature1, signature2).ratio() * 100 - ) + signature_similarity = difflib.SequenceMatcher(None, signature1, signature2).ratio() * 100 # Content similarity using OpenAI embeddings fulltext1 = func1["full_text"] @@ -302,9 +287,7 @@ def process_similarity_analysis(self, repo1_path, repo2_path): models2 = extract_django_models(repo2_path) for model1 in models1: for model2 in models2: - model_similarity = ( - difflib.SequenceMatcher(None, model1["name"], model2["name"]).ratio() * 100 - ) + model_similarity = difflib.SequenceMatcher(None, model1["name"], model2["name"]).ratio() * 100 model_fields_similarity = compare_model_fields(model1, model2) matching_details["models"].append( diff --git a/website/management/commands/check_keywords.py b/website/management/commands/check_keywords.py index 9bbf0050e..f60ad656c 100644 --- a/website/management/commands/check_keywords.py +++ b/website/management/commands/check_keywords.py @@ -35,17 +35,13 @@ def handle(self, *args, **options): monitor.last_checked_time = timezone.now() monitor.save() - self.stdout.write( - self.style.SUCCESS(f"Monitoring {monitor.url}: status {monitor.status}") - ) + self.stdout.write(self.style.SUCCESS(f"Monitoring {monitor.url}: status {monitor.status}")) except Exception as e: self.stderr.write(self.style.ERROR(f"Error monitoring {monitor.url}: {str(e)}")) def notify_user(self, username, website, email, status): subject = f"Website Status Update: {website} is {status}" - message = ( - f"Dear {username},\n\nThe website '{website}' you are monitoring is currently {status}." - ) + message = f"Dear {username},\n\nThe website '{website}' you are monitoring is currently {status}." send_mail( subject, diff --git a/website/management/commands/check_owasp_projects.py b/website/management/commands/check_owasp_projects.py index 427bc7854..0e57bb271 100644 --- a/website/management/commands/check_owasp_projects.py +++ b/website/management/commands/check_owasp_projects.py @@ -23,16 +23,12 @@ def handle(self, *args, **options): slack_webhook_url = os.environ.get("SLACK_WEBHOOK_URL") if not github_token: - self.stderr.write( - self.style.ERROR("GITHUB_TOKEN is not configured in settings. Aborting.") - ) + self.stderr.write(self.style.ERROR("GITHUB_TOKEN is not configured in settings. Aborting.")) return if not slack_webhook_url: self.stderr.write( - self.style.WARNING( - "SLACK_WEBHOOK_URL not found in environment. Slack notifications will be disabled." - ) + self.style.WARNING("SLACK_WEBHOOK_URL not found in environment. Slack notifications will be disabled.") ) headers = { @@ -45,9 +41,7 @@ def handle(self, *args, **options): max_rate_limit_retries = 5 # Get or create OWASP organization - org, created = Organization.objects.get_or_create( - name__iexact="OWASP", defaults={"name": "OWASP"} - ) + org, created = Organization.objects.get_or_create(name__iexact="OWASP", defaults={"name": "OWASP"}) # Fetch all www-project repos www_project_repos = self.fetch_all_repos(headers) @@ -66,9 +60,7 @@ def handle(self, *args, **options): # Skip if repo already exists by checking Repo table if Repo.objects.filter(repo_url=repo_url).exists(): - self.stdout.write( - self.style.WARNING(f"Repository {repo_url} already exists. Skipping...") - ) + self.stdout.write(self.style.WARNING(f"Repository {repo_url} already exists. Skipping...")) continue self.stdout.write(f"Processing repository {repo_url}") @@ -93,8 +85,7 @@ def handle(self, *args, **options): "name": project_name, "description": repo_data.get("description") or "No description available", # Set default description - "url": base_url - or repo_data.get("html_url", ""), # Fallback to repo URL if no homepage + "url": base_url or repo_data.get("html_url", ""), # Fallback to repo URL if no homepage "organization": org, } @@ -132,9 +123,7 @@ def handle(self, *args, **options): watchers=repo_info.get("watchers", 0), primary_language=repo_info.get("primary_language", ""), license=repo_info.get("license", ""), - last_commit_date=self.parse_date_safely( - repo_info.get("last_commit_date") - ), + last_commit_date=self.parse_date_safely(repo_info.get("last_commit_date")), created=self.parse_date_safely(repo_info.get("created")), modified=self.parse_date_safely(repo_info.get("modified")), network_count=repo_info.get("network_count", 0), @@ -148,9 +137,7 @@ def handle(self, *args, **options): contributor_count=repo_info.get("contributor_count", 0), commit_count=repo_info.get("commit_count", 0), release_name=repo_info.get("release_name", ""), - release_datetime=self.parse_date_safely( - repo_info.get("release_datetime") - ), + release_datetime=self.parse_date_safely(repo_info.get("release_datetime")), ) # Add to new projects list for Slack notification @@ -175,29 +162,19 @@ def handle(self, *args, **options): if repo_info.get("logo_url"): self.fetch_and_save_logo(project, repo_info["logo_url"], headers) - self.stdout.write( - self.style.SUCCESS(f"Successfully created project and repo: {project_name}") - ) + self.stdout.write(self.style.SUCCESS(f"Successfully created project and repo: {project_name}")) except ValueError as ve: - self.stderr.write( - self.style.ERROR(f"Validation error for {repo_url}: {str(ve)}") - ) + self.stderr.write(self.style.ERROR(f"Validation error for {repo_url}: {str(ve)}")) continue except IntegrityError as ie: - self.stderr.write( - self.style.ERROR(f"Database integrity error for {repo_url}: {str(ie)}") - ) + self.stderr.write(self.style.ERROR(f"Database integrity error for {repo_url}: {str(ie)}")) continue except requests.RequestException as re: - self.stderr.write( - self.style.ERROR(f"Network error while processing {repo_url}: {str(re)}") - ) + self.stderr.write(self.style.ERROR(f"Network error while processing {repo_url}: {str(re)}")) continue except CommandError as ce: - self.stderr.write( - self.style.ERROR(f"Command execution error for {repo_url}: {str(ce)}") - ) + self.stderr.write(self.style.ERROR(f"Command execution error for {repo_url}: {str(ce)}")) continue # Send Slack notification if new projects were found and Slack webhook is configured @@ -217,9 +194,7 @@ def fetch_all_repos(self, headers, per_page=100): try: response = requests.get(url, headers=headers, timeout=10) if response.status_code != 200: - self.stderr.write( - self.style.ERROR(f"Error: API returned status {response.status_code}") - ) + self.stderr.write(self.style.ERROR(f"Error: API returned status {response.status_code}")) break data = response.json() @@ -240,9 +215,7 @@ def fetch_all_repos(self, headers, per_page=100): return all_repos - def fetch_github_repo_data( - self, repo_url, headers, delay, max_retries, is_wiki=False, is_main=False - ): + def fetch_github_repo_data(self, repo_url, headers, delay, max_retries, is_wiki=False, is_main=False): match = re.match(r"https://github.com/([^/]+/[^/]+)", repo_url) if not match: return None @@ -252,26 +225,18 @@ def api_get(url): try: response = requests.get(url, headers=headers, timeout=10) if response.status_code in (403, 429): # Rate limit or forbidden - self.stderr.write( - self.style.WARNING( - f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}" - ) - ) + self.stderr.write(self.style.WARNING(f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}")) time.sleep(delay) continue return response except requests.exceptions.RequestException as e: self.stderr.write( - self.style.WARNING( - f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}" - ) + self.style.WARNING(f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}") ) time.sleep(delay) continue # After max retries, return None instead of raising exception - self.stderr.write( - self.style.WARNING(f"Failed to fetch {url} after {max_retries} attempts") - ) + self.stderr.write(self.style.WARNING(f"Failed to fetch {url} after {max_retries} attempts")) return None # Main repo data @@ -325,9 +290,7 @@ def parse_date_safely(date_string): "last_updated": last_updated, "watchers": repo_data.get("watchers_count", 0), "primary_language": repo_data.get("language", ""), - "license": ( - repo_data.get("license", {}).get("name") if repo_data.get("license") else None - ), + "license": (repo_data.get("license", {}).get("name") if repo_data.get("license") else None), "last_commit_date": last_commit_date, "created": created_date, "modified": modified_date, @@ -403,19 +366,13 @@ def api_get(url): try: response = requests.get(url, headers=headers, timeout=10) if response.status_code in (403, 429): - self.stderr.write( - self.style.WARNING( - f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}" - ) - ) + self.stderr.write(self.style.WARNING(f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}")) time.sleep(delay) continue return response except requests.exceptions.RequestException as e: self.stderr.write( - self.style.WARNING( - f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}" - ) + self.style.WARNING(f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}") ) time.sleep(delay) continue @@ -495,28 +452,18 @@ def handle_contributors(self, repo_instance, contributors_data): if not created: contributor_obj.name = contributor.get("login", contributor_obj.name) contributor_obj.github_url = contributor.get("html_url", contributor_obj.github_url) - contributor_obj.avatar_url = contributor.get( - "avatar_url", contributor_obj.avatar_url - ) - contributor_obj.contributor_type = contributor.get( - "type", contributor_obj.contributor_type - ) - contributor_obj.contributions = contributor.get( - "contributions", contributor_obj.contributions - ) + contributor_obj.avatar_url = contributor.get("avatar_url", contributor_obj.avatar_url) + contributor_obj.contributor_type = contributor.get("type", contributor_obj.contributor_type) + contributor_obj.contributions = contributor.get("contributions", contributor_obj.contributions) contributor_obj.save() contributor_instances.append(contributor_obj) - self.stdout.write( - self.style.SUCCESS(f" -> Added/Updated Contributor: {contributor_obj.name}") - ) + self.stdout.write(self.style.SUCCESS(f" -> Added/Updated Contributor: {contributor_obj.name}")) # Assign all contributors to the repo repo_instance.contributor.add(*contributor_instances) self.stdout.write( - self.style.SUCCESS( - f"Added {len(contributor_instances)} contributors to {repo_instance.name}" - ) + self.style.SUCCESS(f"Added {len(contributor_instances)} contributors to {repo_instance.name}") ) def send_slack_notification(self, new_projects, webhook_url): @@ -557,14 +504,10 @@ def send_slack_notification(self, new_projects, webhook_url): self.stdout.write(self.style.SUCCESS("Successfully sent Slack notification")) else: self.stderr.write( - self.style.WARNING( - f"Failed to send Slack notification. Status code: {response.status_code}" - ) + self.style.WARNING(f"Failed to send Slack notification. Status code: {response.status_code}") ) except requests.RequestException as re: - self.stderr.write( - self.style.ERROR(f"Network error sending Slack notification: {str(re)}") - ) + self.stderr.write(self.style.ERROR(f"Network error sending Slack notification: {str(re)}")) except ValueError as ve: self.stderr.write(self.style.ERROR(f"Invalid message format for Slack: {str(ve)}")) diff --git a/website/management/commands/check_trademarks.py b/website/management/commands/check_trademarks.py index b088059d2..c6fcfb937 100644 --- a/website/management/commands/check_trademarks.py +++ b/website/management/commands/check_trademarks.py @@ -86,9 +86,7 @@ def initialize_trademark_data(self, organizations): f"The last trademark check date for {organization.name} is updated to {organization.trademark_check_date}" ) organization.save() - self.stdout.write( - f"Initialized data for {organization.name}: Count = {organization.trademark_count}" - ) + self.stdout.write(f"Initialized data for {organization.name}: Count = {organization.trademark_count}") else: self.stderr.write(f"Failed to fetch trademark data for {organization.name}.") @@ -111,9 +109,7 @@ def rate_limited_check(self): if response_data: new_trademark_count = response_data.get("count", 0) if new_trademark_count > organization.trademark_count: - self.stdout.write( - f"New trademarks found for {organization.name}: {new_trademark_count}" - ) + self.stdout.write(f"New trademarks found for {organization.name}: {new_trademark_count}") organization.trademark_count = new_trademark_count organization.trademark_check_date = now() organization.save() diff --git a/website/management/commands/fetch_contributor_stats.py b/website/management/commands/fetch_contributor_stats.py index 79568b756..b50a7ebbd 100644 --- a/website/management/commands/fetch_contributor_stats.py +++ b/website/management/commands/fetch_contributor_stats.py @@ -34,8 +34,7 @@ def handle(self, **options): data_types = ["pulls", "issuesopen", "issuesclosed", "commits", "comments"] with ThreadPoolExecutor(max_workers=5) as executor: futures = [ - executor.submit(self.fetch_and_update_data, data_type, headers, owner, repo) - for data_type in data_types + executor.submit(self.fetch_and_update_data, data_type, headers, owner, repo) for data_type in data_types ] for future in futures: future.result() # Wait for all tasks to complete @@ -57,9 +56,7 @@ def fetch_and_update_data(self, data_type, headers, owner, repo): while url: response = requests.get(url, headers=headers) if response.status_code != 200: - self.stdout.write( - self.style.ERROR(f"Error fetching {data_type}: {response.json()}") - ) + self.stdout.write(self.style.ERROR(f"Error fetching {data_type}: {response.json()}")) break data = response.json() if not data: @@ -128,9 +125,7 @@ def fetch_and_update_data(self, data_type, headers, owner, repo): contribution_type="issue_closed", github_id=str(item["id"]), github_url=item["html_url"], - created=datetime.strptime( - item.get("closed_at") or item["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ), + created=datetime.strptime(item.get("closed_at") or item["created_at"], "%Y-%m-%dT%H:%M:%SZ"), status="closed", repository=project, ) @@ -147,9 +142,7 @@ def fetch_and_update_data(self, data_type, headers, owner, repo): contribution_type="commit", github_id=item["sha"], github_url=item["html_url"], - created=datetime.strptime( - item["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ" - ), + created=datetime.strptime(item["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ"), repository=project, ) ) diff --git a/website/management/commands/fetch_contributors.py b/website/management/commands/fetch_contributors.py index 8548af965..62b9c6f7f 100644 --- a/website/management/commands/fetch_contributors.py +++ b/website/management/commands/fetch_contributors.py @@ -85,6 +85,4 @@ def handle(self, *args, **kwargs): project.contributor_count = len(contributors) project.save() - self.stdout.write( - self.style.SUCCESS(f"Successfully fetched contributors for project {project.name}") - ) + self.stdout.write(self.style.SUCCESS(f"Successfully fetched contributors for project {project.name}")) diff --git a/website/management/commands/initsuperuser.py b/website/management/commands/initsuperuser.py index 8e9b70275..43160ea53 100644 --- a/website/management/commands/initsuperuser.py +++ b/website/management/commands/initsuperuser.py @@ -10,7 +10,5 @@ def handle(self, *args, **options): EMAIL = user[1] PASSWORD = user[2] print("Creating superuser for %s (%s)" % (USERNAME, EMAIL)) - superuser = User.objects.create_superuser( - username=USERNAME, email=EMAIL, password=PASSWORD - ) + superuser = User.objects.create_superuser(username=USERNAME, email=EMAIL, password=PASSWORD) superuser.save() diff --git a/website/management/commands/owasp_project_upload.py b/website/management/commands/owasp_project_upload.py index ee11d3414..a56da0269 100644 --- a/website/management/commands/owasp_project_upload.py +++ b/website/management/commands/owasp_project_upload.py @@ -44,9 +44,7 @@ def handle(self, *args, **options): # Check if GITHUB_TOKEN is set github_token = getattr(settings, "GITHUB_TOKEN", None) if not github_token: - self.stderr.write( - self.style.ERROR("GITHUB_TOKEN is not configured in settings. Aborting.") - ) + self.stderr.write(self.style.ERROR("GITHUB_TOKEN is not configured in settings. Aborting.")) return headers = { @@ -55,20 +53,14 @@ def handle(self, *args, **options): } # Get or create OWASP organization - org, created = Organization.objects.get_or_create( - name__iexact="OWASP", defaults={"name": "OWASP"} - ) + org, created = Organization.objects.get_or_create(name__iexact="OWASP", defaults={"name": "OWASP"}) if created: self.stdout.write(self.style.SUCCESS(f"Created Organization: {org.name}")) else: self.stdout.write(self.style.SUCCESS(f"Found Organization: {org.name}")) # Prompt user for confirmation - confirm = ( - input(f"Do you want to add projects to the organization '{org.name}'? (yes/no): ") - .strip() - .lower() - ) + confirm = input(f"Do you want to add projects to the organization '{org.name}'? (yes/no): ").strip().lower() if confirm not in ["yes", "y"]: self.stdout.write(self.style.WARNING("Operation cancelled by the user.")) return @@ -100,9 +92,7 @@ def handle(self, *args, **options): self.stdout.write(self.style.WARNING("CSV file is empty. No projects to add.")) return - self.stdout.write( - self.style.NOTICE(f"Processing {len(rows)} projects from the CSV file...") - ) + self.stdout.write(self.style.NOTICE(f"Processing {len(rows)} projects from the CSV file...")) project_count = 0 @@ -127,11 +117,7 @@ def clean_github_url(url): repo_field = row.get("Repo", "").strip() website_url = row.get("Website URL", "").strip() code_urls_csv = row.get("Code URL", "").strip() - code_urls = [ - clean_github_url(url.strip()) - for url in re.split(r"[,\n]+", code_urls_csv) - if url.strip() - ] + code_urls = [clean_github_url(url.strip()) for url in re.split(r"[,\n]+", code_urls_csv) if url.strip()] # Filter out any empty strings after cleaning code_urls = [url for url in code_urls if url] # Remove duplicates that might occur after cleaning URLs @@ -148,13 +134,9 @@ def clean_github_url(url): repo_url = f"https://github.com/OWASP/{repo_field}" # Validate GitHub repo existence - if not self.validate_github_repo( - repo_url, headers, delay_on_rate_limit, max_rate_limit_retries - ): + if not self.validate_github_repo(repo_url, headers, delay_on_rate_limit, max_rate_limit_retries): self.stderr.write( - self.style.WARNING( - f"Invalid or inaccessible Repo URL: {repo_url}. Skipping row {row_index}." - ) + self.style.WARNING(f"Invalid or inaccessible Repo URL: {repo_url}. Skipping row {row_index}.") ) continue @@ -169,9 +151,7 @@ def clean_github_url(url): ) if not repo_info: self.stderr.write( - self.style.WARNING( - f"Failed to fetch complete data for {repo_url}. Skipping row {row_index}." - ) + self.style.WARNING(f"Failed to fetch complete data for {repo_url}. Skipping row {row_index}.") ) continue @@ -212,9 +192,7 @@ def clean_github_url(url): with transaction.atomic(): # Check if project already exists by URL or slug if Project.objects.filter( - models.Q(url=website_url) - | models.Q(url=repo_info.get("html_url")) - | models.Q(slug=project_slug) + models.Q(url=website_url) | models.Q(url=repo_info.get("html_url")) | models.Q(slug=project_slug) ).exists(): self.stdout.write( self.style.WARNING( @@ -235,36 +213,22 @@ def clean_github_url(url): organization=org, ) except IntegrityError: - self.stdout.write( - self.style.WARNING( - "Failed to create project due to duplicate data. Skipping..." - ) - ) + self.stdout.write(self.style.WARNING("Failed to create project due to duplicate data. Skipping...")) continue # Fetch and save the logo project_logo_url = repo_info.get("logo_url", "") if self.fetch_and_save_logo(project, project_logo_url, headers): - self.stdout.write( - self.style.SUCCESS( - f"Successfully fetched and saved logo for {project.name}" - ) - ) + self.stdout.write(self.style.SUCCESS(f"Successfully fetched and saved logo for {project.name}")) else: self.stdout.write(self.style.WARNING(f"No logo found for {project.name}")) - self.stdout.write( - self.style.SUCCESS(f"Updated project: {project.name} ({repo_url})") - ) + self.stdout.write(self.style.SUCCESS(f"Updated project: {project.name} ({repo_url})")) # Handle wiki repo try: repo = Repo.objects.get(repo_url=repo_url) - self.stdout.write( - self.style.WARNING( - f"Wiki repo {repo_url} already exists. Skipping creation..." - ) - ) + self.stdout.write(self.style.WARNING(f"Wiki repo {repo_url} already exists. Skipping creation...")) except Repo.DoesNotExist: try: repo = Repo.objects.create( @@ -279,9 +243,7 @@ def clean_github_url(url): stars=repo_info.get("stars", 0), forks=repo_info.get("forks", 0), last_updated=( - parse_datetime(repo_info.get("last_updated")) - if repo_info.get("last_updated") - else None + parse_datetime(repo_info.get("last_updated")) if repo_info.get("last_updated") else None ), watchers=repo_info.get("watchers", 0), primary_language=repo_info.get("primary_language", ""), @@ -310,28 +272,20 @@ def clean_github_url(url): ) except IntegrityError: self.stdout.write( - self.style.WARNING( - "Failed to create wiki repo due to duplicate data. Skipping..." - ) + self.style.WARNING("Failed to create wiki repo due to duplicate data. Skipping...") ) continue # Handle additional repos for idx, code_url in enumerate(code_urls, start=1): if not code_url.startswith("https://github.com/"): - self.stderr.write( - self.style.WARNING(f"Invalid Code URL: {code_url}. Skipping.") - ) + self.stderr.write(self.style.WARNING(f"Invalid Code URL: {code_url}. Skipping.")) continue # Validate Code Repo URL - if not self.validate_github_repo( - code_url, headers, delay_on_rate_limit, max_rate_limit_retries - ): + if not self.validate_github_repo(code_url, headers, delay_on_rate_limit, max_rate_limit_retries): self.stderr.write( - self.style.WARNING( - f"Invalid or inaccessible Code Repo URL: {code_url}. Skipping." - ) + self.style.WARNING(f"Invalid or inaccessible Code Repo URL: {code_url}. Skipping.") ) continue @@ -347,18 +301,14 @@ def clean_github_url(url): if not code_repo_info: self.stderr.write( - self.style.WARNING( - f"Failed to fetch complete data for {code_url}. Skipping." - ) + self.style.WARNING(f"Failed to fetch complete data for {code_url}. Skipping.") ) continue try: code_repo = Repo.objects.get(repo_url=code_url) self.stdout.write( - self.style.WARNING( - f"Code repo {code_url} already exists. Skipping creation..." - ) + self.style.WARNING(f"Code repo {code_url} already exists. Skipping creation...") ) continue except Repo.DoesNotExist: @@ -424,9 +374,7 @@ def clean_github_url(url): ) except IntegrityError: self.stdout.write( - self.style.WARNING( - "Failed to create code repo due to duplicate data. Skipping..." - ) + self.style.WARNING("Failed to create code repo due to duplicate data. Skipping...") ) continue @@ -436,9 +384,7 @@ def clean_github_url(url): if not code_repo: self.stderr.write( - self.style.WARNING( - f"Failed to create/update Code Repo for {code_url}. Skipping." - ) + self.style.WARNING(f"Failed to create/update Code Repo for {code_url}. Skipping.") ) continue @@ -453,17 +399,11 @@ def clean_github_url(url): if code_contributors_data: self.handle_contributors(code_repo, code_contributors_data) - self.stdout.write( - self.style.SUCCESS( - f" -> Added/Updated Repo: {code_repo.name} ({code_url})" - ) - ) + self.stdout.write(self.style.SUCCESS(f" -> Added/Updated Repo: {code_repo.name} ({code_url})")) project_count += 1 - self.stdout.write( - self.style.SUCCESS(f"Import completed. Processed {project_count} projects.") - ) + self.stdout.write(self.style.SUCCESS(f"Import completed. Processed {project_count} projects.")) def validate_github_repo(self, repo_url, headers, delay, max_retries): """Check if a GitHub repository exists.""" @@ -477,18 +417,14 @@ def validate_github_repo(self, repo_url, headers, delay, max_retries): if response.status_code == 200: return True elif response.status_code in [403, 429]: - self.stderr.write( - self.style.WARNING(f"Rate limit reached. Waiting for {delay} seconds...") - ) + self.stderr.write(self.style.WARNING(f"Rate limit reached. Waiting for {delay} seconds...")) time.sleep(delay) continue elif response.status_code == 404: return False else: self.stderr.write( - self.style.WARNING( - f"Unexpected status code {response.status_code} for URL: {repo_url}" - ) + self.style.WARNING(f"Unexpected status code {response.status_code} for URL: {repo_url}") ) return False except requests.exceptions.RequestException as e: @@ -513,9 +449,7 @@ def convert_to_api_url(self, repo_url): self.stderr.write(self.style.WARNING(f"Invalid GitHub URL format: {repo_url}")) return None - def fetch_github_repo_data( - self, repo_url, headers, delay, max_retries, is_wiki=False, is_main=False - ): + def fetch_github_repo_data(self, repo_url, headers, delay, max_retries, is_wiki=False, is_main=False): match = re.match(r"https://github.com/([^/]+/[^/]+)", repo_url) if not match: return None @@ -525,26 +459,18 @@ def api_get(url): try: response = requests.get(url, headers=headers, timeout=10) if response.status_code in (403, 429): # Rate limit or forbidden - self.stderr.write( - self.style.WARNING( - f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}" - ) - ) + self.stderr.write(self.style.WARNING(f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}")) time.sleep(delay) continue return response except requests.exceptions.RequestException as e: self.stderr.write( - self.style.WARNING( - f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}" - ) + self.style.WARNING(f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}") ) time.sleep(delay) continue # After max retries, return None instead of raising exception - self.stderr.write( - self.style.WARNING(f"Failed to fetch {url} after {max_retries} attempts") - ) + self.stderr.write(self.style.WARNING(f"Failed to fetch {url} after {max_retries} attempts")) return None # Main repo data @@ -574,9 +500,7 @@ def api_get(url): "last_updated": repo_data.get("updated_at"), "watchers": repo_data.get("watchers_count", 0), "primary_language": repo_data.get("language", ""), - "license": ( - repo_data.get("license", {}).get("name") if repo_data.get("license") else None - ), + "license": (repo_data.get("license", {}).get("name") if repo_data.get("license") else None), "last_commit_date": repo_data.get("pushed_at"), "created": repo_data.get("created_at", ""), "modified": repo_data.get("updated_at", ""), @@ -652,19 +576,13 @@ def api_get(url): try: response = requests.get(url, headers=headers, timeout=10) if response.status_code in (403, 429): - self.stderr.write( - self.style.WARNING( - f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}" - ) - ) + self.stderr.write(self.style.WARNING(f"Rate limit hit for {url}. Attempt {i+1}/{max_retries}")) time.sleep(delay) continue return response except requests.exceptions.RequestException as e: self.stderr.write( - self.style.WARNING( - f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}" - ) + self.style.WARNING(f"Request failed for {url}: {str(e)}. Attempt {i+1}/{max_retries}") ) time.sleep(delay) continue @@ -741,26 +659,16 @@ def handle_contributors(self, repo_instance, contributors_data): if not created: contributor_obj.name = contributor.get("login", contributor_obj.name) contributor_obj.github_url = contributor.get("html_url", contributor_obj.github_url) - contributor_obj.avatar_url = contributor.get( - "avatar_url", contributor_obj.avatar_url - ) - contributor_obj.contributor_type = contributor.get( - "type", contributor_obj.contributor_type - ) - contributor_obj.contributions = contributor.get( - "contributions", contributor_obj.contributions - ) + contributor_obj.avatar_url = contributor.get("avatar_url", contributor_obj.avatar_url) + contributor_obj.contributor_type = contributor.get("type", contributor_obj.contributor_type) + contributor_obj.contributions = contributor.get("contributions", contributor_obj.contributions) contributor_obj.save() contributor_instances.append(contributor_obj) - self.stdout.write( - self.style.SUCCESS(f" -> Added/Updated Contributor: {contributor_obj.name}") - ) + self.stdout.write(self.style.SUCCESS(f" -> Added/Updated Contributor: {contributor_obj.name}")) # Assign all contributors to the repo repo_instance.contributor.add(*contributor_instances) self.stdout.write( - self.style.SUCCESS( - f"Added {len(contributor_instances)} contributors to {repo_instance.name}" - ) + self.style.SUCCESS(f"Added {len(contributor_instances)} contributors to {repo_instance.name}") ) diff --git a/website/management/commands/slack_daily_timelogs.py b/website/management/commands/slack_daily_timelogs.py index ad2ba3e32..73cc1e5f1 100644 --- a/website/management/commands/slack_daily_timelogs.py +++ b/website/management/commands/slack_daily_timelogs.py @@ -15,9 +15,7 @@ def handle(self, *args, **kwargs): current_hour_utc = datetime.utcnow().hour # Fetch all Slack integrations with related integration data - slack_integrations = SlackIntegration.objects.select_related( - "integration__organization" - ).all() + slack_integrations = SlackIntegration.objects.select_related("integration__organization").all() for integration in slack_integrations: current_org = integration.integration.organization @@ -25,8 +23,7 @@ def handle(self, *args, **kwargs): integration.default_channel_id and current_org and integration.daily_updates - and integration.daily_update_time - == current_hour_utc # Ensure it's the correct hour + and integration.daily_update_time == current_hour_utc # Ensure it's the correct hour ): print(f"Processing updates for organization: {current_org.name}") @@ -46,14 +43,9 @@ def handle(self, *args, **kwargs): for timelog in timelog_history: st = timelog.start_time et = timelog.end_time - issue_url = ( - timelog.github_issue_url if timelog.github_issue_url else "No issue URL" - ) + issue_url = timelog.github_issue_url if timelog.github_issue_url else "No issue URL" summary_message += ( - f"Task: {timelog}\n" - f"Start: {st}\n" - f"End: {et}\n" - f"Issue URL: {issue_url}\n\n" + f"Task: {timelog}\n" f"Start: {st}\n" f"End: {et}\n" f"Issue URL: {issue_url}\n\n" ) total_time += et - st diff --git a/website/management/commands/update_contributor_stats.py b/website/management/commands/update_contributor_stats.py index d8566fbc5..e208f3b02 100644 --- a/website/management/commands/update_contributor_stats.py +++ b/website/management/commands/update_contributor_stats.py @@ -63,9 +63,7 @@ def parse_github_url(self, url): def delete_existing_daily_stats(self, repo, current_month_start): """Delete existing daily stats for the current month""" with transaction.atomic(): - ContributorStats.objects.filter( - repo=repo, granularity="day", date__gte=current_month_start - ).delete() + ContributorStats.objects.filter(repo=repo, granularity="day", date__gte=current_month_start).delete() def fetch_contributor_stats(self, owner, repo_name, start_date, end_date): """Fetch contributor statistics using GitHub REST API""" @@ -90,9 +88,7 @@ def get_paginated_data(url, params=None): continue if response.status_code != 200: - self.stdout.write( - self.style.WARNING(f"API error: {response.status_code} - {response.text}") - ) + self.stdout.write(self.style.WARNING(f"API error: {response.status_code} - {response.text}")) break data = response.json() @@ -124,9 +120,7 @@ def get_paginated_data(url, params=None): for commit in commits: if commit.get("author") and commit.get("commit", {}).get("author", {}).get("date"): - date = datetime.strptime( - commit["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + date = datetime.strptime(commit["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ").date() login = commit["author"].get("login") if login: self.increment_stat(stats, date, login, "commits") @@ -142,17 +136,13 @@ def get_paginated_data(url, params=None): login = issue["user"]["login"] # Handle issue creation - created_date = datetime.strptime( - issue["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + created_date = datetime.strptime(issue["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() if start_date <= created_date <= end_date: self.increment_stat(stats, created_date, login, "issues_opened") # Handle issue closure if issue.get("closed_at"): - closed_date = datetime.strptime( - issue["closed_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + closed_date = datetime.strptime(issue["closed_at"], "%Y-%m-%dT%H:%M:%SZ").date() if start_date <= closed_date <= end_date: self.increment_stat(stats, closed_date, login, "issues_closed") @@ -176,9 +166,7 @@ def get_paginated_data(url, params=None): for comment in comments: if comment.get("user", {}).get("login"): login = comment["user"]["login"] - comment_date = datetime.strptime( - comment["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + comment_date = datetime.strptime(comment["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() if start_date <= comment_date <= end_date: self.increment_stat(stats, comment_date, login, "comments") @@ -216,11 +204,7 @@ def update_monthly_stats(self, repo, start_date): owner, repo_name = self.parse_github_url(repo.repo_url) # Get the last monthly stat to know where to start from - last_monthly_stat = ( - ContributorStats.objects.filter(repo=repo, granularity="month") - .order_by("-date") - .first() - ) + last_monthly_stat = ContributorStats.objects.filter(repo=repo, granularity="month").order_by("-date").first() if last_monthly_stat: # Start from the month after the last stored monthly stat @@ -236,15 +220,11 @@ def update_monthly_stats(self, repo, start_date): response = requests.get(repo_api_url, headers=headers) if response.status_code != 200: - self.stdout.write( - self.style.ERROR(f"Failed to fetch repo data: {response.text}") - ) + self.stdout.write(self.style.ERROR(f"Failed to fetch repo data: {response.text}")) return repo_data = response.json() - repo_created_at = datetime.strptime( - repo_data["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + repo_created_at = datetime.strptime(repo_data["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() except Exception as e: self.stdout.write(self.style.ERROR(f"Error fetching repo creation date: {str(e)}")) return @@ -261,9 +241,7 @@ def update_monthly_stats(self, repo, start_date): self.stdout.write(f"Fetching stats for month: {current_month_start} to {month_end}") - monthly_stats = self.fetch_monthly_contributor_stats( - owner, repo_name, current_month_start, month_end - ) + monthly_stats = self.fetch_monthly_contributor_stats(owner, repo_name, current_month_start, month_end) if monthly_stats: self.store_monthly_stats(repo, current_month_start, monthly_stats) @@ -293,9 +271,7 @@ def get_paginated_data(url, params=None): continue if response.status_code != 200: - self.stdout.write( - self.style.WARNING(f"API error: {response.status_code} - {response.text}") - ) + self.stdout.write(self.style.WARNING(f"API error: {response.status_code} - {response.text}")) break data = response.json() @@ -343,9 +319,7 @@ def get_paginated_data(url, params=None): # Process commits for commit in commits: if commit.get("author") and commit.get("commit", {}).get("author", {}).get("date"): - date = datetime.strptime( - commit["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + date = datetime.strptime(commit["commit"]["author"]["date"], "%Y-%m-%dT%H:%M:%SZ").date() if month_start <= date <= month_end: login = commit["author"].get("login") if login: @@ -358,16 +332,12 @@ def get_paginated_data(url, params=None): if not login: continue - created_date = datetime.strptime( - issue["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + created_date = datetime.strptime(issue["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() if month_start <= created_date <= month_end: self.increment_monthly_stat(monthly_stats, login, "issues_opened") if issue.get("closed_at"): - closed_date = datetime.strptime( - issue["closed_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + closed_date = datetime.strptime(issue["closed_at"], "%Y-%m-%dT%H:%M:%SZ").date() if month_start <= closed_date <= month_end: self.increment_monthly_stat(monthly_stats, login, "issues_closed") @@ -376,9 +346,7 @@ def get_paginated_data(url, params=None): login = pr.get("user", {}).get("login") if ( login - and month_start - <= datetime.strptime(pr["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() - <= month_end + and month_start <= datetime.strptime(pr["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() <= month_end ): self.increment_monthly_stat(monthly_stats, login, "pull_requests") @@ -415,9 +383,7 @@ def store_monthly_stats(self, repo, month_start, monthly_stats): """Store monthly statistics in the database""" with transaction.atomic(): # Delete existing monthly stat for this month if exists - ContributorStats.objects.filter( - repo=repo, granularity="month", date=month_start - ).delete() + ContributorStats.objects.filter(repo=repo, granularity="month", date=month_start).delete() # Create new monthly stats for login, stats in monthly_stats.items(): diff --git a/website/management/commands/update_faiss.py b/website/management/commands/update_faiss.py index bda01a2df..d3731bdd2 100644 --- a/website/management/commands/update_faiss.py +++ b/website/management/commands/update_faiss.py @@ -25,9 +25,7 @@ def handle(self, *args, **kwargs): # Check if the documents directory exists if not documents_dir.exists(): - self.stdout.write( - self.style.ERROR(f"Documents directory does not exist: {documents_dir}") - ) + self.stdout.write(self.style.ERROR(f"Documents directory does not exist: {documents_dir}")) return None # Load the list of already processed files diff --git a/website/management/commands/update_projects.py b/website/management/commands/update_projects.py index 52503c564..24148113e 100644 --- a/website/management/commands/update_projects.py +++ b/website/management/commands/update_projects.py @@ -67,15 +67,9 @@ def get_issue_count(repo_name, query, headers): return 0 project.open_issues = get_issue_count(repo_name, "type:issue+state:open", headers) - project.closed_issues = get_issue_count( - repo_name, "type:issue+state:closed", headers - ) - project.open_pull_requests = get_issue_count( - repo_name, "type:pr+state:open", headers - ) - project.closed_pull_requests = get_issue_count( - repo_name, "type:pr+state:closed", headers - ) + project.closed_issues = get_issue_count(repo_name, "type:issue+state:closed", headers) + project.open_pull_requests = get_issue_count(repo_name, "type:pr+state:open", headers) + project.closed_pull_requests = get_issue_count(repo_name, "type:pr+state:closed", headers) # Fetch latest release url = f"https://api.github.com/repos/{repo_name}/releases/latest" @@ -85,11 +79,7 @@ def get_issue_count(repo_name, query, headers): project.release_name = release_data.get("name") or release_data.get("tag_name") project.release_datetime = parse_datetime(release_data.get("published_at")) else: - self.stdout.write( - self.style.WARNING( - f"No releases found for {repo_name}: {response.status_code}" - ) - ) + self.stdout.write(self.style.WARNING(f"No releases found for {repo_name}: {response.status_code}")) page = 1 commit_count = 0 @@ -100,15 +90,11 @@ def get_issue_count(repo_name, query, headers): contributors_data = response.json() if not contributors_data: break - commit_count += sum( - contributor.get("contributions", 0) for contributor in contributors_data - ) + commit_count += sum(contributor.get("contributions", 0) for contributor in contributors_data) page += 1 else: self.stdout.write( - self.style.WARNING( - f"Failed to fetch contributors for {repo_name}: {response.status_code}" - ) + self.style.WARNING(f"Failed to fetch contributors for {repo_name}: {response.status_code}") ) break project.commit_count = commit_count @@ -116,9 +102,7 @@ def get_issue_count(repo_name, query, headers): else: self.stdout.write( - self.style.WARNING( - f"Failed to fetch repository data for {repo_name}: {response.status_code}" - ) + self.style.WARNING(f"Failed to fetch repository data for {repo_name}: {response.status_code}") ) continue # Skip to next project diff --git a/website/migrations/0001_initial.py b/website/migrations/0001_initial.py index d07bedaf3..4d04aa2ae 100644 --- a/website/migrations/0001_initial.py +++ b/website/migrations/0001_initial.py @@ -15,9 +15,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("when", models.DateTimeField(auto_now_add=True, verbose_name=b"date created")), ], diff --git a/website/migrations/0002_auto_20160828_0116.py b/website/migrations/0002_auto_20160828_0116.py index 468fa5e0c..5fb48f7d4 100644 --- a/website/migrations/0002_auto_20160828_0116.py +++ b/website/migrations/0002_auto_20160828_0116.py @@ -18,9 +18,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("url", models.URLField()), ("description", models.TextField()), @@ -29,9 +27,7 @@ class Migration(migrations.Migration): ("modified", models.DateTimeField(auto_now=True)), ( "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ], ), diff --git a/website/migrations/0003_auto_20160831_2326.py b/website/migrations/0003_auto_20160831_2326.py index 5089691f1..82a56c674 100644 --- a/website/migrations/0003_auto_20160831_2326.py +++ b/website/migrations/0003_auto_20160831_2326.py @@ -18,9 +18,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("score", models.IntegerField()), ], @@ -33,15 +31,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name="points", name="issue", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.Issue" - ), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.Issue"), ), migrations.AddField( model_name="points", name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0004_auto_20160903_2344.py b/website/migrations/0004_auto_20160903_2344.py index cc90af1d8..0c442c17f 100644 --- a/website/migrations/0004_auto_20160903_2344.py +++ b/website/migrations/0004_auto_20160903_2344.py @@ -18,9 +18,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("url", models.URLField()), ("prize", models.IntegerField()), @@ -30,9 +28,7 @@ class Migration(migrations.Migration): ("modified", models.DateTimeField(auto_now=True)), ( "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ], ), diff --git a/website/migrations/0006_auto_20160920_1713.py b/website/migrations/0006_auto_20160920_1713.py index 33b12d493..6669a6705 100644 --- a/website/migrations/0006_auto_20160920_1713.py +++ b/website/migrations/0006_auto_20160920_1713.py @@ -15,9 +15,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("name", models.TextField()), ("url", models.URLField()), diff --git a/website/migrations/0014_auto_20161113_1417.py b/website/migrations/0014_auto_20161113_1417.py index c758e5699..5b539f465 100644 --- a/website/migrations/0014_auto_20161113_1417.py +++ b/website/migrations/0014_auto_20161113_1417.py @@ -15,8 +15,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="issue", name="screenshot", - field=models.ImageField( - upload_to=b"screenshots", validators=[website.models.validate_image] - ), + field=models.ImageField(upload_to=b"screenshots", validators=[website.models.validate_image]), ), ] diff --git a/website/migrations/0023_invitefriend.py b/website/migrations/0023_invitefriend.py index ee2c9cf4b..316f93cbf 100644 --- a/website/migrations/0023_invitefriend.py +++ b/website/migrations/0023_invitefriend.py @@ -18,17 +18,13 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("recipient", models.EmailField(max_length=254)), ("sent", models.DateTimeField(auto_now_add=True, db_index=True)), ( "sender", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ], options={ diff --git a/website/migrations/0024_userprofile.py b/website/migrations/0024_userprofile.py index d7661c59e..f7a9ed3f2 100644 --- a/website/migrations/0024_userprofile.py +++ b/website/migrations/0024_userprofile.py @@ -26,9 +26,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("user_avatar", models.ImageField(blank=True, null=True, upload_to=b"avatars/")), ( diff --git a/website/migrations/0025_auto_20170605_1909.py b/website/migrations/0025_auto_20170605_1909.py index e82d150ac..1de3e4c4a 100644 --- a/website/migrations/0025_auto_20170605_1909.py +++ b/website/migrations/0025_auto_20170605_1909.py @@ -19,9 +19,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("author", models.CharField(max_length=200)), ("author_url", models.CharField(max_length=200)), @@ -41,8 +39,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="userprofile", name="user_avatar", - field=models.ImageField( - blank=True, null=True, upload_to=website.models.user_images_path - ), + field=models.ImageField(blank=True, null=True, upload_to=website.models.user_images_path), ), ] diff --git a/website/migrations/0037_auto_20170813_0319.py b/website/migrations/0037_auto_20170813_0319.py index 64add128f..9de6334f0 100644 --- a/website/migrations/0037_auto_20170813_0319.py +++ b/website/migrations/0037_auto_20170813_0319.py @@ -13,8 +13,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="userprofile", name="follows", - field=models.ManyToManyField( - blank=True, related_name="follower", to="website.UserProfile" - ), + field=models.ManyToManyField(blank=True, related_name="follower", to="website.UserProfile"), ), ] diff --git a/website/migrations/0044_auto_20170907_1605.py b/website/migrations/0044_auto_20170907_1605.py index 908b63848..2203563ca 100644 --- a/website/migrations/0044_auto_20170907_1605.py +++ b/website/migrations/0044_auto_20170907_1605.py @@ -17,8 +17,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="userprofile", name="issue_upvoted", - field=models.ManyToManyField( - blank=True, null=True, related_name="upvoted", to="website.Issue" - ), + field=models.ManyToManyField(blank=True, null=True, related_name="upvoted", to="website.Issue"), ), ] diff --git a/website/migrations/0045_auto_20180314_2032.py b/website/migrations/0045_auto_20180314_2032.py index 8a54fad6b..1f393fdbe 100644 --- a/website/migrations/0045_auto_20180314_2032.py +++ b/website/migrations/0045_auto_20180314_2032.py @@ -15,9 +15,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("address", models.CharField(blank=True, max_length=25, null=True)), ("user", models.CharField(blank=True, max_length=25, null=True)), diff --git a/website/migrations/0046_auto_20180630_0848.py b/website/migrations/0046_auto_20180630_0848.py index d73c48c31..36fedb110 100644 --- a/website/migrations/0046_auto_20180630_0848.py +++ b/website/migrations/0046_auto_20180630_0848.py @@ -60,9 +60,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="issue", name="screenshot", - field=models.ImageField( - upload_to="screenshots", validators=[website.models.validate_image] - ), + field=models.ImageField(upload_to="screenshots", validators=[website.models.validate_image]), ), migrations.AlterField( model_name="issue", diff --git a/website/migrations/0047_auto_20200613_0814.py b/website/migrations/0047_auto_20200613_0814.py index 3df33eaf3..c409657b0 100644 --- a/website/migrations/0047_auto_20200613_0814.py +++ b/website/migrations/0047_auto_20200613_0814.py @@ -17,9 +17,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("name", models.CharField(blank=True, max_length=25)), ("charge_per_month", models.IntegerField(blank=True)), @@ -48,9 +46,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="hunt", name="domain", - field=models.ForeignKey( - default=1, on_delete=django.db.models.deletion.CASCADE, to="website.Domain" - ), + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to="website.Domain"), preserve_default=False, ), migrations.CreateModel( @@ -58,9 +54,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("is_active", models.BooleanField(default=True)), ( diff --git a/website/migrations/0052_auto_20200619_0540.py b/website/migrations/0052_auto_20200619_0540.py index 34ebe8a54..7d691d6f3 100644 --- a/website/migrations/0052_auto_20200619_0540.py +++ b/website/migrations/0052_auto_20200619_0540.py @@ -36,9 +36,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("name", models.CharField(max_length=255, unique=True)), ("url", models.URLField()), diff --git a/website/migrations/0053_auto_20200619_0551.py b/website/migrations/0053_auto_20200619_0551.py index 352863f7c..cb5a34c1a 100644 --- a/website/migrations/0053_auto_20200619_0551.py +++ b/website/migrations/0053_auto_20200619_0551.py @@ -17,9 +17,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ( "role", diff --git a/website/migrations/0059_transaction_wallet.py b/website/migrations/0059_transaction_wallet.py index b1146d46d..eb9c6a140 100644 --- a/website/migrations/0059_transaction_wallet.py +++ b/website/migrations/0059_transaction_wallet.py @@ -17,17 +17,13 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("current_balance", models.DecimalField(decimal_places=2, default=0, max_digits=6)), ("created_at", models.DateTimeField(auto_now_add=True)), ( "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ], ), @@ -36,18 +32,14 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("value", models.DecimalField(decimal_places=2, max_digits=6)), ("running_balance", models.DecimalField(decimal_places=2, max_digits=6)), ("created_at", models.DateTimeField(auto_now_add=True)), ( "wallet", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.Wallet" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.Wallet"), ), ], ), diff --git a/website/migrations/0061_payment.py b/website/migrations/0061_payment.py index c76b8c4c9..1e4e61f1a 100644 --- a/website/migrations/0061_payment.py +++ b/website/migrations/0061_payment.py @@ -15,17 +15,13 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ("value", models.DecimalField(decimal_places=2, max_digits=6)), ("active", models.BooleanField(default=True)), ( "wallet", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.Wallet" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.Wallet"), ), ], ), diff --git a/website/migrations/0066_auto_20200827_1733.py b/website/migrations/0066_auto_20200827_1733.py index 5e18f99ee..c95a55516 100644 --- a/website/migrations/0066_auto_20200827_1733.py +++ b/website/migrations/0066_auto_20200827_1733.py @@ -22,9 +22,7 @@ class Migration(migrations.Migration): fields=[ ( "id", - models.AutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), ), ( "user", diff --git a/website/migrations/0070_alter_issue_label_issuescreenshot.py b/website/migrations/0070_alter_issue_label_issuescreenshot.py index ed3aaf0c5..c1f5ad8c6 100644 --- a/website/migrations/0070_alter_issue_label_issuescreenshot.py +++ b/website/migrations/0070_alter_issue_label_issuescreenshot.py @@ -50,9 +50,7 @@ class Migration(migrations.Migration): ), ( "issue", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.issue" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.issue"), ), ], ), diff --git a/website/migrations/0074_company_company_id_company_managers_domain_managers_and_more.py b/website/migrations/0074_company_company_id_company_managers_domain_managers_and_more.py index dcf4b9edc..8c68dbcfd 100644 --- a/website/migrations/0074_company_company_id_company_managers_domain_managers_and_more.py +++ b/website/migrations/0074_company_company_id_company_managers_domain_managers_and_more.py @@ -26,9 +26,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="company", name="managers", - field=models.ManyToManyField( - related_name="user_companies", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(related_name="user_companies", to=settings.AUTH_USER_MODEL), ), migrations.AddField( model_name="domain", diff --git a/website/migrations/0077_hunt_banner_huntprize.py b/website/migrations/0077_hunt_banner_huntprize.py index aab0e8412..196f12220 100644 --- a/website/migrations/0077_hunt_banner_huntprize.py +++ b/website/migrations/0077_hunt_banner_huntprize.py @@ -35,9 +35,7 @@ class Migration(migrations.Migration): ("description", models.TextField(blank=True, null=True)), ( "hunt", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.hunt" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.hunt"), ), ], ), diff --git a/website/migrations/0079_userprofile_crypto_address_and_more.py b/website/migrations/0079_userprofile_crypto_address_and_more.py index 60e4dbf85..95655ea04 100644 --- a/website/migrations/0079_userprofile_crypto_address_and_more.py +++ b/website/migrations/0079_userprofile_crypto_address_and_more.py @@ -19,15 +19,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name="userprofile", name="subscribed_domains", - field=models.ManyToManyField( - related_name="user_subscribed_domains", to="website.domain" - ), + field=models.ManyToManyField(related_name="user_subscribed_domains", to="website.domain"), ), migrations.AddField( model_name="userprofile", name="subscribed_users", - field=models.ManyToManyField( - related_name="user_subscribed_users", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(related_name="user_subscribed_users", to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0080_alter_issue_team_members.py b/website/migrations/0080_alter_issue_team_members.py index 9cac15112..de1133edb 100644 --- a/website/migrations/0080_alter_issue_team_members.py +++ b/website/migrations/0080_alter_issue_team_members.py @@ -14,8 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="issue", name="team_members", - field=models.ManyToManyField( - blank=True, related_name="reportmembers", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(blank=True, related_name="reportmembers", to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0083_alter_invitefriend_options_and_more.py b/website/migrations/0083_alter_invitefriend_options_and_more.py index 7c97970e0..fc4e446a5 100644 --- a/website/migrations/0083_alter_invitefriend_options_and_more.py +++ b/website/migrations/0083_alter_invitefriend_options_and_more.py @@ -34,9 +34,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="invitefriend", name="recipients", - field=models.ManyToManyField( - blank=True, related_name="received_invites", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(blank=True, related_name="received_invites", to=settings.AUTH_USER_MODEL), ), migrations.AddField( model_name="invitefriend", diff --git a/website/migrations/0090_alter_domain_managers.py b/website/migrations/0090_alter_domain_managers.py index 887a23752..8a44d6fe8 100644 --- a/website/migrations/0090_alter_domain_managers.py +++ b/website/migrations/0090_alter_domain_managers.py @@ -14,8 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domain", name="managers", - field=models.ManyToManyField( - blank=True, related_name="user_domains", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(blank=True, related_name="user_domains", to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0097_contributor_project_contributors.py b/website/migrations/0097_contributor_project_contributors.py index 5fd0bb3d8..c75593ec2 100644 --- a/website/migrations/0097_contributor_project_contributors.py +++ b/website/migrations/0097_contributor_project_contributors.py @@ -32,8 +32,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="project", name="contributors", - field=models.ManyToManyField( - blank=True, null=True, related_name="projects", to="website.contributor" - ), + field=models.ManyToManyField(blank=True, null=True, related_name="projects", to="website.contributor"), ), ] diff --git a/website/migrations/0101_alter_bid_user.py b/website/migrations/0101_alter_bid_user.py index fed87d9c1..0b647e4fc 100644 --- a/website/migrations/0101_alter_bid_user.py +++ b/website/migrations/0101_alter_bid_user.py @@ -15,8 +15,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="bid", name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0102_remove_bid_amount_bid_amount_bch_and_more.py b/website/migrations/0102_remove_bid_amount_bid_amount_bch_and_more.py index df170d762..5bce1db41 100644 --- a/website/migrations/0102_remove_bid_amount_bid_amount_bch_and_more.py +++ b/website/migrations/0102_remove_bid_amount_bid_amount_bch_and_more.py @@ -21,8 +21,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="project", name="contributors", - field=models.ManyToManyField( - blank=True, related_name="projects", to="website.contributor" - ), + field=models.ManyToManyField(blank=True, related_name="projects", to="website.contributor"), ), ] diff --git a/website/migrations/0103_contribution_bacontoken.py b/website/migrations/0103_contribution_bacontoken.py index c263a75a7..45bbe3a16 100644 --- a/website/migrations/0103_contribution_bacontoken.py +++ b/website/migrations/0103_contribution_bacontoken.py @@ -29,9 +29,7 @@ class Migration(migrations.Migration): ("date_created", models.DateTimeField(auto_now_add=True)), ( "status", - models.CharField( - choices=[("open", "Open"), ("closed", "Closed")], max_length=50 - ), + models.CharField(choices=[("open", "Open"), ("closed", "Closed")], max_length=50), ), ("txid", models.CharField(blank=True, max_length=64, null=True)), ( diff --git a/website/migrations/0126_alter_userprofile_subscribed_domains_and_more.py b/website/migrations/0126_alter_userprofile_subscribed_domains_and_more.py index 44515ca62..cf0f5a708 100644 --- a/website/migrations/0126_alter_userprofile_subscribed_domains_and_more.py +++ b/website/migrations/0126_alter_userprofile_subscribed_domains_and_more.py @@ -14,9 +14,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="userprofile", name="subscribed_domains", - field=models.ManyToManyField( - blank=True, related_name="user_subscribed_domains", to="website.domain" - ), + field=models.ManyToManyField(blank=True, related_name="user_subscribed_domains", to="website.domain"), ), migrations.AlterField( model_name="userprofile", diff --git a/website/migrations/0144_delete_contributorstats_and_more.py b/website/migrations/0144_delete_contributorstats_and_more.py index 9d664749a..08feda3e2 100644 --- a/website/migrations/0144_delete_contributorstats_and_more.py +++ b/website/migrations/0144_delete_contributorstats_and_more.py @@ -65,8 +65,6 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name="contribution", - index=models.Index( - fields=["repository", "created"], name="website_con_reposit_9a7e49_idx" - ), + index=models.Index(fields=["repository", "created"], name="website_con_reposit_9a7e49_idx"), ), ] diff --git a/website/migrations/0155_syning_contributors_tag_20241124_0457.py b/website/migrations/0155_syning_contributors_tag_20241124_0457.py index 77898edac..8acf31594 100644 --- a/website/migrations/0155_syning_contributors_tag_20241124_0457.py +++ b/website/migrations/0155_syning_contributors_tag_20241124_0457.py @@ -9,9 +9,7 @@ def replace_blt_contributors_tag(apps, schema_editor): UserProfile = apps.get_model("website", "UserProfile") # Get or create the "BLT Contributors" tag - blt_contributors_tag, _ = Tag.objects.get_or_create( - name="BLT Contributors", slug="blt_contributors" - ) + blt_contributors_tag, _ = Tag.objects.get_or_create(name="BLT Contributors", slug="blt_contributors") try: # Get the "BLT-Contributors" tag diff --git a/website/migrations/0157_badge_userbadge.py b/website/migrations/0157_badge_userbadge.py index 3af40b377..5a9e958fe 100644 --- a/website/migrations/0157_badge_userbadge.py +++ b/website/migrations/0157_badge_userbadge.py @@ -68,9 +68,7 @@ class Migration(migrations.Migration): ), ( "badge", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="website.badge" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="website.badge"), ), ( "user", diff --git a/website/migrations/0160_activity_dislike_count_activity_dislikes_and_more.py b/website/migrations/0160_activity_dislike_count_activity_dislikes_and_more.py index fef162d82..0d5c0e68c 100644 --- a/website/migrations/0160_activity_dislike_count_activity_dislikes_and_more.py +++ b/website/migrations/0160_activity_dislike_count_activity_dislikes_and_more.py @@ -43,8 +43,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="activity", name="likes", - field=models.ManyToManyField( - blank=True, related_name="liked_activities", to=settings.AUTH_USER_MODEL - ), + field=models.ManyToManyField(blank=True, related_name="liked_activities", to=settings.AUTH_USER_MODEL), ), ] diff --git a/website/migrations/0165_add_badge_icons.py b/website/migrations/0165_add_badge_icons.py index b30b5569e..983381428 100644 --- a/website/migrations/0165_add_badge_icons.py +++ b/website/migrations/0165_add_badge_icons.py @@ -89,9 +89,7 @@ def add_badge_icons(apps, schema_editor): print(f"Found image for {badge_data['title']} at {static_icon_path}") # Create the target directory in MEDIA_ROOT (media/badges/) - media_icon_path = os.path.join( - settings.MEDIA_ROOT, "badges", os.path.basename(static_icon_path) - ) + media_icon_path = os.path.join(settings.MEDIA_ROOT, "badges", os.path.basename(static_icon_path)) # Ensure the target directory exists os.makedirs(os.path.dirname(media_icon_path), exist_ok=True) diff --git a/website/migrations/0168_add_streak_badges.py b/website/migrations/0168_add_streak_badges.py index 0620b798e..3222efc3e 100644 --- a/website/migrations/0168_add_streak_badges.py +++ b/website/migrations/0168_add_streak_badges.py @@ -58,9 +58,7 @@ def add_badge_icons(apps, schema_editor): print(f"Found image for {badge_data['title']} at {static_icon_path}") # Create the target directory in MEDIA_ROOT (media/badges/) - media_icon_path = os.path.join( - settings.MEDIA_ROOT, "badges", os.path.basename(static_icon_path) - ) + media_icon_path = os.path.join(settings.MEDIA_ROOT, "badges", os.path.basename(static_icon_path)) # Ensure the target directory exists os.makedirs(os.path.dirname(media_icon_path), exist_ok=True) diff --git a/website/migrations/0173_remove_company_admin_remove_company_integrations_and_more.py b/website/migrations/0173_remove_company_admin_remove_company_integrations_and_more.py index 3ea350f44..370dcbdb3 100644 --- a/website/migrations/0173_remove_company_admin_remove_company_integrations_and_more.py +++ b/website/migrations/0173_remove_company_admin_remove_company_integrations_and_more.py @@ -98,9 +98,7 @@ class Migration(migrations.Migration): ), ( "managers", - models.ManyToManyField( - related_name="user_organizations", to=settings.AUTH_USER_MODEL - ), + models.ManyToManyField(related_name="user_organizations", to=settings.AUTH_USER_MODEL), ), ( "subscription", diff --git a/website/migrations/0176_repo_contributor_repo_contributor_count_and_more.py b/website/migrations/0176_repo_contributor_repo_contributor_count_and_more.py index b55ff9feb..cff084745 100644 --- a/website/migrations/0176_repo_contributor_repo_contributor_count_and_more.py +++ b/website/migrations/0176_repo_contributor_repo_contributor_count_and_more.py @@ -12,9 +12,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="repo", name="contributor", - field=models.ManyToManyField( - blank=True, related_name="repos", to="website.contributor" - ), + field=models.ManyToManyField(blank=True, related_name="repos", to="website.contributor"), ), migrations.AddField( model_name="repo", diff --git a/website/serializers.py b/website/serializers.py index 5e1129213..bd88a7d43 100644 --- a/website/serializers.py +++ b/website/serializers.py @@ -35,11 +35,7 @@ class UserProfileSerializer(serializers.ModelSerializer): """ def get_total_score(self, instance): - score = ( - Points.objects.filter(user=instance.user) - .aggregate(total_score=Sum("score")) - .get("total_score") - ) + score = Points.objects.filter(user=instance.user).aggregate(total_score=Sum("score")).get("total_score") if score is None: return 0 return score diff --git a/website/signals.py b/website/signals.py index 62bc9b2d2..b8995c7ac 100644 --- a/website/signals.py +++ b/website/signals.py @@ -3,19 +3,7 @@ from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver -from .models import ( - Activity, - Badge, - Bid, - Hunt, - IpReport, - Issue, - Post, - Suggestion, - TimeLog, - UserBadge, - UserProfile, -) +from .models import Activity, Badge, Bid, Hunt, IpReport, Issue, Post, Suggestion, TimeLog, UserBadge, UserProfile def get_default_user(): @@ -38,9 +26,7 @@ def create_activity(instance, action_type): """Generic function to create an activity for a given model instance.""" model_name = instance._meta.model_name user_field = ( - getattr(instance, "user", None) - or getattr(instance, "author", None) - or getattr(instance, "modified_by", None) + getattr(instance, "user", None) or getattr(instance, "author", None) or getattr(instance, "modified_by", None) ) user = user_field or get_default_user() diff --git a/website/test_api.py b/website/test_api.py index 73e7ad9e2..a7a1cefdf 100644 --- a/website/test_api.py +++ b/website/test_api.py @@ -111,8 +111,7 @@ def test_get_bug_hunt(self): self.assertEqual(response.status_code, status.HTTP_200_OK) if len(response.data): self.assertTrue( - response.data[0]["starts_on"] < timezone.now() - and response.data[0]["end_on"] > timezone.now(), + response.data[0]["starts_on"] < timezone.now() and response.data[0]["end_on"] > timezone.now(), "Invalid Response", ) response = self.client.get("".join([url, "previousHunt=1/"])) diff --git a/website/test_blog.py b/website/test_blog.py index 93e718d7e..8446145de 100644 --- a/website/test_blog.py +++ b/website/test_blog.py @@ -20,9 +20,7 @@ def test_add_comment(self): data = {"content_type": "post", "comment": "This is a test comment."} response = self.client.post(url, data) self.assertEqual(response.status_code, 200) - self.assertTrue( - Comment.objects.filter(content_type__model="post", object_id=self.post.pk).exists() - ) + self.assertTrue(Comment.objects.filter(content_type__model="post", object_id=self.post.pk).exists()) def test_update_comment(self): comment = Comment.objects.create( diff --git a/website/test_issues.py b/website/test_issues.py index 250b7988a..52b3f4ff0 100644 --- a/website/test_issues.py +++ b/website/test_issues.py @@ -12,9 +12,7 @@ class IssueCommentTests(TestCase): def setUp(self): self.user = User.objects.create_user(username="testuser", password="12345") self.user_profile, created = UserProfile.objects.get_or_create(user=self.user) - self.issue = Issue.objects.create( - url="http://example.com", description="Test Issue", user=self.user - ) + self.issue = Issue.objects.create(url="http://example.com", description="Test Issue", user=self.user) self.client.login(username="testuser", password="12345") def test_add_comment(self): @@ -22,9 +20,7 @@ def test_add_comment(self): data = {"content_type": "issue", "comment": "This is a test comment."} response = self.client.post(url, data) self.assertEqual(response.status_code, 200) - self.assertTrue( - Comment.objects.filter(content_type__model="issue", object_id=self.issue.pk).exists() - ) + self.assertTrue(Comment.objects.filter(content_type__model="issue", object_id=self.issue.pk).exists()) def test_update_comment(self): comment = Comment.objects.create( diff --git a/website/test_slack.py b/website/test_slack.py index d414589a8..acc577a1d 100644 --- a/website/test_slack.py +++ b/website/test_slack.py @@ -11,9 +11,7 @@ class SlackHandlerTests(TestCase): def setUp(self): # Create test organization and integration self.organization = Organization.objects.create(name="Test Org", url="https://test.org") - self.integration = Integration.objects.create( - organization=self.organization, service_name="slack" - ) + self.integration = Integration.objects.create(organization=self.organization, service_name="slack") self.slack_integration = SlackIntegration.objects.create( integration=self.integration, bot_access_token="xoxb-test-token", diff --git a/website/tests.py b/website/tests.py index 554029b34..1075365d3 100644 --- a/website/tests.py +++ b/website/tests.py @@ -42,9 +42,7 @@ def test_signup(self): self.selenium.find_element("name", "password1").send_keys("6:}jga,6mRKNUqMQ") self.selenium.find_element("name", "password2").send_keys("6:}jga,6mRKNUqMQ") self.selenium.find_element("name", "signup_button").click() - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) body = self.selenium.find_element("tag name", "body") self.assertIn("bugbugbug (0 Pts)", body.text) @@ -54,9 +52,7 @@ def test_login(self): self.selenium.find_element("name", "login").send_keys("bugbug") self.selenium.find_element("name", "password").send_keys("secret") self.selenium.find_element("name", "login_button").click() - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) body = self.selenium.find_element("tag name", "body") self.assertIn("bugbug (0 Pts)", body.text) @@ -67,14 +63,10 @@ def test_post_bug_full_url(self): self.selenium.find_element("name", "login").send_keys("bugbug") self.selenium.find_element("name", "password").send_keys("secret") self.selenium.find_element("name", "login_button").click() - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) self.selenium.get("%s%s" % (self.live_server_url, "/report/")) self.selenium.find_element("name", "url").send_keys("https://blt.owasp.org/report/") - self.selenium.find_element("id", "description").send_keys( - "XSS Attack on Google" - ) # title of bug + self.selenium.find_element("id", "description").send_keys("XSS Attack on Google") # title of bug self.selenium.find_element("id", "markdownInput").send_keys("Description of bug") Imagepath = os.path.abspath(os.path.join(os.getcwd(), "website/static/img/background.jpg")) self.selenium.find_element("name", "screenshots").send_keys(Imagepath) @@ -82,9 +74,7 @@ def test_post_bug_full_url(self): self.selenium.find_element("name", "captcha_1").send_keys("PASSED") self.selenium.find_element("name", "reportbug_button").click() self.selenium.get("%s%s" % (self.live_server_url, "/all_activity/")) - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) body = self.selenium.find_element("tag name", "body") self.assertIn("XSS Attack on Google", body.text) @@ -95,14 +85,10 @@ def test_post_bug_domain_url(self): self.selenium.find_element("name", "login").send_keys("bugbug") self.selenium.find_element("name", "password").send_keys("secret") self.selenium.find_element("name", "login_button").click() - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) self.selenium.get("%s%s" % (self.live_server_url, "/report/")) self.selenium.find_element("name", "url").send_keys("https://google.com") - self.selenium.find_element("id", "description").send_keys( - "XSS Attack on Google" - ) # title of bug + self.selenium.find_element("id", "description").send_keys("XSS Attack on Google") # title of bug self.selenium.find_element("id", "markdownInput").send_keys("Description of bug") Imagepath = os.path.abspath(os.path.join(os.getcwd(), "website/static/img/background.jpg")) self.selenium.find_element("name", "screenshots").send_keys(Imagepath) @@ -110,9 +96,7 @@ def test_post_bug_domain_url(self): self.selenium.find_element("name", "captcha_1").send_keys("PASSED") self.selenium.find_element("name", "reportbug_button").click() self.selenium.get("%s%s" % (self.live_server_url, "/all_activity/")) - WebDriverWait(self.selenium, 30).until( - EC.presence_of_element_located((By.TAG_NAME, "body")) - ) + WebDriverWait(self.selenium, 30).until(EC.presence_of_element_located((By.TAG_NAME, "body"))) body = self.selenium.find_element("tag name", "body") self.assertIn("XSS Attack on Google", body.text) diff --git a/website/tests_urls.py b/website/tests_urls.py index 5a25dc7e0..ebace8930 100644 --- a/website/tests_urls.py +++ b/website/tests_urls.py @@ -91,9 +91,9 @@ def check_urls(urlpatterns, prefix=""): regex = pattern.pattern.regex if regex.groups > 0: - if regex.groups > len(list(regex.groupindex.keys())) or set( - regex.groupindex.keys() - ) - set(default_kwargs.keys()): + if regex.groups > len(list(regex.groupindex.keys())) or set(regex.groupindex.keys()) - set( + default_kwargs.keys() + ): skip = True else: for key in set(default_kwargs.keys()) & set(regex.groupindex.keys()): @@ -137,8 +137,7 @@ def check_urls(urlpatterns, prefix=""): self.assertIn( response.status_code, allowed_http_codes, - msg="!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!the url that caused the eror is: %s" - % url, + msg="!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!the url that caused the eror is: %s" % url, ) self.selenium.get("%s%s" % (self.live_server_url, url)) @@ -146,8 +145,7 @@ def check_urls(urlpatterns, prefix=""): self.assertNotIn( "SyntaxError", str(entry), - msg="!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!the url that caused the eror is: %s" - % url, + msg="!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!the url that caused the eror is: %s" % url, ) check_urls(module.urlpatterns) diff --git a/website/utils.py b/website/utils.py index 46f0ee309..f81c53e58 100644 --- a/website/utils.py +++ b/website/utils.py @@ -55,9 +55,7 @@ def get_email_from_domain(domain_name): response = requests.get(url) except: continue - new_emails = set( - re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+", response.text, re.I) - ) + new_emails = set(re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+", response.text, re.I)) if new_emails: emails.update(new_emails) break @@ -170,9 +168,7 @@ def safe_redirect_request(request: HttpRequest): if http_referer: referer_url = urlparse(http_referer) if referer_url.netloc == request.get_host(): - safe_url = urlunparse( - (referer_url.scheme, referer_url.netloc, referer_url.path, "", "", "") - ) + safe_url = urlunparse((referer_url.scheme, referer_url.netloc, referer_url.path, "", "", "")) return redirect(safe_url) fallback_url = f"{request.scheme}://{request.get_host()}/" return redirect(fallback_url) @@ -254,9 +250,7 @@ def generate_embedding(text, retries=2, backoff_factor=2): """ for attempt in range(retries): try: - response = openai.embeddings.create( - model="text-embedding-ada-002", input=text, encoding_format="float" - ) + response = openai.embeddings.create(model="text-embedding-ada-002", input=text, encoding_format="float") # response = { # "object": "list", # "data": [ @@ -301,9 +295,7 @@ def cosine_similarity(embedding1, embedding2): :param embedding2: The second embedding vector. :return: The cosine similarity score between the two embeddings. """ - similarity = np.dot(embedding1, embedding2) / ( - np.linalg.norm(embedding1) * np.linalg.norm(embedding2) - ) + similarity = np.dot(embedding1, embedding2) / (np.linalg.norm(embedding1) * np.linalg.norm(embedding2)) similarity_score = similarity * 100 # Scale similarity to 0-100 return round(similarity_score, 2) @@ -329,9 +321,7 @@ def extract_function_signatures_and_content(repo_path): signature = { "name": node.name, "args": [arg.arg for arg in node.args.args], - "defaults": [ - ast.dump(default) for default in node.args.defaults - ], + "defaults": [ast.dump(default) for default in node.args.defaults], } # Extract function body as full text function_text = ast.get_source_segment(file_content, node) @@ -416,9 +406,7 @@ def compare_model_fields(model1, model2): :return: Dictionary containing name and field similarity details """ # Compare model names - model_name_similarity = ( - difflib.SequenceMatcher(None, model1["name"], model2["name"]).ratio() * 100 - ) + model_name_similarity = difflib.SequenceMatcher(None, model1["name"], model2["name"]).ratio() * 100 # Initialize field comparison details field_comparison_details = [] @@ -431,14 +419,12 @@ def compare_model_fields(model1, model2): for field2 in fields2: # Compare field names field_name_similarity = ( - difflib.SequenceMatcher(None, field1["field_name"], field2["field_name"]).ratio() - * 100 + difflib.SequenceMatcher(None, field1["field_name"], field2["field_name"]).ratio() * 100 ) # Compare field types field_type_similarity = ( - difflib.SequenceMatcher(None, field1["field_type"], field2["field_type"]).ratio() - * 100 + difflib.SequenceMatcher(None, field1["field_type"], field2["field_type"]).ratio() * 100 ) # Average similarity between the field name and type diff --git a/website/views/company.py b/website/views/company.py index 01efe51dc..a26639ccd 100644 --- a/website/views/company.py +++ b/website/views/company.py @@ -147,9 +147,7 @@ def post(self, request, *args, **kwargs): organization_url = data.get("organization_url", "") if user_domain in restricted_domain: - messages.error( - request, "Login with organization email in order to create the organization." - ) + messages.error(request, "Login with organization email in order to create the organization.") return redirect("/") if organization_name == "" or Organization.objects.filter(name=organization_name).exists(): @@ -165,9 +163,7 @@ def post(self, request, *args, **kwargs): organization_logo_file = organization_logo.name.split(".")[0] extension = organization_logo.name.split(".")[-1] organization_logo.name = f"{organization_logo_file[:99]}_{uuid.uuid4()}.{extension}" - logo_path = default_storage.save( - f"organization_logos/{organization_logo.name}", organization_logo - ) + logo_path = default_storage.save(f"organization_logos/{organization_logo.name}", organization_logo) else: logo_path = None @@ -213,20 +209,16 @@ class OrganizationDashboardAnalyticsView(View): months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def get_general_info(self, organization): - total_organization_bugs = Issue.objects.filter( - domain__organization__id=organization - ).count() + total_organization_bugs = Issue.objects.filter(domain__organization__id=organization).count() total_bug_hunts = Hunt.objects.filter(domain__organization__id=organization).count() total_domains = Domain.objects.filter(organization__id=organization).count() # Step 1: Retrieve all hunt IDs associated with the specified organization - hunt_ids = Hunt.objects.filter(domain__organization__id=organization).values_list( - "id", flat=True - ) + hunt_ids = Hunt.objects.filter(domain__organization__id=organization).values_list("id", flat=True) # Step 2: Sum the rewarded values from issues that have a hunt_id in the hunt_ids list - total_money_distributed = Issue.objects.filter(hunt_id__in=hunt_ids).aggregate( - total_money=Sum("rewarded") - )["total_money"] + total_money_distributed = Issue.objects.filter(hunt_id__in=hunt_ids).aggregate(total_money=Sum("rewarded"))[ + "total_money" + ] total_money_distributed = 0 if total_money_distributed is None else total_money_distributed return { @@ -238,9 +230,7 @@ def get_general_info(self, organization): def get_bug_report_type_piechart_data(self, organization): bug_report_type = ( - Issue.objects.values("label") - .filter(domain__organization__id=organization) - .annotate(count=Count("label")) + Issue.objects.values("label").filter(domain__organization__id=organization).annotate(count=Count("label")) ) bug_report_type_labels = [] bug_report_type_data = [] @@ -258,9 +248,7 @@ def get_bug_report_type_piechart_data(self, organization): def get_reports_on_domain_piechart_data(self, organization): report_piechart = ( - Issue.objects.values("url") - .filter(domain__organization__id=organization) - .annotate(count=Count("url")) + Issue.objects.values("url").filter(domain__organization__id=organization).annotate(count=Count("url")) ) report_labels = [] @@ -352,23 +340,17 @@ def bug_rate_increase_descrease_weekly(self, organization, is_accepted_bugs=Fals if prev_week_issue_count == 0: percent_increase = this_week_issue_count * 100 else: - percent_increase = ( - (this_week_issue_count - prev_week_issue_count) / prev_week_issue_count - ) * 100 + percent_increase = ((this_week_issue_count - prev_week_issue_count) / prev_week_issue_count) * 100 return { "percent_increase": percent_increase, - "is_increasing": True - if (this_week_issue_count - prev_week_issue_count) >= 0 - else False, + "is_increasing": True if (this_week_issue_count - prev_week_issue_count) >= 0 else False, "this_week_issue_count": this_week_issue_count, } def get_spent_on_bugtypes(self, organization): spent_on_bugtypes = ( - Issue.objects.values("label") - .filter(domain__organization__id=organization) - .annotate(spent=Sum("rewarded")) + Issue.objects.values("label").filter(domain__organization__id=organization).annotate(spent=Sum("rewarded")) ) labels = list(self.labels.values()) data = [0 for label in labels] # make all labels spent 0 / init with 0 @@ -397,13 +379,9 @@ def get(self, request, id, *args, **kwargs): "total_info": self.get_general_info(id), "bug_report_type_piechart_data": self.get_bug_report_type_piechart_data(id), "reports_on_domain_piechart_data": self.get_reports_on_domain_piechart_data(id), - "get_current_year_monthly_reported_bar_data": self.get_current_year_monthly_reported_bar_data( - id - ), + "get_current_year_monthly_reported_bar_data": self.get_current_year_monthly_reported_bar_data(id), "bug_rate_increase_descrease_weekly": self.bug_rate_increase_descrease_weekly(id), - "accepted_bug_rate_increase_descrease_weekly": self.bug_rate_increase_descrease_weekly( - id, True - ), + "accepted_bug_rate_increase_descrease_weekly": self.bug_rate_increase_descrease_weekly(id, True), "spent_on_bugtypes": self.get_spent_on_bugtypes(id), } self.get_spent_on_bugtypes(id) @@ -493,9 +471,7 @@ def get(self, request, id, *args, **kwargs): } if sort_field in sort_mapping: - daily_status_reports = daily_status_reports.order_by( - f"{sort_prefix}{sort_mapping[sort_field]}" - ) + daily_status_reports = daily_status_reports.order_by(f"{sort_prefix}{sort_mapping[sort_field]}") context = { "organization": id, @@ -539,11 +515,7 @@ def get(self, request, id, *args, **kwargs): class OrganizationDashboardManageDomainsView(View): @validate_organization_user def get(self, request, id, *args, **kwargs): - domains = ( - Domain.objects.values("id", "name", "url", "logo") - .filter(organization__id=id) - .order_by("modified") - ) + domains = Domain.objects.values("id", "name", "url", "logo").filter(organization__id=id).order_by("modified") organizations = ( Organization.objects.values("name", "id") @@ -630,9 +602,7 @@ def post(self, request, id, *args, **kwargs): managers_list = request.POST.getlist("user") organization_obj = Organization.objects.get(id=id) - domain_exist = Domain.objects.filter( - Q(name=domain_data["name"]) | Q(url=domain_data["url"]) - ).exists() + domain_exist = Domain.objects.filter(Q(name=domain_data["name"]) | Q(url=domain_data["url"])).exists() if domain_exist: messages.error(request, "Domain name or url already exist.") @@ -663,9 +633,7 @@ def post(self, request, id, *args, **kwargs): for domain_manager_email in managers_list: manager_email_domain = domain_manager_email.split("@")[-1] if not domain.endswith(f".{manager_email_domain}") and domain != manager_email_domain: - messages.error( - request, f"Manager: {domain_manager_email} does not match domain email." - ) + messages.error(request, f"Manager: {domain_manager_email} does not match domain email.") return redirect("add_domain", id=id) if request.FILES.get("logo"): @@ -692,10 +660,7 @@ def post(self, request, id, *args, **kwargs): messages.error(request, "Facebook url should contain facebook.com") return redirect("add_domain", id=id) if domain_data["twitter"]: - if ( - "twitter.com" not in domain_data["twitter"] - and "x.com" not in domain_data["twitter"] - ): + if "twitter.com" not in domain_data["twitter"] and "x.com" not in domain_data["twitter"]: messages.error(request, "Twitter url should contain twitter.com or x.com") return redirect("add_domain", id=id) if domain_data["github"] and "github.com" not in domain_data["github"]: @@ -779,13 +744,8 @@ def put(self, request, id, *args, **kwargs): for domain_manager_email in managers_list: manager_email_domain = domain_manager_email.split("@")[-1] - if ( - not domain_name.endswith(f".{manager_email_domain}") - and domain_name != manager_email_domain - ): - messages.error( - request, f"Manager: {domain_manager_email} does not match domain email." - ) + if not domain_name.endswith(f".{manager_email_domain}") and domain_name != manager_email_domain: + messages.error(request, f"Manager: {domain_manager_email} does not match domain email.") return redirect("edit_domain", id=id, domain_id=domain_id) if request.FILES.get("logo"): @@ -808,10 +768,7 @@ def put(self, request, id, *args, **kwargs): messages.error(request, "Facebook url should contain facebook.com") return redirect("edit_domain", id=id, domain_id=domain_id) if domain_data["twitter"]: - if ( - "twitter.com" not in domain_data["twitter"] - and "x.com" not in domain_data["twitter"] - ): + if "twitter.com" not in domain_data["twitter"] and "x.com" not in domain_data["twitter"]: messages.error(request, "Twitter url should contain twitter.com or x.com") return redirect("edit_domain", id=id, domain_id=domain_id) if domain_data["github"] and "github.com" not in domain_data["github"]: @@ -936,9 +893,7 @@ def post(self, request, id, *args, **kwargs): if slack_integration: app = App(token=slack_integration.bot_access_token) if slack_data["default_channel"]: - slack_integration.default_channel_id = self.get_channel_id( - app, slack_data["default_channel"] - ) + slack_integration.default_channel_id = self.get_channel_id(app, slack_data["default_channel"]) slack_integration.default_channel_name = slack_data["default_channel"] slack_integration.daily_updates = bool(slack_data["daily_sizzle_timelogs_status"]) slack_integration.daily_update_time = slack_data["daily_sizzle_timelogs_hour"] @@ -1088,18 +1043,16 @@ def get(self, request, pk, *args, **kwargs): if not domain: raise Http404("Domain not found") - total_money_distributed = Issue.objects.filter(domain__id=domain["id"]).aggregate( - total_money=Sum("rewarded") - )["total_money"] + total_money_distributed = Issue.objects.filter(domain__id=domain["id"]).aggregate(total_money=Sum("rewarded"))[ + "total_money" + ] total_money_distributed = 0 if total_money_distributed is None else total_money_distributed # Query the database for the exact domain total_bug_reported = Issue.objects.filter(domain__id=domain["id"]).count() total_bug_accepted = Issue.objects.filter(domain__id=domain["id"], verified=True).count() - is_domain_manager = Domain.objects.filter( - Q(id=domain["id"]) & Q(managers__in=[request.user]) - ).exists() + is_domain_manager = Domain.objects.filter(Q(id=domain["id"]) & Q(managers__in=[request.user])).exists() if is_domain_manager: latest_issues = ( Issue.objects.values( @@ -1165,18 +1118,16 @@ def get(self, request, pk, *args, **kwargs): first_bug = Issue.objects.filter(domain__id=domain["id"]).order_by("created").first() last_bug = Issue.objects.filter(domain__id=domain["id"]).order_by("-created").first() - ongoing_bughunts = Hunt.objects.filter(domain__id=domain["id"]).annotate( - total_prize=Sum("huntprize__value") - )[:3] + ongoing_bughunts = Hunt.objects.filter(domain__id=domain["id"]).annotate(total_prize=Sum("huntprize__value"))[ + :3 + ] context = { **domain, "total_money_distributed": total_money_distributed, "total_bug_reported": total_bug_reported, "total_bug_accepted": total_bug_accepted, "latest_issues": cleaned_issues, - "monthly_activity_chart": json.dumps( - self.get_current_year_monthly_reported_bar_data(domain["id"]) - ), + "monthly_activity_chart": json.dumps(self.get_current_year_monthly_reported_bar_data(domain["id"])), "top_testers": top_testers, "first_bug": first_bug, "last_bug": last_bug, @@ -1368,9 +1319,7 @@ def get(self, request, pk, *args, **kwargs): # bughunt prizes rewards = HuntPrize.objects.filter(hunt_id=hunt_obj.id) - winners_count = { - reward.id: Winner.objects.filter(prize_id=reward.id).count() for reward in rewards - } + winners_count = {reward.id: Winner.objects.filter(prize_id=reward.id).count() for reward in rewards} # check winner have for this bughunt winners = Winner.objects.filter(hunt_id=hunt_obj.id).select_related("prize") @@ -1622,12 +1571,8 @@ def edit_prize(request, prize_id, organization_id): data = json.loads(request.body) prize.name = data.get("prize_name", prize.name) prize.value = data.get("cash_value", prize.value) - prize.no_of_eligible_projects = data.get( - "number_of_winning_projects", prize.no_of_eligible_projects - ) - prize.valid_submissions_eligible = data.get( - "every_valid_submissions", prize.valid_submissions_eligible - ) + prize.no_of_eligible_projects = data.get("number_of_winning_projects", prize.no_of_eligible_projects) + prize.valid_submissions_eligible = data.get("every_valid_submissions", prize.valid_submissions_eligible) prize.description = data.get("prize_description", prize.description) prize.save() @@ -1642,9 +1587,7 @@ def accept_bug(request, issue_id, reward_id=None): issue.verified = True issue.rewarded = 0 issue.save() - Winner( - hunt_id=issue.hunt.id, prize_id=None, winner_id=issue.user.id, prize_amount=0 - ).save() + Winner(hunt_id=issue.hunt.id, prize_id=None, winner_id=issue.user.id, prize_amount=0).save() else: reward = get_object_or_404(HuntPrize, id=reward_id) issue.verified = True diff --git a/website/views/core.py b/website/views/core.py index 4a6079c3a..b35558586 100644 --- a/website/views/core.py +++ b/website/views/core.py @@ -48,12 +48,7 @@ UserProfile, Wallet, ) -from website.utils import ( - analyze_pr_content, - fetch_github_data, - safe_redirect_allowed, - save_analysis_report, -) +from website.utils import analyze_pr_content, fetch_github_data, safe_redirect_allowed, save_analysis_report # from website.bot import conversation_chain, is_api_key_valid, load_vector_store @@ -249,10 +244,7 @@ def check_status(request): # Database connection check if CHECK_DATABASE: print("Getting database connection count...") - if ( - settings.DATABASES.get("default", {}).get("ENGINE") - == "django.db.backends.postgresql" - ): + if settings.DATABASES.get("default", {}).get("ENGINE") == "django.db.backends.postgresql": with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'") status_data["db_connection_count"] = cursor.fetchone()[0] @@ -362,17 +354,13 @@ def search(request, template="search.html"): context = { "query": query, "type": stype, - "projects": Project.objects.filter( - Q(name__icontains=query) | Q(description__icontains=query) - ), + "projects": Project.objects.filter(Q(name__icontains=query) | Q(description__icontains=query)), } elif stype == "repos": context = { "query": query, "type": stype, - "repos": Repo.objects.filter( - Q(name__icontains=query) | Q(description__icontains=query) - ), + "repos": Repo.objects.filter(Q(name__icontains=query) | Q(description__icontains=query)), } elif stype == "tags": tags = Tag.objects.filter(name__icontains=query) @@ -527,15 +515,11 @@ def vote_suggestions(request): voted = SuggestionVotes.objects.filter(user=user, suggestion=suggestion).delete() if up_vote: - voted = SuggestionVotes.objects.create( - user=user, suggestion=suggestion, up_vote=True, down_vote=False - ) + voted = SuggestionVotes.objects.create(user=user, suggestion=suggestion, up_vote=True, down_vote=False) suggestion.up_votes += 1 if down_vote: - voted = SuggestionVotes.objects.create( - user=user, suggestion=suggestion, down_vote=True, up_vote=False - ) + voted = SuggestionVotes.objects.create(user=user, suggestion=suggestion, down_vote=True, up_vote=False) suggestion.down_votes += 1 suggestion.save() @@ -561,12 +545,8 @@ def set_vote_status(request): except Suggestion.DoesNotExist: return JsonResponse({"success": False, "error": "Suggestion not found"}, status=404) - up_vote = SuggestionVotes.objects.filter( - suggestion=suggestion, user=user, up_vote=True - ).exists() - down_vote = SuggestionVotes.objects.filter( - suggestion=suggestion, user=user, down_vote=True - ).exists() + up_vote = SuggestionVotes.objects.filter(suggestion=suggestion, user=user, up_vote=True).exists() + down_vote = SuggestionVotes.objects.filter(suggestion=suggestion, user=user, down_vote=True).exists() response = {"up_vote": up_vote, "down_vote": down_vote} return JsonResponse(response) @@ -655,9 +635,7 @@ def dispatch(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): data = request.FILES.get("image") - result = default_storage.save( - "uploads/" + self.kwargs["hash"] + ".png", ContentFile(data.read()) - ) + result = default_storage.save("uploads/" + self.kwargs["hash"] + ".png", ContentFile(data.read())) return JsonResponse({"status": result}) @@ -853,12 +831,7 @@ def submit_roadmap_pr(request): if "error" in pr_data or "error" in roadmap_data: return JsonResponse( - { - "error": ( - f"Failed to fetch PR or roadmap data: " - f"{pr_data.get('error', 'Unknown error')}" - ) - }, + {"error": (f"Failed to fetch PR or roadmap data: " f"{pr_data.get('error', 'Unknown error')}")}, status=500, ) diff --git a/website/views/issue.py b/website/views/issue.py index 1324e79ce..88ab24fed 100644 --- a/website/views/issue.py +++ b/website/views/issue.py @@ -136,9 +136,7 @@ def dislike_issue(request, issue_pk): total_votes = UserProfile.objects.filter(issue_downvoted=issue).count() context["object"] = issue context["dislikes"] = total_votes - context["isDisliked"] = UserProfile.objects.filter( - issue_downvoted=issue, user=request.user - ).exists() + context["isDisliked"] = UserProfile.objects.filter(issue_downvoted=issue, user=request.user).exists() return HttpResponse("Success") @@ -167,9 +165,7 @@ def create_github_issue(request, id): if issue.domain.github: screenshot_text = "" for screenshot in screenshot_all: - screenshot_text += ( - f"![{screenshot.image.name}]({settings.FQDN}{screenshot.image.url})\n" - ) + screenshot_text += f"![{screenshot.image.name}]({settings.FQDN}{screenshot.image.url})\n" github_url = issue.domain.github.replace("https", "git").replace("http", "git") + ".git" from giturlparse import parse as parse_github_url @@ -256,11 +252,7 @@ def UpdateIssue(request): break except: tokenauth = False - if ( - request.method == "POST" - and request.user.is_superuser - or (issue is not None and request.user == issue.user) - ): + if request.method == "POST" and request.user.is_superuser or (issue is not None and request.user == issue.user): if request.POST.get("action") == "close": issue.status = "closed" issue.closed_by = request.user @@ -276,13 +268,7 @@ def UpdateIssue(request): "action": "closed", }, ) - subject = ( - issue.domain.name - + " bug # " - + str(issue.id) - + " closed by " - + request.user.username - ) + subject = issue.domain.name + " bug # " + str(issue.id) + " closed by " + request.user.username elif request.POST.get("action") == "open": issue.status = "open" @@ -298,13 +284,7 @@ def UpdateIssue(request): "action": "opened", }, ) - subject = ( - issue.domain.name - + " bug # " - + str(issue.id) - + " opened by " - + request.user.username - ) + subject = issue.domain.name + " bug # " + str(issue.id) + " opened by " + request.user.username mailer = settings.EMAIL_TO_STRING email_to = issue.user.email @@ -428,9 +408,7 @@ def search_issues(request, template="search.html"): query = query[6:] if stype == "issue" or stype is None: if request.user.is_anonymous: - issues = Issue.objects.filter(Q(description__icontains=query), hunt=None).exclude( - Q(is_hidden=True) - )[0:20] + issues = Issue.objects.filter(Q(description__icontains=query), hunt=None).exclude(Q(is_hidden=True))[0:20] else: issues = Issue.objects.filter(Q(description__icontains=query), hunt=None).exclude( Q(is_hidden=True) & ~Q(user_id=request.user.id) @@ -602,13 +580,9 @@ def form_valid(self, form): if self.request.POST.get("screenshot-hash"): filename = self.request.POST.get("screenshot-hash") extension = filename.split(".")[-1] - self.request.POST["screenshot-hash"] = ( - filename[:99] + str(uuid.uuid4()) + "." + extension - ) + self.request.POST["screenshot-hash"] = filename[:99] + str(uuid.uuid4()) + "." + extension - reopen = default_storage.open( - "uploads\/" + self.request.POST.get("screenshot-hash") + ".png", "rb" - ) + reopen = default_storage.open("uploads\/" + self.request.POST.get("screenshot-hash") + ".png", "rb") django_file = File(reopen) obj.screenshot.save( self.request.POST.get("screenshot-hash") + ".png", @@ -639,9 +613,7 @@ def process_issue(self, user, obj, created, domain, tokenauth=False, score=3): ) domain_name = domain.get_name twitter_account = ( - "@" + domain.get_or_set_x_url(domain_name) + " " - if domain.get_or_set_x_url(domain_name) - else "" + "@" + domain.get_or_set_x_url(domain_name) + " " if domain.get_or_set_x_url(domain_name) else "" ) issue_title = obj.description + " " if not obj.is_hidden else "" @@ -675,12 +647,8 @@ def process_issue(self, user, obj, created, domain, tokenauth=False, score=3): name = email_to.split("@")[0] - msg_plain = render_to_string( - "email/domain_added.txt", {"domain": domain.name, "name": name} - ) - msg_html = render_to_string( - "email/domain_added.txt", {"domain": domain.name, "name": name} - ) + msg_plain = render_to_string("email/domain_added.txt", {"domain": domain.name, "name": name}) + msg_html = render_to_string("email/domain_added.txt", {"domain": domain.name, "name": name}) send_mail( domain.name + " added to " + settings.PROJECT_NAME, @@ -780,12 +748,7 @@ def get_initial(self): if isinstance(self.request.POST.get("file"), six.string_types): import imghdr - data = ( - "data:image/" - + self.request.POST.get("type") - + ";base64," - + self.request.POST.get("file") - ) + data = "data:image/" + self.request.POST.get("type") + ";base64," + self.request.POST.get("file") data = data.replace(" ", "") data += "=" * ((4 - len(data) % 4) % 4) if "data:" in data and ";base64," in data: @@ -806,9 +769,7 @@ def get_initial(self): file_extension, ) - self.request.FILES["screenshot"] = ContentFile( - decoded_file, name=complete_file_name - ) + self.request.FILES["screenshot"] = ContentFile(decoded_file, name=complete_file_name) except: tokenauth = False initial = super(IssueCreate, self).get_initial() @@ -891,9 +852,7 @@ def form_valid(self, form): limit = 50 if self.request.user.is_authenticated else 30 today = now().date() - recent_issues_count = Issue.objects.filter( - reporter_ip_address=reporter_ip, created__date=today - ).count() + recent_issues_count = Issue.objects.filter(reporter_ip_address=reporter_ip, created__date=today).count() if recent_issues_count >= limit: messages.error(self.request, "You have reached your issue creation limit for today.") @@ -903,9 +862,7 @@ def form_valid(self, form): @atomic def create_issue(self, form): # Validate screenshots first before any database operations - if len(self.request.FILES.getlist("screenshots")) == 0 and not self.request.POST.get( - "screenshot-hash" - ): + if len(self.request.FILES.getlist("screenshots")) == 0 and not self.request.POST.get("screenshot-hash"): messages.error(self.request, "Screenshot is needed!") return render( self.request, @@ -1012,9 +969,7 @@ def create_issue(self, form): # Handle team members team_members_id = [ member["id"] - for member in User.objects.values("id").filter( - email__in=self.request.POST.getlist("team_members") - ) + for member in User.objects.values("id").filter(email__in=self.request.POST.getlist("team_members")) ] + [self.request.user.id] team_members_id = [member_id for member_id in team_members_id if member_id is not None] obj.team_members.set(team_members_id) @@ -1037,9 +992,7 @@ def create_issue(self, form): user_prof.save() if tokenauth: - total_issues = Issue.objects.filter( - user=User.objects.get(id=token.user_id) - ).count() + total_issues = Issue.objects.filter(user=User.objects.get(id=token.user_id)).count() user_prof = UserProfile.objects.get(user=User.objects.get(id=token.user_id)) if total_issues <= 10: user_prof.title = 1 @@ -1094,9 +1047,7 @@ def create_issue(self, form): obj.github_url = response["html_url"] except Exception as e: send_mail( - "Error in github issue creation for " - + str(domain.name) - + ", check your github settings", + "Error in github issue creation for " + str(domain.name) + ", check your github settings", "Error in github issue creation, check your github settings\n" + " your current settings are: " + str(domain.github) @@ -1117,9 +1068,7 @@ def create_issue(self, form): return HttpResponseRedirect("/") if tokenauth: - self.process_issue( - User.objects.get(id=token.user_id), obj, domain_exists, domain, True - ) + self.process_issue(User.objects.get(id=token.user_id), obj, domain_exists, domain, True) return JsonResponse("Created", safe=False) else: self.process_issue(self.request.user, obj, domain_exists, domain) @@ -1137,9 +1086,7 @@ def get_context_data(self, **kwargs): # "processing get_context_data for ip address: ", get_client_ip(self.request) # ) context = super(IssueCreate, self).get_context_data(**kwargs) - context["activities"] = Issue.objects.exclude( - Q(is_hidden=True) & ~Q(user_id=self.request.user.id) - )[0:10] + context["activities"] = Issue.objects.exclude(Q(is_hidden=True) & ~Q(user_id=self.request.user.id))[0:10] context["captcha_form"] = CaptchaForm() if self.request.user.is_authenticated: context["wallet"] = Wallet.objects.get(user=self.request.user) @@ -1160,15 +1107,11 @@ def get_context_data(self, **kwargs): ) context["report_on_hunt"] = True else: - context["hunts"] = Hunt.objects.values("id", "name").filter( - is_published=True, result_published=False - ) + context["hunts"] = Hunt.objects.values("id", "name").filter(is_published=True, result_published=False) context["report_on_hunt"] = False context["top_domains"] = ( - Issue.objects.values("domain__name") - .annotate(count=Count("domain__name")) - .order_by("-count")[:30] + Issue.objects.values("domain__name").annotate(count=Count("domain__name")).order_by("-count")[:30] ) return context @@ -1208,9 +1151,7 @@ def get_context_data(self, *args, **kwargs): context["user"] = self.request.GET.get("user") context["activity_screenshots"] = {} for activity in self.activities: - context["activity_screenshots"][activity] = IssueScreenshot.objects.filter( - issue=activity - ).first() + context["activity_screenshots"][activity] = IssueScreenshot.objects.filter(issue=activity).first() return context @@ -1248,13 +1189,13 @@ def get_queryset(self): Q(is_hidden=True) & ~Q(user_id=self.request.user.id) ) elif statu != "none": - self.activities = Issue.objects.filter( - user__username=username, status=statu, hunt=None - ).exclude(Q(is_hidden=True) & ~Q(user_id=self.request.user.id)) + self.activities = Issue.objects.filter(user__username=username, status=statu, hunt=None).exclude( + Q(is_hidden=True) & ~Q(user_id=self.request.user.id) + ) else: - self.activities = Issue.objects.filter( - user__username=username, label=query, hunt=None - ).exclude(Q(is_hidden=True) & ~Q(user_id=self.request.user.id)) + self.activities = Issue.objects.filter(user__username=username, label=query, hunt=None).exclude( + Q(is_hidden=True) & ~Q(user_id=self.request.user.id) + ) return self.activities def get_context_data(self, *args, **kwargs): @@ -1313,9 +1254,7 @@ def get(self, request, *args, **kwargs): self.object.save() else: try: - objectget = IP.objects.get( - address=get_client_ip(request), issuenumber=self.object.id - ) + objectget = IP.objects.get(address=get_client_ip(request), issuenumber=self.object.id) self.object.save() except Exception as e: print(e) @@ -1341,9 +1280,7 @@ def get_context_data(self, **kwargs): context["os_family"] = user_agent.os.family context["os_version"] = user_agent.os.version_string context["users_score"] = list( - Points.objects.filter(user=self.object.user) - .aggregate(total_score=Sum("score")) - .values() + Points.objects.filter(user=self.object.user).aggregate(total_score=Sum("score")).values() )[0] if self.request.user.is_authenticated: @@ -1403,12 +1340,7 @@ def submit_bug(request, pk, template="hunt_submittion.html"): if isinstance(request.POST.get("file"), six.string_types): import imghdr - data = ( - "data:image/" - + request.POST.get("type") - + ";base64," - + request.POST.get("file") - ) + data = "data:image/" + request.POST.get("type") + ";base64," + request.POST.get("file") data = data.replace(" ", "") data += "=" * ((4 - len(data) % 4) % 4) if "data:" in data and ";base64," in data: @@ -1464,15 +1396,13 @@ def delete_content_comment(request): content = content_type_obj.get_object_for_this_type(pk=content_pk) if request.method == "POST": - comment = Comment.objects.get( - pk=int(request.POST["comment_pk"]), author=request.user.username - ) + comment = Comment.objects.get(pk=int(request.POST["comment_pk"]), author=request.user.username) comment.delete() context = { - "all_comments": Comment.objects.filter( - content_type=content_type_obj, object_id=content_pk - ).order_by("-created_date"), + "all_comments": Comment.objects.filter(content_type=content_type_obj, object_id=content_pk).order_by( + "-created_date" + ), "object": content, } return render(request, "comments2.html", context) @@ -1489,9 +1419,9 @@ def update_content_comment(request, content_pk, comment_pk): comment.save() context = { - "all_comment": Comment.objects.filter( - content_type=content_type_obj, object_id=content_pk - ).order_by("-created_date"), + "all_comment": Comment.objects.filter(content_type=content_type_obj, object_id=content_pk).order_by( + "-created_date" + ), "object": content, } return render(request, "comments2.html", context) @@ -1545,9 +1475,9 @@ def comment_on_content(request, content_pk): ) context = { - "all_comment": Comment.objects.filter( - content_type=content_type_obj, object_id=content_pk - ).order_by("-created_date"), + "all_comment": Comment.objects.filter(content_type=content_type_obj, object_id=content_pk).order_by( + "-created_date" + ), "object": content, } @@ -1611,9 +1541,7 @@ def IssueEdit(request): uri = request.POST.get("domain") link = uri.replace("www.", "") if request.user == issue.user or request.user.is_superuser: - domain, created = Domain.objects.get_or_create( - name=link, defaults={"url": "http://" + link} - ) + domain, created = Domain.objects.get_or_create(name=link, defaults={"url": "http://" + link}) issue.domain = domain if uri[:4] != "http" and uri[:5] != "https": uri = "https://" + uri diff --git a/website/views/organization.py b/website/views/organization.py index 28d24c595..c4c807b2c 100644 --- a/website/views/organization.py +++ b/website/views/organization.py @@ -124,9 +124,7 @@ def admin_organization_dashboard(request, template="admin_dashboard_organization @login_required(login_url="/accounts/login") -def admin_organization_dashboard_detail( - request, pk, template="admin_dashboard_organization_detail.html" -): +def admin_organization_dashboard_detail(request, pk, template="admin_dashboard_organization_detail.html"): user = request.user if user.is_superuser: if not user.is_active: @@ -139,9 +137,7 @@ def admin_organization_dashboard_detail( def weekly_report(request): domains = Domain.objects.all() - report_data = [ - "Hey This is a weekly report from OWASP BLT regarding the bugs reported for your organization!" - ] + report_data = ["Hey This is a weekly report from OWASP BLT regarding the bugs reported for your organization!"] try: for domain in domains: open_issues = domain.open_issues @@ -160,9 +156,7 @@ def weekly_report(request): description = issue.description views = issue.views label = issue.get_label_display() - report_data.append( - f"\n Description: {description} \n Views: {views} \n Labels: {label} \n" - ) + report_data.append(f"\n Description: {description} \n Views: {views} \n Labels: {label} \n") report_string = "".join(report_data) send_mail( @@ -181,15 +175,11 @@ def weekly_report(request): @login_required(login_url="/accounts/login") def organization_hunt_results(request, pk, template="organization_hunt_results.html"): hunt = get_object_or_404(Hunt, pk=pk) - issues = Issue.objects.filter(hunt=hunt).exclude( - Q(is_hidden=True) & ~Q(user_id=request.user.id) - ) + issues = Issue.objects.filter(hunt=hunt).exclude(Q(is_hidden=True) & ~Q(user_id=request.user.id)) context = {} if request.method == "GET": context["hunt"] = get_object_or_404(Hunt, pk=pk) - context["issues"] = Issue.objects.filter(hunt=hunt).exclude( - Q(is_hidden=True) & ~Q(user_id=request.user.id) - ) + context["issues"] = Issue.objects.filter(hunt=hunt).exclude(Q(is_hidden=True) & ~Q(user_id=request.user.id)) if hunt.result_published: context["winner"] = Winner.objects.get(hunt=hunt) return render(request, template, context) @@ -238,11 +228,7 @@ def organization_hunt_results(request, pk, template="organization_hunt_results.h if index == 4: break index = index + 1 - total_amount = ( - Decimal(hunt.prize_winner) - + Decimal(hunt.prize_runner) - + Decimal(hunt.prize_second_runner) - ) + total_amount = Decimal(hunt.prize_winner) + Decimal(hunt.prize_runner) + Decimal(hunt.prize_second_runner) from django.conf import settings stripe.api_key = settings.STRIPE_TEST_SECRET_KEY @@ -267,9 +253,7 @@ def organization_hunt_results(request, pk, template="organization_hunt_results.h hunt.save() context["winner"] = winner context["hunt"] = get_object_or_404(Hunt, pk=pk) - context["issues"] = Issue.objects.filter(hunt=hunt).exclude( - Q(is_hidden=True) & ~Q(user_id=request.user.id) - ) + context["issues"] = Issue.objects.filter(hunt=hunt).exclude(Q(is_hidden=True) & ~Q(user_id=request.user.id)) return render(request, template, context) @@ -595,13 +579,9 @@ def get(self, request, *args, **kwargs): domain_admins = [] domain_list = Domain.objects.filter(organization=domain_admin.organization) if domain_admin.role == 0: - domain_admins = OrganizationAdmin.objects.filter( - organization=domain_admin.organization, is_active=True - ) + domain_admins = OrganizationAdmin.objects.filter(organization=domain_admin.organization, is_active=True) else: - domain_admins = OrganizationAdmin.objects.filter( - domain=domain_admin.domain, is_active=True - ) + domain_admins = OrganizationAdmin.objects.filter(domain=domain_admin.domain, is_active=True) context = { "admins": domain_admins, "user": domain_admin, @@ -688,9 +668,7 @@ def get_context_data(self, *args, **kwargs): .order_by() ) for i in range(0, 7): - context["bug_type_" + str(i)] = Issue.objects.filter( - domain=context["domain"], hunt=None, label=str(i) - ) + context["bug_type_" + str(i)] = Issue.objects.filter(domain=context["domain"], hunt=None, label=str(i)) context["total_bugs"] = Issue.objects.filter(domain=context["domain"], hunt=None).count() context["pie_chart"] = ( Issue.objects.filter(domain=context["domain"], hunt=None) @@ -703,9 +681,7 @@ def get_context_data(self, *args, **kwargs): )[0:3] context["activity_screenshots"] = {} for activity in context["activities"]: - context["activity_screenshots"][activity] = IssueScreenshot.objects.filter( - issue=activity.pk - ).first() + context["activity_screenshots"][activity] = IssueScreenshot.objects.filter(issue=activity.pk).first() context["twitter_url"] = "https://twitter.com/%s" % domain.get_or_set_x_url(domain.get_name) return context @@ -812,10 +788,7 @@ def post(self, request, *args, **kwargs): domain_admin = OrganizationAdmin.objects.get(user=request.user) if ( domain_admin.role == 1 - and ( - str(domain_admin.domain.pk) - == ((request.POST["domain"]).split("-"))[0].replace(" ", "") - ) + and (str(domain_admin.domain.pk) == ((request.POST["domain"]).split("-"))[0].replace(" ", "")) ) or domain_admin.role == 0: wallet, created = Wallet.objects.get_or_create(user=request.user) total_amount = ( @@ -826,9 +799,7 @@ def post(self, request, *args, **kwargs): if total_amount > wallet.current_balance: return HttpResponse("failed") hunt = Hunt() - hunt.domain = Domain.objects.get( - pk=(request.POST["domain"]).split("-")[0].replace(" ", "") - ) + hunt.domain = Domain.objects.get(pk=(request.POST["domain"]).split("-")[0].replace(" ", "")) data = {} data["content"] = request.POST["content"] data["start_date"] = request.POST["start_date"] @@ -841,9 +812,7 @@ def post(self, request, *args, **kwargs): if domain_admin.role == 1: if hunt.domain != domain_admin.domain: return HttpResponse("failed") - hunt.domain = Domain.objects.get( - pk=(request.POST["domain"]).split("-")[0].replace(" ", "") - ) + hunt.domain = Domain.objects.get(pk=(request.POST["domain"]).split("-")[0].replace(" ", "")) tzsign = 1 offset = request.POST["tzoffset"] if int(offset) < 0: @@ -852,19 +821,11 @@ def post(self, request, *args, **kwargs): start_date = form.cleaned_data["start_date"] end_date = form.cleaned_data["end_date"] if tzsign > 0: - start_date = start_date + timedelta( - hours=int(int(offset) / 60), minutes=int(int(offset) % 60) - ) - end_date = end_date + timedelta( - hours=int(int(offset) / 60), minutes=int(int(offset) % 60) - ) + start_date = start_date + timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) + end_date = end_date + timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) else: - start_date = start_date - ( - timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) - ) - end_date = end_date - ( - timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) - ) + start_date = start_date - (timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60))) + end_date = end_date - (timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60))) hunt.starts_on = start_date hunt.prize_winner = Decimal(request.POST["prize_winner"]) hunt.prize_runner = Decimal(request.POST["prize_runner"]) @@ -903,9 +864,7 @@ def user_sizzle_report(request, username): total_duration = sum((log.duration for log in logs if log.duration), timedelta()) total_duration_seconds = total_duration.total_seconds() - formatted_duration = ( - f"{int(total_duration_seconds // 60)} min {int(total_duration_seconds % 60)} sec" - ) + formatted_duration = f"{int(total_duration_seconds // 60)} min {int(total_duration_seconds % 60)} sec" issue_title = get_github_issue_title(first_log.github_issue_url) @@ -923,9 +882,7 @@ def user_sizzle_report(request, username): response_data.append(day_data) - return render( - request, "sizzle/user_sizzle_report.html", {"response_data": response_data, "user": user} - ) + return render(request, "sizzle/user_sizzle_report.html", {"response_data": response_data, "user": user}) @login_required @@ -954,9 +911,7 @@ def sizzle_daily_log(request): ) messages.success(request, "Daily status report submitted successfully.") - return JsonResponse( - {"success": "true", "message": "Daily status report submitted successfully."} - ) + return JsonResponse({"success": "true", "message": "Daily status report submitted successfully."}) except Exception as e: messages.error(request, f"An error occurred: {e}") @@ -1009,9 +964,7 @@ def TimeLogListAPIView(request): if not start_date or not end_date: return JsonResponse({"error": "Invalid date format."}, status=status.HTTP_400_BAD_REQUEST) - time_logs = TimeLog.objects.filter( - user=request.user, created__range=[start_date, end_date] - ).order_by("created") + time_logs = TimeLog.objects.filter(user=request.user, created__range=[start_date, end_date]).order_by("created") grouped_logs = defaultdict(list) for log in time_logs: @@ -1024,9 +977,7 @@ def TimeLogListAPIView(request): total_duration = sum((log.duration for log in logs if log.duration), timedelta()) total_duration_seconds = total_duration.total_seconds() - formatted_duration = ( - f"{int(total_duration_seconds // 60)} min {int(total_duration_seconds % 60)} sec" - ) + formatted_duration = f"{int(total_duration_seconds // 60)} min {int(total_duration_seconds % 60)} sec" issue_title = get_github_issue_title(first_log.github_issue_url) @@ -1053,9 +1004,7 @@ def sizzle_docs(request): def sizzle(request): # Aggregate leaderboard data: username and total_duration leaderboard_qs = ( - TimeLog.objects.values("user__username") - .annotate(total_duration=Sum("duration")) - .order_by("-total_duration") + TimeLog.objects.values("user__username").annotate(total_duration=Sum("duration")).order_by("-total_duration") ) # Process leaderboard to include formatted_duration @@ -1078,14 +1027,12 @@ def sizzle(request): last_data = TimeLog.objects.filter(user=request.user).order_by("-created").first() if last_data: - all_data = TimeLog.objects.filter( - user=request.user, created__date=last_data.created.date() - ).order_by("created") - - total_duration = sum( - (entry.duration for entry in all_data if entry.duration), timedelta() + all_data = TimeLog.objects.filter(user=request.user, created__date=last_data.created.date()).order_by( + "created" ) + total_duration = sum((entry.duration for entry in all_data if entry.duration), timedelta()) + formatted_duration = format_timedelta(total_duration) github_issue_url = all_data.first().github_issue_url @@ -1102,18 +1049,14 @@ def sizzle(request): "date": date, } - return render( - request, "sizzle/sizzle.html", {"sizzle_data": sizzle_data, "leaderboard": leaderboard} - ) + return render(request, "sizzle/sizzle.html", {"sizzle_data": sizzle_data, "leaderboard": leaderboard}) def trademark_detailview(request, slug): if settings.USPTO_API is None: return HttpResponse("API KEY NOT SETUP") - trademark_available_url = "https://uspto-trademark.p.rapidapi.com/v1/trademarkAvailable/%s" % ( - slug - ) + trademark_available_url = "https://uspto-trademark.p.rapidapi.com/v1/trademarkAvailable/%s" % (slug) headers = { "x-rapidapi-host": "uspto-trademark.p.rapidapi.com", "x-rapidapi-key": settings.USPTO_API, @@ -1122,9 +1065,7 @@ def trademark_detailview(request, slug): ta_data = trademark_available_response.json() if ta_data[0]["available"] == "no": - trademark_search_url = ( - "https://uspto-trademark.p.rapidapi.com/v1/trademarkSearch/%s/active" % (slug) - ) + trademark_search_url = "https://uspto-trademark.p.rapidapi.com/v1/trademarkSearch/%s/active" % (slug) trademark_search_response = requests.get(trademark_search_url, headers=headers) ts_data = trademark_search_response.json() context = {"count": ts_data["count"], "items": ts_data["items"], "query": slug} @@ -1210,19 +1151,11 @@ def organization_dashboard_hunt_edit(request, pk, template="organization_dashboa start_date = form.cleaned_data["start_date"] end_date = form.cleaned_data["end_date"] if tzsign > 0: - start_date = start_date + timedelta( - hours=int(int(offset) / 60), minutes=int(int(offset) % 60) - ) - end_date = end_date + timedelta( - hours=int(int(offset) / 60), minutes=int(int(offset) % 60) - ) + start_date = start_date + timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) + end_date = end_date + timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) else: - start_date = start_date - ( - timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) - ) - end_date = end_date - ( - timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60)) - ) + start_date = start_date - (timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60))) + end_date = end_date - (timedelta(hours=int(int(offset) / 60), minutes=int(int(offset) % 60))) hunt.starts_on = start_date hunt.end_on = end_date @@ -1238,9 +1171,7 @@ def organization_dashboard_hunt_edit(request, pk, template="organization_dashboa @login_required(login_url="/accounts/login") -def organization_dashboard_hunt_detail( - request, pk, template="organization_dashboard_hunt_detail.html" -): +def organization_dashboard_hunt_detail(request, pk, template="organization_dashboard_hunt_detail.html"): hunt = get_object_or_404(Hunt, pk=pk) return render(request, template, {"hunt": hunt}) @@ -1252,9 +1183,7 @@ def hunt_results(request, pk, template="hunt_results.html"): @login_required(login_url="/accounts/login") -def organization_dashboard_domain_detail( - request, pk, template="organization_dashboard_domain_detail.html" -): +def organization_dashboard_domain_detail(request, pk, template="organization_dashboard_domain_detail.html"): user = request.user domain_admin = OrganizationAdmin.objects.get(user=request.user) try: @@ -1347,9 +1276,7 @@ def add_or_update_organization(request): except: organization.is_active = False try: - organization.subscription = Subscription.objects.get( - name=request.POST["subscription"] - ) + organization.subscription = Subscription.objects.get(name=request.POST["subscription"]) except: pass try: @@ -1472,9 +1399,7 @@ def get_scoreboard(request): domain = paginator.page(1) except EmptyPage: domain = paginator.page(paginator.num_pages) - return HttpResponse( - json.dumps(domain.object_list, default=str), content_type="application/json" - ) + return HttpResponse(json.dumps(domain.object_list, default=str), content_type="application/json") @require_POST @@ -1561,9 +1486,7 @@ def form_valid(self, form): reporter_ip = get_client_ip(self.request) limit = 50 if self.request.user.is_authenticated else 30 today = now().date() - recent_reports_count = IpReport.objects.filter( - reporter_ip_address=reporter_ip, created=today - ).count() + recent_reports_count = IpReport.objects.filter(reporter_ip_address=reporter_ip, created=today).count() if recent_reports_count >= limit: messages.error(self.request, "You have reached the daily limit for IP reports.") @@ -1712,10 +1635,7 @@ def approve_activity(request, id): user = request.user # Check if the user has the "Mentor" badge - if ( - UserBadge.objects.filter(user=user, badge__title="Mentor").exists() - and not activity.is_approved - ): + if UserBadge.objects.filter(user=user, badge__title="Mentor").exists() and not activity.is_approved: activity.is_approved = True activity.save() diff --git a/website/views/project.py b/website/views/project.py index 3477afda7..22211cd8b 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -33,16 +33,7 @@ from rest_framework.views import APIView from website.bitcoin_utils import create_bacon_token -from website.models import ( - IP, - BaconToken, - Contribution, - Contributor, - ContributorStats, - Organization, - Project, - Repo, -) +from website.models import IP, BaconToken, Contribution, Contributor, ContributorStats, Organization, Project, Repo from website.utils import admin_required # logging.getLogger("matplotlib").setLevel(logging.ERROR) @@ -79,10 +70,7 @@ def select_contribution(request): @user_passes_test(admin_required) def distribute_bacon(request, contribution_id): contribution = Contribution.objects.get(id=contribution_id) - if ( - contribution.status == "closed" - and not BaconToken.objects.filter(contribution=contribution).exists() - ): + if contribution.status == "closed" and not BaconToken.objects.filter(contribution=contribution).exists(): token = create_bacon_token(contribution.user, contribution) if token: messages.success(request, "Bacon distributed successfully") @@ -124,9 +112,7 @@ def get(self, request, slug): user_ip = self.get_client_ip(request) # Continue with existing code but use the new user_ip - visited_data = IP.objects.filter( - address=user_ip, path=request.path, created__date=today - ).last() + visited_data = IP.objects.filter(address=user_ip, path=request.path, created__date=today).last() if visited_data: # If the creation date is today @@ -483,9 +469,7 @@ def validate_url(url): org = Organization.objects.get(id=org_id) if not (request.user == org.admin): return JsonResponse( - { - "error": "You do not have permission to add projects to this organization" - }, + {"error": "You do not have permission to add projects to this organization"}, status=403, ) project_data["organization"] = org @@ -626,9 +610,7 @@ def get_issue_count(full_name, query): contributor_count=len(all_contributors), commit_count=commit_count, release_name=release_name, - release_datetime=( - parse_datetime(release_datetime) if release_datetime else None - ), + release_datetime=(parse_datetime(release_datetime) if release_datetime else None), open_pull_requests=open_pull_requests, ) @@ -638,9 +620,7 @@ def get_issue_count(full_name, query): return JsonResponse({"message": "Project created successfully"}, status=201) except Organization.DoesNotExist: - return JsonResponse( - {"error": "Organization not found", "code": "ORG_NOT_FOUND"}, status=404 - ) + return JsonResponse({"error": "Organization not found", "code": "ORG_NOT_FOUND"}, status=404) except PermissionError: return JsonResponse( { @@ -662,9 +642,7 @@ def get_context_data(self, **kwargs): # Get all repositories associated with the project repositories = ( - Repo.objects.select_related("project") - .filter(project=project) - .prefetch_related("tags", "contributor") + Repo.objects.select_related("project").filter(project=project).prefetch_related("tags", "contributor") ) # Calculate aggregate metrics @@ -748,9 +726,7 @@ def get_context_data(self, **kwargs): # Get other repos from same project context["related_repos"] = ( - Repo.objects.filter(project=repo.project) - .exclude(id=repo.id) - .select_related("project")[:5] + Repo.objects.filter(project=repo.project).exclude(id=repo.id).select_related("project")[:5] ) # Get top contributors from GitHub @@ -759,9 +735,7 @@ def get_context_data(self, **kwargs): if github_contributors: # Match by github_id instead of username github_ids = [str(c["id"]) for c in github_contributors] - verified_contributors = repo.contributor.filter( - github_id__in=github_ids - ).select_related() + verified_contributors = repo.contributor.filter(github_id__in=github_ids).select_related() # Create a mapping of github_id to database contributor contributor_map = {str(c.github_id): c for c in verified_contributors} @@ -841,23 +815,17 @@ def get_context_data(self, **kwargs): "Authorization": f"token {settings.GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json", } - response = requests.get( - f"https://api.github.com/repos/{owner}/{repo_name}", headers=headers - ) + response = requests.get(f"https://api.github.com/repos/{owner}/{repo_name}", headers=headers) if response.status_code == 200: repo_data = response.json() - start_date = datetime.strptime( - repo_data["created_at"], "%Y-%m-%dT%H:%M:%SZ" - ).date() + start_date = datetime.strptime(repo_data["created_at"], "%Y-%m-%dT%H:%M:%SZ").date() else: start_date = end_date - relativedelta(years=1) # Fallback to 1 year except Exception: start_date = end_date - relativedelta(years=1) # Fallback to 1 year # Query contributor stats - stats_query = ContributorStats.objects.filter( - repo=repo, date__gte=start_date, date__lte=end_date - ) + stats_query = ContributorStats.objects.filter(repo=repo, date__gte=start_date, date__lte=end_date) # Aggregate the stats stats_query = ( @@ -968,16 +936,12 @@ def get_issue_count(full_name, query, headers): # Get GitHub API token github_token = getattr(settings, "GITHUB_TOKEN", None) if not github_token: - return JsonResponse( - {"status": "error", "message": "GitHub token not configured"}, status=500 - ) + return JsonResponse({"status": "error", "message": "GitHub token not configured"}, status=500) # Extract owner/repo from GitHub URL match = re.match(r"https://github.com/([^/]+)/([^/]+)/?", repo.repo_url) if not match: - return JsonResponse( - {"status": "error", "message": "Invalid repository URL"}, status=400 - ) + return JsonResponse({"status": "error", "message": "Invalid repository URL"}, status=400) owner, repo_name = match.groups() api_url = f"https://api.github.com/repos/{owner}/{repo_name}" @@ -1050,15 +1014,11 @@ def get_issue_count(full_name, query, headers): try: github_token = getattr(settings, "GITHUB_TOKEN", None) if not github_token: - return JsonResponse( - {"status": "error", "message": "GitHub token not configured"}, status=500 - ) + return JsonResponse({"status": "error", "message": "GitHub token not configured"}, status=500) match = re.match(r"https://github.com/([^/]+)/([^/]+)/?", repo.repo_url) if not match: - return JsonResponse( - {"status": "error", "message": "Invalid repository URL"}, status=400 - ) + return JsonResponse({"status": "error", "message": "Invalid repository URL"}, status=400) # Extract owner and repo from API call owner, repo_name = match.groups() @@ -1177,15 +1137,11 @@ def get_issue_count(full_name, query, headers): try: github_token = getattr(settings, "GITHUB_TOKEN", None) if not github_token: - return JsonResponse( - {"status": "error", "message": "GitHub token not configured"}, status=500 - ) + return JsonResponse({"status": "error", "message": "GitHub token not configured"}, status=500) match = re.match(r"https://github.com/([^/]+)/([^/]+)/?", repo.repo_url) if not match: - return JsonResponse( - {"status": "error", "message": "Invalid repository URL"}, status=400 - ) + return JsonResponse({"status": "error", "message": "Invalid repository URL"}, status=400) owner, repo_name = match.groups() api_url = f"https://api.github.com/repos/{owner}/{repo_name}" @@ -1246,9 +1202,7 @@ def get_issue_count(full_name, query, headers): status=503, ) except Exception as e: - return JsonResponse( - {"status": "error", "message": "An unexpected error occurred."}, status=500 - ) + return JsonResponse({"status": "error", "message": "An unexpected error occurred."}, status=500) elif section == "community": try: @@ -1350,9 +1304,7 @@ def get(self, request, slug): user_ip = self.get_client_ip(request) # Continue with existing code but use the new user_ip - visited_data = IP.objects.filter( - address=user_ip, path=request.path, created__date=today - ).last() + visited_data = IP.objects.filter(address=user_ip, path=request.path, created__date=today).last() if visited_data: # If the creation date is today diff --git a/website/views/slackbot.py b/website/views/slackbot.py index 5ab7d502e..ea52dc124 100644 --- a/website/views/slackbot.py +++ b/website/views/slackbot.py @@ -91,11 +91,7 @@ def handle_discover_command(ack, client, command): lang = (repo["language"] or "").lower() topics = [t.lower() for t in repo.get("topics", [])] - if ( - search_term.lower() in name_desc - or search_term.lower() in lang - or search_term.lower() in topics - ): + if search_term.lower() in name_desc or search_term.lower() in lang or search_term.lower() in topics: desc = repo["description"] or "No description provided." found_urls = url_pattern.findall(desc) @@ -145,28 +141,19 @@ def handle_discover_command(ack, client, command): if gh_response.status_code == 200: repos = gh_response.json() if not repos: - send_dm( - client, command["user_id"], "No repositories found for OWASP-BLT." - ) + send_dm(client, command["user_id"], "No repositories found for OWASP-BLT.") else: repo_list = [] for idx, repo in enumerate(repos, start=1): - desc = ( - repo["description"] - if repo["description"] - else "No description provided." - ) - repo_list.append( - f"{idx}. <{repo['html_url']}|{repo['name']}> - {desc}" - ) + desc = repo["description"] if repo["description"] else "No description provided." + repo_list.append(f"{idx}. <{repo['html_url']}|{repo['name']}> - {desc}") blocks = [ { "type": "section", "text": { "type": "mrkdwn", - "text": "Here are the OWASP BLT project repositories:\n" - + "\n".join(repo_list), + "text": "Here are the OWASP BLT project repositories:\n" + "\n".join(repo_list), }, }, { @@ -236,8 +223,7 @@ def handle_repository_selection(ack, body, client): send_dm(client, user_id, "No issues found for this repository.") else: issues_list = [ - f"- <{issue['html_url']}|{issue['title']}> (#{issue['number']})" - for issue in issues[:5] + f"- <{issue['html_url']}|{issue['title']}> (#{issue['number']})" for issue in issues[:5] ] issues_text = "Here are the latest issues:\n" + "\n".join(issues_list) send_dm(client, user_id, issues_text) diff --git a/website/views/teams.py b/website/views/teams.py index 1f16f8257..66e927742 100644 --- a/website/views/teams.py +++ b/website/views/teams.py @@ -29,13 +29,8 @@ def get_context_data(self, **kwargs): def search_users(request): query = request.GET.get("query", "") if query: - users = User.objects.filter(username__icontains=query).values( - "username", "userprofile__team__name" - ) - users_list = [ - {"username": user["username"], "team": user["userprofile__team__name"]} - for user in users - ] + users = User.objects.filter(username__icontains=query).values("username", "userprofile__team__name") + users_list = [{"username": user["username"], "team": user["userprofile__team__name"]} for user in users] return JsonResponse(users_list, safe=False) return JsonResponse([], safe=False) @@ -61,9 +56,7 @@ def create_team(request): counter += 1 # Create the team - team = Organization.objects.create( - name=team_name, type="team", admin=request.user, url=team_url - ) + team = Organization.objects.create(name=team_name, type="team", admin=request.user, url=team_url) if team_avatar: team.logo = team_avatar team.save() # Save the logo if provided @@ -85,9 +78,7 @@ def create_team(request): return redirect("team_overview") except IntegrityError: - messages.error( - request, "A team with this name or URL already exists. Please choose another name." - ) + messages.error(request, "A team with this name or URL already exists. Please choose another name.") except Exception as e: messages.error(request, f"An error occurred: {str(e)}") @@ -192,9 +183,7 @@ def kick_member(request): # Check if the requester is the team admin if team.admin != request.user: - return JsonResponse( - {"success": False, "error": "Only the team admin can kick members"} - ) + return JsonResponse({"success": False, "error": "Only the team admin can kick members"}) # Check if the user is a manager in the team if not team.managers.filter(username=username).exists(): @@ -208,9 +197,7 @@ def kick_member(request): user_profile.team = None user_profile.save() - return JsonResponse( - {"success": True, "message": f"User {username} has been kicked out of the team."} - ) + return JsonResponse({"success": True, "message": f"User {username} has been kicked out of the team."}) except User.DoesNotExist: return JsonResponse({"success": False, "error": "User does not exist"}) diff --git a/website/views/user.py b/website/views/user.py index 1ed592044..2e5d9c6ee 100644 --- a/website/views/user.py +++ b/website/views/user.py @@ -17,13 +17,7 @@ from django.db.models import Count, F, Q, Sum from django.db.models.functions import ExtractMonth from django.dispatch import receiver -from django.http import ( - Http404, - HttpResponse, - HttpResponseNotFound, - HttpResponseRedirect, - JsonResponse, -) +from django.http import Http404, HttpResponse, HttpResponseNotFound, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.template.loader import render_to_string from django.urls import reverse @@ -238,18 +232,14 @@ def get_context_data(self, **kwargs): context["user_points"] = user_points context["my_score"] = list(user_points.aggregate(total_score=Sum("score")).values())[0] context["websites"] = ( - Domain.objects.filter(issue__user=self.object) - .annotate(total=Count("issue")) - .order_by("-total") + Domain.objects.filter(issue__user=self.object).annotate(total=Count("issue")).order_by("-total") ) context["activities"] = Issue.objects.filter(user=self.object, hunt=None).exclude( Q(is_hidden=True) & ~Q(user_id=self.request.user.id) )[0:3] context["activity_screenshots"] = {} for activity in context["activities"]: - context["activity_screenshots"][activity] = IssueScreenshot.objects.filter( - issue=activity.pk - ).first() + context["activity_screenshots"][activity] = IssueScreenshot.objects.filter(issue=activity.pk).first() context["profile_form"] = UserProfileForm() context["total_open"] = Issue.objects.filter(user=self.object, status="open").count() context["total_closed"] = Issue.objects.filter(user=self.object, status="closed").count() @@ -269,9 +259,7 @@ def get_context_data(self, **kwargs): ) context["total_bugs"] = Issue.objects.filter(user=self.object, hunt=None).count() for i in range(0, 7): - context["bug_type_" + str(i)] = Issue.objects.filter( - user=self.object, hunt=None, label=str(i) - ) + context["bug_type_" + str(i)] = Issue.objects.filter(user=self.object, hunt=None, label=str(i)) arr = [] allFollowers = user.userprofile.follower.all() @@ -285,14 +273,10 @@ def get_context_data(self, **kwargs): arr.append(User.objects.get(username=str(userprofile.user))) context["following"] = arr - context["followers_list"] = [ - str(prof.user.email) for prof in user.userprofile.follower.all() - ] + context["followers_list"] = [str(prof.user.email) for prof in user.userprofile.follower.all()] context["bookmarks"] = user.userprofile.issue_saved.all() # tags - context["user_related_tags"] = ( - UserProfile.objects.filter(user=self.object).first().tags.all() - ) + context["user_related_tags"] = UserProfile.objects.filter(user=self.object).first().tags.all() context["issues_hidden"] = "checked" if user.userprofile.issues_hidden else "!checked" return context @@ -333,9 +317,7 @@ def get_context_data(self, **kwargs): Points.objects.filter(user=self.object).aggregate(total_score=Sum("score")).values() )[0] context["websites"] = ( - Domain.objects.filter(issue__user=self.object) - .annotate(total=Count("issue")) - .order_by("-total") + Domain.objects.filter(issue__user=self.object).annotate(total=Count("issue")).order_by("-total") ) if self.request.user.is_authenticated: context["wallet"] = Wallet.objects.get(user=self.request.user) @@ -360,9 +342,9 @@ def get_context_data(self, **kwargs): ) context["total_bugs"] = Issue.objects.filter(user=self.object).count() for i in range(0, 7): - context["bug_type_" + str(i)] = Issue.objects.filter( - user=self.object, hunt=None, label=str(i) - ).exclude(Q(is_hidden=True) & ~Q(user_id=self.request.user.id)) + context["bug_type_" + str(i)] = Issue.objects.filter(user=self.object, hunt=None, label=str(i)).exclude( + Q(is_hidden=True) & ~Q(user_id=self.request.user.id) + ) arr = [] allFollowers = user.userprofile.follower.all() @@ -376,9 +358,7 @@ def get_context_data(self, **kwargs): arr.append(User.objects.get(username=str(userprofile.user))) context["following"] = arr - context["followers_list"] = [ - str(prof.user.email) for prof in user.userprofile.follower.all() - ] + context["followers_list"] = [str(prof.user.email) for prof in user.userprofile.follower.all()] context["bookmarks"] = user.userprofile.issue_saved.all() return context @@ -416,9 +396,7 @@ def current_month_leaderboard(self, api=False): """ leaderboard which includes current month users scores """ - return self.get_leaderboard( - month=int(datetime.now().month), year=int(datetime.now().year), api=api - ) + return self.get_leaderboard(month=int(datetime.now().month), year=int(datetime.now().year), api=api) def monthly_year_leaderboard(self, year, api=False): """ @@ -704,9 +682,7 @@ def withdraw(request): wallet.save() payment.active = False payment.save() - return HttpResponseRedirect( - "/dashboard/user/profile/" + request.user.username - ) + return HttpResponseRedirect("/dashboard/user/profile/" + request.user.username) else: return HttpResponse("INSUFFICIENT BALANCE") else: @@ -769,9 +745,7 @@ def create_tokens(request): def get_score(request): users = [] temp_users = ( - User.objects.annotate(total_score=Sum("points__score")) - .order_by("-total_score") - .filter(total_score__gt=0) + User.objects.annotate(total_score=Sum("points__score")).order_by("-total_score").filter(total_score__gt=0) ) rank_user = 1 for each in temp_users.all(): @@ -801,12 +775,8 @@ def follow_user(request, user): flag = 1 if flag != 1: request.user.userprofile.follows.add(userx.userprofile) - msg_plain = render_to_string( - "email/follow_user.txt", {"follower": request.user, "followed": userx} - ) - msg_html = render_to_string( - "email/follow_user.txt", {"follower": request.user, "followed": userx} - ) + msg_plain = render_to_string("email/follow_user.txt", {"follower": request.user, "followed": userx}) + msg_html = render_to_string("email/follow_user.txt", {"follower": request.user, "followed": userx}) send_mail( "You got a new follower!!", @@ -940,9 +910,7 @@ def github_webhook(request): def handle_pull_request_event(payload): if payload["action"] == "closed" and payload["pull_request"]["merged"]: - pr_user_profile = UserProfile.objects.filter( - github_url=payload["pull_request"]["user"]["html_url"] - ).first() + pr_user_profile = UserProfile.objects.filter(github_url=payload["pull_request"]["user"]["html_url"]).first() if pr_user_profile: pr_user_instance = pr_user_profile.user assign_github_badge(pr_user_instance, "First PR Merged") @@ -969,9 +937,7 @@ def handle_review_event(payload): def handle_issue_event(payload): print("issue closed") if payload["action"] == "closed": - closer_profile = UserProfile.objects.filter( - github_url=payload["sender"]["html_url"] - ).first() + closer_profile = UserProfile.objects.filter(github_url=payload["sender"]["html_url"]).first() if closer_profile: closer_user = closer_profile.user assign_github_badge(closer_user, "First Issue Closed") From ea48d99e62de39d43aa3937cbcc3303ed64cfe50 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Fri, 24 Jan 2025 23:46:06 +0530 Subject: [PATCH 15/20] resolved tests --- website/admin.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/website/admin.py b/website/admin.py index 15d59944f..544f0963a 100644 --- a/website/admin.py +++ b/website/admin.py @@ -121,11 +121,6 @@ class ImageInline(admin.TabularInline): extra = 1 -class SlackChannelAdmin(admin.ModelAdmin): - list_display = ("slack_channel", "slack_id", "slack_url") - search_fields = ("slack_channel", "slack_id") - - class IssueAdmin(admin.ModelAdmin): list_display = ( "id", @@ -499,4 +494,3 @@ class PostAdmin(admin.ModelAdmin): admin.site.register(Activity) admin.site.register(PRAnalysisReport) admin.site.register(Post, PostAdmin) -admin.site.register(SlackChannel, SlackChannelAdmin) From aae41df172700b1426caf043af56df3db2537b5a Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Sat, 25 Jan 2025 00:38:09 +0530 Subject: [PATCH 16/20] removed myenv --- myenv/bin/python | 1 - myenv/bin/python3 | 1 - myenv/bin/python3.12 | 1 - myenv/lib64 | 1 - myenv/pyvenv.cfg | 5 ----- 5 files changed, 9 deletions(-) delete mode 120000 myenv/bin/python delete mode 120000 myenv/bin/python3 delete mode 120000 myenv/bin/python3.12 delete mode 120000 myenv/lib64 delete mode 100644 myenv/pyvenv.cfg diff --git a/myenv/bin/python b/myenv/bin/python deleted file mode 120000 index b8a0adbbb..000000000 --- a/myenv/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/myenv/bin/python3 b/myenv/bin/python3 deleted file mode 120000 index ae65fdaa1..000000000 --- a/myenv/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/python3 \ No newline at end of file diff --git a/myenv/bin/python3.12 b/myenv/bin/python3.12 deleted file mode 120000 index b8a0adbbb..000000000 --- a/myenv/bin/python3.12 +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/myenv/lib64 b/myenv/lib64 deleted file mode 120000 index 7951405f8..000000000 --- a/myenv/lib64 +++ /dev/null @@ -1 +0,0 @@ -lib \ No newline at end of file diff --git a/myenv/pyvenv.cfg b/myenv/pyvenv.cfg deleted file mode 100644 index 7d51fe610..000000000 --- a/myenv/pyvenv.cfg +++ /dev/null @@ -1,5 +0,0 @@ -home = /usr/bin -include-system-site-packages = false -version = 3.12.3 -executable = /usr/bin/python3.12 -command = /usr/bin/python3 -m venv /home/dhruv-sharma/Desktop/OWASP_BLT/BLT/myenv From 31bf5aee3c256766f7da567771ff2fc8ea85fede Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Fri, 31 Jan 2025 03:54:23 +0530 Subject: [PATCH 17/20] Resolving --- website/migrations/0180_project_slack.py | 17 ---------- .../migrations/0181_alter_project_slack.py | 17 ---------- ..._project_slack_channel_project_slack_id.py | 32 +++++++++++++++++++ .../migrations/0182_merge_20250116_0944.py | 12 ------- website/migrations/0183_slackchannel.py | 29 ----------------- 5 files changed, 32 insertions(+), 75 deletions(-) delete mode 100644 website/migrations/0180_project_slack.py delete mode 100644 website/migrations/0181_alter_project_slack.py create mode 100644 website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py delete mode 100644 website/migrations/0182_merge_20250116_0944.py delete mode 100644 website/migrations/0183_slackchannel.py diff --git a/website/migrations/0180_project_slack.py b/website/migrations/0180_project_slack.py deleted file mode 100644 index f83c2eb12..000000000 --- a/website/migrations/0180_project_slack.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.1.4 on 2025-01-12 08:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0179_contributorstats"), - ] - - operations = [ - migrations.AddField( - model_name="project", - name="slack", - field=models.CharField(blank=True, max_length=30, null=True), - ), - ] diff --git a/website/migrations/0181_alter_project_slack.py b/website/migrations/0181_alter_project_slack.py deleted file mode 100644 index 25f41f1b3..000000000 --- a/website/migrations/0181_alter_project_slack.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.1.4 on 2025-01-15 15:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0180_project_slack"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="slack", - field=models.URLField(blank=True, null=True), - ), - ] diff --git a/website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py b/website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py new file mode 100644 index 000000000..05cbab625 --- /dev/null +++ b/website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py @@ -0,0 +1,32 @@ +# Generated by Django 5.1.4 on 2025-01-30 22:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + replaces = [ + ("website", "0181_alter_project_slack"), + ("website", "0184_project_slack_channel_project_slack_id"), + ] + + dependencies = [ + ("website", "0179_contributorstats"), + ] + + operations = [ + migrations.AlterField( + model_name="project", + name="slack", + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name="project", + name="slack_channel", + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name="project", + name="slack_id", + field=models.CharField(blank=True, max_length=255, null=True, unique=True), + ), + ] diff --git a/website/migrations/0182_merge_20250116_0944.py b/website/migrations/0182_merge_20250116_0944.py deleted file mode 100644 index e8109bb1e..000000000 --- a/website/migrations/0182_merge_20250116_0944.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 5.1.4 on 2025-01-16 09:44 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0180_rename_project_visit_count_repo_repo_visit_count"), - ("website", "0181_alter_project_slack"), - ] - - operations = [] diff --git a/website/migrations/0183_slackchannel.py b/website/migrations/0183_slackchannel.py deleted file mode 100644 index bd7deaa2d..000000000 --- a/website/migrations/0183_slackchannel.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 5.1.4 on 2025-01-19 17:57 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0182_merge_20250116_0944"), - ] - - operations = [ - migrations.CreateModel( - name="SlackChannel", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("slack_channel", models.CharField(max_length=255)), - ("slack_id", models.CharField(max_length=255, unique=True)), - ("slack_url", models.URLField()), - ], - ), - ] From 1bad1c3e4e77c8b56ce4f580740bf1d2354b1dcd Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Fri, 31 Jan 2025 04:21:27 +0530 Subject: [PATCH 18/20] Resolving --- website/migrations/0187_merge_20250130_2249.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 website/migrations/0187_merge_20250130_2249.py diff --git a/website/migrations/0187_merge_20250130_2249.py b/website/migrations/0187_merge_20250130_2249.py new file mode 100644 index 000000000..926af2b00 --- /dev/null +++ b/website/migrations/0187_merge_20250130_2249.py @@ -0,0 +1,15 @@ +# Generated by Django 5.1.4 on 2025-01-30 22:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ( + "website", + "0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id", + ), + ("website", "0186_userprofile_contribution_rank_and_more"), + ] + + operations = [] From e29f8ea1ae7b5c23798d78f3aed1945d334f1cc8 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Sat, 1 Feb 2025 16:20:13 +0530 Subject: [PATCH 19/20] Remove Slack link from repository detail template --- website/templates/projects/repo_detail.html | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/website/templates/projects/repo_detail.html b/website/templates/projects/repo_detail.html index f5112de19..95ef68032 100644 --- a/website/templates/projects/repo_detail.html +++ b/website/templates/projects/repo_detail.html @@ -62,19 +62,6 @@

{{ repo.name }}

Visit Homepage
{% endif %} - {% if repo.slack %} - - - - - Join on Slack - - {% endif %} From ccc13404b2c88df5706ae56a4a9f6ca97a670741 Mon Sep 17 00:00:00 2001 From: Dhruv-Sharma01 <121188299+Dhruv-Sharma01@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:09:43 +0530 Subject: [PATCH 20/20] Rename 0187_merge_20250130_2249.py to 0189_merge_20250130_2249.py --- .../{0187_merge_20250130_2249.py => 0189_merge_20250130_2249.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/migrations/{0187_merge_20250130_2249.py => 0189_merge_20250130_2249.py} (100%) diff --git a/website/migrations/0187_merge_20250130_2249.py b/website/migrations/0189_merge_20250130_2249.py similarity index 100% rename from website/migrations/0187_merge_20250130_2249.py rename to website/migrations/0189_merge_20250130_2249.py