Skip to content. | Skip to navigation

Personal tools
Log in
Sections
You are here: Home

Latest Plone Posts

How I made my wedding site

By Benoît Suttor from Planet Plone. Published on Mar 26, 2015.

So I'll getting maried !

I decide to make a website for my wedding with a list of gift, my honneymoon, presentation of my witnesses and so on.

I was looking for a litlle CMS with a "list of gift" (an online shopping) which can be installed on cheap and reliable hosting (An it's when I loose Plone)

Pyramid vs Django

I started looking on Pyramid (because I'm a Plone/Zope dev). I thought Kotti, but I didn't find a way to make easily gift, and I thougt project looks cool, but it'was maybe a little young for my kind of requirements. I didn't find good solution on pyramid for a wedding list. 

Such as I have some exprience in Django, And in my daily work, we started intereset on Geonode for GIS project.

-> I started looking on Django !

Django CMS vs Mezzanine

Django CMS and Django CMS e-commerce plugin. But it seems this project is a almost dead ? Last commit on github make me septic.

With little search, I found Mezzanine and Cartridge. I try it and It seems perfect for my porject, So I choose it !

Hosting

My first choose was OVH, because it's very cheap (5€ / month). But with little search, it is almost impossible to create a complex Django site (by complex, I mean a "Mezzanine" Django site, and it's not very complex). I pursued my searching... And I found Webfaction. They have local pythons, postgres, 600Go data for 10 € / month. It looks perfect for me, except they do not manage domain name directly. So I host my wedding site on webfaction and my domain name on OVH.

Maybe I could made an heroku Django website, but I was little affraid about complexity.

 

Next step is to create an online shop with Kotti or with Pyramid !

Testing web hook HTTP API callbacks with ngrok in Python

By Mikko Ohtamaa from Planet Plone. Published on Mar 26, 2015.

Today many API services provide webhooks calling back your website or system over HTTP. This enables simple third party interprocess communications and notifications for websites. However unless you are running in production, you often find yourself in a situation where … Continue reading

How to install Kotti CMS on Windows

By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

Yes, as expected, you can install Kotti CMS also on Windows if you have this constraint!

What is Kotti

From the official doc:

"""A high-level, Pythonic web application framework based on Pyramid and SQLAlchemy. It includes an extensible Content Management System called the Kotti CMS.

Kotti is most useful when you are developing applications that:
  • have complex security requirements
  • use workflows, and/or
  • work with hierarchical data
"""

It is developer friendly and with a good user interface. You can easily extend it, develop new features or install one of the available third party modules (search for Kotti on https://pypi.python.org/pypi if you want to browse existing modules ready to be used). Heavily inspired by Plone (http://plone.org).
If you want to evaluate Kotti you can install it locally (no database installation is required, you can use SQLlite during evaluation or development).
Otherwise if you are particular lazy there is a working demo online with admin / qwerty administrator credentials: 

Prerequisites

  • python (tested with python 2.7.9 but it should work also on newer versions)
  • Microsoft Visual C++ 9.0 available on the following url http://aka.ms/vcpython27 (needed for an issue with bcrypt)
  • virtualenv (suggested)

Installation steps

Once you have installed python from http://www.python.org you can start installing Kotti. I assume in this article that your Python installation path is C:\Python27.
Now create a new folder (it doesn't matter the name, in this article my folder name is just kotti):
> mkdir kotti
> cd kotti
Install virtualenv and create a new isolated python environment in your kotti dir:
> C:\Python27\Scripts\pip.exe install virtualenv> C:\Python27\Scripts\virtualenv.exe --no-site-packages .
Install Kotti and its requirements:
> Scripts\pip.exe install -r https://raw.github.com/Kotti/Kotti/stable/requirements.txt
> Scripts\pip.exe install Kotti

Put inside your kotti dir the app.ini file downloaded from:
Runs Kotti:
Scripts\pserve.exe app.ini
Starting server in PID 2452
serving on http://127.0.0.1:5000
Done!

Update 20150219: if you want to install Kotti as a standard Windows service see this tutorial: http://pyramid-cookbook.readthedocs.org/en/latest/deployment/windows.html.

Troubleshooting (tested on Windows Vista)

If Microsoft Visual C++ Compiler for Python 2.7 is not installed on your environment you'll get an error during the requirements installation phase (only on Windows):
> Scripts\pip.exe install -r https://raw.githubusercontent.co
m/Kotti/Kotti/stable/requirements.txt
....
  Running setup.py install for py-bcrypt
    building 'bcrypt._bcrypt' extension
    error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat).
Get it from http://aka.ms/vcpython27
    Complete output from command C:\Users\dmoro\kotti\Scripts\python.exe -c "imp
ort setuptools, tokenize;__file__='c:\\users\\dmoro\\appdata\\local\\temp\\pip-b
uild-mact2r\\py-bcrypt\\setup.py';exec(compile(getattr(tokenize, 'open', open)(_
_file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record c:\u
sers\dmoro\appdata\local\temp\pip-wcmy6c-record\install-record.txt --single-vers
ion-externally-managed --compile --install-headers C:\Users\dmoro\kotti\include\
site\python2.7:
    running install

    running build

    running build_py

    creating build

    creating build\lib.win-amd64-2.7

    creating build\lib.win-amd64-2.7\bcrypt

    copying bcrypt\__init__.py -> build\lib.win-amd64-2.7\bcrypt

    running build_ext

    building 'bcrypt._bcrypt' extension

    error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat).
Get it from http://aka.ms/vcpython27
You just need to install this requirement and all will work fine.

Troubleshooting 2 (tested on Windows 2008 R2 Server - updated 20150219)

You might experience other compilation errors on Windows due to different compiler versions, role management tool configuration, missing DLLs, environment variables (vcvars32.bat), missing header files, etc. The same C code that compiles fine on a Windows machine, on a different version of Windows could produce a compilation error (compiling under Windows is a pain).

Anyway the following links helped me a lot a install py-bcrypt under Windows 2008 R2 Server with Visual Studio 2008 Express (free version downloadable from http://go.microsoft.com/?linkid=7729279):

Links

Screenshots

Kotti's front page (from the public demo online):

Kotti's folder contents (from the public demo online), requires authentication:

All posts about Kotti


Kotti - avoid types addable in content root

By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

With Kotti CMS (http://kotti.pylonsproject.org/) you don't have to fight against the framework: after one or two days you'll love it and you will be productive.

You can add new content types mapped on database tables, extend existing ones, add one or more object actions, easy building of add and edit views without having to touch any html file.

Kotti is shipped with the pytest framework and I love it! The tests setup is very easy and you can mock or initialize your reusable fixtures with a dependency injection technique.

If your customer wants to use Windows, no problem:

How to prevent your content types to be added in content root

This blog post will explain how to prevent your content type to be added in the content root but only in Document types (they behave like folderish items too). What's the matter? The root itself is a Document.

My solution was similar to the following one, but a bit different:

# resources.py

from kotti.resources import TypeInfo
from kotti.resources import get_root
from kotti.resources import Content
...

class YourContentTypeInfo(TypeInfo):

    def addable(self, context, request):
        root = get_root()
        if context == root:
            return False
        return super(YourContentTypeInfo, self).addable(context, request)

yourcontent_type_info_data = Content.type_info.copy(
    name=u'YourContent',
    title=_(u'YourContent'),
    add_view=u'add_yourcontent',
    addable_to=[u'Document'],
    ).__dict__.copy()
yourcontent_type_info = YourContentTypeInfo(**course_type_info_data)

class YourContent(Content):
    """ A yourcontent type. """

    implements(IDefaultWorkflow)

    id = Column(Integer, ForeignKey('contents.id'), primary_key=True)
    ...

    type_info = yourcontent_type_info
I tried to inherit all the default options and actions from the default Content's type info. This way you'll inherit all the backend menu actions.

Done!

Feedback

After using Kotti for a while I can tell that the feedback is absolutely positive. It is the right choice when you don't need a much more complex system like Plone. So join the Python, Pyramid and Kotti community and say love to Kotti!
https://twitter.com/davidemoro/status/558188730222383104

All posts about Kotti

Kotti CMS - how to create a new content type with an image

By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

If you want to create a new content type based on an existing one with Kotti you need to write few lines of code and zero html for the add and edit views: it is very simple (browse Kotti's resources.py and views code).


Basically you have to extend the existing content type shipped with Kotti and add your custom fields.

But let's suppose you need a new content type named ImageWithLink with the following fields:
  • title
  • description
  • image
  • link
In this case the implementation is more verbose compared to extend another content type (like the Document, but it is still an easy job).

resources.py
from zope.interface import implements
from kotti.resources import Image
from kotti.interfaces import IImage
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Unicode


class ImageWithLink(Image):
    implements(IImage)

    id = Column(Integer, ForeignKey('images.id'), primary_key=True)
    link = Column(Unicode(1000))

    type_info = Image.type_info.copy(
        name=u'ImageWithLink',
        title=u'ImageWithLink',
        add_view=u'add_image_link',
        addable_to=['Document'],
        )

    def __init__(self, link=u"", **kwargs):
        super(ImageWithLink, self).__init__(**kwargs)
        self.link = link 
The code is quite self-explaining: you create a new ImageWithLink class that inherits from Image. You only need to add your custom field named link and you initialize the link in the __init__ code after calling the super method.

views/content.py
import colander
from deform import FileData
from deform.widget import FileUploadWidget
from kotti.views.edit import ContentSchema
from kotti.views.edit.content import ImageEditForm
from kotti.views.edit.content import ImageAddForm
from kotti.views.form import validate_file_size_limit
from kotti.views.form import FileUploadTempStore
from kotti.views.form import AddFormView
from pyramid.view import view_config
from kotti_yourplugin import _
from kotti_yourplugin.resources import ImageWithLink
from kotti_yourplugin.validators import link_validator


def ImageWithLinkSchema(tmpstore):
    """ File schema with no set title missing binding """
    class ImageWithLinkSchema(ContentSchema):
        file = colander.SchemaNode(
            FileData(),
            title=_(u'File'),
            widget=FileUploadWidget(tmpstore),
            validator=validate_file_size_limit,
            )
        link = colander.SchemaNode(
            colander.String(),
            title=_('Link'),
            validator=link_validator,
            missing=u'',
            )

    def after_bind(node, kw):
        del node['tags']

    return ImageWithLinkSchema(after_bind=after_bind)


@view_config(name='edit', permission='edit',
             renderer='kotti:templates/edit/node.pt')
class ImageWithLinkEditForm(ImageEditForm):
    def schema_factory(self):
        tmpstore = FileUploadTempStore(self.request)
        return ImageWithLinkSchema(tmpstore)


@view_config(name=ImageWithLink.type_info.add_view, permission='add',
             renderer='kotti:templates/edit/node.pt')
class ImageWithLinkAddForm(ImageAddForm):
    item_type = _(u"Banner Box")
    item_class = ImageWithLink

    def schema_factory(self):
        tmpstore = FileUploadTempStore(self.request)
        return ImageWithLinkSchema(tmpstore)

    def save_success(self, appstruct):
        # override this method (no filename as title
        # like images)
        return AddFormView.save_success(self, appstruct)

    def add(self, **appstruct):
        # override (no tags in our form)
        buf = appstruct['file']['fp'].read()
        filename = appstruct['file']['filename']
        return self.item_class(
            title=appstruct['title'] or filename,
            description=appstruct['description'],
            data=buf,
            filename=filename,
            mimetype=appstruct['file']['mimetype'],
            size=len(buf),
            )
Here the code is more complex. There is a dynamic schema definition with the Kotti's temp store implementation. Both the add and the edit form refer to this schema, with some overrides because our object does not behave like files or images.

validators.py
UPDATE 20150211: no need to write this validator. Use the url validator provided by colander instead (colander.url). Anyway you can use all the builtin colander validators or write your own validators.

import re
import colander
from kotti_yourplugin import _


VALID_PROTOCOLS = ('http',)
URL_REGEXP = r'(%s)s?://[^\s\r\n]+' % '|'.join(VALID_PROTOCOLS)


def link_validator(node, value):
    """ Raise a colander.Invalid exception if the provided url
        is not valid
    """
    def raise_invalid_url(node, value):
        raise colander.Invalid(
            node, _(u"You must provide a valid url."))
    if value:
        if not re.match(URL_REGEXP, value):
            raise_invalid_url(node, value)
Here you can see an example of link validator based on a regular expression. This validator decorates our link field of the ImageWithLink schema.

Obviously you need to add in your kotti_configure method your ImageWithLink in the kotti.available_types settings.

__init__.py
def kotti_configure(settings):
    settings['pyramid.includes'] += ' kotti_yourplugin'
    settings['kotti.available_types'] += ' kotti_yourplugin.resources.ImageWithLink'

and enable your configurator in your .ini file:
kotti.configurators =     mip_course.kotti_configure

And what about the default view of your content types? If you visit an ImageWithLink box it will behave like an image: it inherits the default view of the image (you should customize it adding the link on the image, very simple: not showed in this blog post), no need to deal with the image resize machinery, etc.

As you can see, Kotti is a flexible solution if you need a simple but powerful CMS solution based on Python, Pyramid and SQLAlchemy. You may consider it as a simple framework (but easy to understand, don't be scared by the word framework. It is really developer friendly). If you are curious about how to manage contents with Kotti you may play with the demo online: http://kottidemo.danielnouri.org/ (admin - qwerty).

All posts about Kotti

Kotti CMS - workflow reference

By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

Yet another blog post about Kotti CMS (http://kotti.pylonsproject.org/): this time I'm going to talk about workflows and security.

Workflows in Kotti are based on repoze.workflow. See http://docs.repoze.org/workflow/ for further information. Basically you can use an xml file (zcml) in order to describe your workflow definition. You can see an example here: https://github.com/Kotti/Kotti/blob/master/kotti/workflow.zcml. A you can see it is quite straightforward adding new states, new transitions, new permissions, etc. You can easily turn your 2-states website workflow into a 3-states website workflow with reviewers or turn Kotti app into an intranet application.

The default workflow definition is loaded from your project .ini file settings (using the kotti.use_workflow settings). The kotti.use_workflow setting's default value is:
kotti.use_workflow = kotti:workflow.zcml
but can change change default workflow for the whole site, register new workflows related to specific content types or disable it as well.

Anyway, if you need to write a Python based CMS-ish application with hierarchical contents, custom content types, workflows, security, global and local ACL (sharing permissions), pluggable and extensible, based on relational databases, developer friendly, with a simple UI, etc... Kotti is your friend!

How to disable the default workflow

Kotti is shipped with a simple workflow implementation based on private and public states. If your particular use case does not require workflows at all, you can disable this feature with a non true value. For example:
kotti.use_workflow = 0

How to override the Kotti's default workflow for all content types

The default workflow is quite useful for websites, but sometimes you need something of different. Just change your workflow setting and point to your zcml file:
kotti.use_workflow = kotti_yourplugin:workflow.zcml
The simplest way to deal with workflow definitions is:
  • create a copy of the default workflow definition
  • customize it (change permissions, add new states, permissions, transitions, initial state and so on)
If your site already has content and you configure it use a workflow for the first time, or you use a different workflow than the one you used before, run the kotti-reset-workflow command to reset all your content's workflow.

    How to enable the custom workflow for images and files

    Images and files are not associated with the default workflow. If you need a workflow for these items you need to attach the IDefaultWorkflow marker interface.

    You can add the following lines in your includeme function:
    from zope.interface import implementer
    from kotti.interfaces import IDefaultWorkflow
    from kotti.resources import File
    from kotti.resources import Image
    ...

    def includeme(config):
        ...
        # enable workflow for images and files
        implementer(IDefaultWorkflow)(Image)
        implementer(IDefaultWorkflow)(File)
        ...

    How to assign a different workflow to a content type

    In this kind of situation you want to use the default workflow for all your types and a different workflow implementation for a particular content type.

    You'll need to:
    • create the new workflow definition, with a workflow elector
    • write an elector function that will returns True or False depending if the workflow should be applied (otherwise will win the default default workflow, or better, the first matching workflow without an elector)
    • load manually your zcml file in your includeme function
    .ini file (optional)
    kotti_boxes.use_workflow = kotti_boxes:workflow.zcml
    __init__.py

    from pyramid.i18n import TranslationStringFactory
    from kotti import FALSE_VALUES


    def includeme(config):
        ...
        workflow = config.registry.settings.get('kotti_boxes.use_workflow', None)
        if workflow and workflow.lower() not in FALSE_VALUES:
            config.begin()

            config.hook_zca()
            config.include('pyramid_zcml')
            config.load_zcml(workflow)
            config.commit()

        ...


    workflow.py
    From the repoze.workflow documentation: """A workflow is unique in a system using multiple workflows if the combination of its type, its content type, its elector, and its state_attr are different than the combination of those attributes configured in any other workflow."""
    Depending on how specific is your combination you may need to implement an elector (a function that returns True or False for a given context).
    from kotti_boxes.interfaces import IBoxWorkflow


    def elector(context):
        return IBoxWorkflow.providedBy(context)
    workflow.zcml
    <configure xmlns="http://namespaces.repoze.org/bfg"
               xmlns:i18n="http://xml.zope.org/namespaces/i18n"
               i18n:domain="Kotti">

      <include package="repoze.workflow" file="meta.zcml"/>

      <workflow
          type="security"
          name="simple"
          state_attr="state"
          initial_state="private"
          content_types="kotti_boxes.interfaces.IBoxWorkflow"
          elector='kotti_boxes.workflow.elector'
          permission_checker="pyramid.security.has_permission"
          >

        <state name="private" callback="kotti.workflow.workflow_callback">

          <key name="title" value="_(u'Private')" />
          <key name="order" value="1" />

          <key name="inherit" value="0" />
          <key name="system.Everyone" value="" />
          <key name="role:viewer" value="viewbox view" />
          <key name="role:editor" value="viewbox view add edit delete state_change" />
          <key name="role:owner" value="viewbox view add edit delete manage state_change" />

        </state>

        ...

      <transition
          name="private_to_public"
          from_state="private"
          to_state="public"
          permission="state_change" />
      ...

      </workflow>

    </configure>

    All posts about Kotti

    Kotti CMS - how to store arbitrary data with annotations

    By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

    With Kotti CMS you can extend existing types inheriting from a base class (eg: Document) and obtain another type of object (eg: MyDocument) with new fields, new workflows, custom views, custom addability conditions, etc.

    But sometimes you may want to add a custom field to one or more resources, without having to create a new type. For example you might want to add a colour attribute to all existing Document objects, let's imagine a simple select widget with few colours that will be used for adding a class depending on the choosen colour.

    By default Kotti is shipped with an annotations column that can be used to store arbitrary data in a nested dictionary.

    You can store arbitrary data in the nested dictionary with a syntax similar to the following one:
    context.annotations['SOMEKEY'] = VALUE
    and read annotations with:
    context.annotations
    All you need to do is overriding the add and edit form of your target class. With Pyramid is quite easy to extending an existing application and override views, assets, routes, etc. See http://docs.pylonsproject.org/docs/pyramid/en/latest/narr/extending.html for further info.

    Here you can see one possible implementation:
    from pyramid.view import view_config
    import colander
    from deform.widget import SelectWidget
    from kotti_actions.views.edit.actions.link import (
        LinkActionAddForm as OriginalLinkActionAddForm,
        LinkActionEditForm as OriginalLinkActionEditForm,
        )
    from kotti_actions.resources import (
        LinkAction
        )
    ...
            colours = [
                ('', 'Select'),
                ('red', 'Red'),
                ('brown', 'Brown'),
                ('beige', 'Beige'),
                ('blue', 'Blue'),
                ]

    def add_colour(schema):
        schema['colour'] = colander.SchemaNode(
            colander.String(),
            title=_('Colour'),
            widget=SelectWidget(values=colours),
            missing=u"",
            )

    @view_config(name=LinkAction.type_info.add_view, permission='add',
                 renderer='kotti:templates/edit/node.pt')
    class LinkActionAddForm(OriginalLinkActionAddForm):
        """ Form to add a new instance of CustomContent. """

        def schema_factory(self):
            schema = super(LinkActionAddForm, self).schema_factory()
            add_colour(schema)
            return schema

        def add(self, **appstruct):
            colour = u''
            try:
                colour = appstruct.pop('colour')
            except KeyError:
                pass
            obj = super(LinkActionAddForm, self).add(**appstruct)

            obj.annotations['colour'] = colour
            return obj


    @view_config(name='edit', context=LinkAction, permission='edit',
                 renderer='kotti:templates/edit/node.pt')
    class LinkActionEditForm(OriginalLinkActionEditForm):
        """ Form to edit existing calendars. """

        def schema_factory(self):
            schema = super(LinkActionEditForm, self).schema_factory()
            add_colour(schema)
            return schema

        def before(self, form):
            super(LinkActionEditForm, self).before(form)
            colour = self.context.annotations.get('colour')
            if colour:
                form.appstruct.update({'colour': colour})

        def edit(self, **appstruct):
            super(LinkActionEditForm, self).edit(**appstruct)
            self.context.annotations['colour'] = appstruct['colour']

    Now our LinkAction add and edit form will have an additional select with our colours.

    All posts about Kotti

    Kotti CMS - how to turn your Kotti CMS into an intranet

    By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

    In the previous posts we have seen that Kotti is a minimal but robust high-level Pythonic web application framework based on Pyramid that includes an extensible CMS solution, both user and developer friendly. For developer friendly I mean that you can be productive in one or two days without any knowledge of Kotti or Pyramid if you already know the Python language programming.

    If you have to work relational databases, hierarchical data, workflows or complex security requirements Kotti is your friend. It uses well know Python libraries.

    In this post we'll try to turn our Kotti CMS public site into a private intranet/extranet service.

    I know, there are other solutions keen on building intranet or collaboration portals like Plone (I've been working 8 years on large and complex intranets, big public administration customers with thousands of active users and several editor teams, multiple migrations, etc) or the KARL project. But let's pretend that in our use case we have simpler requirements and we don't need too complex solutions, features like communities, email subscriptions or similar things.

    Thanks to the Pyramid and Kotti's architectural design, you can turn your public website into an intranet without having to fork the Kotti code: no forks!

    How to turn your site into an intranet

    This could be an hard task if you use other CMS solutions, but with Kotti (or the heavier Plone) it will requires you just 4 steps:
    1. define a custom intranet workflow
    2. apply your custom worklows to images and files (by default they are not associated to any workflow, so once added they are immediatly public) 
    3. set a default fallback permission for all views
    4. override the default root ACL (populators)

    1 - define a custom intranet workflow

    Intranet workflows maybe different depending on your organization requirements. It might be very simple or with multiple review steps.

    The important thing is: no more granting the view permission for anonymous users, unless you are willing to define an externally published state

    With Kotti you can design your workflow just editing an xml file. For further information you can follow the Kotti CMS - workflow reference article.

    2 - apply your custom workflow to images and files

    By default they are not associated to any workflow, so once added they are immediately public.

    This step will requires you just two additional lines of code in your includeme or kotti_configure function.

    Already described here: Kotti CMS - workflow reference, see the "How to enable the custom workflow for images and files" section.

    3 - set a default fallback permission

    In your includeme function you just need to tell the configurator to set a default permission even for public views already registered.

    I mean that if somewhere into the Kotti code there is any callable view not associated to a permission, it won't be accessible by anonymous after this step.

    In your includeme function you'll need to :
    def includeme(config):
        ...
        # set a default permission even for public views already registered
        # without permission
        config.set_default_permission('view') 
    If you want to bypass the default permission for certain views, you can decorate them with a special permission (NO_PERMISSION_REQUIRED from pyramid.security) which indicates that the view should always be executable by entirely anonymous users, regardless of the default permission. See:

    4 - override the default root ACL (populators)

    The default Kotti's ACL associated with the root of the site
    from kotti.security import SITE_ACL
    gives view privileges to every user, including anonymous.
    You can override this configuration to require users to log in before they can view any of your site's pages. To achieve this, you'll have to set your site's ACL as shown on the following url:
    You'll need you add or override the default populator. See the kotti.populators options here:

    Results

    After reading this article you should be able to close your Kotti site for anonymous users and obtaining a simple, private intranet-like area.

    Off-topic: you can also use Kotti as a content backend-only administration area for public websites, with a complete decoupled frontend solution.

    Useful links

    All posts about Kotti

    Pyramid, MySQL and Windows: the good, the ugly and the bad

    By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

    Pyramid, MySQL and Windows: the good (Pyramid), the ugly and the bad. This title does not fit perfectly the main characters of this blog post because some of theme are both ugly and bad, but it doesn't matter.

    Just in case you are going to set up a Pyramid project based on MySQL and Windows (sometimes you have to)... there are a couple of things useful to know. But let's start with a chronologically order.

    Day 0 - morning

    You feel like the brave Steeve McQueen:

    Evening - day 0

    At the end of the day you'll feel also like Steeve McQueen, but a little more proved:


    What happened?

    Random problems with normal transactions considered too large, thread disconnected, error log entries like:
    • InterfaceError
    • OperationalError
    • MySQL Server has gone away
    • database connection failure
    • TimeoutError: QueuePool limit of size ... overflow ... reached, connection timed out, timeout ...
    • pyramid process hangs
    • etc

    The solution


    1 - adjust your my.ini options like that:
    [mysqld]
    max_allowed_packet = 64MB # adjust this parameter according to your situation
    wait_timeout = 28800
    interactive_timeout = 2880
    2 - be sure your production.ini file looks like the following one (with Python 2):
    sqlalchemy.url = mysql+mysqldb://USER:PASSWORD@127.0.0.1:3306/YOURDB?charset=utf8&use_unicode=0
    # For Mysql "MySQL Connection Timeout and SQLAlchemy Connection Pool Recycling" issues see:
    # http://docs.sqlalchemy.org/en/latest/core/pooling.html#setting-pool-recycle
    # http://douglatornell.ca/blog/2012/01/08/staying-alive/
    sqlalchemy.pool_recycle = 3600
    3 - you can schedule a restart of your application once a day.

    4 - [OPTIONAL, not only Windows related] adjust your SqlAlchemy configuration parameters according to how many threads your server runs. For example (production.ini):
    sqlalchemy.pool_size = 20
    sqlalchemy.max_overflow = 10
    5 - if you are using CherryPy as a Windows service, be sure your  'engine.autoreload.on' option is set to False.

    Results

    No more exceptions or odd behaviours!

    Links

      Kotti CMS events - insert subobjects automatically

      By davide moro (noreply@blogger.com) from Planet Plone. Published on Mar 25, 2015.

      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

      Reboot of my Plone activities

      By Kamon Ayeva from Planet Plone. Published on Mar 22, 2015.

      The first months of this year have seen more activities on the Plone front in my realm, and there are signs of a regain of energy for future work and collaborations. Let me share some information here.

      Meetups in Geneva

      I started proposing a monthly Plone meetup. Though everyone is busy these days, we had 3 participants for each of the february and march meetups. Here is the combined summary of the stuff we discussed with links to useful resources for people interested.

      Plone theming

      We talked about Diazo in the perspective of the "move from old practices to use the currently recommended way" mantra.

      Diazo is a theming engine integrated to Plone, actually since Plone 4.2. Diazo allows you to apply an HTML/CSS theme to your Plone site. Since Plone 4.3, there is a theme editor which you can see showcased in this video by Eric Steele.

      File-system-based vs. Through-the-web customizations

      In summary, the advice is this: Avoid doing everything through the web!

      Through the web customization, though helpful, can lead to a trap: the inability to translate your work into code which can be versioned, reused across sites and by a community of webmasters. And sometimes simply debugging and fixing your customizations will be tricky.

      In case you have missed it, this article from the Six Feet Up blog gives advices for keeping all customizations (e.g., templates, Python code, stylesheets, javascript code) in version control and using the through-the-web trick sparingly. The article also discusses how to make customizations properly when needed.

      Bob templates

      mr.bob is a generic Python project scaffolding tool. It helps speed developers' work and their adherence to best practices. In the Plone world, mr.bob provides a replacement for ZopeSkel with the bobtemplates.plone package, a set of templates for creating our add-on packages.

      Front-end stuff

      • Icono: Not strickly related to Plone, but Icono is an icon pack I like to use for small projects or static apps. It doesn’t require external resources; only CSS (i.e. no font or svg). Can be seen as a lightweight alternative to FontAwesome, which I also use.

      Plone support offer

      I re-started helping people with projects where Plone is the preferred choice. Or Pyramid.

      Note that my process for taking and delivering work is more optimized for cases where you come with a clearly defined picture of you want and you need me for specific tasks.

      To make things dead simple for me and others, I am using the microtasks platform Fiverr for handling everything. So if you are someone who sees outsourcing as a natural way of doing things and getting productive, or if you just want to offload small maintenance tasks, you are welcome to use my Fiverr Gigs. You can also use their custom order feature when you have more involved work planned.

      In addition to that, I am available on AirPair, a micro-consulting service site.

      On the horizon

      • I started exploring Node.js which, added to Python, gives us the choice between 2 powerful sets of scripting tools and frameworks. Obviously, I quickly came accross Express, and I will definitely play with it on a project this year.

      • There is a Static Apps online class in the works. I will talk about it in a dedicated post.

      Thanks

      I want to thank Nicola Lazzari and Gianguglielmo Calvi I recently met in Geneva and started collaborating with, for their trust in Plone, and their commitment to try and convince people around them to use these tools for their Internet and intranet projects.

      All scripts in the basket

      By Manuel Reinhardt from Planet Plone. Published on Mar 20, 2015.

      In a buildout that has several sections using zc.recipe.egg I had the problem that a script I was building in one section ended up with the initialization of another script in another section.

      Let's assume we have an egg "main_egg_a" that defines a script "script_a" and "common_egg" defines a script "common_script" and a couple of other scripts. The way we want to use script_a requires us to also include "common_egg" in the respective section. In the other section we want only "common_script", skipping any other scripts declared by "common_egg", so we declare it with the "scripts" option.

      [script-a]
      recipe = zc.recipe.egg
      eggs =
      main_egg_a
      common_egg
      initialization =
      import os
      os.environ["foo"] = "emerald"

      [script-b]
      recipe = zc.recipe.egg
      eggs =
      common_egg
      scripts = common_script
      initialization =
      import os
      os.environ["foo"] = "zirconia"

      With this configuration however, bin/common_script kept having "emerald" set in the environment variable.

      The problem is that the section [script-a] does not have a "scripts" option, but also includes common_egg. Without "scripts" declared it builds all the scripts in the given eggs, here script_a and common_script. If both sections build bin/common_script, the result depends on the order of execution. In my setup the script-b section always ran first, building bin/common_script with "zirconia" as the value for "foo". Then script-a ran afterwards, overwriting the previously built bin/common_script using its own setting for "foo", "emerald".

      The fix is simple once you've figured out what's going on: Declare "scripts" if you give multiple eggs to the recipe.

      [script-a]
      recipe = zc.recipe.egg
      eggs =
      main_egg_a
      common_egg
      scripts = script_a
      initialization =
      import os
      os.environ["foo"] = "emerald"

      [script-b]
      recipe = zc.recipe.egg
      eggs =
      common_egg
      scripts = common_script
      initialization =
      import os
      os.environ["foo"] = "zirconia"

      Omit attribute in TAL

      By Gillian Sampont from Planet Plone. Published on Mar 18, 2015.

      I always tough than it was impossible to completely omit a tag attribute using TAL. So when I wanted to automatically check or not a radio button, I duplicated it like this: But we can omit a tag attribute by passing nothing to a tal:attributes, like […]

      Fix tinyMCE small font problem

      By ledwell from Planet Plone. Published on Mar 18, 2015.

      Fixes font and spacing problem when using bootstrap and diazo

      Best Practices for Customizing Your Live Plone Site

      By Chrissy Wainwright from Planet Plone. Published on Mar 18, 2015.

      Customizations Header Graphic

      Plone is increasingly allowing you to build an entire site through the web (TTW). This is great for new Plone users or when you need to throw up a site quickly without dealing with the code. But if you are a Plone developer, I recommend keeping all your customizations in version control (like Subversion or Git), only doing TTW customizations sparingly.

      For customizations, I am referring to making changes to templates, Python code, stylesheets or Javascript that may be in the Theming control panel, portal_skins, or portal_view_customizations.

      Why should these customizations be avoided?

    • When changes are made directly in the site, there is no information kept as to when or why that change was made. When changes are checked into version control, this information is stored in the commit, which can prevent many future headaches.
    • If you make a mistake in the customization, it can break your site. This tends to be limited to a single page or template, but I've also had to clean up after a client that rendered their site completely useless after they had made a change to the colophon.
    • With customizations, you're more likely to be in a hurry and not fully test the changes being made.
    • Also keep in mind that with any Plone upgrade, you should update your customized templates if those templates had changes in the Plone core. This will especially be needed when upgrading to Plone 5, where many templates have been moved, and can no longer be customized using portal_skins. For me, managing these updates is much easier when working with the code.
    • How to make customizations properly

      First decide if it's appropriate to do directly on prod - Think twice before applying some complex solution directly on your production instance. If it is a change that may need extensive testing, don't do it on prod.

      Add comments - Add a comment with the line of code you are changes, so you can remember later why it was done.

      Commit the change - When you do make a change on prod, apply the same change to your code so there is a record of the change, why it was done, and what ticket is it attached to. With this commit, you can also include an upgrade step that will remove the customized file next time the code is released.

      Process is Important

      Here is the general process we follow for fixing bugs or adding customizations to a site:

    • Use a local checkout of the site, make the change, test and commit.
    • Tag the code and release it to a testing instance.
    • Test the code. If there's something wrong, it goes back to the developer. Repeat steps until your QA team says the code is good.
    • Release the code to prod.
    •  

      Was this article useful? Let us know in the comments below. For more, be sure to sign up for our Plone & Python How-To digests and receive how-to guides as soon as they are published!