Skip to content

Commit cfb1271

Browse files
authored
feat: add OpenAPI support for "preview" query parameter (#53)
* feat: add OpenAPI support for "preview" query parameter * refactor: implement fallback for OpenAPI schema utilities in case of missing drf-spectacular * fix: remove unused typing import `Callable` from views_base.py * add `drf-spectacular` to test settings and requirements * chore: fix missing libcairo support
1 parent c141335 commit cfb1271

File tree

5 files changed

+82
-7
lines changed

5 files changed

+82
-7
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ jobs:
2525
uses: actions/setup-python@v6
2626
with:
2727
python-version: ${{ matrix.python-version }}
28+
- name: Install system deps (cairo stack)
29+
run: |
30+
sudo apt-get update
31+
sudo apt-get install -y \
32+
build-essential libcairo2-dev pkg-config python3-dev
2833
- name: Install dependencies
2934
run: |
3035
python -m pip install --upgrade pip

djangocms_rest/views.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import Any
3+
from typing import Any, Callable, ParamSpec, TypeVar
44
from django.contrib.sites.shortcuts import get_current_site
55
from django.urls import reverse
66
from django.utils.functional import lazy
@@ -32,26 +32,53 @@
3232
)
3333
from djangocms_rest.views_base import BaseAPIView, BaseListAPIView
3434

35+
P = ParamSpec("P")
36+
T = TypeVar("T")
3537

3638
try:
37-
from drf_spectacular.types import OpenApiTypes # noqa: F401
38-
from drf_spectacular.utils import OpenApiParameter, extend_schema # noqa: F401
39+
from drf_spectacular.types import OpenApiTypes
40+
from drf_spectacular.utils import OpenApiParameter, extend_schema
3941

4042
extend_placeholder_schema = extend_schema(
4143
parameters=[
4244
OpenApiParameter(
4345
name="html",
4446
type=OpenApiTypes.INT,
45-
location=OpenApiParameter.QUERY,
47+
location="query",
4648
description="Set to 1 to include HTML rendering in response",
4749
required=False,
4850
enum=[1],
51+
),
52+
OpenApiParameter(
53+
name="preview",
54+
type=OpenApiTypes.BOOL,
55+
location="query",
56+
description="Set to true to preview unpublished content (admin access required)",
57+
required=False,
4958
)
5059
]
5160
)
52-
except ImportError:
5361

54-
def extend_placeholder_schema(func):
62+
except ImportError: # pragma: no cover
63+
class OpenApiTypes:
64+
BOOL = "boolean"
65+
INT = "integer"
66+
67+
class OpenApiParameter: # pragma: no cover
68+
QUERY = "query"
69+
PATH = "path"
70+
HEADER = "header"
71+
COOKIE = "cookie"
72+
73+
def __init__(self, *args, **kwargs):
74+
pass
75+
76+
def extend_schema(*_args, **_kwargs): # pragma: no cover
77+
def _decorator(obj: T) -> T:
78+
return obj
79+
return _decorator
80+
81+
def extend_placeholder_schema(func: Callable[P, T]) -> Callable[P, T]:
5582
return func
5683

5784

@@ -60,7 +87,7 @@ def extend_placeholder_schema(func):
6087
# and keeps the code cleaner.
6188
# Attn: Dynamic changes to the plugin pool will not be reflected in the
6289
# plugin definitions.
63-
# If you need to update the plugin definitions, you need reassign the variable.
90+
# If you need to update the plugin definitions, you need to reassign the variable.
6491
PLUGIN_DEFINITIONS = lazy(
6592
PluginDefinitionSerializer.generate_plugin_definitions, dict
6693
)()

djangocms_rest/views_base.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,51 @@
1+
from typing import ParamSpec, TypeVar
2+
13
from django.contrib.sites.shortcuts import get_current_site
24
from django.utils.functional import cached_property
35
from rest_framework.generics import ListAPIView
46
from rest_framework.permissions import IsAdminUser
57
from rest_framework.views import APIView
68

9+
P = ParamSpec("P")
10+
T = TypeVar("T")
11+
12+
try:
13+
from drf_spectacular.types import OpenApiTypes
14+
from drf_spectacular.utils import OpenApiParameter, extend_schema
15+
16+
preview_schema = extend_schema(
17+
parameters=[
18+
OpenApiParameter(
19+
name="preview",
20+
type=OpenApiTypes.BOOL,
21+
location="query",
22+
description="Set to true to preview unpublished content (admin access required)",
23+
required=False,
24+
)
25+
]
26+
)
27+
except ImportError: # pragma: no cover
28+
class OpenApiTypes:
29+
BOOL = "boolean"
30+
31+
class OpenApiParameter: # pragma: no cover
32+
QUERY = "query"
33+
PATH = "path"
34+
HEADER = "header"
35+
COOKIE = "cookie"
36+
37+
def __init__(self, *args, **kwargs):
38+
pass
39+
40+
def extend_schema(*_args, **_kwargs): # pragma: no cover
41+
def _decorator(obj: T) -> T:
42+
return obj
43+
return _decorator
44+
45+
def preview_schema(obj: T) -> T: # pragma: no cover
46+
return obj
747

48+
@preview_schema
849
class BaseAPIMixin:
950
"""
1051
This mixin provides common functionality for all API views.

tests/requirements/base.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ djangocms-text
44
django-filer
55
beautifulsoup4
66
setuptools
7+
drf-spectacular
78

89
# other requirements
910
coverage

tests/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __getitem__(self, item):
3434
"tests.test_app",
3535
"filer",
3636
"easy_thumbnails",
37+
"drf_spectacular",
3738
]
3839

3940
MIDDLEWARE = [

0 commit comments

Comments
 (0)