コード例 #1
0
    def test_get_all_active_subscribers(self, tiny_db_storage):
        active = (
            Registration(
                email=Email("*****@*****.**"),
                last_update=datetime.utcnow(),
                state=State.subscribed,
            ),
            Registration(
                email=Email("*****@*****.**"),
                last_update=datetime.now(),
                state=State.pending_unsubscribe,
                confirm_action=Action.unsubscribe,
                confirm_token=Token(b"token"),
            ),
        )
        inactive = (Registration(
            email=Email("*****@*****.**"),
            last_update=datetime.now(),
            state=State.pending_subscribe,
            confirm_action=Action.subscribe,
            confirm_token=Token(b"token"),
        ), )

        for r in active + inactive:
            tiny_db_storage.upsert(r)

        result = tiny_db_storage.get_all_active_subscribers()

        assert tuple(sorted(result, key=lambda r: r.email)) == active
コード例 #2
0
    def test_find_returns_matching_entity(self, tiny_db, tiny_db_storage):
        last_update = datetime(2019, 10, 25, 13, 37)
        tiny_db.insert({
            "email": "*****@*****.**",
            "last_update": last_update.isoformat(),
            "state": "subscribed",
            "confirm_action": None,
            "confirm_token": None,
        })

        assert tiny_db_storage.find(Email("*****@*****.**")) == Registration(
            email=Email("*****@*****.**"),
            last_update=last_update,
            state=State.subscribed,
        )
コード例 #3
0
    def test_confirm_link_substitutions(self, settings):
        template = "{{confirm_link}}"
        token = Token(b"token")

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                "subscribe.subject.txt": template,
                "subscribe.txt": template,
                "subscribe.html": template,
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_confirmation_request_msg(Email("email@local"),
                                                    action=Action.subscribe,
                                                    confirm_token=token)

        expected_link = (
            "https://test.local/subscribe/confirm/email%40local?token=" +
            quote(token.to_string()))
        assert msg["Subject"] == expected_link
        assert (msg.get_body("plain").get_content().strip() ==
                expected_link  # type: ignore
                )
        assert (msg.get_body("html").get_content().strip() ==
                expected_link  # type: ignore
                )
コード例 #4
0
def test_subscription_and_unsubscription_flow(client, db,
                                              confirmation_requester):
    given_email = Email("*****@*****.**")
    assert_success(client.post(f"/subscribe/{given_email}"))
    assert_success(
        client.post(
            f"/confirm/{given_email}",
            headers=[(
                "Authorization",
                "Bearer " + confirmation_requester.tokens[given_email],
            )],
        ))

    assert db.get(Query().email == given_email)["state"] == "subscribed"

    assert_success(client.post(f"/unsubscribe/{given_email}"))
    assert_success(
        client.post(
            f"/confirm/{given_email}",
            headers=[(
                "Authorization",
                "Bearer " + confirmation_requester.tokens[given_email],
            )],
        ))

    assert db.get(Query().email == given_email) is None
コード例 #5
0
    def test_if_subscription_pending_has_no_effect(self, registration_service,
                                                   storage,
                                                   confirmation_requester,
                                                   utcnow):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(
                email=given_email,
                state=State.pending_subscribe,
                last_update=utcnow() - timedelta(days=1),
                confirm_token=Token(b"token"),
                confirm_action=Action.subscribe,
            ))

        registration_service.unsubscribe(given_email)

        stored = storage.find(given_email)
        assert not confirmation_requester.request_confirmation.called
        assert stored == Registration(
            email=given_email,
            state=State.pending_subscribe,
            last_update=utcnow() - timedelta(days=1),
            confirm_token=Token(b"token"),
            confirm_action=Action.subscribe,
        )
コード例 #6
0
def test_confirm_unauthorized(client, db, confirmation_requester):
    given_email = Email("*****@*****.**")
    assert_success(client.post(f"/subscribe/{given_email}"))

    unknown_email_response = client.post(
        f"/confirm/non-{given_email}",
        headers=[("Authorization",
                  "Bearer " + confirmation_requester.tokens[given_email])],
    )
    assert unknown_email_response.status_code == http.HTTPStatus.UNAUTHORIZED

    missing_auth_response = client.post(f"/confirm/{given_email}")
    assert missing_auth_response.status_code == http.HTTPStatus.UNAUTHORIZED

    assert (client.post(
        f"/confirm/non-{given_email}",
        headers=[("Authorization",
                  "Basic " + confirmation_requester.tokens[given_email])],
    )).status_code == http.HTTPStatus.UNAUTHORIZED

    known_email_response = client.post(
        f"/confirm/non-{given_email}",
        headers=[("Authorization", "Bearer invalid-token")],
    )
    assert known_email_response.status_code == http.HTTPStatus.UNAUTHORIZED

    assert known_email_response.data == unknown_email_response.data
コード例 #7
0
    def test_if_subscription_is_pending_resends_confirm_mail(
        self,
        registration_service,
        storage,
        confirmation_requester,
        token_generator,
        utcnow,
    ):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(
                email=given_email,
                state=State.pending_subscribe,
                last_update=utcnow() - timedelta(days=1),
                confirm_token=next(token_generator),
                confirm_action=Action.subscribe,
            ))

        registration_service.subscribe(given_email)

        confirmation_requester.request_confirmation.assert_called_with(
            given_email,
            action=Action.subscribe,
            confirm_token=token_generator.generated_tokens[0],
        )
コード例 #8
0
def test_email_notifier():
    subscribers = [
        Registration(
            email=Email("*****@*****.**"),
            last_update=datetime.utcnow(),
            state=State.subscribed,
        ),
        Registration(
            email=Email("*****@*****.**"),
            last_update=datetime.utcnow(),
            state=State.subscribed,
        ),
    ]
    message = EmailMessage()
    feed_item = FeedItem(
        title="title",
        link="link",
        pub_date=datetime.now(),
        description="description",
        image=None,
    )

    storage = MagicMock()
    connection_manager = MagicMock()
    connection = MagicMock()
    message_provider = MagicMock()

    storage.get_all_active_subscribers.return_value = subscribers
    connection_manager.__enter__.return_value = connection
    message_provider.get_new_post_msg.return_value = message

    email_notifier = EmailNotifier(storage, lambda: connection_manager,
                                   message_provider)
    email_notifier(feed_item)

    message_provider.get_new_post_msg.assert_has_calls(
        (
            call(feed_item, Email("*****@*****.**")),
            call(feed_item, Email("*****@*****.**")),
        ),
        any_order=True,
    )
    connection.send_message.assert_has_calls((call(message), call(message)))
コード例 #9
0
 def test_if_email_unknown_sends_subscription_confirm_mail(
         self, registration_service, confirmation_requester,
         token_generator, utcnow):
     given_email = Email("*****@*****.**")
     registration_service.subscribe(given_email)
     confirmation_requester.request_confirmation.assert_called_with(
         given_email,
         action=Action.subscribe,
         confirm_token=token_generator.generated_tokens[0],
     )
コード例 #10
0
    def test_confirm_for_registration_without_confirm_action_raises_exception(
            self, registration_service, storage, utcnow):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(
                email=given_email,
                state=State.subscribed,
                last_update=utcnow() - timedelta(days=1),
            ))

        with pytest.raises(UnauthorizedException):
            registration_service.confirm(given_email, None)
コード例 #11
0
    def test_drop_old_unconfirmed(self, tiny_db_storage):
        reference_datetime = datetime(2019, 10, 25, 13, 18)
        fresh = (
            Registration(
                email=Email("*****@*****.**"),
                last_update=reference_datetime - timedelta(days=1),
                state=State.pending_subscribe,
                confirm_action=Action.subscribe,
                confirm_token=Token(b"token"),
            ),
            Registration(
                email=Email("*****@*****.**"),
                last_update=reference_datetime - timedelta(days=3),
                state=State.subscribed,
            ),
            Registration(
                email=Email("*****@*****.**"),
                last_update=reference_datetime - timedelta(days=3),
                state=State.pending_unsubscribe,
                confirm_action=Action.unsubscribe,
                confirm_token=Token(b"token"),
            ),
        )
        old = (Registration(
            email=Email("*****@*****.**"),
            last_update=reference_datetime - timedelta(days=3),
            state=State.pending_subscribe,
            confirm_action=Action.subscribe,
            confirm_token=Token(b"token"),
        ), )

        for r in fresh + old:
            tiny_db_storage.upsert(r)

        tiny_db_storage.drop_old_unconfirmed(drop_before=reference_datetime -
                                             timedelta(days=2))

        assert tuple(sorted(tiny_db_storage.all(),
                            key=lambda r: r.email)) == fresh
コード例 #12
0
 def test_if_email_unknown_creates_registration(self, registration_service,
                                                storage, token_generator,
                                                utcnow):
     given_email = Email("*****@*****.**")
     registration_service.subscribe(given_email)
     stored = storage.find(given_email)
     assert stored == Registration(
         email=given_email,
         state=State.pending_subscribe,
         last_update=utcnow(),
         confirm_token=token_generator.generated_tokens[0],
         confirm_action=Action.subscribe,
     )
コード例 #13
0
    def test_urlquote(self, feed_item, settings):
        subject = "{{ '@' | urlquote }}"
        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                f"new-post.subject.txt": subject,
                "new-post.txt": "",
                "new-post.html": "",
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_new_post_msg(feed_item, Email("email"))

        assert msg["Subject"] == "%40"
コード例 #14
0
    def test_constructs_email_message_from_templates(self, feed_item,
                                                     settings):
        to_email = Email("*****@*****.**")
        subject = "subject"
        plain_text = "plain text"
        html = "html"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                f"new-post.subject.txt": subject,
                f"new-post.txt": plain_text,
                f"new-post.html": html,
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_new_post_msg(feed_item, Email("email"))

        assert msg["Subject"] == subject
        assert msg.get_body(
            "plain").get_content().strip() == plain_text  # type: ignore
        assert msg.get_body(
            "html").get_content().strip() == html  # type: ignore
コード例 #15
0
    def test_include_binary_and_b64encode(self, feed_item, settings):
        binary_content = b"binary content"
        subject = "{{ include_binary('bin') | b64encode }}"
        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                f"new-post.subject.txt": subject,
                "new-post.txt": "",
                "new-post.html": "",
            }),
            binary_loader=MockBinaryLoader({"bin": binary_content}),
        )
        msg = provider.get_new_post_msg(feed_item, Email("email"))

        assert msg["Subject"] == b64encode(binary_content).decode("ascii")
コード例 #16
0
    def test_confirm_with_invalid_token_raises_exception(
            self, state, registration_service, storage, utcnow):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(
                email=given_email,
                state=state,
                last_update=utcnow() - timedelta(days=1),
                confirm_token=Token(b"actual token"),
                confirm_action=Action.subscribe
                if state == State.pending_subscribe else Action.unsubscribe,
            ))

        with pytest.raises(UnauthorizedException):
            registration_service.confirm(given_email, Token(b"invalid token"))
コード例 #17
0
    def test_subject_substitutions(self, feed_item, settings):
        subject = "{{display_name}} {{host}} {{to_email}} {{post.title}}"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                "new-post.subject.txt": subject,
                "new-post.txt": "",
                "new-post.html": "",
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_new_post_msg(feed_item, Email("email"))

        assert msg[
            "Subject"] == f"{settings.display_name} {settings.host} email title"
コード例 #18
0
    def test_confirm_with_valid_token_removes_subscription(
            self, registration_service, storage, utcnow):
        given_email = Email("*****@*****.**")
        given_token = Token(b"token")
        storage.upsert(
            Registration(
                email=given_email,
                state=State.pending_unsubscribe,
                last_update=utcnow() - timedelta(days=1),
                confirm_token=given_token,
                confirm_action=Action.unsubscribe,
            ))

        registration_service.confirm(given_email, given_token)

        assert storage.find(given_email) is None
コード例 #19
0
    def test_delete_existing_entity(self, tiny_db, tiny_db_storage):
        tiny_db.insert({
            "email":
            "*****@*****.**",
            "last_update":
            datetime(2019, 10, 25, 13, 37).isoformat(),
            "state":
            "subscribed",
            "confirm_action":
            None,
            "confirm_token":
            None,
        })

        tiny_db_storage.delete(Email("*****@*****.**"))

        assert tiny_db.get(Query().email == "*****@*****.**") is None
コード例 #20
0
    def test_upsert_of_new_entity(self, tiny_db, tiny_db_storage):
        last_update = datetime(2019, 10, 25, 13, 37)
        registration = Registration(
            email=Email("*****@*****.**"),
            last_update=last_update,
            state=State.subscribed,
        )

        tiny_db_storage.upsert(registration)

        assert tiny_db.get(Query().email == "*****@*****.**") == {
            "email": "*****@*****.**",
            "last_update": last_update.isoformat(),
            "state": "subscribed",
            "confirm_action": None,
            "confirm_token": None,
        }
コード例 #21
0
    def test_include_binary_and_b64encode(self, settings):
        binary_content = b"binary content"
        subject = "{{ include_binary('bin') | b64encode }}"
        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                f"subscribe.subject.txt": subject,
                "subscribe.txt": "",
                "subscribe.html": "",
            }),
            binary_loader=MockBinaryLoader({"bin": binary_content}),
        )
        msg = provider.get_confirmation_request_msg(
            Email("email"),
            action=Action.subscribe,
            confirm_token=Token(b"token"))

        assert msg["Subject"] == b64encode(binary_content).decode("ascii")
コード例 #22
0
    def test_subject_substitutions(self, settings):
        subject = "{{display_name}} {{host}} {{to_email}}"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                "subscribe.subject.txt": subject,
                "subscribe.txt": "",
                "subscribe.html": "",
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_confirmation_request_msg(
            Email("email"),
            action=Action.subscribe,
            confirm_token=Token(b"token"))

        assert msg[
            "Subject"] == f"{settings.display_name} {settings.host} email"
コード例 #23
0
    def test_if_subscribed_sets_registration_to_pending_unsubscribe(
            self, state, registration_service, storage, token_generator,
            utcnow):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(email=given_email,
                         state=state,
                         last_update=utcnow() - timedelta(days=1)))

        registration_service.unsubscribe(given_email)

        stored = storage.find(given_email)
        assert stored == Registration(
            email=given_email,
            state=State.pending_unsubscribe,
            last_update=utcnow(),
            confirm_token=token_generator.generated_tokens[0],
            confirm_action=Action.unsubscribe,
        )
コード例 #24
0
    def test_body_substitutions(self, feed_item, settings):
        subject = "subject"
        template = "{{subject}} {{display_name}} {{host}} {{to_email}} {{post.title}}"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                "new-post.subject.txt": subject,
                "new-post.txt": template,
                "new-post.html": template,
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_new_post_msg(feed_item, Email("email"))

        assert (
            msg.get_body("plain").get_content().strip()  # type: ignore
            == f"{subject} {settings.display_name} {settings.host} email title"
        )
コード例 #25
0
    def test_body_substitutions(self, settings):
        subject = "subject"
        template = "{{subject}} {{display_name}} {{host}} {{to_email}}"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                "subscribe.subject.txt": subject,
                "subscribe.txt": template,
                "subscribe.html": template,
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_confirmation_request_msg(
            Email("email"),
            action=Action.subscribe,
            confirm_token=Token(b"token"))

        assert (msg.get_body("plain").get_content().strip()  # type: ignore
                == f"{subject} {settings.display_name} {settings.host} email")
コード例 #26
0
    def test_if_subscribed_no_effect(
        self,
        state,
        registration_service,
        storage,
        confirmation_requester,
        token_generator,
        utcnow,
    ):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(email=given_email,
                         state=state,
                         last_update=utcnow() - timedelta(days=1)))

        registration_service.subscribe(given_email)

        stored = storage.find(given_email)
        assert not confirmation_requester.request_confirmation.called
        assert stored == Registration(email=given_email,
                                      state=state,
                                      last_update=utcnow() - timedelta(days=1))
コード例 #27
0
    def test_if_subscribed_requests_confirmation(
        self,
        state,
        registration_service,
        storage,
        confirmation_requester,
        token_generator,
        utcnow,
    ):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(email=given_email,
                         state=state,
                         last_update=utcnow() - timedelta(days=1)))

        registration_service.unsubscribe(given_email)

        confirmation_requester.request_confirmation.assert_called_with(
            given_email,
            action=Action.unsubscribe,
            confirm_token=token_generator.generated_tokens[0],
        )
コード例 #28
0
    def test_if_subscription_is_pending_bumps_last_update(
            self, registration_service, storage, token_generator, utcnow):
        given_email = Email("*****@*****.**")
        storage.upsert(
            Registration(
                email=given_email,
                state=State.pending_subscribe,
                last_update=utcnow() - timedelta(days=1),
                confirm_token=next(token_generator),
                confirm_action=Action.subscribe,
            ))

        registration_service.subscribe(given_email)

        stored = storage.find(given_email)
        assert stored == Registration(
            email=given_email,
            state=State.pending_subscribe,
            last_update=utcnow(),
            confirm_token=token_generator.generated_tokens[0],
            confirm_action=Action.subscribe,
        )
コード例 #29
0
def test_email_confirmation_requester():
    email = Email("email")
    action = Action.subscribe
    confirm_token = Token(b"token")
    message = EmailMessage()

    connection_manager = MagicMock()
    connection = MagicMock()
    message_provider = MagicMock()

    connection_manager.__enter__.return_value = connection
    message_provider.get_confirmation_request_msg.return_value = message

    requester = EmailConfirmationRequester(
        connection=lambda: connection_manager,
        message_provider=message_provider)
    requester.request_confirmation(email,
                                   action=action,
                                   confirm_token=confirm_token)

    message_provider.get_confirmation_request_msg.assert_called_once_with(
        email, action=action, confirm_token=confirm_token)
    connection.send_message.assert_called_once_with(message)
コード例 #30
0
    def test_constructs_email_message_from_templates(self, action, settings):
        to_email = Email("*****@*****.**")
        subject = "subject"
        plain_text = "plain text"
        html = "html"

        provider = EmailFromTemplateProvider(
            settings=settings,
            template_loader=MockTemplateLoader({
                f"{action.name}.subject.txt": subject,
                f"{action.name}.txt": plain_text,
                f"{action.name}.html": html,
            }),
            binary_loader=MockBinaryLoader(dict()),
        )
        msg = provider.get_confirmation_request_msg(
            to_email, action=action, confirm_token=Token(b"token"))

        assert msg["Subject"] == subject
        assert msg["To"] == to_email
        assert msg.get_body(
            "plain").get_content().strip() == plain_text  # type: ignore
        assert msg.get_body(
            "html").get_content().strip() == html  # type: ignore