Skip to content

Commit

Permalink
Merge branch 'main' into disable-CSRF-history
Browse files Browse the repository at this point in the history
  • Loading branch information
nileshgulia1 authored Feb 7, 2025
2 parents ec5acf9 + bc29368 commit bebe885
Show file tree
Hide file tree
Showing 74 changed files with 837 additions and 173 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ jobs:
include:
- python-version: "3.8"
plone-version: "5.2"
- python-version: "3.8"
plone-version: "6.0"
- python-version: "3.9"
plone-version: "6.0"
- python-version: "3.10"
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# See https://docs.readthedocs.com/platform/stable/config-file/v2.html for details

# Required
version: 2
Expand Down
36 changes: 36 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,42 @@ Changelog
.. towncrier release notes start
9.11.0 (2025-01-31)
-------------------

New features:


- Support working copies of the Plone Site. This feature is available when using `plone.app.iterate` 6.1.0 or later. @wesleybl (#1823)


9.10.0 (2025-01-27)
-------------------

New features:


- Add a `@login` endpoint to get external login services' links. @erral (#1757)
- In the `@registry` endpoint, added support for filtering the list of registry records. @Faakhir30 (#1861)


Bug fixes:


- Changed bad int inputs into 500 Exceptions to 400 BadRequest so they can be filtered out of logs more easily. @djay (#1855)
- Handle TypeError on querystringsearch as BadRequest. @djay (#1857)
- Add parse_int to handle all cases of BadRequests from ints passed in. @djay (#1858)
- In the `@contextnavigation` endpoint, return `"icon": null` for Files with a mimetype not found in the `content_type_registry`, instead of raising `TypeError`. @mamico (#1864)
- In the `@locking` endpoint, fixed edge cases where the user who owns the lock was not found correctly. @mamico (#1867)
- Prevent deprecation warnings. @mauritsvanrees (#4090)


Internal:


- Update CI. @davisagli (#1685)


9.9.0 (2024-12-18)
------------------

Expand Down
9 changes: 5 additions & 4 deletions docs/source/endpoints/index.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
myst:
html_meta:
"description": "Usage of the Plone REST API."
"property=og:description": "Usage of the Plone REST API."
"property=og:title": "Usage of the Plone REST API"
"keywords": "Plone, plone.restapi, REST, API, Usage"
"description": "Endpoints of the Plone REST API."
"property=og:description": "Endpoints of the Plone REST API."
"property=og:title": "Endpoints of the Plone REST API"
"keywords": "Plone, plone.restapi, REST, API, endpoints"
---

(restapi-endpoints)=
Expand Down Expand Up @@ -33,6 +33,7 @@ groups
history
linkintegrity
locking
login
navigation
navroot
actions
Expand Down
71 changes: 71 additions & 0 deletions docs/source/endpoints/login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
myst:
html_meta:
"description": "The @login endpoint exposes the list of external authentication services that may be used in the Plone site."
"property=og:description": "The @login endpoint exposes the list of external authentication services that may be used in the Plone site."
"property=og:title": "@login for external authentication links"
"keywords": "Plone, plone.restapi, REST, API, login, authentication, external services"
---

# Login for external authentication links

It is common to use add-ons that allow logging in to your site using third party services.
Such add-ons include using authentication services provided by KeyCloak, GitHub, or other OAuth2 or OpenID Connect enabled services.

When you install one of these add-ons, it modifies the login process, directing the user to third party services.

To expose the links provided by these add-ons, `plone.restapi` provides an adapter based service registration.
It lets those add-ons know that the REST API can use those services to authenticate users.
This will mostly be used by frontends that need to show the end user the links to those services.

To achieve that, third party products need to register one or more adapters for the Plone site root object, providing the `plone.restapi.interfaces.IExternalLoginProviders` interface.

In the adapter, the add-on needs to return the list of external links and some metadata, including the `id`, `title`, and name of the `plugin`.

An example adapter would be the following, in a file named {file}`adapter.py`:

```python
from zope.component import adapter
from zope.interface import implementer

@adapter(IPloneSiteRoot)
@implementer(IExternalLoginProviders)
class MyExternalLinks:
def __init__(self, context):
self.context = context

def get_providers(self):
return [
{
"id": "myprovider",
"title": "Provider",
"plugin": "pas.plugins.authomatic",
"url": "https://some.example.com/login-url",
},
{
"id": "github",
"title": "GitHub",
"plugin": "pas.plugins.authomatic",
"url": "https://some.example.com/login-authomatic/github",
},
]
```

With the corresponding ZCML stanza, in the corresponding {file}`configure.zcml` file:

```xml
<adapter factory=".adapter.MyExternalLinks" name="my-external-links"/>
```

The API request would be as follows:

```{eval-rst}
.. http:example:: curl httpie python-requests
:request: ../../../src/plone/restapi/tests/http-examples/external_authentication_links.req
```

The server will respond with a `Status 200` and the list of external providers:

```{literalinclude} ../../../src/plone/restapi/tests/http-examples/external_authentication_links.resp
:language: http
```
19 changes: 19 additions & 0 deletions docs/source/endpoints/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ Example response:
:language: http
```

## Filter list of registry records

```{versionadded} plone.restapi 9.10.0
```

You can filter a list of registry records and batch the results.
To do so, append a query string to the listing endpoint with a `q` parameter and its value set to the prefix of the desired record name.
See {doc}`../usage/batching` for details of how to work with batched results.

```{eval-rst}
.. http:example:: curl httpie python-requests
:request: ../../../src/plone/restapi/tests/http-examples/registry_get_list_filtered.req
```

Example response:

```{literalinclude} ../../../src/plone/restapi/tests/http-examples/registry_get_list_filtered.resp
:language: http
```

## Updating registry records

Expand Down
31 changes: 23 additions & 8 deletions docs/source/endpoints/userschema.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,22 @@ myst:

# User schema

```{note}
This is only available on Plone 5.
```

Users in Plone have a set of properties defined by a default set of fields such as `fullname`, `email`, `portrait`, and so on.
These properties define the site user's profile and the user itself via the Plone UI, or the site managers can add them in a variety of ways including PAS plugins.

These fields are dynamic and customizable by integrators so they do not adhere to a fixed schema interface.
This dynamic schema is exposed by this endpoint in order to build the user's profile form.
This dynamic schema is exposed by this endpoint in order to build the user's profile form and the registration form.

## Getting the user schema
## Get the schema for the user profile

To get the current user schema, make a request to the `/@userschema` endpoint.
To get the current schema for the user profile, make a request to the `/@userschema` endpoint.

```{eval-rst}
.. http:example:: curl httpie python-requests
:request: ../../../src/plone/restapi/tests/http-examples/userschema.req
```

The server will respond with the user schema.
The server will respond with the user profile schema.

```{literalinclude} ../../../src/plone/restapi/tests/http-examples/userschema.resp
:language: http
Expand All @@ -37,3 +33,22 @@ The server will respond with the user schema.
The user schema uses the same serialization as the type's JSON schema.

See {ref}`types-schema` for detailed documentation about the available field types.

## Get the registration form

In Plone you can configure each of the fields of the user schema to be available in only one of either the user profile form or registration form, or in both of them.

To get the user schema available for the user registration form, make a request to the `@userschema/registration` endpoint.

```{eval-rst}
.. http:example:: curl httpie python-requests
:request: ../../../src/plone/restapi/tests/http-examples/userschema_registration.req
```

The server will respond with the user schema for registration.

```{literalinclude} ../../../src/plone/restapi/tests/http-examples/userschema_registration.resp
:language: http
```

The user schema uses the same serialization as the type's JSON schema.
1 change: 1 addition & 0 deletions news/1873.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a `@userschema/registration` endpoint to get the fields for the registration form. @erral
3 changes: 2 additions & 1 deletion plone-6.0.x-python3.8.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[buildout]
extends =
https://dist.plone.org/release/6.0.12/versions.cfg
https://dist.plone.org/release/6.0.14/versions.cfg
base.cfg

[instance]
Expand All @@ -15,3 +15,4 @@ robotframework-assertion-engine = 2.0.0
robotframework-debuglibrary = 2.3.0
robotframework-pythonlibcore = 4.2.0
grpcio-tools = 1.59.0
twine = 5.1.1
17 changes: 2 additions & 15 deletions plone-6.0.x.cfg
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
[buildout]
extends =
https://dist.plone.org/release/6.0.12/versions.cfg
https://dist.plone.org/release/6.0.14/versions.cfg
base.cfg

[buildout:python37]
parts =
test
code-analysis

[instance]
recipe = plone.recipe.zope2instance
zodb-temporary-storage = off

[versions]
# Override pin from Zope. https://github.com/zopefoundation/Zope/issues/1220
docutils = 0.21.2
pygments = 2.14.0
plone.app.linkintegrity = 4.0.3
robotframework-browser = 17.5.2
robotframework-assertion-engine = 2.0.0
robotframework-debuglibrary = 2.3.0
robotframework-pythonlibcore = 4.2.0
grpcio-tools = 1.59.0
twine = 5.1.1
9 changes: 1 addition & 8 deletions plone-6.1.x.cfg
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
[buildout]
extends =
https://dist.plone.org/release/6.1.0a3/versions.cfg
https://dist.plone.org/release/6.1.0b2/versions.cfg
base.cfg

[buildout:python37]
parts =
test
code-analysis

[instance]
recipe = plone.recipe.zope2instance
zodb-temporary-storage = off

[versions]
# Override pin from Zope. https://github.com/zopefoundation/Zope/issues/1220
docutils = 0.21.2
2 changes: 1 addition & 1 deletion requirements-6.0.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
-r https://dist.plone.org/release/6.0.12/requirements.txt
-r https://dist.plone.org/release/6.0.14/requirements.txt
2 changes: 1 addition & 1 deletion requirements-6.1.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
-r https://dist.plone.org/release/6.1.0a3/requirements.txt
-r https://dist.plone.org/release/6.1.0b2/requirements.txt
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys


version = "9.9.1.dev0"
version = "9.11.1.dev0"

if sys.version_info.major == 2:
raise ValueError(
Expand Down
16 changes: 11 additions & 5 deletions src/plone/restapi/batching.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from plone.batching.batch import Batch
from plone.restapi.deserializer import json_body
from plone.restapi.deserializer import parse_int
from plone.restapi.exceptions import DeserializationError
from urllib.parse import parse_qsl
from urllib.parse import urlencode
from zExceptions import BadRequest


DEFAULT_BATCH_SIZE = 25
Expand All @@ -11,13 +14,16 @@ class HypermediaBatch:
def __init__(self, request, results):
self.request = request

self.b_start = int(json_body(self.request).get("b_start", False)) or int(
self.request.form.get("b_start", 0)
try:
data = json_body(request)
except DeserializationError as e:
raise BadRequest(e)
self.b_start = parse_int(data, "b_start", False) or parse_int(
self.request.form, "b_start", 0
)
self.b_size = int(json_body(self.request).get("b_size", False)) or int(
self.request.form.get("b_size", DEFAULT_BATCH_SIZE)
self.b_size = parse_int(data, "b_size", False) or parse_int(
self.request.form, "b_size", DEFAULT_BATCH_SIZE
)

self.batch = Batch(results, self.b_size, self.b_start)

def __iter__(self):
Expand Down
10 changes: 10 additions & 0 deletions src/plone/restapi/bbb.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from plone.base.interfaces import IImagingSchema
from plone.base.interfaces import ILanguage
from plone.base.interfaces import IMailSchema
from plone.base.interfaces import IMigratingPloneSiteRoot
from plone.base.interfaces import INavigationRoot
from plone.base.interfaces import INavigationSchema
from plone.base.interfaces import INonInstallable
from plone.base.interfaces import INonStructuralFolder
Expand All @@ -13,18 +15,25 @@
from plone.base.interfaces import ISecuritySchema
from plone.base.interfaces import ISelectableConstrainTypes
from plone.base.interfaces import ISiteSchema
from plone.base.interfaces import ITestCasePloneSiteRoot
from plone.base.navigationroot import get_navigation_root
from plone.base.utils import base_hasattr
from plone.base.utils import safe_callable
from plone.base.utils import safe_hasattr
from plone.base.utils import safe_text
except ImportError:
# BBB Plone 5.2
from plone.app.layout.navigation.interfaces import INavigationRoot
from plone.app.layout.navigation.root import (
getNavigationRoot as get_navigation_root,
)
from Products.CMFPlone.defaultpage import is_default_page
from Products.CMFPlone.interfaces import IConstrainTypes
from Products.CMFPlone.interfaces import IEditingSchema
from Products.CMFPlone.interfaces import IImagingSchema
from Products.CMFPlone.interfaces import ILanguage
from Products.CMFPlone.interfaces import IMailSchema
from Products.CMFPlone.interfaces import IMigratingPloneSiteRoot
from Products.CMFPlone.interfaces import INavigationSchema
from Products.CMFPlone.interfaces import INonInstallable
from Products.CMFPlone.interfaces import INonStructuralFolder
Expand All @@ -33,6 +42,7 @@
from Products.CMFPlone.interfaces import ISecuritySchema
from Products.CMFPlone.interfaces import ISelectableConstrainTypes
from Products.CMFPlone.interfaces import ISiteSchema
from Products.CMFPlone.interfaces import ITestCasePloneSiteRoot
from Products.CMFPlone.utils import base_hasattr
from Products.CMFPlone.utils import safe_callable
from Products.CMFPlone.utils import safe_hasattr
Expand Down
Loading

0 comments on commit bebe885

Please sign in to comment.