From 249746af3a7dbcb1c71069e4a614e6e628d16f54 Mon Sep 17 00:00:00 2001 From: catbet2004 Date: Sun, 30 Aug 2026 15:37:09 -0400 Subject: [PATCH] Add user registration and authentication for Issue #106 --- backend/api.py | 2 ++ backend/quickstart/views.py | 65 ++++++++++++++++++++++++++++++++++++- backend/settings/base.py | 8 +++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/backend/api.py b/backend/api.py index 3100e65..127b6ba 100644 --- a/backend/api.py +++ b/backend/api.py @@ -4,6 +4,8 @@ urlpatterns: list[URLPattern] = [ path("ping/", views.ping), + path("create_user/", views.create_user), + path("login/", views.login_user), path("create_task/", views.create_task), path("get_task/", views.get_task), ] diff --git a/backend/quickstart/views.py b/backend/quickstart/views.py index f91d6cf..6a4edb4 100644 --- a/backend/quickstart/views.py +++ b/backend/quickstart/views.py @@ -1,12 +1,15 @@ from django.db.models import QuerySet +from django.contrib.auth import authenticate from rest_framework import status from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request from rest_framework.response import Response +from rest_framework.authtoken.models import Token +from rest_framework.permissions import AllowAny, IsAuthenticated from .models import StudyUser, Task # TODO remove, should be serializer -from .serializers import TaskSerializer +from .serializers import StudyUserSerializer, TaskSerializer @api_view(["GET"]) @@ -15,6 +18,66 @@ def ping(_request: Request) -> Response: return Response("pong") +@api_view(["POST"]) +@permission_classes([AllowAny]) +def create_user(request: Request)-> Response: + serializer =StudyUserSerializer(data=request.data) + + if serializer.is_valid(): + user=serializer.save() + token, _=Token.objects.get_or_create(user=user) + + return Response( + { + "id": user.id, + "username": user.username, + "email": user.email, + "token": token.key, + }, + status=status.HTTP_201_CREATED, + ) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST, + ) + +@api_view(["POST"]) +@permission_classes([AllowAny]) +def login_user(request: Request) -> Response: + username=request.data.get("username") + password=request.data.get("password") + + if not username or not password: + return Response( + {"error": "Username and password are required."}, + status=status.HTTP_400_BAD_REQUEST, + ) + user=authenticate( + request=request, + username=username, + password=password, + + ) + if user is None: + return Response( + {"error": "Invalid username or password."}, + status=status.HTTP_401_UNAUTHORIZED, + ) + token, _ =Token.objects.get_or_create(user=user) + + return Response( + { + "id": user.id, + "username": user.username, + "email": user.email, + "token": token.key, + + }, + status=status.HTTP_200_OK, + ) + + + @api_view(["POST"]) @permission_classes([IsAuthenticated]) def create_task(request: Request) -> Response: diff --git a/backend/settings/base.py b/backend/settings/base.py index 8bab626..e754476 100644 --- a/backend/settings/base.py +++ b/backend/settings/base.py @@ -28,8 +28,16 @@ "django.contrib.staticfiles", "quickstart", "rest_framework", + "rest_framework.authtoken", ] +REST_FRAMEWORK={ + "DEFAULT_AUTHENTICATION_CLASSES": [ + "rest_framework.authentication.TokenAuthentication", + "rest_framework.authentication.SessionAuthentication", + ], +} + MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",