✨(api) allow to list and create Mailboxes
Simply display all Mailboxes create for a MailDomain. LDAP connection is not yet available, it will be implemented soon. Read and create permissions will be refined soon too.
This commit is contained in:
0
src/backend/mailbox_manager/api/__init__.py
Normal file
0
src/backend/mailbox_manager/api/__init__.py
Normal file
21
src/backend/mailbox_manager/api/serializers.py
Normal file
21
src/backend/mailbox_manager/api/serializers.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
"""Client serializers for the People mailbox_manager app."""
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from mailbox_manager import models
|
||||||
|
|
||||||
|
|
||||||
|
class MailboxSerializer(serializers.ModelSerializer):
|
||||||
|
"""Serialize mailbox."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Mailbox
|
||||||
|
fields = ["id", "local_part", "secondary_email"]
|
||||||
|
|
||||||
|
|
||||||
|
class MailDomainSerializer(serializers.ModelSerializer):
|
||||||
|
"""Serialize mail domain."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.MailDomain
|
||||||
|
fields = ["id", "name"]
|
||||||
47
src/backend/mailbox_manager/api/viewsets.py
Normal file
47
src/backend/mailbox_manager/api/viewsets.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
"""API endpoints"""
|
||||||
|
|
||||||
|
from rest_framework import mixins, viewsets
|
||||||
|
from rest_framework import permissions as drf_permissions
|
||||||
|
|
||||||
|
from mailbox_manager import models
|
||||||
|
|
||||||
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class MailDomainViewSet(
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
viewsets.GenericViewSet,
|
||||||
|
):
|
||||||
|
"""MailDomain ViewSet"""
|
||||||
|
|
||||||
|
permission_classes = [drf_permissions.IsAuthenticated]
|
||||||
|
serializer_class = serializers.MailDomainSerializer
|
||||||
|
queryset = models.MailDomain.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class MailBoxViewSet(
|
||||||
|
mixins.CreateModelMixin,
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
viewsets.GenericViewSet,
|
||||||
|
):
|
||||||
|
"""MailBox ViewSet"""
|
||||||
|
|
||||||
|
permission_classes = [drf_permissions.IsAuthenticated]
|
||||||
|
serializer_class = serializers.MailboxSerializer
|
||||||
|
queryset = models.Mailbox.objects.all()
|
||||||
|
|
||||||
|
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)
|
||||||
|
return self.queryset
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
"""Create new mailbox."""
|
||||||
|
domain_id = self.kwargs.get("domain_id", "")
|
||||||
|
if domain_id:
|
||||||
|
serializer.validated_data["domain"] = models.MailDomain.objects.get(
|
||||||
|
id=domain_id
|
||||||
|
)
|
||||||
|
super().perform_create(serializer)
|
||||||
103
src/backend/mailbox_manager/tests/test_api_mailboxes_create.py
Normal file
103
src/backend/mailbox_manager/tests/test_api_mailboxes_create.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
"""
|
||||||
|
Unit tests for the mailbox API
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core import factories as core_factories
|
||||||
|
|
||||||
|
from mailbox_manager import factories, models
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mailboxes__create_anonymous_forbidden():
|
||||||
|
"""Anonymous users should not be able to create a new mailbox via the API."""
|
||||||
|
mail_domain = factories.MailDomainFactory()
|
||||||
|
|
||||||
|
response = APIClient().post(
|
||||||
|
f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/",
|
||||||
|
{
|
||||||
|
"first_name": "jean",
|
||||||
|
"last_name": "doe",
|
||||||
|
"local_part": "jean.doe",
|
||||||
|
"secondary_email": "jean.doe@gmail.com",
|
||||||
|
"phone_number": "+33150142700",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
assert not models.Mailbox.objects.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mailboxes__create_authenticated_missing_fields():
|
||||||
|
"""
|
||||||
|
Authenticated users should not be able to create mailboxes
|
||||||
|
without local part or secondary mail.
|
||||||
|
"""
|
||||||
|
user = core_factories.UserFactory(admin_email="tester@ministry.fr")
|
||||||
|
core_factories.IdentityFactory(user=user, email=user.admin_email, name="john doe")
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
|
||||||
|
mail_domain = factories.MailDomainFactory()
|
||||||
|
response = client.post(
|
||||||
|
f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/",
|
||||||
|
{
|
||||||
|
"first_name": "jean",
|
||||||
|
"last_name": "doe",
|
||||||
|
"secondary_email": "jean.doe@gmail.com",
|
||||||
|
"phone_number": "+33150142700",
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
|
assert models.Mailbox.objects.exists() is False
|
||||||
|
assert response.json() == {"local_part": ["This field is required."]}
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/",
|
||||||
|
{
|
||||||
|
"first_name": "jean",
|
||||||
|
"last_name": "doe",
|
||||||
|
"local_part": "jean.doe",
|
||||||
|
"phone_number": "+33150142700",
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
|
assert models.Mailbox.objects.exists() is False
|
||||||
|
assert response.json() == {"secondary_email": ["This field is required."]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mailboxes__create_authenticated_successful():
|
||||||
|
"""Authenticated users should be able to create mailbox."""
|
||||||
|
user = core_factories.UserFactory(admin_email="tester@ministry.fr")
|
||||||
|
core_factories.IdentityFactory(user=user, email=user.admin_email, name="john doe")
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
|
||||||
|
mail_domain = factories.MailDomainFactory(name="saint-jean.collectivite.fr")
|
||||||
|
response = client.post(
|
||||||
|
f"/api/v1.0/mail-domains/{mail_domain.id}/mailboxes/",
|
||||||
|
{
|
||||||
|
"first_name": "jean",
|
||||||
|
"last_name": "doe",
|
||||||
|
"local_part": "jean.doe",
|
||||||
|
"secondary_email": "jean.doe@gmail.com",
|
||||||
|
"phone_number": "+33150142700",
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_201_CREATED
|
||||||
|
mailbox = models.Mailbox.objects.get()
|
||||||
|
assert mailbox.local_part == "jean.doe"
|
||||||
|
assert mailbox.secondary_email == "jean.doe@gmail.com"
|
||||||
|
assert response.json() == {
|
||||||
|
"id": str(mailbox.id),
|
||||||
|
"local_part": str(mailbox.local_part),
|
||||||
|
"secondary_email": str(mailbox.secondary_email),
|
||||||
|
}
|
||||||
53
src/backend/mailbox_manager/tests/test_api_mailboxes_list.py
Normal file
53
src/backend/mailbox_manager/tests/test_api_mailboxes_list.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
Unit tests for the mailbox API
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core import factories as core_factories
|
||||||
|
|
||||||
|
from mailbox_manager import factories
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mailboxes__list_anonymous():
|
||||||
|
"""Anonymous users should not be allowed to list mailboxes."""
|
||||||
|
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/")
|
||||||
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
assert response.json() == {
|
||||||
|
"detail": "Authentication credentials were not provided."
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mailboxes__list_authenticated_no_query():
|
||||||
|
"""Authenticated users should be able to list mailboxes without applying a query."""
|
||||||
|
user = core_factories.UserFactory(admin_email="tester@ministry.fr")
|
||||||
|
core_factories.IdentityFactory(user=user, email=user.admin_email, name="john doe")
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
|
||||||
|
mail_domain = factories.MailDomainFactory()
|
||||||
|
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/")
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
assert response.json()["results"] == [
|
||||||
|
{
|
||||||
|
"id": str(mailbox1.id),
|
||||||
|
"local_part": str(mailbox1.local_part),
|
||||||
|
"secondary_email": str(mailbox1.secondary_email),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": str(mailbox2.id),
|
||||||
|
"local_part": str(mailbox2.local_part),
|
||||||
|
"secondary_email": str(mailbox2.secondary_email),
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -8,11 +8,16 @@ from rest_framework.routers import DefaultRouter
|
|||||||
|
|
||||||
from core.api import viewsets
|
from core.api import viewsets
|
||||||
|
|
||||||
|
from mailbox_manager.api import viewsets as mail_viewsets
|
||||||
|
|
||||||
# - Main endpoints
|
# - Main endpoints
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register("contacts", viewsets.ContactViewSet, basename="contacts")
|
router.register("contacts", viewsets.ContactViewSet, basename="contacts")
|
||||||
router.register("teams", viewsets.TeamViewSet, basename="teams")
|
router.register("teams", viewsets.TeamViewSet, basename="teams")
|
||||||
router.register("users", viewsets.UserViewSet, basename="users")
|
router.register("users", viewsets.UserViewSet, basename="users")
|
||||||
|
router.register(
|
||||||
|
"mail-domains", mail_viewsets.MailDomainViewSet, basename="mail-domains"
|
||||||
|
)
|
||||||
|
|
||||||
# - Routes nested under a team
|
# - Routes nested under a team
|
||||||
team_related_router = DefaultRouter()
|
team_related_router = DefaultRouter()
|
||||||
@@ -28,6 +33,15 @@ team_related_router.register(
|
|||||||
basename="invitations",
|
basename="invitations",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# - Routes nested under a mail domain
|
||||||
|
maildomain_related_router = DefaultRouter()
|
||||||
|
maildomain_related_router.register(
|
||||||
|
"mailboxes",
|
||||||
|
mail_viewsets.MailBoxViewSet,
|
||||||
|
basename="mailboxes",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
path(
|
||||||
f"api/{settings.API_VERSION}/",
|
f"api/{settings.API_VERSION}/",
|
||||||
@@ -39,6 +53,10 @@ urlpatterns = [
|
|||||||
r"^teams/(?P<team_id>[0-9a-z-]*)/",
|
r"^teams/(?P<team_id>[0-9a-z-]*)/",
|
||||||
include(team_related_router.urls),
|
include(team_related_router.urls),
|
||||||
),
|
),
|
||||||
|
re_path(
|
||||||
|
r"^mail-domains/(?P<domain_id>[0-9a-z-]*)/",
|
||||||
|
include(maildomain_related_router.urls),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user