From 410dd8c2238252493f86f73441349da6b6916c6c Mon Sep 17 00:00:00 2001 From: Viggo de Vries Date: Thu, 18 Apr 2024 13:23:12 +0200 Subject: [PATCH] Add category bulk admin api --- oscarapi/urls.py | 3 +++ oscarapi/utils/categories.py | 35 +++++++++++++++++++++++++++++++++ oscarapi/views/admin/product.py | 13 ++++++++++++ oscarapi/views/root.py | 1 + 4 files changed, 52 insertions(+) diff --git a/oscarapi/urls.py b/oscarapi/urls.py index 01f68868..cbf3b829 100644 --- a/oscarapi/urls.py +++ b/oscarapi/urls.py @@ -114,6 +114,7 @@ AttributeOptionGroupAdminDetail, CategoryAdminList, CategoryAdminDetail, + CategoryBulkAdminApi, ) = get_api_classes( "views.admin.product", [ @@ -127,6 +128,7 @@ "AttributeOptionGroupAdminDetail", "CategoryAdminList", "CategoryAdminDetail", + "CategoryBulkAdminApi", ], ) @@ -204,6 +206,7 @@ path("ranges//", RangeDetail.as_view(), name="range-detail"), path("categories/", CategoryList.as_view(), name="category-list"), path("categories//", CategoryDetail.as_view(), name="category-detail"), + path("categories-bulk/", CategoryBulkAdminApi.as_view(), name="admin-category-bulk"), re_path( "^categories/(?P.*)/$", CategoryList.as_view(), diff --git a/oscarapi/utils/categories.py b/oscarapi/utils/categories.py index 539b7d6c..8b30ca0a 100644 --- a/oscarapi/utils/categories.py +++ b/oscarapi/utils/categories.py @@ -71,3 +71,38 @@ def find_from_full_slug(breadcrumb_str, separator="/"): category_names = [x.strip() for x in breadcrumb_str.split(separator)] categories = create_from_sequence(category_names, False) return categories[-1] + + + +def upsert_categories(data, parent_category=None): + if parent_category is None: + # Starting from root, we want the first category in the root + sibling = Category.get_first_root_node() + else: + # We are further down the category tree, we want to get the first child from the parent + sibling = parent_category.get_first_child() + + for cat in data: + children = cat.pop("children", None) + + try: + category = Category.objects.get(code=cat["data"]["code"]) + except Category.DoesNotExist: + # Category with code does not exist, create it on the root + category = Category.add_root(**cat["data"]) + + if sibling is not None: + if category.pk != sibling.pk: + # Move the category to the right of the sibling + category.move(sibling, pos="right") + elif parent_category is not None: + if category.get_parent().pk != parent_category.pk: + # Move the category as the first child under the parent category since we have not sibling + category.move(parent_category, pos="first-child") + + # The category is now the sibling, new categories will be moved to the right of this category + sibling = category + + if children: + # Add children under this category + upsert_categories(children, parent_category=category) \ No newline at end of file diff --git a/oscarapi/views/admin/product.py b/oscarapi/views/admin/product.py index b54b39c3..ce64b029 100644 --- a/oscarapi/views/admin/product.py +++ b/oscarapi/views/admin/product.py @@ -2,10 +2,13 @@ from django.http import Http404 from rest_framework import generics from rest_framework.exceptions import NotFound +from rest_framework.views import APIView +from rest_framework.response import Response from oscar.core.loading import get_model from oscarapi.utils.loading import get_api_classes, get_api_class from oscarapi.utils.exists import construct_id_filter +from oscarapi.utils.categories import upsert_categories APIAdminPermission = get_api_class("permissions", "APIAdminPermission") ProductAttributeSerializer, AttributeOptionGroupSerializer = get_api_classes( @@ -140,3 +143,13 @@ class CategoryAdminDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Category.objects.all() serializer_class = AdminCategorySerializer permission_classes = (APIAdminPermission,) + + +class CategoryBulkAdminApi(APIView): + def get(self, request, format=None): + return Response(Category.dump_bulk(keep_ids=False)) + + def post(self, request): + upsert_categories(request.data) + + return self.get(request) diff --git a/oscarapi/views/root.py b/oscarapi/views/root.py index ed8a6b1a..002e08d2 100644 --- a/oscarapi/views/root.py +++ b/oscarapi/views/root.py @@ -37,6 +37,7 @@ def ADMIN_APIS(r, f): ("productclasses", reverse("admin-productclass-list", request=r, format=f)), ("products", reverse("admin-product-list", request=r, format=f)), ("categories", reverse("admin-category-list", request=r, format=f)), + ("categories-bulk", reverse("admin-category-bulk", request=r, format=f)), ("orders", reverse("admin-order-list", request=r, format=f)), ("partners", reverse("admin-partner-list", request=r, format=f)), ("users", reverse("admin-user-list", request=r, format=f)),