diff --git a/last_commit.txt b/last_commit.txt index 9999a2400b..4dcdf15820 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,49 +1,26 @@ -Repository: plone.rest +Repository: plone.restapi Branch: refs/heads/main -Date: 2023-10-28T22:14:31+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.rest/commit/8fdc78cd1420898d6ac954b5946f725ab63b33b3 +Date: 2023-10-28T22:15:39+02:00 +Author: Maurits van Rees (mauritsvanrees) +Commit: https://github.com/plone/plone.restapi/commit/f37cd9cbbe1d84d592e36ed71fd345140bf97991 -Config with default template (#150) +Be more strict when checking if mimetype is allowed inline. (#1724) -* Configuring with plone/meta +* Be more strict when checking if mimetype is allowed to be displayed inline. -* feat: drop GHA replaced by pre-commit.ci +This takes over some code from https://github.com/zopefoundation/Zope/pull/1167. +See also https://github.com/plone/plone.namedfile/pull/154 -* chore: zpretty +* Copy a test for extract_media_type from Zope. -* feat: drop six usage - -* feat: drop old pkgutil namespace - -* chore: keep try/except imports last - -* feat: declare dependencies +* Rename extract_media_type to _extract_media_type to signal it as private. Files changed: -A .editorconfig -A .github/workflows/meta.yml -A .meta.toml -A news/93e1ab65.internal -A tox.ini -M .flake8 -M .gitignore -M .pre-commit-config.yaml -M pyproject.toml -M setup.py -M src/plone/__init__.py -M src/plone/rest/configure.zcml -M src/plone/rest/errors.py -M src/plone/rest/meta.zcml -M src/plone/rest/patches.zcml -M src/plone/rest/testing.zcml -D .github/workflows/black.yml -D .github/workflows/flake8.yml -D .github/workflows/pyroma.yml -D .github/workflows/zpretty.yml -D setup.cfg +A news/1167.bugfix +M src/plone/restapi/services/users/get.py +M src/plone/restapi/tests/test_services_users.py -b'diff --git a/.editorconfig b/.editorconfig\nnew file mode 100644\nindex 0000000..8ae05aa\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,54 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+#\n+# EditorConfig Configuration file, for more details see:\n+# http://EditorConfig.org\n+# EditorConfig is a convention description, that could be interpreted\n+# by multiple editors to enforce common coding conventions for specific\n+# file types\n+\n+# top-most EditorConfig file:\n+# Will ignore other EditorConfig files in Home directory or upper tree level.\n+root = true\n+\n+\n+[*] # For All Files\n+# Unix-style newlines with a newline ending every file\n+end_of_line = lf\n+insert_final_newline = true\n+trim_trailing_whitespace = true\n+# Set default charset\n+charset = utf-8\n+# Indent style default\n+indent_style = space\n+# Max Line Length - a hard line wrap, should be disabled\n+max_line_length = off\n+\n+[*.{py,cfg,ini}]\n+# 4 space indentation\n+indent_size = 4\n+\n+[*.{yml,zpt,pt,dtml,zcml}]\n+# 2 space indentation\n+indent_size = 2\n+\n+[*.{json,jsonl,js,jsx,ts,tsx,css,less,scss,html}] # Frontend development\n+# 2 space indentation\n+indent_size = 2\n+max_line_length = 80\n+\n+[{Makefile,.gitmodules}]\n+# Tab indentation (no size specified, but view as 4 spaces)\n+indent_style = tab\n+indent_size = unset\n+tab_width = unset\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [editorconfig]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.flake8 b/.flake8\nindex 9ec27e5..7ef4f64 100644\n--- a/.flake8\n+++ b/.flake8\n@@ -1,7 +1,22 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [flake8]\n-# Recommend matching the black line length (default 88),\n-# rather than using the flake8 default of 79:\n-max-line-length = 100000\n-extend-ignore =\n- # See https://github.com/PyCQA/pycodestyle/issues/373\n+doctests = 1\n+ignore =\n+ # black takes care of line length\n+ E501,\n+ # black takes care of where to break lines\n+ W503,\n+ # black takes care of spaces within slicing (list[:])\n E203,\n+ # black takes care of spaces after commas\n+ E231,\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [flake8]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.github/workflows/black.yml b/.github/workflows/black.yml\ndeleted file mode 100644\nindex adaf340..0000000\n--- a/.github/workflows/black.yml\n+++ /dev/null\n@@ -1,35 +0,0 @@\n-name: Black\n-on: [push]\n-jobs:\n- build:\n- runs-on: ubuntu-latest\n- strategy:\n- fail-fast: false\n- matrix:\n- python-version: [3.8]\n-\n- steps:\n- # git checkout\n- - uses: actions/checkout@v2\n-\n- # python setup\n- - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n- with:\n- python-version: ${{ matrix.python-version }}\n-\n- # python cache\n- - uses: actions/cache@v1\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-\n-\n- # install black (extract version from versions.cfg)\n- - name: install black\n- run: pip install click==8.0.4 black==$(awk \'/^black =/{print $NF}\' versions.cfg)\n-\n- # run black\n- - name: run black\n- run: black src/ --check --diff\ndiff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml\ndeleted file mode 100644\nindex 97c7dfa..0000000\n--- a/.github/workflows/flake8.yml\n+++ /dev/null\n@@ -1,35 +0,0 @@\n-name: Flake8\n-on: [push]\n-jobs:\n- build:\n- runs-on: ubuntu-latest\n- strategy:\n- fail-fast: false\n- matrix:\n- python-version: [3.8]\n-\n- steps:\n- # git checkout\n- - uses: actions/checkout@v2\n-\n- # python setup\n- - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n- with:\n- python-version: ${{ matrix.python-version }}\n-\n- # python cache\n- - uses: actions/cache@v1\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-\n-\n- # install flake8\n- - name: install flake8\n- run: pip install flake8\n-\n- # run black\n- - name: run flake8\n- run: flake8 src/ setup.py\ndiff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml\nnew file mode 100644\nindex 0000000..b6d147d\n--- /dev/null\n+++ b/.github/workflows/meta.yml\n@@ -0,0 +1,67 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+name: Meta\n+on:\n+ push:\n+ branches:\n+ - master\n+ - main\n+ pull_request:\n+ branches:\n+ - master\n+ - main\n+ workflow_dispatch:\n+\n+##\n+# To set environment variables for all jobs, add in .meta.toml:\n+# [github]\n+# env = """\n+# debug: 1\n+# image-name: \'org/image\'\n+# image-tag: \'latest\'\n+# """\n+##\n+\n+jobs:\n+ qa:\n+ uses: plone/meta/.github/workflows/qa.yml@main\n+ dependencies:\n+ uses: plone/meta/.github/workflows/dependencies.yml@main\n+ release_ready:\n+ uses: plone/meta/.github/workflows/release_ready.yml@main\n+ circular:\n+ uses: plone/meta/.github/workflows/circular.yml@main\n+\n+#TODO: the test and coverage jobs are not used as plone.rest has a complicated use case\n+# when plone/meta is capable of it, we should try to enable them\n+\n+##\n+# To modify the list of default jobs being created add in .meta.toml:\n+# [github]\n+# jobs = [\n+# "qa",\n+# "test",\n+# "coverage",\n+# "dependencies",\n+# "release_ready",\n+# "circular",\n+# ]\n+##\n+\n+##\n+# To request that some OS level dependencies get installed\n+# when running tests/coverage jobs, add in .meta.toml:\n+# [github]\n+# os_dependencies = "git libxml2 libxslt"\n+##\n+\n+\n+##\n+# Specify additional jobs in .meta.toml:\n+# [github]\n+# extra_lines = """\n+# another:\n+# uses: org/repo/.github/workflows/file.yml@main\n+# """\n+##\ndiff --git a/.github/workflows/pyroma.yml b/.github/workflows/pyroma.yml\ndeleted file mode 100644\nindex bbad3c2..0000000\n--- a/.github/workflows/pyroma.yml\n+++ /dev/null\n@@ -1,35 +0,0 @@\n-name: Pyroma\n-on: [push]\n-jobs:\n- build:\n- runs-on: ubuntu-latest\n- strategy:\n- fail-fast: false\n- matrix:\n- python-version: [3.8]\n-\n- steps:\n- # git checkout\n- - uses: actions/checkout@v2\n-\n- # python setup\n- - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n- with:\n- python-version: ${{ matrix.python-version }}\n-\n- # python cache\n- - uses: actions/cache@v1\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-\n-\n- # install pyroma\n- - name: install pyroma\n- run: pip install pyroma\n-\n- # run pyroma\n- - name: run pyroma\n- run: pyroma -n 10 -d .\ndiff --git a/.github/workflows/zpretty.yml b/.github/workflows/zpretty.yml\ndeleted file mode 100644\nindex a329901..0000000\n--- a/.github/workflows/zpretty.yml\n+++ /dev/null\n@@ -1,40 +0,0 @@\n-name: zpretty\n-on: [push]\n-jobs:\n- build:\n- runs-on: ubuntu-latest\n- strategy:\n- fail-fast: false\n- matrix:\n- python-version: [3.8]\n-\n- steps:\n- # git checkout\n- - uses: actions/checkout@v2\n-\n- # python setup\n- - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n- with:\n- python-version: ${{ matrix.python-version }}\n-\n- # python cache\n- - uses: actions/cache@v1\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-\n-\n- # install zpretty\n- - name: install zpretty\n- run: pip install zpretty\n-\n- # run zpretty\n- - name: run zpretty\n- run: find src/ -name *.zcml | xargs zpretty -i\n-\n- # XXX: this doesn\'t work on gh actions (https://github.com/plone/plone.restapi/pull/1119/checks?check_run_id=2686474411)\n- # # run git diff\n- # - name: run git diff\n- # run: git diff --exit-code\ndiff --git a/.gitignore b/.gitignore\nindex ece0007..503e47c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,33 +1,55 @@\n-/develop-eggs\n-/eggs\n-/fake-eggs\n-/bin\n-/parts\n-/downloads\n-/var\n-/build\n-/dist\n-/extras\n-/local.cfg\n-.coverage\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+# python related\n *.egg-info\n-*.eggs\n-/.installed.cfg\n *.pyc\n-/.Python\n-/include\n-/lib\n-/lib64\n-/.mr.developer.cfg\n+*.pyo\n+\n+# translation related\n *.mo\n-local/\n-pip-selfcheck.json\n-share/\n-docs/Makefile\n-docs/make.bat\n-docs/doctrees\n-docs/html\n-htmlcov\n-bower_components\n+\n+# tools related\n+build/\n+.coverage\n+.*project\n+coverage.xml\n+dist/\n+docs/_build\n+__pycache__/\n+.tox\n .vscode/\n+node_modules/\n+\n+# venv / buildout related\n+bin/\n+develop-eggs/\n+eggs/\n+.eggs/\n+etc/\n+.installed.cfg\n+include/\n+lib/\n+lib64\n+.mr.developer.cfg\n+parts/\n pyvenv.cfg\n+var/\n+\n+# mxdev\n+/instance/\n+/.make-sentinels/\n+/*-mxdev.txt\n+/reports/\n+/sources/\n+/venv/\n+.installed.txt\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [gitignore]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000..2ca393b\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,17 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[meta]\n+template = "default"\n+commit-id = "68cda6e4"\n+\n+[github]\n+jobs = [\n+ "qa",\n+ "dependencies",\n+ "release_ready",\n+ "circular",\n+ ]\n+\n+[pyproject]\n+dependencies_ignores = "[\'plone.app.redirector\']"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nindex 621be3e..b6eb043 100644\n--- a/.pre-commit-config.yaml\n+++ b/.pre-commit-config.yaml\n@@ -1,38 +1,94 @@\n # Generated from:\n # https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n ci:\n- autofix_prs: false\n- autoupdate_schedule: monthly\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n \n repos:\n- - repo: https://github.com/asottile/pyupgrade\n+- repo: https://github.com/asottile/pyupgrade\n rev: v3.14.0\n hooks:\n- - id: pyupgrade\n+ - id: pyupgrade\n args: [--py38-plus]\n- - repo: https://github.com/pycqa/isort\n+- repo: https://github.com/pycqa/isort\n rev: 5.12.0\n hooks:\n- - id: isort\n- - repo: https://github.com/psf/black\n+ - id: isort\n+- repo: https://github.com/psf/black\n rev: 23.9.1\n hooks:\n- - id: black\n- - repo: https://github.com/PyCQA/flake8\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.1.0\n+ hooks:\n+ - id: zpretty\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# zpretty_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/PyCQA/flake8\n rev: 6.1.0\n hooks:\n- - id: flake8\n- - repo: https://github.com/codespell-project/codespell\n+ - id: flake8\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# flake8_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/codespell-project/codespell\n rev: v2.2.6\n hooks:\n- - id: codespell\n+ - id: codespell\n additional_dependencies:\n - tomli\n- - repo: https://github.com/mgedmin/check-manifest\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# codespell_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/mgedmin/check-manifest\n rev: "0.49"\n hooks:\n- - id: check-manifest\n- - repo: https://github.com/regebro/pyroma\n+ - id: check-manifest\n+- repo: https://github.com/regebro/pyroma\n rev: "4.2"\n hooks:\n- - id: pyroma\n+ - id: pyroma\n+- repo: https://github.com/mgedmin/check-python-versions\n+ rev: "0.21.3"\n+ hooks:\n+ - id: check-python-versions\n+ args: [\'--only\', \'setup.py,pyproject.toml\']\n+- repo: https://github.com/collective/i18ndude\n+ rev: "6.1.0"\n+ hooks:\n+ - id: i18ndude\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# i18ndude_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/news/93e1ab65.internal b/news/93e1ab65.internal\nnew file mode 100644\nindex 0000000..c08f539\n--- /dev/null\n+++ b/news/93e1ab65.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex a9ead58..6e5db43 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,6 +1,9 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [tool.towncrier]\n-filename = "CHANGES.rst"\n directory = "news/"\n+filename = "CHANGES.rst"\n title_format = "{version} ({project_date})"\n underlines = ["-", ""]\n \n@@ -24,8 +27,131 @@ directory = "internal"\n name = "Internal:"\n showcontent = true\n \n+[[tool.towncrier.type]]\n+directory = "documentation"\n+name = "Documentation:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "tests"\n+name = "Tests"\n+showcontent = true\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# towncrier_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n [tool.isort]\n profile = "plone"\n \n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# isort_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n [tool.black]\n-target-version = ["py38"]\n\\ No newline at end of file\n+target-version = ["py38"]\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# black_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n+[tool.codespell]\n+ignore-words-list = "discreet,"\n+skip = "*.po,"\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# codespell_ignores = "foo,bar"\n+# codespell_skip = "*.po,*.map,package-lock.json"\n+##\n+\n+[tool.dependencychecker]\n+Zope = [\n+ # Zope own provided namespaces\n+ \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n+ \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n+ \'Zope2\', \'webdav\', \'zmi\',\n+ # ExtensionClass own provided namespaces\n+ \'ExtensionClass\', \'ComputedAttribute\', \'MethodObject\',\n+ # Zope dependencies\n+ \'AccessControl\', \'Acquisition\', \'AuthEncoding\', \'beautifulsoup4\', \'BTrees\',\n+ \'cffi\', \'Chameleon\', \'DateTime\', \'DocumentTemplate\',\n+ \'MultiMapping\', \'multipart\', \'PasteDeploy\', \'Persistence\', \'persistent\',\n+ \'pycparser\', \'python-gettext\', \'pytz\', \'RestrictedPython\', \'roman\',\n+ \'soupsieve\', \'transaction\', \'waitress\', \'WebOb\', \'WebTest\', \'WSGIProxy2\',\n+ \'z3c.pt\', \'zc.lockfile\', \'ZConfig\', \'zExceptions\', \'ZODB\', \'zodbpickle\',\n+ \'zope.annotation\', \'zope.browser\', \'zope.browsermenu\', \'zope.browserpage\',\n+ \'zope.browserresource\', \'zope.cachedescriptors\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.contentprovider\',\n+ \'zope.contenttype\', \'zope.datetime\', \'zope.deferredimport\',\n+ \'zope.deprecation\', \'zope.dottedname\', \'zope.event\', \'zope.exceptions\',\n+ \'zope.filerepresentation\', \'zope.globalrequest\', \'zope.hookable\',\n+ \'zope.i18n\', \'zope.i18nmessageid\', \'zope.interface\', \'zope.lifecycleevent\',\n+ \'zope.location\', \'zope.pagetemplate\', \'zope.processlifetime\', \'zope.proxy\',\n+ \'zope.ptresource\', \'zope.publisher\', \'zope.schema\', \'zope.security\',\n+ \'zope.sequencesort\', \'zope.site\', \'zope.size\', \'zope.structuredtext\',\n+ \'zope.tal\', \'zope.tales\', \'zope.testbrowser\', \'zope.testing\',\n+ \'zope.traversing\', \'zope.viewlet\'\n+]\n+\'Products.CMFCore\' = [\n+ \'docutils\', \'five.localsitemanager\', \'Missing\', \'Products.BTreeFolder2\',\n+ \'Products.GenericSetup\', \'Products.MailHost\', \'Products.PythonScripts\',\n+ \'Products.StandardCacheManagers\', \'Products.ZCatalog\', \'Record\',\n+ \'zope.sendmail\', \'Zope\'\n+]\n+\'plone.base\' = [\n+ \'plone.batching\', \'plone.registry\', \'plone.schema\',\'plone.z3cform\',\n+ \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n+]\n+python-dateutil = [\'dateutil\']\n+ignore-packages = [\'plone.app.redirector\']\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# dependencies_ignores = "[\'zestreleaser.towncrier\']"\n+# dependencies_mappings = [\n+# "gitpython = [\'git\']",\n+# "pygithub = [\'github\']",\n+# ]\n+##\n+\n+[tool.check-manifest]\n+ignore = [\n+ ".editorconfig",\n+ ".meta.toml",\n+ ".pre-commit-config.yaml",\n+ "tox.ini",\n+ ".flake8",\n+ "mx.ini",\n+\n+]\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# check_manifest_ignores = """\n+# "*.map.js",\n+# "*.pyc",\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/setup.cfg b/setup.cfg\ndeleted file mode 100644\nindex 2a9acf1..0000000\n--- a/setup.cfg\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-[bdist_wheel]\n-universal = 1\ndiff --git a/setup.py b/setup.py\nindex 65b1001..9ebf27b 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -54,22 +54,26 @@ def read(*rnames):\n extras_require=dict(\n test=[\n "plone.app.testing[robot]>=4.2.2",\n- "plone.app.robotframework",\n- "plone.dexterity",\n- "Products.CMFCore",\n "requests",\n+ "BTrees",\n+ "plone.app.contenttypes[test]",\n+ "plone.app.layout",\n+ "plone.app.redirector",\n+ "plone.app.textfield",\n+ "plone.namedfile",\n+ "plone.testing",\n+ "z3c.relationfield",\n+ "zope.intid",\n+ "plone.base",\n ]\n ),\n install_requires=[\n "setuptools",\n "collective.monkeypatcher",\n- "zope.component",\n- "zope.interface",\n- "zope.publisher",\n- "zope.traversing",\n "Products.CMFCore",\n- "Zope2",\n- "six",\n+ "Zope",\n+ "plone.memoize",\n+ "zope.browserpage",\n ],\n entry_points="""\n # -*- Entry points: -*-\ndiff --git a/src/plone/__init__.py b/src/plone/__init__.py\nindex 05f0beb..5284146 100644\n--- a/src/plone/__init__.py\n+++ b/src/plone/__init__.py\n@@ -1,7 +1 @@\n-# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages\n-try:\n- __import__("pkg_resources").declare_namespace(__name__)\n-except ImportError:\n- from pkgutil import extend_path\n-\n- __path__ = extend_path(__path__, __name__)\n+__import__("pkg_resources").declare_namespace(__name__)\ndiff --git a/src/plone/rest/configure.zcml b/src/plone/rest/configure.zcml\nindex af6c115..f2c4f93 100644\n--- a/src/plone/rest/configure.zcml\n+++ b/src/plone/rest/configure.zcml\n@@ -1,33 +1,36 @@\n \n+ xmlns:five="http://namespaces.zope.org/five"\n+ xmlns:plone="http://namespaces.plone.org/plone"\n+ >\n \n- \n+ \n \n+ for="ZPublisher.interfaces.IPubStart"\n+ handler=".events.subscriber_mark_as_api_request"\n+ />\n \n \n \n \n \n \n \n \n \n \n+ />\n \n \ndiff --git a/src/plone/rest/errors.py b/src/plone/rest/errors.py\nindex d6a9c53..ac6014c 100644\n--- a/src/plone/rest/errors.py\n+++ b/src/plone/rest/errors.py\n@@ -1,36 +1,34 @@\n from AccessControl import getSecurityManager\n-\n-\n-try:\n- from plone.app.redirector.interfaces import IRedirectionStorage\n-except ImportError:\n- IRedirectionStorage = None\n from plone.memoize.instance import memoize\n from plone.rest.interfaces import IAPIRequest\n from plone.rest.interfaces import ICORSPolicy\n from Products.CMFCore.permissions import ManagePortal\n from Products.Five.browser import BrowserView\n-from six.moves import urllib\n from urllib.parse import quote\n from urllib.parse import unquote\n from zExceptions import NotFound\n-\n-\n-try:\n- from ZPublisher.HTTPRequest import WSGIRequest\n-\n- HAS_WSGI = True\n-except ImportError:\n- HAS_WSGI = False\n from zope.component import adapter\n from zope.component import queryMultiAdapter\n from zope.component import queryUtility\n from zope.component.hooks import getSite\n \n import json\n-import six\n import sys\n import traceback\n+import urllib\n+\n+\n+try:\n+ from plone.app.redirector.interfaces import IRedirectionStorage\n+except ImportError:\n+ IRedirectionStorage = None\n+\n+try:\n+ from ZPublisher.HTTPRequest import WSGIRequest\n+\n+ HAS_WSGI = True\n+except ImportError:\n+ HAS_WSGI = False\n \n \n @adapter(Exception, IAPIRequest)\n@@ -60,9 +58,6 @@ def __call__(self):\n def render_exception(self, exception):\n name = type(exception).__name__\n message = str(exception)\n- if six.PY2:\n- name = name.decode("utf-8")\n- message = message.decode("utf-8")\n result = {"type": name, "message": message}\n \n policy = queryMultiAdapter((self.context, self.request), ICORSPolicy)\ndiff --git a/src/plone/rest/meta.zcml b/src/plone/rest/meta.zcml\nindex c027b7a..16873ec 100644\n--- a/src/plone/rest/meta.zcml\n+++ b/src/plone/rest/meta.zcml\n@@ -1,18 +1,19 @@\n \n+ i18n_domain="plone.rest"\n+ >\n \n \n \n \n+ name="CORSPolicy"\n+ handler=".zcml.cors_policy_directive"\n+ schema=".zcml.ICORSPolicyDirective"\n+ />\n \n \n \ndiff --git a/src/plone/rest/patches.zcml b/src/plone/rest/patches.zcml\nindex a0245bf..a26791d 100644\n--- a/src/plone/rest/patches.zcml\n+++ b/src/plone/rest/patches.zcml\n@@ -1,26 +1,27 @@\n \n+ i18n_domain="collective.monkeypatcher"\n+ >\n \n \n \n \n+ original="__before_publishing_traverse__"\n+ replacement=".patches.__before_publishing_traverse__"\n+ class="Products.CMFCore.DynamicType.DynamicType"\n+ description="Disables DynamicType traversal hook for REST requests."\n+ preserveOriginal="true"\n+ />\n \n \n+ original="status_codes"\n+ replacement=".patches.PERMANENT_REDIRECT"\n+ module="ZPublisher.HTTPResponse"\n+ handler=".patches.patch_zpublisher_status_codes"\n+ description="Teach ZPublisher about status 308"\n+ ignoreOriginal="True"\n+ preconditions="Zope2-=4.0a1"\n+ />\n \n \ndiff --git a/src/plone/rest/testing.zcml b/src/plone/rest/testing.zcml\nindex aef9b87..2033039 100644\n--- a/src/plone/rest/testing.zcml\n+++ b/src/plone/rest/testing.zcml\n@@ -1,169 +1,170 @@\n \n+ xmlns:five="http://namespaces.zope.org/five"\n+ xmlns:plone="http://namespaces.plone.org/plone"\n+ >\n \n \n \n \n+ method="GET"\n+ factory=".demo.Get"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.View"\n+ />\n \n \n+ method="POST"\n+ factory=".demo.Post"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.AddPortalContent"\n+ />\n \n \n+ method="PUT"\n+ factory=".demo.Put"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.ModifyPortalContent"\n+ />\n \n \n+ method="DELETE"\n+ factory=".demo.Delete"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.DeleteObjects"\n+ />\n \n \n+ method="PATCH"\n+ factory=".demo.Patch"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.ModifyPortalContent"\n+ />\n \n \n+ method="OPTIONS"\n+ factory=".demo.Options"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.View"\n+ />\n \n \n \n \n+ method="GET"\n+ factory=".demo.Get"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="zope2.View"\n+ />\n \n \n+ method="POST"\n+ factory=".demo.Post"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="cmf.AddPortalContent"\n+ />\n \n \n+ method="PUT"\n+ factory=".demo.Put"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="cmf.ModifyPortalContent"\n+ />\n \n \n+ method="DELETE"\n+ factory=".demo.Delete"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="zope2.DeleteObjects"\n+ />\n \n \n+ method="PATCH"\n+ factory=".demo.Patch"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="cmf.ModifyPortalContent"\n+ />\n \n \n+ method="OPTIONS"\n+ factory=".demo.Options"\n+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"\n+ permission="zope2.View"\n+ />\n \n \n \n \n+ method="GET"\n+ factory=".demo.NamedGet"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.View"\n+ name="namedservice"\n+ />\n \n \n+ method="POST"\n+ factory=".demo.NamedPost"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.AddPortalContent"\n+ name="namedservice"\n+ />\n \n \n+ method="PUT"\n+ factory=".demo.NamedPut"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.ModifyPortalContent"\n+ name="namedservice"\n+ />\n \n \n+ method="DELETE"\n+ factory=".demo.NamedDelete"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.DeleteObjects"\n+ name="namedservice"\n+ />\n \n \n+ method="PATCH"\n+ factory=".demo.NamedPatch"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="cmf.ModifyPortalContent"\n+ name="namedservice"\n+ />\n \n \n+ method="OPTIONS"\n+ factory=".demo.NamedOptions"\n+ for="plone.dexterity.interfaces.IDexterityContent"\n+ permission="zope2.View"\n+ name="namedservice"\n+ />\n \n \n+ method="GET"\n+ factory=".demo.NamedGet"\n+ for="*"\n+ permission="zope2.View"\n+ name="search"\n+ />\n \n \n \n \n+ method="GET"\n+ factory=".testing.InternalServerErrorService"\n+ for="*"\n+ permission="zope2.View"\n+ name="500-internal-server-error"\n+ />\n \n \n+ allow_origin="*"\n+ allow_methods="GET"\n+ expose_headers="X-My-Header"\n+ />\n \n \ndiff --git a/tox.ini b/tox.ini\nnew file mode 100644\nindex 0000000..c30d780\n--- /dev/null\n+++ b/tox.ini\n@@ -0,0 +1,208 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n+envlist =\n+ lint\n+ test\n+ dependencies\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# envlist_lines = """\n+# my_other_environment\n+# """\n+# config_lines = """\n+# my_extra_top_level_tox_configuration_lines\n+# """\n+##\n+\n+[testenv]\n+skip_install = true\n+allowlist_externals =\n+ echo\n+ false\n+# Make sure typos like `tox -e formaat` are caught instead of silently doing nothing.\n+# See https://github.com/tox-dev/tox/issues/2858.\n+commands =\n+ echo "Unrecognized environment name {envname}"\n+ false\n+\n+[testenv:init]\n+description = Prepare environment\n+skip_install = true\n+commands =\n+ echo "Initial setup complete"\n+\n+\n+[testenv:format]\n+description = automatically reformat code\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a pyupgrade\n+ pre-commit run -a isort\n+ pre-commit run -a black\n+ pre-commit run -a zpretty\n+\n+[testenv:lint]\n+description = run linters that will help improve the code style\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a\n+\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies\n+skip_install = true\n+deps =\n+ build\n+ z3c.dependencychecker==2.11\n+commands =\n+ python -m build --sdist --no-isolation\n+ dependencychecker\n+\n+[testenv:dependencies-graph]\n+description = generate a graph out of the dependencies of the package\n+skip_install = false\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree==2.5.1\n+ graphviz # optional dependency of pipdeptree\n+commands =\n+ sh -c \'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg\'\n+\n+[testenv:test]\n+description = run the distribution tests\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+#\n+# Set constrain_package_deps .meta.toml:\n+# [tox]\n+# constrain_package_deps = "false"\n+##\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+##\n+# Specify additional deps in .meta.toml:\n+# [tox]\n+# test_deps_additional = "-esources/plonegovbr.portal_base[test]"\n+#\n+# Specify a custom constraints file in .meta.toml:\n+# [tox]\n+# constraints_file = "https://my-server.com/constraints.txt"\n+##\n+commands =\n+ zope-testrunner --all --test-path={toxinidir}/src -s plone.rest {posargs}\n+extras =\n+ test\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# test_extras = """\n+# tests\n+# widgets\n+# """\n+##\n+\n+[testenv:coverage]\n+description = get a test coverage report\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+commands =\n+ coverage run --branch --source plone.rest {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.rest {posargs}\n+ coverage report -m --format markdown\n+ coverage xml\n+extras =\n+ test\n+\n+\n+[testenv:release-check]\n+description = ensure that the distribution is ready to release\n+skip_install = true\n+deps =\n+ twine\n+ build\n+ towncrier\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+commands =\n+ # fake version to not have to install the package\n+ # we build the change log as news entries might break\n+ # the README that is displayed on PyPI\n+ towncrier build --version=100.0.0 --yes\n+ python -m build --sdist --no-isolation\n+ twine check dist/*\n+\n+[testenv:circular]\n+description = ensure there are no cyclic dependencies\n+use_develop = true\n+skip_install = false\n+set_env =\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree\n+ pipforester\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+commands =\n+ # Generate the full dependency tree\n+ sh -c \'pipdeptree -j > forest.json\'\n+ # Generate a DOT graph with the circular dependencies, if any\n+ pipforester -i forest.json -o forest.dot --cycles\n+ # Report if there are any circular dependencies, i.e. error if there are any\n+ pipforester -i forest.json --check-cycles -o /dev/null\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n' +b'diff --git a/news/1167.bugfix b/news/1167.bugfix\nnew file mode 100644\nindex 0000000000..3d8ef86055\n--- /dev/null\n+++ b/news/1167.bugfix\n@@ -0,0 +1,2 @@\n+Be more strict when checking if mimetype is allowed to be displayed inline.\n+[maurits]\ndiff --git a/src/plone/restapi/services/users/get.py b/src/plone/restapi/services/users/get.py\nindex bef0c3ef0e..393237f740 100644\n--- a/src/plone/restapi/services/users/get.py\n+++ b/src/plone/restapi/services/users/get.py\n@@ -27,6 +27,31 @@\n \n DEFAULT_SEARCH_RESULTS_LIMIT = 25\n \n+try:\n+ # Zope 5.8.4+\n+ from OFS.Image import extract_media_type as _extract_media_type\n+except ImportError:\n+ try:\n+ from plone.namedfile.utils import extract_media_type as _extract_media_type\n+ except ImportError:\n+ # Note that we start the method with an underscore, to signal that this\n+ # is a private implementation detail and no one should be importing this.\n+\n+ def _extract_media_type(content_type):\n+ """extract the proper media type from *content_type*.\n+\n+ Ignore parameters and whitespace and normalize to lower case.\n+ See https://github.com/zopefoundation/Zope/pull/1167\n+ """\n+ if not content_type:\n+ return content_type\n+ # ignore parameters\n+ content_type = content_type.split(";", 1)[0]\n+ # ignore whitespace\n+ content_type = "".join(content_type.split())\n+ # normalize to lowercase\n+ return content_type.lower()\n+\n \n def getPortraitUrl(user):\n if not user:\n@@ -84,7 +109,6 @@ def _sort_users(users: Iterable[MemberData]) -> Sequence[MemberData]:\n def _principal_search_results(\n self, search_for_principal, get_principal_by_id, principal_type, id_key\n ):\n-\n hunter = getMultiAdapter((self.context, self.request), name="pas_search")\n \n principals = []\n@@ -209,7 +233,6 @@ def reply(self):\n if self.has_permission_to_access_user_info() or (\n current_user_id and current_user_id == self._get_user_id\n ):\n-\n # we retrieve the user on the user id not the username\n user = self._get_user(self._get_user_id)\n if not user:\n@@ -251,7 +274,7 @@ def _get_user_id(self):\n \n def _should_force_download(self, portrait):\n # If this returns True, the caller should set the Content-Disposition header.\n- mimetype = portrait.content_type\n+ mimetype = _extract_media_type(portrait.content_type)\n if not mimetype:\n return False\n if self.use_denylist:\ndiff --git a/src/plone/restapi/tests/test_services_users.py b/src/plone/restapi/tests/test_services_users.py\nindex 6de014a8cb..59cdd97d4e 100644\n--- a/src/plone/restapi/tests/test_services_users.py\n+++ b/src/plone/restapi/tests/test_services_users.py\n@@ -23,6 +23,17 @@\n import unittest\n \n \n+class TestUnit(unittest.TestCase):\n+ def test_extract_media_type(self):\n+ from plone.restapi.services.users.get import _extract_media_type as extract\n+\n+ self.assertIsNone(extract(None))\n+ self.assertEqual(extract("text/plain"), "text/plain")\n+ self.assertEqual(extract("TEXT/PLAIN"), "text/plain")\n+ self.assertEqual(extract("text / plain"), "text/plain")\n+ self.assertEqual(extract(" text/plain ; charset=utf-8"), "text/plain")\n+\n+\n class TestUsersEndpoint(unittest.TestCase):\n \n layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING\n'