From 1e5a1102408a583fa57f22cf987f6e1da4479343 Mon Sep 17 00:00:00 2001 From: Archly2022 <97497497+Archly2022@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:10:45 -0800 Subject: [PATCH 1/8] new file --- file.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 file.txt diff --git a/file.txt b/file.txt new file mode 100644 index 00000000..c57eff55 --- /dev/null +++ b/file.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file From ba203f1296c97496764f02db275ba1b6f083a2a8 Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:19:45 -0800 Subject: [PATCH 2/8] login, register, logout, resetpassword, checkstatus views --- server/farmapp/views.py | 102 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/server/farmapp/views.py b/server/farmapp/views.py index 91ea44a2..97f2d065 100644 --- a/server/farmapp/views.py +++ b/server/farmapp/views.py @@ -1,3 +1,101 @@ -from django.shortcuts import render +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView +from .models import User +from .serializers import RegisterSerializer, LoginSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer, UserSerializer +from rest_framework_simplejwt.tokens import RefreshToken +from rest_framework.permissions import IsAuthenticated +from django.utils.crypto import get_random_string +from django.core.mail import send_mail +from django.conf import settings -# Create your views here. +class RegisterView(APIView): + def post(self, request): + serializer = RegisterSerializer(data=request.data) + 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) + +class LoginView(APIView): + def post(self, request): + serializer = LoginSerializer(data=request.data) + if serializer.is_valid(): + email = serializer.validated_data['email'] + password = serializer.validated_data['passwordHash'] + user = User.objects.filter(email=email).first() + if user and user.check_password(password): + refresh = RefreshToken.for_user(user) + return Response({ + 'refresh': str(refresh), + 'access': str(refresh.access_token), + }, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ForgotPasswordView(APIView): + def post(self, request): + serializer = ForgotPasswordSerializer(data=request.data) + if serializer.is_valid(): + email = serializer.validated_data['email'] + user = User.objects.filter(email=email).first() + if user: + token = get_random_string(length=32) + # Save token to database or cache + # Send reset password link to user's email + send_mail( + 'Reset Password', + f'Reset password link: {request.build_absolute_uri("/reset-password")}?token={token}', + settings.EMAIL_HOST_USER, + [email], + fail_silently=False, + ) + return Response({'message': 'Reset password link sent successfully'}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ResetPasswordView(APIView): + def post(self, request): + serializer = ResetPasswordSerializer(data=request.data) + if serializer.is_valid(): + token = serializer.validated_data['token'] + password = serializer.validated_data['passwordHash'] + # Verify token from database or cache + user = User.objects.filter(email=request.data.get('email')).first() + if user: + user.set_password(password) + user.save() + return Response({'message': 'Password reset successfully'}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ChangePasswordView(APIView): + permission_classes = [IsAuthenticated] + + def post(self, request): + serializer = ChangePasswordSerializer(data=request.data) + if serializer.is_valid(): + old_password = serializer.validated_data['old_password'] + new_password = serializer.validated_data['new_password'] + user = request.user + if user.check_password(old_password): + user.set_password(new_password) + user.save() + return Response({'message': 'Password changed successfully'}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class CheckStatusView(APIView): + permission_classes = [IsAuthenticated] + + def get(self, request): + serializer = UserSerializer(request.user) + return Response(serializer.data, status=status.HTTP_200_OK) + +class SignoutView(APIView): + permission_classes = [IsAuthenticated] + + def post(self, request): + try: + refresh_token = request.data['refresh'] + token = RefreshToken(refresh_token) + token.blacklist() + return Response({'message': 'User signed out successfully'}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file From d957a6be2cfdaa80353e8b7f442a2ffbd80180da Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:20:37 -0800 Subject: [PATCH 3/8] url test endpoints --- server/farmsales/urls.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/farmsales/urls.py b/server/farmsales/urls.py index 7376a3a0..ce7b5b59 100644 --- a/server/farmsales/urls.py +++ b/server/farmsales/urls.py @@ -15,8 +15,10 @@ 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 urlpatterns = [ path('admin/', admin.site.urls), + path('api/', include('farmapp.urls')), + ] From 66bfc5550e1c327ab6a328a5f0bff0f1b8ff5e21 Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:21:42 -0800 Subject: [PATCH 4/8] serializers for views authentications --- server/farmapp/serializers.py | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 server/farmapp/serializers.py diff --git a/server/farmapp/serializers.py b/server/farmapp/serializers.py new file mode 100644 index 00000000..5752f5b9 --- /dev/null +++ b/server/farmapp/serializers.py @@ -0,0 +1,40 @@ +from rest_framework import serializers +from .models import User + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['userId', 'name', 'email', 'role', 'phone', 'address'] + extra_kwargs = { + 'email': {'required': True}, + 'name': {'required': True}, + 'role': {'required': True}, + } + +class RegisterSerializer(serializers.ModelSerializer): + passwordHash = serializers.CharField(max_length=255, write_only=True) + + class Meta: + model = User + fields = ['email', 'name', 'passwordHash', 'role', 'phone', 'address'] + extra_kwargs = { + 'email': {'required': True}, + 'name': {'required': True}, + 'passwordHash': {'required': True}, + 'role': {'required': True}, + } + +class LoginSerializer(serializers.Serializer): + email = serializers.EmailField(required=True) + passwordHash = serializers.CharField(max_length=255, write_only=True) + +class ForgotPasswordSerializer(serializers.Serializer): + email = serializers.EmailField(required=True) + +class ResetPasswordSerializer(serializers.Serializer): + token = serializers.CharField(max_length=255, required=True) + passwordHash = serializers.CharField(max_length=255, write_only=True) + +class ChangePasswordSerializer(serializers.Serializer): + old_password = serializers.CharField(max_length=255, write_only=True) + new_password = serializers.CharField(max_length=255, write_only=True) \ No newline at end of file From 45a4d39d68eae7094a60744e3db67cc40cef0349 Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:23:15 -0800 Subject: [PATCH 5/8] url endpoints --- server/farmapp/urls.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 server/farmapp/urls.py diff --git a/server/farmapp/urls.py b/server/farmapp/urls.py new file mode 100644 index 00000000..76efe043 --- /dev/null +++ b/server/farmapp/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from .views import RegisterView, LoginView, ForgotPasswordView, ResetPasswordView, ChangePasswordView, CheckStatusView, SignoutView + +urlpatterns = [ + path('farmer/auth/register/', RegisterView.as_view(), name='register'), + path('farmer/auth/login/', LoginView.as_view(), name='login'), + path('farmer/auth/forgot-password/', ForgotPasswordView.as_view(), name='forgot-password'), + path('farmer/auth/reset-password/', ResetPasswordView.as_view(), name='reset-password'), + path('farmer/auth/change-password/', ChangePasswordView.as_view(), name='change-password'), + path('farmer/auth/check-status/', CheckStatusView.as_view(), name='check-status'), + path('farmer/auth/signout/', SignoutView.as_view(), name='signout'), +] \ No newline at end of file From 8a25e83993f515db0746aebae15db7829fba1771 Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:09:32 -0800 Subject: [PATCH 6/8] Fixed 4 enpoints --- server/farmapp/models.py | 20 ++-- server/farmapp/serializers.py | 43 ++++----- server/farmapp/views.py | 167 +++++++++++++++++++++------------- server/farmsales/settings.py | 24 ++++- 4 files changed, 153 insertions(+), 101 deletions(-) diff --git a/server/farmapp/models.py b/server/farmapp/models.py index 8a05040d..9729ac8c 100644 --- a/server/farmapp/models.py +++ b/server/farmapp/models.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import AbstractBaseUser from django.utils import timezone + # 1. User Model class User(AbstractBaseUser): ROLE_CHOICES = [ @@ -16,12 +17,15 @@ class User(AbstractBaseUser): userId = models.AutoField(primary_key=True) name = models.CharField(max_length=255) email = models.EmailField(unique=True) - passwordHash = models.CharField(max_length=255) + password = models.CharField(max_length=255) role = models.CharField(max_length=10, choices=ROLE_CHOICES) phone = models.CharField(max_length=15, null=True, blank=True) address = models.CharField(max_length=255, null=True, blank=True) createdAt = models.DateTimeField(auto_now_add=True) updatedAt = models.DateTimeField(auto_now=True) + reset_password_token = models.CharField(max_length=36, null=True, blank=True) # UUID token + reset_token_created_at = models.DateTimeField(null=True, blank=True) # Token timestamp + USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name'] @@ -31,7 +35,7 @@ def __str__(self): class Meta: db_table = 'User' - managed = False + managed = True # 2. Farmer Model @@ -57,7 +61,7 @@ def __str__(self): class Meta: db_table = 'Farmer' - managed = False + managed = True # 3. Product Model class Product(models.Model): @@ -84,7 +88,7 @@ def __str__(self): class Meta: db_table = 'Product' - managed = False + managed = True # 4. Order Model class Order(models.Model): @@ -108,7 +112,7 @@ def __str__(self): class Meta: db_table = 'Order' - managed = False + managed = True # 5. Cart Model (for Customers) class Cart(models.Model): @@ -124,7 +128,7 @@ def __str__(self): class Meta: db_table = 'Cart' - managed = False + managed = True # 6. Review Model class Review(models.Model): @@ -141,7 +145,7 @@ def __str__(self): class Meta: db_table = 'Review' - managed = False + managed = True # 7. Admin Activity Log Model class AdminActivityLog(models.Model): @@ -156,4 +160,4 @@ def __str__(self): class Meta: db_table = 'AdminActivityLog' - managed = False + managed = True diff --git a/server/farmapp/serializers.py b/server/farmapp/serializers.py index 5752f5b9..bb248483 100644 --- a/server/farmapp/serializers.py +++ b/server/farmapp/serializers.py @@ -1,40 +1,29 @@ from rest_framework import serializers +from django.contrib.auth.hashers import make_password from .models import User -class UserSerializer(serializers.ModelSerializer): - class Meta: - model = User - fields = ['userId', 'name', 'email', 'role', 'phone', 'address'] - extra_kwargs = { - 'email': {'required': True}, - 'name': {'required': True}, - 'role': {'required': True}, - } - class RegisterSerializer(serializers.ModelSerializer): - passwordHash = serializers.CharField(max_length=255, write_only=True) + password = serializers.CharField(write_only=True) class Meta: model = User - fields = ['email', 'name', 'passwordHash', 'role', 'phone', 'address'] - extra_kwargs = { - 'email': {'required': True}, - 'name': {'required': True}, - 'passwordHash': {'required': True}, - 'role': {'required': True}, - } + fields = ['name', 'email', 'password', 'role', 'phone', 'address'] + + def create(self, validated_data): + validated_data['password'] = make_password(validated_data['password']) + return super().create(validated_data) class LoginSerializer(serializers.Serializer): - email = serializers.EmailField(required=True) - passwordHash = serializers.CharField(max_length=255, write_only=True) + email = serializers.EmailField() + password = serializers.CharField(write_only=True) + +class ChangePasswordSerializer(serializers.Serializer): + old_password = serializers.CharField(write_only=True) + new_password = serializers.CharField(write_only=True) class ForgotPasswordSerializer(serializers.Serializer): - email = serializers.EmailField(required=True) + email = serializers.EmailField() class ResetPasswordSerializer(serializers.Serializer): - token = serializers.CharField(max_length=255, required=True) - passwordHash = serializers.CharField(max_length=255, write_only=True) - -class ChangePasswordSerializer(serializers.Serializer): - old_password = serializers.CharField(max_length=255, write_only=True) - new_password = serializers.CharField(max_length=255, write_only=True) \ No newline at end of file + token = serializers.CharField() + new_password = serializers.CharField(write_only=True) diff --git a/server/farmapp/views.py b/server/farmapp/views.py index 97f2d065..3aba57da 100644 --- a/server/farmapp/views.py +++ b/server/farmapp/views.py @@ -1,101 +1,146 @@ -from rest_framework import status -from rest_framework.response import Response from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from django.contrib.auth import authenticate +from django.contrib.auth.hashers import check_password, make_password from .models import User -from .serializers import RegisterSerializer, LoginSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer, UserSerializer -from rest_framework_simplejwt.tokens import RefreshToken +from datetime import timedelta +from django.utils.timezone import now +import uuid +import jwt +from django.conf import settings from rest_framework.permissions import IsAuthenticated -from django.utils.crypto import get_random_string from django.core.mail import send_mail -from django.conf import settings +from .serializers import ( + RegisterSerializer, LoginSerializer, ChangePasswordSerializer, + ForgotPasswordSerializer, ResetPasswordSerializer +) + + +# JWT Utility +def generate_jwt(user): + payload = {'user_id': user.userId, 'email': user.email} + token = jwt.encode(payload, settings.SECRET_KEY, algorithm='HS256') + return token class RegisterView(APIView): def post(self, request): serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) + user = serializer.save() + return Response({"message": "User registered successfully."}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + class LoginView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] - password = serializer.validated_data['passwordHash'] - user = User.objects.filter(email=email).first() - if user and user.check_password(password): - refresh = RefreshToken.for_user(user) - return Response({ - 'refresh': str(refresh), - 'access': str(refresh.access_token), - }, status=status.HTTP_200_OK) + password = serializer.validated_data['password'] + try: + user = User.objects.get(email=email) + except User.DoesNotExist: + return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED) + + # Check if the password matches + if not check_password(password, user.password): + return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED) + + # Ensure user is active + if not user.is_active: + return Response({"error": "Email not verified."}, status=status.HTTP_403_FORBIDDEN) + + # Generate JWT token + token = generate_jwt(user) + return Response({"token": token}, status=status.HTTP_200_OK) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class ChangePasswordView(APIView): + permission_classes = [IsAuthenticated] + + def post(self, request): + user = request.user + serializer = ChangePasswordSerializer(data=request.data) + if serializer.is_valid(): + if check_password(serializer.validated_data['old_password'], user.password): + user.password = make_password(serializer.validated_data['new_password']) + user.save() + return Response({"message": "Password changed successfully."}, status=status.HTTP_200_OK) + return Response({"error": "Old password is incorrect."}, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + + + class ForgotPasswordView(APIView): def post(self, request): serializer = ForgotPasswordSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] - user = User.objects.filter(email=email).first() - if user: - token = get_random_string(length=32) - # Save token to database or cache - # Send reset password link to user's email - send_mail( - 'Reset Password', - f'Reset password link: {request.build_absolute_uri("/reset-password")}?token={token}', - settings.EMAIL_HOST_USER, - [email], - fail_silently=False, - ) - return Response({'message': 'Reset password link sent successfully'}, status=status.HTTP_200_OK) + try: + user = User.objects.get(email=email) + except User.DoesNotExist: + return Response({"error": "No user found with this email address."}, status=status.HTTP_404_NOT_FOUND) + + # Generate a UUID token + reset_token = str(uuid.uuid4()) + user.reset_password_token = reset_token + user.reset_token_created_at = now() + user.save() + + # Create the reset password link + reset_url = f"http://your-frontend-url.com/reset-password?token={reset_token}" + + # Simulate sending email + subject = "Password Reset Request" + message = f"Hi {user.name},\n\nYou requested a password reset. Click the link below to reset your password:\n\n{reset_url}\n\nIf you did not request this, please ignore this email." + from_email = "no-reply@yourdomain.com" + recipient_list = [email] + + send_mail(subject, message, from_email, recipient_list) + + return Response({"message": "Password reset link sent to your email."}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + class ResetPasswordView(APIView): def post(self, request): serializer = ResetPasswordSerializer(data=request.data) if serializer.is_valid(): token = serializer.validated_data['token'] - password = serializer.validated_data['passwordHash'] - # Verify token from database or cache - user = User.objects.filter(email=request.data.get('email')).first() - if user: - user.set_password(password) - user.save() - return Response({'message': 'Password reset successfully'}, status=status.HTTP_200_OK) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + new_password = serializer.validated_data['new_password'] -class ChangePasswordView(APIView): - permission_classes = [IsAuthenticated] + try: + # Find user with the given reset token + user = User.objects.get(reset_password_token=token) - def post(self, request): - serializer = ChangePasswordSerializer(data=request.data) - if serializer.is_valid(): - old_password = serializer.validated_data['old_password'] - new_password = serializer.validated_data['new_password'] - user = request.user - if user.check_password(old_password): - user.set_password(new_password) + # Check token validity (e.g., expire after 1 hour) + token_age = now() - user.reset_token_created_at + if token_age > timedelta(hours=1): + return Response({"error": "Token has expired."}, status=status.HTTP_400_BAD_REQUEST) + + # Reset the password + user.password = make_password(new_password) + user.reset_password_token = None # Clear the token + user.reset_token_created_at = None user.save() - return Response({'message': 'Password changed successfully'}, status=status.HTTP_200_OK) + + return Response({"message": "Password reset successfully."}, status=status.HTTP_200_OK) + except User.DoesNotExist: + return Response({"error": "Invalid token."}, status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class CheckStatusView(APIView): - permission_classes = [IsAuthenticated] - def get(self, request): - serializer = UserSerializer(request.user) - return Response(serializer.data, status=status.HTTP_200_OK) + user = request.user + return Response({"user": {"id": user.userId, "name": user.name, "email": user.email}}, status=status.HTTP_200_OK) class SignoutView(APIView): - permission_classes = [IsAuthenticated] - def post(self, request): - try: - refresh_token = request.data['refresh'] - token = RefreshToken(refresh_token) - token.blacklist() - return Response({'message': 'User signed out successfully'}, status=status.HTTP_200_OK) - except Exception as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file + # Implement signout logic (if using token blacklist or other session tracking) + return Response({"message": "Successfully signed out."}, status=status.HTTP_200_OK) diff --git a/server/farmsales/settings.py b/server/farmsales/settings.py index f5c2855f..feefc390 100644 --- a/server/farmsales/settings.py +++ b/server/farmsales/settings.py @@ -11,6 +11,9 @@ """ from pathlib import Path +import os +from dotenv import load_dotenv +load_dotenv() # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -37,6 +40,9 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'farmapp', + 'rest_framework', + 'rest_framework.authtoken', ] MIDDLEWARE = [ @@ -75,16 +81,15 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', + 'ENGINE': 'django.db.backends.mysql', 'NAME': 'CropCircle', - 'USER': 'backend_team', - 'PASSWORD': 'Akogo660221.', + 'USER': f'{os.getenv('DB_USER')}', + 'PASSWORD': f'{os.getenv('DB_PASSWORD')}', 'HOST': 'localhost', - 'PORT': '3306', + 'PORT': '3306', } } - # Password validation # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators @@ -125,3 +130,12 @@ # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# settings.py + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = 'archillesjacob2@gmail.com' +EMAIL_HOST_PASSWORD = f'{os.getenv('password')}' # or App Password +EMAIL_USE_TLS = True \ No newline at end of file From fbf8fedada24410830d2b2faeee7a0d10728b91d Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Sat, 16 Nov 2024 07:26:22 -0800 Subject: [PATCH 7/8] reslove conflicts --- server/farmapp/models.py | 23 +++--- server/farmapp/serializers.py | 64 ++++++++++++++++- server/farmapp/urls.py | 25 ++++++- server/farmapp/views.py | 127 +++++++++++++++++++++++----------- server/farmsales/settings.py | 81 +++++++++++----------- server/farmsales/urls.py | 6 +- 6 files changed, 229 insertions(+), 97 deletions(-) diff --git a/server/farmapp/models.py b/server/farmapp/models.py index 9729ac8c..1fef2386 100644 --- a/server/farmapp/models.py +++ b/server/farmapp/models.py @@ -1,7 +1,4 @@ from django.db import models - -# Create your models here. -from django.db import models from django.contrib.auth.models import AbstractBaseUser from django.utils import timezone @@ -17,7 +14,7 @@ class User(AbstractBaseUser): userId = models.AutoField(primary_key=True) name = models.CharField(max_length=255) email = models.EmailField(unique=True) - password = models.CharField(max_length=255) + password = models.CharField(max_length=255) # Password field role = models.CharField(max_length=10, choices=ROLE_CHOICES) phone = models.CharField(max_length=15, null=True, blank=True) address = models.CharField(max_length=255, null=True, blank=True) @@ -25,19 +22,18 @@ class User(AbstractBaseUser): updatedAt = models.DateTimeField(auto_now=True) reset_password_token = models.CharField(max_length=36, null=True, blank=True) # UUID token reset_token_created_at = models.DateTimeField(null=True, blank=True) # Token timestamp + last_login = models.DateTimeField(null=True, blank=True) # Last login timestamp - USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name'] def __str__(self): return self.name - + class Meta: db_table = 'User' managed = True - # 2. Farmer Model class Farmer(models.Model): VERIFICATION_STATUS_CHOICES = [ @@ -47,7 +43,7 @@ class Farmer(models.Model): ] farmerId = models.AutoField(primary_key=True) - user = models.OneToOneField(User, on_delete=models.CASCADE, limit_choices_to={'role': 'farmer'}) + userId = models.OneToOneField(User, on_delete=models.CASCADE, limit_choices_to={'role': 'farmer'}, related_name='farmer', db_column='userId') farmName = models.CharField(max_length=255) location = models.CharField(max_length=255) farmType = models.CharField(max_length=50) @@ -72,7 +68,7 @@ class Product(models.Model): ] productId = models.AutoField(primary_key=True) - farmer = models.ForeignKey(Farmer, on_delete=models.CASCADE) + farmer = models.ForeignKey(Farmer, on_delete=models.CASCADE, db_column='farmerId') productName = models.CharField(max_length=255) description = models.TextField() category = models.CharField(max_length=50) @@ -100,15 +96,16 @@ class Order(models.Model): ] orderId = models.AutoField(primary_key=True) - customer = models.ForeignKey(User, on_delete=models.CASCADE, limit_choices_to={'role': 'customer'}) + customer = models.ForeignKey(User, on_delete=models.CASCADE, db_column='customerId') orderItems = models.JSONField() # Store an array of products, including productId, quantity, and price totalAmount = models.DecimalField(max_digits=10, decimal_places=2) status = models.CharField(max_length=20, choices=ORDER_STATUS_CHOICES) createdAt = models.DateTimeField(auto_now_add=True) updatedAt = models.DateTimeField(auto_now=True) + deliveryDate = models.DateTimeField(null=True, blank=True) def __str__(self): - return self.orderId + return str(self.orderId) class Meta: db_table = 'Order' @@ -124,7 +121,7 @@ class Cart(models.Model): updatedAt = models.DateTimeField(auto_now=True) def __str__(self): - return self.customer + return str(self.cartId) class Meta: db_table = 'Cart' @@ -141,7 +138,7 @@ class Review(models.Model): updatedAt = models.DateTimeField(auto_now=True) def __str__(self): - return self.reviewId + return str(self.reviewId) class Meta: db_table = 'Review' diff --git a/server/farmapp/serializers.py b/server/farmapp/serializers.py index bb248483..8138ad34 100644 --- a/server/farmapp/serializers.py +++ b/server/farmapp/serializers.py @@ -1,7 +1,8 @@ from rest_framework import serializers from django.contrib.auth.hashers import make_password -from .models import User +from .models import User, Order, Product +# User Management Serializers class RegisterSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) @@ -27,3 +28,64 @@ class ForgotPasswordSerializer(serializers.Serializer): class ResetPasswordSerializer(serializers.Serializer): token = serializers.CharField() new_password = serializers.CharField(write_only=True) + +# Order Management Serializers +class OrderDetailSerializer(serializers.ModelSerializer): + """ + Serializer for displaying detailed information about an order. + """ + orderId = serializers.IntegerField() # Removed 'source' argument + customerName = serializers.CharField(source='customer.name') + productName = serializers.SerializerMethodField() + quantity = serializers.SerializerMethodField() + totalPrice = serializers.DecimalField(source='totalAmount', max_digits=10, decimal_places=2) + orderStatus = serializers.CharField(source='status') + dateOrdered = serializers.DateTimeField(source='createdAt') + deliveryDate = serializers.DateTimeField() + address = serializers.CharField(source='customer.address') + phone = serializers.CharField(source='customer.phone', allow_null=True, required=False) + + def get_productName(self, obj): + """ + Retrieves the name of the product from the Product model based on productId. + """ + product_ids = [item['productId'] for item in obj.orderItems] + products = Product.objects.filter(productId__in=product_ids) + return ', '.join([product.productName for product in products]) + + def get_quantity(self, obj): + """ + Retrieves the quantity of the product ordered. + """ + return sum(item.get('quantity', 0) for item in obj.orderItems) + + class Meta: + model = Order + fields = ['orderId', 'customerName', 'productName', 'phone', 'orderItems', 'totalPrice', 'orderStatus', 'address', 'quantity', 'dateOrdered', 'deliveryDate'] + +class OrderStatusUpdateSerializer(serializers.ModelSerializer): + """ + Serializer for updating the status of an order. + """ + status = serializers.ChoiceField(choices=Order.ORDER_STATUS_CHOICES) + + def validate_status(self, value): + """ + Validates allowed status transitions for the order. + """ + current_status = self.instance.status + allowed_transitions = { + 'pending': ['shipped', 'cancelled'], + 'shipped': ['delivered'], + 'delivered': [], + } + + if value not in allowed_transitions.get(current_status, []): + raise serializers.ValidationError( + f"Invalid status transition from '{current_status}' to '{value}'" + ) + return value + + class Meta: + model = Order + fields = ['status'] diff --git a/server/farmapp/urls.py b/server/farmapp/urls.py index 76efe043..b9473d84 100644 --- a/server/farmapp/urls.py +++ b/server/farmapp/urls.py @@ -1,7 +1,20 @@ from django.urls import path -from .views import RegisterView, LoginView, ForgotPasswordView, ResetPasswordView, ChangePasswordView, CheckStatusView, SignoutView +from .views import ( + RegisterView, + LoginView, + ForgotPasswordView, + ResetPasswordView, + ChangePasswordView, + CheckStatusView, + SignoutView, + DeleteReviewView, + OrderDetailView, + UpdateOrderStatusView, + DeleteOrderView, +) urlpatterns = [ + # Auth-related endpoints path('farmer/auth/register/', RegisterView.as_view(), name='register'), path('farmer/auth/login/', LoginView.as_view(), name='login'), path('farmer/auth/forgot-password/', ForgotPasswordView.as_view(), name='forgot-password'), @@ -9,4 +22,12 @@ path('farmer/auth/change-password/', ChangePasswordView.as_view(), name='change-password'), path('farmer/auth/check-status/', CheckStatusView.as_view(), name='check-status'), path('farmer/auth/signout/', SignoutView.as_view(), name='signout'), -] \ No newline at end of file + + # Order-related endpoints + path("api/farmer//orders/", OrderDetailView.as_view(), name="order-detail"), + path("api/farmer//orders//status", UpdateOrderStatusView.as_view(), name="update-order-status"), + path("api/farmer//orders//delete", DeleteOrderView.as_view(), name="delete-order"), + + # Review-related endpoints + path("api/product//reviews/", DeleteReviewView.as_view(), name="delete-review"), +] diff --git a/server/farmapp/views.py b/server/farmapp/views.py index 3aba57da..69a74aa4 100644 --- a/server/farmapp/views.py +++ b/server/farmapp/views.py @@ -1,28 +1,32 @@ from rest_framework.views import APIView from rest_framework.response import Response -from rest_framework import status +from rest_framework import status, views from django.contrib.auth import authenticate from django.contrib.auth.hashers import check_password, make_password -from .models import User -from datetime import timedelta +from django.core.mail import send_mail from django.utils.timezone import now -import uuid +from django.shortcuts import get_object_or_404 +from datetime import timedelta import jwt +import uuid from django.conf import settings +from django.db import DatabaseError from rest_framework.permissions import IsAuthenticated -from django.core.mail import send_mail + +from .models import User, Farmer, Order, Product, Review from .serializers import ( RegisterSerializer, LoginSerializer, ChangePasswordSerializer, - ForgotPasswordSerializer, ResetPasswordSerializer + ForgotPasswordSerializer, ResetPasswordSerializer, OrderDetailSerializer, + OrderStatusUpdateSerializer ) - # JWT Utility def generate_jwt(user): payload = {'user_id': user.userId, 'email': user.email} token = jwt.encode(payload, settings.SECRET_KEY, algorithm='HS256') return token +# Authentication Views class RegisterView(APIView): def post(self, request): serializer = RegisterSerializer(data=request.data) @@ -31,7 +35,6 @@ def post(self, request): return Response({"message": "User registered successfully."}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class LoginView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) @@ -43,21 +46,16 @@ def post(self, request): except User.DoesNotExist: return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED) - # Check if the password matches if not check_password(password, user.password): return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED) - - # Ensure user is active if not user.is_active: return Response({"error": "Email not verified."}, status=status.HTTP_403_FORBIDDEN) - # Generate JWT token token = generate_jwt(user) return Response({"token": token}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class ChangePasswordView(APIView): permission_classes = [IsAuthenticated] @@ -71,10 +69,6 @@ def post(self, request): return Response({"message": "Password changed successfully."}, status=status.HTTP_200_OK) return Response({"error": "Old password is incorrect."}, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - - - class ForgotPasswordView(APIView): def post(self, request): @@ -86,49 +80,36 @@ def post(self, request): except User.DoesNotExist: return Response({"error": "No user found with this email address."}, status=status.HTTP_404_NOT_FOUND) - # Generate a UUID token reset_token = str(uuid.uuid4()) user.reset_password_token = reset_token user.reset_token_created_at = now() user.save() - # Create the reset password link reset_url = f"http://your-frontend-url.com/reset-password?token={reset_token}" - - # Simulate sending email - subject = "Password Reset Request" - message = f"Hi {user.name},\n\nYou requested a password reset. Click the link below to reset your password:\n\n{reset_url}\n\nIf you did not request this, please ignore this email." - from_email = "no-reply@yourdomain.com" - recipient_list = [email] - - send_mail(subject, message, from_email, recipient_list) - + send_mail( + subject="Password Reset Request", + message=f"Hi {user.name},\n\nClick the link to reset your password:\n\n{reset_url}", + from_email="no-reply@yourdomain.com", + recipient_list=[email] + ) return Response({"message": "Password reset link sent to your email."}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class ResetPasswordView(APIView): def post(self, request): serializer = ResetPasswordSerializer(data=request.data) if serializer.is_valid(): token = serializer.validated_data['token'] new_password = serializer.validated_data['new_password'] - try: - # Find user with the given reset token user = User.objects.get(reset_password_token=token) - - # Check token validity (e.g., expire after 1 hour) - token_age = now() - user.reset_token_created_at - if token_age > timedelta(hours=1): + if now() - user.reset_token_created_at > timedelta(hours=1): return Response({"error": "Token has expired."}, status=status.HTTP_400_BAD_REQUEST) - # Reset the password user.password = make_password(new_password) - user.reset_password_token = None # Clear the token + user.reset_password_token = None user.reset_token_created_at = None user.save() - return Response({"message": "Password reset successfully."}, status=status.HTTP_200_OK) except User.DoesNotExist: return Response({"error": "Invalid token."}, status=status.HTTP_400_BAD_REQUEST) @@ -142,5 +123,73 @@ def get(self, request): class SignoutView(APIView): def post(self, request): - # Implement signout logic (if using token blacklist or other session tracking) return Response({"message": "Successfully signed out."}, status=status.HTTP_200_OK) + +# Order and Review Management Views +class OrderDetailView(APIView): + def get(self, request, farmerId, orderId): + try: + farmer = Farmer.objects.get(farmerId=farmerId) + order = Order.objects.get(orderId=orderId) + product_ids = [item['productId'] for item in order.orderItems] + if not Product.objects.filter(productId__in=product_ids, farmer=farmer).exists(): + return Response({"error": "Order not associated with this farmer"}, status=status.HTTP_404_NOT_FOUND) + + serializer = OrderDetailSerializer(order) + return Response(serializer.data, status=status.HTTP_200_OK) + except Farmer.DoesNotExist: + return Response({"error": "Farmer not found"}, status=status.HTTP_404_NOT_FOUND) + except Order.DoesNotExist: + return Response({"error": "Order not found"}, status=status.HTTP_404_NOT_FOUND) + +class UpdateOrderStatusView(APIView): + def put(self, request, farmerId, orderId): + try: + farmer = Farmer.objects.get(farmerId=farmerId) + order = Order.objects.get(orderId=orderId) + product_ids = [item['productId'] for item in order.orderItems] + if not Product.objects.filter(productId__in=product_ids, farmer=farmer).exists(): + return Response({"error": "Order not associated with this farmer"}, status=status.HTTP_404_NOT_FOUND) + + serializer = OrderStatusUpdateSerializer(order, data=request.data, partial=True) + if serializer.is_valid(): + order.status = serializer.validated_data['status'] + order.save() + return Response({"message": "Order status updated successfully", "status": order.status}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + except Farmer.DoesNotExist: + return Response({"error": "Farmer not found"}, status=status.HTTP_404_NOT_FOUND) + except Order.DoesNotExist: + return Response({"error": "Order not found"}, status=status.HTTP_404_NOT_FOUND) + +class DeleteOrderView(APIView): + def delete(self, request, farmerId, orderId): + try: + farmer = Farmer.objects.get(farmerId=farmerId) + order = Order.objects.get(orderId=orderId) + product_ids = [item['productId'] for item in order.orderItems] + if not Product.objects.filter(productId__in=product_ids, farmer=farmer).exists(): + return Response({"error": "Order not associated with this farmer"}, status=status.HTTP_404_NOT_FOUND) + + if order.status not in ["pending", "cancelled"]: + return Response({"error": "Cannot delete a completed or delivered order"}, status=status.HTTP_400_BAD_REQUEST) + + order.status = "cancelled" + order.save() + return Response({"message": "Order cancelled successfully"}, status=status.HTTP_200_OK) + except Farmer.DoesNotExist: + return Response({"error": "Farmer not found"}, status=status.HTTP_404_NOT_FOUND) + except Order.DoesNotExist: + return Response({"error": "Order not found"}, status=status.HTTP_404_NOT_FOUND) + +class DeleteReviewView(APIView): + def delete(self, request, productId, reviewId): + try: + review = get_object_or_404(Review, reviewId=reviewId, product__id=productId) + if review.customer != request.user: + return Response({"error": "You are not authorized to delete this review."}, status=status.HTTP_403_FORBIDDEN) + + review.delete() + return Response({"review": {}}, status=status.HTTP_204_NO_CONTENT) + except DatabaseError: + return Response({"error": "An error occurred while deleting the review."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/server/farmsales/settings.py b/server/farmsales/settings.py index feefc390..0ff8760c 100644 --- a/server/farmsales/settings.py +++ b/server/farmsales/settings.py @@ -13,26 +13,25 @@ from pathlib import Path import os from dotenv import load_dotenv + +# Load environment variables from .env file load_dotenv() # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-h$tn#ey-^dnq4!+3n!yn+w3-pc_*=nej@wc8b+-i0b*!=p64+h' +SECRET_KEY = os.getenv('SECRET_KEY', 'default-secret-key') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] +DEBUG = os.getenv('DEBUG', 'False').lower() in ('true', '1', 't') +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split(',') # Application definition - INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -40,9 +39,8 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'farmapp', - 'rest_framework', - 'rest_framework.authtoken', + 'rest_framework', + 'farmapp', # Custom app ] MIDDLEWARE = [ @@ -75,43 +73,30 @@ WSGI_APPLICATION = 'farmsales.wsgi.application' - # Database # https://docs.djangoproject.com/en/5.1/ref/settings/#databases - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'CropCircle', - 'USER': f'{os.getenv('DB_USER')}', - 'PASSWORD': f'{os.getenv('DB_PASSWORD')}', - 'HOST': 'localhost', - 'PORT': '3306', + 'NAME': os.getenv('DB_NAME', 'CropCircle'), + 'USER': os.getenv('DB_USER', 'root'), + 'PASSWORD': os.getenv('DB_PASSWORD', 'password'), + 'HOST': os.getenv('DB_HOST', 'localhost'), + 'PORT': os.getenv('DB_PORT', '3306'), } } # Password validation # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators - AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, + {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'}, + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, + {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, ] - # Internationalization # https://docs.djangoproject.com/en/5.1/topics/i18n/ - LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' @@ -120,22 +105,40 @@ USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.1/howto/static-files/ - STATIC_URL = 'static/' # Default primary key field type # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field - DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -# settings.py - +# Email settings EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' EMAIL_PORT = 587 -EMAIL_HOST_USER = 'archillesjacob2@gmail.com' -EMAIL_HOST_PASSWORD = f'{os.getenv('password')}' # or App Password -EMAIL_USE_TLS = True \ No newline at end of file +EMAIL_HOST_USER = os.getenv('EMAIL_USER', 'example@gmail.com') +EMAIL_HOST_PASSWORD = os.getenv('EMAIL_PASSWORD', 'password') +EMAIL_USE_TLS = True + +# Logging configuration +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + }, + }, + 'root': { + 'handlers': ['console'], + 'level': 'WARNING', + }, + 'django': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, +} + +# ALLOWED_HOSTS=['127.0.0.1'] \ No newline at end of file diff --git a/server/farmsales/urls.py b/server/farmsales/urls.py index ce7b5b59..a3d00f3f 100644 --- a/server/farmsales/urls.py +++ b/server/farmsales/urls.py @@ -14,11 +14,11 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin -from django.urls import path, include +from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), - path('api/', include('farmapp.urls')), - + path('api/', include('farmapp.urls')), # API routes for farmapp ] From a1e2090c540e0f4bfb11a595afd371de5ff22a37 Mon Sep 17 00:00:00 2001 From: Archlyjakins <97497497+Archillesjakins@users.noreply.github.com> Date: Wed, 20 Nov 2024 23:34:59 -0800 Subject: [PATCH 8/8] Url improvements --- server/farmapp/models.py | 1 + server/farmapp/serializers.py | 5 +++++ server/farmapp/views.py | 26 ++++++++++++++++++++------ server/farmsales/settings.py | 25 ++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/server/farmapp/models.py b/server/farmapp/models.py index 96cb89e8..8592d037 100644 --- a/server/farmapp/models.py +++ b/server/farmapp/models.py @@ -24,6 +24,7 @@ class User(AbstractBaseUser): reset_password_token = models.CharField(max_length=36, null=True, blank=True) # UUID token reset_token_created_at = models.DateTimeField(null=True, blank=True) # Token timestamp last_login = models.DateTimeField(null=True, blank=True) # Last login timestamp + is_active = models.BooleanField(default=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name'] diff --git a/server/farmapp/serializers.py b/server/farmapp/serializers.py index 8138ad34..812d30d4 100644 --- a/server/farmapp/serializers.py +++ b/server/farmapp/serializers.py @@ -29,6 +29,11 @@ class ResetPasswordSerializer(serializers.Serializer): token = serializers.CharField() new_password = serializers.CharField(write_only=True) +class UserStatusSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['userId', 'name', 'email', 'is_active', 'role'] + # Order Management Serializers class OrderDetailSerializer(serializers.ModelSerializer): """ diff --git a/server/farmapp/views.py b/server/farmapp/views.py index 69a74aa4..cff84773 100644 --- a/server/farmapp/views.py +++ b/server/farmapp/views.py @@ -17,7 +17,7 @@ from .serializers import ( RegisterSerializer, LoginSerializer, ChangePasswordSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, OrderDetailSerializer, - OrderStatusUpdateSerializer + OrderStatusUpdateSerializer, UserStatusSerializer ) # JWT Utility @@ -28,6 +28,7 @@ def generate_jwt(user): # Authentication Views class RegisterView(APIView): + def post(self, request): serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): @@ -35,6 +36,8 @@ def post(self, request): return Response({"message": "User registered successfully."}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +from rest_framework_simplejwt.tokens import RefreshToken + class LoginView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) @@ -48,12 +51,15 @@ def post(self, request): if not check_password(password, user.password): return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED) + if not user.is_active: return Response({"error": "Email not verified."}, status=status.HTTP_403_FORBIDDEN) - token = generate_jwt(user) - return Response({"token": token}, status=status.HTTP_200_OK) - + refresh = RefreshToken.for_user(user) + return Response({ + 'access': str(refresh.access_token), + 'refresh': str(refresh), + }, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class ChangePasswordView(APIView): @@ -117,10 +123,18 @@ def post(self, request): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class CheckStatusView(APIView): + permission_classes = [IsAuthenticated] + def get(self, request): user = request.user - return Response({"user": {"id": user.userId, "name": user.name, "email": user.email}}, status=status.HTTP_200_OK) - + if not user.is_active: + return Response({"error": "User account is Inactive!."}, status=403) + + serializer = UserStatusSerializer(user) + return Response(serializer.data, status=status.HTTP_200_OK) + + + class SignoutView(APIView): def post(self, request): return Response({"message": "Successfully signed out."}, status=status.HTTP_200_OK) diff --git a/server/farmsales/settings.py b/server/farmsales/settings.py index 0ff8760c..2bbf36ca 100644 --- a/server/farmsales/settings.py +++ b/server/farmsales/settings.py @@ -78,9 +78,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': os.getenv('DB_NAME', 'CropCircle'), + 'NAME': os.getenv('DB_NAME', 'Cropsdb'), 'USER': os.getenv('DB_USER', 'root'), - 'PASSWORD': os.getenv('DB_PASSWORD', 'password'), + 'PASSWORD': os.getenv('DB_PASSWORD', 'Archilles5522'), 'HOST': os.getenv('DB_HOST', 'localhost'), 'PORT': os.getenv('DB_PORT', '3306'), } @@ -141,4 +141,23 @@ }, } -# ALLOWED_HOSTS=['127.0.0.1'] \ No newline at end of file +ALLOWED_HOSTS=['127.0.0.1'] + +from datetime import timedelta + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'ROTATE_REFRESH_TOKENS': False, + 'BLACKLIST_AFTER_ROTATION': True, + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUTH_HEADER_TYPES': ('Bearer',), + 'USER_ID_FIELD': 'userId', + 'USER_ID_CLAIM': 'userId', +} + + + +