diff --git a/docs/source/endpoints/aliases.md b/docs/source/endpoints/aliases.md index 46f68342e..da841c2e0 100644 --- a/docs/source/endpoints/aliases.md +++ b/docs/source/endpoints/aliases.md @@ -70,9 +70,10 @@ Response: :language: http ``` -## Adding URL aliases in bulk +## Adding URL aliases in bulk via JSON -You can add multiple URL aliases for multiple pages by sending a `POST` request to the `/@aliases` endpoint on site `root`. **datetime** parameter is optional: +You can add multiple URL aliases for multiple pages by sending a `POST` request to the `/@aliases` endpoint on site `root` using a JSON payload. +**datetime** parameter is optional: ```{eval-rst} .. http:example:: curl httpie python-requests @@ -85,10 +86,26 @@ Response: :language: http ``` +## Adding URL aliases in bulk via CSV -## Listing all available aliases +You can add multiple URL aliases for multiple pages by sending a `POST` request to the `/@aliases` endpoint on site `root` using a CSV file. +**datetime** parameter is optional: -To list all aliases, send a `GET` request to the `/@aliases` endpoint on site `root`: +```{eval-rst} +.. http:example:: curl httpie python-requests + :request: ../../../src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.req +``` + +Response: + +```{literalinclude} ../../../src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.resp +:language: http +``` + + +## Listing all available aliases via JSON + +To list all aliases in JSON format, send a `GET` request to the `/@aliases` endpoint on site `root`: ```{eval-rst} .. http:example:: curl httpie python-requests @@ -101,6 +118,21 @@ Response: :language: http ``` +## Listing all available aliases via CSV + +To download all aliases as a CSV file, send a `GET` request to the `/@aliases` endpoint on site `root`: + +```{eval-rst} +.. http:example:: curl httpie python-requests + :request: ../../../src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.req +``` + +Response: + +```{literalinclude} ../../../src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.resp +:language: http +``` + ## Filter aliases To search for specific aliases, send a `GET` request to the `/@aliases` endpoint on site `root` with a `q` parameter: diff --git a/news/1812.feature b/news/1812.feature new file mode 100644 index 000000000..85727b674 --- /dev/null +++ b/news/1812.feature @@ -0,0 +1 @@ +Added create and fetch aliases in CSV format. @Faakhir30 diff --git a/src/plone/restapi/services/aliases/add.py b/src/plone/restapi/services/aliases/add.py index 555fbdbe0..ab8af1ed2 100644 --- a/src/plone/restapi/services/aliases/add.py +++ b/src/plone/restapi/services/aliases/add.py @@ -1,17 +1,24 @@ from DateTime import DateTime +from DateTime.interfaces import DateTimeError from plone.app.redirector.interfaces import IRedirectionStorage from plone.restapi import _ from plone.restapi.deserializer import json_body from plone.restapi.services import Service from Products.CMFPlone.controlpanel.browser.redirects import absolutize_path +from Products.CMFPlone.controlpanel.browser.redirects import RedirectsControlPanel +from Products.statusmessages.interfaces import IStatusMessage from zExceptions import BadRequest from zope.component import getMultiAdapter +from zope.component.hooks import getSite from zope.component import getUtility from zope.interface import alsoProvides from zope.interface import implementer from zope.publisher.interfaces import IPublishTraverse import plone.protect.interfaces +import logging + +logger = logging.getLogger("Plone") @implementer(IPublishTraverse) @@ -83,15 +90,35 @@ def edit_for_navigation_root(self, alias): class AliasesRootPost(Service): """Creates new aliases via controlpanel""" - def reply(self): - data = json_body(self.request) + def _reply_csv(self): + form = self.request.form + if not form.get("file"): + raise BadRequest("No file uploaded") + controlpanel = RedirectsControlPanel(self.context, self.request) storage = getUtility(IRedirectionStorage) - aliases = data.get("items", []) + status = IStatusMessage(self.request) + portal = getSite() + file = form["file"] + controlpanel.upload(file, portal, storage, status) + file.close() + + if err := status.show(): + if err[0].type == "error": + raise BadRequest(err[0].message) + elif err[0].type == "info": + logger.info(err[0].message) + return self.reply_no_content() + def reply(self): # Disable CSRF protection if "IDisableCSRFProtection" in dir(plone.protect.interfaces): alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) + if "multipart/form-data" in self.request.getHeader("Content-Type"): + return self._reply_csv() + storage = getUtility(IRedirectionStorage) + data = json_body(self.request) + aliases = data.get("items", []) for alias in aliases: redirection = alias.get("path") target = alias.get("redirect-to") @@ -113,7 +140,11 @@ def reply(self): date = alias.get("datetime", None) if date: - date = DateTime(date) + try: + date = DateTime(date) + except DateTimeError: + logger.warning("Failed to parse as DateTime: %s", date) + date = None storage.add(abs_redirection, abs_target, now=date, manual=True) diff --git a/src/plone/restapi/services/aliases/configure.zcml b/src/plone/restapi/services/aliases/configure.zcml index e3291cf16..c6499d117 100644 --- a/src/plone/restapi/services/aliases/configure.zcml +++ b/src/plone/restapi/services/aliases/configure.zcml @@ -12,6 +12,15 @@ name="@aliases" /> + +