From 81399dd2e4814be5b3a95fb7d1621f15d9ffea0e Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 10:29:53 +0200 Subject: [PATCH 1/3] Only show frontend user apps if they are enabled. --- modoboa/core/api/v2/viewsets.py | 55 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/modoboa/core/api/v2/viewsets.py b/modoboa/core/api/v2/viewsets.py index e6e2fae95..ef80c673f 100644 --- a/modoboa/core/api/v2/viewsets.py +++ b/modoboa/core/api/v2/viewsets.py @@ -1,5 +1,6 @@ """Core API v2 viewsets.""" +from django.conf import settings from django.utils.translation import gettext as _ from django_otp.plugins.otp_static.models import StaticDevice, StaticToken @@ -166,29 +167,37 @@ class AccountViewSet(core_v1_viewsets.AccountViewSet): } ) if hasattr(request.user, "mailbox"): - apps += [ - { - "name": "calendar", - "label": _("Calendars"), - "icon": "mdi-calendar", - "description": _("Calendar"), - "url": "/user/calendars", - }, - { - "name": "contacts", - "label": _("Contacts"), - "icon": "mdi-contacts-outline", - "description": _("Address book"), - "url": "/user/contacts", - }, - { - "name": "webmail", - "label": _("Webmail"), - "icon": "mdi-at", - "description": _("Webmail"), - "url": "/user/webmail", - }, - ] + if "modoboa.contacts" in settings.MODOBOA_APPS: + apps += [ + { + "name": "contacts", + "label": _("Contacts"), + "icon": "mdi-contacts-outline", + "description": _("Address book"), + "url": "/user/contacts", + } + ] + if "modoboa.calendars" in settings.MODOBOA_APPS: + apps += [ + { + "name": "calendar", + "label": _("Calendars"), + "icon": "mdi-calendar", + "description": _("Calendar"), + "url": "/user/calendars", + } + ] + if "modoboa.webmail" in settings.MODOBOA_APPS: + apps += [ + { + "name": "webmail", + "label": _("Webmail"), + "icon": "mdi-at", + "description": _("Webmail"), + "url": "/user/webmail", + } + ] + apps += exts_pool.get_available_apps() serializer = serializers.ModoboaApplicationSerializer(apps, many=True) return response.Response(serializer.data) From b097b868aa0df112e29e0d7293331e5da78b22ce Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 11:07:08 +0200 Subject: [PATCH 2/3] Added test --- modoboa/core/api/v2/tests.py | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/modoboa/core/api/v2/tests.py b/modoboa/core/api/v2/tests.py index 9d2588631..6612c04b1 100644 --- a/modoboa/core/api/v2/tests.py +++ b/modoboa/core/api/v2/tests.py @@ -183,6 +183,13 @@ class ParametersAPITestCase(ModoAPITestCase): class AccountViewSetTestCase(ModoAPITestCase): + + @classmethod + def setUpTestData(cls): # NOQA:N802 + """Create test data.""" + super().setUpTestData() + factories.populate_database() + def test_me(self): url = reverse("v2:account-me") resp = self.client.get(url) @@ -261,6 +268,57 @@ class AccountViewSetTestCase(ModoAPITestCase): user.refresh_from_db() self.assertEqual(user.totp_enabled, False) + def test_available_applications(self): + url = reverse("v2:account-available-applications") + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + # admin -> only 1 app. + self.assertEqual(len(resp.json()), 1) + + # Domain admin with mailbox + dadmin = models.User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(len(resp.json()), 4) + + # Simple user + user = models.User.objects.get(username="user@test.com") + self.authenticate_user(user) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(len(resp.json()), 3) + + @override_settings( + MODOBOA_APPS=[ + "modoboa", + "modoboa.core", + "modoboa.lib", + "modoboa.admin", + "modoboa.transport", + "modoboa.relaydomains", + "modoboa.limits", + "modoboa.parameters", + "modoboa.dnstools", + "modoboa.policyd", + "modoboa.maillog", + "modoboa.pdfcredentials", + "modoboa.dmarc", + "modoboa.imap_migration", + "modoboa.autoreply", + "modoboa.sievefilters", + "modoboa.rspamd", + ] + ) + def test_available_applications_with_disabled(self): + url = reverse("v2:account-available-applications") + # Domain admin with mailbox + dadmin = models.User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(len(resp.json()), 1) + class PasswordResetTestCase(AccountViewSetTestCase): def __init__(self, *args, **kwargs): From f4c4c230cd186475bea1db3758052210648763c6 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 31 Jul 2025 11:37:24 +0200 Subject: [PATCH 3/3] Fixed test --- modoboa/core/api/v2/tests.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/modoboa/core/api/v2/tests.py b/modoboa/core/api/v2/tests.py index 6612c04b1..592d96f4a 100644 --- a/modoboa/core/api/v2/tests.py +++ b/modoboa/core/api/v2/tests.py @@ -19,7 +19,6 @@ from modoboa.admin import ( from modoboa.core import models, constants from modoboa.core.tests import utils from modoboa.lib.tests import ModoAPITestCase -from rest_framework.authtoken.models import Token DOVEADM_TEST_PATH = utils.get_doveadm_test_path() DOVECOT_USER = getpass.getuser() @@ -326,15 +325,6 @@ class PasswordResetTestCase(AccountViewSetTestCase): self.id = 0 self.sms_token = 0 - @classmethod - def setUpTestData(cls): # NOQA:N802 - """Create test data.""" - super().setUpTestData() - factories.populate_database() - cls.da_token = Token.objects.create( - user=models.User.objects.get(username="admin@test.com") - ) - @mock.patch("ovh.Client.get") @mock.patch("ovh.Client.post") def test_reset_password(self, client_post, client_get):