Completed
Push — master ( b6f8ef...f3cde1 )
by Jochen
16:59
created

newsletter.test_views.subscribers()   A

Complexity

Conditions 4

Size

Total Lines 27
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

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