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

Commit

Permalink
Move jsonfield to a separate field
Browse files Browse the repository at this point in the history
  • Loading branch information
bloodbare committed Dec 18, 2016
1 parent ca2d0d7 commit c1081e0
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 52 deletions.
1 change: 1 addition & 0 deletions src/plone.server/plone/server/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class index(MetadataDictDirective):
'binary',
'object',
'float',
'nested',
'path'
)

Expand Down
11 changes: 11 additions & 0 deletions src/plone.server/plone/server/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from plone.server.interfaces import IObjectFinallyVisitedEvent
from plone.server.interfaces import IObjectPermissionsViewEvent
from plone.server.interfaces import IObjectPermissionsModifiedEvent
from plone.server.interfaces import IBeforeJSONAssignedEvent
from zope.component._api import getSiteManager
from zope.component._declaration import adapter
from zope.component.interfaces import ComponentLookupError
Expand Down Expand Up @@ -59,6 +60,16 @@ def __init__(self, user):
self.user = user


@implementer(IBeforeJSONAssignedEvent)
class BeforeJSONAssignedEvent(object):
"""An object is going to be assigned to an attribute on another object."""

def __init__(self, object, name, context):
self.object = object
self.name = name
self.context = context


def modified_object(obj, event):
"""Set the modification date of an object."""
now = datetime.now(tz=_zone)
Expand Down
2 changes: 2 additions & 0 deletions src/plone.server/plone/server/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from plone.server.interfaces.files import IFileManager # noqa
from plone.server.interfaces.files import IStorage # noqa
from plone.server.interfaces.files import NotStorable # noqa
from plone.server.interfaces.json import IJSONField # noqa
from plone.server.interfaces.json import IBeforeJSONAssignedEvent # noqa
from plone.server.interfaces.text import IRichText # noqa
from plone.server.interfaces.text import IRichTextValue # noqa
from plone.server.interfaces.types import IConstrainTypes # noqa
Expand Down
50 changes: 0 additions & 50 deletions src/plone.server/plone/server/interfaces/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@
from zope.interface import Interface, Attribute
from zope.interface import implementer
from zope.schema.interfaces import IField
from zope.schema._bootstrapfields import Field
from jsonschema import validate, ValidationError
from zope.schema.interfaces import WrongType
from zope.schema.interfaces import WrongContainedType
from zope.event import notify

import json


class IJSONField(IField):
Expand All @@ -20,39 +13,6 @@ class IJSONField(IField):
)


@implementer(IJSONField)
class JSONField(Field):

def __init__(self, schema, **kw):
if not isinstance(schema, str):
raise WrongType

try:
self.schema = json.loads(schema)
except ValueError:
raise WrongType
super(JSONField, self).__init__(**kw)

def _validate(self, value):
super(JSONField, self)._validate(value)

try:
validate(value, self.schema)
except ValidationError as e:
raise WrongContainedType(e.message, self.__name__)

def set(self, object, value):
# Announce that we're going to assign the value to the object.
# Motivation: Widgets typically like to take care of policy-specific
# actions, like establishing location.
event = BeforeJSONAssignedEvent(value, self.__name__, object)
notify(event)
# The event subscribers are allowed to replace the object, thus we need
# to replace our previous value.
value = event.object
super(JSONField, self).set(object, value)


class IBeforeJSONAssignedEvent(Interface):
"""An object is going to be assigned to an attribute on another object.
Expand All @@ -69,13 +29,3 @@ class IBeforeJSONAssignedEvent(Interface):

context = Attribute("The context object where the object will be "
"assigned to.")


@implementer(IBeforeJSONAssignedEvent)
class BeforeJSONAssignedEvent(object):
"""An object is going to be assigned to an attribute on another object."""

def __init__(self, object, name, context):
self.object = object
self.name = name
self.context = context
2 changes: 1 addition & 1 deletion src/plone.server/plone/server/json/deserialize_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from zope.schema.interfaces import IList
from zope.schema.interfaces import ISet
from zope.schema.interfaces import ITuple
from plone.server.interfaces.json import IJSONField
from plone.server.interfaces import IJSONField

import logging

Expand Down
43 changes: 43 additions & 0 deletions src/plone.server/plone/server/jsonfield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- encoding: utf-8 -*-
from zope.schema._bootstrapfields import Field
from jsonschema import validate, ValidationError
from zope.schema.interfaces import WrongType
from zope.schema.interfaces import WrongContainedType
from zope.event import notify
from zope.interface import implementer
from plone.server.interfaces import IJSONField

import json


@implementer(IJSONField)
class JSONField(Field):

def __init__(self, schema, **kw):
if not isinstance(schema, str):
raise WrongType

try:
self.schema = json.loads(schema)
except ValueError:
raise WrongType
super(JSONField, self).__init__(**kw)

def _validate(self, value):
super(JSONField, self)._validate(value)

try:
validate(value, self.schema)
except ValidationError as e:
raise WrongContainedType(e.message, self.__name__)

def set(self, object, value):
# Announce that we're going to assign the value to the object.
# Motivation: Widgets typically like to take care of policy-specific
# actions, like establishing location.
event = BeforeJSONAssignedEvent(value, self.__name__, object)
notify(event)
# The event subscribers are allowed to replace the object, thus we need
# to replace our previous value.
value = event.object
super(JSONField, self).set(object, value)
34 changes: 33 additions & 1 deletion src/plone.server/plone/server/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@
from plone.server.factory import make_app
from zope.component import getUtility
from zope.configuration.xmlconfig import include
from zope.component import getGlobalSiteManager
from zope.interface import Interface
from zope.security.interfaces import IInteraction
from plone.server.api.layer import IDefaultLayer
from plone.server.interfaces import IRequest
from zope.interface import implementer
from plone.server.auth.users import RootUser
from plone.server.auth.users import ROOT_USER_ID
from plone.server.directives import index
from plone.server.directives import metadata
from plone.server.jsonfield import JSONField
from plone.server.content import Resource
from zope.schema import List

import asyncio
import json
Expand Down Expand Up @@ -68,6 +73,33 @@
'utf-8')).decode('utf-8')
DEBUG = False

TERM_SCHEMA = json.dumps({
'type': 'object',
'properties': {
'label': {'type': 'string'},
'number': {'type': 'number'}
},
})


class IExample(Interface):

metadata('categories')

index('categories', type='nested')
categories = List(
title='categories',
default=[],
value_type=JSONField(
title='term',
schema=TERM_SCHEMA)
)


@implementer(IExample)
class Example(Resource):
pass


class MockView(View):

Expand Down
8 changes: 8 additions & 0 deletions src/plone.server/plone/server/testing.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@
.behaviors.attachment.IAttachment"
/>

<plone:contenttype
portal_type="Example"
schema=".testing.IExample"
class=".testing.Example"
behaviors=".behaviors.dublincore.IDublinCore
.behaviors.attachment.IAttachment"
/>

</configure>
19 changes: 19 additions & 0 deletions src/plone.server/plone/server/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,22 @@ def test_create_duplicate_id(self):
}
)
self.assertTrue(resp.status_code == 201)

def test_create_nested_object(self):
resp = self.layer.requester(
'POST',
'/plone/plone/',
data=json.dumps({
'@type': 'Example',
'title': 'Item1',
'id': 'item1',
'categories': [{
'label': 'term1',
'number': 1.0
}, {
'label': 'term2',
'number': 2.0
}]
})
)
self.assertTrue(resp.status_code == 201)

0 comments on commit c1081e0

Please sign in to comment.