Skip to content
This repository has been archived by the owner on Apr 9, 2023. It is now read-only.

Commit

Permalink
Merge pull request #49 from plone/decorator-views
Browse files Browse the repository at this point in the history
be able to define services with decorators
  • Loading branch information
bloodbare committed Jan 9, 2017
2 parents 32c6c7c + fca5b79 commit ac4152b
Show file tree
Hide file tree
Showing 38 changed files with 679 additions and 630 deletions.
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Contents:
roles
applications
addons
services
migrations
behavior
commands
Expand Down
32 changes: 32 additions & 0 deletions docs/source/services.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Services

Services provide responses to api endpoint requests. A service is the same as
a "view" that you mean see in many web frameworks.

The reason we're using the convention "service" is because we're focusing on
creating API endpoints.


## Defining a service

A service can be as simple as a function in your application:

```python
from plone.server.configure import service
from plone.server.interfaces import ISite

@service(context=ISite, name='@myservice', method='GET',
permission='plone.AccessContent')
async def my_service(context, request):
return {
'foo': 'bar'
}
```

The most simple way to define a service is to use the decorator method shown here.

As long as your application imports the module where your service is defined,
your service will be loaded for you.

In this example, the service will apply to a GET request against a site,
`/zodb/plone/@myservice`.
18 changes: 16 additions & 2 deletions src/plone.server/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
1.0a9 (unreleased)
------------------

- Adding HTTP Precondition exception
Fixes:

- Use zope.schema getter and setter to set attributes
[ramonnb]

- User zope.schema getter and setter to set attributes
New features:

- Adding HTTP Precondition exception
[ramonnb]

- New way to create services with decorators instead of zcml/json configuration
[vangheem]

- Add functionality like virtualhost monster to define the urls
[ramonnb]

Expand Down Expand Up @@ -34,6 +41,13 @@
- Role member for Manager group
[ramonnb]


Breaking changes:

- plone:api zcml directive deprecated in favor of decorator variant
[vangheem]


1.0a8 (2016-12-18)
------------------

Expand Down
35 changes: 27 additions & 8 deletions src/plone.server/plone/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from plone.server import patch # noqa
# load defined migrations
from plone.server.migrate import migrations # noqa
from zope.i18nmessageid import MessageFactory

import collections
from plone.server import interfaces
from plone.server import languages

import collections

_ = MessageFactory('plone')

app_settings = {
"databases": [],
Expand All @@ -28,11 +28,30 @@
"plone.server.auth.validators.SaltedHashPasswordValidator",
"plone.server.auth.validators.JWTValidator"
],
"default_layers": [],
"http_methods": {},
"renderers": collections.OrderedDict(),
"languages": {},
"default_permission": '',
"default_layers": [
interfaces.IDefaultLayer
],
"http_methods": {
"PUT": interfaces.IPUT,
"POST": interfaces.IPOST,
"PATCH": interfaces.IPATCH,
"DELETE": interfaces.IDELETE,
"GET": interfaces.IGET,
"OPTIONS": interfaces.IOPTIONS,
"HEAD": interfaces.IHEAD,
"CONNECT": interfaces.ICONNECT
},
"renderers": collections.OrderedDict({
"application/json": interfaces.IRendererFormatJson,
"text/html": interfaces.IRendererFormatHtml,
"*/*": interfaces.IRendererFormatRaw
}),
"languages": {
"en": languages.IEN,
"en-us": languages.IENUS,
"ca": languages.ICA
},
"default_permission": 'zope.Public',
"available_addons": {},
"api_definition": {},
"cors": {
Expand Down
12 changes: 12 additions & 0 deletions src/plone.server/plone/server/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# these imports are done to force loading services
from . import addons # noqa
from . import app # noqa
from . import files # noqa
from . import content # noqa
from . import search # noqa
from . import behaviors # noqa
from . import registry # noqa
from . import types # noqa
from . import ws # noqa
from . import user # noqa
from . import portal # noqa
113 changes: 60 additions & 53 deletions src/plone.server/plone/server/api/addons.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,77 @@
# -*- coding: utf-8 -*-
from plone.server import _
from plone.server import app_settings
from plone.server.api.service import Service
from plone.server.browser import ErrorResponse
from plone.server.configure import service
from plone.server.interfaces import ISite
from plone.server.registry import IAddons
from zope.i18nmessageid import MessageFactory


class Install(Service):
async def __call__(self):
data = await self.request.json()
id_to_install = data.get('id', None)
if id_to_install not in app_settings['available_addons']:
return ErrorResponse(
'RequiredParam',
_("Property 'id' is required to be valid"))
_ = MessageFactory('plone')

registry = self.request.site_settings
config = registry.for_interface(IAddons)

if id_to_install in config.enabled:
return ErrorResponse(
'Duplicate',
_("Addon already installed"))
handler = app_settings['available_addons'][id_to_install]['handler']
handler.install(self.request)
config.enabled |= {id_to_install}
return await getAddons(self.context, self.request)()
@service(context=ISite, name='@addons', method='POST',
permission='plone.ManageAddons')
async def install(context, request):
data = await request.json()
id_to_install = data.get('id', None)
if id_to_install not in app_settings['available_addons']:
return ErrorResponse(
'RequiredParam',
_("Property 'id' is required to be valid"))

registry = request.site_settings
config = registry.for_interface(IAddons)

class Uninstall(Service):
async def __call__(self):
data = await self.request.json()
id_to_install = data.get('id', None)
if id_to_install not in app_settings['available_addons']:
return ErrorResponse(
'RequiredParam',
_("Property 'id' is required to be valid"))
if id_to_install in config.enabled:
return ErrorResponse(
'Duplicate',
_("Addon already installed"))
handler = app_settings['available_addons'][id_to_install]['handler']
handler.install(request)
config.enabled |= {id_to_install}
return await get_addons(context, request)()

registry = self.request.site_settings
config = registry.for_interface(IAddons)

if id_to_install not in config.enabled:
return ErrorResponse(
'Duplicate',
_("Addon not installed"))
@service(context=ISite, name='@addons', method='DELETE',
permission='plone.ManageAddons')
async def uninstall(context, request):
data = await request.json()
id_to_install = data.get('id', None)
if id_to_install not in app_settings['available_addons']:
return ErrorResponse(
'RequiredParam',
_("Property 'id' is required to be valid"))

handler = app_settings['available_addons'][id_to_install]['handler']
handler.uninstall(self.request)
config.enabled -= {id_to_install}
registry = request.site_settings
config = registry.for_interface(IAddons)

if id_to_install not in config.enabled:
return ErrorResponse(
'Duplicate',
_("Addon not installed"))

class getAddons(Service):
async def __call__(self):
result = {
'available': [],
'installed': []
}
for key, addon in app_settings['available_addons'].items():
result['available'].append({
'id': key,
'title': addon['title']
})
handler = app_settings['available_addons'][id_to_install]['handler']
handler.uninstall(request)
config.enabled -= {id_to_install}

registry = self.request.site_settings
config = registry.for_interface(IAddons)

for installed in config.enabled:
result['installed'].append(installed)
return result
@service(context=ISite, name='@addons', method='GET',
permission='plone.ManageAddons')
async def get_addons(context, request):
result = {
'available': [],
'installed': []
}
for key, addon in app_settings['available_addons'].items():
result['available'].append({
'id': key,
'title': addon['title']
})

registry = request.site_settings
config = registry.for_interface(IAddons)

for installed in config.enabled:
result['installed'].append(installed)
return result

0 comments on commit ac4152b

Please sign in to comment.