Commit 3d15d7d4 authored by Ivan Tyagov's avatar Ivan Tyagov

Make iCal bt5 more generic and add support for dynamic skin selection from URL.

Return always dates in UTC.
Make ICal style applicable anywhere in an ERP5 site.
Update XML.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@22723 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 812285ee
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="Folder" module="OFS.Folder"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>_owner</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_ical_core</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
<tal:block metal:define-macro="master"\n
><tal:block tal:define="dummy python: request.RESPONSE.setHeader(\'Content-Type\', \'text/calendar;; charset=utf-8\');\n
ical_string string:iCal;\n
dummy python: context.getPortalObject().portal_skins.changeSkin(ical_string);\n
dummy python: request.set(\'portal_skin\', ical_string);"\n
><tal:block tal:define="listbox_fields python: [field for field in form.get_fields() if\n
(field.meta_type == \'ListBox\' or \n
field.meta_type == \'ProxyField\' and\n
field.getRecursiveTemplateField().meta_type == \'ListBox\')]"\n
>BEGIN:VCALENDAR\n
VERSION:2.0\n
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN\n
<tal:block tal:repeat="listbox_field listbox_fields"\n
><tal:block tal:content="structure python: listbox_field.render()"/></tal:block\n
>END:VCALENDAR</tal:block\n
></tal:block\n
></tal:block>
]]></string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ical_view</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>OFS.Folder</string>
<string>Folder</string>
</tuple>
<none/>
<global name="Folder" module="OFS.Folder"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -18,12 +15,39 @@
<none/>
</value>
</item>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>business_template_registered_skin_selections</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>_owner</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>business_template_registered_skin_selections</string> </key>
<value> <string>iCal</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_ical_style</string> </value>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -74,11 +71,18 @@
or events related to the same sale opportunity)\n
"""\n
project = None\n
ptype = context.getPortalType()\n
if ptype == \'Task\':\n
project = context.getSourceProjectValue()\n
if ptype in context.getPortalEventTypeList():\n
project = context.getFollowUpValue()\n
\n
if brainObject is not None:\n
real_context = brainObject\n
else:\n
real_context = context\n
\n
portal_type = real_context.getPortalType()\n
if portal_type == \'Task\':\n
project = real_context.getSourceProjectValue()\n
elif portal_type in context.getPortalEventTypeList():\n
project = real_context.getFollowUpValue()\n
\n
if project is not None:\n
# we have to tweak here because not all object have references\n
if hasattr(project, \'getReference\'):\n
......@@ -102,7 +106,7 @@ return \'\'\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>brainObject=None</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -122,17 +126,19 @@ return \'\'\n
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>brainObject</string>
<string>None</string>
<string>project</string>
<string>_getattr_</string>
<string>real_context</string>
<string>context</string>
<string>ptype</string>
<string>_getattr_</string>
<string>portal_type</string>
<string>hasattr</string>
</tuple>
</value>
......@@ -145,7 +151,9 @@ return \'\'\n
<item>
<key> <string>func_defaults</string> </key>
<value>
<tuple>
<none/>
</tuple>
</value>
</item>
<item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -69,17 +66,21 @@
<item>
<key> <string>_body</string> </key>
<value> <string>"""\n
Figure out if it is an event or a todo.\n
Figure out if it is an journal, event or a todo.\n
Sample implementation: Task is a todo, event is an event, \n
anything else is an event too.\n
anything else is an journal.\n
"""\n
portal_type = None\n
if brainObject is not None:\n
portal_type = brainObject.getPortalType()\n
else:\n
portal_type = context.getPortalType()\n
\n
ptype = context.getPortalType()\n
if ptype == \'Task\':\n
if portal_type == \'Task\':\n
return \'todo\'\n
if ptype in context.getPortalEventTypeList():\n
elif portal_type in context.getPortalEventTypeList():\n
return \'event\'\n
return \'event\'\n
return \'journal\'\n
</string> </value>
</item>
<item>
......@@ -96,7 +97,7 @@ return \'event\'\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>brainObject=None</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -116,15 +117,17 @@ return \'event\'\n
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>brainObject</string>
<string>None</string>
<string>portal_type</string>
<string>_getattr_</string>
<string>context</string>
<string>ptype</string>
</tuple>
</value>
</item>
......@@ -136,7 +139,9 @@ return \'event\'\n
<item>
<key> <string>func_defaults</string> </key>
<value>
<tuple>
<none/>
</tuple>
</value>
</item>
<item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -68,7 +65,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return context.Base_getICalStatusItem()[1]\n
<value> <string>return context.Base_getICalStatusItem(brainObject)[1]\n
</string> </value>
</item>
<item>
......@@ -85,7 +82,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>brainObject=None</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -105,15 +102,16 @@
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>brainObject</string>
<string>_getitem_</string>
<string>_getattr_</string>
<string>context</string>
<string>context</string>
</tuple>
</value>
</item>
......@@ -125,7 +123,9 @@
<item>
<key> <string>func_defaults</string> </key>
<value>
<tuple>
<none/>
</tuple>
</value>
</item>
<item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -68,7 +65,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return context.Base_getICalStatusItem()[0]\n
<value> <string>return context.Base_getICalStatusItem(brainObject)[0]\n
</string> </value>
</item>
<item>
......@@ -85,7 +82,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>brainObject=None</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -105,12 +102,13 @@
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>brainObject</string>
<string>_getitem_</string>
<string>_getattr_</string>
<string>context</string>
......@@ -125,7 +123,9 @@
<item>
<key> <string>func_defaults</string> </key>
<value>
<tuple>
<none/>
</tuple>
</value>
</item>
<item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -69,17 +66,15 @@
<item>
<key> <string>_body</string> </key>
<value> <string>"""\n
Give an ICal status and percent-completed for a todo entry.\n
Give an ICal status and percent-completed for a todo entry and status for a event entry.\n
Return a tuple of (status, percent_complete).\n
Status is one of: \'needs-action\', \'in-process\', \'completed\' and \'cancelled\'\n
or nothing, then we\'ll assume it is \'needs-action\'.\n
Sample implementation for a Task:\n
For todo status is one of: \'needs-action\', \'in-process\', \'completed\' and \'cancelled\' or nothing,\n
then we\'ll assume it is \'needs-action\'.\n
For event status is one of: \'cancelled\', \'confirmed\', \'tentative\' or nothing, \n
then we\'ll assume it is \'tentative\'.\n
"""\n
\n
if context.getPortalType() != \'Task\':\n
return (\'\', 0)\n
\n
status_map = {\n
status = \'\'\n
status_map_task = {\n
\'draft\' : (\'needs-action\', 0),\n
\'planned\' : (\'needs-action\', 33),\n
\'ordered\' : (\'in-process\', 66),\n
......@@ -87,7 +82,26 @@ status_map = {\n
\'cancelled\' : (\'cancelled\', 0)\n
}\n
\n
return status_map.get(context.getSimulationState(), (\'\', 0))\n
status_map_event = {\n
\'CANCELLED\' : (\'expired\', \'deleted\', \'cancelled\'),\n
\'CONFIRMED\' : (\'started\', \'responded\', \'delivered\', \'assigned\', \'acknowledged\'),\n
\'TENTATIVE\' : (\'draft\', \'planned\', \'new\', \'ordered\')\n
}\n
\n
if brainObject is not None:\n
real_context = brainObject\n
else:\n
real_context = context\n
\n
portal_type = real_context.getPortalType()\n
if portal_type == \'Task\':\n
return status_map_task.get(real_context.getSimulationState(), (\'\', 0))\n
elif portal_type in context.getPortalEventTypeList():\n
for status_item in status_map_event:\n
if real_context.getSimulationState() in status_map_event[status_item]:\n
status = status_item\n
break\n
return (status, 0)\n
</string> </value>
</item>
<item>
......@@ -104,7 +118,7 @@ return status_map.get(context.getSimulationState(), (\'\', 0))\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>brainObject=None</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -124,15 +138,24 @@ return status_map.get(context.getSimulationState(), (\'\', 0))\n
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>_getattr_</string>
<string>brainObject</string>
<string>status</string>
<string>status_map_task</string>
<string>status_map_event</string>
<string>None</string>
<string>real_context</string>
<string>context</string>
<string>status_map</string>
<string>_getattr_</string>
<string>portal_type</string>
<string>_getiter_</string>
<string>status_item</string>
<string>_getitem_</string>
</tuple>
</value>
</item>
......@@ -144,7 +167,9 @@ return status_map.get(context.getSimulationState(), (\'\', 0))\n
<item>
<key> <string>func_defaults</string> </key>
<value>
<tuple>
<none/>
</tuple>
</value>
</item>
<item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.ERP5Form.Form</string>
<string>ERP5Form</string>
</tuple>
<none/>
<global name="ERP5Form" module="Products.ERP5Form.Form"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -49,6 +46,16 @@
<key> <string>action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
......@@ -118,11 +125,11 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Folder_asRSS</string> </value>
<value> <string>Folder_viewContentListAsICal</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>template_ical_style</string> </value>
<value> <string>ical_view</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.ERP5Form.ListBox</string>
<string>ListBox</string>
</tuple>
<none/>
<global name="ListBox" module="Products.ERP5Form.ListBox"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -319,49 +316,53 @@
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>anchor</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>title</string>
<string>ical_summary</string>
<string>summary</string>
</tuple>
<tuple>
<string>creation_date</string>
<string>ical_created</string>
<string>created</string>
</tuple>
<tuple>
<string>modification_date</string>
<string>ical_last-modified</string>
<string>last-modified</string>
</tuple>
<tuple>
<string>uid</string>
<string>ical_uid</string>
<string>uid</string>
</tuple>
<tuple>
<string>start_date</string>
<string>ical_dtstart</string>
<string>dtstart</string>
</tuple>
<tuple>
<string>stop_date</string>
<string>ical_dtend</string>
<string>dtend</string>
</tuple>
<tuple>
<string>Base_getICalComponent</string>
<string>ical_component</string>
<string>component</string>
</tuple>
<tuple>
<string>Base_getICalCategory</string>
<string>ical_categories</string>
<string>categories</string>
</tuple>
<tuple>
<string>Base_getICalStatus</string>
<string>ical_status</string>
<string>status</string>
</tuple>
<tuple>
<string>Base_getICalPercentComplete</string>
<string>ical_percent-complete</string>
<string>percent-complete</string>
</tuple>
</list>
</value>
......@@ -444,7 +445,7 @@
</item>
<item>
<key> <string>page_template</string> </key>
<value> <string>Listbox_viewAsICal</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
......@@ -521,11 +522,8 @@
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.MethodField</string>
<string>Method</string>
</tuple>
<none/>
<global name="Method" module="Products.Formulator.MethodField"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Change_bindings_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Change_cache_settings_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Change_permissions_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Copy_or_Move_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Delete_objects_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_FTP_access_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Manage_WebDAV_Locks_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Manage_properties_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Take_ownership_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_Undo_changes_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_View_management_screens_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_WebDAV_Lock_items_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_WebDAV_Unlock_items_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>_WebDAV_access_Permission</string> </key>
<value>
<list>
<string>Manager</string>
</list>
</value>
</item>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
<tal:block \n
xmlns:tal="http://xml.zope.org/namespaces/tal"\n
xmlns:i18n="http://xml.zope.org/namespaces/i18n"\n
tal:define="line_list here/query;\n
label_list here/getLabelValueList;\n
real_context here/getContext;"\n
><tal:block tal:replace="structure python: real_context.Listbox_asICal(label_list, line_list)"/></tal:block>
]]></string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/calendar; charset=utf-8</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ListBox_asHTML</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -71,47 +68,83 @@
<value> <string>"""\n
An ICal data format implementation.\n
USAGE\n
Data are drawn from a listbox as they are; a custom listbox is needed, with \n
column titles prefixed with \'ical_\'\n
mandatory columns: (\'summary\', \'created\', \'dtstamp\', \'last-modified\', \'uid\', \'dtstart\', \'dtend\', \'component\')\n
optional columns: (\'location\', \'categories\', \'status\', \'completed\', \'percent-complete\')\n
Title (summary) can be anything, same for location and categories (categories can be one word or a comma-separated\n
list, although not all clients can use multiple categories).\n
Component can be "event" or "todo".\n
Data are drawn from a listbox as they are;\n
mandatory columns: (\'summary\', \'description\', \'created\', \'dtstamp\', \'last-modified\', \'uid\', \'dtstart\', \'dtend\', \'component\', \'url\')\n
optional columns: (\'location\', \'status\', \'completed\', \'percent-complete\', \'categories\')\n
Title (summary) can be anything, same for description, location and categories (categories can be one word or a comma-separated list, although not all clients can use multiple categories).\n
Component can be "journal", "event" or "todo".\n
Dates should be returned by listbox with no extra processing - the script formats them appropriately.\n
\'status\' is valid only for todo, and can be: needs-action|completed|in-process|cancelled (default is needs-action)\n
\'completed\' and \'percent-complete\' is valid only for todo\n
\'status\' is valid for todo and can be: needs-action|completed|in-process|cancelled (default is needs-action)\n
\'status\' is valid for event and can be: tentative|confirmed|cancelled\n
PREPROCESSING\n
If start and stop date are the same, we assume it lasts 1 hour.\n
If status is \'completed\' and no percent-complete is given, we take 100%.\n
If status is \'completed\' and no completed date is given, we take dtend.\n
If no start date is given, we take created\n
If no stop date is given, we take start date\n
For "todo" if status is \'completed\' and no percent-complete is given, we take 100%.\n
For "todo" if status is \'completed\' and no completed date is given, we take dtend.\n
IMPLEMENTATION DETAILS:\n
dtstamp = created\n
dtstamp = indicates the date/time that the instance of the iCalendar object was created.\n
due (in VTODO) = dtend\n
dates are formatted "YYYYMMDDTHHMMSSZ" (which is HTML4 without separators).\n
all dates are converted to GMT, then the client will adjust them to its local timezone\n
"""\n
from DateTime import DateTime\n
now = DateTime()\n
allowed_field_list = (\'summary\', \'description\', \'created\', \n
\'last-modified\', \'uid\', \'dtstamp\', \n
\'dtstart\', \'dtend\', \'component\', \'url\', \n
\'location\', \'categories\', \'status\', \n
\'completed\', \'percent-complete\')\n
allowed_status_list_todo = (\'COMPLETED\', \'IN-PROCESS\', \n
\'CANCELLED\', \'NEEDS-ACTION\')\n
\n
allowed_field_list = (\'summary\', \'created\', \'last-modified\', \'uid\', \'dtstart\', \'dtend\', \'component\', \'location\', \'categories\',\n
\'status\', \'completed\', \'percent-complete\')\n
allowed_status_list = (\'COMPLETED\', \'IN-PROCESS\', \'CANCELLED\', \'NEEDS-ACTION\')\n
# mapping listbox column headers with iCalendar properties\n
# if listbox column headers are more than one the index of first occured in listbox columns is getting\n
related_column_map = {\n
\'summary\' : (\'title\',),\n
\'created\' : (\'creation date\',),\n
\'last-modified\' : (\'modification date\',),\n
\'dtstart\' : (\'start date\', \'begin date\',),\n
\'dtend\' : (\'stop date\', \'end date\',)\n
}\n
\n
# items are taken in the standard listbox way\n
line_list = context.query();\n
label_list = context.getLabelValueList();\n
real_context = context.getContext()\n
def convertDate(value):\n
""" Format dates. """\n
if hasattr(value, \'toZone\'):\n
# we dont specify time zone in the file, \n
# but recalculate everything into UTC\n
value = value.toZone(\'UTC\')\n
value = value.HTML4()\n
value = value.replace(\'-\', \'\')\n
value = value.replace(\':\', \'\')\n
return value\n
\n
# figure out which column is which, by using column titles\n
ical_column_mapping = {}\n
for index, column_item in enumerate(label_list):\n
column_header = column_item[1]\n
if column_header.startswith(\'ical_\'):\n
field_name = column_header[5:]\n
if field_name in allowed_field_list:\n
ical_column_mapping[field_name] = index\n
column_header = column_item[1].lower()\n
if column_header in allowed_field_list:\n
ical_column_mapping[column_header] = index\n
continue\n
for related_column in related_column_map:\n
if column_header in related_column_map[related_column] and \\\n
related_column not in ical_column_mapping:\n
ical_column_mapping[related_column] = index\n
break\n
\n
for index, column_item in enumerate(label_list):\n
column_header = column_item[1].lower()\n
if column_header == \'date\':\n
if column_item[0].find(\'start_date\') or column_item[0].find(\'startdate\'):\n
if not ical_column_mapping.get(\'dtstart\', None):\n
ical_column_mapping[\'dtstart\'] = index\n
elif column_item[0].find(\'end_date\') or column_item[0].find(\'enddate\'):\n
if not ical_column_mapping.get(\'dtstart\', None):\n
ical_column_mapping[\'dtend\'] = index\n
\n
items = []\n
\n
for line in line_list:\n
brainObject = line.getBrain()\n
column_item_list = line.getValueList()\n
ical_item_dict = {}\n
# collect values\n
......@@ -121,23 +154,65 @@ for line in line_list:\n
# but other stuff (like int or DateTime) we want as they are\n
if hasattr(value_tuple[0], \'lower\'):\n
value = value_tuple[1]\n
else:\n
if isinstance(value_tuple[0], DateTime):\n
value = convertDate(value_tuple[0])\n
else:\n
value = value_tuple[0]\n
ical_item_dict[header.upper()] = value\n
\n
for field in allowed_field_list:\n
field_upper = field.upper()\n
if field_upper not in ical_item_dict:\n
if field_upper == \'SUMMARY\' and hasattr(brainObject, \'getTitle\'):\n
ical_item_dict[\'SUMMARY\'] = brainObject.getTitle()\n
elif field_upper == \'DESCRIPTION\' and hasattr(brainObject, \'getDescription\'):\n
ical_item_dict[\'DESCRIPTION\'] = brainObject.getDescription()\n
elif field_upper == \'CREATED\' and hasattr(brainObject, \'getCreationDate\'):\n
ical_item_dict[\'CREATED\'] = convertDate(brainObject.getCreationDate())\n
elif field_upper == \'LAST-MODIFIED\' and hasattr(brainObject, \'getModificationDate\'):\n
ical_item_dict[\'LAST-MODIFIED\'] = convertDate(brainObject.getModificationDate())\n
elif field_upper == \'UID\' and hasattr(brainObject, \'getUid\'):\n
ical_item_dict[\'UID\'] = brainObject.getUid()\n
elif field_upper == \'COMPONENT\':\n
if hasattr(brainObject, \'getPortalType\'):\n
ical_item_dict[\'COMPONENT\'] = context.Base_getICalComponent(brainObject)\n
else:\n
ical_item_dict[\'COMPONENT\'] = \'journal\'\n
elif field_upper == \'URL\' and hasattr(brainObject, \'absolute_url\'):\n
ical_item_dict[\'URL\'] = brainObject.absolute_url() + \'/view\'\n
elif field_upper == \'DTSTAMP\':\n
ical_item_dict[\'DTSTAMP\'] = convertDate(now)\n
elif field_upper == \'DTSTART\':\n
if hasattr(line.getBrain(), \'getCreationDate\'):\n
ical_item_dict[\'DTSTART\'] = convertDate(brainObject.getCreationDate())\n
else:\n
ical_item_dict[\'DTSTART\'] = convertDate(now)\n
elif field_upper == \'DTEND\':\n
ical_item_dict[\'DTEND\'] = ical_item_dict[\'DTSTART\']\n
elif field_upper == \'CATEGORIES\' and ical_item_dict[\'COMPONENT\'] != \'journal\' and \\\n
hasattr(brainObject, \'getPortalType\'):\n
ical_item_dict[\'CATEGORIES\'] = context.Base_getICalCategory(brainObject)\n
elif field_upper == \'STATUS\' and ical_item_dict[\'COMPONENT\'] != \'journal\' and \\\n
hasattr(brainObject, \'getPortalType\'):\n
ical_item_dict[\'STATUS\'] = context.Base_getICalStatus(brainObject)\n
elif field_upper == \'PERCENT-COMPLETE\' and ical_item_dict[\'COMPONENT\'] == \'todo\' and \\\n
hasattr(brainObject, \'getPortalType\'):\n
ical_item_dict[\'PERCENT-COMPLETE\'] = context.Base_getICalPercentComplete(brainObject)\n
\n
# check and process\n
if not hasattr(ical_item_dict[\'DTSTART\'], \'HTML4\'):\n
# real_context.log(\'Item %(SUMMARY)s has illegal start date: %(DTSTART)s, skipping\' % ical_item_dict) \n
continue\n
if ical_item_dict[\'DTSTART\'] == ical_item_dict[\'DTEND\'] or not hasattr(ical_item_dict[\'DTEND\'], \'HTML4\'):\n
# real_context.log(\'End date %(DTEND)s for item %(SUMMARY)s is empty, illegal or equal to start date, assuming start date + 1 hour\' % ical_item_dict)\n
ical_item_dict[\'DTEND\'] = DateTime(ical_item_dict[\'DTSTART\'].timeTime() + 3600) # add 1 hour\n
# check and fix for todo\n
if ical_item_dict[\'DTSTART\'] is None:\n
ical_item_dict[\'DTSTART\'] = ical_item_dict[\'CREATED\']\n
if ical_item_dict[\'DTEND\'] is None:\n
ical_item_dict[\'DTEND\'] = ical_item_dict[\'DTSTART\']\n
\n
# check and fix for todo and event\n
if ical_item_dict[\'COMPONENT\'] == \'todo\':\n
status = ical_item_dict.get(\'STATUS\', False)\n
if status:\n
status = status.upper()\n
ical_item_dict[\'STATUS\'] = status\n
if status not in allowed_status_list:\n
if status not in allowed_status_list_todo:\n
raise ValueError(\'ICal status %s is not allowed\' % status)\n
if status == \'COMPLETED\':\n
if not ical_item_dict.get(\'PERCENT-COMPLETE\', False):\n
......@@ -146,17 +221,15 @@ for line in line_list:\n
ical_item_dict[\'COMPLETED\'] = ical_item_dict[\'DTEND\']\n
else:\n
ical_item_dict[\'STATUS\'] = \'NEEDS-ACTION\'\n
# reformat dates\n
for header, value in ical_item_dict.items():\n
if hasattr(value, \'toZone\'):\n
value = value.toZone(\'GMT\') # we dont specify time zone in the file, but recalculate everything into GMT instead\n
value = value.HTML4()\n
value = value.replace(\'-\', \'\')\n
value = value.replace(\':\', \'\')\n
ical_item_dict[header] = value\n
if not ical_item_dict.get(\'PERCENT-COMPLETE\', False):\n
ical_item_dict[\'PERCENT-COMPLETE\'] = 0\n
elif ical_item_dict[\'COMPONENT\'] == \'event\':\n
status = ical_item_dict.get(\'STATUS\', False)\n
if not status:\n
ical_item_dict[\'STATUS\'] = \'TENTATIVE\'\n
items.append(ical_item_dict)\n
\n
return real_context.Listbox_renderAsICal(items=items)\n
return context.Listbox_renderAsICal(items=items)\n
</string> </value>
</item>
<item>
......@@ -173,7 +246,7 @@ return real_context.Listbox_renderAsICal(items=items)\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>label_list, line_list</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
......@@ -193,37 +266,44 @@ return real_context.Listbox_renderAsICal(items=items)\n
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>allowed_field_list</string>
<string>allowed_status_list</string>
<string>_getattr_</string>
<string>context</string>
<string>line_list</string>
<string>label_list</string>
<string>real_context</string>
<string>line_list</string>
<string>DateTime</string>
<string>now</string>
<string>allowed_field_list</string>
<string>allowed_status_list_todo</string>
<string>related_column_map</string>
<string>convertDate</string>
<string>ical_column_mapping</string>
<string>_getiter_</string>
<string>enumerate</string>
<string>index</string>
<string>column_item</string>
<string>_getattr_</string>
<string>_getitem_</string>
<string>column_header</string>
<string>field_name</string>
<string>_write_</string>
<string>related_column</string>
<string>None</string>
<string>items</string>
<string>line</string>
<string>brainObject</string>
<string>column_item_list</string>
<string>ical_item_dict</string>
<string>header</string>
<string>value_tuple</string>
<string>hasattr</string>
<string>value</string>
<string>DateTime</string>
<string>isinstance</string>
<string>field</string>
<string>field_upper</string>
<string>context</string>
<string>False</string>
<string>status</string>
<string>ValueError</string>
......@@ -243,7 +323,7 @@ return real_context.Listbox_renderAsICal(items=items)\n
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Listbox_viewAsICal</string> </value>
<value> <string>Listbox_asICal</string> </value>
</item>
<item>
<key> <string>warnings</string> </key>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>OFS.DTMLMethod</string>
<string>DTMLMethod</string>
</tuple>
<none/>
<global name="DTMLMethod" module="OFS.DTMLMethod"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -38,39 +35,110 @@
<key> <string>raw</string> </key>
<value> <string encoding="cdata"><![CDATA[
BEGIN:VCALENDAR\n
VERSION:2.0\n
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN\n
<dtml-in prefix="loop" expr="items">\n
<dtml-if expr="loop_item[\'COMPONENT\']==\'journal\'">\n
BEGIN:VJOURNAL\n
<dtml-if expr="loop_item.get(\'CREATED\')">\n
CREATED:<dtml-var expr="loop_item[\'CREATED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'LAST-MODIFIED\')">\n
LAST-MODIFIED:<dtml-var expr="loop_item[\'LAST-MODIFIED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTAMP\')">\n
DTSTAMP:<dtml-var expr="loop_item[\'DTSTAMP\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'UID\')">\n
UID:uuid<dtml-var expr="loop_item[\'UID\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'SUMMARY\')">\n
SUMMARY:<dtml-var expr="loop_item[\'SUMMARY\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DESCRIPTION\')">\n
DESCRIPTION:<dtml-var expr="loop_item[\'DESCRIPTION\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTART\')">\n
DTSTART:<dtml-var expr="loop_item[\'DTSTART\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'URL\')">\n
URL:<dtml-var expr="loop_item[\'URL\']">\n
</dtml-if>\n
END:VJOURNAL\n
</dtml-if>\n
<dtml-if expr="loop_item[\'COMPONENT\']==\'event\'">\n
BEGIN:VEVENT\n
<dtml-if expr="loop_item.get(\'CREATED\')">\n
CREATED:<dtml-var expr="loop_item[\'CREATED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'LAST-MODIFIED\')">\n
LAST-MODIFIED:<dtml-var expr="loop_item[\'LAST-MODIFIED\']">\n
DTSTAMP:<dtml-var expr="loop_item[\'CREATED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTAMP\')">\n
DTSTAMP:<dtml-var expr="loop_item[\'DTSTAMP\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'UID\')">\n
UID:uuid<dtml-var expr="loop_item[\'UID\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'SUMMARY\')">\n
SUMMARY:<dtml-var expr="loop_item[\'SUMMARY\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DESCRIPTION\')">\n
DESCRIPTION:<dtml-var expr="loop_item[\'DESCRIPTION\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'STATUS\')">\n
STATUS:<dtml-var expr="loop_item[\'STATUS\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTART\')">\n
DTSTART:<dtml-var expr="loop_item[\'DTSTART\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTEND\')">\n
DTEND:<dtml-var expr="loop_item[\'DTEND\']">\n
<dtml-if expr="loop_item.get(\'LOCATION\', \'\')">\n
LOCATION:<dtml-var expr="loop_item[\'LOCATION\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'CATEGORIES\', \'\')">\n
<dtml-if expr="loop_item.get(\'URL\')">\n
URL:<dtml-var expr="loop_item[\'URL\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'CATEGORIES\')">\n
CATEGORIES:<dtml-var expr="loop_item[\'CATEGORIES\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'LOCATION\')">\n
LOCATION:<dtml-var expr="loop_item[\'LOCATION\']">\n
</dtml-if>\n
END:VEVENT\n
</dtml-if>\n
<dtml-if expr="loop_item[\'COMPONENT\']==\'todo\'">\n
BEGIN:VTODO\n
<dtml-if expr="loop_item.get(\'CREATED\')">\n
CREATED:<dtml-var expr="loop_item[\'CREATED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'LAST-MODIFIED\')">\n
LAST-MODIFIED:<dtml-var expr="loop_item[\'LAST-MODIFIED\']">\n
DTSTAMP:<dtml-var expr="loop_item[\'CREATED\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTAMP\')">\n
DTSTAMP:<dtml-var expr="loop_item[\'DTSTAMP\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'UID\')">\n
UID:uuid<dtml-var expr="loop_item[\'UID\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'SUMMARY\')">\n
SUMMARY:<dtml-var expr="loop_item[\'SUMMARY\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DESCRIPTION\')">\n
DESCRIPTION:<dtml-var expr="loop_item[\'DESCRIPTION\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'STATUS\')">\n
STATUS:<dtml-var expr="loop_item[\'STATUS\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTSTART\')">\n
DTSTART:<dtml-var expr="loop_item[\'DTSTART\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'DTEND\')">\n
DUE:<dtml-var expr="loop_item[\'DTEND\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'URL\')">\n
URL:<dtml-var expr="loop_item[\'URL\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'CATEGORIES\')">\n
CATEGORIES:<dtml-var expr="loop_item[\'CATEGORIES\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'COMPLETED\')">\n
COMPLETED:<dtml-var expr="loop_item[\'COMPLETED\']">\n
</dtml-if>\n
......@@ -80,14 +148,9 @@ PERCENT-COMPLETE:<dtml-var expr="loop_item[\'PERCENT-COMPLETE\']">\n
<dtml-if expr="loop_item.get(\'LOCATION\')">\n
LOCATION:<dtml-var expr="loop_item[\'LOCATION\']">\n
</dtml-if>\n
<dtml-if expr="loop_item.get(\'CATEGORIES\')">\n
CATEGORIES:<dtml-var expr="loop_item[\'CATEGORIES\']">\n
</dtml-if>\n
END:VTODO\n
</dtml-if>\n
</dtml-in>\n
END:VCALENDAR\n
</dtml-in>
]]></string> </value>
</item>
......
......@@ -3,11 +3,8 @@
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PageTemplates.ZopePageTemplate</string>
<string>ZopePageTemplate</string>
</tuple>
<none/>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
<tuple/>
</tuple>
</pickle>
<pickle>
......@@ -48,12 +45,7 @@
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
<tal:block tal:define="dummy python:request.RESPONSE.setHeader(\'Content-Type\', \'text/calendar;; charset=utf-8\');"\n
><tal:block tal:define="listbox python:form[\'listbox\'];" \n
><tal:block tal:content="structure python: listbox.render()" />\n
</tal:block>\n
</tal:block>\n
<tal:block metal:use-macro="here/ical_view/macros/master" />
]]></string> </value>
</item>
......@@ -67,7 +59,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_ical_style</string> </value>
<value> <string>form_list</string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
<tal:block metal:use-macro="here/ical_view/macros/master" />
]]></string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>form_view</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2007-07-22 zstoinov
* Make iCal bt5 more generic and add support for dynamic skin selection from URL.
2007-08-29
Release-ready.
* Release-ready.
2007-08-13
First working version.
\ No newline at end of file
* First working version.
\ No newline at end of file
7
\ No newline at end of file
14
\ No newline at end of file
erp5_ical_core
erp5_ical_style
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment