From a8b9b7380af112235faf62425c99c1686f435286 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:13:03 +0300 Subject: [PATCH 01/13] Remove IDE specific configurations files --- .idea/.gitignore | 8 - .idea/03-commerce.iml | 29 -- .idea/dataSources.xml | 17 - .idea/dbnavigator.xml | 456 ------------------ .idea/inspectionProfiles/Project_Default.xml | 52 -- .../inspectionProfiles/profiles_settings.xml | 6 - .idea/misc.xml | 4 - .idea/modules.xml | 8 - .../1e9075f5bf079c01ef2c910709e91a497d262080 | 0 .../3899eaa57c40eb771c98133213ba36b6448c9fff | 0 .../496a238a6afa168dbaf6efd37bb459331589579c | 0 .../5672f685b93c26153a807ef6a52ff2a42f198564 | 0 .../597ed58946079f795070145abd2ba40aaf51a0ae | 0 .../7a4aaa54a3efb112f8e2592ed1507e33ab6a7b8c | 0 .../7a7d33b09c54ec66d8355befd1b7bba3f2dcb442 | 0 .../7bc8a653bcb2d639a49932a5ceac337f728844b4 | 0 .../7c4c5de0ae6801f08fa7c742af850c6198fdb35d | 0 .../816a718040e81705eecf3d2ee5661e3df09ee75b | 0 .../b81cf84376ffae4f5d23a7f977567a52e49d4e8c | 0 .../ea3c42abe4941ad1241819c1d6fbf5bb7bd659be | 0 .../f2bd2292f6ef3fccb4e29b9f652489934d9ddf07 | 0 .idea/sonarlint/issuestore/index.pb | 40 -- .idea/vcs.xml | 6 - 23 files changed, 626 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/03-commerce.iml delete mode 100644 .idea/dataSources.xml delete mode 100644 .idea/dbnavigator.xml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/sonarlint/issuestore/1/e/1e9075f5bf079c01ef2c910709e91a497d262080 delete mode 100644 .idea/sonarlint/issuestore/3/8/3899eaa57c40eb771c98133213ba36b6448c9fff delete mode 100644 .idea/sonarlint/issuestore/4/9/496a238a6afa168dbaf6efd37bb459331589579c delete mode 100644 .idea/sonarlint/issuestore/5/6/5672f685b93c26153a807ef6a52ff2a42f198564 delete mode 100644 .idea/sonarlint/issuestore/5/9/597ed58946079f795070145abd2ba40aaf51a0ae delete mode 100644 .idea/sonarlint/issuestore/7/a/7a4aaa54a3efb112f8e2592ed1507e33ab6a7b8c delete mode 100644 .idea/sonarlint/issuestore/7/a/7a7d33b09c54ec66d8355befd1b7bba3f2dcb442 delete mode 100644 .idea/sonarlint/issuestore/7/b/7bc8a653bcb2d639a49932a5ceac337f728844b4 delete mode 100644 .idea/sonarlint/issuestore/7/c/7c4c5de0ae6801f08fa7c742af850c6198fdb35d delete mode 100644 .idea/sonarlint/issuestore/8/1/816a718040e81705eecf3d2ee5661e3df09ee75b delete mode 100644 .idea/sonarlint/issuestore/b/8/b81cf84376ffae4f5d23a7f977567a52e49d4e8c delete mode 100644 .idea/sonarlint/issuestore/e/a/ea3c42abe4941ad1241819c1d6fbf5bb7bd659be delete mode 100644 .idea/sonarlint/issuestore/f/2/f2bd2292f6ef3fccb4e29b9f652489934d9ddf07 delete mode 100644 .idea/sonarlint/issuestore/index.pb delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/03-commerce.iml b/.idea/03-commerce.iml deleted file mode 100644 index f602895..0000000 --- a/.idea/03-commerce.iml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index f1f4a08..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - sqlite.xerial - true - org.sqlite.JDBC - jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 - $ProjectFileDir$ - - - file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.34.0/sqlite-jdbc-3.34.0.jar - - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index 86ee15e..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,456 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 6314360..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 0c95c56..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 0de4b85..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/1/e/1e9075f5bf079c01ef2c910709e91a497d262080 b/.idea/sonarlint/issuestore/1/e/1e9075f5bf079c01ef2c910709e91a497d262080 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/3/8/3899eaa57c40eb771c98133213ba36b6448c9fff b/.idea/sonarlint/issuestore/3/8/3899eaa57c40eb771c98133213ba36b6448c9fff deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/4/9/496a238a6afa168dbaf6efd37bb459331589579c b/.idea/sonarlint/issuestore/4/9/496a238a6afa168dbaf6efd37bb459331589579c deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/5/6/5672f685b93c26153a807ef6a52ff2a42f198564 b/.idea/sonarlint/issuestore/5/6/5672f685b93c26153a807ef6a52ff2a42f198564 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/5/9/597ed58946079f795070145abd2ba40aaf51a0ae b/.idea/sonarlint/issuestore/5/9/597ed58946079f795070145abd2ba40aaf51a0ae deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/7/a/7a4aaa54a3efb112f8e2592ed1507e33ab6a7b8c b/.idea/sonarlint/issuestore/7/a/7a4aaa54a3efb112f8e2592ed1507e33ab6a7b8c deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/7/a/7a7d33b09c54ec66d8355befd1b7bba3f2dcb442 b/.idea/sonarlint/issuestore/7/a/7a7d33b09c54ec66d8355befd1b7bba3f2dcb442 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/7/b/7bc8a653bcb2d639a49932a5ceac337f728844b4 b/.idea/sonarlint/issuestore/7/b/7bc8a653bcb2d639a49932a5ceac337f728844b4 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/7/c/7c4c5de0ae6801f08fa7c742af850c6198fdb35d b/.idea/sonarlint/issuestore/7/c/7c4c5de0ae6801f08fa7c742af850c6198fdb35d deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/8/1/816a718040e81705eecf3d2ee5661e3df09ee75b b/.idea/sonarlint/issuestore/8/1/816a718040e81705eecf3d2ee5661e3df09ee75b deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/b/8/b81cf84376ffae4f5d23a7f977567a52e49d4e8c b/.idea/sonarlint/issuestore/b/8/b81cf84376ffae4f5d23a7f977567a52e49d4e8c deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/e/a/ea3c42abe4941ad1241819c1d6fbf5bb7bd659be b/.idea/sonarlint/issuestore/e/a/ea3c42abe4941ad1241819c1d6fbf5bb7bd659be deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/f/2/f2bd2292f6ef3fccb4e29b9f652489934d9ddf07 b/.idea/sonarlint/issuestore/f/2/f2bd2292f6ef3fccb4e29b9f652489934d9ddf07 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/issuestore/index.pb b/.idea/sonarlint/issuestore/index.pb deleted file mode 100644 index 690c582..0000000 --- a/.idea/sonarlint/issuestore/index.pb +++ /dev/null @@ -1,40 +0,0 @@ - -S -#commerce/migrations/0001_initial.py,5/6/5672f685b93c26153a807ef6a52ff2a42f198564 -B -config/__init__.py,7/c/7c4c5de0ae6801f08fa7c742af850c6198fdb35d -C -account/__init__.py,7/a/7a7d33b09c54ec66d8355befd1b7bba3f2dcb442 -D -commerce/__init__.py,f/2/f2bd2292f6ef3fccb4e29b9f652489934d9ddf07 -> -config/wsgi.py,7/a/7a4aaa54a3efb112f8e2592ed1507e33ab6a7b8c -> -config/asgi.py,5/9/597ed58946079f795070145abd2ba40aaf51a0ae -\ -,.idea/inspectionProfiles/Project_Default.xml,4/9/496a238a6afa168dbaf6efd37bb459331589579c -@ -account/tests.py,8/1/816a718040e81705eecf3d2ee5661e3df09ee75b -^ -..idea/inspectionProfiles/profiles_settings.xml,1/e/1e9075f5bf079c01ef2c910709e91a497d262080 -? -account/apps.py,3/8/3899eaa57c40eb771c98133213ba36b6448c9fff -N -account/migrations/__init__.py,7/b/7bc8a653bcb2d639a49932a5ceac337f728844b4 -@ -commerce/apps.py,e/a/ea3c42abe4941ad1241819c1d6fbf5bb7bd659be -O -commerce/migrations/__init__.py,b/8/b81cf84376ffae4f5d23a7f977567a52e49d4e8c -@ -requirements.txt,1/9/19359a61ae2446b51b549167b014da2fcf265768 -A -commerce/tests.py,5/2/52ea416cfb7f2a70c29e2ed02817ad03d3de8885 -: - -.gitignore,a/5/a5cc2925ca8258af241be7e5b0381edf30266302 -A -commerce/admin.py,d/7/d7369e273d90449ac8ca98014a010a921d984597 -^ -.commerce/migrations/0002_auto_20211027_1637.py,d/a/daa0931328d2da3ea0d7525a016a5059103dbb53 -9 - manage.py,3/1/3156ad13e4d695cd526bbb7b031016ecba842270 \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 4f9a1cd9af200dde28c71a58b49d17e027e135c7 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:14:24 +0300 Subject: [PATCH 02/13] Add Schemas for the `address` and `order` endpoints --- commerce/schemas.py | 54 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/commerce/schemas.py b/commerce/schemas.py index 5d68396..4f38238 100644 --- a/commerce/schemas.py +++ b/commerce/schemas.py @@ -42,10 +42,10 @@ class CategoryOut(UUIDSchema): class ProductOut(ModelSchema): - vendor: VendorOut + category: CategoryOut label: LabelOut merchant: MerchantOut - category: CategoryOut + vendor: VendorOut class Config: model = Product @@ -55,11 +55,10 @@ class Config: 'qty', 'price', 'discounted_price', - 'vendor', 'category', 'label', 'merchant', - + 'vendor', ] @@ -75,11 +74,31 @@ class CitiesOut(CitySchema, UUIDSchema): pass +class AddressSchema(Schema): + # user: + work_address: bool = False + address1: str + address2: str = None + phone: str + +class AddressesCreate(AddressSchema): + user_id: str + city_id: UUID4 + + +class AddressesUpdate(AddressSchema): + city_id: UUID4 + + +class AddressesOut(AddressSchema, UUIDSchema): + city: CitiesOut + + class ItemSchema(Schema): # user: - product: ProductOut item_qty: int ordered: bool + product: ProductOut class ItemCreate(Schema): @@ -87,7 +106,30 @@ class ItemCreate(Schema): item_qty: int -class ItemOut(UUIDSchema, ItemSchema): +class ItemOut(ItemSchema, UUIDSchema): pass +class OrderStatusOut(Schema): + title: str + + +class UserOut(Schema): + username: str + + +class OrderSchema(Schema): + items: List[ItemSchema] + status: OrderStatusOut + address: AddressesOut + order_total: float + ordered: bool + user: UserOut + ref_code: str + note: str + + +class OrderCreate(Schema): + items: List[UUID4] + address: UUID4 + note: str From de71bd45f1a7506db01a0ef647d9af7555f56ca0 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:15:32 +0300 Subject: [PATCH 03/13] Fix plural string for `address` and `order_status` models --- commerce/models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/commerce/models.py b/commerce/models.py index b0446b8..e81c3c7 100644 --- a/commerce/models.py +++ b/commerce/models.py @@ -98,6 +98,10 @@ class OrderStatus(Entity): ]) is_default = models.BooleanField('is default') + class Meta: + verbose_name = 'order status' + verbose_name_plural = 'order statuses' + def __str__(self): return self.title @@ -206,5 +210,9 @@ class Address(Entity): city = models.ForeignKey(City, related_name='addresses', on_delete=models.CASCADE) phone = models.CharField('phone', max_length=255) + class Meta: + verbose_name = 'address' + verbose_name_plural = 'addresses' + def __str__(self): return f'{self.user.first_name} - {self.address1} - {self.address2} - {self.phone}' From 40fe42b773b6bbbb77caeb6cee8cde4d49be3782 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:17:39 +0300 Subject: [PATCH 04/13] Code clean-ups and minor formatting improvements --- commerce/controllers.py | 65 +++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/commerce/controllers.py b/commerce/controllers.py index a8a551a..6339b26 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -9,8 +9,11 @@ from pydantic import UUID4 from account.authorization import GlobalAuth -from commerce.models import Product, Category, City, Vendor, Item, Order, OrderStatus -from commerce.schemas import ProductOut, CitiesOut, CitySchema, VendorOut, ItemOut, ItemSchema, ItemCreate +from commerce.models import Product, Category, City, Vendor, Item, Address\ + ,Order, OrderStatus +from commerce.schemas import MessageOut, ProductOut, CitiesOut, CitySchema \ + , VendorOut, ItemOut, ItemSchema, ItemCreate, CategoryOut, AddressSchema\ + , AddressesOut , AddressesCreate, AddressesUpdate, OrderSchema, OrderCreate from config.utils.schemas import MessageOut products_controller = Router(tags=['products']) @@ -22,7 +25,12 @@ @vendor_controller.get('', response=List[VendorOut]) def list_vendors(request): - return Vendor.objects.all() + vendor_set = Vendor.objects.all() + + if vendor_set: + return vendor_set + + return 400, {'detail': 'No categories found'} @products_controller.get('', response={ @@ -36,26 +44,26 @@ def list_products( price_to: int = None, vendor=None, ): - products_qs = Product.objects.filter(is_active=True).select_related('merchant', 'vendor', 'category', 'label') + products_set = Product.objects.filter(is_active=True).select_related('merchant', 'vendor', 'category', 'label') - if not products_qs: + if not products_set: return 404, {'detail': 'No products found'} if q: - products_qs = products_qs.filter( + products_set = products_set.filter( Q(name__icontains=q) | Q(description__icontains=q) ) if price_from: - products_qs = products_qs.filter(discounted_price__gte=price_from) + products_set = products_set.filter(discounted_price__gte=price_from) if price_to: - products_qs = products_qs.filter(discounted_price__lte=price_to) + products_set = products_set.filter(discounted_price__lte=price_to) if vendor: - products_qs = products_qs.filter(vendor_id=vendor) + products_set = products_set.filter(vendor_id=vendor) - return products_qs + return products_set """ @@ -114,14 +122,17 @@ def list_products( """ -@address_controller.get('') -def list_addresses(request): - pass +@products_controller.get('categories', response={ + 200: List[CategoryOut], + 404: MessageOut +}) +def list_categories(request): + category_set = Category.objects.all() + if category_set: + return category_set -# @products_controller.get('categories', response=List[CategoryOut]) -# def list_categories(request): -# return Category.objects.all() + return 404, {'detail': 'No categories found'} @address_controller.get('cities', response={ @@ -129,10 +140,10 @@ def list_addresses(request): 404: MessageOut }) def list_cities(request): - cities_qs = City.objects.all() + city_set = City.objects.all() - if cities_qs: - return cities_qs + if city_set: + return city_set return 404, {'detail': 'No cities found'} @@ -190,7 +201,7 @@ def view_cart(request): @order_controller.post('add-to-cart', response={ 200: MessageOut, - # 400: MessageOut + 400: MessageOut }) def add_update_cart(request, item_in: ItemCreate): try: @@ -206,17 +217,27 @@ def add_update_cart(request, item_in: ItemCreate): @order_controller.post('item/{id}/reduce-quantity', response={ 200: MessageOut, }) -def reduce_item_quantity(request, id: UUID4): +def reduce_item_quantity(request, id: UUID4, qty: int = 1): item = get_object_or_404(Item, id=id, user=User.objects.first()) if item.item_qty <= 1: item.delete() return 200, {'detail': 'Item deleted!'} - item.item_qty -= 1 + item.item_qty -= qty item.save() return 200, {'detail': 'Item quantity reduced successfully!'} +@order_controller.post('item/{id}/increase-quantity', response={ + 200: MessageOut, +}) +def increase_item_quantity(request, id: UUID4, qty: int = 1): + item = get_object_or_404(Item, id=id, user=User.objects.first()) + item.item_qty += qty + item.save() + return 200, {'detail': 'Item quantity increased successfully!'} + + @order_controller.delete('item/{id}', response={ 204: MessageOut }) From b2f7ee7061fd2ca288c24e6bd19a0dbf9cb926d7 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:18:08 +0300 Subject: [PATCH 05/13] Remove unnecessary whitespace --- account/admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/account/admin.py b/account/admin.py index 8d07a97..c10a1bb 100644 --- a/account/admin.py +++ b/account/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin - from account.forms import UserAdminChangeForm, UserAdminCreationForm from account.models import User From d463aff0a39bf2766fddefe1a9774a406a7da0b6 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:18:49 +0300 Subject: [PATCH 06/13] Implement CRUD operations for the `address` endpoint --- commerce/controllers.py | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/commerce/controllers.py b/commerce/controllers.py index 6339b26..8fd1f03 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -186,6 +186,58 @@ def delete_city(request, id: UUID4): return 204, {'detail': ''} +@address_controller.get('', response={ + 200: List[AddressesOut], + 404: MessageOut +}) +def list_addresses(request): + address_set = Address.objects.all() + + if address_set: + return address_set + + return 404, {'detail': 'No addresses found'} + + +@address_controller.get('{id}', response={ + 200: AddressesOut, + 404: MessageOut +}) +def retrieve_address(request, id: UUID4): + return get_object_or_404(Address, id=id) + + +@address_controller.post('', response={ + 201: AddressesOut, + 400: MessageOut +}) +def create_address(request, address_in: AddressesCreate): + address = Address(**address_in.dict()) + address.save() + return 201, address + + +@address_controller.put('{id}', response={ + 200: AddressesOut, + 400: MessageOut +}) +def update_address(request, id: UUID4, address_in: AddressesUpdate): + address = get_object_or_404(Address, id=id) + for attr, value in address_in.dict().items(): + setattr(address, attr, value) + address.save() + return 200, address + + +@address_controller.delete('{id}', response={ + 204: MessageOut +}) +def delete_address(request, id: UUID4): + address = get_object_or_404(Address, id=id) + address.delete() + return 204, {'detail': ''} + + @order_controller.get('cart', response={ 200: List[ItemOut], 404: MessageOut From a6ecf63f622193c59acc585c0af3e04e52c8a235 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:22:12 +0300 Subject: [PATCH 07/13] Implement `create_order` endpoint --- commerce/controllers.py | 75 +++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/commerce/controllers.py b/commerce/controllers.py index 8fd1f03..5e3a624 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -300,27 +300,60 @@ def delete_item(request, id: UUID4): return 204, {'detail': 'Item deleted!'} -def generate_ref_code(): - return ''.join(random.sample(string.ascii_letters + string.digits, 6)) - - -@order_controller.post('create-order', auth=GlobalAuth(), response=MessageOut) -def create_order(request): - ''' - * add items and mark (ordered) field as True - * add ref_number - * add NEW status - * calculate the total - ''' - - order_qs = Order.objects.create( - user=User.objects.first(), - status=OrderStatus.objects.get(is_default=True), - ref_code=generate_ref_code(), - ordered=False, - ) - - user_items = Item.objects.filter(user=User.objects.first()).filter(ordered=False) +@order_controller.get('', response={ + 200: List[OrderSchema], + 404: MessageOut +}) +def list_orders(request, ordered: bool = False): + order_set = Order.objects.filter(user=User.objects.first()) + if not ordered: + order_set = order_set.filter(ordered=ordered) + if not order_set: + return 404, {'detail': 'no orders found'} + return order_set + + +def gen_code(size=6): + chars = string.ascii_letters + string.digits + code = ''.join(random.choice(chars) for _ in range(size)) + return code + + +@order_controller.post('create-order', response={ + 200: MessageOut +}) +def create_order(request, item_in: OrderCreate): + user = User.objects.first() + items = Item.objects.filter(id__in=item_in.items) + current_order = Order.objects.filter(user=user, ordered=False) + + if current_order.exists(): + new_order = current_order.first() + for i in items: + i.ordered = True + i.save() + new_order.items.add(*items) + new_order.total = new_order.order_total + new_order.save() + return 200, {'detail': 'updated the order successfully.'} + else: + for i in items: + i.ordered = True + i.save() + status = OrderStatus.objects.get(title="NEW") + new_order = Order.objects.create( + user=user, + status=status, + address=item_in.address, + ordered=False, + ref_code=gen_code(), + note=item_in.note + ) + new_order.items.add(*items) + new_order.total = new_order.order_total + new_order.save() + return 200, {'detail': 'created the order successfully.'} + order_qs.items.add(*user_items) order_qs.total = order_qs.order_total From 82a302b0261f10ac31cecea65bedfac5dc22069e Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:22:34 +0300 Subject: [PATCH 08/13] Implement `checkout_order` endpoint --- commerce/controllers.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/commerce/controllers.py b/commerce/controllers.py index 5e3a624..873218c 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -355,9 +355,19 @@ def create_order(request, item_in: OrderCreate): return 200, {'detail': 'created the order successfully.'} - order_qs.items.add(*user_items) - order_qs.total = order_qs.order_total - user_items.update(ordered=True) - order_qs.save() - - return {'detail': 'order created successfully'} +@order_controller.post('checkout', response={ + 200: MessageOut, + 404: MessageOut +}) +def checkout_order(request): + try: + order_set = Order.objects.get(ordered=False, user=User.objects.first()) + except Order.DoesNotExist: + return 404, {'detail': 'No order exists'} + + for item in order_set.items.all(): + item.product.qty -= item.item_qty + item.product.save() + order_set.ordered = True + order_set.save() + return 200, {'detail': 'checkout successful'} From e794091e710af267aa7d67ebfb0018af1a2fe3a6 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 10:37:22 +0300 Subject: [PATCH 09/13] Remove unnecessary whitespace Remove unnecessary whitespace --- account/authorization.py | 1 - commerce/models.py | 3 +-- commerce/schemas.py | 7 +++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/account/authorization.py b/account/authorization.py index 661ada1..6be0abf 100644 --- a/account/authorization.py +++ b/account/authorization.py @@ -1,5 +1,4 @@ from datetime import timedelta - from django.conf import settings from django.contrib.auth import get_user_model from jose import jwt, JWTError diff --git a/commerce/models.py b/commerce/models.py index e81c3c7..cd60291 100644 --- a/commerce/models.py +++ b/commerce/models.py @@ -1,11 +1,10 @@ import uuid - from PIL import Image from django.contrib.auth import get_user_model from django.db import models - from config.utils.models import Entity + User = get_user_model() diff --git a/commerce/schemas.py b/commerce/schemas.py index 4f38238..9fa1120 100644 --- a/commerce/schemas.py +++ b/commerce/schemas.py @@ -7,15 +7,13 @@ from commerce.models import Product, Merchant - - - class UUIDSchema(Schema): id: UUID4 # ProductSchemaOut = create_schema(Product, depth=2) + class VendorOut(UUIDSchema): name: str image: str @@ -81,10 +79,11 @@ class AddressSchema(Schema): address2: str = None phone: str + class AddressesCreate(AddressSchema): user_id: str city_id: UUID4 - + class AddressesUpdate(AddressSchema): city_id: UUID4 From 3526f5b507ee57ee48be70d2e0d372d301c99713 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sat, 6 Nov 2021 15:27:40 +0300 Subject: [PATCH 10/13] Add `python-jose` to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 5d025cd..0d0635f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ pydantic==1.8.2 pytz==2021.3 sqlparse==0.4.2 typing-extensions==3.10.0.2 +python-jose==3.3.0 From c714e725fa4e94bfa302d59d8c2238afbf231a66 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sun, 7 Nov 2021 23:41:44 +0300 Subject: [PATCH 11/13] Fix formatting and minor whitespace warnings Fix formatting and minor whitespace warnings Fix formatting and minor whitespace warnings done --- account/authorization.py | 2 +- account/schemas.py | 3 +++ commerce/controllers.py | 21 +++++++++++---------- commerce/models.py | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/account/authorization.py b/account/authorization.py index 6be0abf..4ab7bdc 100644 --- a/account/authorization.py +++ b/account/authorization.py @@ -8,6 +8,7 @@ TIME_DELTA = timedelta(days=120) + class GlobalAuth(HttpBearer): def authenticate(self, request, token): try: @@ -23,4 +24,3 @@ def get_tokens_for_user(user): return { 'access': str(token), } - diff --git a/account/schemas.py b/account/schemas.py index 681457b..9338f5a 100644 --- a/account/schemas.py +++ b/account/schemas.py @@ -22,13 +22,16 @@ class AccountOut(Schema): company_name: str = None company_website: str = None + class TokenOut(Schema): access: str + class AuthOut(Schema): token: TokenOut account: AccountOut + class SigninSchema(Schema): email: EmailStr password: str diff --git a/commerce/controllers.py b/commerce/controllers.py index 873218c..3e7e481 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -9,11 +9,11 @@ from pydantic import UUID4 from account.authorization import GlobalAuth -from commerce.models import Product, Category, City, Vendor, Item, Address\ - ,Order, OrderStatus -from commerce.schemas import MessageOut, ProductOut, CitiesOut, CitySchema \ - , VendorOut, ItemOut, ItemSchema, ItemCreate, CategoryOut, AddressSchema\ - , AddressesOut , AddressesCreate, AddressesUpdate, OrderSchema, OrderCreate +from commerce.models import Product, Category, City, Vendor, Item, Address,\ + Order, OrderStatus +from commerce.schemas import ProductOut, CitiesOut, CitySchema, VendorOut,\ + ItemOut, ItemSchema, ItemCreate, CategoryOut, AddressSchema, AddressesOut,\ + AddressesCreate, AddressesUpdate, OrderSchema, OrderCreate from config.utils.schemas import MessageOut products_controller = Router(tags=['products']) @@ -23,6 +23,7 @@ User = get_user_model() + @vendor_controller.get('', response=List[VendorOut]) def list_vendors(request): vendor_set = Vendor.objects.all() @@ -38,11 +39,11 @@ def list_vendors(request): 404: MessageOut }) def list_products( - request, *, - q: str = None, - price_from: int = None, - price_to: int = None, - vendor=None, + request, *, + q: str = None, + price_from: int = None, + price_to: int = None, + vendor=None, ): products_set = Product.objects.filter(is_active=True).select_related('merchant', 'vendor', 'category', 'label') diff --git a/commerce/models.py b/commerce/models.py index cd60291..e128d92 100644 --- a/commerce/models.py +++ b/commerce/models.py @@ -117,7 +117,6 @@ class Category(Entity): image = models.ImageField('image', upload_to='category/') is_active = models.BooleanField('is active') - def __str__(self): if self.parent: return f'- {self.name}' @@ -131,6 +130,7 @@ class Meta: def children(self): return self.children + class Merchant(Entity): name = models.CharField('name', max_length=255) From 792b513f40e62f4134eedfcf6ec2a066341e4039 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sun, 7 Nov 2021 23:45:48 +0300 Subject: [PATCH 12/13] Implement authentication for `addresses` endpoint --- commerce/controllers.py | 19 ++++++++++--------- commerce/schemas.py | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/commerce/controllers.py b/commerce/controllers.py index 3e7e481..a035f78 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -187,12 +187,12 @@ def delete_city(request, id: UUID4): return 204, {'detail': ''} -@address_controller.get('', response={ +@address_controller.get('', auth=GlobalAuth(), response={ 200: List[AddressesOut], 404: MessageOut }) def list_addresses(request): - address_set = Address.objects.all() + address_set = Address.objects.filter(user=request.auth['pk']) if address_set: return address_set @@ -200,41 +200,42 @@ def list_addresses(request): return 404, {'detail': 'No addresses found'} -@address_controller.get('{id}', response={ +@address_controller.get('{id}', auth=GlobalAuth(), response={ 200: AddressesOut, 404: MessageOut }) def retrieve_address(request, id: UUID4): - return get_object_or_404(Address, id=id) + return get_object_or_404(Address, id=id, user=request.auth['pk']) -@address_controller.post('', response={ +@address_controller.post('', auth=GlobalAuth(), response={ 201: AddressesOut, 400: MessageOut }) def create_address(request, address_in: AddressesCreate): address = Address(**address_in.dict()) + address.user = request.auth['pk'] address.save() return 201, address -@address_controller.put('{id}', response={ +@address_controller.put('{id}', auth=GlobalAuth(), response={ 200: AddressesOut, 400: MessageOut }) def update_address(request, id: UUID4, address_in: AddressesUpdate): - address = get_object_or_404(Address, id=id) + address = get_object_or_404(Address, id=id, user=request.auth['pk']) for attr, value in address_in.dict().items(): setattr(address, attr, value) address.save() return 200, address -@address_controller.delete('{id}', response={ +@address_controller.delete('{id}', auth=GlobalAuth(), response={ 204: MessageOut }) def delete_address(request, id: UUID4): - address = get_object_or_404(Address, id=id) + address = get_object_or_404(Address, id=id, user=request.auth['pk']) address.delete() return 204, {'detail': ''} diff --git a/commerce/schemas.py b/commerce/schemas.py index 9fa1120..8526b77 100644 --- a/commerce/schemas.py +++ b/commerce/schemas.py @@ -81,7 +81,6 @@ class AddressSchema(Schema): class AddressesCreate(AddressSchema): - user_id: str city_id: UUID4 From 74a2419687cc558438d4c0ebcb1e91e61e82fa92 Mon Sep 17 00:00:00 2001 From: Aland <32212842+alandio@users.noreply.github.com> Date: Sun, 7 Nov 2021 23:55:58 +0300 Subject: [PATCH 13/13] Implement authentication for `order` endpoint --- commerce/controllers.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/commerce/controllers.py b/commerce/controllers.py index a035f78..0bcd60a 100644 --- a/commerce/controllers.py +++ b/commerce/controllers.py @@ -240,12 +240,12 @@ def delete_address(request, id: UUID4): return 204, {'detail': ''} -@order_controller.get('cart', response={ +@order_controller.get('cart', auth=GlobalAuth(), response={ 200: List[ItemOut], 404: MessageOut }) def view_cart(request): - cart_items = Item.objects.filter(user=User.objects.first(), ordered=False) + cart_items = Item.objects.filter(user=request.auth['pk'], ordered=False) if cart_items: return cart_items @@ -253,26 +253,26 @@ def view_cart(request): return 404, {'detail': 'Your cart is empty, go shop like crazy!'} -@order_controller.post('add-to-cart', response={ +@order_controller.post('add-to-cart', auth=GlobalAuth(), response={ 200: MessageOut, 400: MessageOut }) def add_update_cart(request, item_in: ItemCreate): try: - item = Item.objects.get(product_id=item_in.product_id, user=User.objects.first()) + item = Item.objects.get(product_id=item_in.product_id, user=request.auth['pk']) item.item_qty += 1 item.save() except Item.DoesNotExist: - Item.objects.create(**item_in.dict(), user=User.objects.first()) + Item.objects.create(**item_in.dict(), user=request.auth['pk']) return 200, {'detail': 'Added to cart successfully'} -@order_controller.post('item/{id}/reduce-quantity', response={ +@order_controller.post('item/{id}/reduce-quantity', auth=GlobalAuth(), response={ 200: MessageOut, }) def reduce_item_quantity(request, id: UUID4, qty: int = 1): - item = get_object_or_404(Item, id=id, user=User.objects.first()) + item = get_object_or_404(Item, id=id, user=request.auth['pk']) if item.item_qty <= 1: item.delete() return 200, {'detail': 'Item deleted!'} @@ -282,32 +282,32 @@ def reduce_item_quantity(request, id: UUID4, qty: int = 1): return 200, {'detail': 'Item quantity reduced successfully!'} -@order_controller.post('item/{id}/increase-quantity', response={ +@order_controller.post('item/{id}/increase-quantity', auth=GlobalAuth(), response={ 200: MessageOut, }) def increase_item_quantity(request, id: UUID4, qty: int = 1): - item = get_object_or_404(Item, id=id, user=User.objects.first()) + item = get_object_or_404(Item, id=id, user=request.auth['pk']) item.item_qty += qty item.save() return 200, {'detail': 'Item quantity increased successfully!'} -@order_controller.delete('item/{id}', response={ +@order_controller.delete('item/{id}', auth=GlobalAuth(), response={ 204: MessageOut }) def delete_item(request, id: UUID4): - item = get_object_or_404(Item, id=id, user=User.objects.first()) + item = get_object_or_404(Item, id=id, user=request.auth['pk']) item.delete() return 204, {'detail': 'Item deleted!'} -@order_controller.get('', response={ +@order_controller.get('', auth=GlobalAuth(), response={ 200: List[OrderSchema], 404: MessageOut }) def list_orders(request, ordered: bool = False): - order_set = Order.objects.filter(user=User.objects.first()) + order_set = Order.objects.filter(user=request.auth['pk']) if not ordered: order_set = order_set.filter(ordered=ordered) if not order_set: @@ -321,12 +321,12 @@ def gen_code(size=6): return code -@order_controller.post('create-order', response={ +@order_controller.post('create-order', auth=GlobalAuth(), response={ 200: MessageOut }) def create_order(request, item_in: OrderCreate): - user = User.objects.first() - items = Item.objects.filter(id__in=item_in.items) + user = User.objects.get(id=request.auth['pk']) + items = Item.objects.filter(id__in=item_in.items, user=request.auth['pk']) current_order = Order.objects.filter(user=user, ordered=False) if current_order.exists(): @@ -363,7 +363,7 @@ def create_order(request, item_in: OrderCreate): }) def checkout_order(request): try: - order_set = Order.objects.get(ordered=False, user=User.objects.first()) + order_set = Order.objects.get(ordered=False, user=request.auth['pk']) except Order.DoesNotExist: return 404, {'detail': 'No order exists'}