Skip to content

Commit

Permalink
Merge pull request #5 from RedTurtle/feedbacks_list_update
Browse files Browse the repository at this point in the history
Feedbacks list update
  • Loading branch information
folix-01 authored Nov 7, 2024
2 parents 40039c7 + 01106ff commit 7139090
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 2 deletions.
4 changes: 2 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Changelog
1.1.5 (unreleased)
------------------

- Nothing changed yet.

- Feedbacks list update endpoint @@feedback-list.
[folix-01]

1.1.4 (2024-08-21)
------------------
Expand Down
21 changes: 21 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ Search reviews
Right now data is not indexed so search filters does not work. You only need to call search method to get all data.


List update
-----------

PATCH
~~~~~

This endpoint allows update feedbacks by list.
By now you can only change "read" property


Example::

curl http://localhost:8080/Plone/@feedback-list \
-X PATCH \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"101010101": {"read": true},
}'


Installation
------------

Expand Down
8 changes: 8 additions & 0 deletions src/collective/feedback/restapi/services/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,13 @@
layer="collective.feedback.interfaces.ICollectiveFeedbackLayer"
name="@feedback"
/>
<plone:service
method="PATCH"
factory=".list_update.FeedbacListkUpdate"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="collective.feedback.FeedbacksOverview"
layer="collective.feedback.interfaces.ICollectiveFeedbackLayer"
name="@feedback-list"
/>

</configure>
23 changes: 23 additions & 0 deletions src/collective/feedback/restapi/services/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

from collective.feedback.interfaces import ICollectiveFeedbackStore

DEFAULT_SORT_KEY = "date"


@implementer(IPublishTraverse)
class FeedbackGet(Service):
Expand All @@ -35,6 +37,9 @@ def reply(self):
results = self.get_single_object_feedbacks(self.params[0])
else:
results = self.get_data()

results = self.filter_unread(self.sort_results(results))

batch = HypermediaBatch(self.request, results)
data = {
"@id": batch.canonical_url,
Expand All @@ -48,6 +53,24 @@ def reply(self):
data["actions"] = {"can_delete_feedbacks": self.can_delete_feedbacks()}
return data

def sort_results(self, results):
sort_on = self.request.get("sort_on")
sort_order = self.request.get("sort_order", "")

return sorted(
results,
key=lambda item: item.get(sort_on, DEFAULT_SORT_KEY),
reverse=sort_order == "descending",
)

def filter_unread(self, results):
unread = self.request.get("unread")

if unread:
return list(filter(lambda item: not item.get("read"), results))

return results

def can_delete_feedbacks(self):
return api.user.has_permission("collective.feedback: Delete Feedbacks")

Expand Down
64 changes: 64 additions & 0 deletions src/collective/feedback/restapi/services/list_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from plone.protect.interfaces import IDisableCSRFProtection
from plone.restapi.deserializer import json_body
from plone.restapi.services import Service
from zExceptions import BadRequest, NotFound
from zope.component import getUtility
from zope.interface import alsoProvides

from collective.feedback.interfaces import ICollectiveFeedbackStore


class FeedbacListkUpdate(Service):
"""
Service for update feedback to object, you can only update `read` field
"""

def __init__(self, context, request):
super().__init__(context, request)

def reply(self):
alsoProvides(self.request, IDisableCSRFProtection)

tool = getUtility(ICollectiveFeedbackStore)

form_data = self.extract_data(json_body(self.request))

for id, value in form_data.items():
comment = tool.get(id)

if comment.get("error", "") == "NotFound":
raise NotFound()

try:
tool.update(id, value)
except ValueError as e:
self.request.response.setStatus(500)
return dict(
error=dict(
type="InternalServerError",
message=getattr(e, "message", e.__str__()),
)
)

return form_data

def extract_data(self, form_data):
data = {}

for id, value in form_data.items():
try:
self.validate_data(value)
data[int(id)] = {"read": value.get("read")}
except ValueError:
raise BadRequest(f"Bad id={id} format provided")

return data

def validate_data(self, data):
"""
check all required fields and parameters
"""
for field in ["read"]:
value = data.get(field, None)
if value is None:
raise BadRequest("Campo obbligatorio mancante: {}".format(field))
122 changes: 122 additions & 0 deletions src/collective/feedback/tests/test_restapi_services_list_upgdate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
import unittest

import transaction
from plone import api
from plone.app.testing import (
SITE_OWNER_NAME,
SITE_OWNER_PASSWORD,
TEST_USER_ID,
setRoles,
)
from plone.restapi.testing import RelativeSession
from zope.component import getUtility

from collective.feedback.interfaces import ICollectiveFeedbackStore
from collective.feedback.testing import RESTAPI_TESTING


class TestAdd(unittest.TestCase):
layer = RESTAPI_TESTING

def setUp(self):
self.app = self.layer["app"]
self.portal = self.layer["portal"]
self.portal_url = self.portal.absolute_url()
setRoles(self.portal, TEST_USER_ID, ["Manager"])

api.user.create(
email="[email protected]",
username="memberuser",
password="secret!!",
)

self.document = api.content.create(
title="Document", container=self.portal, type="Document"
)
api.content.transition(obj=self.document, transition="publish")

self.private_document = api.content.create(
title="restricted document", container=self.portal, type="Document"
)
transaction.commit()

self.api_session = RelativeSession(self.portal_url)
self.api_session.headers.update({"Accept": "application/json"})
self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
self.anon_api_session = RelativeSession(self.portal_url)
self.anon_api_session.headers.update({"Accept": "application/json"})

self.url = "{}/@feedback-add".format(self.document.absolute_url())
self.url_private_document = "{}/@feedback-add".format(
self.private_document.absolute_url()
)

def tearDown(self):
self.api_session.close()
self.anon_api_session.close()

def test_correctly_update_data(self):
self.anon_api_session.post(
self.url,
json={"vote": 3, "comment": "i disagree", "honey": ""},
)
self.anon_api_session.post(
self.url,
json={"vote": 2, "comment": "i disagree", "honey": ""},
)
transaction.commit()
tool = getUtility(ICollectiveFeedbackStore)
feedbacks = tool.search()

self.assertEqual(len(feedbacks), 2)

self.api_session.patch(
api.portal.get().absolute_url() + "/@feedback-list",
json={str(feedbacks[0].intid): {"read": True}},
)
transaction.commit()

self.assertTrue(tool.get(feedbacks[0].intid).attrs.get("read"))

def test_unknown_id(self):
self.anon_api_session.post(
self.url,
json={"vote": 3, "comment": "i disagree", "honey": ""},
)
transaction.commit()

tool = getUtility(ICollectiveFeedbackStore)
feedbacks = tool.search()

self.assertEqual(len(feedbacks), 1)

resp = self.api_session.patch(
api.portal.get().absolute_url() + "/@feedback-list",
json={"1111111111": {"read": True}},
)

transaction.commit()

self.assertEqual(resp.status_code, 404)

def test_bad_id(self):
self.anon_api_session.post(
self.url,
json={"vote": 3, "comment": "i disagree", "honey": ""},
)
transaction.commit()

tool = getUtility(ICollectiveFeedbackStore)
feedbacks = tool.search()

self.assertEqual(len(feedbacks), 1)

resp = self.api_session.patch(
api.portal.get().absolute_url() + "/@feedback-list",
json={"fffffffff": {"read": True}},
)

transaction.commit()

self.assertEqual(resp.status_code, 400)
4 changes: 4 additions & 0 deletions test_plone60.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,7 @@ collective.honeypot = 2.1

# Added by buildout at 2024-02-08 21:49:12.973900
zpretty = 3.1.0

# Added by buildout at 2024-10-08 14:48:52.237066
pluggy = 1.5.0
tomli = 2.0.2

0 comments on commit 7139090

Please sign in to comment.