diff --git a/backend/videoflix/auth/views.py b/backend/videoflix/auth/views.py index ac96a84..5700884 100644 --- a/backend/videoflix/auth/views.py +++ b/backend/videoflix/auth/views.py @@ -4,6 +4,11 @@ from rest_framework import status from rest_framework.authtoken.models import Token from django.contrib.auth import authenticate from .serializer import LoginSerializer +from users.serializer import UserSerializer +from django.utils.html import strip_tags +from django.core.mail import EmailMultiAlternatives +from django.template.loader import render_to_string +from users.models import CustomUser class LoginView(APIView): serializer_class = LoginSerializer @@ -17,11 +22,46 @@ class LoginView(APIView): user = authenticate(request, email=email, password=password) if user: + if not user.is_active: + return Response({'password': 'Account is inactive, please check your mails'}, status=status.HTTP_403_FORBIDDEN) return self._create_token_response(user) return Response({'detail': 'Unable to login with provided credentials.'}, status=status.HTTP_401_UNAUTHORIZED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def _create_token_response(self, user): - token, created = Token.objects.get_or_create(user=user) - return Response({token.key}, status=status.HTTP_200_OK) \ No newline at end of file + token = Token.objects.get_or_create(user=user) + return Response({'token': token.key}, status=status.HTTP_200_OK) + +class RegisterView(APIView): + def post(self, request): + email = request.data.get('email') + password = request.data.get('password') + if CustomUser.objects.filter(email=email).exists(): + return Response({'detail': 'A user with this email already exists.'}, status=status.HTTP_400_BAD_REQUEST) + + serialized = UserSerializer(data=request.data) + if serialized.is_valid(): + user = serialized.save() + user.is_active = False + user.set_password(password) + user.save() + self.send_email(user) + return Response(serialized.data, status=status.HTTP_201_CREATED) + else: + return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST) + + def send_email(self, user): + merge_data = { + 'name': user.username + } + html_body = render_to_string("mail.html", merge_data) + + message = EmailMultiAlternatives( + subject='Confirm your email', + body=strip_tags(html_body), # Plain text fallback + from_email='noreply@videoflix.com', + to=['andre.kempf.dev@gmail.com'] + ) + message.attach_alternative(html_body, "text/html") + message.send(fail_silently=False) \ No newline at end of file diff --git a/backend/videoflix/templates/mail.html b/backend/videoflix/templates/mail.html new file mode 100644 index 0000000..ea3ff02 --- /dev/null +++ b/backend/videoflix/templates/mail.html @@ -0,0 +1,50 @@ + + + + +
+

Dear {{ name }},

+

+ Thank you for registering with Videoflix. To complete your registration + and verify your email address, please click the link below: +

+ Activate account +

+ If you did not create an account with us, please disregard this email. +

+

Best regards,

+

Your Videoflix Team.

+ + diff --git a/backend/videoflix/videoflix/settings.py b/backend/videoflix/videoflix/settings.py index daeb408..8030a52 100644 --- a/backend/videoflix/videoflix/settings.py +++ b/backend/videoflix/videoflix/settings.py @@ -10,6 +10,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.0/ref/settings/ """ +import os from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -25,6 +26,14 @@ SECRET_KEY = 'django-insecure-*o%q)*3l+9^fs!m0z_h=z9bc)su=%)fv$@ktb#pza-pvi^z*en # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True +# EMAIL +EMAIL_USE_TLS = True +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = 'andre.kempf.dev@gmail.com' +EMAIL_HOST_PASSWORD = 'oyxwawshudwytgud' +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + ALLOWED_HOSTS = [] CORS_ALLOWED_ORIGINS = [ @@ -61,7 +70,7 @@ ROOT_URLCONF = 'videoflix.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/backend/videoflix/videoflix/urls.py b/backend/videoflix/videoflix/urls.py index 29f95c4..6b18d44 100644 --- a/backend/videoflix/videoflix/urls.py +++ b/backend/videoflix/videoflix/urls.py @@ -17,12 +17,12 @@ Including another URLconf from django.contrib import admin from django.urls import path, include from users import views -from auth.views import LoginView +from auth.views import LoginView, RegisterView urlpatterns = [ path('admin/', admin.site.urls), path('users/', views.user_list), path('users//', views.user_detail), path('auth/login/', LoginView.as_view()), - + path('auth/register/', RegisterView.as_view()), ] diff --git a/frontend/src/app/components/auth/login/login.component.html b/frontend/src/app/components/auth/login/login.component.html index 780f938..955ffd4 100644 --- a/frontend/src/app/components/auth/login/login.component.html +++ b/frontend/src/app/components/auth/login/login.component.html @@ -5,6 +5,7 @@ #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)" onsubmit="return false" + (input)="this.errorService.clearError()" > 0 && !isUserEmailValid(authData.mail.toLowerCase())) {

This is not a valid email format

- }} @if ((errorService.error$ | async)) { -

{{ errorService.error$ | async }}

- } + }} + +
+
+

{{ errors["mail"] }}

+
+
Password is too short, min 6 characters

} } + +
+
+

{{ errors["password"] }}

+
+