@@ -0,0 +1,6 @@
+from django.utils.translation import gettext as _
+
+
+class AccessDenied(Exception):
+ def __str__(self):
+ return _('You do not have sufficient rights to perform this action')
@@ -0,0 +1,11 @@
+from authentication.exceptions.email_exceptions.letter_not_found import (
+ LetterNotFound
+)
+from authentication.exceptions.email_exceptions.letter_unknown import (
+ LetterUnknownException
+)
+
+__all__ = (
+ 'LetterNotFound',
+ 'LetterUnknownException'
+)
\ No newline at end of file
@@ -0,0 +1,6 @@
+from django.utils.translation import gettext as _
+
+
+class LetterNotFound(Exception):
+ def __str__(self):
+ return _('Letter template not found')
@@ -0,0 +1,6 @@
+from django.utils.translation import gettext as _
+
+
+class LetterUnknownException(Exception):
+ def __str__(self):
+ return _('There was an unknown error while sending an email')
@@ -10,6 +10,7 @@ from authentication.exceptions.business_host_exceptions import (
AlreadyAccount,
AlreadyHasPlan,
)
+from authentication.exceptions.business_host_exceptions.access_denied import AccessDenied
from authentication.exceptions.business_host_exceptions.already_host import (
AlreadyHost,
)
@@ -246,3 +247,14 @@ class BusinessHostService:
self.user.host_account.save()
return BusinessHostSelector(self.user).get_allowed_models()
+
+ def reinvite_business_account(self, business_account: BusinessAccount) -> None:
+ if (
+ self.user.account_type == business_account.user.account_type
+ and self.user.account_type == 'business_admin'
+ ):
+ raise AccessDenied
+ password = generate_token(15)
+ business_account.user.set_password(password)
+ business_account.user.save()
+ EmailService(self.user).send_reinvited_email(business_account, password)
@@ -4,9 +4,12 @@ import dns.resolver
from django.conf import settings
from django.core.mail import EmailMessage, send_mail
+from django.template import TemplateDoesNotExist
+from django.template.loader import get_template
from django.utils.html import format_html, strip_tags
from django.utils.translation import gettext_lazy as _
+from authentication.exceptions.email_exceptions import LetterNotFound, LetterUnknownException
from authentication.exceptions.user import DomainNotFound
from authentication.models import BusinessAccount, BusinessUserHost
from authentication.models.user import CustomUserModel
@@ -139,6 +142,20 @@ class EmailService:
)
mail.send(fail_silently=True)
+ def send_reinvited_email(self, account: BusinessAccount, password: str | None = None) -> None:
+ try:
+ template = get_template('authentication/reinvited_employee_letter.html')
+ html_message = template.render(context={'email': account.user.email, 'password': password})
+ except TemplateDoesNotExist:
+ raise LetterNotFound
+ except Exception as exc:
+ raise LetterUnknownException from exc
+ self.send_email(
+ subject='Ваш аккаунт на платформе AIR',
+ message=html_message,
+ user_email=account.user.email
+ )
+
def send_corporate_invitation_email(self, account: BusinessAccount):
if self.user.host_account is None:
raise Exception(_('Regular users cannot send invitation letters'))
@@ -0,0 +1,13 @@
+
+
+
+
+ Ваш аккаунт на платформе AIR:
+
+
+ Новые данные для входа на платформу AIR:
+ E-mail: {{ email }}
+ Пароль: {{ password }}
+ Всегда с вами, команда AIR
+
+
@@ -74,6 +74,11 @@ urlpatterns = [
views.BusinessHostAPIView.as_view(),
name='business-host',
),
+ path(
+ 'business-host/re-invite/',
+ views.ReinviteBusinessAccountAPIView.as_view(),
+ name='business-host-re-invite',
+ ),
path(
'business-host/create',
views.StartHostRegistrationAPIView.as_view(),
@@ -3,6 +3,7 @@ from datetime import date, datetime, timedelta
from decimal import Decimal
from itertools import chain
from logging import getLogger
+from typing import Any, Tuple, Dict
from uuid import UUID
from django.conf import settings
@@ -22,9 +23,11 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from authentication.exceptions import BaseAlready
+from authentication.exceptions.business_host_exceptions.access_denied import AccessDenied
from authentication.exceptions.business_host_exceptions.not_allowed_ip import (
NotAllowedIP,
)
+from authentication.exceptions.email_exceptions import LetterNotFound, LetterUnknownException
from authentication.exceptions.email_token import EmailTokenNotFound
from authentication.exceptions.user import (
DomainNotFound,
@@ -38,12 +41,12 @@ from authentication.models.business_host import BusinessUserHost
from authentication.models.choices import AccountPrivileges, InvitationStatus
from authentication.models.whitelist import CompanyIPWhitelist
from authentication.permissions import (
- ChangeEmployeePassPermission,
HasBusinessAdminPermissions,
IsAnonymous,
IsBusinessSecurity,
IsTelegramAirBot,
IsVKMiniApp,
+ ChangeEmployeePassPermission,
)
from authentication.selectors.business_account_selector import BusinessAccountSelector
from authentication.selectors.business_host_selector import (
@@ -62,7 +65,6 @@ from authentication.serializers import (
BusinessGroupUpdateSerializer,
BusinessHostSerializer,
BusinessHostUpdateSerializer,
- ChangePasswordSerializer,
CompanyIPWhitelistSerializer,
DeleteBusinessAccountSerializer,
DeleteModelsSerializer,
@@ -81,6 +83,7 @@ from authentication.serializers import (
UpdateProfilePictureSerializer,
UpdateUserDataSerializer,
UserDataSerializer,
+ ChangePasswordSerializer,
)
from authentication.services.business_account_service import (
BusinessAccountService,
@@ -323,6 +326,37 @@ class BusinessHostAPIView(APIView):
)
+class ReinviteBusinessAccountAPIView(APIView):
+ permission_classes = (HasBusinessAdminPermissions,)
+
+ @extend_schema(
+ parameters=[
+ OpenApiParameter('email', str, 'path', required=True),
+ ],
+ )
+ def post(self, request: Request, email: str, *args: Tuple[Any], **kwargs: Dict[Any, Any]) -> Response:
+ """Reinvite business account including generation of a new password"""
+ try:
+ business_account = BusinessAccountSelector.filter_by_email(
+ email,
+ BusinessAccountService.get_company_name(request.user)
+ )
+ BusinessHostService(request.user).reinvite_business_account(business_account=business_account)
+ return Response({'detail': _('Business account has been reinvited')}, status=status.HTTP_200_OK)
+ except LetterNotFound as exc:
+ return Response({'detail': f'{exc}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ except LetterUnknownException as exc:
+ logger.exception(exc)
+ return Response({'detail': f'{exc}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ except AccessDenied as exc:
+ return Response({'detail': f'{exc}'}, status=status.HTTP_403_FORBIDDEN)
+ except Exception as exc:
+ logger.exception(exc)
+ return Response(
+ {'detail': _('Server error occured')}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
+ )
+
+
class HostWorkersAPIView(APIView):
permission_classes = (HasBusinessAdminPermissions,)
@@ -372,8 +406,8 @@ class ChangeHostPassAPIView(APIView):
)
BusinessAccountService(business_account).update_user_password(request)
return Response({'detail': 'Host password has been updated'}, status=status.HTTP_200_OK)
- except Exception as err:
- return Response({'detail': f'{err}'}, status=status.HTTP_400_BAD_REQUEST)
+ except Exception as exc:
+ return Response({'detail': f'{exc}'}, status=status.HTTP_400_BAD_REQUEST)
class HostModelStatisticsAPIView(APIView):
@@ -1118,3 +1118,15 @@ msgid "Model is blocked by outdating or temporary block, please retry later"
msgstr ""
"Модель заблокирована, т.к перестала обновляться или временно, попробуйте "
"позже"
+
+msgid "Business account has been reinvited"
+msgstr "Повторное приглашение сотруднику успешно отправлено"
+
+msgid "You do not have sufficient rights to perform this action"
+msgstr "У вас недостаточно прав для выполнения этого действия"
+
+msgid "Letter template not found"
+msgstr "Шаблон письма не найден"
+
+msgid "There was an unknown error while sending an email"
+msgstr "При отправке письма произошла неизвестная ошибка"
\ No newline at end of file