API - allow admin to update a given user email
This commit is contained in:
parent
e8ca600e4a
commit
6c42b9ffbd
@ -228,8 +228,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
For security, this request was received from a {{operating_system}} device using {{browser_name}}.
|
{% if operating_system and browser_name %}For security, this request was received from a {{operating_system}} device using {{browser_name}}.
|
||||||
If this email change wasn't initiated by you, please ignore this email.
|
{% endif %}If this email change wasn't initiated by you, please ignore this email.
|
||||||
</p>
|
</p>
|
||||||
<p>Thanks,
|
<p>Thanks,
|
||||||
<br>The FitTrackee Team</p>
|
<br>The FitTrackee Team</p>
|
||||||
|
@ -4,8 +4,8 @@ You recently requested to change your email address for your FitTrackee account.
|
|||||||
|
|
||||||
Verify your email: {{ email_confirmation_url }}
|
Verify your email: {{ email_confirmation_url }}
|
||||||
|
|
||||||
For security, this request was received from a {{operating_system}} device using {{browser_name}}.
|
{% if operating_system and browser_name %}For security, this request was received from a {{operating_system}} device using {{browser_name}}.
|
||||||
If this email change wasn't initiated by you, please ignore this email.
|
{% endif %}If this email change wasn't initiated by you, please ignore this email.
|
||||||
|
|
||||||
Thanks,
|
Thanks,
|
||||||
The FitTrackee Team
|
The FitTrackee Team
|
||||||
|
@ -230,8 +230,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
Pour vérification, cette demande a été reçue à partir d'un appareil sous {{operating_system}}, utilisant le navigateur {{browser_name}}.
|
{% if operating_system and browser_name %}Pour vérification, cette demande a été reçue à partir d'un appareil sous {{operating_system}}, utilisant le navigateur {{browser_name}}.
|
||||||
Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
{% endif %}Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
||||||
</p>
|
</p>
|
||||||
<p>Merci,
|
<p>Merci,
|
||||||
<br>L'équipe FitTrackee</p>
|
<br>L'équipe FitTrackee</p>
|
||||||
|
@ -5,8 +5,8 @@ Cliquez sur le lien ci-dessous pour confirmer cette adresse email.
|
|||||||
|
|
||||||
Vérifier l'adresse email : {{ email_confirmation_url }}
|
Vérifier l'adresse email : {{ email_confirmation_url }}
|
||||||
|
|
||||||
Pour vérification, cette demande a été reçue à partir d'un appareil sous {{operating_system}}, utilisant le navigateur {{browser_name}}.
|
{% if operating_system and browser_name %}Pour vérification, cette demande a été reçue à partir d'un appareil sous {{operating_system}}, utilisant le navigateur {{browser_name}}.
|
||||||
Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
{% endif %}Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
||||||
|
|
||||||
Merci,
|
Merci,
|
||||||
L'équipe FitTrackee
|
L'équipe FitTrackee
|
||||||
|
@ -13,6 +13,18 @@ Thanks,
|
|||||||
The FitTrackee Team
|
The FitTrackee Team
|
||||||
http://localhost"""
|
http://localhost"""
|
||||||
|
|
||||||
|
expected_en_text_body_without_security = """Hi test,
|
||||||
|
|
||||||
|
You recently requested to change your email address for your FitTrackee account. Use the link below to confirm this address.
|
||||||
|
|
||||||
|
Verify your email: http://localhost/email-update?token=xxx
|
||||||
|
|
||||||
|
If this email change wasn't initiated by you, please ignore this email.
|
||||||
|
|
||||||
|
Thanks,
|
||||||
|
The FitTrackee Team
|
||||||
|
http://localhost"""
|
||||||
|
|
||||||
expected_fr_text_body = """Bonjour test,
|
expected_fr_text_body = """Bonjour test,
|
||||||
|
|
||||||
Vous avez récemment demandé la modification de l'adresse email associée à votre compte sur FitTrackee.
|
Vous avez récemment demandé la modification de l'adresse email associée à votre compte sur FitTrackee.
|
||||||
@ -27,6 +39,19 @@ Merci,
|
|||||||
L'équipe FitTrackee
|
L'équipe FitTrackee
|
||||||
http://localhost"""
|
http://localhost"""
|
||||||
|
|
||||||
|
expected_fr_text_body_without_security = """Bonjour test,
|
||||||
|
|
||||||
|
Vous avez récemment demandé la modification de l'adresse email associée à votre compte sur FitTrackee.
|
||||||
|
Cliquez sur le lien ci-dessous pour confirmer cette adresse email.
|
||||||
|
|
||||||
|
Vérifier l'adresse email : http://localhost/email-update?token=xxx
|
||||||
|
|
||||||
|
Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
||||||
|
|
||||||
|
Merci,
|
||||||
|
L'équipe FitTrackee
|
||||||
|
http://localhost"""
|
||||||
|
|
||||||
expected_en_html_body = """ <body>
|
expected_en_html_body = """ <body>
|
||||||
<span class="preheader">Use this link to confirm email change.</span>
|
<span class="preheader">Use this link to confirm email change.</span>
|
||||||
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
@ -99,6 +124,77 @@ expected_en_html_body = """ <body>
|
|||||||
</body>
|
</body>
|
||||||
</html>"""
|
</html>"""
|
||||||
|
|
||||||
|
expected_en_html_body_without_security = """ <body>
|
||||||
|
<span class="preheader">Use this link to confirm email change.</span>
|
||||||
|
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="email-masthead">
|
||||||
|
<a href="http://localhost" class="f-fallback email-masthead-name">
|
||||||
|
FitTrackee
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="email-body" width="100%" cellpadding="0" cellspacing="0">
|
||||||
|
<table class="email-body-inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="content-cell">
|
||||||
|
<div class="f-fallback">
|
||||||
|
<h1>Hi test,</h1>
|
||||||
|
<p>You recently requested to change your email address for your FitTrackee account. Use the button below to confirm this address.</p>
|
||||||
|
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="http://localhost/email-update?token=xxx" class="f-fallback button button--green" target="_blank">Verify your email</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
If this email change wasn't initiated by you, please ignore this email.
|
||||||
|
</p>
|
||||||
|
<p>Thanks,
|
||||||
|
<br>The FitTrackee Team</p>
|
||||||
|
<table class="body-sub" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="f-fallback sub">If you’re having trouble with the button above, copy and paste the URL below into your web browser.</p>
|
||||||
|
<p class="f-fallback sub">http://localhost/email-update?token=xxx</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="content-cell" align="center">
|
||||||
|
<p class="f-fallback sub align-center">© FitTrackee.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
|
||||||
expected_fr_html_body = """ <body>
|
expected_fr_html_body = """ <body>
|
||||||
<span class="preheader">Utiliser ce lien pour confirmer cette adresse email.</span>
|
<span class="preheader">Utiliser ce lien pour confirmer cette adresse email.</span>
|
||||||
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
@ -172,3 +268,76 @@ expected_fr_html_body = """ <body>
|
|||||||
</table>
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>"""
|
</html>"""
|
||||||
|
|
||||||
|
expected_fr_html_body_without_security = """ <body>
|
||||||
|
<span class="preheader">Utiliser ce lien pour confirmer cette adresse email.</span>
|
||||||
|
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="email-masthead">
|
||||||
|
<a href="http://localhost" class="f-fallback email-masthead-name">
|
||||||
|
FitTrackee
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="email-body" width="100%" cellpadding="0" cellspacing="0">
|
||||||
|
<table class="email-body-inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="content-cell">
|
||||||
|
<div class="f-fallback">
|
||||||
|
<h1>Bonjour test,</h1>
|
||||||
|
<p>Vous avez récemment demandé la modification de l'adresse email associée à votre compte sur FitTrackee.
|
||||||
|
Cliquez sur le bouton ci-dessous pour confirmer cette adresse email.
|
||||||
|
</p>
|
||||||
|
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="http://localhost/email-update?token=xxx" class="f-fallback button button--green" target="_blank">Vérifier l'adresse email</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
Si vous n'êtes pas à l'origine de cette modification, vous pouvez ignorer cet e-mail.
|
||||||
|
</p>
|
||||||
|
<p>Merci,
|
||||||
|
<br>L'équipe FitTrackee</p>
|
||||||
|
<table class="body-sub" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="f-fallback sub">Si vous avez des problèmes avec le bouton, vous pouvez copier et coller le lien suivant dans votre navigateur</p>
|
||||||
|
<p class="f-fallback sub">http://localhost/email-update?token=xxx</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="content-cell" align="center">
|
||||||
|
<p class="f-fallback sub align-center">© FitTrackee.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
@ -9,12 +9,23 @@ from .template_results.email_update_to_current_email import (
|
|||||||
expected_fr_html_body as expected_fr_current_email_html_body,
|
expected_fr_html_body as expected_fr_current_email_html_body,
|
||||||
expected_fr_text_body as expected_fr_current_email_text_body,
|
expected_fr_text_body as expected_fr_current_email_text_body,
|
||||||
)
|
)
|
||||||
from .template_results.email_update_to_new_email import (
|
|
||||||
|
# fmt: off
|
||||||
|
from .template_results.email_update_to_new_email import ( # isort:skip
|
||||||
expected_en_html_body as expected_en_new_email_html_body,
|
expected_en_html_body as expected_en_new_email_html_body,
|
||||||
|
expected_en_html_body_without_security as
|
||||||
|
expected_en_new_email_html_body_without_security,
|
||||||
expected_en_text_body as expected_en_new_email_text_body,
|
expected_en_text_body as expected_en_new_email_text_body,
|
||||||
|
expected_en_text_body_without_security as
|
||||||
|
expected_en_new_email_text_body_without_security,
|
||||||
expected_fr_html_body as expected_fr_new_email_html_body,
|
expected_fr_html_body as expected_fr_new_email_html_body,
|
||||||
|
expected_fr_html_body_without_security as
|
||||||
|
expected_fr_new_email_html_body_without_security,
|
||||||
expected_fr_text_body as expected_fr_new_email_text_body,
|
expected_fr_text_body as expected_fr_new_email_text_body,
|
||||||
|
expected_fr_text_body_without_security as
|
||||||
|
expected_fr_new_email_text_body_without_security,
|
||||||
)
|
)
|
||||||
|
# fmt: off
|
||||||
|
|
||||||
|
|
||||||
class TestEmailTemplateForEmailUpdateToCurrentEmail:
|
class TestEmailTemplateForEmailUpdateToCurrentEmail:
|
||||||
@ -143,3 +154,65 @@ class TestEmailTemplateForEmailUpdateToNewEmail:
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert expected_fr_new_email_html_body in text_body
|
assert expected_fr_new_email_html_body in text_body
|
||||||
|
|
||||||
|
|
||||||
|
class TestEmailTemplateForEmailUpdateToNewEmailWithoutSecurityInfos:
|
||||||
|
EMAIL_DATA = {
|
||||||
|
'username': 'test',
|
||||||
|
'email_confirmation_url': 'http://localhost/email-update?token=xxx',
|
||||||
|
'fittrackee_url': 'http://localhost',
|
||||||
|
}
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'lang, expected_subject',
|
||||||
|
[
|
||||||
|
('en', 'FitTrackee - Confirm email change'),
|
||||||
|
('fr', "FitTrackee - Confirmer le changement d'adresse email"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_it_gets_subject(
|
||||||
|
self, app: Flask, lang: str, expected_subject: str
|
||||||
|
) -> None:
|
||||||
|
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
|
||||||
|
|
||||||
|
subject = email_template.get_content(
|
||||||
|
'email_update_to_new_email', lang, 'subject.txt', {}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert subject == expected_subject
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'lang, expected_text_body',
|
||||||
|
[
|
||||||
|
('en', expected_en_new_email_text_body_without_security),
|
||||||
|
('fr', expected_fr_new_email_text_body_without_security),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_it_gets_text_body(
|
||||||
|
self, app: Flask, lang: str, expected_text_body: str
|
||||||
|
) -> None:
|
||||||
|
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
|
||||||
|
|
||||||
|
text_body = email_template.get_content(
|
||||||
|
'email_update_to_new_email', lang, 'body.txt', self.EMAIL_DATA
|
||||||
|
)
|
||||||
|
|
||||||
|
assert text_body == expected_text_body
|
||||||
|
|
||||||
|
def test_it_gets_en_html_body(self, app: Flask) -> None:
|
||||||
|
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
|
||||||
|
|
||||||
|
text_body = email_template.get_content(
|
||||||
|
'email_update_to_new_email', 'en', 'body.html', self.EMAIL_DATA
|
||||||
|
)
|
||||||
|
|
||||||
|
assert expected_en_new_email_html_body_without_security in text_body
|
||||||
|
|
||||||
|
def test_it_gets_fr_html_body(self, app: Flask) -> None:
|
||||||
|
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
|
||||||
|
|
||||||
|
text_body = email_template.get_content(
|
||||||
|
'email_update_to_new_email', 'fr', 'body.html', self.EMAIL_DATA
|
||||||
|
)
|
||||||
|
|
||||||
|
assert expected_fr_new_email_html_body_without_security in text_body
|
||||||
|
6
fittrackee/tests/fixtures/fixtures_emails.py
vendored
6
fittrackee/tests/fixtures/fixtures_emails.py
vendored
@ -34,3 +34,9 @@ def user_password_change_email_mock() -> Iterator[MagicMock]:
|
|||||||
def user_reset_password_email() -> Iterator[MagicMock]:
|
def user_reset_password_email() -> Iterator[MagicMock]:
|
||||||
with patch('fittrackee.users.users.reset_password_email') as mock:
|
with patch('fittrackee.users.users.reset_password_email') as mock:
|
||||||
yield mock
|
yield mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def user_email_updated_to_new_address_mock() -> Iterator[MagicMock]:
|
||||||
|
with patch('fittrackee.users.users.email_updated_to_new_address') as mock:
|
||||||
|
yield mock
|
||||||
|
@ -6,6 +6,7 @@ from unittest.mock import MagicMock, patch
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
from fittrackee.users.models import User, UserSportPreference
|
from fittrackee.users.models import User, UserSportPreference
|
||||||
|
from fittrackee.users.utils.random import random_string
|
||||||
from fittrackee.utils import get_readable_duration
|
from fittrackee.utils import get_readable_duration
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
@ -1053,6 +1054,99 @@ class TestUpdateUser(ApiTestCaseMixin):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_it_returns_error_when_updating_email_with_invalid_address(
|
||||||
|
self, app: Flask, user_1_admin: User, user_2: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1_admin.email
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.patch(
|
||||||
|
f'/api/users/{user_2.username}',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(new_email=random_string())),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_400(response, 'valid email must be provided')
|
||||||
|
|
||||||
|
def test_it_does_not_send_email_when_error_on_updating_email(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1_admin: User,
|
||||||
|
user_2: User,
|
||||||
|
user_email_updated_to_new_address_mock: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1_admin.email
|
||||||
|
)
|
||||||
|
|
||||||
|
client.patch(
|
||||||
|
f'/api/users/{user_2.username}',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(new_email=random_string())),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
user_email_updated_to_new_address_mock.send.assert_not_called()
|
||||||
|
|
||||||
|
def test_it_updates_user_email(
|
||||||
|
self, app: Flask, user_1_admin: User, user_2: User
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1_admin.email
|
||||||
|
)
|
||||||
|
user_2_email = user_2.email
|
||||||
|
user_2_confirmation_token = user_2.confirmation_token
|
||||||
|
|
||||||
|
response = client.patch(
|
||||||
|
f'/api/users/{user_2.username}',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(new_email='new.' + user_2.email)),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert user_2.email == user_2_email
|
||||||
|
assert user_2.email_to_confirm == 'new.' + user_2.email
|
||||||
|
assert user_2.confirmation_token != user_2_confirmation_token
|
||||||
|
|
||||||
|
def test_it_calls_email_updated_to_new_address_when_password_reset_is_successful( # noqa
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1_admin: User,
|
||||||
|
user_2: User,
|
||||||
|
user_email_updated_to_new_address_mock: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1_admin.email
|
||||||
|
)
|
||||||
|
new_email = 'new.' + user_2.email
|
||||||
|
expected_token = random_string()
|
||||||
|
|
||||||
|
with patch('secrets.token_urlsafe', return_value=expected_token):
|
||||||
|
response = client.patch(
|
||||||
|
f'/api/users/{user_2.username}',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(new_email=new_email)),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
user_email_updated_to_new_address_mock.send.assert_called_once_with(
|
||||||
|
{
|
||||||
|
'language': 'en',
|
||||||
|
'email': new_email,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'username': user_2.username,
|
||||||
|
'fittrackee_url': 'http://0.0.0.0:5000',
|
||||||
|
'email_confirmation_url': (
|
||||||
|
f'http://0.0.0.0:5000/email-update?token={expected_token}'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteUser(ApiTestCaseMixin):
|
class TestDeleteUser(ApiTestCaseMixin):
|
||||||
def test_user_can_delete_its_own_account(
|
def test_user_can_delete_its_own_account(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
from typing import Any, Dict, Tuple, Union
|
from typing import Any, Dict, Tuple, Union
|
||||||
|
|
||||||
@ -8,7 +9,11 @@ from flask import Blueprint, current_app, request, send_file
|
|||||||
from sqlalchemy import exc
|
from sqlalchemy import exc
|
||||||
|
|
||||||
from fittrackee import bcrypt, db
|
from fittrackee import bcrypt, db
|
||||||
from fittrackee.emails.tasks import password_change_email, reset_password_email
|
from fittrackee.emails.tasks import (
|
||||||
|
email_updated_to_new_address,
|
||||||
|
password_change_email,
|
||||||
|
reset_password_email,
|
||||||
|
)
|
||||||
from fittrackee.files import get_absolute_file_path
|
from fittrackee.files import get_absolute_file_path
|
||||||
from fittrackee.responses import (
|
from fittrackee.responses import (
|
||||||
ForbiddenErrorResponse,
|
ForbiddenErrorResponse,
|
||||||
@ -18,6 +23,7 @@ from fittrackee.responses import (
|
|||||||
UserNotFoundErrorResponse,
|
UserNotFoundErrorResponse,
|
||||||
handle_error_and_return_response,
|
handle_error_and_return_response,
|
||||||
)
|
)
|
||||||
|
from fittrackee.users.utils.controls import is_valid_email
|
||||||
from fittrackee.utils import get_readable_duration
|
from fittrackee.utils import get_readable_duration
|
||||||
from fittrackee.workouts.models import Record, Workout, WorkoutSegment
|
from fittrackee.workouts.models import Record, Workout, WorkoutSegment
|
||||||
|
|
||||||
@ -494,7 +500,8 @@ def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
|
|||||||
if not user_data:
|
if not user_data:
|
||||||
return InvalidPayloadErrorResponse()
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
send_emails = False
|
send_password_emails = False
|
||||||
|
send_new_address_email = False
|
||||||
try:
|
try:
|
||||||
user = User.query.filter_by(username=user_name).first()
|
user = User.query.filter_by(username=user_name).first()
|
||||||
if not user:
|
if not user:
|
||||||
@ -511,13 +518,23 @@ def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
|
|||||||
user.password = bcrypt.generate_password_hash(
|
user.password = bcrypt.generate_password_hash(
|
||||||
new_password, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
new_password, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
||||||
).decode()
|
).decode()
|
||||||
send_emails = True
|
send_password_emails = True
|
||||||
|
|
||||||
|
if 'new_email' in user_data:
|
||||||
|
if is_valid_email(user_data['new_email']):
|
||||||
|
user.email_to_confirm = user_data['new_email']
|
||||||
|
user.confirmation_token = secrets.token_urlsafe(16)
|
||||||
|
send_new_address_email = True
|
||||||
|
else:
|
||||||
|
return InvalidPayloadErrorResponse(
|
||||||
|
'valid email must be provided'
|
||||||
|
)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
if send_emails:
|
|
||||||
user_language = 'en' if user.language is None else user.language
|
user_language = 'en' if user.language is None else user.language
|
||||||
ui_url = current_app.config['UI_URL']
|
ui_url = current_app.config['UI_URL']
|
||||||
|
if send_password_emails:
|
||||||
user_data = {
|
user_data = {
|
||||||
'language': user_language,
|
'language': user_language,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
@ -547,6 +564,21 @@ def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if send_new_address_email:
|
||||||
|
user_data = {
|
||||||
|
'language': user_language,
|
||||||
|
'email': user.email_to_confirm,
|
||||||
|
}
|
||||||
|
email_data = {
|
||||||
|
'username': user.username,
|
||||||
|
'fittrackee_url': ui_url,
|
||||||
|
'email_confirmation_url': (
|
||||||
|
f'{ui_url}/email-update'
|
||||||
|
f'?token={user.confirmation_token}'
|
||||||
|
),
|
||||||
|
}
|
||||||
|
email_updated_to_new_address.send(user_data, email_data)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': {'users': [user.serialize()]},
|
'data': {'users': [user.serialize()]},
|
||||||
|
Loading…
Reference in New Issue
Block a user