kopia lustrzana https://github.com/wagtail/wagtail
rodzic
c4ef290859
commit
996abeae8e
|
@ -50,6 +50,7 @@ Changelog
|
|||
* Add the accessibility checker within the page and snippets editor (Thibaud Colas)
|
||||
* Add `DrilldownController` and `w-drilldown` component to support drilldown menus (Thibaud Colas)
|
||||
* Add support for `caption` on admin UI Table component (Aman Pandey)
|
||||
* Add API support for a redirects (contrib) endpoint (Rohit Sharma, Jaap Roes, Andreas Donig)
|
||||
* Fix: Update system check for overwriting storage backends to recognise the `STORAGES` setting introduced in Django 4.2 (phijma-leukeleu)
|
||||
* Fix: Prevent password change form from raising a validation error when browser autocomplete fills in the "Old password" field (Chiemezuo Akujobi)
|
||||
* Fix: Ensure that the legacy dropdown options, when closed, do not get accidentally clicked by other interactions wide viewports (CheesyPhoenix, Christer Jensen)
|
||||
|
|
|
@ -787,6 +787,7 @@
|
|||
* Jai Vignesh J
|
||||
* Sankalp
|
||||
* V Rohitansh
|
||||
* Andreas Donig
|
||||
|
||||
## Translators
|
||||
|
||||
|
|
|
@ -40,11 +40,12 @@ content type (such as pages, images and documents) has its own endpoint.
|
|||
Endpoints are combined by a router, which provides the url configuration you
|
||||
can hook into the rest of your project.
|
||||
|
||||
Wagtail provides three endpoint classes you can use:
|
||||
Wagtail provides multiple endpoint classes you can use:
|
||||
|
||||
- Pages {class}`wagtail.api.v2.views.PagesAPIViewSet`
|
||||
- Images {class}`wagtail.images.api.v2.views.ImagesAPIViewSet`
|
||||
- Documents {class}`wagtail.documents.api.v2.views.DocumentsAPIViewSet`
|
||||
- Redirects {class}`wagtail.contrib.redirects.api.RedirectsAPIViewSet` see [](redirects_api_endpoint)
|
||||
|
||||
You can subclass any of these endpoint classes to customise their functionality.
|
||||
For example, in this case if you need to change the `APIViewSet` by setting a desired renderer class:
|
||||
|
|
|
@ -93,3 +93,24 @@ Options:
|
|||
|
||||
.. automethod:: add_redirect
|
||||
```
|
||||
|
||||
(redirects_api_endpoint)=
|
||||
|
||||
## API
|
||||
|
||||
You can create an API endpoint to retrieve redirects or find specific redirects by path.
|
||||
|
||||
See the [](api_v2_configuration) documentation on how to configure the Wagtail API.
|
||||
|
||||
Add the following code to add the redirects endpoint:
|
||||
|
||||
```python
|
||||
from wagtail.contrib.redirects.api import RedirectsAPIViewSet
|
||||
|
||||
api_router.register_endpoint('redirects', RedirectsAPIViewSet)
|
||||
```
|
||||
|
||||
With this configuration, redirects will be available at `/api/v2/redirects/`.
|
||||
|
||||
Specific redirects by path can be resolved with `/api/v2/redirects/find/?html_path=<path>`,
|
||||
which will return either a `200` response with the redirects detail, or a `404` not found response.
|
||||
|
|
|
@ -82,6 +82,7 @@ This feature was implemented by Nick Lee, Thibaud Colas, and Sage Abdullah.
|
|||
* Keep database state of pages and snippets updated while in draft state (Stefan Hammer)
|
||||
* Add `DrilldownController` and `w-drilldown` component to support drilldown menus (Thibaud Colas)
|
||||
* Add support for `caption` on admin UI Table component (Aman Pandey)
|
||||
* Add API support for a [redirects (contrib)](redirects_api_endpoint) endpoint (Rohit Sharma, Jaap Roes, Andreas Donig)
|
||||
|
||||
|
||||
### Bug fixes
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
from django.http import Http404
|
||||
from rest_framework import serializers
|
||||
|
||||
from wagtail.api.v2.filters import FieldsFilter, OrderingFilter, SearchFilter
|
||||
from wagtail.api.v2.serializers import BaseSerializer
|
||||
from wagtail.api.v2.views import BaseAPIViewSet
|
||||
from wagtail.contrib.redirects.middleware import get_redirect
|
||||
from wagtail.contrib.redirects.models import Redirect
|
||||
|
||||
|
||||
class RedirectSerializer(BaseSerializer):
|
||||
location = serializers.CharField(source="link")
|
||||
|
||||
|
||||
class RedirectsAPIViewSet(BaseAPIViewSet):
|
||||
base_serializer_class = RedirectSerializer
|
||||
filter_backends = [FieldsFilter, OrderingFilter, SearchFilter]
|
||||
body_fields = BaseAPIViewSet.body_fields + ["old_path", "location"]
|
||||
name = "redirects"
|
||||
model = Redirect
|
||||
|
||||
listing_default_fields = BaseAPIViewSet.listing_default_fields + [
|
||||
"old_path",
|
||||
"location",
|
||||
]
|
||||
|
||||
def find_object(self, queryset, request):
|
||||
if "html_path" in request.GET:
|
||||
redirect = get_redirect(
|
||||
request,
|
||||
request.GET["html_path"],
|
||||
)
|
||||
|
||||
if redirect is None:
|
||||
raise Http404
|
||||
else:
|
||||
return redirect
|
||||
|
||||
return super().find_object(queryset, request)
|
|
@ -0,0 +1,105 @@
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.contrib.redirects.models import Redirect
|
||||
from wagtail.models import Page, Site
|
||||
|
||||
|
||||
class TestRedirectsAPI(TestCase):
|
||||
def setUp(self):
|
||||
self.example_home = Page.objects.get(slug="home").add_sibling(
|
||||
instance=Page(title="Example Homepage", slug="example-home")
|
||||
)
|
||||
self.example_page = self.example_home.add_child(
|
||||
instance=Page(title="Example Page", slug="example-page")
|
||||
)
|
||||
self.example_site = Site.objects.create(
|
||||
hostname="example", root_page=self.example_home
|
||||
)
|
||||
|
||||
Redirect.objects.create(
|
||||
old_path="/hello-world",
|
||||
site=self.example_site,
|
||||
redirect_link="https://www.example.com/hello-world/",
|
||||
)
|
||||
|
||||
Redirect.objects.create(
|
||||
old_path="/good-work",
|
||||
site=self.example_site,
|
||||
redirect_link="https://www.example.com/hello-world/",
|
||||
)
|
||||
|
||||
Redirect.add_redirect(
|
||||
old_path="/hello-world", redirect_to="https://www.example.net/new-world/"
|
||||
)
|
||||
|
||||
Redirect.add_redirect(
|
||||
old_path="/old-example", redirect_to=self.example_home, is_permanent=False
|
||||
)
|
||||
|
||||
Redirect.add_redirect(
|
||||
old_path="/old-example?bar=foo&foo=bar",
|
||||
redirect_to=self.example_page,
|
||||
is_permanent=False,
|
||||
)
|
||||
|
||||
def test_redirects_listing(self):
|
||||
"""Returns a list of all redirects"""
|
||||
|
||||
url = reverse("wagtailapi_v2:redirects:listing")
|
||||
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertEqual(5, len(response.json()["items"]))
|
||||
|
||||
item = response.json()["items"][0]
|
||||
|
||||
self.assertEqual("https://www.example.com/hello-world/", item["location"])
|
||||
self.assertEqual("/hello-world", item["old_path"])
|
||||
|
||||
def test_redirect(self):
|
||||
"""Returns a matching (not site specific) redirect"""
|
||||
|
||||
url = reverse("wagtailapi_v2:redirects:find")
|
||||
|
||||
html_path = "/hello-world"
|
||||
|
||||
# Add the html_path to the URL
|
||||
url += f"?html_path={html_path}"
|
||||
|
||||
response = self.client.get(url)
|
||||
|
||||
# Check for a redirect status code
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# Follow the redirect to get the final response
|
||||
response = self.client.get(response.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_id = response.json()["id"]
|
||||
|
||||
expected_dict = {
|
||||
"id": response_id,
|
||||
"meta": {
|
||||
"detail_url": f"http://localhost/api/main/redirects/{response_id}/",
|
||||
"type": "wagtailredirects.Redirect",
|
||||
},
|
||||
"old_path": "/hello-world",
|
||||
"location": "https://www.example.net/new-world/",
|
||||
}
|
||||
|
||||
self.assertEqual(response.json(), expected_dict)
|
||||
|
||||
def test_html_path_without_redirect(self):
|
||||
html_path = "/good-work"
|
||||
|
||||
url = reverse("wagtailapi_v2:redirects:find")
|
||||
|
||||
# Add the html_path to the URL
|
||||
url += f"?html_path={html_path}"
|
||||
|
||||
response = self.client.get(url)
|
||||
|
||||
# Check for a 404 status code
|
||||
self.assertEqual(response.status_code, 404)
|
|
@ -9,6 +9,7 @@ from wagtail.admin.views import home
|
|||
from wagtail.api.v2.router import WagtailAPIRouter
|
||||
from wagtail.api.v2.tests.test_pages import Test10411APIViewSet
|
||||
from wagtail.api.v2.views import PagesAPIViewSet
|
||||
from wagtail.contrib.redirects.api import RedirectsAPIViewSet
|
||||
from wagtail.contrib.sitemaps import Sitemap
|
||||
from wagtail.contrib.sitemaps import views as sitemaps_views
|
||||
from wagtail.documents import urls as wagtaildocs_urls
|
||||
|
@ -23,6 +24,7 @@ api_router = WagtailAPIRouter("wagtailapi_v2")
|
|||
api_router.register_endpoint("pages", PagesAPIViewSet)
|
||||
api_router.register_endpoint("images", ImagesAPIViewSet)
|
||||
api_router.register_endpoint("documents", DocumentsAPIViewSet)
|
||||
api_router.register_endpoint("redirects", RedirectsAPIViewSet)
|
||||
api_router.register_endpoint("issue_10411", Test10411APIViewSet)
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue