diff --git a/.github/workflows/bandit.yml b/.github/workflows/bandit.yml
new file mode 100644
index 0000000..0670805
--- /dev/null
+++ b/.github/workflows/bandit.yml
@@ -0,0 +1,24 @@
+name: Security check - Bandit
+
+on: push
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Security check - Bandit
+ uses: ioggstream/bandit-report-artifacts@v1.7.4
+ with:
+ project_path: src
+ # ignore_failure: true
+
+ # This is optional
+ #- name: Security check report artifacts
+ # uses: actions/upload-artifact@v4
+ # with:
+ # name: Security report
+ # path: output/security_report.txt
+
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..a3469b9
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,60 @@
+name: Tests
+
+on:
+ push:
+ paths-ignore:
+ - '**.md'
+ - '**.rst'
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ max-parallel: 4
+ matrix:
+ python: ["3.10", "3.11"]
+ plone: ["60"]
+ steps:
+ - uses: actions/checkout@v3
+ - name: Cache eggs
+ uses: actions/cache@v3
+ with:
+ path: eggs
+ key: ${{ runner.OS }}-build-python${{ matrix.python }}-${{ matrix.plone }}
+ - name: Set up Python ${{ matrix.python }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python }}
+ - name: Install dependencies
+ run: |
+ pip install -r requirements.txt -c constraints_plone${{ matrix.plone }}.txt
+ cp test_plone${{ matrix.plone }}.cfg buildout.cfg
+ - name: Install buildout
+ run: |
+ buildout -N code-analysis:return-status-codes=True
+ - name: Code analysis
+ run: |
+ bin/code-analysis
+ - name: Run tests
+ run: |
+ bin/test-coverage
+ env:
+ PROXY_BEARER_AUTH: on
+ #- name: Upload coverage data to coveralls.io
+ # run: |
+ # pip install coveralls
+ # coveralls --service=github
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # COVERALLS_FLAG_NAME: py${{ matrix.python }}-plone${{ matrix.plone }}-tz${{ matrix.tz }}
+ # COVERALLS_PARALLEL: true
+
+ #coveralls_finish:
+ # needs: build
+ # runs-on: ubuntu-latest
+ # steps:
+ # - name: Finished
+ # run: |
+ # pip install --upgrade coveralls
+ # coveralls --service=github --finish
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 3988bfb..70ae3c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.coverage
.coverage.*
+.python-version
*.egg-info
*.log
*.mo
@@ -12,6 +13,7 @@ bin/
buildout-cache/
develop-eggs/
eggs/
+extras/
htmlcov/
include/
lib/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 0bb2ac1..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-dist: bionic
-language: python
-cache:
- pip: true
- directories:
- - eggs
- - $HOME/buildout-cache
- - $HOME/.buildout
-python:
- - "2.7"
-matrix:
- include:
- - python: "2.7"
- env: PLONE_VERSION=43
- - python: "2.7"
- env: PLONE_VERSION=51
- - python: "2.7"
- env: PLONE_VERSION=52
- - python: "3.7"
- env: PLONE_VERSION=52
- fast_finish: true
-
-before_install:
- - mkdir -p $HOME/buildout-cache/{downloads,eggs,extends}
- - mkdir -p $HOME/.buildout
- - echo "[buildout]" > $HOME/.buildout/default.cfg
- - echo "download-cache = $HOME/buildout-cache/downloads" >> $HOME/.buildout/default.cfg
- - echo "eggs-directory = $HOME/buildout-cache/eggs" >> $HOME/.buildout/default.cfg
- - echo "extends-cache = $HOME/buildout-cache/extends" >> $HOME/.buildout/default.cfg
- - echo "abi-tag-eggs = true" >> $HOME/.buildout/default.cfg
- - git config --global user.email "travis@travis-ci.org"
- - git config --global user.name "Travis CI"
- - sudo apt-get install -y firefox-geckodriver
- - virtualenv -p `which python` .
- - bin/pip install -r requirements.txt -c constraints_plone$PLONE_VERSION.txt
- - cp test_plone$PLONE_VERSION.cfg buildout.cfg
-
-install:
- - travis_retry pip install -U tox coveralls coverage -c constraints.txt
-
-before_script:
- - 'export DISPLAY=:99.0'
- - export VERBOSE=true
- - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- - sleep 3
-
-script:
- - PYTEST_ADDOPTS="-s -vv" tox
-
-after_success:
- - python -m coverage.pickle2json
- - coverage combine
- - coveralls
-
-notifications:
- email:
- recipients:
-# - travis-reports@plone.com
- - {author}
- on_success: change
- on_failure: change
diff --git a/README.md b/README.md
deleted file mode 100644
index 783446c..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# iosanita.policy
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 22254c0..3eb91f9 100644
--- a/README.rst
+++ b/README.rst
@@ -27,43 +27,75 @@
:alt: License
-===============
-iosanita.policy
-===============
+=======================
+IO-Sanita policy
+=======================
-An add-on for Plone
+Policy per il backend dei portali Io-Sanita.
-Features
---------
+Questo pacchetto si occupa di installare tutte le dipendenze necessarie per il progetto.
-- Can be bullet points
+Rotte API
+=========
-Examples
---------
+@search-tassonomie
+------------------
-This add-on can be seen in action at the following sites:
-- Is there a page on the internet where everybody can see the features?
+Endpoint che serve a ricercare i contenuti marcati da una determinata tassonomia.
+Parametri:
-Documentation
--------------
+- **type** (obbligatorio): il nome dell'indice in catalogo della tassonomia
+- **value**: un eventuale valore per filtrare l'indice
+- **portal_type**: un filtro su uno specifico portal_type
+- **sort_on**: permette di ordinare i risultati in base ad un determinato indice
+- **sort_order**: permette di scegliere l'ordinamento da usare
-Full documentation for end users can be found in the "docs" folder, and is also available online at http://docs.plone.org/foo/bar
+Le tassonomie (*type*) utilizzabili sono limitate:
+- parliamo_di
+- a_chi_si_rivolge_tassonomia
-Translations
-------------
+Esempio di chiamata::
-This product has been translated into
+ > http://localhost:8080/Plone/++api++/@search-tassonomie?type=a_chi_si_rivolge_tassonomia
-- Klingon (thanks, K'Plai)
+Risposta::
-Installation
-------------
+ {
+ "@id": "http://localhost:8080/Plone/++api++/@search-tassonomie?type=a_chi_si_rivolge_tassonomia",
+ "facets": {
+ "portal_types": [
+ {
+ "title": "Struttura",
+ "token": "Struttura"
+ }
+ ]
+ },
+ "items": [
+ {
+ "@id": "http://localhost:8080/Plone/struttura",
+ "@type": "Struttura",
+ "description": "",
+ "enhanced_links_enabled": null,
+ "getObjSize": "0 KB",
+ "image_field": "",
+ "image_scales": null,
+ "mime_type": "text/plain",
+ "review_state": "private",
+ "title": "struttura",
+ "type_title": "Struttura"
+ }
+ ],
+ "items_total": 1
+ }
-Install iosanita.policy by adding it to your buildout::
+Installazione
+=============
+
+Per installare iosanita.policy bisogna per prima cosa aggiungerlo al buildout::
[buildout]
@@ -73,39 +105,28 @@ Install iosanita.policy by adding it to your buildout::
iosanita.policy
-and then running ``bin/buildout``
-
-
-Authors
--------
-
-Provided by awesome people ;)
-
-
-Contributors
-------------
-
-Put your name here, you deserve it!
+e poi lanciare il buildout con ``bin/buildout``.
-- ?
+Successivamente va installato dal pannello di controllo di Plone.
-Contribute
-----------
+Contribuisci
+============
-- Issue Tracker: https://github.com/collective/iosanita.policy/issues
-- Source Code: https://github.com/collective/iosanita.policy
-- Documentation: https://docs.plone.org/foo/bar
+- Issue Tracker: https://github.com/redturtle/iosanita.policy/issues
+- Codice sorgente: https://github.com/redturtle/iosanita.policy
-Support
--------
+Licenza
+=======
-If you are having issues, please let us know.
-We have a mailing list located at: project@example.com
+Questo progetto è rilasciato con licenza GPLv2.
+Autori
+======
-License
--------
+Questo progetto è stato sviluppato da **RedTurtle Technology**.
-The project is licensed under the GPLv2.
+.. image:: https://avatars1.githubusercontent.com/u/1087171?s=100&v=4
+ :alt: RedTurtle Technology Site
+ :target: http://www.redturtle.it/
diff --git a/base.cfg b/base.cfg
index c39bc16..f111a8f 100644
--- a/base.cfg
+++ b/base.cfg
@@ -7,7 +7,7 @@ parts =
instance
test
# we use tox for testing and linting, by default
-# code-analysis
+ code-analysis
coverage
test-coverage
createcoverage
@@ -19,7 +19,9 @@ parts =
vscode
develop = .
-
+sources-dir = extras
+auto-checkout = *
+always-checkout = force
[instance]
recipe = plone.recipe.zope2instance
@@ -37,10 +39,10 @@ recipe = collective.recipe.vscode
eggs = ${instance:eggs}
autocomplete-use-omelette = True
-# [code-analysis]
-# recipe = plone.recipe.codeanalysis
-# directory = ${buildout:directory}/src/iosanita
-# return-status-codes = False
+[code-analysis]
+recipe = plone.recipe.codeanalysis
+directory = ${buildout:directory}/src/iosanita
+return-status-codes = False
[omelette]
@@ -68,7 +70,7 @@ input = inline:
export TZ=UTC
${buildout:directory}/bin/coverage run bin/test $*
${buildout:directory}/bin/coverage html
- ${buildout:directory}/bin/coverage report -m --fail-under=90
+ ${buildout:directory}/bin/coverage report -m --fail-under=30
# Fail (exit status 1) if coverage returns exit status 2 (this happens
# when test coverage is below 100%.
output = ${buildout:directory}/bin/test-coverage
@@ -109,3 +111,7 @@ scripts =
[versions]
# Don't use a released version of iosanita.policy
iosanita.policy =
+setuptools =
+
+[sources]
+iosanita.contenttypes = git https://github.com/RedTurtle/iosanita.contenttypes.git
diff --git a/setup.cfg b/setup.cfg
index 7f3f5c2..bd9250c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,8 +6,13 @@ ignore =
.gitattributes
[isort]
-# black compatible isort rules:
-profile = plone
+# for details see
+# http://docs.plone.org/develop/styleguide/python.html#grouping-and-sorting
+force_alphabetical_sort = True
+force_single_line = True
+lines_after_imports = 2
+line_length = 200
+not_skip = __init__.py
[flake8]
# black compatible flake8 rules:
@@ -17,11 +22,10 @@ ignore =
E501
T001
C813
- C101
# E203, E266
exclude = bootstrap.py,docs,*.egg.,omelette
max-line-length = 88
max-complexity = 18
select = B,C,E,F,W,T4,B9
-
builtins = unicode,basestring
+
diff --git a/setup.py b/setup.py
index c23a0a8..04c7741 100644
--- a/setup.py
+++ b/setup.py
@@ -54,12 +54,10 @@
install_requires=[
"setuptools",
# -*- Extra requirements: -*-
- "z3c.jbot",
"plone.api>=1.8.4",
- "plone.app.dexterity",
- "redturtle.volto",
"iosanita.contenttypes",
"collective.volto.enhancedlinks",
+ "collective.feedback",
],
extras_require={
"test": [
@@ -70,6 +68,7 @@
"plone.testing>=5.0.0",
"plone.app.contenttypes",
"plone.app.robotframework[debug]",
+ "collective.MockMailHost",
],
},
entry_points="""
diff --git a/src/.bandit b/src/.bandit
new file mode 100644
index 0000000..0a55d30
--- /dev/null
+++ b/src/.bandit
@@ -0,0 +1,3 @@
+[bandit]
+exclude = locales,tests
+skips = B410
diff --git a/src/iosanita/policy/browser/configure.zcml b/src/iosanita/policy/browser/configure.zcml
deleted file mode 100644
index 110e09c..0000000
--- a/src/iosanita/policy/browser/configure.zcml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/iosanita/policy/configure.zcml b/src/iosanita/policy/configure.zcml
index 18d0701..be84805 100644
--- a/src/iosanita/policy/configure.zcml
+++ b/src/iosanita/policy/configure.zcml
@@ -14,13 +14,14 @@
-->
-
+
+
1000
- profile-redturtle.volto:default
profile-iosanita.contenttypes:default
profile-collective.volto.enhancedlinks:default
+ profile-collective.feedback:default
diff --git a/src/iosanita/policy/browser/__init__.py b/src/iosanita/policy/restapi/__init__.py
similarity index 100%
rename from src/iosanita/policy/browser/__init__.py
rename to src/iosanita/policy/restapi/__init__.py
diff --git a/src/iosanita/policy/restapi/configure.zcml b/src/iosanita/policy/restapi/configure.zcml
new file mode 100644
index 0000000..64be82b
--- /dev/null
+++ b/src/iosanita/policy/restapi/configure.zcml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/src/iosanita/policy/browser/overrides/.gitkeep b/src/iosanita/policy/restapi/services/__init__.py
similarity index 100%
rename from src/iosanita/policy/browser/overrides/.gitkeep
rename to src/iosanita/policy/restapi/services/__init__.py
diff --git a/src/iosanita/policy/restapi/services/configure.zcml b/src/iosanita/policy/restapi/services/configure.zcml
new file mode 100644
index 0000000..3cb15f6
--- /dev/null
+++ b/src/iosanita/policy/restapi/services/configure.zcml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/src/iosanita/policy/browser/static/.gitkeep b/src/iosanita/policy/restapi/services/search_tassonomie/__init__.py
similarity index 100%
rename from src/iosanita/policy/browser/static/.gitkeep
rename to src/iosanita/policy/restapi/services/search_tassonomie/__init__.py
diff --git a/src/iosanita/policy/restapi/services/search_tassonomie/configure.zcml b/src/iosanita/policy/restapi/services/search_tassonomie/configure.zcml
new file mode 100644
index 0000000..5655944
--- /dev/null
+++ b/src/iosanita/policy/restapi/services/search_tassonomie/configure.zcml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/iosanita/policy/restapi/services/search_tassonomie/get.py b/src/iosanita/policy/restapi/services/search_tassonomie/get.py
new file mode 100644
index 0000000..a33cc10
--- /dev/null
+++ b/src/iosanita/policy/restapi/services/search_tassonomie/get.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+from iosanita.policy import _
+from plone import api
+from plone.restapi.batching import HypermediaBatch
+from plone.restapi.interfaces import ISerializeToJsonSummary
+from plone.restapi.services import Service
+from zExceptions import BadRequest
+from zope.component import getMultiAdapter
+from zope.component import getUtility
+from zope.schema.interfaces import IVocabularyFactory
+
+
+ALLOWED_TAXONOMIES = ["parliamo_di", "a_chi_si_rivolge_tassonomia"]
+
+BASE_FILTERS = [
+ "portal_type",
+ "sort_on",
+ "sort_order",
+ "fullobjects",
+ "b_start",
+ "b_size",
+]
+
+
+class SearchTassonomieGet(Service):
+ def reply(self):
+ index = self.request.form.get("type", "")
+ value = self.request.form.get("value", "")
+
+ if not index:
+ raise BadRequest(
+ api.portal.translate(
+ _("missing_parameter_type_error", default="Missing parameter: type")
+ )
+ )
+ if index not in ALLOWED_TAXONOMIES:
+ raise BadRequest(
+ api.portal.translate(
+ _(
+ "unknown_index_error",
+ default="Unkwnown taxonomy: ${index}",
+ mapping={"index": index},
+ )
+ )
+ )
+ pc = api.portal.get_tool(name="portal_catalog")
+ query = {}
+
+ # add standard query filters
+ for query_index in BASE_FILTERS:
+ value_index = self.request.form.get(query_index, "")
+ if value_index:
+ query[query_index] = value_index
+
+ # then filter by taxonomy
+ all_values = pc.uniqueValuesFor(index)
+
+ if value:
+ query[index] = value
+ else:
+ # return all
+ query[index] = all_values
+
+ # and do search
+ brains = api.content.find(**query)
+ batch = HypermediaBatch(self.request, brains)
+ results = {}
+ results["@id"] = batch.canonical_url
+ results["items_total"] = batch.items_total
+ links = batch.links
+ if links:
+ results["batching"] = links
+
+ results["items"] = []
+ for brain in batch:
+ result = getMultiAdapter((brain, self.request), ISerializeToJsonSummary)()
+ if result:
+ results["items"].append(result)
+
+ # add facets
+ results["facets"] = self.get_facets(query={index: query[index]})
+ return results
+
+ def get_facets(self, query):
+ """
+ return search facets
+ """
+ portal_types = []
+ for brain in api.content.find(**query):
+ if brain.portal_type not in portal_types:
+ portal_types.append(brain.portal_type)
+
+ facets = {}
+
+ factory = getUtility(
+ IVocabularyFactory, "plone.app.vocabularies.ReallyUserFriendlyTypes"
+ )
+ vocabulary = factory(api.portal.get())
+ portal_types_dict = []
+ for ptype in portal_types:
+ try:
+ title = vocabulary.getTerm(ptype).title
+ except LookupError:
+ title = ptype
+ portal_types_dict.append({"title": title, "token": ptype})
+ facets["portal_types"] = sorted(portal_types_dict, key=lambda x: x["title"])
+ return facets
diff --git a/src/iosanita/policy/testing.py b/src/iosanita/policy/testing.py
index 78ef1d7..538f358 100644
--- a/src/iosanita/policy/testing.py
+++ b/src/iosanita/policy/testing.py
@@ -1,55 +1,55 @@
# -*- coding: utf-8 -*-
-from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE
+from iosanita.contenttypes.testing import TestLayer as ContentTypesTestLayer
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 zope.configuration import xmlconfig
+import collective.feedback
+import collective.volto.enhancedlinks
+import iosanita.contenttypes
import iosanita.policy
+import souper.plone
+import plone.app.caching
-class IosanitaPolicyLayer(PloneSandboxLayer):
-
- defaultBases = (PLONE_FIXTURE,)
-
+class TestLayer(ContentTypesTestLayer):
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.
- import plone.app.dexterity
-
- self.loadZCML(package=plone.app.dexterity)
- import plone.restapi
-
- self.loadZCML(package=plone.restapi)
- self.loadZCML(package=iosanita.policy)
+ super().setUpZope(app, configurationContext)
+ self.loadZCML(package=plone.app.caching)
+ self.loadZCML(package=iosanita.contenttypes)
+ self.loadZCML(package=collective.volto.enhancedlinks)
+ self.loadZCML(package=collective.feedback)
+ self.loadZCML(package=souper.plone)
+ self.loadZCML(package=iosanita.policy, context=configurationContext)
+
+ xmlconfig.file(
+ "configure.zcml",
+ iosanita.policy,
+ context=configurationContext,
+ )
def setUpPloneSite(self, portal):
+ applyProfile(portal, "plone.app.caching:default")
applyProfile(portal, "iosanita.policy:default")
-IOSANITA_POLICY_FIXTURE = IosanitaPolicyLayer()
+FIXTURE = TestLayer()
-IOSANITA_POLICY_INTEGRATION_TESTING = IntegrationTesting(
- bases=(IOSANITA_POLICY_FIXTURE,),
- name="IosanitaPolicyLayer:IntegrationTesting",
+INTEGRATION_TESTING = IntegrationTesting(
+ bases=(FIXTURE,),
+ name="IoSanitaPolicyLayer:IntegrationTesting",
)
-IOSANITA_POLICY_FUNCTIONAL_TESTING = FunctionalTesting(
- bases=(IOSANITA_POLICY_FIXTURE,),
- name="IosanitaPolicyLayer:FunctionalTesting",
+FUNCTIONAL_TESTING = FunctionalTesting(
+ bases=(FIXTURE,),
+ name="IoSanitaPolicyLayer:FunctionalTesting",
)
-
-IOSANITA_POLICY_ACCEPTANCE_TESTING = FunctionalTesting(
- bases=(
- IOSANITA_POLICY_FIXTURE,
- REMOTE_LIBRARY_BUNDLE_FIXTURE,
- z2.ZSERVER_FIXTURE,
- ),
- name="IosanitaPolicyLayer:AcceptanceTesting",
+RESTAPI_TESTING = FunctionalTesting(
+ bases=(FIXTURE, WSGI_SERVER_FIXTURE),
+ name="IoSanitaPolicyLayer:RestAPITesting",
)
diff --git a/src/iosanita/policy/tests/robot/test_example.robot b/src/iosanita/policy/tests/robot/test_example.robot
deleted file mode 100644
index 1e5c5b7..0000000
--- a/src/iosanita/policy/tests/robot/test_example.robot
+++ /dev/null
@@ -1,66 +0,0 @@
-# ============================================================================
-# EXAMPLE ROBOT TESTS
-# ============================================================================
-#
-# Run this robot test stand-alone:
-#
-# $ bin/test -s iosanita.policy -t test_example.robot --all
-#
-# Run this robot test with robot server (which is faster):
-#
-# 1) Start robot server:
-#
-# $ bin/robot-server --reload-path src iosanita.policy.testing.IOSANITA_POLICY_ACCEPTANCE_TESTING
-#
-# 2) Run robot tests:
-#
-# $ bin/robot src/iosanita/policy/tests/robot/test_example.robot
-#
-# See the http://docs.plone.org for further details (search for robot
-# framework).
-#
-# ============================================================================
-
-*** Settings *****************************************************************
-
-Resource plone/app/robotframework/selenium.robot
-Resource plone/app/robotframework/keywords.robot
-
-Library Remote ${PLONE_URL}/RobotRemote
-
-Test Setup Open test browser
-Test Teardown Close all browsers
-
-
-*** Test Cases ***************************************************************
-
-Scenario: As a member I want to be able to log into the website
- [Documentation] Example of a BDD-style (Behavior-driven development) test.
- Given a login form
- When I enter valid credentials
- Then I am logged in
-
-
-*** Keywords *****************************************************************
-
-# --- Given ------------------------------------------------------------------
-
-a login form
- Go To ${PLONE_URL}/login_form
- Wait until page contains Login Name
- Wait until page contains Password
-
-
-# --- WHEN -------------------------------------------------------------------
-
-I enter valid credentials
- Input Text __ac_name admin
- Input Text __ac_password secret
- Click Button Log in
-
-
-# --- THEN -------------------------------------------------------------------
-
-I am logged in
- Wait until page contains You are now logged in
- Page should contain You are now logged in
diff --git a/src/iosanita/policy/tests/test_robot.py b/src/iosanita/policy/tests/test_robot.py
deleted file mode 100644
index ee853b1..0000000
--- a/src/iosanita/policy/tests/test_robot.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- coding: utf-8 -*-
-from iosanita.policy.testing import IOSANITA_POLICY_ACCEPTANCE_TESTING # noqa: E501
-from plone.app.testing import ROBOT_TEST_LEVEL
-from plone.testing import layered
-
-import os
-import robotsuite
-import unittest
-
-
-def test_suite():
- suite = unittest.TestSuite()
- current_dir = os.path.abspath(os.path.dirname(__file__))
- robot_dir = os.path.join(current_dir, "robot")
- robot_tests = [
- os.path.join("robot", doc)
- for doc in os.listdir(robot_dir)
- if doc.endswith(".robot") and doc.startswith("test_")
- ]
- for robot_test in robot_tests:
- robottestsuite = robotsuite.RobotTestSuite(robot_test)
- robottestsuite.level = ROBOT_TEST_LEVEL
- suite.addTests(
- [
- layered(
- robottestsuite,
- layer=IOSANITA_POLICY_ACCEPTANCE_TESTING,
- ),
- ]
- )
- return suite
diff --git a/src/iosanita/policy/tests/test_search_tassonomie.py b/src/iosanita/policy/tests/test_search_tassonomie.py
new file mode 100644
index 0000000..76cbe3c
--- /dev/null
+++ b/src/iosanita/policy/tests/test_search_tassonomie.py
@@ -0,0 +1,131 @@
+# -*- coding: utf-8 -*-
+"""Setup tests for this package."""
+from iosanita.policy.testing import RESTAPI_TESTING
+from plone import api
+from plone.app.testing import setRoles
+from plone.app.testing import SITE_OWNER_NAME
+from plone.app.testing import SITE_OWNER_PASSWORD
+from plone.app.testing import TEST_USER_ID
+from plone.restapi.testing import RelativeSession
+from transaction import commit
+
+import unittest
+
+
+class TestStrutturaSchema(unittest.TestCase):
+ layer = RESTAPI_TESTING
+
+ def setUp(self):
+ self.app = self.layer["app"]
+ self.portal = self.layer["portal"]
+ self.request = self.layer["request"]
+ self.portal_url = self.portal.absolute_url()
+ setRoles(self.portal, TEST_USER_ID, ["Manager"])
+
+ 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.news = api.content.create(
+ container=self.portal,
+ type="News Item",
+ title="Test news",
+ parliamo_di=["Alimentazione", "Donazione organi e sangue"],
+ a_chi_si_rivolge_tassonomia=["bambini"],
+ )
+ self.event = api.content.create(
+ container=self.portal,
+ type="Event",
+ title="Test Event",
+ parliamo_di=["Alimentazione"],
+ a_chi_si_rivolge_tassonomia=["foo"],
+ )
+
+ commit()
+
+ def tearDown(self):
+ self.api_session.close()
+
+ def test_endpoint_reply_bad_request_if_missing_parameter(self):
+ res = self.api_session.get("@search-tassonomie")
+ self.assertEqual(res.status_code, 400)
+ self.assertEqual(res.json()["message"], "Missing parameter: type")
+
+ def test_passing_type_reply_all_results(self):
+ res = self.api_session.get("@search-tassonomie?type=parliamo_di").json()
+
+ self.assertEqual(res["items_total"], 2)
+ self.assertEqual(res["items"][0]["title"], self.news.title)
+ self.assertEqual(res["items"][1]["title"], self.event.title)
+
+ def test_passing_sort_order_reply_sorted_results(self):
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&sort_on=sortable_title"
+ ).json()
+
+ self.assertEqual(res["items_total"], 2)
+ self.assertEqual(res["items"][0]["title"], self.event.title)
+ self.assertEqual(res["items"][1]["title"], self.news.title)
+
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&sort_on=sortable_title&sort_order=descending"
+ ).json()
+
+ self.assertEqual(res["items_total"], 2)
+ self.assertEqual(res["items"][0]["title"], self.news.title)
+ self.assertEqual(res["items"][1]["title"], self.event.title)
+
+ def test_passing_type_and_value_reply_filtered_results(self):
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&value=Alimentazione"
+ ).json()
+
+ self.assertEqual(res["items_total"], 2)
+ self.assertEqual(res["items"][0]["title"], self.news.title)
+ self.assertEqual(res["items"][1]["title"], self.event.title)
+
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&value=Donazione organi e sangue"
+ ).json()
+
+ self.assertEqual(res["items_total"], 1)
+ self.assertEqual(res["items"][0]["title"], self.news.title)
+
+ def test_passing_not_accepted_index_reply_bad_request(self):
+ res = self.api_session.get("@search-tassonomie?type=xxx")
+ self.assertEqual(res.status_code, 400)
+ self.assertEqual(res.json()["message"], "Unkwnown taxonomy: xxx")
+
+ def test_if_content_has_wrong_value_it_has_not_been_indexed(self):
+ res = self.api_session.get(
+ "@search-tassonomie?type=a_chi_si_rivolge_tassonomia&value=foo"
+ ).json()
+ self.assertEqual(res["items_total"], 0)
+
+ res = self.api_session.get(
+ "@search-tassonomie?type=a_chi_si_rivolge_tassonomia&value=bambini"
+ ).json()
+ self.assertEqual(res["items_total"], 1)
+
+ def test_endpoint_reply_facets_for_all_portal_types_with_at_least_one_reference(
+ self,
+ ):
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&value=Alimentazione"
+ ).json()
+
+ self.assertEqual(len(res["facets"]["portal_types"]), 2)
+ self.assertEqual(res["facets"]["portal_types"][0]["token"], "Event")
+ self.assertEqual(res["facets"]["portal_types"][1]["token"], "News Item")
+
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&value=Alimentazione"
+ ).json()
+ self.assertEqual(len(res["facets"]["portal_types"]), 2)
+ self.assertEqual(res["facets"]["portal_types"][0]["token"], "Event")
+ self.assertEqual(res["facets"]["portal_types"][1]["token"], "News Item")
+
+ res = self.api_session.get(
+ "@search-tassonomie?type=parliamo_di&value=xxx"
+ ).json()
+ self.assertEqual(len(res["facets"]["portal_types"]), 0)
diff --git a/src/iosanita/policy/tests/test_setup.py b/src/iosanita/policy/tests/test_setup.py
deleted file mode 100644
index 68436f7..0000000
--- a/src/iosanita/policy/tests/test_setup.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Setup tests for this package."""
-from iosanita.policy.testing import IOSANITA_POLICY_INTEGRATION_TESTING # noqa: E501
-from plone import api
-from plone.app.testing import setRoles
-from plone.app.testing import TEST_USER_ID
-
-import unittest
-
-
-try:
- from Products.CMFPlone.utils import get_installer
-except ImportError:
- get_installer = None
-
-
-class TestSetup(unittest.TestCase):
- """Test that iosanita.policy is properly installed."""
-
- layer = IOSANITA_POLICY_INTEGRATION_TESTING
-
- def setUp(self):
- """Custom shared utility setup for tests."""
- self.portal = self.layer["portal"]
- if get_installer:
- self.installer = get_installer(self.portal, self.layer["request"])
- else:
- self.installer = api.portal.get_tool("portal_quickinstaller")
-
- def test_product_installed(self):
- """Test if iosanita.policy is installed."""
- self.assertTrue(self.installer.is_product_installed("iosanita.policy"))
-
- def test_browserlayer(self):
- """Test that IIosanitaPolicyLayer is registered."""
- from iosanita.policy.interfaces import IIosanitaPolicyLayer
- from plone.browserlayer import utils
-
- self.assertIn(IIosanitaPolicyLayer, utils.registered_layers())
-
-
-class TestUninstall(unittest.TestCase):
-
- layer = IOSANITA_POLICY_INTEGRATION_TESTING
-
- def setUp(self):
- self.portal = self.layer["portal"]
- if get_installer:
- self.installer = get_installer(self.portal, self.layer["request"])
- else:
- self.installer = api.portal.get_tool("portal_quickinstaller")
- roles_before = api.user.get_roles(TEST_USER_ID)
- setRoles(self.portal, TEST_USER_ID, ["Manager"])
- self.installer.uninstall_product("iosanita.policy")
- setRoles(self.portal, TEST_USER_ID, roles_before)
-
- def test_product_uninstalled(self):
- """Test if iosanita.policy is cleanly uninstalled."""
- self.assertFalse(self.installer.is_product_installed("iosanita.policy"))
-
- def test_browserlayer_removed(self):
- """Test that IIosanitaPolicyLayer is removed."""
- from iosanita.policy.interfaces import IIosanitaPolicyLayer
- from plone.browserlayer import utils
-
- self.assertNotIn(IIosanitaPolicyLayer, utils.registered_layers())
diff --git a/test_plone60.cfg b/test_plone60.cfg
index d56cb6d..5dbc994 100644
--- a/test_plone60.cfg
+++ b/test_plone60.cfg
@@ -10,3 +10,130 @@ update-versions-file = test_plone60.cfg
[versions]
createcoverage = 1.5
watchdog = 2.1.6
+
+# Added by buildout at 2024-07-17 17:06:40.682096
+build = 1.2.1
+cmarkgfm = 2024.1.14
+collective.geolocationbehavior = 1.7.2
+collective.honeypot = 2.1
+collective.venue = 4.1
+coverage = 7.5.4
+flake8 = 6.1.0
+geographiclib = 2.0
+geopy = 2.4.1
+i18ndude = 6.2.0
+keyring = 25.2.1
+kitconcept.seo = 2.1.0
+markdown-it-py = 3.0.0
+mccabe = 0.7.0
+mdurl = 0.1.2
+nh3 = 0.2.17
+node = 1.2.1
+odict = 1.9.0
+pkginfo = 1.10.0
+plone.formwidget.geolocation = 3.0.6
+plone.recipe.codeanalysis = 3.0.1
+plumber = 1.7
+pycodestyle = 2.11.0
+pyflakes = 3.1.0
+pyproject-hooks = 1.1.0
+readme-renderer = 43.0
+repoze.catalog = 0.9.0
+requests-toolbelt = 1.0.0
+rfc3986 = 2.0.0
+rich = 13.7.1
+twine = 5.1.1
+zest.releaser = 9.2.0
+zope.index = 6.0
+
+# Required by:
+# jaraco.context==5.3.0
+backports.tarfile = 1.2.0
+
+# Required by:
+# plone.recipe.codeanalysis==3.0.1
+check-manifest = 0.49
+
+# Required by:
+# collective.venue==4.1
+collective.address = 1.6
+
+# Required by:
+# iosanita.policy==1.0.0.dev0
+collective.feedback = 1.1.3
+
+# Required by:
+# redturtle.volto==5.5.0
+collective.purgebyid = 1.2.2
+
+# Required by:
+# iosanita.contenttypes==2.0.0.dev0
+collective.taxonomy = 3.1.1
+
+# Required by:
+# iosanita.contenttypes==2.0.0.dev0
+collective.volto.blocksfield = 2.0.0
+
+# Required by:
+# redturtle.volto==5.5.0
+collective.volto.cookieconsent = 1.1.1
+
+# Required by:
+# iosanita.policy==1.0.0.dev0
+collective.volto.enhancedlinks = 1.1.1
+
+# Required by:
+# redturtle.volto==5.5.0
+collective.volto.gdprcookie = 1.0.3
+
+# Required by:
+# redturtle.volto==5.5.0
+collective.volto.sitesettings = 1.0.1
+
+# Required by:
+# iosanita.contenttypes==2.0.0.dev0
+collective.z3cform.datagridfield = 3.0.2
+
+# Required by:
+# keyring==25.2.1
+jaraco.classes = 3.4.0
+
+# Required by:
+# keyring==25.2.1
+jaraco.context = 5.3.0
+
+# Required by:
+# keyring==25.2.1
+jaraco.functools = 4.0.1
+
+# Required by:
+# jaraco.classes==3.4.0
+# jaraco.functools==4.0.1
+more-itertools = 10.3.0
+
+# Required by:
+# souper==1.1.2
+node.ext.zodb = 1.6
+
+# Required by:
+# collective.address==1.6
+pycountry = 24.6.1
+
+# Required by:
+# iosanita.contenttypes==2.0.0.dev0
+# iosanita.policy==1.0.0.dev0
+redturtle.volto = 5.5.0
+
+# Required by:
+# souper.plone==1.3.1
+souper = 1.1.2
+
+# Required by:
+# collective.feedback==1.1.3
+souper.plone = 1.3.1
+
+# Required by:
+# iosanita.contenttypes==2.0.0.dev0
+# iosanita.policy==1.0.0.dev0
+# redturtle.volto==5.5.0
+z3c.jbot = 2.0