Quantcast
Channel: Davide Moro
Viewing all articles
Browse latest Browse all 25

Kotti CMS events - insert subobjects automatically

$
0
0
Yet another small recipe for Kotti CMS: how to initialize automatically a new object once inserted with events, for example adding a subobject.

Use case? When someone creates a UserProfile object /users/name-surname, an event should create automatically a profile image in /users/name-surname/photo (a Kotti image instance).

It is quite simple. Let's see our your_package/events.py module, where IMAGE_ID is equals to 'photo':
import os
from kotti.events import (
ObjectInsert,
subscribe,
notify,
)
from kotti.resources import Image
from your_package.resources import UserProfile
from your_package.config import IMAGE_ID


@subscribe(ObjectInsert, UserProfile)
def user_profile_added(event):
obj = event.object

if IMAGE_ID not in obj.keys():
image_path = os.path.join(
os.path.dirname(__file__),
'data', 'fallback.png'
)
with open(image_path, 'rb') as image_file:
obj[IMAGE_ID] = image_obj = Image(
title='Image',
in_navigation=False,
data=image_file.read(),
filename=u'fallback.png',
mimetype=u'image/png',
)
notify(ObjectInsert(image_obj, event.request)) 
Notes:
  1. the subscribe decorator will register our handler when a UserProfile resource will be inserted
  2. we should check if IMAGE_ID is already instanciated (prevent errors on paste)
  3. if you want your code will work both for Unix-like or under Windows, use os.path.join instead of a plain data/fallback.png path (path separator issues)
  4. the final b in the open is important if you want to write code that works under Windows, see https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files. On Unix, it doesn’t hurt to append a 'b' to the mode, so you can use it platform-independently for all binary files
  5. notify the image insertion
And your_package/__init__.py (in this example I've used the scan method but you could also register your event handlers imperatively):
...
def includeme(config):
""" Don't add this to your ``pyramid_includes``, but add the
``kotti_configure`` above to your ``kotti.configurators`` instead.

:param config: Pyramid configurator object.
:type config: :class:`pyramid.config.Configurator`
"""
...
config.scan(__name__)
And... tests of course (your_package/tests/test_events.py):
from pytest import fixture

from kotti.testing import DummyRequest


@fixture
def user_profile(db_session, config, root):
""" returns dummy UserProfile.
"""
config.include('your_package')

from your_package.resources import UserProfile
root['userprofile'] = userprofile = UserProfile(title='UserProfile')
from kotti.events import notify
from kotti.events import ObjectInsert
notify(ObjectInsert(course, DummyRequest())) return userprofile


class TestUserProfileWithEvents:

def test_assert_userprofile_image(self, user_profile):
from your_package.config import IMAGE_ID
assert IMAGE_ID in user_profile.keys()
...
You can test also if everything goes right after a copy/paste action (see the Kotti's tests).

Done!

All posts about Kotti

All Kotti posts published by @davidemoro:



    Viewing all articles
    Browse latest Browse all 25

    Trending Articles