Skip to content

Commit 31a6f48

Browse files
committed
udpated code
1 parent b29348d commit 31a6f48

5 files changed

Lines changed: 188 additions & 157 deletions

File tree

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/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/entity_member.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
"""EntityMember admin configuration."""
22

33
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
48

9+
from apps.owasp.models.chapter import Chapter
10+
from apps.owasp.models.committee import Committee
511
from apps.owasp.models.entity_member import EntityMember
12+
from apps.owasp.models.project import Project
613

714

815
class EntityMemberAdmin(admin.ModelAdmin):
@@ -20,20 +27,66 @@ class EntityMemberAdmin(admin.ModelAdmin):
2027
)
2128
list_display = (
2229
"member",
30+
"entity",
2331
"kind",
2432
"is_reviewed",
2533
"order",
2634
)
2735
list_filter = (
2836
"kind",
2937
"is_reviewed",
38+
"entity_type",
3039
)
40+
raw_id_fields = ("member",)
3141
search_fields = (
3242
"member__login",
3343
"member__name",
3444
"description",
35-
"entity_id",
3645
)
46+
ordering = ("-id",)
47+
48+
@admin.display(description="Entity", ordering="entity_type")
49+
def entity(self, obj):
50+
"""Return entity link."""
51+
if obj.entity:
52+
link = reverse(
53+
f"admin:{obj.entity_type.app_label}_{obj.entity_type.model}_change",
54+
args=[obj.entity_id],
55+
)
56+
return format_html('<a href="{}">{}</a>', link, obj.entity)
57+
return "— No Associated Entity —"
58+
59+
def get_search_results(self, request, queryset, search_term):
60+
"""Get search results from entity name or key."""
61+
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
62+
63+
if search_term:
64+
project_ids = Project.objects.filter(
65+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
66+
).values_list("pk", flat=True)
67+
68+
chapter_ids = Chapter.objects.filter(
69+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
70+
).values_list("pk", flat=True)
71+
72+
committee_ids = Committee.objects.filter(
73+
Q(name__icontains=search_term) | Q(key__icontains=search_term)
74+
).values_list("pk", flat=True)
75+
76+
project_ct = ContentType.objects.get_for_model(Project)
77+
chapter_ct = ContentType.objects.get_for_model(Chapter)
78+
committee_ct = ContentType.objects.get_for_model(Committee)
79+
80+
entity_match_query = (
81+
Q(entity_type=project_ct, entity_id__in=list(project_ids))
82+
| Q(entity_type=chapter_ct, entity_id__in=list(chapter_ids))
83+
| Q(entity_type=committee_ct, entity_id__in=list(committee_ids))
84+
)
85+
86+
queryset |= self.model.objects.filter(entity_match_query)
87+
use_distinct = True
88+
89+
return queryset, use_distinct
3790

3891

3992
admin.site.register(EntityMember, EntityMemberAdmin)

backend/apps/owasp/management/commands/owasp_update_leaders.py

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,24 @@ def process_entities(self, model_class, users_list, threshold):
6868
if not entity.leaders_raw:
6969
continue
7070

71-
matched_users = self.find_user_matches(entity.leaders_raw, users_list, threshold)
71+
for index, leader_name in enumerate(entity.leaders_raw):
72+
matched_user = self.find_single_user_matches(leader_name, users_list, threshold)
7273

73-
if not matched_users:
74-
continue
74+
if not matched_user:
75+
continue
7576

76-
self.stdout.write(f" - Found {len(matched_users)} leader matches for '{entity}'")
77+
self.stdout.write(f"Match for '{leader_name}': {matched_user['login']}")
7778

78-
new_members_to_create.extend(
79-
[
79+
new_members_to_create.append(
8080
EntityMember(
8181
entity_type=entity_type,
8282
entity_id=entity.pk,
83-
member_id=user["id"],
83+
member_id=matched_user["id"],
8484
kind=EntityMember.MemberKind.LEADER,
8585
is_reviewed=False,
86+
order=((index + 1) * 10),
8687
)
87-
for user in matched_users
88-
]
89-
)
88+
)
9089

9190
if new_members_to_create:
9291
created_records = EntityMember.objects.bulk_create(
@@ -107,39 +106,29 @@ def is_valid_user(self, login, name):
107106
"""Check if GitHub user meets minimum requirements."""
108107
return len(login) >= ID_MIN_LENGTH and len(name or "") >= ID_MIN_LENGTH
109108

110-
def find_user_matches(self, leaders_raw, users_list, threshold):
109+
def find_single_user_matches(self, leader_name, users_list, threshold):
111110
"""Find user matches for a list of raw leader names."""
112-
matched_users = []
111+
if not leader_name:
112+
return None
113113

114-
for leader_name in set(leaders_raw):
115-
if not leader_name:
116-
continue
114+
leader_lower = leader_name.lower()
117115

118-
leader_lower = leader_name.lower()
119-
best_fuzzy_match = None
120-
highest_score = 0
121-
122-
exact_match_found = False
123-
for user in users_list:
124-
if user["login"].lower() == leader_lower or (
125-
user["name"] and user["name"].lower() == leader_lower
126-
):
127-
matched_users.append(user)
128-
exact_match_found = True
129-
130-
if exact_match_found:
131-
continue
116+
for user in users_list:
117+
if user["login"].lower() == leader_lower or (
118+
user["name"] and user["name"].lower() == leader_lower
119+
):
120+
return user
132121

133-
for user in users_list:
134-
score = fuzz.token_sort_ratio(leader_lower, user["login"].lower())
135-
if user["name"]:
136-
score = max(score, fuzz.token_sort_ratio(leader_lower, user["name"].lower()))
122+
best_fuzzy_match = None
123+
highest_score = threshold - 1
137124

138-
if score > highest_score:
139-
highest_score = score
140-
best_fuzzy_match = user
125+
for user in users_list:
126+
score = fuzz.token_sort_ratio(leader_lower, user["login"].lower())
127+
if user["name"]:
128+
score = max(score, fuzz.token_sort_ratio(leader_lower, user["name"].lower()))
141129

142-
if highest_score >= threshold:
143-
matched_users.append(best_fuzzy_match)
130+
if score > highest_score:
131+
highest_score = score
132+
best_fuzzy_match = user
144133

145-
return list({user["id"]: user for user in matched_users}.values())
134+
return best_fuzzy_match

0 commit comments

Comments
 (0)