Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ DEBUG=
DJANGO_SECRET_KEY=

EMAIL_USER=
EMAIL_BACKEND=anymail.backends.unisender_go.EmailBackend
VERIFY_EMAIL_REDIRECT_URL=https://app.procollab.ru/auth/verification/
EMAIL_PASSWORD=
EMAIL_HOST=
EMAIL_PORT=
Expand Down
12 changes: 11 additions & 1 deletion procollab/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,17 @@
SESSION_COOKIE_SECURE = not DEBUG
CSRF_COOKIE_SECURE = not DEBUG

EMAIL_BACKEND = "anymail.backends.unisender_go.EmailBackend"
EMAIL_BACKEND = config(
"EMAIL_BACKEND",
default="anymail.backends.unisender_go.EmailBackend",
cast=str,
)

VERIFY_EMAIL_REDIRECT_URL = config(
"VERIFY_EMAIL_REDIRECT_URL",
default="https://app.procollab.ru/auth/verification/",
cast=str,
)

UNISENDER_GO_API_KEY = config("UNISENDER_GO_API_KEY", default="", cast=str)
ANYMAIL = {
Expand Down
2 changes: 1 addition & 1 deletion users/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class OnboardingStage(Enum):
(INVESTOR, "Инвестор"),
)

VERIFY_EMAIL_REDIRECT_URL = "https://app.procollab.ru/auth/verification/"
VERIFY_EMAIL_REDIRECT_URL = settings.VERIFY_EMAIL_REDIRECT_URL


PROTOCOL = "https"
Expand Down
68 changes: 67 additions & 1 deletion users/tests/test_auth_api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import runpy
from pathlib import Path
from unittest.mock import patch
from urllib.parse import urlparse

from django.test import TestCase
from django.conf import settings
from django.test import SimpleTestCase, TestCase, override_settings
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework_simplejwt.tokens import RefreshToken

from tests.constants import USER_CREATE_DATA
from users.models import CustomUser
Expand Down Expand Up @@ -48,6 +53,21 @@ def test_user_registration_rejects_invalid_payload(self):

self.assertEqual(response.status_code, 400)

@override_settings(EMAIL_BACKEND="django.core.mail.backends.console.EmailBackend")
@patch(
"django.core.mail.backends.console.EmailBackend.write_message",
return_value=1,
)
def test_user_registration_works_with_console_email_backend(self, write_message_mock):
response = self.client.post("/auth/users/", USER_CREATE_DATA, format="json")

self.assertEqual(response.status_code, 201)
self.assertEqual(response.data["email"], USER_CREATE_DATA["email"])
self.assertEqual(response.data["is_active"], False)
user = CustomUser.objects.get(email=USER_CREATE_DATA["email"])
self.assertFalse(user.is_active)
write_message_mock.assert_called_once()

def test_token_obtain_pair_updates_last_login(self):
user = build_user(email="login@example.com")

Expand Down Expand Up @@ -83,3 +103,49 @@ def test_removed_legacy_routes_return_404(self):
self.assertEqual(self.client.get("/auth/users/clone-data").status_code, 404)
self.assertEqual(self.client.get("/auth/subscription/").status_code, 404)
self.assertEqual(self.client.post("/auth/subscription/buy/").status_code, 404)


class EmailSettingsDefaultsTests(SimpleTestCase):
def test_email_settings_keep_existing_defaults_without_env(self):
settings_path = Path(__file__).resolve().parents[2] / "procollab/settings.py"

def return_default(_name, default=None, cast=None):
return cast(default) if cast else default

with patch("decouple.config", side_effect=return_default):
loaded_settings = runpy.run_path(settings_path)

self.assertEqual(
loaded_settings["EMAIL_BACKEND"],
"anymail.backends.unisender_go.EmailBackend",
)
self.assertEqual(
loaded_settings["VERIFY_EMAIL_REDIRECT_URL"],
"https://app.procollab.ru/auth/verification/",
)


class VerifyEmailRedirectTests(TestCase):
def setUp(self):
self.client = APIClient()

@override_settings(
VERIFY_EMAIL_REDIRECT_URL=("https://react-dev.procollab.ru/auth/verification")
)
def test_confirmation_handler_uses_configured_redirect(self):
user = build_user(email="confirm@example.com", is_active=False)
token = str(RefreshToken.for_user(user).access_token)

response = self.client.get(
"/auth/account-confirm-email/",
{"token": token},
)

self.assertEqual(response.status_code, 302)
redirect = urlparse(response["Location"])
self.assertEqual(
redirect._replace(query="", fragment="").geturl(),
settings.VERIFY_EMAIL_REDIRECT_URL,
)
self.assertTrue(redirect.query.startswith("access_token="))
self.assertIn("&refresh_token=", redirect.query)
13 changes: 5 additions & 8 deletions users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@
)
from projects.pagination import ProjectsPagination
from projects.serializers import ProjectListSerializer
from users.constants import (
VERBOSE_ROLE_TYPES,
VERBOSE_USER_TYPES,
VERIFY_EMAIL_REDIRECT_URL,
)
from users.constants import VERBOSE_ROLE_TYPES, VERBOSE_USER_TYPES
from users.helpers import check_related_fields_update, force_verify_user, verify_email
from users.models import LikesOnProject, UserAchievement, UserSkillConfirmation
from users.permissions import IsAchievementOwnerOrReadOnly
Expand Down Expand Up @@ -276,6 +272,7 @@ class VerifyEmail(GenericAPIView):

def get(self, request):
token = request.GET.get("token")
redirect_url = settings.VERIFY_EMAIL_REDIRECT_URL

try:
payload = jwt.decode(jwt=token, key=settings.SECRET_KEY, algorithms=["HS256"])
Expand All @@ -288,20 +285,20 @@ def get(self, request):
user.save()

return redirect(
f"{VERIFY_EMAIL_REDIRECT_URL}?access_token={access_token}&refresh_token={refresh_token}",
f"{redirect_url}?access_token={access_token}&refresh_token={refresh_token}",
status=status.HTTP_200_OK,
message="Succeed",
)

except jwt.ExpiredSignatureError:
return redirect(
VERIFY_EMAIL_REDIRECT_URL,
redirect_url,
status=status.HTTP_400_BAD_REQUEST,
message="Activate Expired",
)
except jwt.DecodeError:
return redirect(
VERIFY_EMAIL_REDIRECT_URL,
redirect_url,
status=status.HTTP_400_BAD_REQUEST,
message="Decode error",
)
Expand Down
Loading