Commit e84d2b51 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Likewise Document, add Mixin (erp5.component.mixin) and...

ZODB Components: Likewise Document, add Mixin (erp5.component.mixin) and Interface (erp5.component.interface).

* One Mixin/Interface class per ZODB Component.
  => Already the case for FS Mixin, not for Interfaces.
* ZODB Components module name ('reference' property) and class name:
  + Mixin: FooMixin.
  + Interface: IFoo.

Rationale:
  + Avoid current FS hacks: registry (Mixins, mixin_class_registry) or import
    all classes explicitly in __init__.py (Products.ERP5Type.interfaces).
  + Consistent naming.
  + Consistent with ZODB Documents Components.

Also, modify pylint checker to handle Zope Interfaces:
  + E: 4, 0: Inheriting 'Interface', which is not a class. (inherit-non-class)
  + E: 5, 2: Method has no argument (no-method-argument)
parent c0cd8524
<tal:block tal:define='site_root python: here.getWebSiteValue() or here.getPortalObject(); <tal:block tal:define='site_root python: here.getWebSiteValue() or here.getPortalObject();
portal_url python: site_root.absolute_url(); portal_url python: site_root.absolute_url();
portal_type python: here.getPortalType();
div_id string:${id}_ace; div_id string:${id}_ace;
mode python: here.Base_getAceEditorMode(); mode python: here.Base_getAceEditorMode();
container_div_id string:${div_id}_container; container_div_id string:${div_id}_container;
...@@ -150,6 +151,7 @@ ...@@ -150,6 +151,7 @@
ace_editor_container_div = null; ace_editor_container_div = null;
ace_editor = null; ace_editor = null;
var mode = '${mode}'; var mode = '${mode}';
var portal_type = '${portal_type}';
var params = '${params}'; var params = '${params}';
function maximizeFullscreenRemoveSaveMessage() { function maximizeFullscreenRemoveSaveMessage() {
...@@ -394,6 +396,7 @@ ...@@ -394,6 +396,7 @@
ace.require('ace/ext/language_tools'); ace.require('ace/ext/language_tools');
ace_editor.setOptions({ enableBasicAutocompletion: true, enableSnippets: true }); ace_editor.setOptions({ enableBasicAutocompletion: true, enableSnippets: true });
var data_options = {}; var data_options = {};
data_options.portal_type = portal_type;
if (params !== 'None') { if (params !== 'None') {
data_options.bound_names = ['context','container','script','traverse_subpath','printed','same_type','string','sequence','random','DateTime','whrandom','reorder','sets','test','math'], data_options.bound_names = ['context','container','script','traverse_subpath','printed','same_type','string','sequence','random','DateTime','whrandom','reorder','sets','test','math'],
data_options.params = params; data_options.params = params;
......
...@@ -200,7 +200,7 @@ def checkPythonSourceCodeAsJSON(self, data, REQUEST=None): ...@@ -200,7 +200,7 @@ def checkPythonSourceCodeAsJSON(self, data, REQUEST=None):
else: else:
body = data['code'] body = data['code']
message_list = checkPythonSourceCode(body.encode('utf8')) message_list = checkPythonSourceCode(body.encode('utf8'), data.get('portal_type'))
for message_dict in message_list: for message_dict in message_list:
if is_python_script: if is_python_script:
message_dict['row'] = message_dict['row'] - 2 message_dict['row'] = message_dict['row'] - 2
......
...@@ -444,7 +444,8 @@ ...@@ -444,7 +444,8 @@
update_check_running = false; update_check_running = false;
function checkPythonSourceCode(text, updateLinting, options, cm) { function checkPythonSourceCode(text, updateLinting, options, cm) {
update_check_text = text; update_check_text = text;
checker_parameters = {code: text}; checker_parameters = {code: text,
portal_type: '<dtml-var name="portal_type">'};
<dtml-if bound_names> <dtml-if bound_names>
checker_parameters['bound_names'] = <dtml-var name="bound_names">; checker_parameters['bound_names'] = <dtml-var name="bound_names">;
checker_parameters['params'] = $('input[name="params"]').val(); checker_parameters['params'] = $('input[name="params"]').val();
......
This diff is collapsed.
...@@ -58,6 +58,8 @@ item_name_list = ( ...@@ -58,6 +58,8 @@ item_name_list = (
'workflow', 'workflow',
'product', 'product',
'document', 'document',
'interface',
'mixin',
'property_sheet', 'property_sheet',
'constraint', 'constraint',
'extension', 'extension',
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ComponentMixin_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object is not None and not object.isWebMode()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ComponentMixin_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object is not None and not object.isWebMode()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
<portal_type id="Component Tool"> <portal_type id="Component Tool">
<item>Document Component</item> <item>Document Component</item>
<item>Extension Component</item> <item>Extension Component</item>
<item>Interface Component</item>
<item>Mixin Component</item>
<item>Test Component</item> <item>Test Component</item>
</portal_type> </portal_type>
<portal_type id="Contribution Registry Tool"> <portal_type id="Contribution Registry Tool">
......
...@@ -41,6 +41,12 @@ ...@@ -41,6 +41,12 @@
<portal_type id="Extension Component"> <portal_type id="Extension Component">
<item>SortIndex</item> <item>SortIndex</item>
</portal_type> </portal_type>
<portal_type id="Interface Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Mixin Component">
<item>SortIndex</item>
</portal_type>
<portal_type id="Property Existence Constraint"> <portal_type id="Property Existence Constraint">
<item>ConstraintType</item> <item>ConstraintType</item>
</portal_type> </portal_type>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_property_domain_dict</string> </key>
<value>
<dictionary>
<item>
<key> <string>short_title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>web_page.png</string> </value>
</item>
<item>
<key> <string>content_meta_type</string> </key>
<value> <string>ERP5 Text Document</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>An Interface Component is just a specific Document Component for Zope Interfaces in ZODB. </string> </value>
</item>
<item>
<key> <string>factory</string> </key>
<value> <string>addDocumentComponent</string> </value>
</item>
<item>
<key> <string>filter_content_types</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Interface Component</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>InterfaceComponent</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>short_title</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>title</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_property_domain_dict</string> </key>
<value>
<dictionary>
<item>
<key> <string>short_title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>web_page.png</string> </value>
</item>
<item>
<key> <string>content_meta_type</string> </key>
<value> <string>ERP5 Text Document</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A Mixin Component is just a specific Document Component for ERP5 mixins in ZODB. </string> </value>
</item>
<item>
<key> <string>factory</string> </key>
<value> <string>addDocumentComponent</string> </value>
</item>
<item>
<key> <string>filter_content_types</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Mixin Component</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>MixinComponent</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>short_title</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>title</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -107,6 +107,10 @@ ...@@ -107,6 +107,10 @@
<type>Extension Component</type> <type>Extension Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow> <workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain> </chain>
<chain>
<type>Interface Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
<chain> <chain>
<type>Mapped Value</type> <type>Mapped Value</type>
<workflow>edit_workflow</workflow> <workflow>edit_workflow</workflow>
...@@ -115,6 +119,10 @@ ...@@ -115,6 +119,10 @@
<type>Memcached Plugin</type> <type>Memcached Plugin</type>
<workflow>memcached_plugin_interaction_workflow</workflow> <workflow>memcached_plugin_interaction_workflow</workflow>
</chain> </chain>
<chain>
<type>Mixin Component</type>
<workflow>component_validation_workflow, dynamic_class_generation_interaction_workflow, edit_workflow</workflow>
</chain>
<chain> <chain>
<type>Predicate</type> <type>Predicate</type>
<workflow>edit_workflow</workflow> <workflow>edit_workflow</workflow>
......
...@@ -64,6 +64,8 @@ ...@@ -64,6 +64,8 @@
<list> <list>
<string>my_template_role_list</string> <string>my_template_role_list</string>
<string>my_template_site_property_id_list</string> <string>my_template_site_property_id_list</string>
<string>my_template_interface_id_list</string>
<string>my_template_mixin_id_list</string>
<string>my_template_document_id_list</string> <string>my_template_document_id_list</string>
<string>my_template_property_sheet_id_list</string> <string>my_template_property_sheet_id_list</string>
<string>my_template_extension_id_list</string> <string>my_template_extension_id_list</string>
......
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
<list> <list>
<string>Document Component</string> <string>Document Component</string>
<string>Extension Component</string> <string>Extension Component</string>
<string>Interface Component</string>
<string>Mixin Component</string>
<string>Test Component</string> <string>Test Component</string>
</list> </list>
</value> </value>
......
...@@ -71,10 +71,18 @@ ...@@ -71,10 +71,18 @@
<list> <list>
<string>Document Component</string> <string>Document Component</string>
<string>Extension Component</string> <string>Extension Component</string>
<string>Interface Component</string>
<string>Mixin Component</string>
<string>Test Component</string> <string>Test Component</string>
</list> </list>
</value> </value>
</item> </item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>script_name</string> </key> <key> <string>script_name</string> </key>
<value> <value>
......
...@@ -85,8 +85,10 @@ Dynamic Category Property | view ...@@ -85,8 +85,10 @@ Dynamic Category Property | view
Extension Component | view Extension Component | view
Folder | view Folder | view
Id Tool | view Id Tool | view
Interface Component | view
Memcached Plugin | view Memcached Plugin | view
Memcached Tool | view Memcached Tool | view
Mixin Component | view
Predicate | view Predicate | view
Preference Tool Type | jump_property_sheets Preference Tool Type | jump_property_sheets
Preference Tool Type | view Preference Tool Type | view
......
...@@ -21,6 +21,8 @@ Category Tool | Base Category ...@@ -21,6 +21,8 @@ Category Tool | Base Category
Category | Category Category | Category
Component Tool | Document Component Component Tool | Document Component
Component Tool | Extension Component Component Tool | Extension Component
Component Tool | Interface Component
Component Tool | Mixin Component
Component Tool | Test Component Component Tool | Test Component
Contribution Registry Tool | Contribution Predicate Contribution Registry Tool | Contribution Predicate
Domain Tool | Base Domain Domain Tool | Base Domain
......
...@@ -48,9 +48,11 @@ Event ...@@ -48,9 +48,11 @@ Event
Extension Component Extension Component
Folder Folder
Id Tool Id Tool
Interface Component
Mapped Value Mapped Value
Memcached Plugin Memcached Plugin
Memcached Tool Memcached Tool
Mixin Component
Movement Movement
Notification Tool Notification Tool
Order Tool Order Tool
......
...@@ -12,6 +12,8 @@ Category Related Membership State Constraint | ConstraintType ...@@ -12,6 +12,8 @@ Category Related Membership State Constraint | ConstraintType
Content Existence Constraint | ConstraintType Content Existence Constraint | ConstraintType
Document Component | SortIndex Document Component | SortIndex
Extension Component | SortIndex Extension Component | SortIndex
Interface Component | SortIndex
Mixin Component | SortIndex
Property Existence Constraint | ConstraintType Property Existence Constraint | ConstraintType
Property Type Validity Constraint | ConstraintType Property Type Validity Constraint | ConstraintType
Python Script | CatalogFilter Python Script | CatalogFilter
......
...@@ -32,8 +32,14 @@ Dynamic Category Property | dynamic_class_generation_interaction_workflow ...@@ -32,8 +32,14 @@ Dynamic Category Property | dynamic_class_generation_interaction_workflow
Extension Component | component_validation_workflow Extension Component | component_validation_workflow
Extension Component | dynamic_class_generation_interaction_workflow Extension Component | dynamic_class_generation_interaction_workflow
Extension Component | edit_workflow Extension Component | edit_workflow
Interface Component | component_validation_workflow
Interface Component | dynamic_class_generation_interaction_workflow
Interface Component | edit_workflow
Mapped Value | edit_workflow Mapped Value | edit_workflow
Memcached Plugin | memcached_plugin_interaction_workflow Memcached Plugin | memcached_plugin_interaction_workflow
Mixin Component | component_validation_workflow
Mixin Component | dynamic_class_generation_interaction_workflow
Mixin Component | edit_workflow
Predicate | edit_workflow Predicate | edit_workflow
Preference | edit_workflow Preference | edit_workflow
Preference | preference_workflow Preference | preference_workflow
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A list of ids of Interfaces used by this template</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_interface_id_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: ()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A list of ids of Mixins used by this template</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_mixin_id_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: ()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
This diff is collapsed.
...@@ -110,12 +110,14 @@ class EditorWidget(Widget.TextAreaWidget): ...@@ -110,12 +110,14 @@ class EditorWidget(Widget.TextAreaWidget):
elif portal_type == "Web Style": elif portal_type == "Web Style":
mode = "css" mode = "css"
site_root = here.getWebSiteValue() or here.getPortalObject() site_root = here.getWebSiteValue() or here.getPortalObject()
portal_type = here.getPortalType()
return code_mirror_support(field=field, return code_mirror_support(field=field,
content=value, content=value,
field_id=key, field_id=key,
portal_url=site_root.absolute_url(), portal_url=site_root.absolute_url(),
mode=mode, mode=mode,
keymap=site_root.portal_preferences.getPreferredSourceCodeEditorKeymap()) keymap=site_root.portal_preferences.getPreferredSourceCodeEditorKeymap(),
portal_type=portal_type)
elif text_editor != 'text_area': elif text_editor != 'text_area':
return here.fckeditor_wysiwyg_support.pt_render( return here.fckeditor_wysiwyg_support.pt_render(
extra_context= { extra_context= {
......
...@@ -31,6 +31,7 @@ from Products.ERP5Type.mixin.component import ComponentMixin ...@@ -31,6 +31,7 @@ from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
import zope.interface import zope.interface
from Products.ERP5Type.interfaces.component import IComponent from Products.ERP5Type.interfaces.component import IComponent
...@@ -62,3 +63,35 @@ class DocumentComponent(ComponentMixin, TextContentHistoryMixin): ...@@ -62,3 +63,35 @@ class DocumentComponent(ComponentMixin, TextContentHistoryMixin):
@staticmethod @staticmethod
def getIdPrefix(): def getIdPrefix():
return 'document' return 'document'
_message_reference_class_not_defined = "Class ${reference} must be defined"
def checkConsistency(self, *args, **kw):
"""
Per convention, a Document Component must have at least a class whose name
is the same as the Reference so that it can be assigned to Portal Types.
XXX: Very basic check for now.
"""
error_list = super(DocumentComponent, self).checkConsistency(*args ,**kw)
reference = self.getReference()
text_content = self.getTextContent()
# Already checked in the parent class
if reference and text_content:
class_definition_str = 'class %s' % reference
try:
sep = text_content[text_content.index(class_definition_str) +
len(class_definition_str)]
except (ValueError, IndexError):
pass
else:
if (sep == ':' or # old-style class
sep == '('): # new-style class
return error_list
error_list.append(ConsistencyMessage(
self,
self.getRelativeUrl(),
message=self._message_reference_class_not_defined,
mapping={'reference': reference}))
return error_list
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from Products.ERP5Type.Core.DocumentComponent import DocumentComponent
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
class InterfaceComponent(DocumentComponent):
"""
ZODB Component for interfaces
"""
meta_type = 'ERP5 Interface Component'
portal_type = 'Interface Component'
@staticmethod
def _getDynamicModuleNamespace():
return 'erp5.component.interface'
@staticmethod
def getIdPrefix():
return 'interface'
_message_reference_wrong_naming = "Interface Reference must start with 'I'"
def checkConsistency(self, *args, **kw):
"""
Per convention, an Interface class must start with 'I'
"""
error_list = super(InterfaceComponent, self).checkConsistency(*args, **kw)
reference = self.getReference()
if (reference and # Already checked in the parent class
not reference.startswith('I')):
error_list.append(ConsistencyMessage(
self,
self.getRelativeUrl(),
message=self._message_reference_wrong_naming,
mapping={}))
return error_list
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from Products.ERP5Type.Core.DocumentComponent import DocumentComponent
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
class MixinComponent(DocumentComponent):
"""
ZODB Component for mixins
"""
meta_type = 'ERP5 Mixin Component'
portal_type = 'Mixin Component'
@staticmethod
def _getDynamicModuleNamespace():
return 'erp5.component.mixin'
@staticmethod
def getIdPrefix():
return 'mixin'
_message_reference_wrong_naming = "Mixin Reference must end with 'Mixin'"
def checkConsistency(self, *args, **kw):
"""
Per convention, a Mixin class must end with 'Mixin'
"""
error_list = super(MixinComponent, self).checkConsistency(*args, **kw)
reference = self.getReference()
if (reference and # Already checked in the parent class
not reference.endswith('Mixin')):
error_list.append(ConsistencyMessage(
self,
self.getRelativeUrl(),
message=self._message_reference_wrong_naming,
mapping={}))
return error_list
...@@ -200,36 +200,6 @@ class TypesTool(TypeProvider): ...@@ -200,36 +200,6 @@ class TypesTool(TypeProvider):
return None return None
return getattr(self, portal_type, None) return getattr(self, portal_type, None)
security.declareProtected(Permissions.AccessContentsInformation, 'getDocumentTypeList')
def getDocumentTypeList(self):
"""
Return a list of Document types (including filesystem and ZODB Component
Documents) that can be used as Base classes
"""
from Products.ERP5Type import document_class_registry
document_type_set = set(document_class_registry)
import erp5.component.document
portal = self.getPortalObject()
version_priority_set = set(portal.getVersionPriorityNameList())
# objectValues should not be used for a large number of objects, but
# this is only done upon reset, moreover using the Catalog is too risky
# as it lags behind and depends upon objects being reindexed
for component in portal.portal_components.objectValues(portal_type='Document Component'):
# Only consider modified or validated states as state transition will
# be handled by component_validation_workflow which will take care of
# updating the registry
validation_state_tuple = component.getValidationState()
if validation_state_tuple in ('modified', 'validated'):
version = component.getVersion(validated_only=True)
# The versions should have always been set on ERP5Site property
# beforehand
if version in version_priority_set:
document_type_set.add(component.getReference(validated_only=True))
return sorted(document_type_set)
security.declareProtected(Permissions.AccessContentsInformation, 'getPortalTypeClass') security.declareProtected(Permissions.AccessContentsInformation, 'getPortalTypeClass')
def getPortalTypeClass(self, context, temp=False): def getPortalTypeClass(self, context, temp=False):
""" """
...@@ -258,13 +228,44 @@ class TypesTool(TypeProvider): ...@@ -258,13 +228,44 @@ class TypesTool(TypeProvider):
module = erp5.portal_type module = erp5.portal_type
return getattr(module, portal_type, None) return getattr(module, portal_type, None)
def _getTypeList(self, component_portal_type, fs_type_list):
portal = self.getPortalObject()
version_priority_set = set(portal.getVersionPriorityNameList())
# objectValues should not be used for a large number of objects, but
# this is only done upon reset, moreover using the Catalog is too risky
# as it lags behind and depends upon objects being reindexed
type_set = set(fs_type_list)
for component in portal.portal_components.objectValues(portal_type=component_portal_type):
# Only consider modified or validated states as state transition will
# be handled by component_validation_workflow which will take care of
# updating the registry
validation_state_tuple = component.getValidationState()
if validation_state_tuple in ('modified', 'validated'):
version = component.getVersion(validated_only=True)
# The versions should have always been set on ERP5Site property
# beforehand
if version in version_priority_set:
type_set.add(component.getReference(validated_only=True))
return sorted(type_set)
security.declareProtected(Permissions.AccessContentsInformation, 'getDocumentTypeList')
def getDocumentTypeList(self):
"""
Return a list of Document types (including filesystem and ZODB Component
Documents) that can be used as Base classes
"""
from Products.ERP5Type import document_class_registry
return self._getTypeList('Document Component', document_class_registry)
security.declareProtected(Permissions.AccessContentsInformation, 'getMixinTypeList') security.declareProtected(Permissions.AccessContentsInformation, 'getMixinTypeList')
def getMixinTypeList(self): def getMixinTypeList(self):
""" """
Return a list of class names that can be used as Mixins Return a list of class names that can be used as Mixins
""" """
from Products.ERP5Type import mixin_class_registry from Products.ERP5Type import mixin_class_registry
return sorted(mixin_class_registry) return self._getTypeList('Mixin Component', mixin_class_registry)
security.declareProtected(Permissions.AccessContentsInformation, 'getInterfaceTypeList') security.declareProtected(Permissions.AccessContentsInformation, 'getInterfaceTypeList')
def getInterfaceTypeList(self): def getInterfaceTypeList(self):
...@@ -272,7 +273,9 @@ class TypesTool(TypeProvider): ...@@ -272,7 +273,9 @@ class TypesTool(TypeProvider):
Return a list of class names that can be used as Interfaces Return a list of class names that can be used as Interfaces
""" """
from Products.ERP5Type import interfaces from Products.ERP5Type import interfaces
return [name for name, cls in inspect.getmembers(interfaces, inspect.isclass)] return self._getTypeList(
'Interface Component',
[name for name, _ in inspect.getmembers(interfaces, inspect.isclass)])
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'resetDynamicDocumentsOnceAtTransactionBoundary') 'resetDynamicDocumentsOnceAtTransactionBoundary')
......
...@@ -423,7 +423,7 @@ def fill_args_from_request(*optional_args): ...@@ -423,7 +423,7 @@ def fill_args_from_request(*optional_args):
_pylint_message_re = re.compile( _pylint_message_re = re.compile(
'^(?P<type>[CRWEF]):\s*(?P<row>\d+),\s*(?P<column>\d+):\s*(?P<message>.*)$') '^(?P<type>[CRWEF]):\s*(?P<row>\d+),\s*(?P<column>\d+):\s*(?P<message>.*)$')
def checkPythonSourceCode(source_code_str): def checkPythonSourceCode(source_code_str, portal_type=None):
""" """
Check source code with pylint or compile() builtin if not available. Check source code with pylint or compile() builtin if not available.
...@@ -511,6 +511,15 @@ def checkPythonSourceCode(source_code_str): ...@@ -511,6 +511,15 @@ def checkPythonSourceCode(source_code_str):
'--disable=W0212', '--disable=W0212',
# string module does not only contain deprecated functions... # string module does not only contain deprecated functions...
'--deprecated-modules=regsub,TERMIOS,Bastion,rexec'] '--deprecated-modules=regsub,TERMIOS,Bastion,rexec']
if portal_type == 'Interface Component':
# Interface inherits from InterfaceClass:
# E: 4, 0: Inheriting 'Interface', which is not a class. (inherit-non-class)
args.append('--disable=E0239')
# Interfaces methods have no arguments:
# E: 5, 2: Method has no argument (no-method-argument)
args.append('--disable=E0211')
try: try:
from pylint.extensions.bad_builtin import __name__ as ext from pylint.extensions.bad_builtin import __name__ as ext
args.append('--load-plugins=' + ext) args.append('--load-plugins=' + ext)
......
...@@ -182,6 +182,10 @@ def initializeDynamicModules(): ...@@ -182,6 +182,10 @@ def initializeDynamicModules():
holds ZODB Component packages holds ZODB Component packages
erp5.component.document: erp5.component.document:
holds Document modules previously found in bt5 in $INSTANCE_HOME/Document holds Document modules previously found in bt5 in $INSTANCE_HOME/Document
erp5.component.interface:
holds Interface modules previously found in Products.NAME.interfaces
erp5.component.mixin:
holds Mixin modules previously found in Products.NAME.mixin
erp5.component.extension: erp5.component.extension:
holds Extension modules previously found in bt5 in holds Extension modules previously found in bt5 in
$INSTANCE_HOME/Extensions $INSTANCE_HOME/Extensions
...@@ -236,6 +240,12 @@ def initializeDynamicModules(): ...@@ -236,6 +240,12 @@ def initializeDynamicModules():
erp5.component.document = ComponentDynamicPackage('erp5.component.document', erp5.component.document = ComponentDynamicPackage('erp5.component.document',
'Document Component') 'Document Component')
erp5.component.interface = ComponentDynamicPackage('erp5.component.interface',
'Interface Component')
erp5.component.mixin = ComponentDynamicPackage('erp5.component.mixin',
'Mixin Component')
erp5.component.test = ComponentDynamicPackage('erp5.component.test', erp5.component.test = ComponentDynamicPackage('erp5.component.test',
'Test Component') 'Test Component')
finally: finally:
......
...@@ -201,9 +201,8 @@ def generatePortalTypeClass(site, portal_type_name): ...@@ -201,9 +201,8 @@ def generatePortalTypeClass(site, portal_type_name):
klass = getattr(module, type_class) klass = getattr(module, type_class)
except AttributeError: except AttributeError:
LOG("ERP5Type.dynamic", WARNING, LOG("ERP5Type.dynamic", WARNING,
"Could not get class '%s' in Component module '%s'" % \ "Could not get class '%s' in Component module %r, fallback on filesystem" %
(type_class, (type_class, module))
module))
if klass is None: if klass is None:
type_class_path = document_class_registry.get(type_class) type_class_path = document_class_registry.get(type_class)
...@@ -244,18 +243,58 @@ def generatePortalTypeClass(site, portal_type_name): ...@@ -244,18 +243,58 @@ def generatePortalTypeClass(site, portal_type_name):
# "Filled accessor holder list for portal_type %s (%s)" % \ # "Filled accessor holder list for portal_type %s (%s)" % \
# (portal_type_name, accessor_holder_list)) # (portal_type_name, accessor_holder_list))
mixin_path_list = [] mixin_class_list = []
if mixin_list: if mixin_list:
mixin_path_list = map(mixin_class_registry.__getitem__, mixin_list) # Only one Mixin class per ZODB Component (!= FS) where module_name ==
mixin_class_list = map(_importClass, mixin_path_list) # class_name, name ending with 'Mixin'.
#
# Rationale: same as Document/Interface; consistent naming; avoid a
# registry like there used to be with FS.
import erp5.component.mixin
for mixin in mixin_list:
mixin_module = erp5.component.mixin.find_load_module(mixin)
mixin_class = None
if mixin_module is not None:
try:
mixin_class = getattr(mixin_module, mixin)
except AttributeError:
LOG("ERP5Type.dynamic", WARNING,
"Could not get class '%s' in Component module %r, fallback on filesystem" %
(mixin, mixin_module))
if mixin_class is None:
mixin_class = _importClass(mixin_class_registry[mixin])
mixin_class_list.append(mixin_class)
base_class_list = [klass] + accessor_holder_list + mixin_class_list base_class_list = [klass] + accessor_holder_list + mixin_class_list
interface_class_list = [] interface_class_list = []
if interface_list: if interface_list:
from Products.ERP5Type import interfaces # Filesystem Interfaces may have defined several Interfaces in one file
interface_class_list = [getattr(interfaces, name) # but only *one* Interface per ZODB Component where module_name ==
for name in interface_list] # class_name, name starting with 'I'.
#
# Rationale: same as Document/Mixin; consistent naming; avoid a registry
# like there used to be for Mixin or importing all class in
# Products.ERP5Type.interfaces.__init__.py.
import erp5.component.interface
from Products.ERP5Type import interfaces as filesystem_interfaces
for interface in interface_list:
interface_module = erp5.component.interface.find_load_module(interface)
interface_class = None
if interface_module is not None:
try:
interface_class = getattr(interface_module, interface)
except AttributeError:
LOG("ERP5Type.dynamic", WARNING,
"Could not get class '%s' in Component module %r, fallback on filesystem" %
(interface, interface_module))
if interface_class is None:
interface_class = getattr(filesystem_interfaces, interface)
interface_class_list.append(interface_class)
if portal_type_name in core_portal_type_class_dict: if portal_type_name in core_portal_type_class_dict:
core_portal_type_class_dict[portal_type_name]['generating'] = False core_portal_type_class_dict[portal_type_name]['generating'] = False
......
...@@ -306,7 +306,7 @@ class ComponentMixin(PropertyRecordableMixin, Base): ...@@ -306,7 +306,7 @@ class ComponentMixin(PropertyRecordableMixin, Base):
Check Component source code through Pylint or compile() builtin if not Check Component source code through Pylint or compile() builtin if not
available available
""" """
return checkPythonSourceCode(self.getTextContent()) return checkPythonSourceCode(self.getTextContent(), self.getPortalType())
security.declareProtected(Permissions.ModifyPortalContent, 'PUT') security.declareProtected(Permissions.ModifyPortalContent, 'PUT')
def PUT(self, REQUEST, RESPONSE): def PUT(self, REQUEST, RESPONSE):
......
...@@ -83,6 +83,7 @@ def manage_page_footer(self): ...@@ -83,6 +83,7 @@ def manage_page_footer(self):
if not textarea_selector: if not textarea_selector:
return default return default
portal_type = document.meta_type
if editor == 'codemirror' and getattr(portal, 'code_mirror_support', None) is not None: if editor == 'codemirror' and getattr(portal, 'code_mirror_support', None) is not None:
keymap = portal.portal_preferences.getPreferredSourceCodeEditorKeymap() keymap = portal.portal_preferences.getPreferredSourceCodeEditorKeymap()
return '''<script type="text/javascript" src="%s/jquery/core/jquery.min.js"></script> return '''<script type="text/javascript" src="%s/jquery/core/jquery.min.js"></script>
...@@ -93,7 +94,8 @@ def manage_page_footer(self): ...@@ -93,7 +94,8 @@ def manage_page_footer(self):
portal_url=portal_url, portal_url=portal_url,
bound_names=bound_names, bound_names=bound_names,
mode=mode, mode=mode,
keymap=keymap)) keymap=keymap,
portal_type=portal_type))
else: else:
return ''' return '''
<script type="text/javascript" src="%(portal_url)s/jquery/core/jquery.min.js"></script> <script type="text/javascript" src="%(portal_url)s/jquery/core/jquery.min.js"></script>
...@@ -133,7 +135,8 @@ $(document).ready(function() { ...@@ -133,7 +135,8 @@ $(document).ready(function() {
{'data': JSON.stringify( {'data': JSON.stringify(
{ code: editor.getSession().getValue(), { code: editor.getSession().getValue(),
bound_names: %(bound_names)s, bound_names: %(bound_names)s,
params: $('input[name="params"]').val() })}, params: $('input[name="params"]').val(),
portal_type: %(portal_type)s })},
function(data){ function(data){
editor.getSession().setAnnotations(data.annotations); editor.getSession().setAnnotations(data.annotations);
} }
......
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