Skip to content
Merged
12 changes: 6 additions & 6 deletions backend/apps/github/models/mixins/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def idx_created_at(self) -> float:
"""Get the repository creation timestamp for indexing.

Returns:
float: Unix timestamp when the repository was created.
float: Unix timestamp (seconds since epoch) when the repository was created.

"""
return self.created_at.timestamp()
Expand Down Expand Up @@ -112,7 +112,7 @@ def idx_license(self) -> str:
"""Get the repository's license identifier for indexing.

Returns:
str: The license identifier.
str: The SPDX license identifier or name, if available.

"""
return self.license
Expand Down Expand Up @@ -153,7 +153,7 @@ def idx_pushed_at(self) -> float:
"""Get the timestamp of the last push to this repository for indexing.

Returns:
float: Unix timestamp of the most recent push.
float: Unix timestamp (seconds since epoch) of the most recent push.

"""
return self.pushed_at.timestamp()
Expand All @@ -170,17 +170,17 @@ def idx_size(self) -> int:

@property
def idx_stars_count(self) -> int:
"""Get the total number of stars this repository has received for indexing.
"""Get the total number of stars (likes) this repository has received for indexing.

Returns:
int: The total count of stars on the repository.
int: The total count of stars/favorites on the repository.

"""
return self.stars_count

@property
def idx_subscribers_count(self) -> int:
"""Get the total number of subscribers for this repository for indexing.
"""Get the total number of watchers/subscribers for this repository for indexing.

Returns:
int: The count of users watching this repository.
Expand Down
10 changes: 7 additions & 3 deletions backend/apps/github/models/mixins/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class UserIndexMixin:
def is_indexable(self):
"""Determine if the user should be indexed.

A user is considered indexable if they are not a bot, their login does not
end with common bot suffixes ("Bot" or "-bot"), and their login is not
present in the non-indexable logins list.

Returns:
bool: True if the user meets all indexing criteria, False otherwise.

Expand Down Expand Up @@ -69,7 +73,7 @@ def idx_created_at(self) -> float:
"""Get the account creation timestamp for indexing.

Returns:
float: Unix timestamp when the account was created.
float: Unix timestamp (seconds since epoch) when the account was created.

"""
return self.created_at.timestamp()
Expand Down Expand Up @@ -159,7 +163,7 @@ def idx_title(self) -> str:
"""Get the user's profile title or headline for indexing.

Returns:
str: The title or headline associated with the user.
str: The title or headline associated with the user, if any.

"""
return self.title
Expand Down Expand Up @@ -252,7 +256,7 @@ def idx_issues_count(self) -> int:

@property
def idx_releases(self) -> list[dict]:
"""Get releases associated with the user for indexing.
"""Get recent releases associated with the user for indexing.

Returns:
list[dict]: A list of release summaries including pre-release flag,
Expand Down
37 changes: 34 additions & 3 deletions backend/apps/owasp/admin/entity_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@

@admin.action(description="Mark selected EntityChannels as reviewed")
def mark_as_reviewed(_modeladmin, request, queryset):
"""Admin action to mark selected EntityChannels as reviewed."""
"""Admin action to mark selected EntityChannels as reviewed.

Args:
_modeladmin: The ModelAdmin instance (unused).
request: The HTTP request object.
queryset: QuerySet of EntityChannel instances to mark as reviewed.

"""
messages.success(
request,
f"Marked {queryset.update(is_reviewed=True)} EntityChannel(s) as reviewed.",
Expand Down Expand Up @@ -62,7 +69,18 @@ class EntityChannelAdmin(admin.ModelAdmin):
)

def channel_search_display(self, obj):
"""Display the channel name for the selected channel."""
"""Display the channel name in the admin list view.

Retrieves and displays the Conversation name if the channel_id
references a valid Slack conversation.

Args:
obj: The EntityChannel instance.

Returns:
str: Channel name as '#name', error message, or '-' if not found.

"""
if obj.channel_id and obj.channel_type:
try:
if obj.channel_type.model == "conversation":
Expand All @@ -75,7 +93,20 @@ def channel_search_display(self, obj):
channel_search_display.short_description = "Channel Name"

def get_form(self, request, obj=None, **kwargs):
"""Get the form for the EntityChannel model."""
"""Get the form for the EntityChannel model.

Prepares the form with necessary metadata for channel selection
and custom widgets.

Args:
request: The HTTP request object.
obj: The EntityChannel instance being edited (None for add).
**kwargs: Additional keyword arguments passed to parent.

Returns:
Form: The EntityChannel form with conversation content type metadata.

"""
form = super().get_form(request, obj, **kwargs)
form.conversation_content_type_id = ContentType.objects.get_for_model(Conversation).id

Expand Down
47 changes: 43 additions & 4 deletions backend/apps/owasp/admin/entity_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,31 @@ class EntityMemberAdmin(admin.ModelAdmin):

@admin.action(description="Approve selected members")
def approve_members(self, request, queryset):
"""Approve selected members."""
"""Admin action to approve selected members.

Sets is_active and is_reviewed flags for selected entity members.

Args:
request: The HTTP request object.
queryset: QuerySet of EntityMember instances to approve.

"""
self.message_user(
request,
f"Successfully approved {queryset.update(is_active=True, is_reviewed=True)} members.",
)

@admin.display(description="Entity", ordering="entity_type")
def entity(self, obj):
"""Return entity link."""
"""Display entity as a link in the admin list view.

Args:
obj: The EntityMember instance.

Returns:
str: HTML link to the entity's admin page or '-' if entity is missing.

"""
return (
format_html(
'<a href="{}" target="_blank">{}</a>',
Expand All @@ -66,15 +82,38 @@ def entity(self, obj):

@admin.display(description="OWASP URL", ordering="entity_type")
def owasp_url(self, obj):
"""Return entity OWASP site URL."""
"""Display entity OWASP website link in admin list view.

Args:
obj: The EntityMember instance.

Returns:
str: HTML link to the entity's OWASP website or '-' if entity is missing.

"""
return (
format_html('<a href="{}" target="_blank">↗️</a>', obj.entity.owasp_url)
if obj.entity
else "-"
)

def get_search_results(self, request, queryset, search_term):
"""Get search results from entity name or key."""
"""Extend search results to include entity name or key matches.

Searches across Project, Chapter, and Committee entities by name or key
and includes matching results in the EntityMember search results.

Args:
request: The HTTP request object.
queryset: Initial QuerySet of EntityMember instances.
search_term: The search term entered by the user.

Returns:
tuple: (QuerySet, use_distinct) where QuerySet includes matching members
and related entities by name/key, and use_distinct indicates
if DISTINCT should be applied to the query.

"""
queryset, use_distinct = super().get_search_results(request, queryset, search_term)

if search_term:
Expand Down
13 changes: 12 additions & 1 deletion backend/apps/owasp/admin/member_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,18 @@ class MemberProfileAdmin(admin.ModelAdmin):
)

def get_queryset(self, request):
"""Optimize queryset with select_related."""
"""Retrieve optimized queryset with related GitHub user.

Applies select_related on github_user to reduce database queries when displaying
member profile lists.

Args:
request: The HTTP request object.

Returns:
QuerySet: MemberProfile queryset with prefetched github_user relations.

"""
queryset = super().get_queryset(request)
return queryset.select_related("github_user")

Expand Down
13 changes: 12 additions & 1 deletion backend/apps/owasp/admin/member_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,18 @@ class MemberSnapshotAdmin(admin.ModelAdmin):
)

def get_queryset(self, request):
"""Optimize queryset with select_related."""
"""Retrieve optimized queryset with related GitHub user.

Applies select_related on github_user to reduce database queries when displaying
member snapshot lists.

Args:
request: The HTTP request object.

Returns:
QuerySet: MemberSnapshot queryset with select_related("github_user") applied.

"""
queryset = super().get_queryset(request)
return queryset.select_related("github_user")

Expand Down
Loading