✨(dimail) send domain creation request to dimail
Send domain creation request to dimail when someone creates a domain in people.
This commit is contained in:
committed by
Marie
parent
8f30264445
commit
21bf431940
@@ -18,6 +18,7 @@ and this project adheres to
|
||||
|
||||
### Added
|
||||
|
||||
- ✨(dimail) send domain creation requests to dimail #454
|
||||
- ✨(dimail) synchronize mailboxes from dimail to our db #453
|
||||
- ✨(ci) add security scan #429
|
||||
- ✨(teams) register contacts on admin views
|
||||
|
||||
@@ -15,6 +15,8 @@ As dimail's primary goal is to act as an interface between People and OX, its ar
|
||||
|
||||
Upon creating a domain on People, the same domain is created on dimail and will undergo a series of checks. When all checks have passed, the domain is considered valid and mailboxes can be created on it.
|
||||
|
||||
Domains in OX have a field called "context". Context is a shared space between domains, allowing users to discover users not only on their domain but on their entire context.
|
||||
|
||||
### Users
|
||||
|
||||
The ones issuing requests. Dimail users will reflect domains owners and administrators on People, for logging purposes and to allow direct use of dimail, if desired. User reconciliation is made on user uuid provided by ProConnect.
|
||||
|
||||
@@ -77,6 +77,19 @@ class MailDomainSerializer(serializers.ModelSerializer):
|
||||
return domain.get_abilities(request.user)
|
||||
return {}
|
||||
|
||||
def create(self, validated_data):
|
||||
"""
|
||||
Override create function to fire a request to dimail upon domain creation.
|
||||
"""
|
||||
# send new domain request to dimail
|
||||
client = DimailAPIClient()
|
||||
client.send_domain_creation_request(
|
||||
validated_data["name"], self.context["request"].user.sub
|
||||
)
|
||||
|
||||
# no exception raised ? Then actually save domain on our database
|
||||
return models.MailDomain.objects.create(**validated_data)
|
||||
|
||||
|
||||
class MailDomainAccessSerializer(serializers.ModelSerializer):
|
||||
"""Serialize mail domain access."""
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
Tests for MailDomains API endpoint in People's app mailbox_manager. Focus on "create" action.
|
||||
"""
|
||||
|
||||
import re
|
||||
from logging import Logger
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
import responses
|
||||
from requests.exceptions import HTTPError
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
@@ -56,11 +62,24 @@ def test_api_mail_domains__create_authenticated():
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
domain_name = "test.domain.fr"
|
||||
|
||||
with responses.RequestsMock() as rsps:
|
||||
rsps.add(
|
||||
rsps.POST,
|
||||
re.compile(r".*/domains/"),
|
||||
body=str(
|
||||
{
|
||||
"name": domain_name,
|
||||
}
|
||||
),
|
||||
status=status.HTTP_201_CREATED,
|
||||
content_type="application/json",
|
||||
)
|
||||
response = client.post(
|
||||
"/api/v1.0/mail-domains/",
|
||||
{
|
||||
"name": "mydomain.com",
|
||||
},
|
||||
{"name": domain_name, "context": "null", "features": ["webmail"]},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
@@ -79,5 +98,94 @@ def test_api_mail_domains__create_authenticated():
|
||||
|
||||
# a new domain with status "pending" is created and authenticated user is the owner
|
||||
assert domain.status == enums.MailDomainStatusChoices.PENDING
|
||||
assert domain.name == "mydomain.com"
|
||||
assert domain.name == domain_name
|
||||
assert domain.accesses.filter(role="owner", user=user).exists()
|
||||
|
||||
|
||||
## SYNC TO DIMAIL
|
||||
@mock.patch.object(Logger, "info")
|
||||
def test_api_mail_domains__create_dimail_domain(mock_info):
|
||||
"""
|
||||
Creating a domain should trigger a call to create a domain on dimail too.
|
||||
"""
|
||||
user = core_factories.UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
domain_name = "test.fr"
|
||||
|
||||
with responses.RequestsMock() as rsps:
|
||||
rsp = rsps.add(
|
||||
rsps.POST,
|
||||
re.compile(r".*/domains/"),
|
||||
body=str(
|
||||
{
|
||||
"name": domain_name,
|
||||
}
|
||||
),
|
||||
status=status.HTTP_201_CREATED,
|
||||
content_type="application/json",
|
||||
)
|
||||
response = client.post(
|
||||
"/api/v1.0/mail-domains/",
|
||||
{
|
||||
"name": domain_name,
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert rsp.call_count == 1 # endpoint was called
|
||||
|
||||
# Logger
|
||||
assert (
|
||||
mock_info.call_count == 2
|
||||
) # should be 1. A new empty info has been added. To be investigated
|
||||
assert mock_info.call_args_list[0][0] == (
|
||||
"Domain %s successfully created on dimail by user %s",
|
||||
domain_name,
|
||||
user.sub,
|
||||
)
|
||||
|
||||
|
||||
def test_api_mail_domains__no_creation_when_dimail_duplicate(caplog):
|
||||
"""No domain should be created when dimail returns a 409 conflict."""
|
||||
user = core_factories.UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
domain_name = "test.fr"
|
||||
dimail_error = {
|
||||
"status_code": status.HTTP_409_CONFLICT,
|
||||
"detail": "Domain already exists",
|
||||
}
|
||||
|
||||
with responses.RequestsMock() as rsps:
|
||||
rsp = rsps.add(
|
||||
rsps.POST,
|
||||
re.compile(r".*/domains/"),
|
||||
body=str({"detail": dimail_error["detail"]}),
|
||||
status=dimail_error["status_code"],
|
||||
content_type="application/json",
|
||||
)
|
||||
with pytest.raises(HTTPError):
|
||||
response = client.post(
|
||||
"/api/v1.0/mail-domains/",
|
||||
{
|
||||
"name": domain_name,
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert rsp.call_count == 1 # endpoint was called
|
||||
assert response.status_code == dimail_error["status_code"]
|
||||
assert response.json() == {"detail": dimail_error["detail"]}
|
||||
|
||||
# check logs
|
||||
assert len(caplog.records) == 2 # 1 + new empty info. To be investigated
|
||||
record = caplog.records[0]
|
||||
assert record.levelname == "ERROR"
|
||||
assert (
|
||||
record.message
|
||||
== f"[DIMAIL] {dimail_error['status_code']}: {dimail_error['detail']}"
|
||||
)
|
||||
|
||||
@@ -76,6 +76,40 @@ class DimailAPIClient:
|
||||
|
||||
return self.pass_dimail_unexpected_response(response)
|
||||
|
||||
def send_domain_creation_request(self, domain_name, request_user):
|
||||
"""Send a domain creation request to dimail API."""
|
||||
|
||||
payload = {
|
||||
"domain": domain_name,
|
||||
"context": domain_name, # for now, we put each domain on its own context
|
||||
"features": ["webmail", "mailboxes"],
|
||||
}
|
||||
try:
|
||||
response = session.post(
|
||||
f"{self.API_URL}/domains/",
|
||||
json=payload,
|
||||
headers={"Authorization": f"Basic {self.API_CREDENTIALS}"},
|
||||
verify=True,
|
||||
timeout=10,
|
||||
)
|
||||
except requests.exceptions.ConnectionError as error:
|
||||
logger.error(
|
||||
"Connection error while trying to reach %s.",
|
||||
self.API_URL,
|
||||
exc_info=error,
|
||||
)
|
||||
raise error
|
||||
|
||||
if response.status_code == status.HTTP_201_CREATED:
|
||||
logger.info(
|
||||
"Domain %s successfully created on dimail by user %s",
|
||||
domain_name,
|
||||
request_user,
|
||||
)
|
||||
return response
|
||||
|
||||
return self.pass_dimail_unexpected_response(response)
|
||||
|
||||
def send_mailbox_request(self, mailbox, user_sub=None):
|
||||
"""Send a CREATE mailbox request to mail provisioning API."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user