From 9065fb99a84e7694d8f2c7cc35cd624ac6f7089b Mon Sep 17 00:00:00 2001 From: Sergei Kliuikov Date: Tue, 31 Oct 2023 22:08:04 -0700 Subject: [PATCH] Release 5.8.8 #### Changelog: * Feature(backend): Add experimental caching check function. * Chore(deps): Upgrade backend MD dependency. --- requirements.txt | 2 +- test_src/test_proj/tests.py | 2 +- vstutils/__init__.py | 2 +- vstutils/api/base.py | 40 +++++++++++++++++++++++++++---------- vstutils/api/base.pyi | 8 ++++++++ 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/requirements.txt b/requirements.txt index 24b48a5b..b1b2c89b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # Main packages configparserc~=2.0.0 -Markdown~=3.5.0 +Markdown~=3.5.1 django-environ~=0.11.2 # REST API packages diff --git a/test_src/test_proj/tests.py b/test_src/test_proj/tests.py index 2cc35e45..a62fc0bc 100644 --- a/test_src/test_proj/tests.py +++ b/test_src/test_proj/tests.py @@ -3559,7 +3559,7 @@ def test_cacheable_model(self): ]) self.assertEqual(results[0]['status'], 200) self.assertEqual(results[0]['data']['count'], 2) - self.assertEqual(results[1]['status'], 304) + self.assertEqual(results[1]['status'], 304, results[1]['data']) self.assertEqual(results[2]['status'], 200) self.assertEqual(results[2]['data']['id'], instance.id) self.assertEqual(results[3]['status'], 304) diff --git a/vstutils/__init__.py b/vstutils/__init__.py index d8552caa..1e5293d8 100644 --- a/vstutils/__init__.py +++ b/vstutils/__init__.py @@ -1,2 +1,2 @@ # pylint: disable=django-not-available -__version__: str = '5.8.7' +__version__: str = '5.8.8' diff --git a/vstutils/api/base.py b/vstutils/api/base.py index b66a17ea..78f517de 100644 --- a/vstutils/api/base.py +++ b/vstutils/api/base.py @@ -496,6 +496,28 @@ class EtagDependency(enum.Flag): LANG = enum.auto() +def check_request_etag(request, etag_value, header_name="If-None-Match", operation_handler=str.__eq__): + header = request.headers.get(header_name) + + if not header: + return etag_value, False + + header = str(header) + if header[:2] in {'W/', "w/"}: + header = header[2:] + + if header[0] != '"': + header = f'"{header}"' + + if etag_value[0] != '"': + etag_value = f'"{etag_value}"' + + if operation_handler(etag_value, header): + return etag_value, True + + return etag_value, False + + class CachableHeadMixin(GenericViewSet): """ Mixin which cache GET responses. @@ -550,16 +572,14 @@ def check_etag(self, request, model_class=None): # For non-standart request methods return # nocv - header = request.headers.get(header_name, None) - if not header: - return - data = self._get_etag(model_class or self.model_class, request) - header = str(header) - if header[:2] in ('W/', "w/"): - header = header[2:] - if header[0] != '"': - header = f'"{header}"' - if operation_handler(data, header): + _, match = check_request_etag( + request, + self.get_etag_value(model_class or self.model_class, request), + header_name, + operation_handler, + ) + + if match: raise exception def finalize_response(self, request, response, *args, **kwargs): diff --git a/vstutils/api/base.pyi b/vstutils/api/base.pyi index 73ffe465..df4daa16 100644 --- a/vstutils/api/base.pyi +++ b/vstutils/api/base.pyi @@ -91,6 +91,14 @@ class EtagDependency(enum.Flag): SESSION: enum.auto() LANG: enum.auto() +def check_request_etag( + request: Request, + etag_value: T, + header_name: _t.Text = "If-None-Match", + operation_handler: _t.Callable[[_t.Text, _t.Text], bool] = str.__eq__ +) -> _t.Tuple[T, bool]: + ... + class CachableHeadMixin(GenericViewSet): class NotModifiedException(exceptions.APIException): ... class PreconditionFailedException(exceptions.APIException): ...