remove custom QueryParams with extend_schema decorator

This commit is contained in:
smilerz
2024-03-27 08:18:50 -05:00
parent d6929e5cf9
commit fb3473459d
2 changed files with 37 additions and 106 deletions

View File

@@ -1,72 +0,0 @@
from rest_framework.schemas.openapi import AutoSchema
from rest_framework.schemas.utils import is_list_view
class QueryParam(object):
def __init__(self, name, description=None, qtype='string', required=False):
self.name = name
self.description = description
self.qtype = qtype
self.required = required
def __str__(self):
return f'{self.name}, {self.qtype}, {self.description}'
class QueryParamAutoSchema(AutoSchema):
def is_query(self, path, method):
return is_list_view(path, method, self.view)
def get_path_parameters(self, path, method):
if not self.is_query(path, method):
return super().get_path_parameters(path, method)
parameters = super().get_path_parameters(path, method)
for q in self.view.query_params:
parameters.append({
"name": q.name, "in": "query", "required": q.required,
"description": q.description,
'schema': {'type': q.qtype, },
})
return parameters
class TreeSchema(AutoSchema):
def get_path_parameters(self, path, method):
if not is_list_view(path, method, self.view):
return super(TreeSchema, self).get_path_parameters(path, method)
api_name = path.split('/')[2]
parameters = super().get_path_parameters(path, method)
parameters.append({
"name": 'query', "in": "query", "required": False,
"description": 'Query string matched against {} name.'.format(api_name),
'schema': {'type': 'string', },
})
parameters.append({
"name": 'root', "in": "query", "required": False,
"description": 'Return first level children of {obj} with ID [int]. Integer 0 will return root {obj}s.'.format(
obj=api_name),
'schema': {'type': 'integer', },
})
parameters.append({
"name": 'tree', "in": "query", "required": False,
"description": 'Return all self and children of {} with ID [int].'.format(api_name),
'schema': {'type': 'integer', },
})
return parameters
class FilterSchema(AutoSchema):
def get_path_parameters(self, path, method):
if not is_list_view(path, method, self.view):
return super(FilterSchema, self).get_path_parameters(path, method)
api_name = path.split('/')[2]
parameters = super().get_path_parameters(path, method)
parameters.append({
"name": 'query', "in": "query", "required": False,
"description": 'Query string matched against {} name.'.format(api_name),
'schema': {'type': 'string', },
})
return parameters

View File

@@ -77,7 +77,6 @@ from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilte
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
from cookbook.provider.nextcloud import Nextcloud
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer,
AutoMealPlanSerializer, BookmarkletImportListSerializer,
BookmarkletImportSerializer, CookLogSerializer,
@@ -617,25 +616,26 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
return self.serializer_class
# TODO I could not find any usage of this and it causes schema generation issues, so commenting it for now
# @decorators.action(detail=True, methods=['PUT'], serializer_class=FoodShoppingUpdateSerializer, )
# this is used on the Shopping Badge
@decorators.action(detail=True, methods=['PUT'], serializer_class=FoodShoppingUpdateSerializer, )
# # TODO DRF only allows one action in a decorator action without overriding get_operation_id_base() this should be PUT and DELETE probably
# def shopping(self, request, pk):
# if self.request.space.demo:
# raise PermissionDenied(detail='Not available in demo', code=None)
# obj = self.get_object()
# shared_users = list(self.request.user.get_shopping_share())
# shared_users.append(request.user)
# if request.data.get('_delete', False) == 'true':
# ShoppingListEntry.objects.filter(food=obj, checked=False, space=request.space, created_by__in=shared_users).delete()
# content = {'msg': _(f'{obj.name} was removed from the shopping list.')}
# return Response(content, status=status.HTTP_204_NO_CONTENT)
#
# amount = request.data.get('amount', 1)
# unit = request.data.get('unit', None)
# content = {'msg': _(f'{obj.name} was added to the shopping list.')}
#
# ShoppingListEntry.objects.create(food=obj, amount=amount, unit=unit, space=request.space, created_by=request.user)
# return Response(content, status=status.HTTP_204_NO_CONTENT)
def shopping(self, request, pk):
if self.request.space.demo:
raise PermissionDenied(detail='Not available in demo', code=None)
obj = self.get_object()
shared_users = list(self.request.user.get_shopping_share())
shared_users.append(request.user)
if request.data.get('_delete', False) == 'true':
ShoppingListEntry.objects.filter(food=obj, checked=False, space=request.space, created_by__in=shared_users).delete()
content = {'msg': _(f'{obj.name} was removed from the shopping list.')}
return Response(content, status=status.HTTP_204_NO_CONTENT)
amount = request.data.get('amount', 1)
unit = request.data.get('unit', None)
content = {'msg': _(f'{obj.name} was added to the shopping list.')}
ShoppingListEntry.objects.create(food=obj, amount=amount, unit=unit, space=request.space, created_by=request.user)
return Response(content, status=status.HTTP_204_NO_CONTENT)
@decorators.action(detail=True, methods=['POST'], )
def fdc(self, request, pk):
@@ -663,13 +663,11 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
json_dumps_params={'indent': 4})
food.properties_food_amount = 100
food.properties_food_unit = Unit.objects.get_or_create(base_unit__iexact='g',
space=self.request.space,
defaults={
'name': 'g',
'base_unit': 'g',
'space': self.request.space
})[0]
food.properties_food_unit = Unit.objects.get_or_create(
base_unit__iexact='g',
space=self.request.space,
defaults={ 'name': 'g', 'base_unit': 'g', 'space': self.request.space}
)[0]
food.save()
@@ -772,9 +770,10 @@ MealPlanViewQueryParameters = [
OpenApiParameter(name='meal_type', description=_('Filter meal plans with MealType ID. For multiple repeat parameter.'), type=str),
]
@extend_schema_view(
list=extend_schema(
parameters= MealPlanViewQueryParameters
parameters=MealPlanViewQueryParameters
),
ical=extend_schema(
parameters=MealPlanViewQueryParameters,
@@ -811,7 +810,7 @@ class MealPlanViewSet(viewsets.ModelViewSet):
queryset = queryset.filter(meal_type__in=meal_type)
return queryset
@action(detail=False)
def ical(self, request):
from_date = self.request.query_params.get('from_date', None)
@@ -819,7 +818,6 @@ class MealPlanViewSet(viewsets.ModelViewSet):
return meal_plans_to_ical(self.get_queryset(), f'meal_plan_{from_date}-{to_date}.ics')
class AutoPlanViewSet(viewsets.ViewSet):
def create(self, request):
@@ -1136,8 +1134,8 @@ class RecipeViewSet(viewsets.ModelViewSet):
serializer_class=RecipeFlatSerializer,
)
def flat(self, request):
qs = Recipe.objects.filter(
space=request.space).filter(Q(private=False) | (Q(private=True) & (Q(created_by=self.request.user) | Q(shared=self.request.user)))).all() # TODO limit fields retrieved but .values() kills image
# TODO limit fields retrieved but .values() kills image
qs = Recipe.objects.filter(space=request.space).filter(Q(private=False) | (Q(private=True) & (Q(created_by=self.request.user) | Q(shared=self.request.user)))).all()
return Response(self.serializer_class(qs, many=True).data)
@@ -1284,14 +1282,18 @@ class ViewLogViewSet(viewsets.ModelViewSet):
return self.queryset.filter(created_by=self.request.user).filter(space=self.request.space)
@extend_schema_view(
list=extend_schema(
parameters=[
OpenApiParameter(name='recipe', description='Filter for entries with the given recipe', type=int),
]
)
)
class CookLogViewSet(viewsets.ModelViewSet):
queryset = CookLog.objects
serializer_class = CookLogSerializer
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
pagination_class = DefaultPagination
query_params = [
QueryParam(name='recipe', description=_('Filter for entries with the given recipe'), qtype='integer'),
]
def get_queryset(self):
if self.request.query_params.get('recipe', None):
@@ -1802,6 +1804,7 @@ def get_plan_ical(request, from_date=datetime.date.today(), to_date=None):
return meal_plans_to_ical(queryset, f'meal_plan_{from_date}-{to_date}.ics')
def meal_plans_to_ical(queryset, filename):
cal = Calendar()