Passed
Push — main ( 419964...c34879 )
by Jochen
04:40
created

subscribers()   B

Complexity

Conditions 5

Size

Total Lines 41
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 34
nop 2
dl 0
loc 41
rs 8.5973
c 0
b 0
f 0
1
"""
2
:Copyright: 2014-2022 Jochen Kupperschmidt
3
:License: Revised BSD (see `LICENSE` file for details)
4
"""
5
6
from datetime import datetime
7
8
import pytest
9
10
from byceps.services.newsletter import command_service
11
from byceps.services.newsletter.types import SubscriptionState
12
from byceps.services.user import command_service as user_command_service
13
14
from tests.helpers import log_in_user
15
16
17
def test_export_subscribers(newsletter_list, subscribers, client):
18
    expected_data = {
19
        'subscribers': [
20
            {
21
                'screen_name': 'User-1',
22
                'email_address': '[email protected]',
23
            },
24
25
            # User #2 has declined a subscription, and thus should be
26
            # excluded.
27
28
            # User #3 is not initialized, and thus should be excluded.
29
30
            # User #4 was initialized, but has its email address marked
31
            # as unverified later on, so it should be included.
32
33
            # User #5 has initially declined, but later requested a
34
            # subscription, so it should be included.
35
            {
36
                'screen_name': 'User-5',
37
                'email_address': '[email protected]',
38
            },
39
40
            # User #6 has initially requested, but later declined a
41
            # subscription, so it should be excluded.
42
43
            {
44
                'screen_name': 'User-7',
45
                'email_address': '[email protected]',
46
            },
47
48
            # User #8 has been suspended and should be excluded, regardless
49
            # of subscription state.
50
51
            # User #9 has been deleted and should be excluded, regardless
52
            # of subscription state.
53
54
            # Just another user to ensure the list hasn't been truncated early.
55
            {
56
                'screen_name': 'User-10',
57
                'email_address': '[email protected]',
58
            },
59
        ],
60
    }
61
62
    url = f'/admin/newsletter/lists/{newsletter_list.id}/subscriptions/export'
63
    response = client.get(url)
64
65
    assert response.status_code == 200
66
    assert response.content_type == 'application/json'
67
    assert response.json == expected_data
68
69
70
def test_export_subscriber_email_addresses(
71
    newsletter_list, subscribers, client
72
):
73
    expected_email_addresses = [
74
        '[email protected]',
75
        # User #2 has declined a subscription.
76
        # User #3 is not initialized.
77
        # User #4 is initialized, but email address is unverified.
78
        # User #5 has initially declined, but later requested a subscription.
79
        '[email protected]',
80
        # User #6 has initially requested, but later declined a subscription.
81
        '[email protected]',
82
        # User #8 has been suspended, and thus should be excluded.
83
        # User #9 has been deleted, and thus should be excluded.
84
        '[email protected]',
85
    ]
86
    expected_data = '\n'.join(expected_email_addresses).encode('utf-8')
87
88
    url = f'/admin/newsletter/lists/{newsletter_list.id}/subscriptions/email_addresses/export'
89
    response = client.get(url)
90
91
    assert response.status_code == 200
92
    assert response.content_type == 'text/plain; charset=utf-8'
93
    assert response.mimetype == 'text/plain'
94
    assert response.get_data() == expected_data
95
96
97
@pytest.fixture(scope='package')
98
def newsletter_admin(make_admin):
99
    permission_ids = {'admin.access', 'newsletter.export_subscribers'}
100
    admin = make_admin('NewsletterAdmin', permission_ids)
101
    log_in_user(admin.id)
102
    return admin
103
104
105
@pytest.fixture(scope='module')
106
def newsletter_list(admin_app):
107
    return command_service.create_list('example', 'Example')
108
109
110
@pytest.fixture(scope='module')
111
def subscribers(make_user, newsletter_list):
112
    for (
113
        number,
114
        initialized,
115
        email_address_verified,
116
        suspended,
117
        deleted,
118
        states,
119
    ) in [
120
        ( 1, True , True , False, False, [SubscriptionState.requested                             ]),
121
        ( 2, True , True , False, False, [SubscriptionState.declined                              ]),
122
        ( 3, False, True , False, False, [SubscriptionState.requested                             ]),
123
        ( 4, True , False, False, False, [SubscriptionState.requested                             ]),
124
        ( 5, True , True , False, False, [SubscriptionState.declined,  SubscriptionState.requested]),
125
        ( 6, True , True , False, False, [SubscriptionState.requested, SubscriptionState.declined ]),
126
        ( 7, True , True , False, False, [SubscriptionState.requested                             ]),
127
        ( 8, True , True , True , False, [SubscriptionState.requested                             ]),
128
        ( 9, True , True , False, True , [SubscriptionState.requested                             ]),
129
        (10, True , True , False, False, [SubscriptionState.requested                             ]),
130
    ]:
131
        user = make_user(
132
            screen_name=f'User-{number:d}',
133
            email_address=f'user{number:03d}@users.test',
134
            email_address_verified=email_address_verified,
135
            initialized=initialized,
136
            suspended=suspended,
137
            deleted=deleted,
138
        )
139
140
        list_id = newsletter_list.id
141
142
        for state in states:
143
            # Timestamp must not be identical for multiple
144
            # `(user_id, list_id)` pairs.
145
            expressed_at = datetime.utcnow()
146
147
            if state == SubscriptionState.requested:
148
                command_service.subscribe(user.id, list_id, expressed_at)
149
            elif state == SubscriptionState.declined:
150
                command_service.unsubscribe(user.id, list_id, expressed_at)
151
152
153
@pytest.fixture(scope='package')
154
def client(admin_app, make_client, newsletter_admin):
155
    return make_client(admin_app, user_id=newsletter_admin.id)
156