Skip to content

Commit

Permalink
some refactoring to improve tests and allow users to access data
Browse files Browse the repository at this point in the history
  • Loading branch information
cekk committed Feb 8, 2024
1 parent 7ac6343 commit dc008a9
Show file tree
Hide file tree
Showing 20 changed files with 630 additions and 300 deletions.
61 changes: 0 additions & 61 deletions .travis.yml

This file was deleted.

11 changes: 9 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ Changelog
1.0.1 (unreleased)
------------------

- Nothing changed yet.

- Only managers can access deleted feedbacks.
[cekk]
- Allow all authenticated users to access @feedback endpoint.
The endpoint will return only feedbacks on objects that they can edit.
[cekk]
- Improve tests.
[cekk]
- Install souper.plone to have its control-panel in backend.
[cekk]

1.0.0 (2023-02-16)
------------------
Expand Down
22 changes: 12 additions & 10 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,23 @@
python_requires=">=3.7",
install_requires=[
"setuptools",
# -*- Extra requirements: -*-
"z3c.jbot",
"plone.api>=1.8.4",
"plone.app.dexterity",
"souper.plone",
"collective.honeypot>=2.1",
],
extras_require={
"test": [
"gocept.pytestlayer",
"plone.app.testing",
# Plone KGS does not use this version, because it would break
# Remove if your package shall be part of coredev.
# plone_coredev tests as of 2016-04-01.
"plone.testing>=5.0.0",
"plone.app.contenttypes",
"plone.app.robotframework[debug]",
"plone.restapi[test]",
"pytest-cov",
"pytest-plone>=0.2.0",
"pytest-docker",
"pytest-mock",
"pytest",
"zest.releaser[recommended]",
"zestreleaser.towncrier",
"pytest-mock",
"requests-mock",
],
},
entry_points="""
Expand Down
2 changes: 2 additions & 0 deletions src/collective/feedback/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<include package=".storage" />
<include package=".restapi" />
<include package=".upgrades" />


<genericsetup:registerProfile
name="default"
Expand Down
6 changes: 5 additions & 1 deletion src/collective/feedback/permissions.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
id="collective.feedback.AccessFeedbacks"
title="collective.feedback: Access Feedbacks"
/>
<permission
id="collective.feedback.FeedbacksOverview"
title="collective.feedback: Feedbacks Overview"
/>
</configure>

</configure>
3 changes: 2 additions & 1 deletion src/collective/feedback/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<metadata>
<version>1000</version>
<dependencies>
<!--<dependency>profile-plone.app.dexterity:default</dependency>-->
<dependency>profile-plone.restapi:default</dependency>
<dependency>profile-souper.plone:default</dependency>
</dependencies>
</metadata>
4 changes: 4 additions & 0 deletions src/collective/feedback/profiles/default/rolemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
<permission acquire="True"
name="collective.feedback: Access Feedbacks"
>
<role name="Editor" />
<role name="Manager" />
<role name="Site Administrator" />
</permission>

<permission acquire="True" name="collective.feedback: Feedbacks Overview">
<role name="Authenticated" />
</permission>
</permissions>
</rolemap>
4 changes: 2 additions & 2 deletions src/collective/feedback/restapi/services/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
method="GET"
factory=".get.FeedbackGet"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="collective.feedback.AccessFeedbacks"
permission="collective.feedback.FeedbacksOverview"
layer="collective.feedback.interfaces.ICollectiveFeedbackLayer"
name="@feedback"
/>
<plone:service
method="GET"
factory=".get.FeedbackGetCSV"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="collective.feedback.AccessFeedbacks"
permission="collective.feedback.FeedbacksOverview"
layer="collective.feedback.interfaces.ICollectiveFeedbackLayer"
name="@feedback-csv"
/>
Expand Down
71 changes: 39 additions & 32 deletions src/collective/feedback/restapi/services/get.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from AccessControl import Unauthorized
from AccessControl import Unauthorized
from collective.feedback.interfaces import ICollectiveFeedbackStore
from copy import deepcopy
from datetime import datetime
Expand All @@ -23,39 +24,35 @@ def __init__(self, context, request):
super().__init__(context, request)
self.params = []

def publishTraverse(self, request, name):
def publishTraverse(self, request, uid):
# Consume any path segments after /@users as parameters
self.params.append(name)
self.params.append(uid)
return self

def reply(self):
if self.params:
# single object detail
results = self.get_single_object_feedbacks(self.params[0])
batch = HypermediaBatch(self.request, results)
data = {
"@id": batch.canonical_url,
"items": [self.fix_fields(x, "date") for x in batch],
"items_total": batch.items_total,
}
links = batch.links
if links:
data["batching"] = links
else:
results = self.get_data()
batch = HypermediaBatch(self.request, results)
data = {
"@id": batch.canonical_url,
"items": [self.fix_fields(x, "last_vote") for x in batch],
"items_total": batch.items_total,
}
links = batch.links
if links:
data["batching"] = links
batch = HypermediaBatch(self.request, results)
data = {
"@id": batch.canonical_url,
"items": [self.fix_fields(data=x) for x in batch],
"items_total": batch.items_total,
}
links = batch.links
if links:
data["batching"] = links

return data

def fix_fields(self, data, param):
data[param] = json_compatible(data[param])
def fix_fields(self, data):
"""
Make data json compatible
"""
for k, v in data.items():
data[k] = json_compatible(v)
return data

def parse_query(self):
Expand All @@ -75,8 +72,10 @@ def parse_query(self):
res["query"] = query
return res

def get_commented_obj(self, record):
uid = record._attrs.get("uid", "")
def get_commented_obj(self, uid):
"""
Return obj based on uid.
"""
try:
obj = api.content.get(UID=uid)
except Unauthorized:
Expand All @@ -86,27 +85,33 @@ def get_commented_obj(self, record):
return

if not api.user.has_permission(
"rer.customersatisfaction: Access Customer Satisfaction", obj=obj
"collective.feedback: Access Feedbacks", obj=obj
):
# user does not have that permission on object
return

return obj

def get_single_object_feedbacks(self, uid):
"""
Return data for single object
"""
commented_object = self.get_commented_obj(uid=uid)
if not commented_object:
return []
tool = getUtility(ICollectiveFeedbackStore)
results = tool.search(query={"uid": uid})
feedbacks = []

for record in results:
feedbacks.append(
{
"uid": record._attrs.get("uid", ""),
"uid": uid,
"date": record._attrs.get("date", ""),
"vote": record._attrs.get("vote", ""),
"answer": record._attrs.get("answer", ""),
"comment": record._attrs.get("comment", ""),
"title": record._attrs.get("title", ""),
"title": commented_object.title,
}
)

Expand All @@ -127,12 +132,13 @@ def get_data(self):
uid = feedback._attrs.get("uid", "")
date = feedback._attrs.get("date", "")
vote = feedback._attrs.get("vote", "")

if uid not in feedbacks:
obj = self.get_commented_obj(record=feedback)
if not obj:
obj = self.get_commented_obj(uid=uid)
if not obj and not api.user.has_permission(
"collective.feedback: Show Deleted Feedbacks"
):
# only manager can list deleted object's reviews
continue

new_data = {
"vote_num": 0,
"vote_sum": 0,
Expand Down Expand Up @@ -212,7 +218,8 @@ def get_data(self):
columns = ["title", "url", "vote", "comment", "date", "answer"]

for item in tool.search():
obj = self.get_commented_obj(record=item)
uid = item._attrs.get("uid", "")
obj = self.get_commented_obj(uid=uid)
if not obj:
continue

Expand Down
42 changes: 19 additions & 23 deletions src/collective/feedback/testing.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
# -*- coding: utf-8 -*-
from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE
from plone.app.testing import applyProfile
from plone.app.testing import FunctionalTesting
from plone.app.testing import IntegrationTesting
from plone.app.testing import PLONE_FIXTURE
from plone.app.testing import PloneSandboxLayer
from plone.testing import z2
from plone.testing.zope import WSGI_SERVER_FIXTURE
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE

import collective.feedback
import plone.app.dexterity
import plone.restapi
import souper.plone
import collective.honeypot
import collective.honeypot.config

collective.honeypot.config.EXTRA_PROTECTED_ACTIONS = set(["feedback-add"])
collective.honeypot.config.HONEYPOT_FIELD = "honey"

class CollectiveFeedbackLayer(PloneSandboxLayer):
defaultBases = (PLONE_FIXTURE,)

class TestLayer(PloneSandboxLayer):
defaultBases = (PLONE_APP_CONTENTTYPES_FIXTURE,)

def setUpZope(self, app, configurationContext):
# Load any other ZCML that is required for your tests.
# The z3c.autoinclude feature is disabled in the Plone fixture base
# layer.

self.loadZCML(package=plone.app.dexterity)
self.loadZCML(package=plone.restapi)
self.loadZCML(package=collective.feedback)
self.loadZCML(package=collective.honeypot)
self.loadZCML(package=souper.plone)
self.loadZCML(package=collective.feedback)

def setUpPloneSite(self, portal):
applyProfile(portal, "collective.feedback:default")


COLLECTIVE_FEEDBACK_FIXTURE = CollectiveFeedbackLayer()
FIXTURE = TestLayer()


COLLECTIVE_FEEDBACK_INTEGRATION_TESTING = IntegrationTesting(
bases=(COLLECTIVE_FEEDBACK_FIXTURE,),
INTEGRATION_TESTING = IntegrationTesting(
bases=(FIXTURE,),
name="CollectiveFeedbackLayer:IntegrationTesting",
)


COLLECTIVE_FEEDBACK_FUNCTIONAL_TESTING = FunctionalTesting(
bases=(COLLECTIVE_FEEDBACK_FIXTURE,),
FUNCTIONAL_TESTING = FunctionalTesting(
bases=(FIXTURE,),
name="CollectiveFeedbackLayer:FunctionalTesting",
)


COLLECTIVE_FEEDBACK_ACCEPTANCE_TESTING = FunctionalTesting(
bases=(
COLLECTIVE_FEEDBACK_FIXTURE,
REMOTE_LIBRARY_BUNDLE_FIXTURE,
z2.ZSERVER_FIXTURE,
),
name="CollectiveFeedbackLayer:AcceptanceTesting",
RESTAPI_TESTING = FunctionalTesting(
bases=(FIXTURE, WSGI_SERVER_FIXTURE),
name="CollectiveFeedbackLayer:RestAPITesting",
)
Loading

0 comments on commit dc008a9

Please sign in to comment.