From f590d2bc5960cafede1e596d67028052f2fad5b2 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 05:39:11 +1000 Subject: Add message log links, improved formatting to message deletion admin pages. --- pydis_site/apps/api/admin.py | 82 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 059f52eb..6d6a9b3b 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,7 +1,10 @@ +import json from typing import Optional +from django import urls from django.contrib import admin from django.http import HttpRequest +from django.utils.html import format_html from .models import ( BotSetting, @@ -44,21 +47,86 @@ class LogEntryAdmin(admin.ModelAdmin): """Deny manual LogEntry creation.""" return False - def has_delete_permission( - self, - request: HttpRequest, - obj: Optional[LogEntry] = None - ) -> bool: + def has_delete_permission(self, request: HttpRequest, obj: Optional[LogEntry] = None) -> bool: """Deny LogEntry deletion.""" return False +class DeletedMessageAdmin(admin.ModelAdmin): + """Admin formatting for the DeletedMessage model.""" + + readonly_fields = ( + "id", + "author", + "channel_id", + "content", + "embed_data", + "context", + "view_full_log" + ) + + exclude = ("embeds", "deletion_context") + + search_fields = ( + "id", + "content", + "author__name", + "author__id", + "deletion_context__actor__name", + "deletion_context__actor__id" + ) + + @staticmethod + def embed_data(instance: DeletedMessage) -> Optional[str]: + """Format embed data in a code block for better readability.""" + if instance.embeds: + return format_html( + "
{0}
", + json.dumps(instance.embeds, indent=4) + ) + + @staticmethod + def context(instance: DeletedMessage) -> str: + """Provide full context info with a link through to context admin view.""" + link = urls.reverse( + "admin:api_messagedeletioncontext_change", + args=[instance.deletion_context.id] + ) + details = ( + f"Deleted by {instance.deletion_context.actor} at " + f"{instance.deletion_context.creation}" + ) + return format_html("{1}", link, details) + + @staticmethod + def view_full_log(instance: DeletedMessage) -> str: + """Provide a link to the message logs for the relevant context.""" + return format_html( + "Click to view full context log", + instance.deletion_context.log_url + ) + + +class MessageDeletionContextAdmin(admin.ModelAdmin): + """Admin formatting for the MessageDeletionContext model.""" + + readonly_fields = ("actor", "creation", "message_log") + + @staticmethod + def message_log(instance: MessageDeletionContext) -> str: + """Provide a formatted link to the message logs for the context.""" + return format_html( + "Click to see deleted message log", + instance.log_url + ) + + admin.site.register(BotSetting) -admin.site.register(DeletedMessage) +admin.site.register(DeletedMessage, DeletedMessageAdmin) admin.site.register(DocumentationLink) admin.site.register(Infraction) admin.site.register(LogEntry, LogEntryAdmin) -admin.site.register(MessageDeletionContext) +admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) admin.site.register(Nomination) admin.site.register(OffTopicChannelName) admin.site.register(Role) -- cgit v1.2.3 From 618610fe367b0c8d6175d251c276c2e37db8aa52 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 05:43:21 +1000 Subject: Order roles by positioning, add filters and search to api user admin page. --- pydis_site/apps/api/admin.py | 45 ++++++++++++++++++++++++++++++++-- pydis_site/apps/api/models/bot/role.py | 5 ++++ 2 files changed, 48 insertions(+), 2 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 6d6a9b3b..65cc0a6c 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,8 +1,9 @@ import json -from typing import Optional +from typing import Optional, Tuple from django import urls from django.contrib import admin +from django.db.models.query import QuerySet from django.http import HttpRequest from django.utils.html import format_html @@ -121,6 +122,46 @@ class MessageDeletionContextAdmin(admin.ModelAdmin): ) +class StaffRolesFilter(admin.SimpleListFilter): + """Filter options for Staff Roles.""" + + title = "Staff Role" + parameter_name = "staff_role" + + @staticmethod + def lookups(*_) -> Tuple[Tuple[str, str], ...]: + """Available filter options.""" + return ( + ("Owners", "Owners"), + ("Admins", "Admins"), + ("Moderators", "Moderators"), + ("Core Developers", "Core Developers"), + ("Helpers", "Helpers"), + ) + + def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]: + """Returned data filter based on selected option.""" + value = self.value() + if value: + return queryset.filter(roles__name=value) + + +class UserAdmin(admin.ModelAdmin): + """Admin formatting for the User model.""" + + search_fields = ("name", "id", "roles__name", "roles__id") + list_filter = ("in_guild", StaffRolesFilter) + exclude = ("name", "discriminator") + readonly_fields = ( + "__str__", + "id", + "avatar_hash", + "top_role", + "roles", + "in_guild", + ) + + admin.site.register(BotSetting) admin.site.register(DeletedMessage, DeletedMessageAdmin) admin.site.register(DocumentationLink) @@ -131,4 +172,4 @@ admin.site.register(Nomination) admin.site.register(OffTopicChannelName) admin.site.register(Role) admin.site.register(Tag) -admin.site.register(User) +admin.site.register(User, UserAdmin) diff --git a/pydis_site/apps/api/models/bot/role.py b/pydis_site/apps/api/models/bot/role.py index 58bbf8b4..b95740da 100644 --- a/pydis_site/apps/api/models/bot/role.py +++ b/pydis_site/apps/api/models/bot/role.py @@ -65,3 +65,8 @@ class Role(ModelReprMixin, models.Model): def __le__(self, other: Role) -> bool: """Compares the roles based on their position in the role hierarchy of the guild.""" return self.position <= other.position + + class Meta: + """Set role ordering from highest to lowest position.""" + + ordering = ("-position",) -- cgit v1.2.3 From 0021d4a2906021351203ffabc73d6e02ecf400c4 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 06:21:13 +1000 Subject: Improve infractions admin list and page, add search and filters. --- pydis_site/apps/api/admin.py | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 65cc0a6c..74b9413b 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -122,6 +122,50 @@ class MessageDeletionContextAdmin(admin.ModelAdmin): ) +class InfractionAdmin(admin.ModelAdmin): + """Admin formatting for the Infraction model.""" + + fields = ( + "user", + "actor", + "type", + "reason", + "inserted_at", + "expires_at", + "active", + "hidden" + ) + readonly_fields = ( + "user", + "actor", + "type", + "inserted_at" + ) + list_display = ( + "type", + "user", + "actor", + "inserted_at", + "expires_at", + "reason", + "active", + ) + search_fields = ( + "id", + "user__name", + "user__id", + "actor__name", + "actor__id", + "reason", + "type" + ) + list_filter = ( + "type", + "hidden", + "active" + ) + + class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" @@ -165,7 +209,7 @@ class UserAdmin(admin.ModelAdmin): admin.site.register(BotSetting) admin.site.register(DeletedMessage, DeletedMessageAdmin) admin.site.register(DocumentationLink) -admin.site.register(Infraction) +admin.site.register(Infraction, InfractionAdmin) admin.site.register(LogEntry, LogEntryAdmin) admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) admin.site.register(Nomination) -- cgit v1.2.3 From 1c41c8a1aa07d7a716561c7594f769db7aa58cf5 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 06:33:35 +1000 Subject: Improve nominations admin list and page, add search and filter by active. --- pydis_site/apps/api/admin.py | 39 +++++++++++++++++++++++++++- pydis_site/apps/api/models/bot/nomination.py | 5 ++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 74b9413b..55a9d655 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -166,6 +166,43 @@ class InfractionAdmin(admin.ModelAdmin): ) +class NominationAdmin(admin.ModelAdmin): + """Admin formatting for the Nomination model.""" + + list_display = ( + "user", + "active", + "reason", + "actor", + "inserted_at", + "ended_at" + ) + fields = ( + "user", + "active", + "actor", + "reason", + "inserted_at", + "ended_at", + "end_reason" + ) + readonly_fields = ( + "user", + "active", + "actor", + "inserted_at", + "ended_at" + ) + search_fields = ( + "actor__name", + "actor__id", + "user__name", + "user__id", + "reason" + ) + list_filter = ("active",) + + class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" @@ -212,7 +249,7 @@ admin.site.register(DocumentationLink) admin.site.register(Infraction, InfractionAdmin) admin.site.register(LogEntry, LogEntryAdmin) admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) -admin.site.register(Nomination) +admin.site.register(Nomination, NominationAdmin) admin.site.register(OffTopicChannelName) admin.site.register(Role) admin.site.register(Tag) diff --git a/pydis_site/apps/api/models/bot/nomination.py b/pydis_site/apps/api/models/bot/nomination.py index cd9951aa..a0ba42a3 100644 --- a/pydis_site/apps/api/models/bot/nomination.py +++ b/pydis_site/apps/api/models/bot/nomination.py @@ -44,3 +44,8 @@ class Nomination(ModelReprMixin, models.Model): """Representation that makes the target and state of the nomination immediately evident.""" status = "active" if self.active else "ended" return f"Nomination of {self.user} ({status})" + + class Meta: + """Set the ordering of nominations to most recent first.""" + + ordering = ("-inserted_at",) -- cgit v1.2.3 From 77da3336a248a5a01fe1f83493e0424dbd261cd2 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 06:37:55 +1000 Subject: Add search field to off topic admin page. --- pydis_site/apps/api/admin.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 55a9d655..fe0e3235 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -203,6 +203,12 @@ class NominationAdmin(admin.ModelAdmin): list_filter = ("active",) +class OffTopicChannelNameAdmin(admin.ModelAdmin): + """Admin formatting for the OffTopicChannelName model.""" + + search_fields = ("name",) + + class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" @@ -250,7 +256,7 @@ admin.site.register(Infraction, InfractionAdmin) admin.site.register(LogEntry, LogEntryAdmin) admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) admin.site.register(Nomination, NominationAdmin) -admin.site.register(OffTopicChannelName) +admin.site.register(OffTopicChannelName, OffTopicChannelNameAdmin) admin.site.register(Role) admin.site.register(Tag) admin.site.register(User, UserAdmin) -- cgit v1.2.3 From 72f156fda828a7e28605d0fe07bd990d05f61925 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 07:18:42 +1000 Subject: Show role colour style and add hex value, link perms to calc page, add role search. --- pydis_site/apps/api/admin.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index fe0e3235..237d68a4 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -209,6 +209,38 @@ class OffTopicChannelNameAdmin(admin.ModelAdmin): search_fields = ("name",) +class RoleAdmin(admin.ModelAdmin): + """Admin formatting for the Role model.""" + + exclude = ("permissions", "colour") + readonly_fields = ( + "name", + "id", + "colour_with_preview", + "permissions_with_calc_link", + "position" + ) + search_fields = ("name", "id") + + def colour_with_preview(self, instance: Role) -> str: + """Show colour value in both int and hex, in bolded and coloured style.""" + return format_html( + "{1} / #{0}", + f"{instance.colour:06x}", + instance.colour + ) + + def permissions_with_calc_link(self, instance: Role) -> str: + """Show permissions with link to API permissions calculator page.""" + return format_html( + "{0}", + instance.permissions + ) + + colour_with_preview.short_description = "Colour" + permissions_with_calc_link.short_description = "Permissions" + + class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" @@ -257,6 +289,6 @@ admin.site.register(LogEntry, LogEntryAdmin) admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) admin.site.register(Nomination, NominationAdmin) admin.site.register(OffTopicChannelName, OffTopicChannelNameAdmin) -admin.site.register(Role) +admin.site.register(Role, RoleAdmin) admin.site.register(Tag) admin.site.register(User, UserAdmin) -- cgit v1.2.3 From e19d34b06f6485d2809b600547ae5b672c31fe7e Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 07:50:00 +1000 Subject: Add tag search and rendered preview. --- pydis_site/apps/api/admin.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 237d68a4..010541a6 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -82,7 +82,8 @@ class DeletedMessageAdmin(admin.ModelAdmin): """Format embed data in a code block for better readability.""" if instance.embeds: return format_html( - "
{0}
", + "
"
+                "{0}
", json.dumps(instance.embeds, indent=4) ) @@ -241,6 +242,29 @@ class RoleAdmin(admin.ModelAdmin): permissions_with_calc_link.short_description = "Permissions" +class TagAdmin(admin.ModelAdmin): + """Admin formatting for the Tag model.""" + + fields = ("title", "embed", "preview") + readonly_fields = ("preview",) + search_fields = ("title", "embed") + + @staticmethod + def preview(instance: Tag) -> Optional[str]: + """Render tag markdown contents to preview actual appearance.""" + if instance.embed: + import markdown + return format_html( + markdown.markdown( + instance.embed["description"], + extensions=[ + "markdown.extensions.nl2br", + "markdown.extensions.extra" + ] + ) + ) + + class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" @@ -290,5 +314,5 @@ admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) admin.site.register(Nomination, NominationAdmin) admin.site.register(OffTopicChannelName, OffTopicChannelNameAdmin) admin.site.register(Role, RoleAdmin) -admin.site.register(Tag) +admin.site.register(Tag, TagAdmin) admin.site.register(User, UserAdmin) -- cgit v1.2.3 From 2029cf511ee61d48eca94811e6e891a6c827de7e Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 04:30:05 +1000 Subject: Remove TagAdmin model as Tags were removed from site. --- pydis_site/apps/api/admin.py | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 271ff119..4bf2a6ee 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -242,29 +242,6 @@ class RoleAdmin(admin.ModelAdmin): permissions_with_calc_link.short_description = "Permissions" -class TagAdmin(admin.ModelAdmin): - """Admin formatting for the Tag model.""" - - fields = ("title", "embed", "preview") - readonly_fields = ("preview",) - search_fields = ("title", "embed") - - @staticmethod - def preview(instance: Tag) -> Optional[str]: - """Render tag markdown contents to preview actual appearance.""" - if instance.embed: - import markdown - return format_html( - markdown.markdown( - instance.embed["description"], - extensions=[ - "markdown.extensions.nl2br", - "markdown.extensions.extra" - ] - ) - ) - - class StaffRolesFilter(admin.SimpleListFilter): """Filter options for Staff Roles.""" -- cgit v1.2.3 From 4ad759c21ca91bc38727c27083e8aa48b30b7325 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 11:46:53 +1000 Subject: Use admin.register decorators. --- pydis_site/apps/api/admin.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 4bf2a6ee..6116fbf8 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -22,6 +22,7 @@ from .models import ( ) +@admin.register(LogEntry) class LogEntryAdmin(admin.ModelAdmin): """Allows viewing logs in the Django Admin without allowing edits.""" @@ -53,6 +54,7 @@ class LogEntryAdmin(admin.ModelAdmin): return False +@admin.register(DeletedMessage) class DeletedMessageAdmin(admin.ModelAdmin): """Admin formatting for the DeletedMessage model.""" @@ -109,6 +111,7 @@ class DeletedMessageAdmin(admin.ModelAdmin): ) +@admin.register(MessageDeletionContext) class MessageDeletionContextAdmin(admin.ModelAdmin): """Admin formatting for the MessageDeletionContext model.""" @@ -123,6 +126,7 @@ class MessageDeletionContextAdmin(admin.ModelAdmin): ) +@admin.register(Infraction) class InfractionAdmin(admin.ModelAdmin): """Admin formatting for the Infraction model.""" @@ -167,6 +171,7 @@ class InfractionAdmin(admin.ModelAdmin): ) +@admin.register(Nomination) class NominationAdmin(admin.ModelAdmin): """Admin formatting for the Nomination model.""" @@ -204,12 +209,14 @@ class NominationAdmin(admin.ModelAdmin): list_filter = ("active",) +@admin.register(OffTopicChannelName) class OffTopicChannelNameAdmin(admin.ModelAdmin): """Admin formatting for the OffTopicChannelName model.""" search_fields = ("name",) +@admin.register(Role) class RoleAdmin(admin.ModelAdmin): """Admin formatting for the Role model.""" @@ -266,6 +273,7 @@ class StaffRolesFilter(admin.SimpleListFilter): return queryset.filter(roles__name=value) +@admin.register(User) class UserAdmin(admin.ModelAdmin): """Admin formatting for the User model.""" @@ -283,13 +291,5 @@ class UserAdmin(admin.ModelAdmin): admin.site.register(BotSetting) -admin.site.register(DeletedMessage, DeletedMessageAdmin) admin.site.register(DocumentationLink) -admin.site.register(Infraction, InfractionAdmin) -admin.site.register(LogEntry, LogEntryAdmin) -admin.site.register(MessageDeletionContext, MessageDeletionContextAdmin) -admin.site.register(Nomination, NominationAdmin) admin.site.register(OffensiveMessage) -admin.site.register(OffTopicChannelName, OffTopicChannelNameAdmin) -admin.site.register(Role, RoleAdmin) -admin.site.register(User, UserAdmin) -- cgit v1.2.3 From a311ad08003203a5aa38bf49fec69d6d42f74439 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 11:48:54 +1000 Subject: Update UserAdmin to use new role values, pretty colours. --- pydis_site/apps/api/admin.py | 78 ++++++++++++++++++++-------------- pydis_site/apps/api/models/bot/user.py | 4 ++ 2 files changed, 50 insertions(+), 32 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 6116fbf8..6101f88c 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import json -from typing import Optional, Tuple +from typing import Optional from django import urls from django.contrib import admin -from django.db.models.query import QuerySet from django.http import HttpRequest from django.utils.html import format_html @@ -249,45 +250,58 @@ class RoleAdmin(admin.ModelAdmin): permissions_with_calc_link.short_description = "Permissions" -class StaffRolesFilter(admin.SimpleListFilter): - """Filter options for Staff Roles.""" +class UserTopRoleFilter(admin.SimpleListFilter): + """List Filter for User list Admin page.""" - title = "Staff Role" - parameter_name = "staff_role" + title = "Role" + parameter_name = "role" - @staticmethod - def lookups(*_) -> Tuple[Tuple[str, str], ...]: - """Available filter options.""" - return ( - ("Owners", "Owners"), - ("Admins", "Admins"), - ("Moderators", "Moderators"), - ("Core Developers", "Core Developers"), - ("Helpers", "Helpers"), - ) + def lookups(self, request, model_admin: UserAdmin): + """Selectable values for viewer to filter by.""" + roles = Role.objects.all() + return ((r.name, r.name) for r in roles) - def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]: - """Returned data filter based on selected option.""" - value = self.value() - if value: - return queryset.filter(roles__name=value) + def queryset(self, request, queryset): + if not self.value(): + return + role = Role.objects.get(name=self.value()) + return queryset.filter(roles__contains=[role.id]) @admin.register(User) class UserAdmin(admin.ModelAdmin): """Admin formatting for the User model.""" - search_fields = ("name", "id", "roles__name", "roles__id") - list_filter = ("in_guild", StaffRolesFilter) - exclude = ("name", "discriminator") - readonly_fields = ( - "__str__", - "id", - "avatar_hash", - "top_role", - "roles", - "in_guild", - ) + def top_role_coloured(self, obj: User): + """Returns the top role of the user with html style matching role colour.""" + return format_html( + f'{obj.top_role.name}' + ) + + top_role_coloured.short_description = "Top Role" + + def all_roles_coloured(self, obj: User): + """Returns all user roles with html style matching role colours.""" + roles = Role.objects.filter(id__in=obj.roles) + return format_html( + "
".join( + f'{r.name}' for r in roles + ) + ) + + all_roles_coloured.short_description = "All Roles" + + search_fields = ("name", "id", "roles") + list_filter = (UserTopRoleFilter, "in_guild") + list_display = ("username", "top_role_coloured", "in_guild") + fields = ("username", "id", "in_guild", "all_roles_coloured") + sortable_by = ("username",) + + def has_add_permission(self, request): + return False + + def has_change_permission(self, request, obj=None): + return False admin.site.register(BotSetting) diff --git a/pydis_site/apps/api/models/bot/user.py b/pydis_site/apps/api/models/bot/user.py index cd2d58b9..70a30449 100644 --- a/pydis_site/apps/api/models/bot/user.py +++ b/pydis_site/apps/api/models/bot/user.py @@ -75,3 +75,7 @@ class User(ModelReprMixin, models.Model): if not roles: return Role.objects.get(name="Developers") return max(roles) + + @property + def username(self): + return f"{self.name}#{self.discriminator:04d}" -- cgit v1.2.3 From 77c9e3ffce7992706202cf20ae3addf42c4dbf6c Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:40:24 +1000 Subject: Add return types and docstrings for new user admin changes. --- pydis_site/apps/api/admin.py | 29 ++++++++++++++++++----------- pydis_site/apps/api/models/bot/user.py | 11 ++++++++--- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 6101f88c..d77ae620 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,12 +1,13 @@ from __future__ import annotations import json -from typing import Optional +from typing import Iterable, Optional, Tuple from django import urls from django.contrib import admin +from django.db.models import QuerySet from django.http import HttpRequest -from django.utils.html import format_html +from django.utils.html import SafeString, format_html from .models import ( BotSetting, @@ -256,12 +257,13 @@ class UserTopRoleFilter(admin.SimpleListFilter): title = "Role" parameter_name = "role" - def lookups(self, request, model_admin: UserAdmin): + def lookups(self, request: HttpRequest, model_admin: UserAdmin) -> Iterable[Tuple[str, str]]: """Selectable values for viewer to filter by.""" roles = Role.objects.all() return ((r.name, r.name) for r in roles) - def queryset(self, request, queryset): + def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]: + """Query to filter the list of Users against.""" if not self.value(): return role = Role.objects.get(name=self.value()) @@ -272,20 +274,23 @@ class UserTopRoleFilter(admin.SimpleListFilter): class UserAdmin(admin.ModelAdmin): """Admin formatting for the User model.""" - def top_role_coloured(self, obj: User): + def top_role_coloured(self, user: User) -> SafeString: """Returns the top role of the user with html style matching role colour.""" return format_html( - f'{obj.top_role.name}' + '{1}', + user.top_role.colour, + user.top_role.name ) top_role_coloured.short_description = "Top Role" - def all_roles_coloured(self, obj: User): + def all_roles_coloured(self, user: User) -> SafeString: """Returns all user roles with html style matching role colours.""" - roles = Role.objects.filter(id__in=obj.roles) + roles = Role.objects.filter(id__in=user.roles) return format_html( "
".join( - f'{r.name}' for r in roles + f'{r.name}' + for r in roles ) ) @@ -297,10 +302,12 @@ class UserAdmin(admin.ModelAdmin): fields = ("username", "id", "in_guild", "all_roles_coloured") sortable_by = ("username",) - def has_add_permission(self, request): + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" return False - def has_change_permission(self, request, obj=None): + def has_change_permission(self, *args) -> bool: + """Prevent editing from django admin.""" return False diff --git a/pydis_site/apps/api/models/bot/user.py b/pydis_site/apps/api/models/bot/user.py index a8604001..afc5ba1e 100644 --- a/pydis_site/apps/api/models/bot/user.py +++ b/pydis_site/apps/api/models/bot/user.py @@ -64,7 +64,7 @@ class User(ModelReprMixin, models.Model): def __str__(self): """Returns the name and discriminator for the current user, for display purposes.""" - return f"{self.name}#{self.discriminator:0>4}" + return f"{self.name}#{self.discriminator:04d}" @property def top_role(self) -> Role: @@ -79,5 +79,10 @@ class User(ModelReprMixin, models.Model): return max(roles) @property - def username(self): - return f"{self.name}#{self.discriminator:04d}" + def username(self) -> str: + """ + Returns the display version with name and discriminator as a standard attribute. + + For usability in read-only fields such as Django Admin. + """ + return str(self) -- cgit v1.2.3 From f132c485c7ecff661a257dcdf4b528b7300e95c1 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:45:25 +1000 Subject: Fix format-style not supporting X hex casting like f-strings. --- pydis_site/apps/api/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index d77ae620..15a1ec78 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -277,8 +277,8 @@ class UserAdmin(admin.ModelAdmin): def top_role_coloured(self, user: User) -> SafeString: """Returns the top role of the user with html style matching role colour.""" return format_html( - '{1}', - user.top_role.colour, + '{1}', + f"#{user.top_role.colour:06X}", user.top_role.name ) -- cgit v1.2.3 From bbecf18704837f087e8254b657adf1c5e859dff9 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:47:32 +1000 Subject: Update Role ModelAdmin to past changes, cleanup formatting. --- pydis_site/apps/api/admin.py | 45 ++++++++++++++++++++++------------ pydis_site/apps/api/models/bot/role.py | 3 ++- 2 files changed, 31 insertions(+), 17 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 15a1ec78..d32b4911 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -222,34 +222,47 @@ class OffTopicChannelNameAdmin(admin.ModelAdmin): class RoleAdmin(admin.ModelAdmin): """Admin formatting for the Role model.""" - exclude = ("permissions", "colour") - readonly_fields = ( - "name", - "id", - "colour_with_preview", - "permissions_with_calc_link", - "position" - ) - search_fields = ("name", "id") + def coloured_name(self, role: Role) -> SafeString: + """Role name with html style colouring.""" + return format_html( + '{1}', + f"#{role.colour:06X}", + role.name + ) + + coloured_name.short_description = "Name" - def colour_with_preview(self, instance: Role) -> str: + def colour_with_preview(self, role: Role) -> SafeString: """Show colour value in both int and hex, in bolded and coloured style.""" return format_html( - "{1} / #{0}", - f"{instance.colour:06x}", - instance.colour + "{0} ({1})", + f"#{role.colour:06x}", + role.colour ) - def permissions_with_calc_link(self, instance: Role) -> str: + colour_with_preview.short_description = "Colour" + + def permissions_with_calc_link(self, role: Role) -> SafeString: """Show permissions with link to API permissions calculator page.""" return format_html( "{0}", - instance.permissions + role.permissions ) - colour_with_preview.short_description = "Colour" permissions_with_calc_link.short_description = "Permissions" + search_fields = ("name", "id") + list_display = ("coloured_name",) + fields = ("id", "name", "colour_with_preview", "permissions_with_calc_link", "position") + + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False + + def has_change_permission(self, *args) -> bool: + """Prevent editing from django admin.""" + return False + class UserTopRoleFilter(admin.SimpleListFilter): """List Filter for User list Admin page.""" diff --git a/pydis_site/apps/api/models/bot/role.py b/pydis_site/apps/api/models/bot/role.py index b23fc5f4..cfadfec4 100644 --- a/pydis_site/apps/api/models/bot/role.py +++ b/pydis_site/apps/api/models/bot/role.py @@ -22,7 +22,8 @@ class Role(ModelReprMixin, models.Model): message="Role IDs cannot be negative." ), ), - help_text="The role ID, taken from Discord." + help_text="The role ID, taken from Discord.", + verbose_name="ID" ) name = models.CharField( max_length=100, -- cgit v1.2.3 From 8ed8b9ad62fd83e93d8dd5a136b7433f7240c4c2 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 13:01:49 +1000 Subject: Add OffensiveMessage Admin model. --- pydis_site/apps/api/admin.py | 25 +++++++++++++++++++++- .../apps/api/models/bot/offensive_message.py | 9 +++++--- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index d32b4911..59cab78d 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -218,6 +218,30 @@ class OffTopicChannelNameAdmin(admin.ModelAdmin): search_fields = ("name",) +@admin.register(OffensiveMessage) +class OffensiveMessageAdmin(admin.ModelAdmin): + """Admin formatting for the OffensiveMessage model.""" + + def message_jumplink(self, message: OffensiveMessage) -> SafeString: + """Message ID hyperlinked to the direct discord jumplink.""" + return format_html( + '{1}', + message.channel_id, + message.id + ) + + message_jumplink.short_description = "Message ID" + + search_fields = ("id", "channel_id") + list_display = ("id", "channel_id", "delete_date") + fields = ("message_jumplink", "channel_id", "delete_date") + readonly_fields = ("message_jumplink", "channel_id") + + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False + + @admin.register(Role) class RoleAdmin(admin.ModelAdmin): """Admin formatting for the Role model.""" @@ -326,4 +350,3 @@ class UserAdmin(admin.ModelAdmin): admin.site.register(BotSetting) admin.site.register(DocumentationLink) -admin.site.register(OffensiveMessage) diff --git a/pydis_site/apps/api/models/bot/offensive_message.py b/pydis_site/apps/api/models/bot/offensive_message.py index 6c0e5ffb..74dab59b 100644 --- a/pydis_site/apps/api/models/bot/offensive_message.py +++ b/pydis_site/apps/api/models/bot/offensive_message.py @@ -24,7 +24,8 @@ class OffensiveMessage(ModelReprMixin, models.Model): limit_value=0, message="Message IDs cannot be negative." ), - ) + ), + verbose_name="Message ID" ) channel_id = models.BigIntegerField( help_text=( @@ -36,11 +37,13 @@ class OffensiveMessage(ModelReprMixin, models.Model): limit_value=0, message="Channel IDs cannot be negative." ), - ) + ), + verbose_name="Channel ID" ) delete_date = models.DateTimeField( help_text="The date on which the message will be auto-deleted.", - validators=(future_date_validator,) + validators=(future_date_validator,), + verbose_name="To Be Deleted" ) def __str__(self): -- cgit v1.2.3 From c9671fb8fe8004c79139bca9a50ccc8ed1b3dffc Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 13:07:35 +1000 Subject: Add Used filter for OffTopicChannelName Admin model. --- pydis_site/apps/api/admin.py | 1 + 1 file changed, 1 insertion(+) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 59cab78d..d07fc335 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -216,6 +216,7 @@ class OffTopicChannelNameAdmin(admin.ModelAdmin): """Admin formatting for the OffTopicChannelName model.""" search_fields = ("name",) + list_filter = ("used",) @admin.register(OffensiveMessage) -- cgit v1.2.3 From f4c47c976f72033f133bc90fcc8f30f291f3ad59 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 13:40:32 +1000 Subject: Update Nomination Admin model, add actor filter. --- pydis_site/apps/api/admin.py | 47 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index d07fc335..a85b4cac 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -173,18 +173,47 @@ class InfractionAdmin(admin.ModelAdmin): ) +class NominationActorFilter(admin.SimpleListFilter): + """Actor Filter for Nomination Admin list page.""" + + title = "Actor" + parameter_name = "actor" + + def lookups(self, request: HttpRequest, model_admin: NominationAdmin) -> Iterable[Tuple[int, str]]: + """Selectable values for viewer to filter by.""" + actor_ids = Nomination.objects.order_by().values_list("actor").distinct() + actors = User.objects.filter(id__in=actor_ids) + return ((a.id, a.username) for a in actors) + + def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]: + """Query to filter the list of Users against.""" + if not self.value(): + return + return queryset.filter(actor__id=self.value()) + + @admin.register(Nomination) class NominationAdmin(admin.ModelAdmin): """Admin formatting for the Nomination model.""" + search_fields = ( + "user__name", + "user__id", + "actor__name", + "actor__id", + "reason", + "end_reason" + ) + + list_filter = ("active", NominationActorFilter) + list_display = ( "user", "active", "reason", "actor", - "inserted_at", - "ended_at" ) + fields = ( "user", "active", @@ -194,6 +223,8 @@ class NominationAdmin(admin.ModelAdmin): "ended_at", "end_reason" ) + + # only allow reason fields to be edited. readonly_fields = ( "user", "active", @@ -201,14 +232,10 @@ class NominationAdmin(admin.ModelAdmin): "inserted_at", "ended_at" ) - search_fields = ( - "actor__name", - "actor__id", - "user__name", - "user__id", - "reason" - ) - list_filter = ("active",) + + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False @admin.register(OffTopicChannelName) -- cgit v1.2.3 From 5c2e750b6ff19248aaafbb0a1c12f8c7523b7273 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 14:59:30 +1000 Subject: Update DeletedMessage and LogEntry Admin models, add verbose names for Message --- pydis_site/apps/api/admin.py | 167 ++++++++++++++++-------------- pydis_site/apps/api/models/bot/message.py | 6 +- 2 files changed, 95 insertions(+), 78 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index a85b4cac..ca97512f 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -23,34 +23,77 @@ from .models import ( User ) +admin.site.site_header = "Python Discord | Administration" +admin.site.site_title = "Python Discord" + + +@admin.register(Infraction) +class InfractionAdmin(admin.ModelAdmin): + """Admin formatting for the Infraction model.""" + + fields = ( + "user", + "actor", + "type", + "reason", + "inserted_at", + "expires_at", + "active", + "hidden" + ) + readonly_fields = ( + "user", + "actor", + "type", + "inserted_at" + ) + list_display = ( + "type", + "user", + "actor", + "inserted_at", + "expires_at", + "reason", + "active", + ) + search_fields = ( + "id", + "user__name", + "user__id", + "actor__name", + "actor__id", + "reason", + "type" + ) + list_filter = ( + "type", + "hidden", + "active" + ) + @admin.register(LogEntry) class LogEntryAdmin(admin.ModelAdmin): """Allows viewing logs in the Django Admin without allowing edits.""" actions = None - list_display = ('timestamp', 'application', 'level', 'message') + list_display = ('timestamp', 'level', 'message') fieldsets = ( ('Overview', {'fields': ('timestamp', 'application', 'logger_name')}), ('Metadata', {'fields': ('level', 'module', 'line')}), ('Contents', {'fields': ('message',)}) ) - list_filter = ('application', 'level', 'timestamp') + list_filter = ('level', 'timestamp') search_fields = ('message',) - readonly_fields = ( - 'application', - 'logger_name', - 'timestamp', - 'level', - 'module', - 'line', - 'message' - ) def has_add_permission(self, request: HttpRequest) -> bool: """Deny manual LogEntry creation.""" return False + def has_change_permission(self, *args) -> bool: + """Prevent editing from django admin.""" + return False + def has_delete_permission(self, request: HttpRequest, obj: Optional[LogEntry] = None) -> bool: """Deny LogEntry deletion.""" return False @@ -60,7 +103,7 @@ class LogEntryAdmin(admin.ModelAdmin): class DeletedMessageAdmin(admin.ModelAdmin): """Admin formatting for the DeletedMessage model.""" - readonly_fields = ( + fields = ( "id", "author", "channel_id", @@ -81,96 +124,68 @@ class DeletedMessageAdmin(admin.ModelAdmin): "deletion_context__actor__id" ) - @staticmethod - def embed_data(instance: DeletedMessage) -> Optional[str]: + def embed_data(self, message: DeletedMessage) -> Optional[str]: """Format embed data in a code block for better readability.""" - if instance.embeds: + if message.embeds: return format_html( "
"
                 "{0}
", - json.dumps(instance.embeds, indent=4) + json.dumps(message.embeds, indent=4) ) + embed_data.short_description = "Embeds" + @staticmethod - def context(instance: DeletedMessage) -> str: + def context(message: DeletedMessage) -> str: """Provide full context info with a link through to context admin view.""" link = urls.reverse( "admin:api_messagedeletioncontext_change", - args=[instance.deletion_context.id] + args=[message.deletion_context.id] ) details = ( - f"Deleted by {instance.deletion_context.actor} at " - f"{instance.deletion_context.creation}" + f"Deleted by {message.deletion_context.actor} at " + f"{message.deletion_context.creation}" ) return format_html("{1}", link, details) @staticmethod - def view_full_log(instance: DeletedMessage) -> str: + def view_full_log(message: DeletedMessage) -> str: """Provide a link to the message logs for the relevant context.""" return format_html( "Click to view full context log", - instance.deletion_context.log_url + message.deletion_context.log_url ) + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False + + def has_change_permission(self, *args) -> bool: + """Prevent editing from django admin.""" + return False + + +class DeletedMessageInline(admin.TabularInline): + """Tabular Inline Admin model for Deleted Message to be viewed within Context.""" + + model = DeletedMessage + @admin.register(MessageDeletionContext) class MessageDeletionContextAdmin(admin.ModelAdmin): """Admin formatting for the MessageDeletionContext model.""" - readonly_fields = ("actor", "creation", "message_log") + fields = ("actor", "creation") + list_display = ("id", "creation", "actor") + inlines = (DeletedMessageInline,) - @staticmethod - def message_log(instance: MessageDeletionContext) -> str: - """Provide a formatted link to the message logs for the context.""" - return format_html( - "Click to see deleted message log", - instance.log_url - ) - - -@admin.register(Infraction) -class InfractionAdmin(admin.ModelAdmin): - """Admin formatting for the Infraction model.""" + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False - fields = ( - "user", - "actor", - "type", - "reason", - "inserted_at", - "expires_at", - "active", - "hidden" - ) - readonly_fields = ( - "user", - "actor", - "type", - "inserted_at" - ) - list_display = ( - "type", - "user", - "actor", - "inserted_at", - "expires_at", - "reason", - "active", - ) - search_fields = ( - "id", - "user__name", - "user__id", - "actor__name", - "actor__id", - "reason", - "type" - ) - list_filter = ( - "type", - "hidden", - "active" - ) + def has_change_permission(self, *args) -> bool: + """Prevent editing from django admin.""" + return False class NominationActorFilter(admin.SimpleListFilter): @@ -179,7 +194,7 @@ class NominationActorFilter(admin.SimpleListFilter): title = "Actor" parameter_name = "actor" - def lookups(self, request: HttpRequest, model_admin: NominationAdmin) -> Iterable[Tuple[int, str]]: + def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[Tuple[int, str]]: """Selectable values for viewer to filter by.""" actor_ids = Nomination.objects.order_by().values_list("actor").distinct() actors = User.objects.filter(id__in=actor_ids) @@ -322,7 +337,7 @@ class UserTopRoleFilter(admin.SimpleListFilter): title = "Role" parameter_name = "role" - def lookups(self, request: HttpRequest, model_admin: UserAdmin) -> Iterable[Tuple[str, str]]: + def lookups(self, request: HttpRequest, model: UserAdmin) -> Iterable[Tuple[str, str]]: """Selectable values for viewer to filter by.""" roles = Role.objects.all() return ((r.name, r.name) for r in roles) diff --git a/pydis_site/apps/api/models/bot/message.py b/pydis_site/apps/api/models/bot/message.py index f6ae55a5..ff06de21 100644 --- a/pydis_site/apps/api/models/bot/message.py +++ b/pydis_site/apps/api/models/bot/message.py @@ -21,7 +21,8 @@ class Message(ModelReprMixin, models.Model): limit_value=0, message="Message IDs cannot be negative." ), - ) + ), + verbose_name="ID" ) author = models.ForeignKey( User, @@ -38,7 +39,8 @@ class Message(ModelReprMixin, models.Model): limit_value=0, message="Channel IDs cannot be negative." ), - ) + ), + verbose_name="Channel ID" ) content = models.CharField( max_length=2_000, -- cgit v1.2.3 From c6e80a97bb9e40dc404e274d6ebc419b410a2b66 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 15:16:00 +1000 Subject: Add DocumentationLink and BotSetting Admin models. --- pydis_site/apps/api/admin.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index ca97512f..7b571005 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -27,6 +27,28 @@ admin.site.site_header = "Python Discord | Administration" admin.site.site_title = "Python Discord" +@admin.register(BotSetting) +class BotSettingAdmin(admin.ModelAdmin): + """Admin formatting for the BotSetting model.""" + + fields = ("name", "data") + list_display = ("name",) + + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False + + +@admin.register(DocumentationLink) +class DocumentationLinkAdmin(admin.ModelAdmin): + """Admin formatting for the DocumentationLink model.""" + + fields = ("package", "base_url", "inventory_url") + list_display = ("package", "base_url", "inventory_url") + list_editable = ("base_url", "inventory_url") + search_fields = ("package",) + + @admin.register(Infraction) class InfractionAdmin(admin.ModelAdmin): """Admin formatting for the Infraction model.""" @@ -71,6 +93,10 @@ class InfractionAdmin(admin.ModelAdmin): "active" ) + def has_add_permission(self, *args) -> bool: + """Prevent adding from django admin.""" + return False + @admin.register(LogEntry) class LogEntryAdmin(admin.ModelAdmin): @@ -124,6 +150,8 @@ class DeletedMessageAdmin(admin.ModelAdmin): "deletion_context__actor__id" ) + list_display = ("id", "author", "channel_id") + def embed_data(self, message: DeletedMessage) -> Optional[str]: """Format embed data in a code block for better readability.""" if message.embeds: @@ -389,7 +417,3 @@ class UserAdmin(admin.ModelAdmin): def has_change_permission(self, *args) -> bool: """Prevent editing from django admin.""" return False - - -admin.site.register(BotSetting) -admin.site.register(DocumentationLink) -- cgit v1.2.3 From 8af9e190f69484efb5fe3b5910a9125738e0ee84 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 15:22:48 +1000 Subject: Declutter Infraction admin list, add actor list filter. --- pydis_site/apps/api/admin.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 7b571005..ff9afc46 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -49,6 +49,25 @@ class DocumentationLinkAdmin(admin.ModelAdmin): search_fields = ("package",) +class InfractionActorFilter(admin.SimpleListFilter): + """Actor Filter for Infraction Admin list page.""" + + title = "Actor" + parameter_name = "actor" + + def lookups(self, request: HttpRequest, model: NominationAdmin) -> Iterable[Tuple[int, str]]: + """Selectable values for viewer to filter by.""" + actor_ids = Infraction.objects.order_by().values_list("actor").distinct() + actors = User.objects.filter(id__in=actor_ids) + return ((a.id, a.username) for a in actors) + + def queryset(self, request: HttpRequest, queryset: QuerySet) -> Optional[QuerySet]: + """Query to filter the list of Users against.""" + if not self.value(): + return + return queryset.filter(actor__id=self.value()) + + @admin.register(Infraction) class InfractionAdmin(admin.ModelAdmin): """Admin formatting for the Infraction model.""" @@ -67,16 +86,16 @@ class InfractionAdmin(admin.ModelAdmin): "user", "actor", "type", - "inserted_at" + "inserted_at", + "active", + "hidden" ) list_display = ( "type", + "active", "user", - "actor", "inserted_at", - "expires_at", "reason", - "active", ) search_fields = ( "id", @@ -90,7 +109,8 @@ class InfractionAdmin(admin.ModelAdmin): list_filter = ( "type", "hidden", - "active" + "active", + InfractionActorFilter ) def has_add_permission(self, *args) -> bool: -- cgit v1.2.3 From 2c4b3451b3349d098ceebce774b08946b5e378d5 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Fri, 18 Sep 2020 15:24:54 +1000 Subject: Don't allow expiry to be editable, due to pending bot tasks unsyncing --- pydis_site/apps/api/admin.py | 1 + 1 file changed, 1 insertion(+) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index ff9afc46..6267b7a8 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -87,6 +87,7 @@ class InfractionAdmin(admin.ModelAdmin): "actor", "type", "inserted_at", + "expires_at", "active", "hidden" ) -- cgit v1.2.3 From dafca0fee8ac618ee9aab5ce8a1d7c34aafc3a05 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Sep 2020 02:06:11 +1000 Subject: Change UserTopRoleFilter to UserRoleFilter. Filter checks for general role membership instead of only those who have the selected role as top role. Noticed during development that we'd not be able to filter to show all Helpers otherwise, as some Helpers have different top roles such as Core Dev that wouldn't give immediately obvious behaviour to user expectations. --- pydis_site/apps/api/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 6267b7a8..733a056d 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -380,7 +380,7 @@ class RoleAdmin(admin.ModelAdmin): return False -class UserTopRoleFilter(admin.SimpleListFilter): +class UserRoleFilter(admin.SimpleListFilter): """List Filter for User list Admin page.""" title = "Role" @@ -426,7 +426,7 @@ class UserAdmin(admin.ModelAdmin): all_roles_coloured.short_description = "All Roles" search_fields = ("name", "id", "roles") - list_filter = (UserTopRoleFilter, "in_guild") + list_filter = (UserRoleFilter, "in_guild") list_display = ("username", "top_role_coloured", "in_guild") fields = ("username", "id", "in_guild", "all_roles_coloured") sortable_by = ("username",) -- cgit v1.2.3 From d39eeb9b7e936f264abcfbb998453179ef8556f5 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Sep 2020 06:27:16 +1000 Subject: Change Infraction admin to use fieldsets for better grouping of info. --- pydis_site/apps/api/admin.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 733a056d..c3f1179e 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -72,15 +72,11 @@ class InfractionActorFilter(admin.SimpleListFilter): class InfractionAdmin(admin.ModelAdmin): """Admin formatting for the Infraction model.""" - fields = ( - "user", - "actor", - "type", - "reason", - "inserted_at", - "expires_at", - "active", - "hidden" + fieldsets = ( + ("Members", {"fields": ("user", "actor")}), + ("Action", {"fields": ("type", "hidden", "active")}), + ("Dates", {"fields": ("inserted_at", "expires_at")}), + ("Reason", {"fields": ("reason",)}), ) readonly_fields = ( "user", -- cgit v1.2.3 From a105de702d2f64a66acfc2f06a3b994cd46a5c3e Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Sep 2020 07:06:40 +1000 Subject: Remove delete permission for bot settings admin. I'm unable to see any cases where this would be wanted, and instead accidental deletion would result in the system possibly breaking, as we are unable to add the setting again to replace it if it got removed. The name has also set to read only in item view, to prevent renames, effectively doing the same thing as deleting it. --- pydis_site/apps/api/admin.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'pydis_site/apps/api/admin.py') diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index c3f1179e..5093e605 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -33,11 +33,16 @@ class BotSettingAdmin(admin.ModelAdmin): fields = ("name", "data") list_display = ("name",) + readonly_fields = ("name",) def has_add_permission(self, *args) -> bool: """Prevent adding from django admin.""" return False + def has_delete_permission(self, *args) -> bool: + """Prevent deleting from django admin.""" + return False + @admin.register(DocumentationLink) class DocumentationLinkAdmin(admin.ModelAdmin): -- cgit v1.2.3