mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-24 02:39:20 -05:00
Merge branch 'feature/vue3' of https://github.com/vabene1111/recipes into feature/vue3
This commit is contained in:
@@ -20,6 +20,10 @@
|
||||
"ms-python.python"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"containerEnv": {
|
||||
"CSRF_TRUSTED_ORIGINS": "http://localhost:8000,http://localhost:8080"
|
||||
}
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
|
||||
@@ -14,8 +14,11 @@ class QueryParam(object):
|
||||
|
||||
|
||||
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 is_list_view(path, method, self.view):
|
||||
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:
|
||||
|
||||
@@ -5,12 +5,14 @@ import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from icalendar import Calendar
|
||||
|
||||
from cookbook.models import MealPlan, MealType
|
||||
from cookbook.tests.factories import RecipeFactory
|
||||
|
||||
LIST_URL = 'api:mealplan-list'
|
||||
DETAIL_URL = 'api:mealplan-detail'
|
||||
ICAL_URL = 'api:mealplan-ical'
|
||||
|
||||
|
||||
# NOTE: auto adding shopping list from meal plan is tested in test_shopping_recipe as tests are identical
|
||||
@@ -32,6 +34,11 @@ def obj_2(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(),
|
||||
created_by=auth.get_user(u1_s1))
|
||||
|
||||
@pytest.fixture
|
||||
def obj_3(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now() - timedelta(days=30), to_date=datetime.now() - timedelta(days=1),
|
||||
created_by=auth.get_user(u1_s1))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
@@ -163,3 +170,32 @@ def test_add_with_shopping(u1_s1, meal_type):
|
||||
)
|
||||
|
||||
assert len(json.loads(u1_s1.get(reverse('api:shoppinglistentry-list')).content)) == 10
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
[f'', 2],
|
||||
[f'?from_date={datetime.now().strftime("%Y-%m-%d")}', 1],
|
||||
[f'?to_date={(datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")}', 1],
|
||||
[f'?from_date={(datetime.now() + timedelta(days=2)).strftime("%Y-%m-%d")}&to_date={(datetime.now() + timedelta(days=2)).strftime("%Y-%m-%d")}', 0],
|
||||
])
|
||||
def test_ical(arg, request, obj_1, obj_3, u1_s1):
|
||||
r = u1_s1.get(f'{reverse(ICAL_URL)}{arg[0]}')
|
||||
assert r.status_code == 200
|
||||
cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
events = cal.walk('VEVENT')
|
||||
assert len(events) == arg[1]
|
||||
|
||||
|
||||
def test_ical_event(obj_1, u1_s1):
|
||||
r = u1_s1.get(f'{reverse(ICAL_URL)}')
|
||||
|
||||
cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
events = cal.walk('VEVENT')
|
||||
assert len(events) == 1
|
||||
|
||||
event = events[0]
|
||||
assert int(event['uid']) == obj_1.id
|
||||
assert event['summary'] == f'{obj_1.meal_type.name}: {obj_1.get_label()}'
|
||||
assert event['description'] == obj_1.note
|
||||
assert event.decoded('dtstart') == datetime.now().date()
|
||||
assert event.decoded('dtend') == datetime.now().date()
|
||||
@@ -1,88 +1,55 @@
|
||||
# from datetime import datetime, timedelta
|
||||
#
|
||||
# import pytest
|
||||
# from django.contrib import auth
|
||||
# from django.urls import reverse
|
||||
# from icalendar import Calendar
|
||||
#
|
||||
# from cookbook.models import MealPlan, MealType
|
||||
#
|
||||
# BOUND_URL = 'api_get_plan_ical'
|
||||
# FROM_URL = 'api_get_plan_ical'
|
||||
# FUTURE_URL = 'api_get_plan_ical'
|
||||
#
|
||||
#
|
||||
# @pytest.fixture()
|
||||
# def meal_type(space_1, u1_s1):
|
||||
# return MealType.objects.get_or_create(name='test', space=space_1, created_by=auth.get_user(u1_s1))[0]
|
||||
#
|
||||
#
|
||||
# @pytest.fixture()
|
||||
# def obj_1(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
# return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(),
|
||||
# created_by=auth.get_user(u1_s1))
|
||||
#
|
||||
#
|
||||
# @pytest.fixture
|
||||
# def obj_2(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
# return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=30), to_date=datetime.now()+timedelta(days=30),
|
||||
# created_by=auth.get_user(u1_s1))
|
||||
#
|
||||
# @pytest.fixture
|
||||
# def obj_3(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
# return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=-30), to_date=datetime.now()+timedelta(days=-1),
|
||||
# created_by=auth.get_user(u1_s1))
|
||||
#
|
||||
#
|
||||
# @pytest.mark.parametrize("arg", [
|
||||
# ['a_u', 403],
|
||||
# ['g1_s1', 403],
|
||||
# ['u1_s1', 200],
|
||||
# ['a1_s1', 200],
|
||||
# ])
|
||||
# def test_permissions(arg, request):
|
||||
# c = request.getfixturevalue(arg[0])
|
||||
# assert c.get(reverse(FUTURE_URL)).status_code == arg[1]
|
||||
#
|
||||
# def test_future(obj_1, obj_2, obj_3, u1_s1):
|
||||
# r = u1_s1.get(reverse(FUTURE_URL))
|
||||
# assert r.status_code == 200
|
||||
#
|
||||
# cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
# events = cal.walk('VEVENT')
|
||||
# assert len(events) == 2
|
||||
#
|
||||
# def test_from(obj_1, obj_2, obj_3, u1_s1):
|
||||
# from_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
# r = u1_s1.get(reverse(FROM_URL, kwargs={'from_date': from_date_slug}))
|
||||
# assert r.status_code == 200
|
||||
#
|
||||
# cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
# events = cal.walk('VEVENT')
|
||||
# assert len(events) == 1
|
||||
#
|
||||
# def test_bound(obj_1, obj_2, obj_3, u1_s1):
|
||||
# from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d")
|
||||
# to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
# r = u1_s1.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug}))
|
||||
# assert r.status_code == 200
|
||||
#
|
||||
# cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
# events = cal.walk('VEVENT')
|
||||
# assert len(events) == 1
|
||||
#
|
||||
# def test_event(obj_1, u1_s1):
|
||||
# from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d")
|
||||
# to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
# r = u1_s1.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug}))
|
||||
#
|
||||
# cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
# events = cal.walk('VEVENT')
|
||||
# assert len(events) == 1
|
||||
#
|
||||
# event = events[0]
|
||||
# assert int(event['uid']) == obj_1.id
|
||||
# assert event['summary'] == f'{obj_1.meal_type.name}: {obj_1.get_label()}'
|
||||
# assert event['description'] == obj_1.note
|
||||
# assert event.decoded('dtstart') == datetime.now().date()
|
||||
# assert event.decoded('dtend') == datetime.now().date()
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from icalendar import Calendar
|
||||
|
||||
from cookbook.models import MealPlan, MealType
|
||||
|
||||
BOUND_URL = 'api_get_plan_ical'
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def meal_type(space_1, u1_s1):
|
||||
return MealType.objects.get_or_create(name='test', space=space_1, created_by=auth.get_user(u1_s1))[0]
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def obj_1(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(),
|
||||
created_by=auth.get_user(u1_s1))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def obj_2(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=30), to_date=datetime.now()+timedelta(days=30),
|
||||
created_by=auth.get_user(u1_s1))
|
||||
|
||||
@pytest.fixture
|
||||
def obj_3(space_1, recipe_1_s1, meal_type, u1_s1):
|
||||
return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=-30), to_date=datetime.now()+timedelta(days=-1),
|
||||
created_by=auth.get_user(u1_s1))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 403],
|
||||
['u1_s1', 200],
|
||||
['a1_s1', 200],
|
||||
])
|
||||
def test_permissions(arg, request):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d")
|
||||
to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
assert c.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug})).status_code == arg[1]
|
||||
|
||||
def test_bound(obj_1, obj_2, obj_3, u1_s1):
|
||||
from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d")
|
||||
to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
r = u1_s1.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug}))
|
||||
assert r.status_code == 200
|
||||
|
||||
cal = Calendar.from_ical(r.getvalue().decode('UTF-8'))
|
||||
events = cal.walk('VEVENT')
|
||||
assert len(events) == 1
|
||||
|
||||
@@ -33,6 +33,7 @@ from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema, OpenApiParameter, extend_schema_view
|
||||
from icalendar import Calendar, Event
|
||||
from oauth2_provider.models import AccessToken
|
||||
@@ -41,7 +42,7 @@ from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
|
||||
from requests.exceptions import MissingSchema
|
||||
from rest_framework import decorators, status, viewsets
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.decorators import action, api_view, permission_classes
|
||||
from rest_framework.exceptions import APIException, PermissionDenied
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
@@ -765,13 +766,19 @@ class RecipeBookEntryViewSet(viewsets.ModelViewSet, viewsets.GenericViewSet):
|
||||
return queryset
|
||||
|
||||
|
||||
MealPlanViewQueryParameters = [
|
||||
OpenApiParameter(name='from_date', description=_('Filter meal plans from date (inclusive) in the format of YYYY-MM-DD.'), type=str),
|
||||
OpenApiParameter(name='to_date', description=_('Filter meal plans to date (inclusive) in the format of YYYY-MM-DD.'), type=str),
|
||||
OpenApiParameter(name='meal_type', description=_('Filter meal plans with MealType ID. For multiple repeat parameter.'), type=str),
|
||||
]
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(name='from_date', description=_('Filter meal plans from date (inclusive) in the format of YYYY-MM-DD.'), type=str),
|
||||
OpenApiParameter(name='to_date', description=_('Filter meal plans to date (inclusive) in the format of YYYY-MM-DD.'), type=str),
|
||||
OpenApiParameter(name='meal_type', description=_('Filter meal plans with MealType ID. For multiple repeat parameter.'), type=str),
|
||||
]
|
||||
parameters= MealPlanViewQueryParameters
|
||||
),
|
||||
ical=extend_schema(
|
||||
parameters=MealPlanViewQueryParameters,
|
||||
responses={(200, 'text/calendar'): OpenApiTypes.STR}
|
||||
)
|
||||
)
|
||||
class MealPlanViewSet(viewsets.ModelViewSet):
|
||||
@@ -804,6 +811,13 @@ 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)
|
||||
to_date = self.request.query_params.get('to_date', None)
|
||||
return meal_plans_to_ical(self.get_queryset(), f'meal_plan_{from_date}-{to_date}.ics')
|
||||
|
||||
|
||||
|
||||
class AutoPlanViewSet(viewsets.ViewSet):
|
||||
@@ -1786,6 +1800,9 @@ def get_plan_ical(request, from_date=datetime.date.today(), to_date=None):
|
||||
if to_date is not None:
|
||||
queryset = queryset.filter(to_date__lte=to_date)
|
||||
|
||||
return meal_plans_to_ical(queryset, f'meal_plan_{from_date}-{to_date}.ics')
|
||||
|
||||
def meal_plans_to_ical(queryset, filename):
|
||||
cal = Calendar()
|
||||
|
||||
for p in queryset:
|
||||
@@ -1801,7 +1818,7 @@ def get_plan_ical(request, from_date=datetime.date.today(), to_date=None):
|
||||
cal.add_component(event)
|
||||
|
||||
response = FileResponse(io.BytesIO(cal.to_ical()))
|
||||
response["Content-Disposition"] = f'attachment; filename=meal_plan_{from_date}-{to_date}.ics' # noqa: E501
|
||||
response["Content-Disposition"] = f'attachment; filename={filename}' # noqa: E501
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -55,4 +55,4 @@ pytest-cov===4.1.0
|
||||
pytest-factoryboy==2.6.0
|
||||
pytest-html==4.1.1
|
||||
pytest-asyncio==0.23.5
|
||||
|
||||
pytest-xdist==3.5.0
|
||||
Reference in New Issue
Block a user