From 227cb3e12bd5ec218594919f706340ad3135f8e3 Mon Sep 17 00:00:00 2001 From: Lance Tan Date: Thu, 23 Nov 2023 22:31:08 -0800 Subject: [PATCH 1/2] Create endpoints for user --- backend/bid/migrations/0001_initial.py | 4 +- backend/bid/serializers.py | 0 backend/bid/urls.py | 4 + backend/core/urls.py | 5 +- backend/user/migrations/0001_initial.py | 67 +++++++++++++ ...bidder_number_alter_bidder_company_name.py | 22 +++++ backend/user/migrations/__init__.py | 0 backend/user/models.py | 6 +- backend/user/serializers.py | 21 ++++ backend/user/urls.py | 23 +++++ backend/user/views.py | 99 ++++++++++++++++++- backend/vehicle/views.py | 2 +- 12 files changed, 242 insertions(+), 11 deletions(-) create mode 100644 backend/bid/serializers.py create mode 100644 backend/bid/urls.py create mode 100644 backend/user/migrations/0001_initial.py create mode 100644 backend/user/migrations/0002_alter_bidder_bidder_number_alter_bidder_company_name.py create mode 100644 backend/user/migrations/__init__.py create mode 100644 backend/user/serializers.py create mode 100644 backend/user/urls.py diff --git a/backend/bid/migrations/0001_initial.py b/backend/bid/migrations/0001_initial.py index ff44874..ee39a9f 100644 --- a/backend/bid/migrations/0001_initial.py +++ b/backend/bid/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2023-10-24 19:21 +# Generated by Django 4.2.6 on 2023-11-24 06:21 from django.db import migrations, models import django.db.models.deletion @@ -9,8 +9,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ("user", "0001_initial"), ("contenttypes", "0002_remove_content_type_name"), - ("user", "__first__"), ] operations = [ diff --git a/backend/bid/serializers.py b/backend/bid/serializers.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/bid/urls.py b/backend/bid/urls.py new file mode 100644 index 0000000..d89da4a --- /dev/null +++ b/backend/bid/urls.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from django.urls import include, path + +urlpatterns = [] diff --git a/backend/core/urls.py b/backend/core/urls.py index 5a68321..30b1276 100644 --- a/backend/core/urls.py +++ b/backend/core/urls.py @@ -19,6 +19,7 @@ urlpatterns = [ path("admin/", admin.site.urls), - path("api/v1/auction/", include("auction.urls")), - path("api/v1/vehicle/", include("vehicle.urls")), + path("api/v1/auctions/", include("auction.urls")), + path("api/v1/vehicles/", include("vehicle.urls")), + path("api/v1/", include("user.urls")), ] diff --git a/backend/user/migrations/0001_initial.py b/backend/user/migrations/0001_initial.py new file mode 100644 index 0000000..bfb5d3a --- /dev/null +++ b/backend/user/migrations/0001_initial.py @@ -0,0 +1,67 @@ +# Generated by Django 4.2.6 on 2023-11-24 05:59 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Admin", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("email", models.CharField(max_length=150)), + ("password", models.CharField(max_length=50)), + ("first_name", models.CharField(max_length=150)), + ("last_name", models.CharField(max_length=150)), + ("permission_level", models.IntegerField(default=0)), + ], + options={ + "ordering": ["-created_at"], + "abstract": False, + }, + ), + migrations.CreateModel( + name="Bidder", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("email", models.CharField(max_length=150)), + ("first_name", models.CharField(max_length=150)), + ("last_name", models.CharField(max_length=150)), + ("company_name", models.CharField(max_length=150)), + ("bidder_number", models.IntegerField(unique=True)), + ("is_verified", models.BooleanField(default=False)), + ("is_blacklisted", models.BooleanField(default=False)), + ], + options={ + "ordering": ["-created_at"], + "abstract": False, + }, + ), + ] diff --git a/backend/user/migrations/0002_alter_bidder_bidder_number_alter_bidder_company_name.py b/backend/user/migrations/0002_alter_bidder_bidder_number_alter_bidder_company_name.py new file mode 100644 index 0000000..e9b86cb --- /dev/null +++ b/backend/user/migrations/0002_alter_bidder_bidder_number_alter_bidder_company_name.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.6 on 2023-11-24 06:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("user", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="bidder", + name="bidder_number", + field=models.IntegerField(blank=True, unique=True), + ), + migrations.AlterField( + model_name="bidder", + name="company_name", + field=models.CharField(blank=True, max_length=150, null=True), + ), + ] diff --git a/backend/user/migrations/__init__.py b/backend/user/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/user/models.py b/backend/user/models.py index 2b2330a..d259e87 100644 --- a/backend/user/models.py +++ b/backend/user/models.py @@ -8,7 +8,6 @@ # Create your models here. class Admin(MainModel): email = models.CharField(max_length=150, null=False) - password = models.CharField(max_length=50, null=False) first_name = models.CharField(max_length=150, null=False) last_name = models.CharField(max_length=150, null=False) permission_level = models.IntegerField(default=0) @@ -19,11 +18,10 @@ def __str__(self): class Bidder(MainModel): email = models.CharField(max_length=150, null=False) - password = models.CharField(max_length=50, null=False) first_name = models.CharField(max_length=150, null=False) last_name = models.CharField(max_length=150, null=False) - company_name = models.CharField(max_length=150) - bidder_number = models.IntegerField(unique=True, null=False) + company_name = models.CharField(max_length=150, blank=True, null=True) + bidder_number = models.IntegerField(unique=True, blank=True, null=False) is_verified = models.BooleanField(default=False) is_blacklisted = models.BooleanField(default=False) diff --git a/backend/user/serializers.py b/backend/user/serializers.py new file mode 100644 index 0000000..0e393ef --- /dev/null +++ b/backend/user/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from .models import Bidder + + +class BidderSerializer(serializers.ModelSerializer): + class Meta: + model = Bidder + fields = "__all__" + + +class BidderVerifiedSerializer(serializers.ModelSerializer): + class Meta: + model = Bidder + fields = ["id", "is_verified"] + + +class BidderBlacklistedSerializer(serializers.ModelSerializer): + class Meta: + model = Bidder + fields = ["id", "is_blacklisted"] diff --git a/backend/user/urls.py b/backend/user/urls.py new file mode 100644 index 0000000..4f2ec9f --- /dev/null +++ b/backend/user/urls.py @@ -0,0 +1,23 @@ +from django.contrib import admin +from django.urls import include, path + +from .views import ( + BidderBlacklistApiView, BidderDetailApiView, BidderListApiView, + BidderVerifyApiView) + +urlpatterns = [ + path("bidders/", BidderListApiView.as_view(), name="bidder-list"), + path( + "bidders//", BidderDetailApiView.as_view(), name="bidder-detail" + ), + path( + "bidders//verify", + BidderVerifyApiView.as_view(), + name="bidder-verify", + ), + path( + "bidders//blacklist", + BidderBlacklistApiView.as_view(), + name="bidder-blacklist", + ), +] diff --git a/backend/user/views.py b/backend/user/views.py index 91ea44a..d86b2c2 100644 --- a/backend/user/views.py +++ b/backend/user/views.py @@ -1,3 +1,98 @@ -from django.shortcuts import render +from django.shortcuts import get_object_or_404 +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView -# Create your views here. +from .models import Bidder +from .serializers import ( + BidderBlacklistedSerializer, BidderSerializer, BidderVerifiedSerializer) + + +class BidderListApiView(APIView): + def get(self, request): + """ + Return a list of all bidders. + """ + bidders = Bidder.objects.all() + serializer = BidderSerializer(bidders, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + def post(self, request): + """ + Create a new bidder. + """ + serializer = BidderSerializer(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 BidderDetailApiView(APIView): + def get(self, request, bidder_id): + """ + Return a single bidder. + """ + bidder = get_object_or_404(Bidder, id=bidder_id) + serializer = BidderSerializer(bidder) + return Response(serializer.data, status=status.HTTP_200_OK) + + def put(self, request, bidder_id): + """ + Update a single bidder. + """ + bidder = get_object_or_404(Bidder, id=bidder_id) + serializer = BidderSerializer(bidder, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, bidder_id): + """ + Delete a single bidder. + """ + # TODO: User JWT Token to check that admin is making this request + + bidder = get_object_or_404(Bidder, id=bidder_id) + bidder.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class BidderVerifyApiView(APIView): + def put(self, request, bidder_id): + # TODO: User JWT Token to check that admin is making this request + if "is_verified" not in request.data: + return Response( + {"error": "is_verified field is required."}, + status=status.HTTP_400_BAD_REQUEST, + ) + + bidder = get_object_or_404(Bidder, id=bidder_id) + + serializer = BidderVerifiedSerializer(bidder, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class BidderBlacklistApiView(APIView): + def put(self, request, bidder_id): + # TODO: User JWT Token to check that admin is making this request + if "is_blacklisted" not in request.data: + return Response( + {"error": "is_blacklisted field is required."}, + status=status.HTTP_400_BAD_REQUEST, + ) + + bidder = get_object_or_404(Bidder, id=bidder_id) + + serializer = BidderBlacklistedSerializer( + bidder, data=request.data, partial=True + ) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/backend/vehicle/views.py b/backend/vehicle/views.py index ab62079..e2f7b44 100644 --- a/backend/vehicle/views.py +++ b/backend/vehicle/views.py @@ -1,9 +1,9 @@ from datetime import datetime from rest_framework import generics, status +from rest_framework.generics import get_object_or_404 from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework.generics import get_object_or_404 from .models import ( Brand, Equipment, Supplier, Trailer, Type, UnitImage, Vehicle) From 3ca2e365044b8e03c800125951c19c6afb17ea16 Mon Sep 17 00:00:00 2001 From: Lance Tan Date: Thu, 23 Nov 2023 23:47:37 -0800 Subject: [PATCH 2/2] Create admin endpoints --- backend/user/serializers.py | 8 +++++- backend/user/urls.py | 6 ++-- backend/user/views.py | 56 +++++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/backend/user/serializers.py b/backend/user/serializers.py index 0e393ef..c277c91 100644 --- a/backend/user/serializers.py +++ b/backend/user/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Bidder +from .models import Admin, Bidder class BidderSerializer(serializers.ModelSerializer): @@ -19,3 +19,9 @@ class BidderBlacklistedSerializer(serializers.ModelSerializer): class Meta: model = Bidder fields = ["id", "is_blacklisted"] + + +class AdminSerializer(serializers.ModelSerializer): + class Meta: + model = Admin + fields = "__all__" diff --git a/backend/user/urls.py b/backend/user/urls.py index 4f2ec9f..f0bcd68 100644 --- a/backend/user/urls.py +++ b/backend/user/urls.py @@ -2,8 +2,8 @@ from django.urls import include, path from .views import ( - BidderBlacklistApiView, BidderDetailApiView, BidderListApiView, - BidderVerifyApiView) + AdminDetailApiView, AdminListApiView, BidderBlacklistApiView, + BidderDetailApiView, BidderListApiView, BidderVerifyApiView) urlpatterns = [ path("bidders/", BidderListApiView.as_view(), name="bidder-list"), @@ -20,4 +20,6 @@ BidderBlacklistApiView.as_view(), name="bidder-blacklist", ), + path("admins/", AdminListApiView.as_view(), name="admin-list"), + path("admins//", AdminDetailApiView.as_view(), name="admin-detail"), ] diff --git a/backend/user/views.py b/backend/user/views.py index d86b2c2..a71782c 100644 --- a/backend/user/views.py +++ b/backend/user/views.py @@ -3,9 +3,10 @@ from rest_framework.response import Response from rest_framework.views import APIView -from .models import Bidder +from .models import Admin, Bidder from .serializers import ( - BidderBlacklistedSerializer, BidderSerializer, BidderVerifiedSerializer) + AdminSerializer, BidderBlacklistedSerializer, BidderSerializer, + BidderVerifiedSerializer) class BidderListApiView(APIView): @@ -96,3 +97,54 @@ def put(self, request, bidder_id): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class AdminListApiView(APIView): + def get(self, request): + """ + Return a list of all admins. + """ + admins = Admin.objects.all() + serializer = AdminSerializer(admins, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + def post(self, request): + """ + Create a new admin. + """ + serializer = AdminSerializer(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 AdminDetailApiView(APIView): + def get(self, request, admin_id): + """ + Return a single admin. + """ + admin = get_object_or_404(Admin, id=admin_id) + serializer = AdminSerializer(admin) + return Response(serializer.data, status=status.HTTP_200_OK) + + def put(self, request, admin_id): + """ + Update a single admin. + """ + admin = get_object_or_404(Admin, id=admin_id) + serializer = AdminSerializer(admin, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, admin_id): + """ + Delete a single admin. + """ + admin = get_object_or_404(Admin, id=admin_id) + admin.delete() + return Response(status=status.HTTP_204_NO_CONTENT)