diff --git a/django_project_base/account/rest/profile.py b/django_project_base/account/rest/profile.py
index e318cead..c0912807 100644
--- a/django_project_base/account/rest/profile.py
+++ b/django_project_base/account/rest/profile.py
@@ -1,5 +1,6 @@
import datetime
import uuid
+from random import randrange
import django
import swapper
@@ -21,6 +22,7 @@
from dynamicforms.template_render.layout import Column, Layout, Row
from dynamicforms.template_render.responsive_table_layout import ResponsiveTableLayout, ResponsiveTableLayouts
from dynamicforms.viewsets import ModelViewSet
+from natural.date import compress
from rest_framework import exceptions, filters, status
from rest_framework.decorators import action
from rest_framework.exceptions import APIException, ValidationError
@@ -36,7 +38,10 @@
from django_project_base.account.rest.project_profiles_utils import get_project_members
from django_project_base.base.event import UserRegisteredEvent
from django_project_base.constants import NOTIFY_NEW_USER_SETTING_NAME
-from django_project_base.notifications.email_notification import SystemEMailNotification
+from django_project_base.notifications.email_notification import (
+ EMailNotificationWithListOfEmails,
+ SystemEMailNotification,
+)
from django_project_base.notifications.models import DjangoProjectBaseMessage
from django_project_base.permissions import BasePermissions
from django_project_base.rest.project import ProjectSerializer, ProjectViewSet
@@ -429,10 +434,56 @@ def get_current_profile(self, request: Request, **kwargs) -> Response:
@get_current_profile.mapping.post
def update_current_profile(self, request: Request, **kwargs) -> Response:
user: Model = request.user
+ new_email = request.data.pop("email", None)
serializer = self.get_serializer(user, data=request.data, many=False)
serializer.is_valid(raise_exception=True)
serializer.save()
- return Response(serializer.data)
+ email_changed = new_email and user.email != new_email
+ response = Response(serializer.data)
+ if email_changed:
+ code = randrange(100001, 999999)
+ response.set_cookie("verify-email", user.pk, samesite="Lax")
+ request.session[f"email-changed-{code}-{user.pk}"] = new_email
+ # TODO: Use system email
+ # TODO: SEND THIS AS SYSTEM MSG WHEN PR IS MERGED
+ # TODO: https://taiga.velis.si/project/velis-django-project-admin/issue/728
+ EMailNotificationWithListOfEmails(
+ message=DjangoProjectBaseMessage(
+ subject=f"{_('Email change for account on')} {request.META['HTTP_HOST']}",
+ body=f"{_('You requested an email change for your account at')} {request.META['HTTP_HOST']}. "
+ f"\n\n{_('Your verification code is')}: "
+ f"{code} \n\n {_('Code is valid for')} {compress(settings.CONFIRMATION_CODE_TIMEOUT)}.\n",
+ footer="",
+ content_type=DjangoProjectBaseMessage.PLAIN_TEXT,
+ ),
+ recipients=[new_email],
+ project=self.request.selected_project.slug,
+ user=user.pk,
+ ).send()
+ return response
+
+ @extend_schema(exclude=True)
+ @action(
+ methods=["POST"],
+ detail=False,
+ url_path="confirm-new-email",
+ url_name="confirm-new-email",
+ )
+ @transaction.atomic()
+ def confirm_new_email(self, request: Request, **kwargs) -> Response:
+ user = request.user
+ if not request.data.get("code"):
+ raise ValidationError(dict(code=[_("Code required")]))
+ key = f"email-changed-{request.data['code']}-{user.pk}"
+ new_email = request.session.get(key)
+ if email := new_email:
+ user.email = email
+ user.save(update_fields=["email"])
+ request.session.pop(key, None)
+ response = Response()
+ response.delete_cookie("verify-email")
+ return response
+ raise ValidationError(dict(code=[_("Invalid code")]))
@extend_schema(
description="Marks profile of calling user for deletion in future. Future date is determined " "by settings",
diff --git a/vue/components/profile-search.vue b/vue/components/profile-search.vue
index d7ff627f..675356af 100644
--- a/vue/components/profile-search.vue
+++ b/vue/components/profile-search.vue
@@ -91,9 +91,12 @@ function customLabel(profile: UserDataJSON) {
@select="onSelect"
>
- {{ props.option.email }}
- {{ props.option.first_name }}
- {{ props.option.last_name }}
+ {{ //@ts-ignore
+ props.option.email }}
+ {{ //@ts-ignore
+ props.option.first_name }}
+ {{ //@ts-ignore
+ props.option.last_name }}
diff --git a/vue/components/user-session/user-profile.vue b/vue/components/user-session/user-profile.vue
index e64b8f50..74ae5363 100644
--- a/vue/components/user-session/user-profile.vue
+++ b/vue/components/user-session/user-profile.vue
@@ -1,8 +1,9 @@