Skip to content

Commit fe91cae

Browse files
authored
Slack admin interface (#2057)
1 parent 64e1138 commit fe91cae

2 files changed

Lines changed: 186 additions & 0 deletions

File tree

slack/admin.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from django.contrib import admin
2+
3+
from slack.filters import FilterByReleaseDates
4+
from slack.models import Channel, SlackActivityBucket, Thread
5+
6+
7+
@admin.register(Channel)
8+
class ChannelAdmin(admin.ModelAdmin):
9+
list_display = ["id", "name", "last_update_ts_readable"]
10+
search_fields = ["name", "id"]
11+
readonly_fields = ["id", "name", "topic", "purpose", "last_update_ts"]
12+
ordering = ["name"]
13+
14+
@admin.display(description="Last Update")
15+
def last_update_ts_readable(self, obj):
16+
"""Display last_update_ts in a human-readable format."""
17+
if obj.last_update_ts:
18+
from slack.models import parse_ts
19+
20+
return parse_ts(obj.last_update_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
21+
return "-"
22+
23+
def has_add_permission(self, request):
24+
return False
25+
26+
def has_change_permission(self, request, obj=None):
27+
return False
28+
29+
def has_delete_permission(self, request, obj=None):
30+
return False
31+
32+
33+
@admin.register(SlackActivityBucket)
34+
class SlackActivityBucketAdmin(admin.ModelAdmin):
35+
list_display = ["day", "channel_name", "user_name", "count"]
36+
search_fields = ["channel__name", "user__name", "user__real_name"]
37+
list_filter = ["day", "channel__name", FilterByReleaseDates]
38+
readonly_fields = ["day", "user", "channel", "count"]
39+
raw_id_fields = ["user", "channel"]
40+
date_hierarchy = "day"
41+
ordering = ["-day"]
42+
43+
@admin.display(
44+
description="Channel",
45+
ordering="channel__name",
46+
)
47+
def channel_name(self, obj):
48+
"""Display channel name instead of Channel object."""
49+
return obj.channel.name if obj.channel else "-"
50+
51+
@admin.display(
52+
description="User",
53+
ordering="user__name",
54+
)
55+
def user_name(self, obj):
56+
"""Display user name instead of SlackUser object."""
57+
return obj.user.real_name or obj.user.name if obj.user else "-"
58+
59+
def has_add_permission(self, request):
60+
return False
61+
62+
def has_change_permission(self, request, obj=None):
63+
return False
64+
65+
def has_delete_permission(self, request, obj=None):
66+
return False
67+
68+
69+
@admin.register(Thread)
70+
class ThreadAdmin(admin.ModelAdmin):
71+
list_display = [
72+
"id",
73+
"channel__id",
74+
"channel__name",
75+
"thread_ts_readable",
76+
"last_update_ts_readable",
77+
]
78+
search_fields = ["channel__id", "channel__name", "thread_ts"]
79+
list_filter = ["channel__name"]
80+
readonly_fields = ["channel", "thread_ts", "last_update_ts", "db_created_at"]
81+
raw_id_fields = ["channel"]
82+
date_hierarchy = "db_created_at"
83+
ordering = ["-db_created_at"]
84+
85+
@admin.display(description="Thread Created")
86+
def thread_ts_readable(self, obj):
87+
"""Display thread_ts in a human-readable format."""
88+
if obj.thread_ts:
89+
from slack.models import parse_ts
90+
91+
return parse_ts(obj.thread_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
92+
return "-"
93+
94+
@admin.display(description="Last Update")
95+
def last_update_ts_readable(self, obj):
96+
"""Display last_update_ts in a human-readable format."""
97+
if obj.last_update_ts:
98+
from slack.models import parse_ts
99+
100+
return parse_ts(obj.last_update_ts).strftime("%Y-%m-%d %H:%M:%S UTC")
101+
return "-"
102+
103+
def has_add_permission(self, request):
104+
return False
105+
106+
def has_change_permission(self, request, obj=None):
107+
return False
108+
109+
def has_delete_permission(self, request, obj=None):
110+
return False

slack/filters.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from django.contrib import admin
2+
3+
4+
class FilterByReleaseDates(admin.SimpleListFilter):
5+
"""Filter slack activity by Boost version release periods.
6+
7+
The release date is considered the END of the development period for that version.
8+
Messages are attributed to the version they were leading up to, not the one just released.
9+
"""
10+
11+
title = "release"
12+
parameter_name = "release"
13+
14+
def lookups(self, request, model_admin):
15+
from versions.models import Version
16+
17+
versions = Version.objects.filter(
18+
release_date__isnull=False, active=True, full_release=True
19+
).order_by("-release_date")[:20]
20+
21+
# Add special entries for ongoing development
22+
choices = [
23+
("master", "master (after latest release)"),
24+
("develop", "develop (after latest release)"),
25+
]
26+
27+
# Add version entries
28+
choices.extend([(v.id, f"{v.name} ({v.release_date})") for v in versions])
29+
30+
return choices
31+
32+
def queryset(self, request, queryset):
33+
if self.value() in ("master", "develop"):
34+
# Get messages after the latest release
35+
from versions.models import Version
36+
37+
latest_version = (
38+
Version.objects.filter(
39+
release_date__isnull=False, active=True, full_release=True
40+
)
41+
.order_by("-release_date")
42+
.first()
43+
)
44+
45+
if latest_version and latest_version.release_date:
46+
return queryset.filter(day__gt=latest_version.release_date)
47+
48+
elif self.value():
49+
from versions.models import Version
50+
51+
try:
52+
version = Version.objects.get(id=self.value())
53+
if version.release_date:
54+
# Get the previous version's release date (this is the start of the period)
55+
previous_version = (
56+
Version.objects.filter(
57+
release_date__lt=version.release_date,
58+
active=True,
59+
full_release=True,
60+
)
61+
.order_by("-release_date")
62+
.first()
63+
)
64+
65+
if previous_version and previous_version.release_date:
66+
# Filter messages between previous release and current release
67+
return queryset.filter(
68+
day__gt=previous_version.release_date,
69+
day__lte=version.release_date,
70+
)
71+
else:
72+
# No previous version, so filter up to this release
73+
return queryset.filter(day__lte=version.release_date)
74+
except Version.DoesNotExist:
75+
pass
76+
return queryset

0 commit comments

Comments
 (0)