👔(dimail) allow creation of "pending" mailboxes

Previously, mailbox creation was restricted to "enabled" domains.
We now allow users to create mailboxes on pending and failed domains.
Mailboxes thus created have the "pending" mailboxes status.
This commit is contained in:
Marie PUPO JEAMMET
2024-11-15 18:14:10 +01:00
committed by Sabrina Demagny
parent 28a972e19e
commit 863c85e3f0
12 changed files with 334 additions and 139 deletions

View File

@@ -10,6 +10,7 @@ and this project adheres to
### Added ### Added
- ✨(domains) allow creation of "pending" mailboxes
- ✨(teams) allow team management for team admins/owners #509 - ✨(teams) allow team management for team admins/owners #509
## [1.5.0] - 2024-11-14 ## [1.5.0] - 2024-11-14

View File

@@ -9,21 +9,29 @@ API and its documentation can be found [here](https://api.dev.ox.numerique.gouv.
## Architectural links of dimail ## Architectural links of dimail
As dimail's primary goal is to act as an interface between People and OX, its architecture is similar to that of People. A series of requests are sent from People to dimail upon creating domains, users and accesses. As dimail's primary goal is to act as an interface between People and OX, its architecture is similar to that of People. A series of requests are sent from People to dimail upon creating domains, users, permissions and mailboxes.
### Domains ### Domains
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. 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 enabled.
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. 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.
### Mailboxes
Mailboxes can be created by a domain owners or administrators in People's domain tab.
On enabled domains, mailboxes are created at the same time on dimail (and a confirmation email is sent to the secondary email).
On pending/failed domains, mailboxes are only created locally with "pending" status and are sent to dimail upon domain's activation.
On disabled domains, mailboxes creation is not allowed.
### Users ### 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. 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.
### Accesses ### Permissions
As for People, an access - a permissions (or "allows" in dimail) - grants an user permission to create objects on a domain. As for People, an access - a permissions (or an "allow" in dimail) - grants an user permission to create objects on a domain.
Permissions requests are sent automatically upon : Permissions requests are sent automatically upon :
- dimail database initialisation: - dimail database initialisation:

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: lasuite-people\n" "Project-Id-Version: lasuite-people\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-10-15 10:52+0000\n" "POT-Creation-Date: 2024-11-18 23:02+0000\n"
"PO-Revision-Date: 2024-01-03 23:15\n" "PO-Revision-Date: 2024-01-03 23:15\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: French\n" "Language-Team: French\n"
@@ -17,225 +17,261 @@ msgstr ""
"X-Crowdin-File: backend.pot\n" "X-Crowdin-File: backend.pot\n"
"X-Crowdin-File-ID: 2\n" "X-Crowdin-File-ID: 2\n"
#: core/admin.py:45 #: core/admin.py:55
msgid "Personal info" msgid "Personal info"
msgstr "" msgstr ""
#: core/admin.py:47 #: core/admin.py:57
msgid "Permissions" msgid "Permissions"
msgstr "" msgstr ""
#: core/admin.py:59 #: core/admin.py:69
msgid "Important dates" msgid "Important dates"
msgstr "" msgstr ""
#: core/admin.py:97 #: core/admin.py:108
msgid "User" msgid "User"
msgstr "" msgstr ""
#: core/authentication/backends.py:82 #: core/authentication/backends.py:89
msgid "User info contained no recognizable user identification" msgid "User info contained no recognizable user identification"
msgstr "" msgstr ""
#: core/authentication/backends.py:90 #: core/authentication/backends.py:111
msgid "User account is disabled" msgid "User account is disabled"
msgstr "" msgstr ""
#: core/authentication/backends.py:102 #: core/authentication/backends.py:157
msgid "Claims contained no recognizable user identification" msgid "Claims contained no recognizable user identification"
msgstr "" msgstr ""
#: core/authentication/backends.py:176
msgid "Claims contained no recognizable organization identification"
msgstr ""
#: core/enums.py:23 #: core/enums.py:23
msgid "Failure" msgid "Failure"
msgstr "" msgstr ""
#: core/enums.py:24 mailbox_manager/enums.py:20 #: core/enums.py:24 mailbox_manager/enums.py:21 mailbox_manager/enums.py:30
msgid "Pending" msgid "Pending"
msgstr "" msgstr "En attente"
#: core/enums.py:25 #: core/enums.py:25
msgid "Success" msgid "Success"
msgstr "" msgstr ""
#: core/models.py:42 #: core/models.py:46
msgid "Member" msgid "Member"
msgstr "" msgstr ""
#: core/models.py:43 mailbox_manager/enums.py:13 #: core/models.py:47 core/models.py:59 mailbox_manager/enums.py:14
msgid "Administrator" msgid "Administrator"
msgstr "" msgstr ""
#: core/models.py:44 mailbox_manager/enums.py:14 #: core/models.py:48 mailbox_manager/enums.py:15
msgid "Owner" msgid "Owner"
msgstr "" msgstr ""
#: core/models.py:56 #: core/models.py:71
msgid "id" msgid "id"
msgstr "" msgstr ""
#: core/models.py:57 #: core/models.py:72
msgid "primary key for the record as UUID" msgid "primary key for the record as UUID"
msgstr "" msgstr ""
#: core/models.py:63 #: core/models.py:78
msgid "created at" msgid "created at"
msgstr "" msgstr ""
#: core/models.py:64 #: core/models.py:79
msgid "date and time at which a record was created" msgid "date and time at which a record was created"
msgstr "" msgstr ""
#: core/models.py:69 #: core/models.py:84
msgid "updated at" msgid "updated at"
msgstr "" msgstr ""
#: core/models.py:70 #: core/models.py:85
msgid "date and time at which a record was last updated" msgid "date and time at which a record was last updated"
msgstr "" msgstr ""
#: core/models.py:101 #: core/models.py:116
msgid "full name" msgid "full name"
msgstr "" msgstr ""
#: core/models.py:102 #: core/models.py:117
msgid "short name" msgid "short name"
msgstr "" msgstr ""
#: core/models.py:107 #: core/models.py:122
msgid "contact information" msgid "contact information"
msgstr "" msgstr ""
#: core/models.py:108 #: core/models.py:123
msgid "A JSON object containing the contact information" msgid "A JSON object containing the contact information"
msgstr "" msgstr ""
#: core/models.py:122 #: core/models.py:137
msgid "contact" msgid "contact"
msgstr "" msgstr ""
#: core/models.py:123 #: core/models.py:138
msgid "contacts" msgid "contacts"
msgstr "" msgstr ""
#: core/models.py:167 #: core/models.py:262 core/models.py:331 mailbox_manager/models.py:24
msgid "name"
msgstr ""
#: core/models.py:270
msgid "registration ID list"
msgstr ""
#: core/models.py:279
msgid "domain list"
msgstr ""
#: core/models.py:289
msgid "organization"
msgstr ""
#: core/models.py:290
msgid "organizations"
msgstr ""
#: core/models.py:297
msgid "An organization must have at least a registration ID or a domain."
msgstr ""
#: core/models.py:316
msgid "" msgid ""
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/" "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
"_ characters." "_ characters."
msgstr "" msgstr ""
#: core/models.py:173 #: core/models.py:322
msgid "sub" msgid "sub"
msgstr "" msgstr ""
#: core/models.py:175 #: core/models.py:324
msgid "" msgid ""
"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_ " "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_ "
"characters only." "characters only."
msgstr "" msgstr ""
#: core/models.py:181 core/models.py:489 #: core/models.py:330 core/models.py:737
msgid "email address" msgid "email address"
msgstr "" msgstr ""
#: core/models.py:182 mailbox_manager/models.py:20 #: core/models.py:343
msgid "name"
msgstr ""
#: core/models.py:194
msgid "language" msgid "language"
msgstr "" msgstr ""
#: core/models.py:195 #: core/models.py:344
msgid "The language in which the user wants to see the interface." msgid "The language in which the user wants to see the interface."
msgstr "" msgstr ""
#: core/models.py:201 #: core/models.py:350
msgid "The timezone in which the user wants to see times." msgid "The timezone in which the user wants to see times."
msgstr "" msgstr ""
#: core/models.py:204 #: core/models.py:353
msgid "device" msgid "device"
msgstr "" msgstr ""
#: core/models.py:206 #: core/models.py:355
msgid "Whether the user is a device or a real user." msgid "Whether the user is a device or a real user."
msgstr "" msgstr ""
#: core/models.py:209 #: core/models.py:358
msgid "staff status" msgid "staff status"
msgstr "" msgstr ""
#: core/models.py:211 #: core/models.py:360
msgid "Whether the user can log into this admin site." msgid "Whether the user can log into this admin site."
msgstr "" msgstr ""
#: core/models.py:214 #: core/models.py:363
msgid "active" msgid "active"
msgstr "" msgstr ""
#: core/models.py:217 #: core/models.py:366
msgid "" msgid ""
"Whether this user should be treated as active. Unselect this instead of " "Whether this user should be treated as active. Unselect this instead of "
"deleting accounts." "deleting accounts."
msgstr "" msgstr ""
#: core/models.py:229 #: core/models.py:385
msgid "user" msgid "user"
msgstr "" msgstr ""
#: core/models.py:230 #: core/models.py:386
msgid "users" msgid "users"
msgstr "" msgstr ""
#: core/models.py:306 #: core/models.py:525
msgid "Organization/user relation"
msgstr ""
#: core/models.py:526
msgid "Organization/user relations"
msgstr ""
#: core/models.py:531
msgid "This user is already in this organization."
msgstr ""
#: core/models.py:563
msgid "Team" msgid "Team"
msgstr "" msgstr ""
#: core/models.py:307 #: core/models.py:564
msgid "Teams" msgid "Teams"
msgstr "" msgstr ""
#: core/models.py:367 #: core/models.py:615
msgid "Team/user relation" msgid "Team/user relation"
msgstr "" msgstr ""
#: core/models.py:368 #: core/models.py:616
msgid "Team/user relations" msgid "Team/user relations"
msgstr "" msgstr ""
#: core/models.py:373 #: core/models.py:621
msgid "This user is already in this team." msgid "This user is already in this team."
msgstr "" msgstr ""
#: core/models.py:462 #: core/models.py:710
msgid "url" msgid "url"
msgstr "" msgstr ""
#: core/models.py:463 #: core/models.py:711
msgid "secret" msgid "secret"
msgstr "" msgstr ""
#: core/models.py:472 #: core/models.py:720
msgid "Team webhook" msgid "Team webhook"
msgstr "" msgstr ""
#: core/models.py:473 #: core/models.py:721
msgid "Team webhooks" msgid "Team webhooks"
msgstr "" msgstr ""
#: core/models.py:506 #: core/models.py:754
msgid "Team invitation" msgid "Team invitation"
msgstr "" msgstr ""
#: core/models.py:507 #: core/models.py:755
msgid "Team invitations" msgid "Team invitations"
msgstr "" msgstr ""
#: core/models.py:532 #: core/models.py:780
msgid "This email is already associated to a registered user." msgid "This email is already associated to a registered user."
msgstr "" msgstr ""
#: core/models.py:574 core/models.py:580 #: core/models.py:822 core/models.py:828
msgid "Invitation to join Desk!" msgid "Invitation to join Desk!"
msgstr "" msgstr ""
@@ -420,65 +456,80 @@ msgstr "L'équipe de La Suite"
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]" msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
msgstr "" msgstr ""
#: mailbox_manager/enums.py:12 #: mailbox_manager/admin.py:12
msgid "Synchronise from dimail"
msgstr ""
#: mailbox_manager/admin.py:23
#, python-brace-format
msgid "Synchronisation failed for {domain.name} with message: [{err}]"
msgstr ""
#: mailbox_manager/admin.py:29
#, python-brace-format
msgid "Synchronisation succeed for {domain.name}. "
msgstr ""
#: mailbox_manager/enums.py:13
msgid "Viewer" msgid "Viewer"
msgstr "" msgstr ""
#: mailbox_manager/enums.py:21 #: mailbox_manager/enums.py:22 mailbox_manager/enums.py:31
msgid "Enabled" msgid "Enabled"
msgstr "" msgstr "Actif"
#: mailbox_manager/enums.py:22 #: mailbox_manager/enums.py:23 mailbox_manager/enums.py:32
msgid "Failed" msgid "Failed"
msgstr "" msgstr "En échec"
#: mailbox_manager/enums.py:23 #: mailbox_manager/enums.py:24 mailbox_manager/enums.py:33
msgid "Disabled" msgid "Disabled"
msgstr "" msgstr "Désactivé"
#: mailbox_manager/models.py:31 #: mailbox_manager/models.py:35
msgid "Mail domain" msgid "Mail domain"
msgstr "" msgstr ""
#: mailbox_manager/models.py:32 #: mailbox_manager/models.py:36
msgid "Mail domains" msgid "Mail domains"
msgstr "" msgstr ""
#: mailbox_manager/models.py:98 #: mailbox_manager/models.py:102
msgid "User/mail domain relation" msgid "User/mail domain relation"
msgstr "" msgstr ""
#: mailbox_manager/models.py:99 #: mailbox_manager/models.py:103
msgid "User/mail domain relations" msgid "User/mail domain relations"
msgstr "" msgstr ""
#: mailbox_manager/models.py:171 #: mailbox_manager/models.py:175
msgid "local_part" msgid "local_part"
msgstr "" msgstr ""
#: mailbox_manager/models.py:185 #: mailbox_manager/models.py:189
msgid "secondary email address" msgid "secondary email address"
msgstr "" msgstr ""
#: mailbox_manager/models.py:190 #: mailbox_manager/models.py:199
msgid "Mailbox" msgid "Mailbox"
msgstr "" msgstr ""
#: mailbox_manager/models.py:191 #: mailbox_manager/models.py:200
msgid "Mailboxes" msgid "Mailboxes"
msgstr "" msgstr ""
#: mailbox_manager/utils/dimail.py:137 #: mailbox_manager/models.py:224
msgid "You can't create a mailbox for a disabled domain."
msgstr "Vous ne pouvez pas créer de boîte mail pour un domain désactivé."
#: mailbox_manager/utils/dimail.py:183
msgid "Your new mailbox information" msgid "Your new mailbox information"
msgstr "Informations concernant votre nouvelle boîte mail" msgstr "Informations concernant votre nouvelle boîte mail"
#: people/settings.py:134 #: people/settings.py:135
msgid "English" msgid "English"
msgstr "" msgstr ""
#: people/settings.py:135 #: people/settings.py:136
msgid "French" msgid "French"
msgstr "" msgstr ""
#~ msgid "Regards,"
#~ msgstr "Cordialement,"

View File

@@ -16,32 +16,45 @@ class MailboxSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.Mailbox model = models.Mailbox
fields = ["id", "first_name", "last_name", "local_part", "secondary_email"] fields = [
"id",
"first_name",
"last_name",
"local_part",
"secondary_email",
"status",
]
# everything is actually read-only as we do not allow update for now # everything is actually read-only as we do not allow update for now
read_only_fields = ["id"] read_only_fields = ["id", "status"]
def create(self, validated_data): def create(self, validated_data):
""" """
Override create function to fire a request on mailbox creation. Override create function to fire a request on mailbox creation.
""" """
# send new mailbox request to dimail mailbox_status = enums.MailDomainStatusChoices.PENDING
client = DimailAPIClient()
response = client.send_mailbox_request(
validated_data, self.context["request"].user.sub
)
# fix format to have actual json, and remove uuid if validated_data["domain"].status == enums.MailDomainStatusChoices.ENABLED:
mailbox_data = json.loads(response.content.decode("utf-8").replace("'", '"')) client = DimailAPIClient()
del mailbox_data["uuid"] # send new mailbox request to dimail
response = client.send_mailbox_request(
validated_data, self.context["request"].user.sub
)
# fix format to have actual json, and remove uuid
mailbox_data = json.loads(
response.content.decode("utf-8").replace("'", '"')
)
del mailbox_data["uuid"]
mailbox_status = enums.MailDomainStatusChoices.ENABLED
# send confirmation email
client.send_new_mailbox_notification(
recipient=validated_data["secondary_email"], mailbox_data=mailbox_data
)
# actually save mailbox on our database # actually save mailbox on our database
instance = models.Mailbox.objects.create(**validated_data) return models.Mailbox.objects.create(**validated_data, status=mailbox_status)
# send confirmation email
client.send_new_mailbox_notification(
recipient=validated_data["secondary_email"], mailbox_data=mailbox_data
)
return instance
class MailDomainSerializer(serializers.ModelSerializer): class MailDomainSerializer(serializers.ModelSerializer):

View File

@@ -1,3 +1,4 @@
# pylint: disable=too-many-ancestors
""" """
Application enums declaration Application enums declaration
""" """
@@ -21,3 +22,12 @@ class MailDomainStatusChoices(models.TextChoices):
ENABLED = "enabled", _("Enabled") ENABLED = "enabled", _("Enabled")
FAILED = "failed", _("Failed") FAILED = "failed", _("Failed")
DISABLED = "disabled", _("Disabled") DISABLED = "disabled", _("Disabled")
class MailboxStatusChoices(models.TextChoices):
"""Lists the possible statuses in which a mailbox can be."""
PENDING = "pending", _("Pending")
ENABLED = "enabled", _("Enabled")
FAILED = "failed", _("Failed")
DISABLED = "disabled", _("Disabled")

View File

@@ -75,3 +75,9 @@ class MailboxFactory(factory.django.DjangoModelFactory):
) )
domain = factory.SubFactory(MailDomainEnabledFactory) domain = factory.SubFactory(MailDomainEnabledFactory)
secondary_email = factory.Faker("email") secondary_email = factory.Faker("email")
class MailboxEnabledFactory(MailboxFactory):
"""A factory to create mailbox enabled."""
status = enums.MailboxStatusChoices.ENABLED

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.3 on 2024-11-18 14:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mailbox_manager', '0013_remove_maildomain_secret'),
]
operations = [
migrations.AddField(
model_name='mailbox',
name='status',
field=models.CharField(choices=[('pending', 'Pending'), ('enabled', 'Enabled'), ('failed', 'Failed'), ('disabled', 'Disabled')], default='pending', max_length=20),
),
]

View File

@@ -10,7 +10,11 @@ from django.utils.translation import gettext_lazy as _
from core.models import BaseModel from core.models import BaseModel
from mailbox_manager.enums import MailDomainRoleChoices, MailDomainStatusChoices from mailbox_manager.enums import (
MailboxStatusChoices,
MailDomainRoleChoices,
MailDomainStatusChoices,
)
class MailDomain(BaseModel): class MailDomain(BaseModel):
@@ -184,6 +188,11 @@ class Mailbox(BaseModel):
secondary_email = models.EmailField( secondary_email = models.EmailField(
_("secondary email address"), null=False, blank=False _("secondary email address"), null=False, blank=False
) )
status = models.CharField(
max_length=20,
choices=MailboxStatusChoices.choices,
default=MailboxStatusChoices.PENDING,
)
class Meta: class Meta:
db_table = "people_mail_box" db_table = "people_mail_box"
@@ -196,14 +205,8 @@ class Mailbox(BaseModel):
def clean(self): def clean(self):
""" """
Mailboxes can only be created on enabled domains. Mail-provisioning API credentials must be set for dimail to allow auth.
Also, mail-provisioning API credentials must be set for dimail to allow auth.
""" """
if self.domain.status != MailDomainStatusChoices.ENABLED:
raise exceptions.ValidationError(
"You can create mailbox only for a domain enabled"
)
# Won't be able to query user token if MAIL_PROVISIONING_API_CREDENTIALS are not set # Won't be able to query user token if MAIL_PROVISIONING_API_CREDENTIALS are not set
if not settings.MAIL_PROVISIONING_API_CREDENTIALS: if not settings.MAIL_PROVISIONING_API_CREDENTIALS:
raise exceptions.ValidationError( raise exceptions.ValidationError(
@@ -216,6 +219,11 @@ class Mailbox(BaseModel):
""" """
self.full_clean() self.full_clean()
if self.domain.status == MailDomainStatusChoices.DISABLED:
raise exceptions.ValidationError(
_("You can't create a mailbox for a disabled domain.")
)
if self._state.adding: if self._state.adding:
return super().save(*args, **kwargs) return super().save(*args, **kwargs)

View File

@@ -137,6 +137,7 @@ def test_api_mailboxes__create_roles_success(role):
"last_name": str(mailbox.last_name), "last_name": str(mailbox.last_name),
"local_part": str(mailbox.local_part), "local_part": str(mailbox.local_part),
"secondary_email": str(mailbox.secondary_email), "secondary_email": str(mailbox.secondary_email),
"status": enums.MailboxStatusChoices.ENABLED,
} }
@@ -194,6 +195,7 @@ def test_api_mailboxes__create_with_accent_success(role):
"last_name": str(mailbox.last_name), "last_name": str(mailbox.last_name),
"local_part": str(mailbox.local_part), "local_part": str(mailbox.local_part),
"secondary_email": str(mailbox.secondary_email), "secondary_email": str(mailbox.secondary_email),
"status": enums.MailboxStatusChoices.ENABLED,
} }
@@ -236,6 +238,73 @@ def test_api_mailboxes__create_administrator_missing_fields():
assert response.json() == {"secondary_email": ["This field is required."]} assert response.json() == {"secondary_email": ["This field is required."]}
@pytest.mark.parametrize(
"role",
[
enums.MailDomainRoleChoices.OWNER,
enums.MailDomainRoleChoices.ADMIN,
],
)
def test_api_mailboxes__cannot_create_on_disabled_domain(role):
"""Admin and owner users should not be able to create mailboxes for a disabled domain"""
mail_domain = factories.MailDomainFactory(
status=enums.MailDomainStatusChoices.DISABLED
)
access = factories.MailDomainAccessFactory(role=role, domain=mail_domain)
client = APIClient()
client.force_login(access.user)
mailbox_values = serializers.MailboxSerializer(
factories.MailboxFactory.build()
).data
response = client.post(
f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/",
mailbox_values,
format="json",
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert not models.Mailbox.objects.exists()
assert response.json() == ["You can't create a mailbox for a disabled domain."]
@pytest.mark.parametrize(
"domain_status",
[
enums.MailDomainStatusChoices.PENDING,
enums.MailDomainStatusChoices.FAILED,
],
)
def test_api_mailboxes__create_pending_mailboxes(domain_status):
"""
Admin and owner users should be able to create mailboxes, including on pending and failed
domains.
Mailboxes created on pending and failed domains should have the "pending" status
"""
mail_domain = factories.MailDomainFactory(status=domain_status)
access = factories.MailDomainAccessFactory(
role=enums.MailDomainRoleChoices.ADMIN, domain=mail_domain
)
client = APIClient()
client.force_login(access.user)
mailbox_values = serializers.MailboxSerializer(
factories.MailboxFactory.build()
).data
with responses.RequestsMock():
# We add no response in RequestsMock
# because we expect no outside calls to be made
response = client.post(
f"/api/v1.0/mail-domains/{mail_domain.slug}/mailboxes/",
mailbox_values,
format="json",
)
assert response.status_code == status.HTTP_201_CREATED
mailbox = models.Mailbox.objects.get()
assert mailbox.status == "pending"
### REACTING TO DIMAIL-API ### REACTING TO DIMAIL-API
### We mock dimail's responses to avoid testing dimail's container too ### We mock dimail's responses to avoid testing dimail's container too
@@ -411,6 +480,7 @@ def test_api_mailboxes__domain_owner_or_admin_successful_creation_and_provisioni
"last_name": str(mailbox_data["last_name"]), "last_name": str(mailbox_data["last_name"]),
"local_part": str(mailbox_data["local_part"]), "local_part": str(mailbox_data["local_part"]),
"secondary_email": str(mailbox_data["secondary_email"]), "secondary_email": str(mailbox_data["secondary_email"]),
"status": enums.MailboxStatusChoices.ENABLED,
} }
assert mailbox.first_name == mailbox_data["first_name"] assert mailbox.first_name == mailbox_data["first_name"]
assert mailbox.last_name == mailbox_data["last_name"] assert mailbox.last_name == mailbox_data["last_name"]

View File

@@ -53,8 +53,8 @@ def test_api_mailboxes__list_authenticated():
def test_api_mailboxes__list_roles(role): def test_api_mailboxes__list_roles(role):
"""Owner, admin and viewer users should be able to list mailboxes""" """Owner, admin and viewer users should be able to list mailboxes"""
mail_domain = factories.MailDomainEnabledFactory() mail_domain = factories.MailDomainEnabledFactory()
mailbox1 = factories.MailboxFactory(domain=mail_domain) mailbox1 = factories.MailboxEnabledFactory(domain=mail_domain)
mailbox2 = factories.MailboxFactory(domain=mail_domain) mailbox2 = factories.MailboxEnabledFactory(domain=mail_domain)
access = factories.MailDomainAccessFactory(role=role, domain=mail_domain) access = factories.MailDomainAccessFactory(role=role, domain=mail_domain)
client = APIClient() client = APIClient()
@@ -69,6 +69,7 @@ def test_api_mailboxes__list_roles(role):
"last_name": str(mailbox2.last_name), "last_name": str(mailbox2.last_name),
"local_part": str(mailbox2.local_part), "local_part": str(mailbox2.local_part),
"secondary_email": str(mailbox2.secondary_email), "secondary_email": str(mailbox2.secondary_email),
"status": enums.MailboxStatusChoices.ENABLED,
}, },
{ {
"id": str(mailbox1.id), "id": str(mailbox1.id),
@@ -76,6 +77,7 @@ def test_api_mailboxes__list_roles(role):
"last_name": str(mailbox1.last_name), "last_name": str(mailbox1.last_name),
"local_part": str(mailbox1.local_part), "local_part": str(mailbox1.local_part),
"secondary_email": str(mailbox1.secondary_email), "secondary_email": str(mailbox1.secondary_email),
"status": enums.MailboxStatusChoices.ENABLED,
}, },
] ]

View File

@@ -74,7 +74,7 @@ def test_models_mailboxes__domain_must_be_a_maildomain_instance():
def test_models_mailboxes__domain_cannot_be_null(): def test_models_mailboxes__domain_cannot_be_null():
"""The "domain" field should not be null.""" """The "domain" field should not be null."""
with pytest.raises(models.MailDomain.DoesNotExist, match="Mailbox has no domain."): with pytest.raises(exceptions.ValidationError, match="This field cannot be null"):
factories.MailboxFactory(domain=None) factories.MailboxFactory(domain=None)
@@ -93,44 +93,37 @@ def test_models_mailboxes__secondary_email_cannot_be_null():
factories.MailboxFactory(secondary_email=None) factories.MailboxFactory(secondary_email=None)
def test_models_mailboxes__cannot_be_created_for_disabled_maildomain(): @pytest.mark.parametrize(
"""Mailbox creation is allowed only for a domain enabled. "domain_status",
[
enums.MailDomainStatusChoices.PENDING,
enums.MailDomainStatusChoices.FAILED,
],
)
def test_models_mailboxes__can_create_pending_mailboxes_on_non_enabled_domain(
domain_status,
):
"""Mailbox creation is allowed for a domain pending and failed.
A pending mailbox is created."""
mailbox = factories.MailboxFactory(
domain=factories.MailDomainFactory(status=domain_status)
)
assert mailbox.status == enums.MailboxStatusChoices.PENDING
def test_models_mailboxes__cannot_create_mailboxes_on_disabled_domain():
"""Mailbox creation is not allowed for a domain disabled.
A disabled status for the mail domain raises an error.""" A disabled status for the mail domain raises an error."""
with pytest.raises( with pytest.raises(
exceptions.ValidationError, exceptions.ValidationError,
match="You can create mailbox only for a domain enabled", match="You can't create a mailbox for a disabled domain.",
): ):
factories.MailboxFactory( factories.MailboxFactory(
domain=factories.MailDomainFactory( domain=factories.MailDomainFactory(
status=enums.MailDomainStatusChoices.DISABLED status=enums.MailDomainStatusChoices.DISABLED
) )
) )
assert not models.Mailbox.objects.exist()
def test_models_mailboxes__cannot_be_created_for_failed_maildomain():
"""Mailbox creation is allowed only for a domain enabled.
A failed status for the mail domain raises an error."""
with pytest.raises(
exceptions.ValidationError,
match="You can create mailbox only for a domain enabled",
):
factories.MailboxFactory(
domain=factories.MailDomainFactory(
status=enums.MailDomainStatusChoices.FAILED
)
)
def test_models_mailboxes__cannot_be_created_for_pending_maildomain():
"""Mailbox creation is allowed only for a domain enabled.
A pending status for the mail domain raises an error."""
with pytest.raises(
exceptions.ValidationError,
match="You can create mailbox only for a domain enabled",
):
# MailDomainFactory initializes a mail domain with default values,
# so mail domain status is pending!
factories.MailboxFactory(domain=factories.MailDomainFactory())
### REACTING TO DIMAIL-API ### REACTING TO DIMAIL-API

View File

@@ -37,6 +37,21 @@ def test_models_mail_domain__slug_inferred_from_name():
assert domain.slug == slugify(name) assert domain.slug == slugify(name)
# "STATUS" FIELD
def test_models_mail_domain__status_should_not_be_empty():
"""Status field should not be empty."""
with pytest.raises(ValidationError, match="This field cannot be blank"):
factories.MailDomainFactory(status="")
def test_models_mail_domain__status_should_not_be_null():
"""Status field should not be null."""
with pytest.raises(ValidationError, match="This field cannot be null."):
factories.MailDomainFactory(status=None)
# get_abilities # get_abilities