Ploneboard Migration Revisited

之前經驗是 Plone 2.5 昇級到 Plone 3.1,這次是 Plone 4.0.x 到 Plone 4.1.x。總結地說,這段昇級的挑戰主要是因應 Products.TinyMCE 的調整。

測試流程是先在 Plone 4.0.7 (+ TinyMCE 1.1.10) 安裝 Ploneboard 2.2,安裝過程中遇到 Kupu 的 Resource Type 設定內容要把 Large Plone Folder 取消勾選,存檔生效,不然會有 KupuError,在 Products/SimpleAttachment/setuphandlers.py 第 29 行,已經不認得 Large Plone Folder 型別。

 Resource type: linkable, invalid type: Large Plone Folder

另外 Products/Ploneboard/skins/ploneboard_templates/add_conversation_form.cpt 第 36 行要檢查 context 和 python:context 的差別。

如果 Plone 4.0.x 改裝 Ploneboard 3.0 以上,會遇到 Products.CMFPlone >= 4.1 的相依問題。另外,Products.Ploneboard/vocabulary.py 視情況要修改:

-from zope.app.schema.vocabulary import IVocabularyFactory
+from zope.schema.interfaces import IVocabularyFactory

接著,在 Plone 4.1.5 (+ TinyMCE 1.2.11) 安裝 Ploneboard 3.3 (src from github),把 var/filestorage/Data.fs 和 var/blobstorage 複製到新環境,到 ZMI 執行昇級,過程沒遇到問題,但實際的 Ploneboard conversation view 可能會遇到 RuntimeError:

   - URL: file:/home/marr/plone415/buildout-cache/eggs/Products.TinyMCT-1.2.11-py2.6.egg \
   - Line 6, Column 2
   - Expression: <PathExpr standard:u'object|here'>
   - Warning: Macro expansion failed
   - Warning: <type 'exceptions.KeyError'>: 'support'
RuntimeError: maximum recursion depth exceeded while calling a Python object

猜想這只發生在使用 TinyMCE 的場合,根據 https://github.com/plone/Products.TinyMCE/pull/22 的說明,改用 nocall 方式,可以解決這問題。


Listing Plone Member Properties

Be sure first see member profile documentation for more examples. Here is a Script in ZMI to list member property on wysiwyg_editor setting. Member property listing can be found at /portal_memberdata Properties tab.

from Products.CMFCore.utils import getToolByName

membership = getToolByName(context, 'portal_membership')
for member in membership.listMembers():
   print member, member.getProperty('wysiwyg_editor')

return printed

Plone Theme Transition

試用 plonetheme.transition 的心得:優點是基本配色還不錯,列表用的小圖示很亮眼,缺點是 layout 不會隨瀏覽器縮放,預設字級太小,字級變大的話,會造成管理選單的字樣被擠壓,personal tool 放在頁尾處,mouse over 的底色會讓選項字樣消失,左側 portlet 被改到下方。


Plone Undocumented Content Rules Limit

One of my Plone instances has around 100 content rules added, and then hit by an error:

... ...
 Module plone.app.contentrules.namechooser, line 30, in chooseName
 Module zope.container.contained, line 761, in checkName
KeyError: u'The given name is already being used'

From #plone channel, @MacYET tells me to use PDB. Here is the info log:

> /opt/myplone/buildout-cache/eggs/zope.container-3.8.2-py2.6-linux-i686.egg
-> raise KeyError(
(Pdb) dir()
['name', 'object', 'pdb', 'reserved', 'self']
(Pdb) pp name
(Pdb) pp self
<plone.app.contentrules.namechooser.RuleNameChooser object at 0x10a33c6c>
(Pdb) pp self.context
<plone.contentrules.engine.storage.RuleStorage object at 0x10c2f0ac>
(Pdb) pp self.context.__dict__
{'_data': <BTrees.OOBTree.OOBTree object at 0xd97238c>,
 '_order': ['rule-1', ... ... 'rule-99', 'rule-100', 'rule-101']}

In plone/app/contentrules/namechooser.py:


class RuleNameChooser(NameChooser):
    """A name chooser for content rules.


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

    def chooseName(self, name, object):
        container = self.context

        if not name:
            name = object.__class__.__name__.lower()

        i = 1
        new_name = "%s-%d" % (name, i)
        while new_name in container and i <= ATTEMPTS:
            i += 1
            new_name = "%s-%d" % (name, i)

        self.checkName(new_name, object)
        return new_name

I can accept this is not a bug, but a documentation should be helpful.


Plone Content Rules

Content Rule 是 Plone 依據內容變更的條件,執行特定動作的規則,例如某個目錄裡新增了文件,就寄信通知管理員,類似 trigger 的概念。

設定通知信時,還可以指定變數,例如 ${contributor_emails} 代表系統及目錄所指派的貢獻者電子郵件,${owner_emails} 代表項目的擁有者電子郵件。

想要檢查 owner 設定值的話,可以在網址後面加上 /manage_listLocalRoles。


Google Analytics for Plone

collective.googleanalytics 是提供 Google Analytics 資訊的 Plone 模組,啟用前最好先用同一個瀏覽器登入 Google 帳號,在 Plone Site Setup 裡就可以建立授權要求。

在 Tracking Profile 下拉選單裡,會看到 Google Analytics 的設定項目,再指定報表項目,就可以產生報表結果。報表項目分成 site wide 和 per page 兩大類,它們可以由 GenericSetup analytics.xml 檔案來新增,或是在 ZMI portal_analytics 裡新增。

我們可以新增 portlet 來顯示報表,不過預設的選項都是 Page 類型的報表,想要增加 Site Wide 的報表,可到 ZMI portal_analytics 調整 Categories 選項。


Plone SQLAlchemy PAS Plugin

In addition to Plone instances, we have PHP applications heavily relying on PostgreSQL. Then there is a need to have them sharing the same user accounts. Luckily Zope2 product PluggableAuthService (PAS) serves such needs well. For our case pas.plugins.sqlalchemy is an ideal fit.

With instructions, my working installation is for:

Ubuntu = 12.04
postgresql-server-dev = 9.1
Plone = 4.1.5
SQLAlchemy = 0.7.7
pas.plugins.sqlalchemy = 0.3
psycopg2 = 2.4.5
z3c.saconfig = 0.13
zope.sqlalchemy = 0.7

Here are some hints worth notice. First I add these lines in devlop.cfg:

eggs +=

zcml +=

And the "zcml-additional" parameter goes in [instance] section of base.cfg:

zcml-additional =
    <configure xmlns="http://namespaces.zope.org/zope"
      <include package="z3c.saconfig" file="meta.zcml" />
      <db:engine name="pas" url="postgresql://postgres:mypass@localhost/plonepas" />
      <db:session name="pas.plugins.sqlalchemy" engine="pas" />

If you use postgres instead postgresql in the URL format, a warning will be added in the log:

SADeprecationWarning: The SQLAlchemy PostgreSQL dialect has been renamed from 'postgres' to 'postgresql'. The new URL format is postgresql[+driver]://<user>:<pass>@<host>/<dbname>

Run bin/buildout -c devlop.cfg and activate SQLAlchemy PAS in Site Setup.

Now let's see how it works. By default, the admin creates an account, and the account data will appear in ZMI /mysite/acl_users/source_users.

Go /mysite/acl_users/plugins, check User_adder Plugins and move sql up as the first Active Plugin, this will switch account data stored in SQL tables.

Check /mysite/acl_users/sql for more info about SQLAlchemy user/group/prop manager.

Here is the list of relations:

$ psql -d plonepas
psql (9.1.3)
Type "help" for help.

plonepas=# \d
                 List of relations
 Schema |        Name        |   Type   |  Owner
 public | group_members      | table    | postgres
 public | groups             | table    | postgres
 public | principals         | table    | postgres
 public | principals_id      | sequence | postgres
 public | role_assignment_id | sequence | postgres
 public | role_assignments   | table    | postgres
 public | users              | table    | postgres
(7 rows)

plonepas=# \d users
                    Table "public.users"
      Column      |            Type             | Modifiers
 id               | integer                     | not null
 login            | character varying(64)       |
 password         | character varying(64)       |
 salt             | character varying(12)       |
 enabled          | boolean                     | not null
 email            | character varying(40)       |
 portal_skin      | character varying(20)       |
 listed           | integer                     |
 login_time       | timestamp without time zone |
 last_login_time  | timestamp without time zone |
 fullname         | character varying(40)       |
 error_log_update | double precision            |
 home_page        | character varying(40)       |
 location         | character varying(40)       |
 description      | text                        |
 language         | character varying(20)       |
 ext_editor       | integer                     |
 wysiwyg_editor   | character varying(10)       |
 visible_ids      | integer                     |
    "users_pkey" PRIMARY KEY, btree (id)
    "ix_users_login" UNIQUE, btree (login)
    "ix_users_email" btree (email)
    "ix_users_enabled" btree (enabled)
    "ix_users_fullname" btree (fullname)
Foreign-key constraints:
    "users_id_fkey" FOREIGN KEY (id) REFERENCES principals(id)

By switching, one of source_users or sql plugins can be chosen to provide authentication service. For example, when using sql plugin, after changing the user's password via Plone user interface, you will see in the SQL table the corresponding columns, password and salt, values updated.


Turn On/Off Plone Print CSS

ZMI portal_css 取消勾選 print.css 儲存設定後,列印樣式會有不同,設定前後的樣式如下:

有個 Print All 擴充模組,可以把目錄裡的所有項目,分頁顯示各項目的內容,例如新聞目錄的多則新聞,就可以一次印完。

想要 hardcopy 的列印效果,看來還是使用 print screen 的軟體。