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
8 changes: 7 additions & 1 deletion Fools_Arena/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@
"""

from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from django.http import HttpResponse
from django.shortcuts import redirect
from django.urls import path, include

urlpatterns = [
path("admin/", admin.site.urls),
# UI
path('accounts/', include('accounts.urls')),

# API
path('api/accounts/', include('accounts.api_urls')),

]

# Add static files
Expand Down
26 changes: 26 additions & 0 deletions accounts/api_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Comment thread
Viton8 marked this conversation as resolved.
Authentication API routes for the Accounts app.

This module defines the endpoints for user registration, login,
profile retrieval, and logout. These routes are included in the
project’s main urls.py under the prefix "api/accounts/", which means
the final URLs are:

/api/accounts/auth/register/ → Register a new user
/api/accounts/auth/login/ → Log in an existing user
/api/accounts/auth/profile/ → Retrieve the authenticated user's profile
/api/accounts/auth/logout/ → Log out the current user

Each path is mapped to a class-based API view defined in accounts/api_views.py.
"""

from django.urls import path
from .api_views import RegistrationAPI, LoginAPI, ProfileAPI, LogoutAPI


urlpatterns = [
path('auth/register/', RegistrationAPI.as_view(), name='api_register'),
path('auth/login/', LoginAPI.as_view(), name='api_login'),
path('auth/profile/', ProfileAPI.as_view(), name='api_profile'),
path('auth/logout/', LogoutAPI.as_view(), name='api_logout'),
]
96 changes: 96 additions & 0 deletions accounts/api_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
API views for the Accounts app.

This module defines class-based views for handling user authentication
via RESTful endpoints. It includes registration, login, profile retrieval,
and logout functionality. These views are connected to the routes defined
in accounts/api_urls.py and use serializers from accounts/serializers.py.

Available API views:
- RegistrationAPI: create a new user and log them in automatically.
- LoginAPI: authenticate user credentials and start a session.
- ProfileAPI: return profile data for the authenticated user.
- LogoutAPI: end the current user session.
"""

from django.contrib.auth import login as auth_login, logout as auth_logout
Comment thread
Viton8 marked this conversation as resolved.
from rest_framework import generics, permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import RegistrationSerializer, LoginSerializer, ProfileSerializer

class RegistrationAPI(generics.CreateAPIView):
"""
API endpoint for user registration.

Handles the creation of a new user account using validated input.
Automatically logs in the newly created user to establish a session.
"""
serializer_class = RegistrationSerializer
permission_classes = [permissions.AllowAny]

def perform_create(self, serializer):
Comment thread
Viton8 marked this conversation as resolved.
"""
Save the new user instance and log them in.

Overrides the default CreateAPIView behavior to attach the user
to the current session immediately after registration.
"""
user = serializer.save()
auth_login(self.request, user)

class LoginAPI(APIView):
"""
API endpoint for user login.

Accepts username and password, authenticates the user,
and returns their profile data upon successful login.
"""
permission_classes = [permissions.AllowAny]

def post(self, request):
"""
Authenticate user credentials and start a session.

If credentials are valid, the user is logged in and their
profile data is returned in the response.
"""
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
auth_login(request, user)
return Response(ProfileSerializer(user).data)

class ProfileAPI(generics.RetrieveAPIView):
"""
API endpoint for retrieving the authenticated user's profile.

Requires the user to be logged in. Returns basic profile information.
"""
serializer_class = ProfileSerializer
permission_classes = [permissions.IsAuthenticated]

def get_object(self):
"""
Return the current authenticated user.

Used by RetrieveAPIView to serialize and return profile data.
"""
return self.request.user

class LogoutAPI(APIView):
"""
API endpoint for logging out the current user.

Requires authentication. Ends the session and returns a confirmation message.
"""
permission_classes = [permissions.IsAuthenticated]

def post(self, request):
"""
End the current user session.

Logs out the user and returns a success response.
"""
auth_logout(request)
return Response({'detail': 'You are out of the system'}, status=status.HTTP_200_OK)
41 changes: 41 additions & 0 deletions accounts/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Forms for the Accounts app.

This module defines form classes used for user registration and login.
They extend Django's built-in authentication forms to include additional
fields or custom behavior where necessary.

Available forms:
- RegistrationForm: extends UserCreationForm to include an email field.
- LoginForm: extends AuthenticationForm for user login.
"""

from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model

User = get_user_model()

class RegistrationForm(UserCreationForm):
"""
Form for user registration.

Extends Django's built-in UserCreationForm by adding
a required email field. Handles validation and creation
of a new user instance with username, email, and password.
"""
email = forms.EmailField(required=True)

class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')

class LoginForm(AuthenticationForm):
"""
Form for user login.

Extends Django's built-in AuthenticationForm without
additional fields. Used to authenticate existing users
with their username and password.
"""
pass
76 changes: 76 additions & 0 deletions accounts/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Serializers for the Accounts app.

This module defines serializers used for user authentication and profile
management. They handle validation and transformation of input/output data
between Django models and API views.

Available serializers:
- RegistrationSerializer: validates and creates new user accounts.
- LoginSerializer: authenticates existing users with username/password.
- ProfileSerializer: returns basic profile information for authenticated users.
"""

from django.contrib.auth import authenticate, get_user_model
from rest_framework import serializers

User = get_user_model()

class RegistrationSerializer(serializers.ModelSerializer):
"""
Serializer for user registration.

Validates the provided username, email, and password.
Creates a new user instance with an encrypted password.
"""
password = serializers.CharField(write_only=True, min_length=8)

class Meta:
model = User
fields = ('username', 'email', 'password')

def create(self, validated_data):
"""
Create a new user with the given validated data.

Uses Django's built-in create_user method to ensure
the password is properly hashed before saving.
"""
return User.objects.create_user(
username=validated_data['username'],
email=validated_data.get('email', ''),
password=validated_data['password'],
)

class LoginSerializer(serializers.Serializer):
"""
Serializer for user login.

Accepts username and password, and authenticates the user
using Django's built-in authentication system.
"""
username = serializers.CharField()
password = serializers.CharField(write_only=True)

def validate(self, attrs):
"""
Validate the provided credentials.

If authentication fails, raise a ValidationError.
On success, attach the authenticated user to attrs.
"""
user = authenticate(username=attrs['username'], password=attrs['password'])
if not user:
raise serializers.ValidationError('Incorrect login details')
attrs['user'] = user
return attrs

class ProfileSerializer(serializers.ModelSerializer):
"""
Serializer for displaying user profile data.

Returns basic information about the authenticated user.
"""
class Meta:
model = User
fields = ('id', 'username', 'email')
15 changes: 15 additions & 0 deletions accounts/templates/accounts/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends "base.html" %}

{% block title %}Login{% endblock %}

{% block content %}
<h1>Login</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
<p>
Don't have an account? <a href="{% url 'register' %}">Registration</a>
</p>
{% endblock %}
13 changes: 13 additions & 0 deletions accounts/templates/accounts/profile.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "base.html" %}

{% block title %}Profile{% endblock %}

{% block content %}
<h1>Profile</h1>
<p>User name: {{ user.username }}</p>
<p>Email: {{ user.email }}</p>
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit">Exit</button>
</form>
{% endblock %}
13 changes: 13 additions & 0 deletions accounts/templates/accounts/registration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "base.html" %}

{% block title %}Register{% endblock %}

{% block content %}
<h1>Registration</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Register</button>
</form>
<a href="{% url 'login' %}">Already exist? Login</a>
{% endblock %}
27 changes: 27 additions & 0 deletions accounts/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}Fools Arena{% endblock %}</title>
</head>
<body>
<header>
<h1>Fools Arena</h1>
<nav>
<a href="{% url 'login' %}">Login</a> |
<a href="{% url 'register' %}">Register</a> |
<a href="{% url 'profile' %}">Profile</a>
</nav>
</header>

<main>
{% block content %}
<!-- Page-specific content will be injected here -->
{% endblock %}
</main>

<footer>
<p>&copy; 2025 Fools Arena</p>
</footer>
</body>
</html>
Loading