Slack admin interface (#2057)

This commit is contained in:
daveoconnor
2026-01-13 13:31:55 -08:00
committed by GitHub
parent 64e113835f
commit fe91cae207
2 changed files with 186 additions and 0 deletions

110
slack/admin.py Normal file
View File

@@ -0,0 +1,110 @@
from django.contrib import admin
from slack.filters import FilterByReleaseDates
from slack.models import Channel, SlackActivityBucket, Thread
@admin.register(Channel)
class ChannelAdmin(admin.ModelAdmin):
list_display = ["id", "name", "last_update_ts_readable"]
search_fields = ["name", "id"]
readonly_fields = ["id", "name", "topic", "purpose", "last_update_ts"]
ordering = ["name"]
@admin.display(description="Last Update")
def last_update_ts_readable(self, obj):
"""Display last_update_ts in a human-readable format."""
if obj.last_update_ts:
from slack.models import parse_ts
return parse_ts(obj.last_update_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
return "-"
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
@admin.register(SlackActivityBucket)
class SlackActivityBucketAdmin(admin.ModelAdmin):
list_display = ["day", "channel_name", "user_name", "count"]
search_fields = ["channel__name", "user__name", "user__real_name"]
list_filter = ["day", "channel__name", FilterByReleaseDates]
readonly_fields = ["day", "user", "channel", "count"]
raw_id_fields = ["user", "channel"]
date_hierarchy = "day"
ordering = ["-day"]
@admin.display(
description="Channel",
ordering="channel__name",
)
def channel_name(self, obj):
"""Display channel name instead of Channel object."""
return obj.channel.name if obj.channel else "-"
@admin.display(
description="User",
ordering="user__name",
)
def user_name(self, obj):
"""Display user name instead of SlackUser object."""
return obj.user.real_name or obj.user.name if obj.user else "-"
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
@admin.register(Thread)
class ThreadAdmin(admin.ModelAdmin):
list_display = [
"id",
"channel__id",
"channel__name",
"thread_ts_readable",
"last_update_ts_readable",
]
search_fields = ["channel__id", "channel__name", "thread_ts"]
list_filter = ["channel__name"]
readonly_fields = ["channel", "thread_ts", "last_update_ts", "db_created_at"]
raw_id_fields = ["channel"]
date_hierarchy = "db_created_at"
ordering = ["-db_created_at"]
@admin.display(description="Thread Created")
def thread_ts_readable(self, obj):
"""Display thread_ts in a human-readable format."""
if obj.thread_ts:
from slack.models import parse_ts
return parse_ts(obj.thread_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
return "-"
@admin.display(description="Last Update")
def last_update_ts_readable(self, obj):
"""Display last_update_ts in a human-readable format."""
if obj.last_update_ts:
from slack.models import parse_ts
return parse_ts(obj.last_update_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
return "-"
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False

76
slack/filters.py Normal file
View File

@@ -0,0 +1,76 @@
from django.contrib import admin
class FilterByReleaseDates(admin.SimpleListFilter):
"""Filter slack activity by Boost version release periods.
The release date is considered the END of the development period for that version.
Messages are attributed to the version they were leading up to, not the one just released.
"""
title = "release"
parameter_name = "release"
def lookups(self, request, model_admin):
from versions.models import Version
versions = Version.objects.filter(
release_date__isnull=False, active=True, full_release=True
).order_by("-release_date")[:20]
# Add special entries for ongoing development
choices = [
("master", "master (after latest release)"),
("develop", "develop (after latest release)"),
]
# Add version entries
choices.extend([(v.id, f"{v.name} ({v.release_date})") for v in versions])
return choices
def queryset(self, request, queryset):
if self.value() in ("master", "develop"):
# Get messages after the latest release
from versions.models import Version
latest_version = (
Version.objects.filter(
release_date__isnull=False, active=True, full_release=True
)
.order_by("-release_date")
.first()
)
if latest_version and latest_version.release_date:
return queryset.filter(day__gt=latest_version.release_date)
elif self.value():
from versions.models import Version
try:
version = Version.objects.get(id=self.value())
if version.release_date:
# Get the previous version's release date (this is the start of the period)
previous_version = (
Version.objects.filter(
release_date__lt=version.release_date,
active=True,
full_release=True,
)
.order_by("-release_date")
.first()
)
if previous_version and previous_version.release_date:
# Filter messages between previous release and current release
return queryset.filter(
day__gt=previous_version.release_date,
day__lte=version.release_date,
)
else:
# No previous version, so filter up to this release
return queryset.filter(day__lte=version.release_date)
except Version.DoesNotExist:
pass
return queryset