Skip to content

Commit 9c2556c

Browse files
committed
Merge remote-tracking branch 'upstream/main' into context-model
2 parents 466bca3 + 0c4bf1e commit 9c2556c

File tree

26 files changed

+1129
-512
lines changed

26 files changed

+1129
-512
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ __pycache__
1616
.python_history
1717
.python-version
1818
.ruff_cache
19+
.venv/
1920
.vscode
20-
venv/
2121
*.code-workspace
2222
*.key
2323
*.log
2424
*.pdf
2525
*.pem
26-
backend/.venv
2726
backend/data/backup*
2827
backend/staticfiles
2928
frontend/blob-report/
@@ -39,3 +38,4 @@ frontend/yarn-error.log*
3938
logs
4039
node_modules/
4140
TODO
41+
venv/

backend/apps/github/Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ github-enrich-issues:
66
@echo "Enriching GitHub issues"
77
@CMD="python manage.py github_enrich_issues" $(MAKE) exec-backend-command
88

9-
github-match-users:
10-
@CMD="python manage.py github_match_users $(MATCH_MODEL)" $(MAKE) exec-backend-command
11-
129
github-update-owasp-organization:
1310
@echo "Updating OWASP GitHub organization"
1411
@CMD="python manage.py github_update_owasp_organization" $(MAKE) exec-backend-command

backend/apps/github/management/commands/github_match_users.py

Lines changed: 0 additions & 131 deletions
This file was deleted.

backend/apps/nest/admin/user.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
class UserAdmin(admin.ModelAdmin):
99
"""Admin for User model."""
1010

11+
autocomplete_fields = ("github_user",)
1112
ordering = ("username",)
1213
search_fields = ("email", "username")
1314

backend/apps/owasp/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ owasp-process-snapshots:
2626
@echo "Processing OWASP snapshots"
2727
@CMD="python manage.py owasp_process_snapshots" $(MAKE) exec-backend-command
2828

29+
owasp-update-leaders:
30+
@CMD="python manage.py owasp_update_leaders $(MATCH_MODEL)" $(MAKE) exec-backend-command
31+
2932
owasp-update-project-health-metrics:
3033
@echo "Updating OWASP project health metrics"
3134
@CMD="python manage.py owasp_update_project_health_metrics" $(MAKE) exec-backend-command

backend/apps/owasp/admin/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from .chapter import ChapterAdmin
88
from .committee import CommitteeAdmin
9+
from .entity_member import EntityMemberAdmin
910
from .event import EventAdmin
1011
from .post import PostAdmin
1112
from .project import ProjectAdmin

backend/apps/owasp/admin/chapter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
from apps.owasp.models.chapter import Chapter
66

7-
from .mixins import GenericEntityAdminMixin, LeaderAdminMixin
7+
from .mixins import EntityMemberInline, GenericEntityAdminMixin
88

99

10-
class ChapterAdmin(admin.ModelAdmin, GenericEntityAdminMixin, LeaderAdminMixin):
10+
class ChapterAdmin(admin.ModelAdmin, GenericEntityAdminMixin):
1111
"""Admin for Chapter model."""
1212

1313
autocomplete_fields = ("owasp_repository",)
14-
filter_horizontal = LeaderAdminMixin.filter_horizontal
14+
inlines = (EntityMemberInline,)
1515
list_display = (
1616
"name",
1717
"created_at",

backend/apps/owasp/admin/committee.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44

55
from apps.owasp.models.committee import Committee
66

7-
from .mixins import GenericEntityAdminMixin, LeaderAdminMixin
7+
from .mixins import EntityMemberInline, GenericEntityAdminMixin
88

99

10-
class CommitteeAdmin(admin.ModelAdmin, GenericEntityAdminMixin, LeaderAdminMixin):
10+
class CommitteeAdmin(admin.ModelAdmin, GenericEntityAdminMixin):
1111
"""Admin for Committee model."""
1212

13-
autocomplete_fields = (
14-
"leaders",
15-
"owasp_repository",
16-
)
17-
filter_horizontal = LeaderAdminMixin.filter_horizontal
13+
autocomplete_fields = ("owasp_repository",)
14+
inlines = (EntityMemberInline,)
1815
search_fields = ("name",)
1916

2017

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""EntityMember admin configuration."""
2+
3+
from django.contrib import admin
4+
from django.contrib.contenttypes.models import ContentType
5+
from django.db.models import Q
6+
from django.urls import reverse
7+
from django.utils.html import format_html
8+
9+
from apps.owasp.models.chapter import Chapter
10+
from apps.owasp.models.committee import Committee
11+
from apps.owasp.models.entity_member import EntityMember
12+
from apps.owasp.models.project import Project
13+
14+
15+
class EntityMemberAdmin(admin.ModelAdmin):
16+
"""Admin for EntityMember records (generic link to any OWASP entity)."""
17+
18+
actions = ("approve_members",)
19+
autocomplete_fields = ("member",)
20+
fields = (
21+
"entity_type",
22+
"entity_id",
23+
"member",
24+
"role",
25+
"order",
26+
"is_active",
27+
"is_reviewed",
28+
"description",
29+
)
30+
list_display = (
31+
"member",
32+
"entity",
33+
"owasp_url",
34+
"role",
35+
"is_active",
36+
"is_reviewed",
37+
"order",
38+
)
39+
list_filter = (
40+
"role",
41+
"is_active",
42+
"is_reviewed",
43+
)
44+
raw_id_fields = ("member",)
45+
search_fields = (
46+
"member__login",
47+
"member__name",
48+
"description",
49+
)
50+
ordering = ("member__name", "order")
51+
52+
@admin.action(description="Approve selected members")
53+
def approve_members(self, request, queryset):
54+
"""Approve selected members."""
55+
self.message_user(
56+
request,
57+
f"Successfully approved {queryset.update(is_active=True, is_reviewed=True)} members.",
58+
)
59+
60+
@admin.display(description="Entity", ordering="entity_type")
61+
def entity(self, obj):
62+
"""Return entity link."""
63+
return (
64+
format_html(
65+
'<a href="{}" target="_blank">{}</a>',
66+
reverse(
67+
f"admin:{obj.entity_type.app_label}_{obj.entity_type.model}_change",
68+
args=[obj.entity_id],
69+
),
70+
obj.entity,
71+
)
72+
if obj.entity
73+
else "-"
74+
)
75+
76+
@admin.display(description="OWASP URL", ordering="entity_type")
77+
def owasp_url(self, obj):
78+
"""Return entity OWASP site URL."""
79+
return (
80+
format_html('<a href="{}" target="_blank">↗️</a>', obj.entity.owasp_url)
81+
if obj.entity
82+
else "-"
83+
)
84+
85+
def get_search_results(self, request, queryset, search_term):
86+
"""Get search results from entity name or key."""
87+
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
88+
89+
if search_term:
90+
project_ids = Project.objects.filter(
91+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
92+
).values_list("pk", flat=True)
93+
94+
chapter_ids = Chapter.objects.filter(
95+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
96+
).values_list("pk", flat=True)
97+
98+
committee_ids = Committee.objects.filter(
99+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
100+
).values_list("pk", flat=True)
101+
102+
project_ct = ContentType.objects.get_for_model(Project)
103+
chapter_ct = ContentType.objects.get_for_model(Chapter)
104+
committee_ct = ContentType.objects.get_for_model(Committee)
105+
106+
entity_match_query = (
107+
Q(entity_type=project_ct, entity_id__in=list(project_ids))
108+
| Q(entity_type=chapter_ct, entity_id__in=list(chapter_ids))
109+
| Q(entity_type=committee_ct, entity_id__in=list(committee_ids))
110+
)
111+
112+
queryset |= self.model.objects.filter(entity_match_query)
113+
use_distinct = True
114+
115+
return queryset, use_distinct
116+
117+
118+
admin.site.register(EntityMember, EntityMemberAdmin)

0 commit comments

Comments
 (0)