~homeworkprod/byceps

ref: 4237b3ec9496efe95dcce82bea3207ab9de4d520 byceps/byceps/services/user/email_address_verification_service.py -rw-r--r-- 3.6 KiB
4237b3ec — Jochen Kupperschmidt Move ticketing blueprint into `site` subpackage 1 year, 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
byceps.services.user.email_address_verification_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Modified BSD, see LICENSE for details.
"""

from typing import Optional

from ...database import db
from ...events.user import (
    UserEmailAddressConfirmed,
    UserEmailAddressInvalidated,
)
from ...typing import UserID

from ..email import service as email_service
from ..site import service as site_service
from ..site.transfer.models import SiteID
from ..user import service as user_service
from ..verification_token.models import Token
from ..verification_token import service as verification_token_service

from . import command_service, event_service as user_event_service


def send_email_address_confirmation_email(
    recipient_email_address: str,
    recipient_screen_name: str,
    user_id: UserID,
    site_id: SiteID,
) -> None:
    site = site_service.get_site(site_id)

    email_config = email_service.get_config(site.email_config_id)
    sender = email_config.sender

    verification_token = verification_token_service.create_for_email_address_confirmation(
        user_id
    )
    confirmation_url = (
        f'https://{site.server_name}/users/email_address/'
        f'confirmation/{verification_token.token}'
    )

    subject = f'{recipient_screen_name}, bitte bestätige deine E-Mail-Adresse'
    body = (
        f'Hallo {recipient_screen_name},\n\n'
        f'bitte bestätige deine E-Mail-Adresse, indem du diese URL abrufst: {confirmation_url}'
    )
    recipients = [recipient_email_address]

    email_service.enqueue_email(sender, recipients, subject, body)


def confirm_email_address(
    verification_token: Token,
) -> UserEmailAddressConfirmed:
    """Confirm the email address of the user assigned with that
    verification token.
    """
    user = user_service.get_db_user(verification_token.user_id)

    user.email_address_verified = True
    db.session.commit()

    # Currently, the user's e-mail address cannot be changed, but that
    # might be allowed in the future. At that point, the verification
    # token should be extended to include the e-mail address it refers
    # to, and that value should be persisted with user event instead.
    event_data = {'email_address': user.email_address}
    event = user_event_service.create_event(
        'user-email-address-confirmed', user.id, event_data
    )

    if not user.initialized:
        command_service.initialize_account(user.id)

    verification_token_service.delete_token(verification_token)

    return UserEmailAddressConfirmed(
        occurred_at=event.occurred_at, user_id=user.id, initiator_id=user.id
    )


def invalidate_email_address(
    user_id: UserID, reason: str, *, initiator_id: Optional[UserID] = None,
) -> UserEmailAddressInvalidated:
    """Invalidate the user's email address by marking it as unverified.

    This might be appropriate if an email to the user's address bounced
    because of a permanent issue (unknown mailbox, unknown domain, etc.)
    but not a temporary one (for example: mailbox full).
    """
    user = user_service.get_db_user(user_id)

    user.email_address_verified = False
    db.session.commit()

    event_data = {
        'email_address': user.email_address,
        'reason': reason,
    }
    if initiator_id:
        event_data['initiator_id'] = str(initiator_id)
    event = user_event_service.create_event(
        'user-email-address-invalidated', user.id, event_data
    )

    return UserEmailAddressInvalidated(
        occurred_at=event.occurred_at, user_id=user.id, initiator_id=user.id
    )