From 39299de90cef9cfe52b7e76b586eb83838ca87f4 Mon Sep 17 00:00:00 2001 From: Faakhir30 <110815427+Faakhir30@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:47:35 +0500 Subject: [PATCH] [fc] Repository: plone.restapi Branch: refs/heads/main Date: 2024-09-30T17:47:35+05:00 Author: Faakhir Zahid (Faakhir30) <110815427+Faakhir30@users.noreply.github.com> Commit: https://github.com/plone/plone.restapi/commit/a6533499ef33a27a2e4840b76023a09af3903750 added upload and download aliases in csv format. (#1813) * Added text/CSV content-type support to upload/download aliases in bulk. * Added aliases unit/integration tests for aliases service. * Added documentation Files changed: A news/1812.feature A src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.req A src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.resp A src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.req A src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.resp A src/plone/restapi/tests/test_services_aliases.py M docs/source/endpoints/aliases.md M src/plone/restapi/services/aliases/add.py M src/plone/restapi/services/aliases/configure.zcml M src/plone/restapi/services/aliases/get.py M src/plone/restapi/tests/test_documentation.py --- last_commit.txt | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/last_commit.txt b/last_commit.txt index b869cdfd2e..417bf61a4d 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,15 +1,29 @@ -Repository: plone.app.multilingual +Repository: plone.restapi -Branch: refs/heads/master -Date: 2024-09-29T16:24:23-07:00 -Author: David Glick (davisagli) -Commit: https://github.com/plone/plone.app.multilingual/commit/7aedd0ab71d3edf5d1fb4cb86b9f611d428ed76b +Branch: refs/heads/main +Date: 2024-09-30T17:47:35+05:00 +Author: Faakhir Zahid (Faakhir30) <110815427+Faakhir30@users.noreply.github.com> +Commit: https://github.com/plone/plone.restapi/commit/a6533499ef33a27a2e4840b76023a09af3903750 -Update README.rst +added upload and download aliases in csv format. (#1813) + +* Added text/CSV content-type support to upload/download aliases in bulk. +* Added aliases unit/integration tests for aliases service. +* Added documentation Files changed: -M README.rst +A news/1812.feature +A src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.req +A src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.resp +A src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.req +A src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.resp +A src/plone/restapi/tests/test_services_aliases.py +M docs/source/endpoints/aliases.md +M src/plone/restapi/services/aliases/add.py +M src/plone/restapi/services/aliases/configure.zcml +M src/plone/restapi/services/aliases/get.py +M src/plone/restapi/tests/test_documentation.py -b"diff --git a/README.rst b/README.rst\nindex d69a5495..6b563e3f 100644\n--- a/README.rst\n+++ b/README.rst\n@@ -313,7 +313,7 @@ In order to know if a content can be translated there is a marker interface::\n Source Code\n ===========\n \n-Contributors please read the document `Process for Plone core's development `_\n+Contributors please read the document `Contribute to Plone 6 core `_\n \n Sources are at the `Plone code repository hosted at Github `_.\n \n" +b'diff --git a/docs/source/endpoints/aliases.md b/docs/source/endpoints/aliases.md\nindex 46f68342e1..da841c2e0a 100644\n--- a/docs/source/endpoints/aliases.md\n+++ b/docs/source/endpoints/aliases.md\n@@ -70,9 +70,10 @@ Response:\n :language: http\n ```\n \n-## Adding URL aliases in bulk\n+## Adding URL aliases in bulk via JSON\n \n-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:\n+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.\n+**datetime** parameter is optional:\n \n ```{eval-rst}\n .. http:example:: curl httpie python-requests\n@@ -85,10 +86,26 @@ Response:\n :language: http\n ```\n \n+## Adding URL aliases in bulk via CSV\n \n-## Listing all available aliases\n+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.\n+**datetime** parameter is optional:\n \n-To list all aliases, send a `GET` request to the `/@aliases` endpoint on site `root`:\n+```{eval-rst}\n+.. http:example:: curl httpie python-requests\n+ :request: ../../../src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.req\n+```\n+\n+Response:\n+\n+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/aliases_root_add_csv_format.resp\n+:language: http\n+```\n+\n+\n+## Listing all available aliases via JSON\n+\n+To list all aliases in JSON format, send a `GET` request to the `/@aliases` endpoint on site `root`:\n \n ```{eval-rst}\n .. http:example:: curl httpie python-requests\n@@ -101,6 +118,21 @@ Response:\n :language: http\n ```\n \n+## Listing all available aliases via CSV\n+\n+To download all aliases as a CSV file, send a `GET` request to the `/@aliases` endpoint on site `root`:\n+\n+```{eval-rst}\n+.. http:example:: curl httpie python-requests\n+ :request: ../../../src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.req\n+```\n+\n+Response:\n+\n+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/aliases_root_get_csv_format.resp\n+:language: http\n+```\n+\n ## Filter aliases\n \n To search for specific aliases, send a `GET` request to the `/@aliases` endpoint on site `root` with a `q` parameter:\ndiff --git a/news/1812.feature b/news/1812.feature\nnew file mode 100644\nindex 0000000000..85727b674b\n--- /dev/null\n+++ b/news/1812.feature\n@@ -0,0 +1 @@\n+Added create and fetch aliases in CSV format. @Faakhir30\ndiff --git a/src/plone/restapi/services/aliases/add.py b/src/plone/restapi/services/aliases/add.py\nindex 555fbdbe0f..ab8af1ed2a 100644\n--- a/src/plone/restapi/services/aliases/add.py\n+++ b/src/plone/restapi/services/aliases/add.py\n@@ -1,17 +1,24 @@\n from DateTime import DateTime\n+from DateTime.interfaces import DateTimeError\n from plone.app.redirector.interfaces import IRedirectionStorage\n from plone.restapi import _\n from plone.restapi.deserializer import json_body\n from plone.restapi.services import Service\n from Products.CMFPlone.controlpanel.browser.redirects import absolutize_path\n+from Products.CMFPlone.controlpanel.browser.redirects import RedirectsControlPanel\n+from Products.statusmessages.interfaces import IStatusMessage\n from zExceptions import BadRequest\n from zope.component import getMultiAdapter\n+from zope.component.hooks import getSite\n from zope.component import getUtility\n from zope.interface import alsoProvides\n from zope.interface import implementer\n from zope.publisher.interfaces import IPublishTraverse\n \n import plone.protect.interfaces\n+import logging\n+\n+logger = logging.getLogger("Plone")\n \n \n @implementer(IPublishTraverse)\n@@ -83,15 +90,35 @@ def edit_for_navigation_root(self, alias):\n class AliasesRootPost(Service):\n """Creates new aliases via controlpanel"""\n \n- def reply(self):\n- data = json_body(self.request)\n+ def _reply_csv(self):\n+ form = self.request.form\n+ if not form.get("file"):\n+ raise BadRequest("No file uploaded")\n+ controlpanel = RedirectsControlPanel(self.context, self.request)\n storage = getUtility(IRedirectionStorage)\n- aliases = data.get("items", [])\n+ status = IStatusMessage(self.request)\n+ portal = getSite()\n+ file = form["file"]\n+ controlpanel.upload(file, portal, storage, status)\n+ file.close()\n+\n+ if err := status.show():\n+ if err[0].type == "error":\n+ raise BadRequest(err[0].message)\n+ elif err[0].type == "info":\n+ logger.info(err[0].message)\n+ return self.reply_no_content()\n \n+ def reply(self):\n # Disable CSRF protection\n if "IDisableCSRFProtection" in dir(plone.protect.interfaces):\n alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection)\n+ if "multipart/form-data" in self.request.getHeader("Content-Type"):\n+ return self._reply_csv()\n \n+ storage = getUtility(IRedirectionStorage)\n+ data = json_body(self.request)\n+ aliases = data.get("items", [])\n for alias in aliases:\n redirection = alias.get("path")\n target = alias.get("redirect-to")\n@@ -113,7 +140,11 @@ def reply(self):\n \n date = alias.get("datetime", None)\n if date:\n- date = DateTime(date)\n+ try:\n+ date = DateTime(date)\n+ except DateTimeError:\n+ logger.warning("Failed to parse as DateTime: %s", date)\n+ date = None\n \n storage.add(abs_redirection, abs_target, now=date, manual=True)\n \ndiff --git a/src/plone/restapi/services/aliases/configure.zcml b/src/plone/restapi/services/aliases/configure.zcml\nindex e3291cf161..c6499d117a 100644\n--- a/src/plone/restapi/services/aliases/configure.zcml\n+++ b/src/plone/restapi/services/aliases/configure.zcml\n@@ -12,6 +12,15 @@\n name="@aliases"\n />\n \n+ \n+\n