From 6bd2ea4a1d50ea1cecbd4b3a996523425efbd65b Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 19:45:34 +0200 Subject: Allow viewing log entries in the Django Admin. --- pydis_site/apps/api/admin.py | 31 +++++++++++++++++++++---- pydis_site/apps/api/models/log_entry.py | 13 +++++++++++ pydis_site/apps/api/tests/test_models.py | 40 +++++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index c3784317..2c41d624 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,18 +1,39 @@ from django.contrib import admin from .models import ( - BotSetting, DeletedMessage, - DocumentationLink, Infraction, - MessageDeletionContext, Nomination, - OffTopicChannelName, Role, - Tag, User + BotSetting, + DeletedMessage, + DocumentationLink, + Infraction, + LogEntry, + MessageDeletionContext, + Nomination, + OffTopicChannelName, + Role, + Tag, + User ) +class LogEntryAdmin(admin.ModelAdmin): + """Allows viewing logs in the Django Admin without allowing edits.""" + + readonly_fields = ( + 'application', + 'logger_name', + 'timestamp', + 'level', + 'module', + 'line', + 'message' + ) + + admin.site.register(BotSetting) admin.site.register(DeletedMessage) admin.site.register(DocumentationLink) admin.site.register(Infraction) +admin.site.register(LogEntry, LogEntryAdmin) admin.site.register(MessageDeletionContext) admin.site.register(Nomination) admin.site.register(OffTopicChannelName) diff --git a/pydis_site/apps/api/models/log_entry.py b/pydis_site/apps/api/models/log_entry.py index acd7953a..55a022d7 100644 --- a/pydis_site/apps/api/models/log_entry.py +++ b/pydis_site/apps/api/models/log_entry.py @@ -1,9 +1,15 @@ +import textwrap + from django.db import models from django.utils import timezone from pydis_site.apps.api.models.utils import ModelReprMixin +# Used to shorten the timestamp length in the Django Admin. +TIMESTAMP_WITH_SECONDS_LENGTH = len('YYYY-MM-DD HH:MM:SS') + + class LogEntry(ModelReprMixin, models.Model): """A log entry generated by one of the PyDis applications.""" @@ -48,3 +54,10 @@ class LogEntry(ModelReprMixin, models.Model): message = models.TextField( help_text="The textual content of the log line." ) + + def __str__(self) -> str: + timestamp = str(self.timestamp)[:TIMESTAMP_WITH_SECONDS_LENGTH] + message = textwrap.shorten(self.message, width=140) + level = self.level[:4].upper() + + return f'{timestamp} | {self.application} | {level} | {message}' diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py index 2120b056..6011ba21 100644 --- a/pydis_site/apps/api/tests/test_models.py +++ b/pydis_site/apps/api/tests/test_models.py @@ -1,13 +1,21 @@ -from datetime import datetime as dt, timezone +from datetime import datetime as dt from django.test import SimpleTestCase +from django.utils import timezone from ..models import ( - DeletedMessage, DocumentationLink, - Infraction, Message, - MessageDeletionContext, ModelReprMixin, - OffTopicChannelName, Reminder, - Role, Tag, User + DeletedMessage, + DocumentationLink, + Infraction, + LogEntry, + Message, + MessageDeletionContext, + ModelReprMixin, + OffTopicChannelName, + Reminder, + Role, + Tag, + User ) @@ -25,6 +33,26 @@ class ReprMixinTests(SimpleTestCase): self.assertEqual(repr(self.klass), expected) +class LogEntryStringDunderTests(SimpleTestCase): + def setUp(self): + self.entry = LogEntry( + application='bot', + logger_name='bot.rules.antispam', + timestamp=timezone.now(), + level='debug', + module='bot.rules.antispam', + line=44, + message="One day computers might become useful." + ) + + def test_str_shows_content(self): + tokens = str(self.entry).split(' | ') + _timestamp, app, level, message = tokens + self.assertEqual(app, 'bot') + self.assertEqual(level, 'DEBU'), + self.assertEqual(message, "One day computers might become useful.") + + class StringDunderMethodTests(SimpleTestCase): def setUp(self): self.objects = ( -- cgit v1.2.3 From 87105f2c31e5384428e9f44a146b60d2f95fb67b Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 19:49:07 +0200 Subject: Pluralize properly. --- .../migrations/0044_add_plural_name_for_log_entry.py | 17 +++++++++++++++++ pydis_site/apps/api/models/log_entry.py | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py diff --git a/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py b/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py new file mode 100644 index 00000000..6f388179 --- /dev/null +++ b/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.3 on 2019-10-11 17:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0043_infraction_hidden_warnings_to_notes'), + ] + + operations = [ + migrations.AlterModelOptions( + name='logentry', + options={'verbose_name_plural': 'Log entries'}, + ), + ] diff --git a/pydis_site/apps/api/models/log_entry.py b/pydis_site/apps/api/models/log_entry.py index 55a022d7..cb7275f9 100644 --- a/pydis_site/apps/api/models/log_entry.py +++ b/pydis_site/apps/api/models/log_entry.py @@ -61,3 +61,8 @@ class LogEntry(ModelReprMixin, models.Model): level = self.level[:4].upper() return f'{timestamp} | {self.application} | {level} | {message}' + + class Meta: + """Customizes the default generated plural name to valid English.""" + + verbose_name_plural = 'Log entries' -- cgit v1.2.3 From 6fa19e09823680c93acd795c52f6f511a1ae9663 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 19:53:21 +0200 Subject: Use multi-column output from Django. --- pydis_site/apps/api/admin.py | 1 + pydis_site/apps/api/models/log_entry.py | 11 ----------- pydis_site/apps/api/tests/test_models.py | 21 --------------------- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 2c41d624..8a9b6051 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -18,6 +18,7 @@ from .models import ( class LogEntryAdmin(admin.ModelAdmin): """Allows viewing logs in the Django Admin without allowing edits.""" + list_display = ('timestamp', 'application', 'level', 'message') readonly_fields = ( 'application', 'logger_name', diff --git a/pydis_site/apps/api/models/log_entry.py b/pydis_site/apps/api/models/log_entry.py index cb7275f9..9717c700 100644 --- a/pydis_site/apps/api/models/log_entry.py +++ b/pydis_site/apps/api/models/log_entry.py @@ -6,10 +6,6 @@ from django.utils import timezone from pydis_site.apps.api.models.utils import ModelReprMixin -# Used to shorten the timestamp length in the Django Admin. -TIMESTAMP_WITH_SECONDS_LENGTH = len('YYYY-MM-DD HH:MM:SS') - - class LogEntry(ModelReprMixin, models.Model): """A log entry generated by one of the PyDis applications.""" @@ -55,13 +51,6 @@ class LogEntry(ModelReprMixin, models.Model): help_text="The textual content of the log line." ) - def __str__(self) -> str: - timestamp = str(self.timestamp)[:TIMESTAMP_WITH_SECONDS_LENGTH] - message = textwrap.shorten(self.message, width=140) - level = self.level[:4].upper() - - return f'{timestamp} | {self.application} | {level} | {message}' - class Meta: """Customizes the default generated plural name to valid English.""" diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py index 6011ba21..6a3ef085 100644 --- a/pydis_site/apps/api/tests/test_models.py +++ b/pydis_site/apps/api/tests/test_models.py @@ -7,7 +7,6 @@ from ..models import ( DeletedMessage, DocumentationLink, Infraction, - LogEntry, Message, MessageDeletionContext, ModelReprMixin, @@ -33,26 +32,6 @@ class ReprMixinTests(SimpleTestCase): self.assertEqual(repr(self.klass), expected) -class LogEntryStringDunderTests(SimpleTestCase): - def setUp(self): - self.entry = LogEntry( - application='bot', - logger_name='bot.rules.antispam', - timestamp=timezone.now(), - level='debug', - module='bot.rules.antispam', - line=44, - message="One day computers might become useful." - ) - - def test_str_shows_content(self): - tokens = str(self.entry).split(' | ') - _timestamp, app, level, message = tokens - self.assertEqual(app, 'bot') - self.assertEqual(level, 'DEBU'), - self.assertEqual(message, "One day computers might become useful.") - - class StringDunderMethodTests(SimpleTestCase): def setUp(self): self.objects = ( -- cgit v1.2.3 From 8309c94fb2b79ee87b1c2c66533eeb7924e9062f Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 19:57:21 +0200 Subject: Group fieldsets. --- pydis_site/apps/api/admin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 8a9b6051..2a44eb7a 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -19,6 +19,11 @@ class LogEntryAdmin(admin.ModelAdmin): """Allows viewing logs in the Django Admin without allowing edits.""" list_display = ('timestamp', 'application', 'level', 'message') + fieldsets = ( + ('Overview', {'fields': ('timestamp', 'application', 'logger_name')}), + ('Metadata', {'fields': ('level', 'module', 'line')}), + ('Contents', {'fields': ('message',)}) + ) readonly_fields = ( 'application', 'logger_name', -- cgit v1.2.3 From 195d66b310c34e2b0f548a5c0cb1d8d1d69f1f76 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 20:07:41 +0200 Subject: Remove old import. --- pydis_site/apps/api/models/log_entry.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pydis_site/apps/api/models/log_entry.py b/pydis_site/apps/api/models/log_entry.py index 9717c700..488af48e 100644 --- a/pydis_site/apps/api/models/log_entry.py +++ b/pydis_site/apps/api/models/log_entry.py @@ -1,5 +1,3 @@ -import textwrap - from django.db import models from django.utils import timezone -- cgit v1.2.3 From f1584220c5ecdcddb11650fe2764dd47075369fd Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 20:49:51 +0200 Subject: Allow filtering through metadata, and searching by message. --- pydis_site/apps/api/admin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 2a44eb7a..d82ce186 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -24,6 +24,8 @@ class LogEntryAdmin(admin.ModelAdmin): ('Metadata', {'fields': ('level', 'module', 'line')}), ('Contents', {'fields': ('message',)}) ) + list_filter = ('application', 'level', 'timestamp') + search_fields = ('message',) readonly_fields = ( 'application', 'logger_name', -- cgit v1.2.3 From b3aa11bfff29ec1083fbe6217f5f6a499a282bd3 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 21:41:22 +0200 Subject: Deny `LogEntry` deletion. --- pydis_site/apps/api/admin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index d82ce186..ed483897 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -18,6 +18,7 @@ from .models import ( class LogEntryAdmin(admin.ModelAdmin): """Allows viewing logs in the Django Admin without allowing edits.""" + actions = None list_display = ('timestamp', 'application', 'level', 'message') fieldsets = ( ('Overview', {'fields': ('timestamp', 'application', 'logger_name')}), @@ -36,6 +37,10 @@ class LogEntryAdmin(admin.ModelAdmin): 'message' ) + def has_delete_permission(self, request, obj=None) -> bool: + """Deny LogEntry deletion.""" + return False + admin.site.register(BotSetting) admin.site.register(DeletedMessage) -- cgit v1.2.3 From 879d807cf06f52dd54b859ac4610f88e922111a3 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 21:46:29 +0200 Subject: Improve formatting for `has_delete_permission`, typespec. --- pydis_site/apps/api/admin.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index ed483897..2600b410 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -1,4 +1,7 @@ +from typing import Optional + from django.contrib import admin +from django.http import HttpRequest from .models import ( BotSetting, @@ -37,7 +40,11 @@ class LogEntryAdmin(admin.ModelAdmin): 'message' ) - def has_delete_permission(self, request, obj=None) -> bool: + def has_delete_permission( + self, + request: HttpRequest, + obj: Optional[LogEntry] = None + ) -> bool: """Deny LogEntry deletion.""" return False -- cgit v1.2.3 From 673cc3bd89056d288451085488ae6f1f67cc1e21 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 21:47:58 +0200 Subject: Resolve migration merge conflicts. --- .../migrations/0044_add_plural_name_for_log_entry.py | 17 ----------------- .../migrations/0045_add_plural_name_for_log_entry.py | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py create mode 100644 pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py diff --git a/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py b/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py deleted file mode 100644 index 6f388179..00000000 --- a/pydis_site/apps/api/migrations/0044_add_plural_name_for_log_entry.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.3 on 2019-10-11 17:48 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0043_infraction_hidden_warnings_to_notes'), - ] - - operations = [ - migrations.AlterModelOptions( - name='logentry', - options={'verbose_name_plural': 'Log entries'}, - ), - ] diff --git a/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py b/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py new file mode 100644 index 00000000..6b9933d8 --- /dev/null +++ b/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.3 on 2019-10-11 17:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0044_migrate_nominations_from_infraction_to_nomination_model'), + ] + + operations = [ + migrations.AlterModelOptions( + name='logentry', + options={'verbose_name_plural': 'Log entries'}, + ), + ] -- cgit v1.2.3 From 749f1576f3912846d99ccc59e2ba4acb847a737a Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Fri, 11 Oct 2019 21:57:05 +0200 Subject: Deny manual `LogEntry` creation. --- pydis_site/apps/api/admin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py index 2600b410..059f52eb 100644 --- a/pydis_site/apps/api/admin.py +++ b/pydis_site/apps/api/admin.py @@ -40,6 +40,10 @@ class LogEntryAdmin(admin.ModelAdmin): 'message' ) + def has_add_permission(self, request: HttpRequest) -> bool: + """Deny manual LogEntry creation.""" + return False + def has_delete_permission( self, request: HttpRequest, -- cgit v1.2.3