-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1360 from userlocalhost/feature/new_application/c…
…ategory Implement primitive model and API handlers for Category
- Loading branch information
Showing
40 changed files
with
1,133 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Register your models here. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
from rest_framework import serializers | ||
|
||
from category.models import Category | ||
from entity.models import Entity | ||
|
||
|
||
# We bordered the situation that ID parameter would be readonly via OpenAPI generate | ||
# when EntitySerializer, which is defined in the entity.api_v2.serializers, was specified. | ||
class EntitySerializer(serializers.ModelSerializer): | ||
id = serializers.IntegerField() | ||
|
||
class Meta: | ||
model = Entity | ||
fields = ["id", "name", "is_public"] | ||
|
||
|
||
class CategoryListSerializer(serializers.ModelSerializer): | ||
models = EntitySerializer(many=True) | ||
|
||
class Meta: | ||
model = Category | ||
fields = ["id", "name", "note", "models"] | ||
|
||
|
||
class CategoryCreateSerializer(serializers.ModelSerializer): | ||
id = serializers.IntegerField(required=False, read_only=True) | ||
models = EntitySerializer(many=True) | ||
|
||
class Meta: | ||
model = Category | ||
fields = ["id", "name", "note", "models"] | ||
|
||
def create(self, validated_data): | ||
# craete Category instance | ||
category = Category.objects.create( | ||
created_user=self.context["request"].user, | ||
**{k: v for (k, v) in validated_data.items() if k != "models"}, | ||
) | ||
|
||
# make relations created Category with specified Models | ||
for model in Entity.objects.filter( | ||
id__in=[x["id"] for x in validated_data.get("models", [])], is_active=True | ||
): | ||
model.categories.add(category) | ||
|
||
return category | ||
|
||
|
||
class CategoryUpdateSerializer(serializers.ModelSerializer): | ||
models = EntitySerializer(many=True) | ||
|
||
class Meta: | ||
model = Category | ||
fields = ["name", "note", "models"] | ||
|
||
def update(self, category: Category, validated_data): | ||
# name and note are updated | ||
updated_fields: list[str] = [] | ||
category_name = validated_data.get("name", category.name) | ||
if category_name != category.name: | ||
category.name = category_name | ||
updated_fields.append("name") | ||
category_note = validated_data.get("note", category.note) | ||
if category_note != category.note: | ||
category.note = category_note | ||
updated_fields.append("note") | ||
|
||
if len(updated_fields) > 0: | ||
category.save(update_fields=updated_fields) | ||
else: | ||
category.save_without_historical_record() | ||
|
||
curr_model_ids = [x.id for x in category.models.filter(is_active=True)] | ||
new_model_ids = [x["id"] for x in validated_data.get("models", [])] | ||
|
||
# remove models that are unselected from current ones | ||
removing_model_ids = list(set(curr_model_ids) - set(new_model_ids)) | ||
for model in Entity.objects.filter(id__in=removing_model_ids, is_active=True): | ||
model.categories.remove(category) | ||
|
||
# add new models that are added to current ones | ||
adding_model_ids = list(set(new_model_ids) - set(curr_model_ids)) | ||
for model in Entity.objects.filter(id__in=adding_model_ids, is_active=True): | ||
model.categories.add(category) | ||
|
||
return category |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.urls import path | ||
|
||
from . import views | ||
|
||
urlpatterns = [ | ||
path( | ||
"", | ||
views.CategoryAPI.as_view( | ||
{ | ||
"get": "list", | ||
"post": "create", | ||
} | ||
), | ||
), | ||
path( | ||
"<int:pk>/", | ||
views.CategoryAPI.as_view( | ||
{ | ||
"get": "retrieve", | ||
"put": "update", | ||
"delete": "destroy", | ||
} | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from django_filters.rest_framework import DjangoFilterBackend | ||
from rest_framework import filters, status, viewsets | ||
from rest_framework.pagination import LimitOffsetPagination | ||
from rest_framework.permissions import IsAuthenticated | ||
from rest_framework.request import Request | ||
from rest_framework.response import Response | ||
|
||
from airone.lib.acl import ACLType | ||
from airone.lib.drf import ObjectNotExistsError | ||
from category.api_v2.serializers import ( | ||
CategoryCreateSerializer, | ||
CategoryListSerializer, | ||
CategoryUpdateSerializer, | ||
) | ||
from category.models import Category | ||
from entity.api_v2.views import EntityPermission | ||
|
||
|
||
class CategoryAPI(viewsets.ModelViewSet): | ||
pagination_class = LimitOffsetPagination | ||
permission_classes = [IsAuthenticated & EntityPermission] | ||
filter_backends = [DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter] | ||
search_fields = ["name"] | ||
ordering = ["name"] | ||
|
||
def get_serializer_class(self): | ||
serializer = { | ||
"create": CategoryCreateSerializer, | ||
"update": CategoryUpdateSerializer, | ||
} | ||
return serializer.get(self.action, CategoryListSerializer) | ||
|
||
def get_queryset(self): | ||
# get items that has permission to read | ||
targets = [] | ||
for category in Category.objects.filter(is_active=True): | ||
if self.request.user.has_permission(category, ACLType.Readable): | ||
targets.append(category.id) | ||
|
||
return Category.objects.filter(id__in=targets) | ||
|
||
def destroy(self, request: Request, *args, **kwargs) -> Response: | ||
category: Category = self.get_object() | ||
if not category.is_active: | ||
raise ObjectNotExistsError("specified entry has already been deleted") | ||
|
||
# delete specified category | ||
category.delete() | ||
|
||
return Response(status=status.HTTP_204_NO_CONTENT) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class CategoryConfig(AppConfig): | ||
default_auto_field = "django.db.models.BigAutoField" | ||
name = "category" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.db import models | ||
|
||
from acl.models import ACLBase, ACLObjType | ||
|
||
|
||
class Category(ACLBase): | ||
note = models.CharField(max_length=500, blank=True, default="") | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(Category, self).__init__(*args, **kwargs) | ||
self.objtype = ACLObjType.Category |
Empty file.
Oops, something went wrong.