Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slack Work #3232

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions project_channels.csv
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions website/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions website/templates/projects/project_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
{% endblock title %}
{% block content %}
{% include "includes/sidenav.html" %}
<h1> This is where you edited</h1>
Dhruv-Sharma01 marked this conversation as resolved.
Show resolved Hide resolved
<div class="container mx-auto px-4 py-8 max-w-7xl">
<!-- Breadcrumb Navigation -->
<nav class="mb-8 text-sm">
Expand Down Expand Up @@ -125,6 +126,17 @@ <h1 class="text-3xl font-bold text-white mb-2">{{ project.name }}</h1>
Facebook
</a>
{% endif %}
{% if project.slack %}
<a href="{{ project.slack }}"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white transition">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" />
</svg>
Slack
</a>
{% endif %}
</div>
</div>
</div>
Expand Down
200 changes: 200 additions & 0 deletions website/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -135,6 +136,205 @@ 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()
Expand Down