Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename tasks/mailer.py to tasks/email.py #9404

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions h/jinja_extensions/navbar_data_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ def navbar_data_admin(request):
],
},
{
"id": "mailer",
"id": "email",
"permission": Permission.AdminPage.LOW_RISK,
"title": "Mailer",
"route": "admin.mailer",
"title": "Email",
"route": "admin.email",
},
{
"id": "nipsa",
Expand Down
8 changes: 4 additions & 4 deletions h/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ def includeme(config): # noqa: PLR0915
factory="h.traversal.GroupRequiredRoot",
traverse="/{id}",
)
config.add_route("admin.mailer", "/admin/mailer")
config.add_route("admin.mailer_test", "/admin/mailer/test")
config.add_route("admin.email", "/admin/email")
config.add_route("admin.email_test", "/admin/email/test")
config.add_route(
"admin.mailer.preview.mention_notification",
"/admin/mailer/preview/mention-notification",
"admin.email.preview.mention_notification",
"/admin/email/preview/mention-notification",
)
config.add_route("admin.nipsa", "/admin/nipsa")
config.add_route("admin.oauthclients", "/admin/oauthclients")
Expand Down
4 changes: 2 additions & 2 deletions h/services/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ def __init__(self, request: Request, mailer: IMailer) -> None:
self._request = request
self._mailer = mailer

def send(self, email: EmailData) -> None:
def send(self, email_data: EmailData) -> None:
if self._request.debug: # pragma: no cover
logger.info("emailing in debug mode: check the `mail/` directory")
try:
self._mailer.send_immediately(email.message)
self._mailer.send_immediately(email_data.message)
except smtplib.SMTPRecipientsRefused as exc: # pragma: no cover
logger.warning(
"Recipient was refused when trying to send an email. Does the user have an invalid email address?",
Expand Down
6 changes: 3 additions & 3 deletions h/services/user_signup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from h.services import SubscriptionService
from h.services.exceptions import ConflictError
from h.services.user_password import UserPasswordService
from h.tasks import mailer as tasks_mailer
from h.tasks import email

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -124,13 +124,13 @@ def _require_activation(self, user):
self.session.flush()

# Send the activation email
email = signup.generate(
email_data = signup.generate(
request=self.request,
user_id=user.id,
email=user.email,
activation_code=user.activation.code,
)
tasks_mailer.send.delay(asdict(email))
email.send.delay(asdict(email_data))


def user_signup_service_factory(_context, request):
Expand Down
10 changes: 5 additions & 5 deletions h/subscribers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from h.notification import mention, reply
from h.services import NotificationService
from h.services.annotation_read import AnnotationReadService
from h.tasks import mailer
from h.tasks import email

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -108,9 +108,9 @@ def send_reply_notifications(event):
logger.info("Skipping reply notification for %s", notification.parent_user)
return

email = emails.reply_notification.generate(request, notification)
email_data = emails.reply_notification.generate(request, notification)
try:
mailer.send.delay(asdict(email))
email.send.delay(asdict(email_data))
except OperationalError as err: # pragma: no cover
# We could not connect to rabbit! So carry on
report_exception(err)
Expand Down Expand Up @@ -146,9 +146,9 @@ def send_mention_notifications(event):
)
continue

email = emails.mention_notification.generate(request, notification)
email_data = emails.mention_notification.generate(request, notification)
try:
mailer.send.delay(asdict(email))
email.send.delay(asdict(email_data))
except OperationalError as err: # pragma: no cover
# We could not connect to rabbit! So carry on
report_exception(err)
Expand Down
2 changes: 1 addition & 1 deletion h/tasks/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"h.tasks.cleanup",
"h.tasks.indexer",
"h.tasks.job_queue",
"h.tasks.mailer",
"h.tasks.email",
"h.tasks.url_migration",
),
task_routes={
Expand Down
10 changes: 5 additions & 5 deletions h/tasks/mailer.py → h/tasks/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
A module for sending email.

This module defines a Celery task for sending emails in a worker process.
"""
""" # noqa: A005

from typing import Any

Expand All @@ -21,11 +21,11 @@
max_retries=3,
retry_jitter=False,
)
def send(self, email_data: dict[str, Any]) -> None: # noqa: ARG001
def send(self, data: dict[str, Any]) -> None: # noqa: ARG001
"""Send an email.

:param email_data: A dictionary containing email data compatible with EmailData class.
:param data: A dictionary containing email data compatible with EmailData class.
"""
service: EmailService = celery.request.find_service(EmailService)
email = EmailData(**email_data)
service.send(email)
email_data = EmailData(**data)
service.send(email_data)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends "h:templates/layouts/admin.html.jinja2" %}

{% set page_id = 'mailer' %}
{% set page_title = 'Mailer' %}
{% set page_id = 'email' %}
{% set page_title = 'Email' %}

{% block content %}

Expand All @@ -17,7 +17,7 @@
<h3 class="card-title mb-0">Send a test email</h3>
</div>
<div class="card-body">
<form method="POST" action="{{ request.route_path('admin.mailer_test') }}" class="form-inline">
<form method="POST" action="{{ request.route_path('admin.email_test') }}" class="form-inline">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
<div class="form-group">
<label for="recipient">Recipient</label>
Expand All @@ -35,7 +35,7 @@
<iframe
class="card-body p-0"
style="height: 40em; border: none;"
src="{{ request.route_url("admin.mailer.preview.mention_notification") }}"
src="{{ request.route_url("admin.email.preview.mention_notification") }}"
>
</iframe>
</div>
Expand Down
6 changes: 3 additions & 3 deletions h/views/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
ResetPasswordSchema,
)
from h.services import SubscriptionService
from h.tasks import mailer
from h.tasks import email
from h.util.view import json_view

_ = i18n.TranslationString
Expand Down Expand Up @@ -211,8 +211,8 @@ def _redirect_if_logged_in(self):
raise httpexceptions.HTTPFound(self.request.route_path("index"))

def _send_forgot_password_email(self, user):
email = reset_password.generate(self.request, user)
mailer.send.delay(asdict(email))
email_data = reset_password.generate(self.request, user)
email.send.delay(asdict(email_data))


@view_defaults(
Expand Down
26 changes: 13 additions & 13 deletions h/views/admin/mailer.py → h/views/admin/email.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
from dataclasses import asdict
from dataclasses import asdict # noqa: A005

from pyramid.httpexceptions import HTTPSeeOther
from pyramid.view import view_config

from h.emails import test
from h.security import Permission
from h.tasks import mailer
from h.tasks import email


@view_config(
route_name="admin.mailer",
route_name="admin.email",
request_method="GET",
renderer="h:templates/admin/mailer.html.jinja2",
renderer="h:templates/admin/email.html.jinja2",
permission=Permission.AdminPage.LOW_RISK,
)
def mailer_index(request):
"""Show the mailer test tools."""
def email_index(request):
"""Show the email test tools."""
return {"taskid": request.params.get("taskid")}

Check warning

Code scanning / CodeQL

Reflected server-side cross-site scripting Medium

Cross-site scripting vulnerability due to a
user-provided value
.


@view_config(
route_name="admin.mailer_test",
route_name="admin.email_test",
request_method="POST",
permission=Permission.AdminPage.LOW_RISK,
require_csrf=True,
)
def mailer_test(request):
def email_test(request):
"""Send a test email."""
if "recipient" not in request.params:
index = request.route_path("admin.mailer")
index = request.route_path("admin.email")
return HTTPSeeOther(location=index)

email = test.generate(request, request.params["recipient"])
result = mailer.send.delay(asdict(email))
index = request.route_path("admin.mailer", _query={"taskid": result.task_id})
email_data = test.generate(request, request.params["recipient"])
result = email.send.delay(asdict(email_data))
index = request.route_path("admin.email", _query={"taskid": result.task_id})
return HTTPSeeOther(location=index)


@view_config(
route_name="admin.mailer.preview.mention_notification",
route_name="admin.email.preview.mention_notification",
request_method="GET",
permission=Permission.AdminPage.LOW_RISK,
renderer="h:templates/emails/mention_notification.html.jinja2",
Expand Down
8 changes: 4 additions & 4 deletions h/views/api/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from h.emails import flag_notification
from h.security import Permission
from h.security.permission_map import GROUP_MODERATE_PREDICATES
from h.tasks import mailer
from h.tasks import email
from h.views.api.config import api_config


Expand Down Expand Up @@ -38,6 +38,6 @@ def _email_group_moderators(request, annotation):
)

for membership in memberships:
if email := membership.user.email:
email = flag_notification.generate(request, email, incontext_link)
mailer.send.delay(asdict(email))
if user_email := membership.user.email:
email_data = flag_notification.generate(request, user_email, incontext_link)
email.send.delay(asdict(email_data))
2 changes: 1 addition & 1 deletion tests/functional/h/views/admin/permissions_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class TestAdminPermissions:
("/admin/badge", False),
("/admin/features", False),
("/admin/groups", True),
("/admin/mailer", True),
("/admin/email", True),
("/admin/nipsa", False),
("/admin/oauthclients", False),
("/admin/organizations", True),
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/h/jinja2_extensions/navbar_data_admin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from h.jinja_extensions import navbar_data_admin

STAFF_TABS = ["index", "groups", "mailer", "organizations", "users"]
STAFF_TABS = ["index", "groups", "email", "organizations", "users"]


class TestNavbarDataAdmin:
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/h/routes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ def test_includeme():
factory="h.traversal.GroupRequiredRoot",
traverse="/{id}",
),
call("admin.mailer", "/admin/mailer"),
call("admin.mailer_test", "/admin/mailer/test"),
call("admin.email", "/admin/email"),
call("admin.email_test", "/admin/email/test"),
call(
"admin.mailer.preview.mention_notification",
"/admin/mailer/preview/mention-notification",
"admin.email.preview.mention_notification",
"/admin/email/preview/mention-notification",
),
call("admin.nipsa", "/admin/nipsa"),
call("admin.oauthclients", "/admin/oauthclients"),
Expand Down
22 changes: 10 additions & 12 deletions tests/unit/h/services/user_signup_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ def test_signup_sets_password_using_password_service(

user_password_service.update_password.assert_called_once_with(user, "wibble")

def test_signup_sends_email(
self, svc, signup, tasks_mailer, pyramid_request, asdict
):
def test_signup_sends_email(self, svc, signup, email, pyramid_request, asdict):
signup.generate.return_value = sentinel.email
asdict.return_value = sentinel.email_data

Expand All @@ -109,15 +107,15 @@ def test_signup_sends_email(
)

asdict.assert_called_once_with(signup.generate.return_value)
tasks_mailer.send.delay.assert_called_once_with(asdict.return_value)
email.send.delay.assert_called_once_with(asdict.return_value)

def test_signup_does_not_send_email_when_activation_not_required(
self, svc, signup, tasks_mailer
self, svc, signup, email
):
svc.signup(require_activation=False, username="foo", email="[email protected]")

signup.generate.assert_not_called()
tasks_mailer.send.delay.assert_not_called()
email.send.delay.assert_not_called()

def test_signup_creates_subscriptions(self, svc, subscription_service, factories):
subscription = factories.Subscriptions(active=False)
Expand All @@ -144,7 +142,7 @@ def test_signup_logs_conflict_error_when_account_with_email_already_exists(
)

@pytest.mark.parametrize(
"username,email",
"username,user_email",
[
# In the real world these values would be identical to the first signup but
# since we need to force one to error before the other, only the email or
Expand All @@ -157,16 +155,16 @@ def test_signup_logs_conflict_error_when_account_with_email_already_exists(
],
)
def test_signup_raises_conflict_error_when_account_already_exists(
self, svc, username, email
self, svc, username, user_email
):
# This happens when two or more identical
# concurrent signup requests race each other to the db.
with pytest.raises( # noqa: PT012
ConflictError,
match=f"The email address {email} has already been registered.",
match=f"The email address {user_email} has already been registered.",
):
svc.signup(username="foo", email="[email protected]")
svc.signup(username=username, email=email)
svc.signup(username=username, email=user_email)

@pytest.fixture
def svc(self, pyramid_request, user_password_service, subscription_service):
Expand All @@ -178,8 +176,8 @@ def svc(self, pyramid_request, user_password_service, subscription_service):
)

@pytest.fixture(autouse=True)
def tasks_mailer(self, patch):
return patch("h.services.user_signup.tasks_mailer")
def email(self, patch):
return patch("h.services.user_signup.email")

@pytest.fixture(autouse=True)
def signup(self, patch):
Expand Down
Loading
Loading