From a9b4383137eadc0f89ae10b84edee2a5a13dcac0 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 23 Jul 2024 09:41:28 +0200 Subject: [PATCH] Cekk refactoring (#1) * add restapi endpoint and fix ci * fix endpoint name * enable sorting * code cleanup * fix: endpoint serch_tassonomie param value * add bandit file * remove dependency * remove branch * typo * remove unused folder and fix tests * fail under 30 --------- Co-authored-by: Giulia Ghisini Co-authored-by: Mauro Amico --- .github/workflows/bandit.yml | 24 ++++ .github/workflows/tests.yml | 60 ++++++++ .gitignore | 2 + .travis.yml | 61 -------- README.md | 1 - README.rst | 115 ++++++++------- base.cfg | 20 ++- setup.cfg | 12 +- setup.py | 5 +- src/.bandit | 3 + src/iosanita/policy/browser/configure.zcml | 25 ---- src/iosanita/policy/configure.zcml | 7 +- .../policy/profiles/default/metadata.xml | 2 +- .../policy/{browser => restapi}/__init__.py | 0 src/iosanita/policy/restapi/configure.zcml | 12 ++ .../.gitkeep => restapi/services/__init__.py} | 0 .../policy/restapi/services/configure.zcml | 9 ++ .../services/search_tassonomie/__init__.py} | 0 .../services/search_tassonomie/configure.zcml | 16 +++ .../restapi/services/search_tassonomie/get.py | 107 ++++++++++++++ src/iosanita/policy/testing.py | 66 ++++----- .../policy/tests/robot/test_example.robot | 66 --------- src/iosanita/policy/tests/test_robot.py | 31 ----- .../policy/tests/test_search_tassonomie.py | 131 ++++++++++++++++++ src/iosanita/policy/tests/test_setup.py | 66 --------- test_plone60.cfg | 127 +++++++++++++++++ 26 files changed, 620 insertions(+), 348 deletions(-) create mode 100644 .github/workflows/bandit.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml delete mode 100644 README.md create mode 100644 src/.bandit delete mode 100644 src/iosanita/policy/browser/configure.zcml rename src/iosanita/policy/{browser => restapi}/__init__.py (100%) create mode 100644 src/iosanita/policy/restapi/configure.zcml rename src/iosanita/policy/{browser/overrides/.gitkeep => restapi/services/__init__.py} (100%) create mode 100644 src/iosanita/policy/restapi/services/configure.zcml rename src/iosanita/policy/{browser/static/.gitkeep => restapi/services/search_tassonomie/__init__.py} (100%) create mode 100644 src/iosanita/policy/restapi/services/search_tassonomie/configure.zcml create mode 100644 src/iosanita/policy/restapi/services/search_tassonomie/get.py delete mode 100644 src/iosanita/policy/tests/robot/test_example.robot delete mode 100644 src/iosanita/policy/tests/test_robot.py create mode 100644 src/iosanita/policy/tests/test_search_tassonomie.py delete mode 100644 src/iosanita/policy/tests/test_setup.py 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