From 1edb51c67b84593587a55454b060dc1b5b588477 Mon Sep 17 00:00:00 2001 From: Sam Onaisi Date: Mon, 26 Jan 2026 17:17:44 +0100 Subject: [PATCH 1/2] style: Set Jazzmin theme and icons --- ...jectuserattachmentfile_options_and_more.py | 21 ++++++++++ apps/files/models.py | 8 ++++ projects/settings/base.py | 39 ++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 apps/files/migrations/0005_alter_projectuserattachmentfile_options_and_more.py diff --git a/apps/files/migrations/0005_alter_projectuserattachmentfile_options_and_more.py b/apps/files/migrations/0005_alter_projectuserattachmentfile_options_and_more.py new file mode 100644 index 00000000..71b065a9 --- /dev/null +++ b/apps/files/migrations/0005_alter_projectuserattachmentfile_options_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 5.2.10 on 2026-01-26 16:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("files", "0004_projectuserattachmentlink_projectuserattachmentfile_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="projectuserattachmentfile", + options={"verbose_name": "User file", "verbose_name_plural": "User files"}, + ), + migrations.AlterModelOptions( + name="projectuserattachmentlink", + options={"verbose_name": "User link", "verbose_name_plural": "User links"}, + ), + ] diff --git a/apps/files/models.py b/apps/files/models.py index b67010f8..53e38142 100644 --- a/apps/files/models.py +++ b/apps/files/models.py @@ -459,6 +459,10 @@ def get_owner(self): def is_owned_by(self, user: "ProjectUser") -> bool: return user == self.get_owner() + class Meta: + verbose_name = "User file" + verbose_name_plural = "User files" + class ProjectUserAttachmentLink(HasAutoTranslatedFields, HasOwner, models.Model): """ @@ -491,3 +495,7 @@ def get_owner(self): def is_owned_by(self, user: "ProjectUser") -> bool: return user == self.get_owner() + + class Meta: + verbose_name = "User link" + verbose_name_plural = "User links" diff --git a/projects/settings/base.py b/projects/settings/base.py index 396b387f..1424ce4b 100644 --- a/projects/settings/base.py +++ b/projects/settings/base.py @@ -703,14 +703,51 @@ "site_title": "Projects", "welcome_sign": "", "show_ui_builder": DEBUG, - "theme": "flatly", "custom_css": "styles/admin.css", + "icons": { + "accounts.ProjectUser": "fa-solid fa-user", + "accounts.PeopleGroup": "fa-solid fa-users", + "auth.Group": "fa-solid fa-users-gear", + "auth.Permission": "fa-solid fa-key", + "crisalid.CrisalidConfig": "fa-solid fa-cogs", + "crisalid.Document": "fa-solid fa-file-lines", + "crisalid.Identifier": "fa-solid fa-id-badge", + "crisalid.Researcher": "fa-solid fa-user-tie", + "deploys.PostDeployProcess": "fa-solid fa-bars-progress", + "emailing.Email": "fa-solid fa-envelope", + "files.Image": "fa-solid fa-image", + "files.ProjectUserAttachmentFile": "fa-solid fa-paperclip", + "files.ProjectUserAttachmentLink": "fa-solid fa-link", + "google.GoogleAccount": "fa-brands fa-google", + "google.GoogleGroup": "fa-solid fa-group-arrows-rotate", + "google.GoogleSyncErrors": "fa-solid fa-triangle-exclamation", + "keycloak.IdentityProvider": "fa-solid fa-shield-halved", + "keycloak.KeycloakAccount": "fa-solid fa-id-card", + "mistral.DocumentEmbedding": "fa-solid fa-bezier-curve", + "mistral.EmbeddingError": "fa-solid fa-triangle-exclamation", + "mistral.ProjectEmbedding": "fa-solid fa-bezier-curve", + "mistral.UserEmbedding": "fa-solid fa-bezier-curve", + "mixpanel.MixpanelEvent": "fa-solid fa-eye", + "notifications.Notification": "fa-solid fa-bell", + "organizations.Organization": "fa-solid fa-building", + "organizations.ProjectCategory": "fa-solid fa-tags", + "organizations.Template": "fa-solid fa-clone", + "projects.BlogEntry": "fa-solid fa-rss", + "projects.Project": "fa-solid fa-diagram-project", + "skills.Skill": "fa-solid fa-lightbulb", + "skills.TagClassification": "fa-solid fa-folder", + "skills.Tag": "fa-solid fa-tag", + }, } JAZZMIN_UI_TWEAKS = { "navbar_small_text": True, "footer_small_text": True, "body_small_text": True, "brand_small_text": True, + "theme": "cyborg", + "dark_mode_theme": "cyborg", + "navbar_fixed": True, + "navbar": "navbar-dark navbar-gray-dark", } ############## From 5ddbf1980bee3fd96254eecfbd15b732ce6b21f3 Mon Sep 17 00:00:00 2001 From: Sam Onaisi Date: Wed, 4 Feb 2026 15:16:24 +0100 Subject: [PATCH 2/2] fix 500 error on admin failed login --- apps/accounts/authentication.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/accounts/authentication.py b/apps/accounts/authentication.py index 53b418e4..8b55a4ae 100644 --- a/apps/accounts/authentication.py +++ b/apps/accounts/authentication.py @@ -12,6 +12,7 @@ from apps.commons.mixins import HasPermissionsSetup from apps.invitations.models import Invitation +from services.keycloak.exceptions import KeycloakApiAuthenticationError from services.keycloak.interface import KeycloakService from .exceptions import InactiveUserError, InvalidInvitationError, InvalidTokenError @@ -41,7 +42,10 @@ def for_user(cls, user: "ProjectUser"): class AdminAuthentication(ModelBackend): def authenticate(self, request, username=None, password=None): - token = KeycloakService.get_token_for_user(username, password) + try: + token = KeycloakService.get_token_for_user(username, password) + except KeycloakApiAuthenticationError: + return None validated_token = BearerToken(token["access_token"]) user_id = validated_token[api_settings.USER_ID_CLAIM] try: