# pincode.py
from my.addon import _
from plone.app.contenttypes.interfaces import IFile
from plone.autoform.interfaces import IFormFieldProvider
from plone.dexterity.interfaces import IDexterityContent
from plone.supermodel import model
from zope import schema
from zope.component import adapter
from zope.interface import implementer
from zope.interface import Interface
from zope.interface import provider
import random
def create_pincode():
return random.randint(1000, 9999)
class IPinCode(Interface):
pass
@provider(IFormFieldProvider)
class IPinCodeBehavior(model.Schema):
pin = schema.Int(
title=_("Pin Code"),
description=_("the PIN Code to protect the File"),
defaultFactory=create_pincode,
readonly=False,
min=1000,
max=9999,
required=False,
)
@implementer(IPinCodeBehavior)
@adapter(IFile)
class PinCode(object):
def __init__(self, context):
self.context = context
@property
def pin(self):
return self.context.pin
@pin.setter
def pin(self, value):
self.context.pin = value
Here a little Test:
def test_instance_behavior(self):
self.portal.invokeFactory("File", id="file1", title="File 1")
file1 = self.portal.file1
from my.addon.behaviors.pincode import IPinCodeBehavior
from collective.instancebehavior import enable_behaviors
from collective.instancebehavior import IInstanceBehaviorAssignableContent
from collective.instancebehavior import instance_behaviors_of
enable_behaviors(
file1,
["my.addon.pincode"],
[IPinCodeBehavior], # The marker interface or the schema ???
)
self.assertIn(
"my.addon.pincode",
instance_behaviors_of(file1),
"Instance Behavior IPinCode not enabled",
)
self.assertTrue(
IPinCodeBehavior.providedBy(file1),
"IPinCodeBehavior not provided by File1",
)
aspect = IPinCodeBehavior(file1, None)
if aspect is not None:
print(aspect.pin) # don't work
# AttributeError: 'RequestContainer' object has no attribute 'pin'
If i use the Behavior in the normal way via FTI all is fine. But if i use collective.instancebehavior, my behavior is not available, i get an error. I think i forgot something. The Note in the Readme of collective.instancebehavior say:
Note: the targeted object must implement collective.instancebehavior.IInstanceBehaviorAssignableContent.
Context has to provide IInstanceBehaviorAssignableContent. You can inherit it to some marker interface used by the behavior or, if you use base classes, let them implement it.
In the product shop we use it to dynamically assign variants. A base behavior says: this product may have variants:
and in the next step one can activate variant aspects as instance behaviors to it.