From b4bafb6efbcfae4ed8a116061ee471a27737c41e Mon Sep 17 00:00:00 2001 From: Sabrina Demagny Date: Mon, 3 Jun 2024 16:59:55 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(mailbox=5Fmanager)=20modify=20API=20t?= =?UTF-8?q?o=20get=20maildomain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to maildomain by slug name --- .../mailbox_manager/api/serializers.py | 1 + src/backend/mailbox_manager/api/viewsets.py | 17 +++++++------- src/backend/mailbox_manager/factories.py | 3 +++ .../migrations/0003_maildomain_slug.py | 18 +++++++++++++++ .../migrations/0004_maildomain_fill_slug.py | 23 +++++++++++++++++++ .../migrations/0005_alter_maildomain_slug.py | 18 +++++++++++++++ src/backend/mailbox_manager/models.py | 7 ++++++ .../test_api_mail_domains_delete.py | 10 ++++---- .../test_api_mail_domains_retrieve.py | 6 ++--- .../tests/test_api_mailboxes_create.py | 8 +++---- .../tests/test_api_mailboxes_list.py | 4 ++-- src/backend/mailbox_manager/urls.py | 2 +- 12 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 src/backend/mailbox_manager/migrations/0003_maildomain_slug.py create mode 100644 src/backend/mailbox_manager/migrations/0004_maildomain_fill_slug.py create mode 100644 src/backend/mailbox_manager/migrations/0005_alter_maildomain_slug.py diff --git a/src/backend/mailbox_manager/api/serializers.py b/src/backend/mailbox_manager/api/serializers.py index 08b2d5e..612f7fa 100644 --- a/src/backend/mailbox_manager/api/serializers.py +++ b/src/backend/mailbox_manager/api/serializers.py @@ -18,6 +18,7 @@ class MailDomainSerializer(serializers.ModelSerializer): class Meta: model = models.MailDomain + lookup_field = "slug" fields = [ "id", "name", diff --git a/src/backend/mailbox_manager/api/viewsets.py b/src/backend/mailbox_manager/api/viewsets.py index 9c3b653..b19a0df 100644 --- a/src/backend/mailbox_manager/api/viewsets.py +++ b/src/backend/mailbox_manager/api/viewsets.py @@ -23,14 +23,14 @@ class MailDomainViewSet( GET /api//mail-domains/ Return a list of mail domains user has access to. - GET /api//mail-domains// + GET /api//mail-domains// Return details for a mail domain user has access to. POST /api//mail-domains/ with expected data: - name: str Return newly created domain - DELETE /api//mail-domains// + DELETE /api//mail-domains// Delete targeted team access """ @@ -39,6 +39,7 @@ class MailDomainViewSet( filter_backends = [filters.OrderingFilter] ordering_fields = ["created_at", "name"] ordering = ["-created_at"] + lookup_field = "slug" queryset = models.MailDomain.objects.all() def get_queryset(self): @@ -85,16 +86,16 @@ class MailBoxViewSet( def get_queryset(self): """Custom queryset to get mailboxes related to a mail domain.""" - domain_id = self.kwargs.get("domain_id", "") - if domain_id: - return self.queryset.filter(domain__id=domain_id) + domain_slug = self.kwargs.get("domain_slug", "") + if domain_slug: + return self.queryset.filter(domain__slug=domain_slug) return self.queryset def perform_create(self, serializer): """Create new mailbox.""" - domain_id = self.kwargs.get("domain_id", "") - if domain_id: + domain_slug = self.kwargs.get("domain_slug", "") + if domain_slug: serializer.validated_data["domain"] = models.MailDomain.objects.get( - id=domain_id + slug=domain_slug ) super().perform_create(serializer) diff --git a/src/backend/mailbox_manager/factories.py b/src/backend/mailbox_manager/factories.py index e3012b0..2f0ed72 100644 --- a/src/backend/mailbox_manager/factories.py +++ b/src/backend/mailbox_manager/factories.py @@ -2,6 +2,8 @@ Mailbox manager application factories """ +from django.utils.text import slugify + import factory.fuzzy from faker import Faker @@ -22,6 +24,7 @@ class MailDomainFactory(factory.django.DjangoModelFactory): skip_postgeneration_save = True name = factory.Faker("domain_name") + slug = factory.LazyAttribute(lambda o: slugify(o.name)) @factory.post_generation def users(self, create, extracted, **kwargs): diff --git a/src/backend/mailbox_manager/migrations/0003_maildomain_slug.py b/src/backend/mailbox_manager/migrations/0003_maildomain_slug.py new file mode 100644 index 0000000..eb79fd4 --- /dev/null +++ b/src/backend/mailbox_manager/migrations/0003_maildomain_slug.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-06-03 14:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailbox_manager', '0002_alter_maildomainaccess_domain'), + ] + + operations = [ + migrations.AddField( + model_name='maildomain', + name='slug', + field=models.SlugField(blank=True, max_length=80), + ), + ] diff --git a/src/backend/mailbox_manager/migrations/0004_maildomain_fill_slug.py b/src/backend/mailbox_manager/migrations/0004_maildomain_fill_slug.py new file mode 100644 index 0000000..8aa514c --- /dev/null +++ b/src/backend/mailbox_manager/migrations/0004_maildomain_fill_slug.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2024-06-03 14:14 + +from django.db import migrations, models +from django.utils.text import slugify + + +def populate_slug(apps, schema_editor): + MailDomain = apps.get_model('mailbox_manager', 'MailDomain') + for mail_domain in MailDomain.objects.filter(slug=''): + mail_domain.slug = slugify(mail_domain.name) + mail_domain.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailbox_manager', '0003_maildomain_slug'), + ] + + operations = [ + migrations.RunPython(populate_slug, reverse_code=migrations.RunPython.noop), + + ] diff --git a/src/backend/mailbox_manager/migrations/0005_alter_maildomain_slug.py b/src/backend/mailbox_manager/migrations/0005_alter_maildomain_slug.py new file mode 100644 index 0000000..bd4fbb2 --- /dev/null +++ b/src/backend/mailbox_manager/migrations/0005_alter_maildomain_slug.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-06-03 14:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailbox_manager', '0004_maildomain_fill_slug'), + ] + + operations = [ + migrations.AlterField( + model_name='maildomain', + name='slug', + field=models.SlugField(max_length=80, unique=True), + ), + ] diff --git a/src/backend/mailbox_manager/models.py b/src/backend/mailbox_manager/models.py index ffc1551..247bc40 100644 --- a/src/backend/mailbox_manager/models.py +++ b/src/backend/mailbox_manager/models.py @@ -5,6 +5,7 @@ Declare and configure the models for the People additional application : mailbox from django.conf import settings from django.core import validators from django.db import models +from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from core.models import BaseModel, RoleChoices @@ -16,6 +17,7 @@ class MailDomain(BaseModel): name = models.CharField( _("name"), max_length=150, null=False, blank=False, unique=True ) + slug = models.SlugField(null=False, blank=False, unique=True, max_length=80) class Meta: db_table = "people_mail_domain" @@ -25,6 +27,11 @@ class MailDomain(BaseModel): def __str__(self): return self.name + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(self.name) + return super().save(*args, **kwargs) + def get_abilities(self, user): """ Compute and return abilities for a given user on the domain. diff --git a/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_delete.py b/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_delete.py index 9e16f4b..38ea09a 100644 --- a/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_delete.py +++ b/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_delete.py @@ -18,7 +18,7 @@ def test_api_mail_domains__delete_anonymous(): domain = factories.MailDomainFactory() response = APIClient().delete( - f"/api/v1.0/mail-domains/{domain.id!s}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_401_UNAUTHORIZED @@ -36,7 +36,7 @@ def test_api_mail_domains__delete_authenticated_unrelated(): client = APIClient() client.force_login(identity.user) response = client.delete( - f"/api/v1.0/mail-domains/{domain.id!s}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -56,7 +56,7 @@ def test_api_mail_domains__delete_authenticated_member(): client = APIClient() client.force_login(user) response = client.delete( - f"/api/v1.0/mail-domains/{domain.id}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_403_FORBIDDEN @@ -78,7 +78,7 @@ def test_api_mail_domains__delete_authenticated_administrator(): client = APIClient() client.force_login(user) response = client.delete( - f"/api/v1.0/mail-domains/{domain.id}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_403_FORBIDDEN @@ -100,7 +100,7 @@ def test_api_mail_domains__delete_authenticated_owner(): client = APIClient() client.force_login(user) response = client.delete( - f"/api/v1.0/mail-domains/{domain.id}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_204_NO_CONTENT diff --git a/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_retrieve.py b/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_retrieve.py index d768cc1..aaacb27 100644 --- a/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_retrieve.py +++ b/src/backend/mailbox_manager/tests/api/mail_domain/test_api_mail_domains_retrieve.py @@ -17,7 +17,7 @@ def test_api_mail_domains__retrieve_anonymous(): """Anonymous users should not be allowed to retrieve a domain.""" domain = factories.MailDomainFactory() - response = APIClient().get(f"/api/v1.0/mail-domains/{domain.id}/") + response = APIClient().get(f"/api/v1.0/mail-domains/{domain.slug}/") assert response.status_code == status.HTTP_401_UNAUTHORIZED assert response.json() == { @@ -38,7 +38,7 @@ def test_api_mail_domains__retrieve_authenticated_unrelated(): domain = factories.MailDomainFactory() response = client.get( - f"/api/v1.0/mail-domains/{domain.id!s}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == {"detail": "No MailDomain matches the given query."} @@ -59,7 +59,7 @@ def test_api_mail_domains__retrieve_authenticated_related(): factories.MailDomainAccessFactory(domain=domain, user=user) response = client.get( - f"/api/v1.0/mail-domains/{domain.id!s}/", + f"/api/v1.0/mail-domains/{domain.slug}/", ) assert response.status_code == status.HTTP_200_OK diff --git a/src/backend/mailbox_manager/tests/test_api_mailboxes_create.py b/src/backend/mailbox_manager/tests/test_api_mailboxes_create.py index 5ed4bec..6aca56d 100644 --- a/src/backend/mailbox_manager/tests/test_api_mailboxes_create.py +++ b/src/backend/mailbox_manager/tests/test_api_mailboxes_create.py @@ -18,7 +18,7 @@ def test_api_mailboxes__create_anonymous_forbidden(): mail_domain = factories.MailDomainFactory() response = APIClient().post( - f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/", + f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/", { "first_name": "jean", "last_name": "doe", @@ -44,7 +44,7 @@ def test_api_mailboxes__create_authenticated_missing_fields(): mail_domain = factories.MailDomainFactory() response = client.post( - f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/", + f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/", { "first_name": "jean", "last_name": "doe", @@ -58,7 +58,7 @@ def test_api_mailboxes__create_authenticated_missing_fields(): assert response.json() == {"local_part": ["This field is required."]} response = client.post( - f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/", + f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/", { "first_name": "jean", "last_name": "doe", @@ -82,7 +82,7 @@ def test_api_mailboxes__create_authenticated_successful(): mail_domain = factories.MailDomainFactory(name="saint-jean.collectivite.fr") response = client.post( - f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/", + f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/", { "first_name": "jean", "last_name": "doe", diff --git a/src/backend/mailbox_manager/tests/test_api_mailboxes_list.py b/src/backend/mailbox_manager/tests/test_api_mailboxes_list.py index 9eefa1a..3bedb66 100644 --- a/src/backend/mailbox_manager/tests/test_api_mailboxes_list.py +++ b/src/backend/mailbox_manager/tests/test_api_mailboxes_list.py @@ -18,7 +18,7 @@ def test_api_mailboxes__list_anonymous(): mail_domain = factories.MailDomainFactory() factories.MailboxFactory.create_batch(2, domain=mail_domain) - response = APIClient().get(f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/") + response = APIClient().get(f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/") assert response.status_code == status.HTTP_401_UNAUTHORIZED assert response.json() == { "detail": "Authentication credentials were not provided." @@ -37,7 +37,7 @@ def test_api_mailboxes__list_authenticated_no_query(): mailbox1 = factories.MailboxFactory(domain=mail_domain) mailbox2 = factories.MailboxFactory(domain=mail_domain) - response = client.get(f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/") + response = client.get(f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/") assert response.status_code == status.HTTP_200_OK assert response.json()["results"] == [ { diff --git a/src/backend/mailbox_manager/urls.py b/src/backend/mailbox_manager/urls.py index d2bd53b..a024fe8 100644 --- a/src/backend/mailbox_manager/urls.py +++ b/src/backend/mailbox_manager/urls.py @@ -32,7 +32,7 @@ urlpatterns = [ [ *maildomain_router.urls, re_path( - r"^mail-domains/(?P[0-9a-z-]*)/", + r"^mail-domains/(?P[\w-]+)/", include(maildomain_related_router.urls), ), ]