diff --git a/backend/sophon/core/admin.py b/backend/sophon/core/admin.py index fc1bdd6..41e3d54 100644 --- a/backend/sophon/core/admin.py +++ b/backend/sophon/core/admin.py @@ -9,6 +9,25 @@ class SophonAdmin(admin.ModelAdmin): """ +@admin.register(models.SophonInstanceDetails) +class SophonInstanceDetails(SophonAdmin): + list_display = ( + "name", + "id", + "theme", + ) + + def get_actions(self, request): + # Disable all actions + return {} + + def has_add_permission(self, request): + return False + + def has_delete_permission(self, request, obj=None): + return False + + @admin.register(models.ResearchGroup) class ResearchGroupAdmin(SophonAdmin): list_display = ( diff --git a/backend/sophon/core/migrations/0004_sophoninstancedetails.py b/backend/sophon/core/migrations/0004_sophoninstancedetails.py new file mode 100644 index 0000000..52ecb25 --- /dev/null +++ b/backend/sophon/core/migrations/0004_sophoninstancedetails.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.7 on 2021-09-20 15:35 + +from django.db import migrations, models + + +def create_instance_details(apps, schema_editor): + db = schema_editor.connection.alias + # noinspection PyPep8Naming + SophonInstanceDetails = apps.get_model("core", "SophonInstanceDetails") + SophonInstanceDetails.objects.create() + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0003_auto_20210901_1529'), + ] + + operations = [ + migrations.CreateModel( + name='SophonInstanceDetails', + fields=[ + ('id', models.IntegerField(choices=[(1, 'This')], default=1, primary_key=True, serialize=False, verbose_name='Instance details ID')), + ('name', models.CharField(default='Sophon', help_text='The name of this Sophon instance.', max_length=128, verbose_name='Instance name')), + ('description', models.TextField(blank=True, help_text='A description of this Sophon instance, to be displayed on its home page.', null=True, verbose_name='Description')), + ('theme', models.CharField(choices=[('sophon', 'The Sophonity'), ('paper', 'Sheet of Paper'), ('royalblue', 'Royal Blue'), ('hacker', 'Hacker Terminal')], default='sophon', help_text='The bluelib theme of the Sophon instance.', max_length=32, verbose_name='Theme')), + ], + options={ + 'abstract': False, + }, + ), + migrations.RunPython(create_instance_details), + ] diff --git a/backend/sophon/core/models.py b/backend/sophon/core/models.py index 6b05b94..fcc3e40 100644 --- a/backend/sophon/core/models.py +++ b/backend/sophon/core/models.py @@ -157,6 +157,90 @@ class SophonModel(models.Model): return CreateSerializer +class SophonInstanceDetails(SophonModel): + """ + Details about the Sophon instance itself. + + Only one object of this type should exist in a database. + """ + + class Meta: + verbose_name = "Sophon instance details" + verbose_name_plural = "Sophon instance details" + + id = models.IntegerField( + "Instance details ID", + primary_key=True, + choices=( + (1, "This"), + ), + default=1, + ) + + name = models.CharField( + "Instance name", + help_text="The name of this Sophon instance.", + default="Sophon", + max_length=128, + ) + + description = models.TextField( + "Description", + help_text="A description of this Sophon instance, to be displayed on its home page.", + blank=True, null=True, + ) + + theme = models.CharField( + "Theme", + help_text="The bluelib theme of the Sophon instance.", + choices=( + ("sophon", "The Sophonity"), + ("paper", "Sheet of Paper"), + ("royalblue", "Royal Blue"), + ("hacker", "Hacker Terminal"), + ), + default="sophon", + max_length=32, + ) + + @classmethod + def get_fields(cls) -> set[str]: + return { + "name", + "description", + "theme", + } + + @classmethod + def get_editable_fields(cls) -> set[str]: + return { + "name", + "description", + "theme", + } + + def can_edit(self, user: User) -> bool: + return user.is_superuser + + @classmethod + def get_administrable_fields(cls) -> set[str]: + return set() + + def can_admin(self, user: User) -> bool: + return user.is_superuser + + @classmethod + def get_creation_fields(cls) -> set[str]: + return { + "name", + "description", + "theme", + } + + def __repr__(self): + return self.name + + # noinspection PyAbstractClass class SophonGroupModel(SophonModel): """ diff --git a/backend/sophon/core/urls.py b/backend/sophon/core/urls.py index 2c3d59f..477bf4d 100644 --- a/backend/sophon/core/urls.py +++ b/backend/sophon/core/urls.py @@ -11,5 +11,6 @@ router.register("users", views.UserViewSet, basename="user") urlpatterns = [ path("", include(router.urls)), - path("version", views.VersionView.as_view()) + path("version", views.VersionView.as_view()), + path("instance", views.SophonInstanceDetailsView.as_view()), ] diff --git a/backend/sophon/core/views.py b/backend/sophon/core/views.py index a8b3a12..05bf32f 100644 --- a/backend/sophon/core/views.py +++ b/backend/sophon/core/views.py @@ -288,3 +288,16 @@ class VersionView(APIView): def get(self, request, format=None): version = pkg_resources.get_distribution("sophon").version return Response(version, status=s.HTTP_200_OK) + + +class SophonInstanceDetailsView(APIView): + """ + Get the details of this Sophon instance. + """ + + # noinspection PyMethodMayBeStatic,PyUnusedLocal + def get(self, request, format=None): + details = models.SophonInstanceDetails.objects.get() + Serializer = details.get_view_serializer() + serializer = Serializer(instance=details) + return Response(serializer.data, status=s.HTTP_200_OK)