Skip to content

Commit

Permalink
refactor: can_use_domain return cause
Browse files Browse the repository at this point in the history
  • Loading branch information
cquintana92 committed Sep 17, 2024
1 parent f940df0 commit b2e9208
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 16 deletions.
49 changes: 39 additions & 10 deletions app/custom_domain_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re

from dataclasses import dataclass
from enum import Enum
from typing import Optional

from app.db import Session
Expand All @@ -20,6 +21,34 @@ class CreateCustomDomainResult:
redirect: Optional[str] = None


class CannotUseDomainReason(Enum):
InvalidDomain = 1
BuiltinDomain = 2
DomainAlreadyUsed = 3
DomainPartOfUserEmail = 4
DomainUserInMailbox = 5

def message(self, domain: str) -> str:
if self == CannotUseDomainReason.InvalidDomain:
return "This is not a valid domain"
elif self == CannotUseDomainReason.BuiltinDomain:
return "A custom domain cannot be a built-in domain."
elif self == CannotUseDomainReason.DomainAlreadyUsed:
return f"{domain} already used"
elif self == CannotUseDomainReason.DomainPartOfUserEmail:
return "You cannot add a domain that you are currently using for your personal email. Please change your personal email to your real email"
elif self == CannotUseDomainReason.DomainUserInMailbox:
return f"{domain} already used in a SimpleLogin mailbox"
else:
raise Exception("Invalid CannotUseDomainReason")


@dataclass
class CanDomainBeUsedResult:
can_be_used: bool
reason: Optional[CannotUseDomainReason] = None


def is_valid_domain(domain: str) -> bool:
"""
Checks that a domain is valid according to RFC 1035
Expand Down Expand Up @@ -48,21 +77,21 @@ def sanitize_domain(domain: str) -> str:
return new_domain


def can_domain_be_used(user: User, domain: str) -> Optional[str]:
def can_domain_be_used(user: User, domain: str) -> CanDomainBeUsedResult:
if not is_valid_domain(domain):
return "This is not a valid domain"
return CanDomainBeUsedResult(False, CannotUseDomainReason.InvalidDomain)
elif SLDomain.get_by(domain=domain):
return "A custom domain cannot be a built-in domain."
return CanDomainBeUsedResult(False, CannotUseDomainReason.BuiltinDomain)
elif CustomDomain.get_by(domain=domain):
return f"{domain} already used"
return CanDomainBeUsedResult(False, CannotUseDomainReason.DomainAlreadyUsed)
elif get_email_domain_part(user.email) == domain:
return "You cannot add a domain that you are currently using for your personal email. Please change your personal email to your real email"
return CanDomainBeUsedResult(False, CannotUseDomainReason.DomainPartOfUserEmail)
elif Mailbox.filter(
Mailbox.verified.is_(True), Mailbox.email.endswith(f"@{domain}")
).first():
return f"{domain} already used in a SimpleLogin mailbox"
return CanDomainBeUsedResult(False, CannotUseDomainReason.DomainUserInMailbox)
else:
return None
return CanDomainBeUsedResult(True)


def create_custom_domain(
Expand All @@ -75,10 +104,10 @@ def create_custom_domain(
)

new_domain = sanitize_domain(domain)
can_use_domain_error = can_domain_be_used(user, new_domain)
if can_use_domain_error:
can_use_domain = can_domain_be_used(user, new_domain)
if not can_use_domain.can_be_used:
return CreateCustomDomainResult(
message=can_use_domain_error, message_category="error"
message=can_use_domain.reason.message(new_domain), message_category="error"
)

new_custom_domain = CustomDomain.create(domain=new_domain, user_id=user.id)
Expand Down
25 changes: 19 additions & 6 deletions tests/test_custom_domain_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
create_custom_domain,
is_valid_domain,
sanitize_domain,
CannotUseDomainReason,
)
from app.db import Session
from app.models import User, CustomDomain, Mailbox
Expand Down Expand Up @@ -47,34 +48,46 @@ def test_is_valid_domain():
# can_domain_be_used
def test_can_domain_be_used():
domain = f"{random_string(10)}.com"
assert can_domain_be_used(user, domain) is None
res = can_domain_be_used(user, domain)
assert res.can_be_used is True
assert res.reason is None


def test_can_domain_be_used_existing_domain():
domain = random_domain()
CustomDomain.create(user_id=user.id, domain=domain, commit=True)
assert can_domain_be_used(user, domain) is not None
res = can_domain_be_used(user, domain)
assert res.can_be_used is False
assert res.reason is CannotUseDomainReason.DomainAlreadyUsed


def test_can_domain_be_used_sl_domain():
domain = ALIAS_DOMAINS[0]
assert can_domain_be_used(user, domain) is not None
res = can_domain_be_used(user, domain)
assert res.can_be_used is False
assert res.reason is CannotUseDomainReason.BuiltinDomain


def test_can_domain_be_used_domain_of_user_email():
domain = user.email.split("@")[1]
assert can_domain_be_used(user, domain) is not None
res = can_domain_be_used(user, domain)
assert res.can_be_used is False
assert res.reason is CannotUseDomainReason.DomainPartOfUserEmail


def test_can_domain_be_used_domain_of_existing_mailbox():
domain = random_domain()
Mailbox.create(user_id=user.id, email=f"email@{domain}", verified=True, commit=True)
assert can_domain_be_used(user, domain) is not None
res = can_domain_be_used(user, domain)
assert res.can_be_used is False
assert res.reason is CannotUseDomainReason.DomainUserInMailbox


def test_can_domain_be_used_invalid_domain():
domain = f"{random_string(10)}@lol.com"
assert can_domain_be_used(user, domain) is not None
res = can_domain_be_used(user, domain)
assert res.can_be_used is False
assert res.reason is CannotUseDomainReason.InvalidDomain


# sanitize_domain
Expand Down

0 comments on commit b2e9208

Please sign in to comment.