added & configure auth login, environments & error.service

This commit is contained in:
Chneemann 2024-08-04 15:55:49 +02:00
parent 53c2caa45e
commit b8a6c95910
20 changed files with 194 additions and 38 deletions

View file

View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class AuthConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'auth'

View file

@ -0,0 +1,13 @@
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class EmailBackend(ModelBackend):
def authenticate(self, request, email=None, password=None, **kwargs):
try:
user = UserModel.objects.get(email=email)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
return None

View file

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View file

@ -0,0 +1,17 @@
from rest_framework import serializers
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
password = serializers.CharField(write_only=True, required=True)
def validate(self, data):
email = data.get('email')
password = data.get('password')
if not email:
raise serializers.ValidationError("Email is required.")
if not password:
raise serializers.ValidationError("Password is required.")
return data

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

@ -0,0 +1,27 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate
from .serializer import LoginSerializer
class LoginView(APIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
email = serializer.validated_data['email']
password = serializer.validated_data['password']
user = authenticate(request, email=email, password=password)
if user:
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)

View file

@ -4,7 +4,7 @@ from .forms import CustomUserCreationForm
from django.contrib.auth.admin import UserAdmin
@admin.register(CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
fieldsets = (
@ -20,3 +20,4 @@ class CustomUserAdmin(admin.ModelAdmin):
}
)
)

View file

@ -1,7 +1,7 @@
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
custom = models.CharField(max_length=1000, default='')
phone = models.CharField(max_length=20, default='')
address = models.CharField(max_length=150, default='')
custom = models.CharField(max_length=1000, blank=True)
phone = models.CharField(max_length=20, blank=True)
address = models.CharField(max_length=150, blank=True)

View file

@ -1,12 +1,14 @@
from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .serializer import UserSerializer
from .models import CustomUser
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def user_list(request):
if request.method == 'GET':
@ -19,8 +21,10 @@ def user_list(request):
if serializer.is_valid():
serializer.save
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes([IsAuthenticated])
def user_detail(request, id):
try:
@ -35,7 +39,7 @@ def user_detail(request, id):
elif request.method == 'PUT':
serializer = UserSerializer(user, data=request.data)
if serializer.is_valid():
serializer().save()
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

View file

@ -32,7 +32,6 @@ CORS_ALLOWED_ORIGINS = [
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
@ -40,14 +39,12 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework.authtoken',
'rest_framework',
'corsheaders',
'users',
]
AUTH_USER_MODEL = 'users.CustomUser'
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@ -57,7 +54,6 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware'
]
ROOT_URLCONF = 'videoflix.urls'
@ -80,7 +76,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'videoflix.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
@ -132,3 +127,20 @@ STATIC_URL = 'static/'
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Auth
AUTH_EMAIL_VERIFICATION = True
AUTH_USER_MODEL = 'users.CustomUser'
# Rest Framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
AUTHENTICATION_BACKENDS = (
'auth.custom_backend.EmailBackend',
'django.contrib.auth.backends.ModelBackend',
)

View file

@ -15,11 +15,14 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from users import views
from auth.views import LoginView
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.user_list),
path('users/<int:id>/', views.user_detail),
path('auth/login/', LoginView.as_view()),
]

View file

@ -28,7 +28,9 @@
} @else { @if (mail.touched && authData.mail.length > 0 &&
!isUserEmailValid(authData.mail.toLowerCase())) {
<p>This is not a valid email format</p>
}}
}} @if ((errorService.error$ | async)) {
<p>{{ errorService.error$ | async }}</p>
}
</div>
<input
type="password"

View file

@ -1,12 +1,16 @@
import { Component } from '@angular/core';
import { BtnLargeComponent } from '../../../shared/components/btn-large/btn-large.component';
import { FormsModule, NgForm } from '@angular/forms';
import { RouterLink } from '@angular/router';
import { Router, RouterLink } from '@angular/router';
import { AuthService } from '../../../services/auth.service';
import { ErrorService } from '../../../services/error.service';
import { HttpErrorResponse } from '@angular/common/http';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-login',
standalone: true,
imports: [BtnLargeComponent, FormsModule, RouterLink],
imports: [BtnLargeComponent, CommonModule, FormsModule, RouterLink],
templateUrl: './login.component.html',
styleUrl: './login.component.scss',
})
@ -18,17 +22,35 @@ export class LoginComponent {
send: false,
};
constructor() {}
constructor(
private authService: AuthService,
public errorService: ErrorService,
private router: Router
) {}
isUserEmailValid(emailValue: string) {
const emailRegex = /^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(emailValue);
}
onSubmit(ngForm: NgForm) {
async onSubmit(ngForm: NgForm) {
if (ngForm.submitted && ngForm.form.valid) {
console.log(this.authData);
const body = {
email: this.authData.mail,
password: this.authData.password,
};
try {
await this.authService.login(body);
ngForm.resetForm();
this.router.navigate(['/browse/']);
this.errorService.clearError();
} catch (error) {
if (error instanceof HttpErrorResponse) {
this.errorService.setError(error.error.detail);
} else {
this.errorService.setError('An unknown error has occurred.');
}
}
}
}
}

View file

@ -0,0 +1,3 @@
export const environment = {
baseUrl: 'http://127.0.0.1:8000/',
};

View file

@ -0,0 +1,3 @@
export const environment = {
baseUrl: '',
};

View file

@ -1,12 +1,28 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import {
HttpClient,
HttpErrorResponse,
HttpHeaders,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { lastValueFrom, Observable } from 'rxjs';
import { environment } from '../environments/environment.development';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(private http: HttpClient) {}
errorMsg: string | null = null;
constructor(private http: HttpClient, private router: Router) {}
async login(body: any): Promise<void> {
const data = await lastValueFrom(
this.http.post<any>(`${environment.baseUrl}/auth/login/`, body)
);
const authToken = data.toString();
localStorage.setItem('authToken', authToken);
}
getAllUsers(): Observable<any> {
const headers = this.getAuthHeaders();

View file

@ -0,0 +1,18 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class ErrorService {
private errorSubject = new BehaviorSubject<string | null>(null);
error$ = this.errorSubject.asObservable();
setError(message: string | null) {
this.errorSubject.next(message);
}
clearError() {
this.errorSubject.next(null);
}
}