Commit 7ab4b81d authored by Rafael Monnerat's avatar Rafael Monnerat

Solve merge conflicts on revision files modified at rafael and master branch

Merged master into rafael branch

Conflicts:
	bt5/erp5_ui_test/bt/revision
	product/ERP5/bootstrap/erp5_core/bt/revision
parents 8c6785a9 0b539231
Changes Changes
======= =======
0.4.3 (2012-04-24)
----------------
* erp5.util.testnode:
- Improve detection of the cancellation of a test on the master
- better management of SIGTERM signal
- cleanup test instances to make sure nothing stay from a previous
test run
0.4.2 (2012-04-11)
----------------
* erp5.util.testnode:
- Improve testnode logs
- add a thread to upload ongoing logs to the master regularly
- if the software release is not built successfully after a
few time, totally erase software. This help unblocking if
buildout is unable to update software.
- check if the last test result was cancelled in order to
allow relaunching test without restarting testnode
0.4.1 (2012-02-29) 0.4.1 (2012-02-29)
---------------- ----------------
......
...@@ -18,6 +18,7 @@ def generateBarcodeImage(self, barcode_type, data): ...@@ -18,6 +18,7 @@ def generateBarcodeImage(self, barcode_type, data):
elif barcode_type == 'code128': elif barcode_type == 'code128':
from hubarcode.code128 import Code128Encoder from hubarcode.code128 import Code128Encoder
encoder = Code128Encoder(data) encoder = Code128Encoder(data)
encoder.text = '' # get barcode image only
output = encoder.get_imagedata() output = encoder.get_imagedata()
elif barcode_type == 'qrcode': elif barcode_type == 'qrcode':
import qrcode import qrcode
......
...@@ -57,7 +57,10 @@ event = portal.restrictedTraverse(event_relative_url)\n ...@@ -57,7 +57,10 @@ event = portal.restrictedTraverse(event_relative_url)\n
subject = event.getTitle()\n subject = event.getTitle()\n
body = event.getTextContent()\n body = event.getTextContent()\n
sender = event.getSourceValue()\n sender = event.getSourceValue()\n
if sender is not None:\n if kw.get("from_url") is not None:\n
from_url = kw.get("from_url")\n
elif event.getSource() is not None:\n
sender = event.getSourceValue()\n
from_url = formataddr((sender.getTitle(), sender.getDefaultEmailText()))\n from_url = formataddr((sender.getTitle(), sender.getDefaultEmailText()))\n
else:\n else:\n
from_url = portal.portal_preferences.getPreferredEventSenderEmail()\n from_url = portal.portal_preferences.getPreferredEventSenderEmail()\n
......
1020 1022
\ No newline at end of file \ No newline at end of file
...@@ -110,8 +110,15 @@ if portal_preferences.getPreferredCredentialAlarmAutomaticCall():\n ...@@ -110,8 +110,15 @@ if portal_preferences.getPreferredCredentialAlarmAutomaticCall():\n
message_str = "Credential Request Created."\n message_str = "Credential Request Created."\n
else:\n else:\n
if portal_preferences.isPreferredEmailVerificationCheck():\n if portal_preferences.isPreferredEmailVerificationCheck():\n
# Send email to subscriber in order to check email\'s address\n # after_path_and_method_id argument is used below to not activate when\n
credential_request.activate(activity=\'SQLQueue\').CredentialRequest_sendSubmittedNotification(\n # Crededial request object is not indexed yet. This is needed because when\n
# the method searchAndActivate from catalog is called, if the object is not\n
# indexed, the e-mail is not sent.\n
method_id_list = (\'immediateReindexObject\', \'recursiveImmediateReindexObject\')\n
path_and_method_id = (credential_request.getPath(), method_id_list)\n
activity_kw = dict(activity=\'SQLQueue\',\n
after_path_and_method_id=path_and_method_id)\n
credential_request.activate(**activity_kw).CredentialRequest_sendSubmittedNotification(\n
context_url=context.absolute_url(),\n context_url=context.absolute_url(),\n
notification_reference=\'erp5-subscription.notification\')\n notification_reference=\'erp5-subscription.notification\')\n
message_str = "Thanks for your registration. You will be receive an email to activate your account."\n message_str = "Thanks for your registration. You will be receive an email to activate your account."\n
......
412 413
\ No newline at end of file \ No newline at end of file
...@@ -73,6 +73,10 @@ ...@@ -73,6 +73,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Acknowledgement</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -75,6 +75,10 @@ ...@@ -75,6 +75,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Ticket</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -99,22 +99,31 @@ elif direction == \'incoming\':\n ...@@ -99,22 +99,31 @@ elif direction == \'incoming\':\n
else:\n else:\n
raise NotImplementedError, \'The specified direction is not handled: %r\' % (direction,)\n raise NotImplementedError, \'The specified direction is not handled: %r\' % (direction,)\n
\n \n
event_kw = {}\n event_kw = {\n
event_kw[\'portal_type\'] = portal_type\n \'portal_type\' : portal_type,\n
event_kw[\'title\'] = title\n \'title\' : title,\n
event_kw[\'resource\'] = resource\n \'resource\' : resource,\n
event_kw[\'source\'] = source_url\n \'source\' : source_url,\n
event_kw[\'source_section\'] = source_section_url\n \'source_section\' : source_section_url,\n
event_kw[\'destination\'] = destination_url\n \'destination\' : destination_url,\n
event_kw[\'destination_section\'] = destination_section_url\n \'destination_section\' : destination_section_url,\n
event_kw[\'start_date\'] = start_date\n \'start_date\' : start_date,\n
event_kw[\'follow_up\'] = follow_up\n \'follow_up\' : follow_up,\n
event_kw[\'text_content\'] = text_content\n \'text_content\' : text_content,\n
event_kw[\'content_type\'] = portal.portal_preferences.getPreferredTextEditor() and \'text/html\' or \'text/plain\'\n \'content_type\' : portal.portal_preferences.getPreferredTextEditor() and \'text/html\' or \'text/plain\',\n
\n }\n
# Create event\n # Create event\n
module = portal.getDefaultModule(portal_type=portal_type)\n module = portal.getDefaultModule(portal_type=portal_type)\n
event = module.newContent(**event_kw)\n event = module.newContent(**event_kw)\n
if not keep_draft:\n
if direction == \'incoming\':\n
# Support event_workflow and event_simulation_workflow\n
if portal.portal_workflow.isTransitionPossible(event, \'receive\'):\n
event.receive()\n
if portal.portal_workflow.isTransitionPossible(event, \'stop\'):\n
event.stop()\n
else:\n
event.plan()\n
\n \n
if batch_mode:\n if batch_mode:\n
return event\n return event\n
...@@ -126,7 +135,7 @@ event.Base_redirect(keep_items={\'portal_status_message\': message})\n ...@@ -126,7 +135,7 @@ event.Base_redirect(keep_items={\'portal_status_message\': message})\n
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>title, direction, portal_type, resource, text_content=None, batch_mode=False, **kw</string> </value> <value> <string>title, direction, portal_type, resource, text_content=None, batch_mode=False, keep_draft=False, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
<value> <value>
<list> <list>
<string>your_text_content</string> <string>your_text_content</string>
<string>your_keep_draft</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -99,6 +100,8 @@ ...@@ -99,6 +100,8 @@
<string>your_portal_type</string> <string>your_portal_type</string>
<string>your_resource</string> <string>your_resource</string>
<string>your_direction</string> <string>your_direction</string>
<string>your_source</string>
<string>your_destination</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_destination</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Recipient</string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string encoding="cdata"><![CDATA[
<br />
]]></string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getArrowItemList()+ [(here.getTitle(), here.getRelativeUrl())]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_keep_draft</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_checkbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Keep in draft state</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_source</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Sender or Caller</string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string encoding="cdata"><![CDATA[
<br />
]]></string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getArrowItemList() + [(here.getTitle(), here.getRelativeUrl())]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -57,13 +57,24 @@ event = context\n ...@@ -57,13 +57,24 @@ event = context\n
operator_list = event.getDestinationList()\n operator_list = event.getDestinationList()\n
try:\n try:\n
source_value = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n source_value = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if source_value:\n
operator_list.append(source_value.getRelativeUrl())\n
except ValueError:\n except ValueError:\n
source_value = None\n source_value = None\n
if source_value is not None:\n source_section = portal.portal_preferences.getPreferredSection(),\n
source_section_value = source_value.getDefaultCareerSubordinationValue()\n \n
operator_list.append(source_value.getRelativeUrl())\n \n
else:\n resource_kw = {\n
source_section_value = None\n "Campaign" : "follow_up_campaign_resource",\n
"Meeting" : "follow_up_meeting_resource",\n
"Sale Opportunity" : "follow_up_sale_opportunity_resource",\n
"Support Request" : "follow_up_support_request_resource",\n
}\n
\n
resource = None\n
if follow_up_ticket_type in resource_kw:\n
resource = kw.get(resource_kw[follow_up_ticket_type], None)\n
\n
\n \n
module = portal.getDefaultModule(follow_up_ticket_type)\n module = portal.getDefaultModule(follow_up_ticket_type)\n
ticket = module.newContent(\n ticket = module.newContent(\n
...@@ -71,20 +82,25 @@ ticket = module.newContent(\n ...@@ -71,20 +82,25 @@ ticket = module.newContent(\n
title=follow_up_ticket_title,\n title=follow_up_ticket_title,\n
start_date=event.getStartDate(),\n start_date=event.getStartDate(),\n
destination_decision_list=event.getSourceList(),\n destination_decision_list=event.getSourceList(),\n
destination_section=event.getSourceSection() or event.getSource(),\n # destination_section=event.getSourceSection() or event.getSource(),\n
source_trade_set=operator_list,\n source_trade_set=operator_list,\n
source_value=source_value,\n source_value=source_value,\n
source_section_value=source_section_value,\n source_section=source_section,\n
resource=resource,\n
)\n )\n
\n \n
follow_up_list = event.getFollowUpList()\n follow_up_list = event.getFollowUpList()\n
follow_up_list.append(ticket.getRelativeUrl())\n follow_up_list.append(ticket.getRelativeUrl())\n
event.edit(follow_up_list=follow_up_list)\n event.edit(follow_up_list=follow_up_list)\n
\n
if portal.portal_workflow.isTransitionPossible(\n
ticket, \'submit\'):\n
ticket.submit()\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>follow_up_ticket_title="Sale Opportunity", follow_up_ticket_type=None, follow_up_ticket_resource=None, **kw</string> </value> <value> <string>follow_up_ticket_title="Sale Opportunity", follow_up_ticket_type=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -51,17 +51,22 @@ ...@@ -51,17 +51,22 @@
<item> <item>
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string>context.Event_createFollowUpTicket(follow_up_ticket_type=follow_up_ticket_type,\n <value> <string>context.Event_createFollowUpTicket(follow_up_ticket_type=follow_up_ticket_type,\n
follow_up_ticket_title=follow_up_ticket_title)\n follow_up_ticket_title=follow_up_ticket_title,\n
follow_up_campaign_resource=follow_up_campaign_resource,\n
follow_up_meeting_resource=follow_up_meeting_resource,\n
follow_up_sale_opportunity_resource=follow_up_sale_opportunity_resource,\n
follow_up_support_request_resource=follow_up_support_request_resource,\n
**kw)\n
if context.getPortalObject().portal_workflow.isTransitionPossible(\n if context.getPortalObject().portal_workflow.isTransitionPossible(\n
context, \'deliver\'):\n context, \'deliver\'):\n
context.deliver()\n context.deliver()\n
return context.Base_redirect("", \n return context.Base_redirect("",\n
keep_items={\'portal_status_message\':context.getPortalObject().Base_translateString("Follow Up Ticket Created.")})\n keep_items={\'portal_status_message\':context.getPortalObject().Base_translateString("Follow Up Ticket Created.")})\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>follow_up_ticket_type=None, follow_up_ticket_title=None, **kw</string> </value> <value> <string>follow_up_ticket_type=None, follow_up_ticket_title=None, follow_up_campaign_resource=None, follow_up_meeting_resource=None, follow_up_sale_opportunity_resource=None, follow_up_support_request_resource=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
......
...@@ -95,6 +95,11 @@ ...@@ -95,6 +95,11 @@
<list> <list>
<string>your_follow_up_ticket_title</string> <string>your_follow_up_ticket_title</string>
<string>your_follow_up_ticket_type</string> <string>your_follow_up_ticket_type</string>
<string>your_follow_up_campaign_resource</string>
<string>your_follow_up_support_request_resource</string>
<string>your_follow_up_meeting_resource</string>
<string>your_follow_up_sale_opportunity_resource</string>
<string>additionnal_javascript</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="EditorField" module="Products.ERP5Form.EditorField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>additionnal_javascript</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string>hidden</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string encoding="cdata"><![CDATA[
<script>\n
$(function (){\n
function toggleNatureField() {\n
if ($("select[name=\'field_your_follow_up_ticket_type\'] option:selected").val() == \'Support Request\') {\n
$("select[name=\'field_your_follow_up_campaign_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_campaign_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").parent().parent().removeClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").removeClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").addClass("hidden");\n
}\n
else if ($("select[name=\'field_your_follow_up_ticket_type\'] option:selected").val() == \'Campaign\'){\n
$("select[name=\'field_your_follow_up_campaign_resource\']").parent().parent().removeClass("hidden");\n
$("select[name=\'field_your_follow_up_campaign_resource\']").removeClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").addClass("hidden");\n
}\n
else if ($("select[name=\'field_your_follow_up_ticket_type\'] option:selected").val() == \'Meeting\'){\n
$("select[name=\'field_your_follow_up_campaign_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_campaign_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").parent().parent().removeClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").removeClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").addClass("hidden");\n
}\n
else if ($("select[name=\'field_your_follow_up_ticket_type\'] option:selected").val() == \'Sale Opportunity\'){\n
$("select[name=\'field_your_follow_up_campaign_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_campaign_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").parent().parent().removeClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").removeClass("hidden");\n
}\n
else {\n
$("select[name=\'field_your_follow_up_campaign_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_campaign_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_meeting_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_support_request_resource\']").addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").parent().parent().addClass("hidden");\n
$("select[name=\'field_your_follow_up_sale_opportunity_resource\']").addClass("hidden");\n
}\n
}\n
$("select[name=\'field_your_follow_up_ticket_type\']").change(function(){toggleNatureField()});\n
toggleNatureField();\n
});\n
</script>
]]></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string>text_area</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>show</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>string:</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>css_class</string>
<string>default</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_follow_up_campaign_resource</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>css_class</string> </key>
<value> <string>hidden</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>your_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Nature</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getResourceItemList(portal_type="Campaign", include_context=False)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>css_class</string>
<string>default</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_follow_up_meeting_resource</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>css_class</string> </key>
<value> <string>hidden</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>your_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Nature</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getResourceItemList(portal_type="Meeting", include_context=False)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>css_class</string>
<string>default</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_follow_up_sale_opportunity_resource</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>css_class</string> </key>
<value> <string>hidden</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>your_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Nature</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getResourceItemList(portal_type="Sale Opportunity", include_context=False)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>default</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_follow_up_support_request_resource</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>your_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Nature</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.Ticket_getResourceItemList(portal_type="Support Request", include_context=False)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>default</string>
<string>required</string> <string>required</string>
</list> </list>
</value> </value>
...@@ -52,6 +53,12 @@ ...@@ -52,6 +53,12 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -60,6 +67,10 @@ ...@@ -60,6 +67,10 @@
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -71,6 +82,10 @@ ...@@ -71,6 +82,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>your_title</string> </value> <value> <string>your_title</string> </value>
...@@ -93,4 +108,17 @@ ...@@ -93,4 +108,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>here/getTitle</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -148,7 +148,9 @@ ...@@ -148,7 +148,9 @@
</item> </item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <string></string> </value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>external_validator</string> </key> <key> <string>external_validator</string> </key>
...@@ -304,4 +306,17 @@ ...@@ -304,4 +306,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.getPortalType() == "Mail Message"</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -54,18 +54,21 @@ ...@@ -54,18 +54,21 @@
arrow = portal.portal_property_sheets.get("Arrow")\n arrow = portal.portal_property_sheets.get("Arrow")\n
\n \n
value_list = [(\'\', \'\'),]\n value_list = [(\'\', \'\'),]\n
value_list_append = value_list.append\n
\n \n
# add current user\n # add current user\n
user = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n user = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if user is not None:\n if user is not None:\n
value_list.append((user.getTitle(), user.getRelativeUrl()))\n value_list_append((user.getTitle(), user.getRelativeUrl()))\n
\n
for property in arrow.contentValues():\n
value = context.getProperty("%s_value" %property.getReference(), None)\n
if value is not None and value.getPortalType() in portal.getPortalNodeTypeList():\n
value_list.append((value.getTitle(), value.getRelativeUrl()))\n
\n \n
for property_value in arrow.contentValues():\n
value = context.getProperty("%s_value" %property_value.getReference(), None)\n
if value and value.getPortalType() in portal.getPortalNodeTypeList():\n
value = (value.getTitle(), value.getRelativeUrl())\n
if value not in value_list:\n
value_list_append(value)\n
\n \n
value_list.sort(key=lambda x: x[0])\n
\n \n
return value_list\n return value_list\n
</string> </value> </string> </value>
......
...@@ -59,23 +59,26 @@ from zExceptions import Unauthorized\n ...@@ -59,23 +59,26 @@ from zExceptions import Unauthorized\n
from Products.ERP5Type.Cache import CachingMethod\n from Products.ERP5Type.Cache import CachingMethod\n
portal = context.getPortalObject()\n portal = context.getPortalObject()\n
\n \n
preference_id = \'preferred_%s_use\' % \'_\'.join(token.lower() for token in context.getPortalType().split(\' \'))\n if not portal_type:\n
portal_type = context.getPortalType()\n
\n
preference_id = \'preferred_%s_use\' % \'_\'.join(token.lower() for token in portal_type.split(\' \'))\n
sql_kw = {\'portal_type\': portal.getPortalResourceTypeList(),\n sql_kw = {\'portal_type\': portal.getPortalResourceTypeList(),\n
\'use_uid\': portal.portal_categories.getCategoryUid(portal.portal_preferences.getPreference(preference_id), base_category=\'use\'),\n \'use_uid\': portal.portal_categories.getCategoryUid(portal.portal_preferences.getPreference(preference_id), base_category=\'use\'),\n
\'validation_state\': \'validated\',\n \'validation_state\': \'validated\',\n
\'sort_on\': \'title\'}\n \'sort_on\': \'title\'}\n
\n \n
def getResourceItemList():\n def getResourceItemList(portal_type):\n
return [(\'\', \'\')] + [(result.getTitle(), result.getRelativeUrl()) for result in portal.portal_catalog(**sql_kw)]\n return [(\'\', \'\')] + [(result.getTitle(), result.getRelativeUrl()) for result in portal.portal_catalog(**sql_kw)]\n
\n \n
getResourceItemList = CachingMethod(getResourceItemList, \n getResourceItemList = CachingMethod(getResourceItemList, \n
id=(script.id, context.Localizer.get_selected_language()), \n id=(script.id, context.Localizer.get_selected_language()), \n
cache_factory=\'erp5_ui_long\')\n cache_factory=\'erp5_ui_long\')\n
\n \n
result_list = getResourceItemList()[:]\n result_list = getResourceItemList(portal_type)[:]\n
\n \n
# BBB returns actual value in list field\n # BBB returns actual value in list field\n
if context.getResource() and context.getResource() not in [result[1] for result in result_list]:\n if include_context and context.getResource() and context.getResource() not in [result[1] for result in result_list]:\n
try:\n try:\n
resource_value = portal.portal_categories.getCategoryValue(context.getResource(), base_category=\'resource\')\n resource_value = portal.portal_categories.getCategoryValue(context.getResource(), base_category=\'resource\')\n
if resource_value is not None:\n if resource_value is not None:\n
...@@ -94,7 +97,7 @@ return result_list\n ...@@ -94,7 +97,7 @@ return result_list\n
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string></string> </value> <value> <string>portal_type=None, include_context=True</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -77,14 +77,15 @@ event = module.newContent(portal_type=portal_type, \n ...@@ -77,14 +77,15 @@ event = module.newContent(portal_type=portal_type, \n
follow_up=context.getRelativeUrl())\n follow_up=context.getRelativeUrl())\n
\n \n
# Trigger appropriate workflow action\n # Trigger appropriate workflow action\n
if direction == \'incoming\':\n if not keep_draft:\n
# Support event_workflow and event_simulation_workflow\n if direction == \'incoming\':\n
if portal.portal_workflow.isTransitionPossible(event, \'receive\'):\n # Support event_workflow and event_simulation_workflow\n
event.receive()\n if portal.portal_workflow.isTransitionPossible(event, \'receive\'):\n
if portal.portal_workflow.isTransitionPossible(event, \'stop\'):\n event.receive()\n
event.stop()\n if portal.portal_workflow.isTransitionPossible(event, \'stop\'):\n
else:\n event.stop()\n
event.plan()\n else:\n
event.plan()\n
\n \n
# Redirect to event\n # Redirect to event\n
portal_status_message = translateString(\n portal_status_message = translateString(\n
...@@ -95,7 +96,7 @@ return event.Base_redirect(\'view\', keep_items = dict(portal_status_message=por ...@@ -95,7 +96,7 @@ return event.Base_redirect(\'view\', keep_items = dict(portal_status_message=por
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>form_id=\'view\', portal_type=None, title=None, resource=None, text_content=None,direction=None, source=None, destination=None, **kw</string> </value> <value> <string>form_id=\'view\', portal_type=None, title=None, resource=None, text_content=None,direction=None, source=None, destination=None, keep_draft=False, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
<value> <value>
<list> <list>
<string>your_text_content</string> <string>your_text_content</string>
<string>your_keep_draft</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_keep_draft</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_checkbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Keep in draft state</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
592 593
\ No newline at end of file \ No newline at end of file
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
<key> <string>Add portal content</string> </key> <key> <string>Add portal content</string> </key>
<value> <value>
<tuple> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string> <string>Manager</string>
</tuple> </tuple>
</value> </value>
...@@ -76,6 +78,8 @@ ...@@ -76,6 +78,8 @@
<key> <string>Delete objects</string> </key> <key> <string>Delete objects</string> </key>
<value> <value>
<tuple> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string> <string>Manager</string>
</tuple> </tuple>
</value> </value>
...@@ -84,6 +88,8 @@ ...@@ -84,6 +88,8 @@
<key> <string>Modify portal content</string> </key> <key> <string>Modify portal content</string> </key>
<value> <value>
<tuple> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string> <string>Manager</string>
</tuple> </tuple>
</value> </value>
......
9 10
\ No newline at end of file \ No newline at end of file
<?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_report</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_report</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </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>role_information_list_view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Add portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>2.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Role Information List</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}/TypesTool_viewRoleInformationList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5Form" module="Products.ERP5Form.Form"/>
</pickle>
<pickle>
<dictionary>
<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/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<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>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list>
<string>listbox_role_name_list</string>
<string>listbox_role_category_list</string>
<string>listbox_role_base_category_list</string>
</list>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TypesTool_viewRoleInformationList</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>TypesTool_viewRoleInformationList</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_list</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>count_method</string>
<string>list_method</string>
<string>portal_types</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>parent_title</string>
<string>Portal Type</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>role_name_list</string>
<string>Roles</string>
</tuple>
<tuple>
<string>condition_text</string>
<string>Condition</string>
</tuple>
<tuple>
<string>role_base_category_list</string>
<string>Base Categories</string>
</tuple>
<tuple>
<string>role_base_category_script_id</string>
<string>Base Category Script</string>
</tuple>
<tuple>
<string>role_category_list</string>
<string>Categories</string>
</tuple>
<tuple>
<string>description</string>
<string>Description</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>count_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Role Information</string>
<string>Role Information</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>parent_title</string>
<string>parent_title</string>
</tuple>
<tuple>
<string>title</string>
<string>title</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Role Informations</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>countResults</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>portal_catalog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_role_base_category_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_lines_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_role_category_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_lines_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_role_name_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_lines_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2012-04-19 Kazuhiko
* add TypesTool_viewRoleInformationList that lists all Role Informations.
2011-08-08 yusei 2011-08-08 yusei
* Extract messages from constraints in ZODB property sheets for POT. * Extract messages from constraints in ZODB property sheets for POT.
......
665 666
\ No newline at end of file \ No newline at end of file
...@@ -34,4 +34,5 @@ Glossary Term | view ...@@ -34,4 +34,5 @@ Glossary Term | view
Preference | vcs Preference | vcs
Template Tool | bt_vcs_history Template Tool | bt_vcs_history
Template Tool | search_portal_type Template Tool | search_portal_type
Types Tool | role_information_list_view
portal_actions | generate_pot_file portal_actions | generate_pot_file
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>jcarousel</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>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34739351.92</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>jquery.jcarousel.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
/*!\n
* jCarousel - Riding carousels with jQuery\n
* http://sorgalla.com/jcarousel/\n
*\n
* Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)\n
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n
*\n
* Built on top of the jQuery library\n
* http://jquery.com\n
*\n
* Inspired by the "Carousel Component" by Bill Scott\n
* http://billwscott.com/carousel/\n
*/\n
\n
(function(g){var q={vertical:!1,rtl:!1,start:1,offset:1,size:null,scroll:3,visible:null,animation:"normal",easing:"swing",auto:0,wrap:null,initCallback:null,setupCallback:null,reloadCallback:null,itemLoadCallback:null,itemFirstInCallback:null,itemFirstOutCallback:null,itemLastInCallback:null,itemLastOutCallback:null,itemVisibleInCallback:null,itemVisibleOutCallback:null,animationStepCallback:null,buttonNextHTML:"<div></div>",buttonPrevHTML:"<div></div>",buttonNextEvent:"click",buttonPrevEvent:"click", buttonNextCallback:null,buttonPrevCallback:null,itemFallbackDimension:null},m=!1;g(window).bind("load.jcarousel",function(){m=!0});g.jcarousel=function(a,c){this.options=g.extend({},q,c||{});this.autoStopped=this.locked=!1;this.buttonPrevState=this.buttonNextState=this.buttonPrev=this.buttonNext=this.list=this.clip=this.container=null;if(!c||c.rtl===void 0)this.options.rtl=(g(a).attr("dir")||g("html").attr("dir")||"").toLowerCase()=="rtl";this.wh=!this.options.vertical?"width":"height";this.lt=!this.options.vertical? this.options.rtl?"right":"left":"top";for(var b="",d=a.className.split(" "),f=0;f<d.length;f++)if(d[f].indexOf("jcarousel-skin")!=-1){g(a).removeClass(d[f]);b=d[f];break}a.nodeName.toUpperCase()=="UL"||a.nodeName.toUpperCase()=="OL"?(this.list=g(a),this.clip=this.list.parents(".jcarousel-clip"),this.container=this.list.parents(".jcarousel-container")):(this.container=g(a),this.list=this.container.find("ul,ol").eq(0),this.clip=this.container.find(".jcarousel-clip"));if(this.clip.size()===0)this.clip= this.list.wrap("<div></div>").parent();if(this.container.size()===0)this.container=this.clip.wrap("<div></div>").parent();b!==""&&this.container.parent()[0].className.indexOf("jcarousel-skin")==-1&&this.container.wrap(\'<div class=" \'+b+\'"></div>\');this.buttonPrev=g(".jcarousel-prev",this.container);if(this.buttonPrev.size()===0&&this.options.buttonPrevHTML!==null)this.buttonPrev=g(this.options.buttonPrevHTML).appendTo(this.container);this.buttonPrev.addClass(this.className("jcarousel-prev"));this.buttonNext= g(".jcarousel-next",this.container);if(this.buttonNext.size()===0&&this.options.buttonNextHTML!==null)this.buttonNext=g(this.options.buttonNextHTML).appendTo(this.container);this.buttonNext.addClass(this.className("jcarousel-next"));this.clip.addClass(this.className("jcarousel-clip")).css({position:"relative"});this.list.addClass(this.className("jcarousel-list")).css({overflow:"hidden",position:"relative",top:0,margin:0,padding:0}).css(this.options.rtl?"right":"left",0);this.container.addClass(this.className("jcarousel-container")).css({position:"relative"}); !this.options.vertical&&this.options.rtl&&this.container.addClass("jcarousel-direction-rtl").attr("dir","rtl");var j=this.options.visible!==null?Math.ceil(this.clipping()/this.options.visible):null,b=this.list.children("li"),e=this;if(b.size()>0){var h=0,i=this.options.offset;b.each(function(){e.format(this,i++);h+=e.dimension(this,j)});this.list.css(this.wh,h+100+"px");if(!c||c.size===void 0)this.options.size=b.size()}this.container.css("display","block");this.buttonNext.css("display","block");this.buttonPrev.css("display", "block");this.funcNext=function(){e.next()};this.funcPrev=function(){e.prev()};this.funcResize=function(){e.resizeTimer&&clearTimeout(e.resizeTimer);e.resizeTimer=setTimeout(function(){e.reload()},100)};this.options.initCallback!==null&&this.options.initCallback(this,"init");!m&&g.browser.safari?(this.buttons(!1,!1),g(window).bind("load.jcarousel",function(){e.setup()})):this.setup()};var f=g.jcarousel;f.fn=f.prototype={jcarousel:"0.2.8"};f.fn.extend=f.extend=g.extend;f.fn.extend({setup:function(){this.prevLast= this.prevFirst=this.last=this.first=null;this.animating=!1;this.tail=this.resizeTimer=this.timer=null;this.inTail=!1;if(!this.locked){this.list.css(this.lt,this.pos(this.options.offset)+"px");var a=this.pos(this.options.start,!0);this.prevFirst=this.prevLast=null;this.animate(a,!1);g(window).unbind("resize.jcarousel",this.funcResize).bind("resize.jcarousel",this.funcResize);this.options.setupCallback!==null&&this.options.setupCallback(this)}},reset:function(){this.list.empty();this.list.css(this.lt, "0px");this.list.css(this.wh,"10px");this.options.initCallback!==null&&this.options.initCallback(this,"reset");this.setup()},reload:function(){this.tail!==null&&this.inTail&&this.list.css(this.lt,f.intval(this.list.css(this.lt))+this.tail);this.tail=null;this.inTail=!1;this.options.reloadCallback!==null&&this.options.reloadCallback(this);if(this.options.visible!==null){var a=this,c=Math.ceil(this.clipping()/this.options.visible),b=0,d=0;this.list.children("li").each(function(f){b+=a.dimension(this, c);f+1<a.first&&(d=b)});this.list.css(this.wh,b+"px");this.list.css(this.lt,-d+"px")}this.scroll(this.first,!1)},lock:function(){this.locked=!0;this.buttons()},unlock:function(){this.locked=!1;this.buttons()},size:function(a){if(a!==void 0)this.options.size=a,this.locked||this.buttons();return this.options.size},has:function(a,c){if(c===void 0||!c)c=a;if(this.options.size!==null&&c>this.options.size)c=this.options.size;for(var b=a;b<=c;b++){var d=this.get(b);if(!d.length||d.hasClass("jcarousel-item-placeholder"))return!1}return!0}, get:function(a){return g(">.jcarousel-item-"+a,this.list)},add:function(a,c){var b=this.get(a),d=0,p=g(c);if(b.length===0)for(var j,e=f.intval(a),b=this.create(a);;){if(j=this.get(--e),e<=0||j.length){e<=0?this.list.prepend(b):j.after(b);break}}else d=this.dimension(b);p.get(0).nodeName.toUpperCase()=="LI"?(b.replaceWith(p),b=p):b.empty().append(c);this.format(b.removeClass(this.className("jcarousel-item-placeholder")),a);p=this.options.visible!==null?Math.ceil(this.clipping()/this.options.visible): null;d=this.dimension(b,p)-d;a>0&&a<this.first&&this.list.css(this.lt,f.intval(this.list.css(this.lt))-d+"px");this.list.css(this.wh,f.intval(this.list.css(this.wh))+d+"px");return b},remove:function(a){var c=this.get(a);if(c.length&&!(a>=this.first&&a<=this.last)){var b=this.dimension(c);a<this.first&&this.list.css(this.lt,f.intval(this.list.css(this.lt))+b+"px");c.remove();this.list.css(this.wh,f.intval(this.list.css(this.wh))-b+"px")}},next:function(){this.tail!==null&&!this.inTail?this.scrollTail(!1): this.scroll((this.options.wrap=="both"||this.options.wrap=="last")&&this.options.size!==null&&this.last==this.options.size?1:this.first+this.options.scroll)},prev:function(){this.tail!==null&&this.inTail?this.scrollTail(!0):this.scroll((this.options.wrap=="both"||this.options.wrap=="first")&&this.options.size!==null&&this.first==1?this.options.size:this.first-this.options.scroll)},scrollTail:function(a){if(!this.locked&&!this.animating&&this.tail){this.pauseAuto();var c=f.intval(this.list.css(this.lt)), c=!a?c-this.tail:c+this.tail;this.inTail=!a;this.prevFirst=this.first;this.prevLast=this.last;this.animate(c)}},scroll:function(a,c){!this.locked&&!this.animating&&(this.pauseAuto(),this.animate(this.pos(a),c))},pos:function(a,c){var b=f.intval(this.list.css(this.lt));if(this.locked||this.animating)return b;this.options.wrap!="circular"&&(a=a<1?1:this.options.size&&a>this.options.size?this.options.size:a);for(var d=this.first>a,g=this.options.wrap!="circular"&&this.first<=1?1:this.first,j=d?this.get(g): this.get(this.last),e=d?g:g-1,h=null,i=0,k=!1,l=0;d?--e>=a:++e<a;){h=this.get(e);k=!h.length;if(h.length===0&&(h=this.create(e).addClass(this.className("jcarousel-item-placeholder")),j[d?"before":"after"](h),this.first!==null&&this.options.wrap=="circular"&&this.options.size!==null&&(e<=0||e>this.options.size)))j=this.get(this.index(e)),j.length&&(h=this.add(e,j.clone(!0)));j=h;l=this.dimension(h);k&&(i+=l);if(this.first!==null&&(this.options.wrap=="circular"||e>=1&&(this.options.size===null||e<= this.options.size)))b=d?b+l:b-l}for(var g=this.clipping(),m=[],o=0,n=0,j=this.get(a-1),e=a;++o;){h=this.get(e);k=!h.length;if(h.length===0){h=this.create(e).addClass(this.className("jcarousel-item-placeholder"));if(j.length===0)this.list.prepend(h);else j[d?"before":"after"](h);if(this.first!==null&&this.options.wrap=="circular"&&this.options.size!==null&&(e<=0||e>this.options.size))j=this.get(this.index(e)),j.length&&(h=this.add(e,j.clone(!0)))}j=h;l=this.dimension(h);if(l===0)throw Error("jCarousel: No width/height set for items. This will cause an infinite loop. Aborting..."); this.options.wrap!="circular"&&this.options.size!==null&&e>this.options.size?m.push(h):k&&(i+=l);n+=l;if(n>=g)break;e++}for(h=0;h<m.length;h++)m[h].remove();i>0&&(this.list.css(this.wh,this.dimension(this.list)+i+"px"),d&&(b-=i,this.list.css(this.lt,f.intval(this.list.css(this.lt))-i+"px")));i=a+o-1;if(this.options.wrap!="circular"&&this.options.size&&i>this.options.size)i=this.options.size;if(e>i){o=0;e=i;for(n=0;++o;){h=this.get(e--);if(!h.length)break;n+=this.dimension(h);if(n>=g)break}}e=i-o+ 1;this.options.wrap!="circular"&&e<1&&(e=1);if(this.inTail&&d)b+=this.tail,this.inTail=!1;this.tail=null;if(this.options.wrap!="circular"&&i==this.options.size&&i-o+1>=1&&(d=f.intval(this.get(i).css(!this.options.vertical?"marginRight":"marginBottom")),n-d>g))this.tail=n-g-d;if(c&&a===this.options.size&&this.tail)b-=this.tail,this.inTail=!0;for(;a-- >e;)b+=this.dimension(this.get(a));this.prevFirst=this.first;this.prevLast=this.last;this.first=e;this.last=i;return b},animate:function(a,c){if(!this.locked&& !this.animating){this.animating=!0;var b=this,d=function(){b.animating=!1;a===0&&b.list.css(b.lt,0);!b.autoStopped&&(b.options.wrap=="circular"||b.options.wrap=="both"||b.options.wrap=="last"||b.options.size===null||b.last<b.options.size||b.last==b.options.size&&b.tail!==null&&!b.inTail)&&b.startAuto();b.buttons();b.notify("onAfterAnimation");if(b.options.wrap=="circular"&&b.options.size!==null)for(var c=b.prevFirst;c<=b.prevLast;c++)c!==null&&!(c>=b.first&&c<=b.last)&&(c<1||c>b.options.size)&&b.remove(c)}; this.notify("onBeforeAnimation");if(!this.options.animation||c===!1)this.list.css(this.lt,a+"px"),d();else{var f=!this.options.vertical?this.options.rtl?{right:a}:{left:a}:{top:a},d={duration:this.options.animation,easing:this.options.easing,complete:d};if(g.isFunction(this.options.animationStepCallback))d.step=this.options.animationStepCallback;this.list.animate(f,d)}}},startAuto:function(a){if(a!==void 0)this.options.auto=a;if(this.options.auto===0)return this.stopAuto();if(this.timer===null){this.autoStopped= !1;var c=this;this.timer=window.setTimeout(function(){c.next()},this.options.auto*1E3)}},stopAuto:function(){this.pauseAuto();this.autoStopped=!0},pauseAuto:function(){if(this.timer!==null)window.clearTimeout(this.timer),this.timer=null},buttons:function(a,c){if(a==null&&(a=!this.locked&&this.options.size!==0&&(this.options.wrap&&this.options.wrap!="first"||this.options.size===null||this.last<this.options.size),!this.locked&&(!this.options.wrap||this.options.wrap=="first")&&this.options.size!==null&& this.last>=this.options.size))a=this.tail!==null&&!this.inTail;if(c==null&&(c=!this.locked&&this.options.size!==0&&(this.options.wrap&&this.options.wrap!="last"||this.first>1),!this.locked&&(!this.options.wrap||this.options.wrap=="last")&&this.options.size!==null&&this.first==1))c=this.tail!==null&&this.inTail;var b=this;this.buttonNext.size()>0?(this.buttonNext.unbind(this.options.buttonNextEvent+".jcarousel",this.funcNext),a&&this.buttonNext.bind(this.options.buttonNextEvent+".jcarousel",this.funcNext), this.buttonNext[a?"removeClass":"addClass"](this.className("jcarousel-next-disabled")).attr("disabled",a?!1:!0),this.options.buttonNextCallback!==null&&this.buttonNext.data("jcarouselstate")!=a&&this.buttonNext.each(function(){b.options.buttonNextCallback(b,this,a)}).data("jcarouselstate",a)):this.options.buttonNextCallback!==null&&this.buttonNextState!=a&&this.options.buttonNextCallback(b,null,a);this.buttonPrev.size()>0?(this.buttonPrev.unbind(this.options.buttonPrevEvent+".jcarousel",this.funcPrev), c&&this.buttonPrev.bind(this.options.buttonPrevEvent+".jcarousel",this.funcPrev),this.buttonPrev[c?"removeClass":"addClass"](this.className("jcarousel-prev-disabled")).attr("disabled",c?!1:!0),this.options.buttonPrevCallback!==null&&this.buttonPrev.data("jcarouselstate")!=c&&this.buttonPrev.each(function(){b.options.buttonPrevCallback(b,this,c)}).data("jcarouselstate",c)):this.options.buttonPrevCallback!==null&&this.buttonPrevState!=c&&this.options.buttonPrevCallback(b,null,c);this.buttonNextState= a;this.buttonPrevState=c},notify:function(a){var c=this.prevFirst===null?"init":this.prevFirst<this.first?"next":"prev";this.callback("itemLoadCallback",a,c);this.prevFirst!==this.first&&(this.callback("itemFirstInCallback",a,c,this.first),this.callback("itemFirstOutCallback",a,c,this.prevFirst));this.prevLast!==this.last&&(this.callback("itemLastInCallback",a,c,this.last),this.callback("itemLastOutCallback",a,c,this.prevLast));this.callback("itemVisibleInCallback",a,c,this.first,this.last,this.prevFirst, this.prevLast);this.callback("itemVisibleOutCallback",a,c,this.prevFirst,this.prevLast,this.first,this.last)},callback:function(a,c,b,d,f,j,e){if(!(this.options[a]==null||typeof this.options[a]!="object"&&c!="onAfterAnimation")){var h=typeof this.options[a]=="object"?this.options[a][c]:this.options[a];if(g.isFunction(h)){var i=this;if(d===void 0)h(i,b,c);else if(f===void 0)this.get(d).each(function(){h(i,this,d,b,c)});else for(var a=function(a){i.get(a).each(function(){h(i,this,a,b,c)})},k=d;k<=f;k++)k!== null&&!(k>=j&&k<=e)&&a(k)}}},create:function(a){return this.format("<li></li>",a)},format:function(a,c){for(var a=g(a),b=a.get(0).className.split(" "),d=0;d<b.length;d++)b[d].indexOf("jcarousel-")!=-1&&a.removeClass(b[d]);a.addClass(this.className("jcarousel-item")).addClass(this.className("jcarousel-item-"+c)).css({"float":this.options.rtl?"right":"left","list-style":"none"}).attr("jcarouselindex",c);return a},className:function(a){return a+" "+a+(!this.options.vertical?"-horizontal":"-vertical")}, dimension:function(a,c){var b=g(a);if(c==null)return!this.options.vertical?b.outerWidth(!0)||f.intval(this.options.itemFallbackDimension):b.outerHeight(!0)||f.intval(this.options.itemFallbackDimension);else{var d=!this.options.vertical?c-f.intval(b.css("marginLeft"))-f.intval(b.css("marginRight")):c-f.intval(b.css("marginTop"))-f.intval(b.css("marginBottom"));g(b).css(this.wh,d+"px");return this.dimension(b)}},clipping:function(){return!this.options.vertical?this.clip[0].offsetWidth-f.intval(this.clip.css("borderLeftWidth"))- f.intval(this.clip.css("borderRightWidth")):this.clip[0].offsetHeight-f.intval(this.clip.css("borderTopWidth"))-f.intval(this.clip.css("borderBottomWidth"))},index:function(a,c){if(c==null)c=this.options.size;return Math.round(((a-1)/c-Math.floor((a-1)/c))*c)+1}});f.extend({defaults:function(a){return g.extend(q,a||{})},intval:function(a){a=parseInt(a,10);return isNaN(a)?0:a},windowLoaded:function(){m=!0}});g.fn.jcarousel=function(a){if(typeof a=="string"){var c=g(this).data("jcarousel"),b=Array.prototype.slice.call(arguments, 1);return c[a].apply(c,b)}else return this.each(function(){var b=g(this).data("jcarousel");b?(a&&g.extend(b.options,a),b.reload()):g(this).data("jcarousel",new f(this,a))})}})(jQuery);\n
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>15650</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>jquery.jcarousel.min.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2012-04-18 Ivan
* Initial commit
\ No newline at end of file
2012 (c) Nexedi SA
\ No newline at end of file
erp5_jquery
\ No newline at end of file
This Business Template contains only static files of jCarousel jQuery library.
\ No newline at end of file
GPL
\ No newline at end of file
portal_skins/erp5_jquery/jquery/plugin/jcarousel
portal_skins/erp5_jquery/jquery/plugin/jcarousel/**
\ No newline at end of file
erp5_jquery_plugin_jcarousel
\ No newline at end of file
5.4.7
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34648236.68</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>grid.locale-fr.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
;(function($){\r\n
/**\r\n
* jqGrid French Translation\r\n
* Tony Tomov tony@trirand.com\r\n
* http://trirand.com/blog/ \r\n
* Dual licensed under the MIT and GPL licenses:\r\n
* http://www.opensource.org/licenses/mit-license.php\r\n
* http://www.gnu.org/licenses/gpl.html\r\n
**/\r\n
$.jgrid = $.jgrid || {};\r\n
$.extend($.jgrid,{\r\n
\tdefaults : {\r\n
\t\trecordtext: "Enregistrements {0} - {1} sur {2}",\r\n
\t\temptyrecords: "Aucun enregistrement à afficher",\r\n
\t\tloadtext: "Chargement...",\r\n
\t\tpgtext : "Page {0} sur {1}"\r\n
\t},\r\n
\tsearch : {\r\n
\t\tcaption: "Recherche...",\r\n
\t\tFind: "Chercher",\r\n
\t\tReset: "Annuler",\r\n
\t\todata : [\'égal\', \'différent\', \'inférieur\', \'inférieur ou égal\',\'supérieur\',\'supérieur ou égal\', \'commence par\',\'ne commence pas par\',\'est dans\',"n\'est pas dans",\'finit par\',\'ne finit pas par\',\'contient\',\'ne contient pas\'],\r\n
\t\tgroupOps: [\t{ op: "AND", text: "tous" },\t{ op: "OR", text: "aucun" }\t],\r\n
\t\tmatchText: " correspondance",\r\n
\t\trulesText: " règles"\r\n
\t},\r\n
\tedit : {\r\n
\t\taddCaption: "Ajouter",\r\n
\t\teditCaption: "Editer",\r\n
\t\tbSubmit: "Valider",\r\n
\t\tbCancel: "Annuler",\r\n
\t\tbClose: "Fermer",\r\n
\t\tsaveData: "Les données ont changé ! Enregistrer les modifications ?",\r\n
\t\tbYes: "Oui",\r\n
\t\tbNo: "Non",\r\n
\t\tbExit: "Annuler",\r\n
\t\tmsg: {\r\n
\t\t\trequired: "Champ obligatoire",\r\n
\t\t\tnumber: "Saisissez un nombre correct",\r\n
\t\t\tminValue: "La valeur doit être supérieure ou égale à",\r\n
\t\t\tmaxValue: "La valeur doit être inférieure ou égale à",\r\n
\t\t\temail: "n\'est pas un email correct",\r\n
\t\t\tinteger: "Saisissez un entier correct",\r\n
\t\t\turl: "n\'est pas une adresse correcte. Préfixe requis (\'http://\' or \'https://\')",\r\n
\t\t\tnodefined : " n\'est pas défini!",\r\n
\t\t\tnovalue : " la valeur de retour est requise!",\r\n
\t\t\tcustomarray : "Une fonction personnalisée devrait retourner un tableau (array)!",\r\n
\t\t\tcustomfcheck : "Une fonction personnalisée devrait être présente dans le cas d\'une vérification personnalisée!"\r\n
\t\t}\r\n
\t},\r\n
\tview : {\r\n
\t\tcaption: "Voir les enregistrement",\r\n
\t\tbClose: "Fermer"\r\n
\t},\r\n
\tdel : {\r\n
\t\tcaption: "Supprimer",\r\n
\t\tmsg: "Supprimer les enregistrements sélectionnés ?",\r\n
\t\tbSubmit: "Supprimer",\r\n
\t\tbCancel: "Annuler"\r\n
\t},\r\n
\tnav : {\r\n
\t\tedittext: " ",\r\n
\t\tedittitle: "Editer la ligne sélectionnée",\r\n
\t\taddtext:" ",\r\n
\t\taddtitle: "Ajouter une ligne",\r\n
\t\tdeltext: " ",\r\n
\t\tdeltitle: "Supprimer la ligne sélectionnée",\r\n
\t\tsearchtext: " ",\r\n
\t\tsearchtitle: "Chercher un enregistrement",\r\n
\t\trefreshtext: "",\r\n
\t\trefreshtitle: "Recharger le tableau",\r\n
\t\talertcap: "Avertissement",\r\n
\t\talerttext: "Veuillez sélectionner une ligne",\r\n
\t\tviewtext: "",\r\n
\t\tviewtitle: "Afficher la ligne sélectionnée"\r\n
\t},\r\n
\tcol : {\r\n
\t\tcaption: "Afficher/Masquer les colonnes",\r\n
\t\tbSubmit: "Valider",\r\n
\t\tbCancel: "Annuler"\r\n
\t},\r\n
\terrors : {\r\n
\t\terrcap : "Erreur",\r\n
\t\tnourl : "Aucune adresse n\'est paramétrée",\r\n
\t\tnorecords: "Aucun enregistrement à traiter",\r\n
\t\tmodel : "Nombre de titres (colNames) <> Nombre de données (colModel)!"\r\n
\t},\r\n
\tformatter : {\r\n
\t\tinteger : {thousandsSeparator: " ", defaultValue: \'0\'},\r\n
\t\tnumber : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: \'0,00\'},\r\n
\t\tcurrency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: \'0,00\'},\r\n
\t\tdate : {\r\n
\t\t\tdayNames: [\r\n
\t\t\t\t"Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam",\r\n
\t\t\t\t"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"\r\n
\t\t\t],\r\n
\t\t\tmonthNames: [\r\n
\t\t\t\t"Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc",\r\n
\t\t\t\t"Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"\r\n
\t\t\t],\r\n
\t\t\tAmPm : ["am","pm","AM","PM"],\r\n
\t\t\tS: function (j) {return j == 1 ? \'er\' : \'e\';},\r\n
\t\t\tsrcformat: \'Y-m-d\',\r\n
\t\t\tnewformat: \'d/m/Y\',\r\n
\t\t\tmasks : {\r\n
\t\t\t\tISO8601Long:"Y-m-d H:i:s",\r\n
\t\t\t\tISO8601Short:"Y-m-d",\r\n
\t\t\t\tShortDate: "n/j/Y",\r\n
\t\t\t\tLongDate: "l, F d, Y",\r\n
\t\t\t\tFullDateTime: "l, F d, Y g:i:s A",\r\n
\t\t\t\tMonthDay: "F d",\r\n
\t\t\t\tShortTime: "g:i A",\r\n
\t\t\t\tLongTime: "g:i:s A",\r\n
\t\t\t\tSortableDateTime: "Y-m-d\\\\TH:i:s",\r\n
\t\t\t\tUniversalSortableDateTime: "Y-m-d H:i:sO",\r\n
\t\t\t\tYearMonth: "F, Y"\r\n
\t\t\t},\r\n
\t\t\treformatAfterEdit : false\r\n
\t\t},\r\n
\t\tbaseLinkUrl: \'\',\r\n
\t\tshowAction: \'\',\r\n
\t\ttarget: \'\',\r\n
\t\tcheckbox : {disabled:true},\r\n
\t\tidName : \'id\'\r\n
\t}\r\n
});\r\n
})(jQuery);\r\n
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>4273</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>grid.locale-fr.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
1 2
\ No newline at end of file \ No newline at end of file
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34058349.94</string> </value> <value> <string>ts34651695.58</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -75,6 +75,16 @@ var LocalStorageCachePlugin = {\n ...@@ -75,6 +75,16 @@ var LocalStorageCachePlugin = {\n
}\n }\n
\n \n
var Cache = {\n var Cache = {\n
\n
ROOT_CACHE_ID: \'APP_CACHE\',\n
\n
getCacheId: function(cache_id) {\n
/* We should have a way to \'purge\' localStorage by setting a ROOT_CACHE_ID in all browser\n
* instances\n
*/\n
return Cache.ROOT_CACHE_ID + cache_id; \n
\n
},\n
\n \n
hasLocalStorage: function() {\n hasLocalStorage: function() {\n
/*\n /*\n
...@@ -91,6 +101,7 @@ var Cache = {\n ...@@ -91,6 +101,7 @@ var Cache = {\n
\n \n
get: function(cache_id, default_value){\n get: function(cache_id, default_value){\n
/* Get cache key value */\n /* Get cache key value */\n
cache_id = Cache.getCacheId(cache_id);\n
if (Cache.hasLocalStorage()){\n if (Cache.hasLocalStorage()){\n
return LocalStorageCachePlugin.get(cache_id, default_value);}\n return LocalStorageCachePlugin.get(cache_id, default_value);}\n
else{\n else{\n
...@@ -99,6 +110,7 @@ var Cache = {\n ...@@ -99,6 +110,7 @@ var Cache = {\n
\n \n
set: function(cache_id, data){\n set: function(cache_id, data){\n
/* Set cache key value */\n /* Set cache key value */\n
cache_id = Cache.getCacheId(cache_id);\n
if (Cache.hasLocalStorage()){\n if (Cache.hasLocalStorage()){\n
LocalStorageCachePlugin.set(cache_id, data);}\n LocalStorageCachePlugin.set(cache_id, data);}\n
else{\n else{\n
...@@ -300,8 +312,9 @@ var Form = {\n ...@@ -300,8 +312,9 @@ var Form = {\n
column_title_list.push(title);\n column_title_list.push(title);\n
column = {\'name\': index,\n column = {\'name\': index,\n
\'index\': index,\n \'index\': index,\n
\'width\': 150,\n \'width\': 185,\n
\'align\': \'left\'}\n \'align\': \'left\'\n
}\n
colModel.push(column);\n colModel.push(column);\n
});\n });\n
\n \n
...@@ -314,6 +327,11 @@ var Form = {\n ...@@ -314,6 +327,11 @@ var Form = {\n
sortname: \'id\',\n sortname: \'id\',\n
viewrecords: true,\n viewrecords: true,\n
sortorder: "desc",\n sortorder: "desc",\n
loadError : function(xhr, textStatus, errorThrown) {\n
// XXX: handle better than just alert.\n
alert("Error occurred during getting data from server.");\n
},\n
cmTemplate: {sortable:false}, // XXX: until we get list of sortable columns from server\n
caption: field_dict["title"] });\n caption: field_dict["title"] });\n
listbox_table.jqGrid(\'navGrid\', \'#\'+navigation_id, {edit:false,add:false,del:false});\n listbox_table.jqGrid(\'navGrid\', \'#\'+navigation_id, {edit:false,add:false,del:false});\n
return listbox_table;\n return listbox_table;\n
...@@ -535,7 +553,7 @@ var RenderJs = {\n ...@@ -535,7 +553,7 @@ var RenderJs = {\n
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>18537</int> </value> <value> <int>19314</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
2 5
\ No newline at end of file \ No newline at end of file
...@@ -58,17 +58,20 @@ ...@@ -58,17 +58,20 @@
breadcrumb_list python: current_web_section.getBreadcrumbItemList(current_web_document);">\n breadcrumb_list python: current_web_section.getBreadcrumbItemList(current_web_document);">\n
<ul class="breadcrumb">\n <ul class="breadcrumb">\n
<li tal:repeat="breadcrumb python:breadcrumb_list[:(is_web_section_default_document and -1 or None)]">\n <li tal:repeat="breadcrumb python:breadcrumb_list[:(is_web_section_default_document and -1 or None)]">\n
<a href="#" tal:attributes="href python:current_web_section.getPermanentURL(breadcrumb[1]);\n <tal:block tal:define="is_last repeat/breadcrumb/end">\n
title python:breadcrumb[2];"\n <a href="#"\n
tal:content="python:breadcrumb[0]">Title</a>\n tal:attributes="href python:current_web_section.getPermanentURL(breadcrumb[1]);\n
<tal:block tal:condition="not: repeat/breadcrumb/end">\n title python:breadcrumb[2];\n
<img class="breadcrumb_separator" src="../km_img/crumb.png" alt="&gt;"\n class python: test(is_last, \'last-breadcrumb\', \'breadcrumb\')"\n
tal:attributes="src string:${portal_path}/km_img/crumb.png"/>\n tal:content="python:breadcrumb[0]">Title</a>\n
<img tal:condition="not: is_last"\n
class="breadcrumb_separator"\n
src="../km_img/crumb.png" alt="&gt;"\n
tal:attributes="src string:${portal_path}/km_img/crumb.png"/>\n
</tal:block>\n </tal:block>\n
</li>\n </li>\n
</ul>\n </ul>\n
</tal:block>\n </tal:block>
]]></unicode> </value> ]]></unicode> </value>
</item> </item>
...@@ -86,7 +89,7 @@ ...@@ -86,7 +89,7 @@
</item> </item>
<item> <item>
<key> <string>output_encoding</string> </key> <key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value> <value> <string>iso-8859-15</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -122,6 +122,7 @@ ...@@ -122,6 +122,7 @@
<list> <list>
<string>left_menu_widget</string> <string>left_menu_widget</string>
<string>listbox_action_widget</string> <string>listbox_action_widget</string>
<string>analytics_widget</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="EditorField" module="Products.ERP5Form.EditorField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string>hidden_label footer</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>text_editor</string> </key>
<value> <string>text_area</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Analytics</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>here/WebSite_viewAnalyticsWidget</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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> <unicode encoding="cdata"><![CDATA[
<!--Place analytic code or any other tracking scripts which will not be displayed-->
]]></unicode> </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>WebSite_viewAnalyticsWidget</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
<tal:block tal:repeat="menu_item menu_item_list">\n <tal:block tal:repeat="menu_item menu_item_list">\n
\n \n
<li tal:define="sub_item_list menu_item/subsection"\n <li tal:define="sub_item_list menu_item/subsection"\n
tal:attributes="class python:(sub_item_list and \'collapse-menu \' or \'\') + \'menu_item_%s\' % repeat[\'menu_item\'].index">\n tal:attributes="class python:\'menu_item_%s collapse-menu\' % repeat[\'menu_item\'].index + \' \' + (sub_item_list and \'collapse-able\' or \'\')">\n
<a tal:attributes="href menu_item/url" >\n <a tal:attributes="href menu_item/url" >\n
<tal:block tal:replace="menu_item/compact_translated_title | menu_item/translated_title">Menu</tal:block>\n <tal:block tal:replace="menu_item/compact_translated_title | menu_item/translated_title">Menu</tal:block>\n
</a>\n </a>\n
......
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
<value> <value>
<list> <list>
<string>footer_widget</string> <string>footer_widget</string>
<string>analytics_widget</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>WebSection_viewMinimalKMWidgetFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
<value> <value>
<list> <list>
<string>footer_widget</string> <string>footer_widget</string>
<string>analytics_widget</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>WebSection_viewMinimalKMWidgetFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
<value> <value>
<list> <list>
<string>footer_widget</string> <string>footer_widget</string>
<string>analytics_widget</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>analytics_widget</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>WebSection_viewMinimalKMWidgetFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -70,7 +70,8 @@ It is possible to specify a group id and a group title by naming a group followi ...@@ -70,7 +70,8 @@ It is possible to specify a group id and a group title by naming a group followi
<tal:block tal:condition="preferred_html_style_developper_mode">\n <tal:block tal:condition="preferred_html_style_developper_mode">\n
<tal:block metal:use-macro="developper_shortcut_render/macros/form" />\n <tal:block metal:use-macro="developper_shortcut_render/macros/form" />\n
</tal:block>\n </tal:block>\n
\n <div class="form"\n
tal:attributes="id form/getId">\n
<tal:block tal:repeat="group group_list">\n <tal:block tal:repeat="group group_list">\n
<tal:block tal:define="gid group/gid;">\n <tal:block tal:define="gid group/gid;">\n
<fieldset tal:condition="python: gid.find(\'hidden\') &lt; 0"\n <fieldset tal:condition="python: gid.find(\'hidden\') &lt; 0"\n
...@@ -86,11 +87,11 @@ It is possible to specify a group id and a group title by naming a group followi ...@@ -86,11 +87,11 @@ It is possible to specify a group id and a group title by naming a group followi
</fieldset>\n </fieldset>\n
</tal:block>\n </tal:block>\n
</tal:block>\n </tal:block>\n
</div>\n
<p class="clear"></p>\n <p class="clear"></p>\n
</tal:block>\n </tal:block>\n
</tal:block>\n </tal:block>\n
</tal:block>\n </tal:block>
]]></unicode> </value> ]]></unicode> </value>
</item> </item>
...@@ -108,7 +109,7 @@ It is possible to specify a group id and a group title by naming a group followi ...@@ -108,7 +109,7 @@ It is possible to specify a group id and a group title by naming a group followi
</item> </item>
<item> <item>
<key> <string>output_encoding</string> </key> <key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value> <value> <string>iso-8859-15</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -84,7 +84,6 @@ div {\n ...@@ -84,7 +84,6 @@ div {\n
margin:0;\n margin:0;\n
padding:0;\n padding:0;\n
float:none;\n float:none;\n
width:100%;\n
position:relative;\n position:relative;\n
}\n }\n
\n \n
...@@ -171,7 +170,11 @@ fieldset.hidden_fieldset { \n ...@@ -171,7 +170,11 @@ fieldset.hidden_fieldset { \n
padding-bottom:35px;\n padding-bottom:35px;\n
padding-top: 5px;\n padding-top: 5px;\n
}\n }\n
\n #master,\n
.document,\n
.content{\n
width:100%;\n
}\n
#wrapper_right{\n #wrapper_right{\n
float: left;\n float: left;\n
width:22.5%;\n width:22.5%;\n
...@@ -227,7 +230,7 @@ div#wrapper_headline div.header_title {\n ...@@ -227,7 +230,7 @@ div#wrapper_headline div.header_title {\n
}\n }\n
\n \n
#wrapper_path {\n #wrapper_path {\n
float:left;\n /* float:left; */\n
width: 100%;\n width: 100%;\n
}\n }\n
\n \n
...@@ -249,11 +252,14 @@ div#wrapper_headline div.header_title {\n ...@@ -249,11 +252,14 @@ div#wrapper_headline div.header_title {\n
height:100%;\n height:100%;\n
}\n }\n
\n \n
#menu ul li.collapse-menu{\n #menu ul li.collapse-able{\n
background: url(km_img/collapse-down-arrow.gif) no-repeat transparent right 10px;\n background: url(km_img/collapse-down-arrow.gif) no-repeat transparent right 10px;\n
padding-right: 0px;\n padding-right: 0px;\n
}\n }\n
\n \n
\n
\n
\n
#menu ul li.non-collapse-menu{\n #menu ul li.non-collapse-menu{\n
background: none;\n background: none;\n
padding-right: 0px;\n padding-right: 0px;\n
...@@ -567,10 +573,12 @@ fieldset.right{\n ...@@ -567,10 +573,12 @@ fieldset.right{\n
*/\n */\n
\n \n
fieldset.registration {\n fieldset.registration {\n
width:36%;\n width:auto;\n
background-color: #FFFFFF;\n background-color: #FFFFFF;\n
margin-right: 0.5%;\n margin-right: 0.5%;\n
height: auto;\n height: auto;\n
margin-bottom:2em;\n
padding:10px;\n
}\n }\n
\n \n
\n \n
...@@ -934,7 +942,7 @@ fieldset.right h4 {\n ...@@ -934,7 +942,7 @@ fieldset.right h4 {\n
padding:5px;\n padding:5px;\n
}\n }\n
\n \n
.document > .content ul li {\n .content ul li {\n
background:transparent url(km_img/bg_bullet_square.gif) no-repeat scroll 0 0.5em;\n background:transparent url(km_img/bg_bullet_square.gif) no-repeat scroll 0 0.5em;\n
margin:0 0 0.3em 2px;\n margin:0 0 0.3em 2px;\n
padding:0 0 0 12px;\n padding:0 0 0 12px;\n
...@@ -1075,7 +1083,7 @@ table tbody tr td {\n ...@@ -1075,7 +1083,7 @@ table tbody tr td {\n
top:0;\n top:0;\n
padding-top:30px;\n padding-top:30px;\n
left:0;\n left:0;\n
width:205px;\n width:auto;\n
opacity: <tal:block tal:replace="menu_opacity">0.80</tal:block>;\n opacity: <tal:block tal:replace="menu_opacity">0.80</tal:block>;\n
}\n }\n
\n \n
......
1854 1860
\ No newline at end of file \ No newline at end of file
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>text</string> </key> <key> <string>text</string> </key>
<value> <string>python: context.getTextContent() is None or not context.getTextContent()</string> </value> <value> <string>python: context.getTextContent() is None or not context.getTextContent() or context.getValidationState() in context.getPortalObject().getPortalDraftOrderStateList()</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
<value> <value>
<list> <list>
<string>description</string> <string>description</string>
<string>enabled</string>
<string>title</string> <string>title</string>
<string>whitespace_preserve</string> <string>whitespace_preserve</string>
</list> </list>
...@@ -56,10 +55,8 @@ ...@@ -56,10 +55,8 @@
<value> <value>
<dictionary> <dictionary>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>description</string> </key>
<value> <value> <string></string> </value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
...@@ -96,10 +93,6 @@ ...@@ -96,10 +93,6 @@
<key> <string>description</string> </key> <key> <string>description</string> </key>
<value> <string>Name of the Web Page you would like to review.</string> </value> <value> <string>Name of the Web Page you would like to review.</string> </value>
</item> </item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value> <value> <string>my_string_field</string> </value>
...@@ -130,17 +123,4 @@ ...@@ -130,17 +123,4 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>not:here/isExternalDocument</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
<string>delivery_builder/portal_deliveries/internal_packing_list_builder</string> <string>delivery_builder/portal_deliveries/internal_packing_list_builder</string>
<string>delivery_builder/portal_deliveries/purchase_packing_list_builder</string> <string>delivery_builder/portal_deliveries/purchase_packing_list_builder</string>
<string>delivery_builder/portal_deliveries/sale_packing_list_builder</string> <string>delivery_builder/portal_deliveries/sale_packing_list_builder</string>
<string>delivery_builder/portal_deliveries/task_report_builder</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
34 35
\ No newline at end of file \ No newline at end of file
<module> <module>
<id>foo_module</id> <id>foo_module</id>
<permission_list> <permission_list>
<permission type='tuple'>
<name>Access Transient Objects</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Access contents information</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Access session data</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Add portal content</name>
<role>Assignor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Add portal folders</name>
<role>Assignor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Change local roles</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Copy or Move</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Delete objects</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>List folder contents</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Modify portal content</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'> <permission type='tuple'>
<name>View</name> <name>View</name>
<role>Assignee</role> <role>Assignee</role>
...@@ -9,6 +81,15 @@ ...@@ -9,6 +81,15 @@
<role>Auditor</role> <role>Auditor</role>
<role>Manager</role> <role>Manager</role>
</permission> </permission>
<permission type='tuple'>
<name>View History</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
</permission_list> </permission_list>
<portal_type>Foo Module</portal_type> <portal_type>Foo Module</portal_type>
<title>Foos</title> <title>Foos</title>
......
683 683
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2011 Nexedi SA and Contributors. All Rights Reserved.
#
# 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 advised 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 3
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import re
import subprocess
import threading
import signal
import sys
class SubprocessError(EnvironmentError):
def __init__(self, status_dict):
self.status_dict = status_dict
def __getattr__(self, name):
return self.status_dict[name]
def __str__(self):
return 'Error %i' % self.status_code
class CancellationError(EnvironmentError):
pass
_format_command_search = re.compile("[[\\s $({?*\\`#~';<>&|]").search
_format_command_escape = lambda s: "'%s'" % r"'\''".join(s.split("'"))
def format_command(*args, **kw):
cmdline = []
for k, v in sorted(kw.items()):
if _format_command_search(v):
v = _format_command_escape(v)
cmdline.append('%s=%s' % (k, v))
for v in args:
if _format_command_search(v):
v = _format_command_escape(v)
cmdline.append(v)
return ' '.join(cmdline)
def subprocess_capture(p, log, log_prefix, get_output=True):
def readerthread(input, output, buffer):
while True:
data = input.readline()
if not data:
break
if get_output:
buffer.append(data)
if log_prefix:
data = "%s : " % log_prefix + data
data = data.rstrip('\n')
output(data)
if p.stdout:
stdout = []
stdout_thread = threading.Thread(target=readerthread,
args=(p.stdout, log, stdout))
stdout_thread.daemon = True
stdout_thread.start()
if p.stderr:
stderr = []
stderr_thread = threading.Thread(target=readerthread,
args=(p.stderr, log, stderr))
stderr_thread.daemon = True
stderr_thread.start()
p.wait()
if p.stdout:
stdout_thread.join()
if p.stderr:
stderr_thread.join()
return (p.stdout and ''.join(stdout),
p.stderr and ''.join(stderr))
class ProcessManager(object):
stdin = file(os.devnull)
def __init__(self, log, *args, **kw):
self.log = log
self.process_pid_set = set()
signal.signal(signal.SIGTERM, self.sigterm_handler)
self.under_cancellation = False
def spawn(self, *args, **kw):
if self.under_cancellation:
raise CancellationError("Test Result was cancelled")
get_output = kw.pop('get_output', True)
log_prefix = kw.pop('log_prefix', '')
new_session = kw.pop('new_session', True)
subprocess_kw = {}
cwd = kw.pop('cwd', None)
if cwd:
subprocess_kw['cwd'] = cwd
if new_session:
subprocess_kw['preexec_fn'] = os.setsid
raise_error_if_fail = kw.pop('raise_error_if_fail', True)
env = kw and dict(os.environ, **kw) or None
command = format_command(*args, **kw)
self.log('subprocess_kw : %r' % (subprocess_kw,))
self.log('$ ' + command)
sys.stdout.flush()
p = subprocess.Popen(args, stdin=self.stdin, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=env, **subprocess_kw)
self.process_pid_set.add(p.pid)
stdout, stderr = subprocess_capture(p, self.log, log_prefix,
get_output=get_output)
result = dict(status_code=p.returncode, command=command,
stdout=stdout, stderr=stderr)
self.process_pid_set.discard(p.pid)
if self.under_cancellation:
raise CancellationError("Test Result was cancelled")
if raise_error_if_fail and p.returncode:
raise SubprocessError(result)
return result
def killPreviousRun(self, cancellation=False):
self.log('ProcessManager killPreviousRun, going to kill %r' % (self.process_pid_set,))
if cancellation:
self.under_cancellation = True
for pgpid in self.process_pid_set:
try:
os.kill(pgpid, signal.SIGTERM)
except:
pass
try:
if os.path.exists(self.supervisord_pid_file):
supervisor_pid = int(open(self.supervisord_pid_file).read().strip())
self.log('ProcessManager killPreviousRun, going to kill supervisor with pid %r' % supervisor_pid)
os.kill(supervisor_pid, signal.SIGTERM)
except:
self.log('ProcessManager killPreviousRun, exception when killing supervisor')
pass
self.process_pid_set.clear()
def sigterm_handler(self, signal, frame):
self.log('SIGTERM_HANDLER')
sys.exit(1)
...@@ -36,10 +36,12 @@ MAX_SR_RETRIES = 3 ...@@ -36,10 +36,12 @@ MAX_SR_RETRIES = 3
class SlapOSControler(object): class SlapOSControler(object):
def __init__(self, config, log, process_group_pid_set=None, def __init__(self, config, log,
slapproxy_log=None): slapproxy_log=None, process_manager=None, reset_software=False):
log('SlapOSControler, initialize, reset_software: %r' % reset_software)
self.log = log self.log = log
self.config = config self.config = config
self.process_manager = process_manager
# By erasing everything, we make sure that we are able to "update" # By erasing everything, we make sure that we are able to "update"
# existing profiles. This is quite dirty way to do updates... # existing profiles. This is quite dirty way to do updates...
if os.path.exists(config['proxy_database']): if os.path.exists(config['proxy_database']):
...@@ -51,7 +53,7 @@ class SlapOSControler(object): ...@@ -51,7 +53,7 @@ class SlapOSControler(object):
kwargs['stderr'] = slapproxy_log_fp kwargs['stderr'] = slapproxy_log_fp
proxy = subprocess.Popen([config['slapproxy_binary'], proxy = subprocess.Popen([config['slapproxy_binary'],
config['slapos_config']], **kwargs) config['slapos_config']], **kwargs)
process_group_pid_set.add(proxy.pid) process_manager.process_pid_set.add(proxy.pid)
# XXX: dirty, giving some time for proxy to being able to accept # XXX: dirty, giving some time for proxy to being able to accept
# connections # connections
time.sleep(10) time.sleep(10)
...@@ -63,21 +65,33 @@ class SlapOSControler(object): ...@@ -63,21 +65,33 @@ class SlapOSControler(object):
self.software_profile, self.software_profile,
computer_guid=config['computer_id']) computer_guid=config['computer_id'])
computer = slap.registerComputer(config['computer_id']) computer = slap.registerComputer(config['computer_id'])
# Reset all previously generated software if needed
if reset_software:
software_root = config['software_root']
log('SlapOSControler : GOING TO RESET ALL SOFTWARE')
if os.path.exists(software_root):
shutil.rmtree(software_root)
os.mkdir(software_root)
os.chmod(software_root, 0750)
instance_root = config['instance_root']
if os.path.exists(instance_root):
# delete old paritions which may exists in order to not get its data
# (ex. MySQL db content) from previous testnode's runs
# In order to be able to change partition naming scheme, do this at
# instance_root level (such change happened already, causing problems).
shutil.rmtree(instance_root)
os.mkdir(instance_root)
for i in range(0, MAX_PARTIONS): for i in range(0, MAX_PARTIONS):
# create partition and configure computer # create partition and configure computer
# XXX: at the moment all partitions do share same virtual interface address # XXX: at the moment all partitions do share same virtual interface address
# this is not a problem as usually all services are on different ports # this is not a problem as usually all services are on different ports
partition_reference = '%s-%s' %(config['partition_reference'], i) partition_reference = '%s-%s' %(config['partition_reference'], i)
partition_path = os.path.join(config['instance_root'], partition_reference) partition_path = os.path.join(instance_root, partition_reference)
if os.path.exists(partition_path):
# delete old paritions which may exists in order to not get its data (ex. MySQL db content)
# from previous testnode's runs
shutil.rmtree(partition_path)
os.mkdir(partition_path) os.mkdir(partition_path)
os.chmod(partition_path, 0750) os.chmod(partition_path, 0750)
computer.updateConfiguration(xml_marshaller.xml_marshaller.dumps({ computer.updateConfiguration(xml_marshaller.xml_marshaller.dumps({
'address': config['ipv4_address'], 'address': config['ipv4_address'],
'instance_root': config['instance_root'], 'instance_root': instance_root,
'netmask': '255.255.255.255', 'netmask': '255.255.255.255',
'partition_list': [{'address_list': [{'addr': config['ipv4_address'], 'partition_list': [{'address_list': [{'addr': config['ipv4_address'],
'netmask': '255.255.255.255'}, 'netmask': '255.255.255.255'},
...@@ -91,37 +105,23 @@ class SlapOSControler(object): ...@@ -91,37 +105,23 @@ class SlapOSControler(object):
'reference': config['computer_id'], 'reference': config['computer_id'],
'software_root': config['software_root']})) 'software_root': config['software_root']}))
def runSoftwareRelease(self, config, environment, process_group_pid_set=None, def spawn(self, *args, **kw):
stdout=None, stderr=None): return self.process_manager.spawn(*args, **kw)
def runSoftwareRelease(self, config, environment):
self.log("SlapOSControler.runSoftwareRelease") self.log("SlapOSControler.runSoftwareRelease")
cpu_count = os.sysconf("SC_NPROCESSORS_ONLN") cpu_count = os.sysconf("SC_NPROCESSORS_ONLN")
os.putenv('MAKEFLAGS', '-j%s' % cpu_count) os.putenv('MAKEFLAGS', '-j%s' % cpu_count)
os.environ['PATH'] = environment['PATH'] os.environ['PATH'] = environment['PATH']
command = [config['slapgrid_software_binary'], '-v', '-c',
#'--buildout-parameter',"'-U -N' -o",
config['slapos_config']]
# a SR may fail for number of reasons (incl. network failures) # a SR may fail for number of reasons (incl. network failures)
# so be tolerant and run it a few times before giving up # so be tolerant and run it a few times before giving up
for runs in range(0, MAX_SR_RETRIES): for runs in range(0, MAX_SR_RETRIES):
slapgrid = subprocess.Popen(command, status_dict = self.spawn(config['slapgrid_software_binary'], '-v', '-c',
stdout=stdout, stderr=stderr, config['slapos_config'], raise_error_if_fail=False,
close_fds=True, preexec_fn=os.setsid) log_prefix='slapgrid_sr', get_output=False)
process_group_pid_set.add(slapgrid.pid)
slapgrid.wait()
stdout.seek(0)
stderr.seek(0)
process_group_pid_set.remove(slapgrid.pid)
status_dict = {'status_code':slapgrid.returncode,
'command': repr(command),
'stdout':stdout.read(),
'stderr':stderr.read()}
stdout.close()
stderr.close()
return status_dict return status_dict
def runComputerPartition(self, config, environment, def runComputerPartition(self, config, environment,
process_group_pid_set=None,
stdout=None, stderr=None): stdout=None, stderr=None):
self.log("SlapOSControler.runComputerPartition") self.log("SlapOSControler.runComputerPartition")
slap = slapos.slap.slap() slap = slapos.slap.slap()
...@@ -130,26 +130,12 @@ class SlapOSControler(object): ...@@ -130,26 +130,12 @@ class SlapOSControler(object):
slap.registerOpenOrder().request(self.software_profile, slap.registerOpenOrder().request(self.software_profile,
partition_reference='testing partition', partition_reference='testing partition',
partition_parameter_kw=config['instance_dict']) partition_parameter_kw=config['instance_dict'])
command = [config['slapgrid_partition_binary'],
config['slapos_config'], '-c', '-v']
# try to run for all partitions as one partition may in theory request another one # try to run for all partitions as one partition may in theory request another one
# this not always is required but curently no way to know how "tree" of partitions # this not always is required but curently no way to know how "tree" of partitions
# may "expand" # may "expand"
for runs in range(0, MAX_PARTIONS): for runs in range(0, MAX_PARTIONS):
slapgrid = subprocess.Popen(command, status_dict = self.spawn(config['slapgrid_partition_binary'], '-v', '-c',
stdout=stdout, stderr=stderr, config['slapos_config'], raise_error_if_fail=False,
close_fds=True, preexec_fn=os.setsid) log_prefix='slapgrid_cp', get_output=False)
process_group_pid_set.add(slapgrid.pid)
slapgrid.wait()
process_group_pid_set.remove(slapgrid.pid)
stdout.seek(0)
stderr.seek(0)
status_dict = {'status_code':slapgrid.returncode,
'command': repr(command),
'stdout':stdout.read(),
'stderr':stderr.read()}
stdout.close()
stderr.close()
return status_dict return status_dict
...@@ -36,48 +36,6 @@ from testnode import SubprocessError ...@@ -36,48 +36,6 @@ from testnode import SubprocessError
SVN_UP_REV = re.compile(r'^(?:At|Updated to) revision (\d+).$') SVN_UP_REV = re.compile(r'^(?:At|Updated to) revision (\d+).$')
SVN_CHANGED_REV = re.compile(r'^Last Changed Rev.*:\s*(\d+)', re.MULTILINE) SVN_CHANGED_REV = re.compile(r'^Last Changed Rev.*:\s*(\d+)', re.MULTILINE)
_format_command_search = re.compile("[[\\s $({?*\\`#~';<>&|]").search
_format_command_escape = lambda s: "'%s'" % r"'\''".join(s.split("'"))
def format_command(*args, **kw):
cmdline = []
for k, v in sorted(kw.items()):
if _format_command_search(v):
v = _format_command_escape(v)
cmdline.append('%s=%s' % (k, v))
for v in args:
if _format_command_search(v):
v = _format_command_escape(v)
cmdline.append(v)
return ' '.join(cmdline)
def subprocess_capture(p, quiet=False):
def readerthread(input, output, buffer):
while True:
data = input.readline()
if not data:
break
output(data)
buffer.append(data)
if p.stdout:
stdout = []
output = quiet and (lambda data: None) or sys.stdout.write
stdout_thread = threading.Thread(target=readerthread,
args=(p.stdout, output, stdout))
stdout_thread.setDaemon(True)
stdout_thread.start()
if p.stderr:
stderr = []
stderr_thread = threading.Thread(target=readerthread,
args=(p.stderr, sys.stderr.write, stderr))
stderr_thread.setDaemon(True)
stderr_thread.start()
if p.stdout:
stdout_thread.join()
if p.stderr:
stderr_thread.join()
p.wait()
return (p.stdout and ''.join(stdout),
p.stderr and ''.join(stderr))
GIT_TYPE = 'git' GIT_TYPE = 'git'
SVN_TYPE = 'svn' SVN_TYPE = 'svn'
...@@ -88,13 +46,14 @@ class Updater(object): ...@@ -88,13 +46,14 @@ class Updater(object):
stdin = file(os.devnull) stdin = file(os.devnull)
def __init__(self, repository_path, log, revision=None, git_binary=None, def __init__(self, repository_path, log, revision=None, git_binary=None,
realtime_output=True): realtime_output=True, process_manager=None):
self.log = log self.log = log
self.revision = revision self.revision = revision
self._path_list = [] self._path_list = []
self.repository_path = repository_path self.repository_path = repository_path
self.git_binary = git_binary self.git_binary = git_binary
self.realtime_output = realtime_output self.realtime_output = realtime_output
self.process_manager = process_manager
def getRepositoryPath(self): def getRepositoryPath(self):
return self.repository_path return self.repository_path
...@@ -128,25 +87,10 @@ class Updater(object): ...@@ -128,25 +87,10 @@ class Updater(object):
raise raise
def spawn(self, *args, **kw): def spawn(self, *args, **kw):
quiet = kw.pop('quiet', False) return self.process_manager.spawn(*args,
env = kw and dict(os.environ, **kw) or None log_prefix='git',
command = format_command(*args, **kw) cwd=self.getRepositoryPath(),
self.log('$ ' + command) **kw)
sys.stdout.flush()
p = subprocess.Popen(args, stdin=self.stdin, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=env,
cwd=self.getRepositoryPath())
if self.realtime_output:
stdout, stderr = subprocess_capture(p, quiet)
else:
stdout, stderr = p.communicate()
self.log(stdout)
self.log(stderr)
result = dict(status_code=p.returncode, command=command,
stdout=stdout, stderr=stderr)
if p.returncode:
raise SubprocessError(result)
return result
def _git(self, *args, **kw): def _git(self, *args, **kw):
return self.spawn(self.git_binary, *args, **kw)['stdout'].strip() return self.spawn(self.git_binary, *args, **kw)['stdout'].strip()
......
...@@ -30,12 +30,12 @@ import logging ...@@ -30,12 +30,12 @@ import logging
import os import os
import pkg_resources import pkg_resources
import testnode from testnode import TestNode
CONFIG = dict( CONFIG = {
computer_id='COMPUTER', 'computer_id': 'COMPUTER',
partition_reference='test0', 'partition_reference': 'test0',
) }
def main(*args): def main(*args):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
...@@ -48,15 +48,21 @@ def main(*args): ...@@ -48,15 +48,21 @@ def main(*args):
parsed_argument = parser.parse_args(list(args)) parsed_argument = parser.parse_args(list(args))
else: else:
parsed_argument = parser.parse_args() parsed_argument = parser.parse_args()
logger_format = '%(asctime)s %(name)-13s: %(levelname)-8s %(message)s'
formatter = logging.Formatter(logger_format)
logging.basicConfig(level=logging.INFO,
format=logger_format)
logger = logging.getLogger('erp5testnode') logger = logging.getLogger('erp5testnode')
if parsed_argument.console or parsed_argument.logfile: if parsed_argument.console or parsed_argument.logfile:
logger.setLevel(logging.INFO)
if parsed_argument.console: if parsed_argument.console:
logger.addHandler(logging.StreamHandler()) logger.addHandler(logging.StreamHandler())
logger.info('Activated console output.') logger.info('Activated console output.')
if parsed_argument.logfile: if parsed_argument.logfile:
logger.addHandler(logging.FileHandler(filename=parsed_argument.logfile)) file_handler = logging.FileHandler(filename=parsed_argument.logfile)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.info('Activated logfile %r output' % parsed_argument.logfile) logger.info('Activated logfile %r output' % parsed_argument.logfile)
CONFIG['log_file'] = parsed_argument.logfile
else: else:
logger.addHandler(logging.NullHandler()) logger.addHandler(logging.NullHandler())
CONFIG['logger'] = logger.info CONFIG['logger'] = logger.info
...@@ -64,40 +70,33 @@ def main(*args): ...@@ -64,40 +70,33 @@ def main(*args):
# do not change case of option keys # do not change case of option keys
config.optionxform = str config.optionxform = str
config.readfp(parsed_argument.configuration_file[0]) config.readfp(parsed_argument.configuration_file[0])
def geto(o): for key in ('slapos_directory', 'working_directory', 'test_suite_directory',
return config.get('testnode', o) 'log_directory', 'run_directory', 'proxy_host', 'proxy_port',
CONFIG['slapos_directory'] = geto('slapos_directory') 'git_binary', 'zip_binary', 'test_suite_title', 'test_node_title',
CONFIG['working_directory'] = geto('working_directory') 'test_suite', 'project_title', 'node_quantity', 'ipv4_address',
CONFIG['test_suite_directory'] = geto('test_suite_directory') 'ipv6_address', 'test_suite_master_url', 'slapgrid_partition_binary',
CONFIG['log_directory'] = geto('log_directory') 'slapgrid_software_binary', 'slapproxy_binary'):
CONFIG['run_directory'] = geto('run_directory') CONFIG[key] = config.get('testnode', key)
for d in CONFIG['slapos_directory'], CONFIG['working_directory'], \ for key in ('slapos_directory', 'working_directory', 'test_suite_directory',
CONFIG['test_suite_directory'], CONFIG['log_directory'], \ 'log_directory', 'run_directory'):
CONFIG['run_directory']: d = CONFIG[key]
if not os.path.isdir(d): if not os.path.isdir(d):
raise ValueError('Directory %r does not exists.' % d) raise ValueError('Directory %r does not exists.' % d)
CONFIG['software_root'] = os.path.join(CONFIG['slapos_directory'], slapos_directory = CONFIG['slapos_directory']
'software') CONFIG['software_root'] = software_root = os.path.join(slapos_directory,
CONFIG['instance_root'] = os.path.join(CONFIG['slapos_directory'], 'software')
'instance') CONFIG['instance_root'] = instance_root = os.path.join(slapos_directory,
for d in CONFIG['software_root'], CONFIG['instance_root']: 'instance')
if not os.path.lexists(d): CONFIG['proxy_database'] = os.path.join(slapos_directory, 'proxy.db')
os.mkdir(d) CONFIG['slapos_config'] = slapos_config = os.path.join(slapos_directory,
CONFIG['proxy_database'] = os.path.join(CONFIG['slapos_directory'], 'slapos.cfg')
'proxy.db') if not os.path.lexists(software_root):
CONFIG['proxy_host'] = geto('proxy_host') os.mkdir(software_root)
CONFIG['proxy_port'] = geto('proxy_port')
CONFIG['master_url'] = 'http://%s:%s' % (CONFIG['proxy_host'], CONFIG['master_url'] = 'http://%s:%s' % (CONFIG['proxy_host'],
CONFIG['proxy_port']) CONFIG['proxy_port'])
slapos_config = pkg_resources.resource_string('erp5.util.testnode', open(slapos_config, 'w').write(pkg_resources.resource_string(
'template/slapos.cfg.in') 'erp5.util.testnode', 'template/slapos.cfg.in') % CONFIG)
slapos_config = slapos_config % CONFIG CONFIG['runTestSuite'] = os.path.join(instance_root,
CONFIG['slapos_config'] = os.path.join(CONFIG['slapos_directory'],
'slapos.cfg')
open(CONFIG['slapos_config'], 'w').write(slapos_config)
CONFIG['git_binary'] = geto('git_binary')
CONFIG['zip_binary'] = geto('zip_binary')
CONFIG['runTestSuite'] = os.path.join(CONFIG['instance_root'],
CONFIG['partition_reference'], 'bin', 'runTestSuite') CONFIG['partition_reference'], 'bin', 'runTestSuite')
# generate vcs_repository_list # generate vcs_repository_list
...@@ -113,24 +112,16 @@ def main(*args): ...@@ -113,24 +112,16 @@ def main(*args):
CONFIG['bt5_path'] = bt5_path CONFIG['bt5_path'] = bt5_path
CONFIG['vcs_repository_list'] = vcs_repository_list CONFIG['vcs_repository_list'] = vcs_repository_list
CONFIG['test_suite_title'] = geto('test_suite_title')
CONFIG['test_node_title'] = geto('test_node_title')
CONFIG['test_suite'] = geto('test_suite')
CONFIG['project_title'] = geto('project_title')
CONFIG['node_quantity'] = geto('node_quantity')
CONFIG['ipv4_address'] = geto('ipv4_address')
CONFIG['ipv6_address'] = geto('ipv6_address')
CONFIG['test_suite_master_url'] = geto('test_suite_master_url')
CONFIG['slapgrid_partition_binary'] = geto('slapgrid_partition_binary')
CONFIG['slapgrid_software_binary'] = geto('slapgrid_software_binary')
bot_environment = {}
if 'bot_environment' in config.sections(): if 'bot_environment' in config.sections():
bot_environment = dict(config.items('bot_environment')) bot_environment = dict(config.items('bot_environment'))
else:
bot_environment = {}
CONFIG['bot_environment'] = bot_environment CONFIG['bot_environment'] = bot_environment
CONFIG['environment'] = dict(config.items('environment')) CONFIG['environment'] = dict(config.items('environment'))
CONFIG['slapproxy_binary'] = geto('slapproxy_binary')
instance_dict = {}
if 'instance_dict' in config.sections(): if 'instance_dict' in config.sections():
instance_dict = dict(config.items('instance_dict')) instance_dict = dict(config.items('instance_dict'))
else:
instance_dict = {}
CONFIG['instance_dict'] = instance_dict CONFIG['instance_dict'] = instance_dict
testnode.run(CONFIG) testnode = TestNode(logger.info, CONFIG)
testnode.run()
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from datetime import datetime
import os import os
import pprint
import signal import signal
import socket import socket
import subprocess import subprocess
...@@ -34,121 +34,164 @@ import time ...@@ -34,121 +34,164 @@ import time
import xmlrpclib import xmlrpclib
import glob import glob
import SlapOSControler import SlapOSControler
import logging import threading
DEFAULT_SLEEP_TIMEOUT = 120 # time in seconds to sleep
class SubprocessError(EnvironmentError):
def __init__(self, status_dict):
self.status_dict = status_dict
def __getattr__(self, name):
return self.status_dict[name]
def __str__(self):
return 'Error %i' % self.status_code
from ProcessManager import SubprocessError, ProcessManager, CancellationError
from Updater import Updater from Updater import Updater
supervisord_pid_file = None DEFAULT_SLEEP_TIMEOUT = 120 # time in seconds to sleep
process_group_pid_set = set()
def sigterm_handler(signal, frame):
for pgpid in process_group_pid_set:
try:
os.killpg(pgpid, signal.SIGTERM)
except:
pass
sys.exit(1)
signal.signal(signal.SIGTERM, sigterm_handler) supervisord_pid_file = None
def safeRpcCall(proxy, function_id, *args): def safeRpcCall(log, proxy, function_id, retry, *args):
# XXX: this method will try infinitive calls to backend # this method will try infinitive calls to backend
# this can cause testnode to looked "stalled" # this can cause testnode to looked "stalled"
retry = 64 retry_time = 64
while True: while True:
try: try:
# it safer to pass proxy and function_id so we avoid httplib.ResponseNotReady # it safer to pass proxy and function_id so we avoid httplib.ResponseNotReady
# by trying reconnect before server keep-alive ends and the socket closes # by trying reconnect before server keep-alive ends and the socket closes
log('safeRpcCall called with method : %s' % function_id)
function = getattr(proxy, function_id) function = getattr(proxy, function_id)
return function(*args) return function(*args)
except (socket.error, xmlrpclib.ProtocolError, xmlrpclib.Fault), e: except (socket.error, xmlrpclib.ProtocolError, xmlrpclib.Fault), e:
logging.warning(e) log('Exception in safeRpcCall when trying %s with %r' % (function_id, args),
pprint.pprint(args, file(function._Method__name, 'w')) exc_info=sys.exc_info())
time.sleep(retry) if not(retry):
retry += retry >> 1 return
log('will retry safeRpcCall in %i seconds' % retry_time)
time.sleep(retry_time)
retry_time += retry_time >> 1
def getInputOutputFileList(config, command_name): class RemoteLogger(object):
stdout = open(os.path.join(
config['log_directory'],'%s_out' % command_name),
'w+')
stdout.write("%s\n" % command_name)
stderr = open(os.path.join(
config['log_directory'],'%s_err' % command_name),
'w+')
return (stdout, stderr)
slapos_controler = None def __init__(self, log, log_file, test_node_title, process_manager):
self.portal = None
self.test_result_path = None
self.test_node_title = test_node_title
self.log = log
self.log_file = log_file
self.process_manager = process_manager
self.finish = False
self.quit = False
def killPreviousRun(): def update(self, portal, test_result_path):
for pgpid in process_group_pid_set: self.portal = portal
try: self.test_result_path = test_result_path
os.killpg(pgpid, signal.SIGTERM)
except: def getSize(self):
pass erp5testnode_log = open(self.log_file, 'r')
try: erp5testnode_log.seek(0, 2)
if os.path.exists(supervisord_pid_file): size = erp5testnode_log.tell()
os.kill(int(open(supervisord_pid_file).read().strip()), signal.SIGTERM) erp5testnode_log.close()
except: return size
pass
def __call__(self):
size = self.getSize()
while True:
for x in xrange(0,60):
if self.quit or self.finish:
break
time.sleep(1)
if self.quit:
return
finish = retry = self.finish
if self.test_result_path is None:
if finish:
return
continue
start_size = size
end_size = self.getSize()
# file was truncated
if end_size < start_size:
size = end_size
continue
# display some previous data
if start_size >= 5000:
start_size -= 5000
# do not send tons of log, only last logs
if (end_size-start_size >= 10000):
start_size = end_size-10000
erp5testnode_log = open(self.log_file, 'r')
erp5testnode_log.seek(start_size)
output = erp5testnode_log.read()
erp5testnode_log.close()
if end_size == size:
output += '%s : stucked ??' % datetime.now().strftime("%Y/%m/%d %H:%M:%S")
# check if the test result is still alive
is_alive = safeRpcCall(self.log, self.portal, "isTaskAlive", False,
self.test_result_path)
self.log('isTaskAlive result %r' % is_alive)
if is_alive is not None and is_alive == 0:
self.log('Test Result cancelled on server side, stop current test')
self.process_manager.killPreviousRun(cancellation=True)
return
status_dict = dict(command='erp5testnode', status_code=0,
stdout=''.join(output), stderr='')
safeRpcCall(self.log, self.portal, "reportTaskStatus", retry,
self.test_result_path, status_dict, self.test_node_title)
size = end_size
if finish:
return
PROFILE_PATH_KEY = 'profile_path' PROFILE_PATH_KEY = 'profile_path'
def run(config):
log = config['logger']
slapgrid = None
global supervisord_pid_file
supervisord_pid_file = os.path.join(config['instance_root'], 'var', 'run',
'supervisord.pid')
previous_revision = None
run_software = True class TestNode(object):
# Write our own software.cfg to use the local repository
custom_profile_path = os.path.join(config['working_directory'], 'software.cfg') def __init__(self, log, config):
config['custom_profile_path'] = custom_profile_path self.log = log
vcs_repository_list = config['vcs_repository_list'] self.config = config
profile_content = '' self.process_manager = ProcessManager(log)
assert len(vcs_repository_list), "we must have at least one repository" self.process_manager.supervisord_pid_file = os.path.join(config['instance_root'], 'var', 'run',
try: 'supervisord.pid')
# BBB: Accept global profile_path, which is the same as setting it for the
# first configured repository. def run(self):
profile_path = config.pop(PROFILE_PATH_KEY) log = self.log
except KeyError: process_manager = self.process_manager
pass config = self.config
else: slapgrid = None
vcs_repository_list[0][PROFILE_PATH_KEY] = profile_path previous_revision = None
profile_path_count = 0
for vcs_repository in vcs_repository_list: run_software = True
url = vcs_repository['url'] # Write our own software.cfg to use the local repository
buildout_section_id = vcs_repository.get('buildout_section_id', None) custom_profile_path = os.path.join(config['working_directory'], 'software.cfg')
repository_id = buildout_section_id or \ config['custom_profile_path'] = custom_profile_path
url.split('/')[-1].split('.')[0] vcs_repository_list = config['vcs_repository_list']
repository_path = os.path.join(config['working_directory'],repository_id) profile_content = ''
vcs_repository['repository_id'] = repository_id assert len(vcs_repository_list), "we must have at least one repository"
vcs_repository['repository_path'] = repository_path
try: try:
profile_path = vcs_repository[PROFILE_PATH_KEY] # BBB: Accept global profile_path, which is the same as setting it for the
# first configured repository.
profile_path = config.pop(PROFILE_PATH_KEY)
except KeyError: except KeyError:
pass pass
else: else:
profile_path_count += 1 vcs_repository_list[0][PROFILE_PATH_KEY] = profile_path
if profile_path_count > 1: profile_path_count = 0
raise ValueError(PROFILE_PATH_KEY + ' defined more than once') for vcs_repository in vcs_repository_list:
profile_content = """ url = vcs_repository['url']
buildout_section_id = vcs_repository.get('buildout_section_id', None)
repository_id = buildout_section_id or \
url.split('/')[-1].split('.')[0]
repository_path = os.path.join(config['working_directory'],repository_id)
vcs_repository['repository_id'] = repository_id
vcs_repository['repository_path'] = repository_path
try:
profile_path = vcs_repository[PROFILE_PATH_KEY]
except KeyError:
pass
else:
profile_path_count += 1
if profile_path_count > 1:
raise ValueError(PROFILE_PATH_KEY + ' defined more than once')
profile_content = """
[buildout] [buildout]
extends = %(software_config_path)s extends = %(software_config_path)s
""" % {'software_config_path': os.path.join(repository_path, profile_path)} """ % {'software_config_path': os.path.join(repository_path, profile_path)}
if not(buildout_section_id is None): if not(buildout_section_id is None):
profile_content += """ profile_content += """
[%(buildout_section_id)s] [%(buildout_section_id)s]
repository = %(repository_path)s repository = %(repository_path)s
branch = %(branch)s branch = %(branch)s
...@@ -156,145 +199,176 @@ branch = %(branch)s ...@@ -156,145 +199,176 @@ branch = %(branch)s
'repository_path' : repository_path, 'repository_path' : repository_path,
'branch' : vcs_repository.get('branch','master')} 'branch' : vcs_repository.get('branch','master')}
if not profile_path_count: if not profile_path_count:
raise ValueError(PROFILE_PATH_KEY + ' not defined') raise ValueError(PROFILE_PATH_KEY + ' not defined')
custom_profile = open(custom_profile_path, 'w') custom_profile = open(custom_profile_path, 'w')
custom_profile.write(profile_content) custom_profile.write(profile_content)
custom_profile.close() custom_profile.close()
config['repository_path'] = repository_path config['repository_path'] = repository_path
sys.path.append(repository_path) sys.path.append(repository_path)
test_suite_title = config['test_suite_title'] or config['test_suite'] test_suite_title = config['test_suite_title'] or config['test_suite']
retry_software = False retry = False
try: retry_software_count = 0
while True: same_revision_count = 0
remote_test_result_needs_cleanup = False try:
# kill processes from previous loop if any while True:
try: remote_test_result_needs_cleanup = False
killPreviousRun() remote_logger = None
process_group_pid_set.clear() remote_logger_thread = None
full_revision_list = [] try:
# Make sure we have local repository # kill processes from previous loop if any
for vcs_repository in vcs_repository_list: process_manager.killPreviousRun()
repository_path = vcs_repository['repository_path'] full_revision_list = []
repository_id = vcs_repository['repository_id']
if not os.path.exists(repository_path):
parameter_list = [config['git_binary'], 'clone',
vcs_repository['url']]
if vcs_repository.get('branch') is not None:
parameter_list.extend(['-b',vcs_repository.get('branch')])
parameter_list.append(repository_path)
log(subprocess.check_output(parameter_list, stderr=subprocess.STDOUT))
# Make sure we have local repository # Make sure we have local repository
updater = Updater(repository_path, git_binary=config['git_binary'], for vcs_repository in vcs_repository_list:
log=log, realtime_output=False) repository_path = vcs_repository['repository_path']
updater.checkout() repository_id = vcs_repository['repository_id']
revision = "-".join(updater.getRevision()) if not os.path.exists(repository_path):
full_revision_list.append('%s=%s' % (repository_id, revision)) parameter_list = [config['git_binary'], 'clone',
revision = ','.join(full_revision_list) vcs_repository['url']]
if previous_revision == revision: if vcs_repository.get('branch') is not None:
log('Sleeping a bit') parameter_list.extend(['-b',vcs_repository.get('branch')])
time.sleep(DEFAULT_SLEEP_TIMEOUT) parameter_list.append(repository_path)
if not(retry_software): log(subprocess.check_output(parameter_list, stderr=subprocess.STDOUT))
continue # Make sure we have local repository
log('Retrying install') updater = Updater(repository_path, git_binary=config['git_binary'],
retry_software = False log=log, process_manager=process_manager)
previous_revision = revision updater.checkout()
portal_url = config['test_suite_master_url'] revision = "-".join(updater.getRevision())
test_result_path = None full_revision_list.append('%s=%s' % (repository_id, revision))
test_result = (test_result_path, revision) revision = ','.join(full_revision_list)
if portal_url: if previous_revision == revision:
if portal_url[-1] != '/': log('Same Revision')
portal_url += '/' same_revision_count += 1
portal = xmlrpclib.ServerProxy("%s%s" % if not(retry) and same_revision_count <= 2:
(portal_url, 'portal_task_distribution'), log('Sleeping a bit since same revision')
allow_none=1) time.sleep(DEFAULT_SLEEP_TIMEOUT)
assert safeRpcCall(portal, "getProtocolRevision") == 1 continue
test_result = safeRpcCall(portal, "createTestResult", same_revision_count = 0
config['test_suite'], revision, [], log('Retrying install or checking if previous test was cancelled')
False, test_suite_title, retry = False
config['test_node_title'], config['project_title']) previous_revision = revision
remote_test_result_needs_cleanup = True portal_url = config['test_suite_master_url']
log("testnode, test_result : %r" % (test_result, )) test_result_path = None
if test_result: test_result = (test_result_path, revision)
test_result_path, test_revision = test_result if portal_url:
if revision != test_revision: if portal_url[-1] != '/':
log('Disagreement on tested revision, checking out:') portal_url += '/'
for i, repository_revision in enumerate(test_revision.split(',')): portal = xmlrpclib.ServerProxy("%s%s" %
vcs_repository = vcs_repository_list[i] (portal_url, 'portal_task_distribution'),
repository_path = vcs_repository['repository_path'] allow_none=1)
revision = repository_revision.rsplit('-', 1)[1] assert safeRpcCall(log, portal, "getProtocolRevision", True) == 1
# other testnodes on other boxes are already ready to test another test_result = safeRpcCall(log, portal, "createTestResult", True,
# revision config['test_suite'], revision, [],
log(' %s at %s' % (repository_path, revision)) False, test_suite_title,
updater = Updater(repository_path, git_binary=config['git_binary'], config['test_node_title'], config['project_title'])
revision=revision, log=log, remote_test_result_needs_cleanup = True
realtime_output=False)
updater.checkout() log("testnode, test_result : %r" % (test_result, ))
if test_result:
test_result_path, test_revision = test_result
if config.get('log_file'):
remote_logger = RemoteLogger(log, config['log_file'],
config['test_node_title'],
process_manager)
remote_logger.portal = portal
remote_logger.test_result_path = test_result_path
remote_logger_thread = threading.Thread(target=remote_logger)
remote_logger_thread.start()
if revision != test_revision:
previous_revision = test_revision
log('Disagreement on tested revision, checking out:')
for i, repository_revision in enumerate(test_revision.split(',')):
vcs_repository = vcs_repository_list[i]
repository_path = vcs_repository['repository_path']
revision = repository_revision.rsplit('-', 1)[1]
# other testnodes on other boxes are already ready to test another
# revision
log(' %s at %s' % (repository_path, revision))
updater = Updater(repository_path, git_binary=config['git_binary'],
revision=revision, log=log,
process_manager=process_manager)
updater.checkout()
# Now prepare the installation of SlapOS and create instance # Now prepare the installation of SlapOS and create instance
slapproxy_log = os.path.join(config['log_directory'], slapproxy_log = os.path.join(config['log_directory'],
'slapproxy.log') 'slapproxy.log')
log('Configured slapproxy log to %r' % slapproxy_log) log('Configured slapproxy log to %r' % slapproxy_log)
slapos_controler = SlapOSControler.SlapOSControler(config, log('testnode, retry_software_count : %r' % retry_software_count)
process_group_pid_set=process_group_pid_set, log=log, slapos_controler = SlapOSControler.SlapOSControler(config,
slapproxy_log=slapproxy_log) log=log, slapproxy_log=slapproxy_log, process_manager=process_manager,
for method_name in ("runSoftwareRelease", "runComputerPartition",): reset_software=(retry_software_count>0 and retry_software_count%10 == 0))
stdout, stderr = getInputOutputFileList(config, method_name) for method_name in ("runSoftwareRelease", "runComputerPartition",):
slapos_method = getattr(slapos_controler, method_name) slapos_method = getattr(slapos_controler, method_name)
status_dict = slapos_method(config, status_dict = slapos_method(config,
environment=config['environment'], environment=config['environment'],
process_group_pid_set=process_group_pid_set, )
stdout=stdout, stderr=stderr if status_dict['status_code'] != 0:
) retry = True
if status_dict['status_code'] != 0: retry_software_count += 1
retry_software = True raise SubprocessError(status_dict)
raise SubprocessError(status_dict) else:
# Give some time so computer partitions may start retry_software_count = 0
# as partitions can be of any kind we have and likely will never have # Give some time so computer partitions may start
# a reliable way to check if they are up or not ... # as partitions can be of any kind we have and likely will never have
time.sleep(20) # a reliable way to check if they are up or not ...
time.sleep(20)
run_test_suite_path_list = glob.glob("%s/*/bin/runTestSuite" %config['instance_root']) run_test_suite_path_list = glob.glob("%s/*/bin/runTestSuite" %config['instance_root'])
if not len(run_test_suite_path_list): if not len(run_test_suite_path_list):
raise ValueError('No runTestSuite provided in installed partitions.') raise ValueError('No runTestSuite provided in installed partitions.')
run_test_suite_path = run_test_suite_path_list[0] run_test_suite_path = run_test_suite_path_list[0]
run_test_suite_revision = revision run_test_suite_revision = revision
if isinstance(revision, tuple): if isinstance(revision, tuple):
revision = ','.join(revision) revision = ','.join(revision)
# Deal with Shebang size limitation # Deal with Shebang size limitation
line = open(run_test_suite_path, 'r').readline() line = open(run_test_suite_path, 'r').readline()
invocation_list = [] invocation_list = []
if line[:2] == '#!': if line[:2] == '#!':
invocation_list = line[2:].split() invocation_list = line[2:].split()
invocation_list.extend([run_test_suite_path, invocation_list.extend([run_test_suite_path,
'--test_suite', config['test_suite'], '--test_suite', config['test_suite'],
'--revision', revision, '--revision', revision,
'--test_suite_title', test_suite_title, '--test_suite_title', test_suite_title,
'--node_quantity', config['node_quantity'], '--node_quantity', config['node_quantity'],
'--master_url', portal_url]) '--master_url', portal_url])
bt5_path_list = config.get("bt5_path") bt5_path_list = config.get("bt5_path")
if bt5_path_list not in ('', None,): if bt5_path_list not in ('', None,):
invocation_list.extend(["--bt5_path", bt5_path_list]) invocation_list.extend(["--bt5_path", bt5_path_list])
# From this point, test runner becomes responsible for updating test # From this point, test runner becomes responsible for updating test
# result. We only do cleanup if the test runner itself is not able # result. We only do cleanup if the test runner itself is not able
# to run. # to run.
log("call process : %r", (invocation_list,)) process_manager.spawn(*invocation_list,
run_test_suite = subprocess.Popen(invocation_list, cwd=config['test_suite_directory'],
preexec_fn=os.setsid, cwd=config['test_suite_directory'], log_prefix='runTestSuite', get_output=False)
stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if remote_logger:
process_group_pid_set.add(run_test_suite.pid) remote_logger.quit = True
log(run_test_suite.communicate()[0]) remote_logger_thread.join()
process_group_pid_set.remove(run_test_suite.pid) except SubprocessError, e:
except SubprocessError, e: log("SubprocessError", exc_info=sys.exc_info())
if remote_test_result_needs_cleanup: if remote_logger:
safeRpcCall(portal, "reportTaskFailure", remote_logger.finish = True
test_result_path, e.status_dict, config['test_node_title']) remote_logger_thread.join()
time.sleep(DEFAULT_SLEEP_TIMEOUT) if remote_test_result_needs_cleanup:
continue safeRpcCall(log, portal, "reportTaskFailure", True,
test_result_path, e.status_dict, config['test_node_title'])
finally: log("SubprocessError, going to sleep %s" % DEFAULT_SLEEP_TIMEOUT)
# Nice way to kill *everything* generated by run process -- process time.sleep(DEFAULT_SLEEP_TIMEOUT)
# groups working only in POSIX compilant systems continue
# Exceptions are swallowed during cleanup phase except CancellationError, e:
killPreviousRun() log("CancellationError", exc_info=sys.exc_info())
process_manager.under_cancellation = False
retry = True
continue
except:
log("erp5testnode exception", exc_info=sys.exc_info())
raise
finally:
# Nice way to kill *everything* generated by run process -- process
# groups working only in POSIX compilant systems
# Exceptions are swallowed during cleanup phase
log('Testnode.run, finally close')
process_manager.killPreviousRun()
if remote_logger:
remote_logger.quit = True
...@@ -65,13 +65,7 @@ class SQLDict(SQLBase): ...@@ -65,13 +65,7 @@ class SQLDict(SQLBase):
priority_list = [message.activity_kw.get('priority', 1) for message in registered_message_list] priority_list = [message.activity_kw.get('priority', 1) for message in registered_message_list]
dumped_message_list = [self.dumpMessage(message) for message in registered_message_list] dumped_message_list = [self.dumpMessage(message) for message in registered_message_list]
date_list = [message.activity_kw.get('at_date', None) for message in registered_message_list] date_list = [message.activity_kw.get('at_date', None) for message in registered_message_list]
group_method_id_list = [] group_method_id_list = [m.getGroupId() for m in registered_message_list]
for m in registered_message_list:
group_method_id = m.activity_kw.get('group_method_id', '')
if group_method_id is None:
group_method_id = 'portal_activities/dummyGroupMethod/' + m.method_id
group_method_id_list.append(group_method_id + '\0' +
m.activity_kw.get('group_id', ''))
tag_list = [message.activity_kw.get('tag', '') for message in registered_message_list] tag_list = [message.activity_kw.get('tag', '') for message in registered_message_list]
serialization_tag_list = [message.activity_kw.get('serialization_tag', '') for message in registered_message_list] serialization_tag_list = [message.activity_kw.get('serialization_tag', '') for message in registered_message_list]
order_validation_text_list = [self.getOrderValidationText(message) for message in registered_message_list] order_validation_text_list = [self.getOrderValidationText(message) for message in registered_message_list]
......
...@@ -66,13 +66,7 @@ class SQLQueue(SQLBase): ...@@ -66,13 +66,7 @@ class SQLQueue(SQLBase):
method_id_list = [m.method_id for m in registered_message_list] method_id_list = [m.method_id for m in registered_message_list]
priority_list = [m.activity_kw.get('priority', 1) for m in registered_message_list] priority_list = [m.activity_kw.get('priority', 1) for m in registered_message_list]
date_list = [m.activity_kw.get('at_date', None) for m in registered_message_list] date_list = [m.activity_kw.get('at_date', None) for m in registered_message_list]
group_method_id_list = [] group_method_id_list = [m.getGroupId() for m in registered_message_list]
for m in registered_message_list:
group_method_id = m.activity_kw.get('group_method_id', '')
if group_method_id is None:
group_method_id = 'portal_activities/dummyGroupMethod/' + m.method_id
group_method_id_list.append(group_method_id + '\0' +
m.activity_kw.get('group_id', ''))
tag_list = [m.activity_kw.get('tag', '') for m in registered_message_list] tag_list = [m.activity_kw.get('tag', '') for m in registered_message_list]
serialization_tag_list = [m.activity_kw.get('serialization_tag', '') for m in registered_message_list] serialization_tag_list = [m.activity_kw.get('serialization_tag', '') for m in registered_message_list]
dumped_message_list = [self.dumpMessage(m) for m in registered_message_list] dumped_message_list = [self.dumpMessage(m) for m in registered_message_list]
......
...@@ -203,6 +203,13 @@ class Message(BaseMessage): ...@@ -203,6 +203,13 @@ class Message(BaseMessage):
request.environ['HTTP_ACCEPT_LANGUAGE'] request.environ['HTTP_ACCEPT_LANGUAGE']
self.request_info['_script'] = list(request._script) self.request_info['_script'] = list(request._script)
def getGroupId(self):
get = self.activity_kw.get
group_method_id = get('group_method_id', '')
if group_method_id is None:
group_method_id = 'portal_activities/dummyGroupMethod/' + self.method_id
return group_method_id + '\0' + get('group_id', '')
def getObject(self, activity_tool): def getObject(self, activity_tool):
"""return the object referenced in this message.""" """return the object referenced in this message."""
return activity_tool.unrestrictedTraverse(self.object_path) return activity_tool.unrestrictedTraverse(self.object_path)
......
...@@ -14,14 +14,6 @@ DeadlockDebugger can of course also be used in non-deadlock situations, ...@@ -14,14 +14,6 @@ DeadlockDebugger can of course also be used in non-deadlock situations,
when a Zope process is taking a long time and you wish to know what code when a Zope process is taking a long time and you wish to know what code
is being executed. is being executed.
Installation
------------
This product requires the 'threadframe' python module
(http://www.majid.info/mylos/stories/2004/06/10/threadframe.html).
When DeadlockDebugger starts, it verifies that threadframe is available,
please check the event.log for ERROR message.
Configuration Configuration
------------- -------------
......
...@@ -28,24 +28,19 @@ You MUST configure zope.conf before use. ...@@ -28,24 +28,19 @@ You MUST configure zope.conf before use.
from zLOG import LOG, INFO, ERROR from zLOG import LOG, INFO, ERROR
from App.config import getConfiguration from App.config import getConfiguration
try: config = getConfiguration()
import threadframe if getattr(config, 'product_config', None) is not None:
except ImportError: deadlockdebugger = config.product_config.get('deadlockdebugger')
LOG('DeadlockDebugger', ERROR, "Incorrectly installed threadframe module") dump_url = ''
else: secret = ''
config = getConfiguration() if deadlockdebugger is None:
if getattr(config, 'product_config', None) is not None: LOG('DeadlockDebugger', ERROR, 'Missing configuration statement '
deadlockdebugger = config.product_config.get('deadlockdebugger') '<product-config deadlockdebugger>, not activated')
dump_url = '' else:
secret = '' if not 'dump_url' in deadlockdebugger:
if deadlockdebugger is None: LOG('DeadlockDebugger', ERROR, 'Please configure dump_url and '
LOG('DeadlockDebugger', ERROR, 'Missing configuration statement ' 'optionally secret in <product-config deadlockdebugger>, not '
'<product-config deadlockdebugger>, not activated') 'activated')
else: else:
if not 'dump_url' in deadlockdebugger: import dumper
LOG('DeadlockDebugger', ERROR, 'Please configure dump_url and ' LOG('DeadlockDebugger', INFO, "Installed")
'optionally secret in <product-config deadlockdebugger>, not '
'activated')
else:
import dumper
LOG('DeadlockDebugger', INFO, "Installed")
...@@ -23,7 +23,7 @@ ZServer hook to dump a traceback of the running python threads. ...@@ -23,7 +23,7 @@ ZServer hook to dump a traceback of the running python threads.
""" """
import thread import thread
import threadframe from sys import _current_frames
import traceback import traceback
import time import time
from cStringIO import StringIO from cStringIO import StringIO
...@@ -36,11 +36,10 @@ def dump_threads(): ...@@ -36,11 +36,10 @@ def dump_threads():
Returns a string with the tracebacks. Returns a string with the tracebacks.
""" """
frames = threadframe.dict()
this_thread_id = thread.get_ident() this_thread_id = thread.get_ident()
now = time.strftime("%Y-%m-%d %H:%M:%S") now = time.strftime("%Y-%m-%d %H:%M:%S")
res = ["Threads traceback dump at %s\n" % now] res = ["Threads traceback dump at %s\n" % now]
for thread_id, frame in frames.iteritems(): for thread_id, frame in _current_frames().iteritems():
if thread_id == this_thread_id: if thread_id == this_thread_id:
continue continue
...@@ -68,7 +67,6 @@ def dump_threads(): ...@@ -68,7 +67,6 @@ def dump_threads():
res.append("Thread %s%s:\n%s" % res.append("Thread %s%s:\n%s" %
(thread_id, reqinfo, output.getvalue())) (thread_id, reqinfo, output.getvalue()))
frames = None
res.append("End of dump") res.append("End of dump")
result = '\n'.join(res) result = '\n'.join(res)
if isinstance(result, unicode): if isinstance(result, unicode):
......
...@@ -339,18 +339,12 @@ class Delivery(XMLObject, ImmobilisationDelivery, ...@@ -339,18 +339,12 @@ class Delivery(XMLObject, ImmobilisationDelivery,
security.declareProtected(Permissions.AccessContentsInformation, 'isSimulated') security.declareProtected(Permissions.AccessContentsInformation, 'isSimulated')
def isSimulated(self): def isSimulated(self):
""" """
Returns 1 if all movements have a delivery or order counterpart Returns 1 if all non-null movements have a delivery counterpart
in the simulation in the simulation
""" """
for m in self.getMovementList(): for m in self.getMovementList():
#LOG('Delivery.isSimulated m',0,m.getPhysicalPath()) if m.getQuantity() and not m.isSimulated():
#LOG('Delivery.isSimulated m.isSimulated',0,m.isSimulated()) return 0
if not m.isSimulated():
#LOG('Delivery.isSimulated m.getQuantity',0,m.getQuantity())
#LOG('Delivery.isSimulated m.getSimulationQuantity',0,m.getSimulationQuantity())
if m.getQuantity() != 0.0 or m.getSimulationQuantity() not in (0, None):
return 0
# else Do we need to create a simulation movement ? XXX probably not
return 1 return 1
security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent') security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent')
...@@ -844,21 +838,21 @@ class Delivery(XMLObject, ImmobilisationDelivery, ...@@ -844,21 +838,21 @@ class Delivery(XMLObject, ImmobilisationDelivery,
This method will look at the causality and check if the This method will look at the causality and check if the
causality has already a causality causality has already a causality
""" """
causality_value_list = [x for x in self.getCausalityValueList() causality_value_list = self.getCausalityValueList()
if x is not self] if causality_value_list:
initial_list = [] initial_list = []
if len(causality_value_list)==0:
initial_list = [self]
else:
for causality in causality_value_list: for causality in causality_value_list:
# The causality may be something which has not this method # The causality may be something which has not this method
# (e.g. item) # (e.g. item)
if hasattr(causality, 'getRootCausalityValueList'): try:
tmp_causality_list = causality.getRootCausalityValueList() getRootCausalityValueList = causality.getRootCausalityValueList
initial_list.extend([x for x in tmp_causality_list except AttributeError:
if x not in initial_list]) continue
return initial_list assert causality != self
initial_list += [x for x in getRootCausalityValueList()
if x not in initial_list]
return initial_list
return [self]
# XXX Temp hack, should be removed has soon as the structure of # XXX Temp hack, should be removed has soon as the structure of
# the order/delivery builder will be reviewed. It might # the order/delivery builder will be reviewed. It might
...@@ -982,6 +976,7 @@ class Delivery(XMLObject, ImmobilisationDelivery, ...@@ -982,6 +976,7 @@ class Delivery(XMLObject, ImmobilisationDelivery,
""" """
divergent_tester_list = [] divergent_tester_list = []
for simulation_movement in self._getAllRelatedSimulationMovementList(): for simulation_movement in self._getAllRelatedSimulationMovementList():
simulation_movement = simulation_movement.getObject()
rule = simulation_movement.getParentValue().getSpecialiseValue() rule = simulation_movement.getParentValue().getSpecialiseValue()
for tester in rule._getDivergenceTesterList(exclude_quantity=False): for tester in rule._getDivergenceTesterList(exclude_quantity=False):
if tester.explain(simulation_movement) not in (None, []): if tester.explain(simulation_movement) not in (None, []):
......
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Yoshinori Okuji <yo@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability 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
# garantees 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ExtFile.ExtFile import ExtFile
from Products.ExtFile.ExtImage import ExtImage
import os
from App.config import getConfiguration
from Products.ERP5 import product_path
from Shared.DC.ZRDB.TM import TM
import shutil
from zLOG import LOG
class Deletion(TM):
"""Remove the directory at the end of a transaction.
"""
def __init__(self, path):
self.path = path
self._register()
def _finish(self):
try:
LOG('Deletion', 0, 'removing %s' % self.path)
shutil.rmtree(self.path)
except OSError:
pass
def _abort(self):
pass
class ExtFolder( XMLObject ):
"""
ExtFolder stores sub-objects as ExtFile or ExtImage.
"""
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
)
# CMF Type Definition
meta_type='ERP5 External Folder'
portal_type='External Folder'
add_permission = Permissions.AddPortalContent
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declarePrivate('PUT_factory')
def PUT_factory( self, name, typ, body ):
"""Return an ExtFile or ExtImage object.
"""
major, minor = typ.split('/', 1)
if major == 'image':
return ExtImage(name)
return ExtFile(name)
def _getRepositoryPath(self):
"""Return the path in the filesystem.
"""
instance_home = getConfiguration().instancehome
repository = os.path.join(*ExtFile._repository)
return os.path.sep.join((instance_home, repository, self.getPath()))
security.declareProtected('Manage portal', 'generateRpmHeaderList')
def generateRpmHeaderList(self):
"""Run genhdlist on the directory behind this object.
"""
status = os.system("/usr/bin/genhdlist -s %s" % self._getRepositoryPath())
if status != 0:
raise RuntimeError, "failed in executing genhdlist"
security.declareProtected('Manage portal', 'generateBt5HeaderList')
def generateBt5HeaderList(self):
"""Run genbt5list on the directory behind this object.
"""
status = os.system("%s/bin/genbt5list %s" % (product_path, self._getRepositoryPath()))
if status != 0:
raise RuntimeError, "failed in executing genbt5list"
def manage_beforeDelete(self, item, container):
"""Called before deleting this object.
"""
self._v_deletion = Deletion(self._getRepositoryPath())
XMLObject.manage_beforeDelete(self, item, container)
...@@ -348,11 +348,8 @@ class SimulatedDeliveryBuilder(BuilderMixin): ...@@ -348,11 +348,8 @@ class SimulatedDeliveryBuilder(BuilderMixin):
if old_delivery is None: if old_delivery is None:
# from scratch # from scratch
new_delivery_id = str(delivery_module.generateNewId()) new_delivery_id = str(delivery_module.generateNewId())
delivery = delivery_module.newContent( delivery = super(SimulatedDeliveryBuilder, self)._createDelivery(
portal_type=self.getDeliveryPortalType(), delivery_module, movement_list, activate_kw)
id=new_delivery_id,
created_by_builder=1,
activate_kw=activate_kw)
else: else:
# from duplicated original delivery # from duplicated original delivery
cp = tryMethodCallWithTemporaryPermission( cp = tryMethodCallWithTemporaryPermission(
...@@ -383,10 +380,8 @@ class SimulatedDeliveryBuilder(BuilderMixin): ...@@ -383,10 +380,8 @@ class SimulatedDeliveryBuilder(BuilderMixin):
old_delivery_line = None old_delivery_line = None
if old_delivery_line is None: if old_delivery_line is None:
# from scratch # from scratch
new_delivery_line_id = str(delivery.generateNewId())
delivery_line = delivery.newContent( delivery_line = delivery.newContent(
portal_type=self.getDeliveryLinePortalType(), portal_type=self.getDeliveryLinePortalType(),
id=new_delivery_line_id,
variation_category_list=[], variation_category_list=[],
activate_kw=activate_kw) activate_kw=activate_kw)
else: else:
......
...@@ -193,7 +193,7 @@ class IdTool(BaseTool): ...@@ -193,7 +193,7 @@ class IdTool(BaseTool):
last_generator = self._getLatestGeneratorValue(id_generator) last_generator = self._getLatestGeneratorValue(id_generator)
new_id_list = last_generator.generateNewIdList(id_group=id_group, new_id_list = last_generator.generateNewIdList(id_group=id_group,
id_count=id_count, default=default) id_count=id_count, default=default)
except KeyError: except (KeyError, ValueError):
template_tool = getattr(self, 'portal_templates', None) template_tool = getattr(self, 'portal_templates', None)
revision = template_tool.getInstalledBusinessTemplateRevision('erp5_core') revision = template_tool.getInstalledBusinessTemplateRevision('erp5_core')
# XXX backward compatiblity # XXX backward compatiblity
......
...@@ -256,3 +256,26 @@ class TaskDistributionTool(BaseTool): ...@@ -256,3 +256,26 @@ class TaskDistributionTool(BaseTool):
break break
else: else:
test_result.fail() test_result.fail()
security.declarePublic('reportTaskStatus')
def reportTaskStatus(self, test_result_path, status_dict, node_title):
"""report status of node
"""
status_dict = self._extractXMLRPCDict(status_dict)
LOG("TaskDistributionTool.reportTaskStatus", 0, repr((test_result_path,
status_dict)))
portal = self.getPortalObject()
test_result = portal.restrictedTraverse(test_result_path)
node = self._getTestResultNode(test_result, node_title)
assert node is not None
node.edit(cmdline=status_dict['command'],
stdout=status_dict['stdout'], stderr=status_dict['stderr'])
security.declarePublic('isTaskAlive')
def isTaskAlive(self, test_result_path):
"""check status of a test suite
"""
LOG("TaskDistributionTool.checkTaskStatus", 0, repr(test_result_path))
portal = self.getPortalObject()
test_result = portal.restrictedTraverse(test_result_path)
return test_result.getSimulationState() == "started" and 1 or 0
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
<value> <value>
<list> <list>
<string>listbox</string> <string>listbox</string>
<string>listbox_modification_date</string>
</list> </list>
</value> </value>
</item> </item>
......
...@@ -310,7 +310,12 @@ ...@@ -310,7 +310,12 @@
<item> <item>
<key> <string>all_columns</string> </key> <key> <string>all_columns</string> </key>
<value> <value>
<list/> <list>
<tuple>
<string>modification_date</string>
<string>Modification Date</string>
</tuple>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -376,6 +381,10 @@ ...@@ -376,6 +381,10 @@
<key> <string>default</string> </key> <key> <string>default</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>default_display_style</string> </key>
<value> <string>table</string> </value>
</item>
<item> <item>
<key> <string>default_params</string> </key> <key> <string>default_params</string> </key>
<value> <value>
...@@ -409,7 +418,12 @@ ...@@ -409,7 +418,12 @@
<item> <item>
<key> <string>editable_columns</string> </key> <key> <string>editable_columns</string> </key>
<value> <value>
<list/> <list>
<tuple>
<string>modification_date</string>
<string></string>
</tuple>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -430,6 +444,10 @@ ...@@ -430,6 +444,10 @@
<list/> <list/>
</value> </value>
</item> </item>
<item>
<key> <string>global_search_column</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>height</string> </key> <key> <string>height</string> </key>
<value> <int>5</int> </value> <value> <int>5</int> </value>
...@@ -477,6 +495,10 @@ ...@@ -477,6 +495,10 @@
</list> </list>
</value> </value>
</item> </item>
<item>
<key> <string>page_navigation_template</string> </key>
<value> <string>ListBox_viewSliderPageNavigationRenderer</string> </value>
</item>
<item> <item>
<key> <string>page_template</string> </key> <key> <string>page_template</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -584,6 +606,10 @@ ...@@ -584,6 +606,10 @@
<string>revision</string> <string>revision</string>
<string>Revision</string> <string>Revision</string>
</tuple> </tuple>
<tuple>
<string>modification_date</string>
<string>Modification Date</string>
</tuple>
</list> </list>
</value> </value>
</item> </item>
...@@ -597,6 +623,12 @@ ...@@ -597,6 +623,12 @@
<key> <string>stat_method</string> </key> <key> <string>stat_method</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>style_columns</string> </key>
<value>
<list/>
</value>
</item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Business Templates</string> </value> <value> <string>Business Templates</string> </value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_modification_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>listbox_modification_date</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</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>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The BIC code.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>bic_code_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</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>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>International Bank Account Number.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>iban_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -102,7 +102,7 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -102,7 +102,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
security.declarePublic('build') security.declarePublic('build')
def build(self, applied_rule_uid=None, movement_relative_url_list=None, def build(self, applied_rule_uid=None, movement_relative_url_list=None,
delivery_relative_url_list=None, movement_list=None, delivery_relative_url_list=None, movement_list=None,
explanation=None, business_link=None, **kw): explanation=None, business_link=None, activate_kw=None, **kw):
""" """
Build deliveries from a list of movements Build deliveries from a list of movements
...@@ -143,7 +143,8 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -143,7 +143,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
delivery_list = self.buildDeliveryList( delivery_list = self.buildDeliveryList(
root_group_node, root_group_node,
delivery_relative_url_list=delivery_relative_url_list, delivery_relative_url_list=delivery_relative_url_list,
movement_list=movement_list,**kw) movement_list=movement_list, activate_kw=activate_kw,
**kw)
# Call a script after building # Call a script after building
self.callAfterBuildingScript(delivery_list, movement_list, **kw) self.callAfterBuildingScript(delivery_list, movement_list, **kw)
return delivery_list return delivery_list
...@@ -163,7 +164,7 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -163,7 +164,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
""" """
delivery_module_before_building_script_id = \ delivery_module_before_building_script_id = \
self.getDeliveryModuleBeforeBuildingScriptId() self.getDeliveryModuleBeforeBuildingScriptId()
if delivery_module_before_building_script_id not in ["", None]: if delivery_module_before_building_script_id:
delivery_module = getattr(self.getPortalObject(), self.getDeliveryModule()) delivery_module = getattr(self.getPortalObject(), self.getDeliveryModule())
getattr(delivery_module, delivery_module_before_building_script_id)() getattr(delivery_module, delivery_module_before_building_script_id)()
...@@ -368,13 +369,10 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -368,13 +369,10 @@ class BuilderMixin(XMLObject, Amount, Predicate):
Create a new delivery in case where a builder may not update Create a new delivery in case where a builder may not update
an existing one. an existing one.
""" """
new_delivery_id = str(delivery_module.generateNewId()) return delivery_module.newContent(
delivery = delivery_module.newContent(
portal_type=self.getDeliveryPortalType(), portal_type=self.getDeliveryPortalType(),
id=new_delivery_id,
created_by_builder=1, created_by_builder=1,
activate_kw=activate_kw) activate_kw=activate_kw)
return delivery
def _processDeliveryGroup(self, delivery_module, movement_group_node, def _processDeliveryGroup(self, delivery_module, movement_group_node,
collect_order_list, movement_group_node_list=None, collect_order_list, movement_group_node_list=None,
...@@ -452,13 +450,10 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -452,13 +450,10 @@ class BuilderMixin(XMLObject, Amount, Predicate):
Create a new delivery line in case where a builder may not update Create a new delivery line in case where a builder may not update
an existing one. an existing one.
""" """
new_delivery_line_id = str(delivery.generateNewId()) return delivery.newContent(
delivery_line = delivery.newContent(
portal_type=self.getDeliveryLinePortalType(), portal_type=self.getDeliveryLinePortalType(),
id=new_delivery_line_id,
created_by_builder=1, created_by_builder=1,
activate_kw=activate_kw) activate_kw=activate_kw)
return delivery_line
def _processDeliveryLineGroup(self, delivery, movement_group_node, def _processDeliveryLineGroup(self, delivery, movement_group_node,
collect_order_list, movement_group_node_list=None, collect_order_list, movement_group_node_list=None,
...@@ -685,42 +680,33 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -685,42 +680,33 @@ class BuilderMixin(XMLObject, Amount, Predicate):
delivery_movement._edit(force_update=1, **property_dict) delivery_movement._edit(force_update=1, **property_dict)
@UnrestrictedMethod @UnrestrictedMethod
def callAfterBuildingScript(self, delivery_list, movement_list=None, **kw): def callAfterBuildingScript(self, delivery_list, movement_list=(), **kw):
""" """
Call script on each delivery built. Call script on each delivery built.
""" """
if not len(delivery_list):
return
# Parameter initialization
if movement_list is None:
movement_list = []
delivery_after_generation_script_id = \ delivery_after_generation_script_id = \
self.getDeliveryAfterGenerationScriptId() self.getDeliveryAfterGenerationScriptId()
related_simulation_movement_path_list = \ if delivery_after_generation_script_id:
[x.getPath() for x in movement_list] related_simulation_movement_path_list = \
if delivery_after_generation_script_id not in ["", None]: [x.getPath() for x in movement_list]
for delivery in delivery_list: for delivery in delivery_list:
script = getattr(delivery, delivery_after_generation_script_id) script = getattr(delivery, delivery_after_generation_script_id)
# BBB: Only Python Scripts were used in the past, and they might not # BBB: Only Python Scripts were used in the past, and they might not
# accept an arbitrary argument. So to keep compatibility, # accept an arbitrary argument. So to keep compatibility,
# check if it can take the new parameter safely, only when # check if it can take the new parameter safely, only when
# the callable object is a Python Script. # the callable object is a Python Script.
safe_to_pass_parameter = True
meta_type = getattr(script, 'meta_type', None) meta_type = getattr(script, 'meta_type', None)
if meta_type == 'Script (Python)': if meta_type == 'Script (Python)':
# check if the script accepts related_simulation_movement_path_list # check if the script accepts related_simulation_movement_path_list
safe_to_pass_parameter = False
for param in script.params().split(','): for param in script.params().split(','):
param = param.split('=', 1)[0].strip() param = param.split('=', 1)[0].strip()
if param == 'related_simulation_movement_path_list' \ if param == 'related_simulation_movement_path_list' \
or param.startswith('**'): or param.startswith('**'):
safe_to_pass_parameter = True
break break
else:
if safe_to_pass_parameter: script()
script(related_simulation_movement_path_list=related_simulation_movement_path_list) continue
else: script(related_simulation_movement_path_list=related_simulation_movement_path_list)
script()
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getMovementGroupList') 'getMovementGroupList')
......
...@@ -86,16 +86,17 @@ class DownloadableMixin: ...@@ -86,16 +86,17 @@ class DownloadableMixin:
output_format = None output_format = None
if not format: if not format:
# Guess the format from original mimetype # Guess the format from original mimetype
mimetypes_registry = getToolByName(self.getPortalObject(), if mime:
'mimetypes_registry') mimetypes_registry = getToolByName(self.getPortalObject(),
mimetype_object_list = mimetypes_registry.lookup(mime) 'mimetypes_registry')
for mimetype_object in mimetype_object_list: mimetype_object_list = mimetypes_registry.lookup(mime)
if mimetype_object.extensions: for mimetype_object in mimetype_object_list:
output_format = mimetype_object.extensions[0] if mimetype_object.extensions:
break output_format = mimetype_object.extensions[0]
elif mimetype_object.globs: break
output_format = mimetype_object.globs.strip('*.') elif mimetype_object.globs:
break output_format = mimetype_object.globs.strip('*.')
break
else: else:
output_format = format output_format = format
......
...@@ -1301,12 +1301,14 @@ class TestClosingPeriod(AccountingTestCase): ...@@ -1301,12 +1301,14 @@ class TestClosingPeriod(AccountingTestCase):
self.assertEquals(1, q( self.assertEquals(1, q(
"SELECT count(*) FROM stock WHERE portal_type=" "SELECT count(*) FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q( self.assertAlmostEquals(3.3, q(
"SELECT total_price FROM stock WHERE portal_type=" "SELECT total_price FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0],
self.assertEquals(3.3, q( accounting_currency_precision)
self.assertAlmostEquals(3.3, q(
"SELECT quantity FROM stock WHERE portal_type=" "SELECT quantity FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0],
accounting_currency_precision)
self.assertEquals(self.portal.currency_module.euro.getUid(), q( self.assertEquals(self.portal.currency_module.euro.getUid(), q(
"SELECT resource_uid FROM stock WHERE portal_type=" "SELECT resource_uid FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0])
...@@ -1438,12 +1440,14 @@ class TestClosingPeriod(AccountingTestCase): ...@@ -1438,12 +1440,14 @@ class TestClosingPeriod(AccountingTestCase):
self.assertEquals(1, q( self.assertEquals(1, q(
"SELECT count(*) FROM stock WHERE portal_type=" "SELECT count(*) FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q( self.assertAlmostEquals(3.3, q(
"SELECT total_price FROM stock WHERE portal_type=" "SELECT total_price FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0],
self.assertEquals(3.3, q( accounting_currency_precision)
self.assertAlmostEquals(3.3, q(
"SELECT quantity FROM stock WHERE portal_type=" "SELECT quantity FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0],
accounting_currency_precision)
self.assertEquals(self.portal.currency_module.euro.getUid(), q( self.assertEquals(self.portal.currency_module.euro.getUid(), q(
"SELECT resource_uid FROM stock WHERE portal_type=" "SELECT resource_uid FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0]) "'Balance Transaction Line'")[0][0])
......
...@@ -42,6 +42,7 @@ from Products.CMFCore.Expression import Expression ...@@ -42,6 +42,7 @@ from Products.CMFCore.Expression import Expression
from Products.ERP5Type.tests.utils import LogInterceptor from Products.ERP5Type.tests.utils import LogInterceptor
from Products.ERP5Type.Workflow import addWorkflowByType from Products.ERP5Type.Workflow import addWorkflowByType
from Products.ERP5Type.tests.backportUnittest import expectedFailure, skip from Products.ERP5Type.tests.backportUnittest import expectedFailure, skip
from Products.ERP5Type.tests.testDynamicClassGeneration import TestDeveloperMixin
from Products.ERP5VCS.WorkingCopy import getVcsTool from Products.ERP5VCS.WorkingCopy import getVcsTool
import shutil import shutil
import os import os
...@@ -58,7 +59,7 @@ from Products.PortalTransforms.Transform import Transform ...@@ -58,7 +59,7 @@ from Products.PortalTransforms.Transform import Transform
Transform_tr_init = Transform._tr_init Transform_tr_init = Transform._tr_init
Transform_manage_beforeDelete = Transform.manage_beforeDelete Transform_manage_beforeDelete = Transform.manage_beforeDelete
class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): class BusinessTemplateMixin(TestDeveloperMixin, ERP5TypeTestCase, LogInterceptor):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_base', return ('erp5_base',
'erp5_csv_style', 'erp5_csv_style',
...@@ -6963,25 +6964,6 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -6963,25 +6964,6 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
component_module = DocumentComponent._getDynamicModuleNamespace() component_module = DocumentComponent._getDynamicModuleNamespace()
component_portal_type = DocumentComponent.portal_type component_portal_type = DocumentComponent.portal_type
def login(self, user_name='ERP5TypeTestCase', quiet=0):
"""
XXX-arnau: Copy/paste from testDynamicClassGeneration
"""
from App.config import getConfiguration
product_config = getattr(getConfiguration(), 'product_config', None)
if product_config is None:
class DummyDeveloperConfig(object):
pass
dummy_developer_config = DummyDeveloperConfig()
dummy_developer_config.developer_list = [user_name]
getConfiguration().product_config = {'erp5': dummy_developer_config}
elif user_name not in product_config['erp5'].developer_list:
product_config['erp5'].developer_list.append(user_name)
return super(TestDocumentTemplateItem, self).login(user_name, quiet)
def stepCreateZodbDocument(self, sequence=None, **kw): def stepCreateZodbDocument(self, sequence=None, **kw):
document_id = self.component_module + '.erp5.' + self.document_title document_id = self.component_module + '.erp5.' + self.document_title
self.getPortalObject().portal_components.newContent( self.getPortalObject().portal_components.newContent(
......
...@@ -81,7 +81,6 @@ class TestERP5Credential(ERP5TypeTestCase): ...@@ -81,7 +81,6 @@ class TestERP5Credential(ERP5TypeTestCase):
system_preference = self.portal.portal_preferences.newContent( system_preference = self.portal.portal_preferences.newContent(
portal_type='System Preference') portal_type='System Preference')
system_preference.enable() system_preference.enable()
system_preference.edit(preferred_event_sender_email=['Sample s@s.com',])
@reindex @reindex
def enableAlarm(self): def enableAlarm(self):
......
...@@ -273,7 +273,9 @@ class TestIdTool(ERP5TypeTestCase): ...@@ -273,7 +273,9 @@ class TestIdTool(ERP5TypeTestCase):
generator.generateNewId(id_group='foo_bar', default=4) generator.generateNewId(id_group='foo_bar', default=4)
self.assertEquals(generator.last_max_id_dict['foo_bar'].value, 4) self.assertEquals(generator.last_max_id_dict['foo_bar'].value, 4)
portal.IdTool_zDropTable() portal.IdTool_zDropTable()
sql_connection = self.getSQLConnection() # make sure to use same connector as IdTool_zDropTable to avoid mariadb :
# "Waiting for table metadata lock"
sql_connection = portal.erp5_sql_transactionless_connection
query = 'select last_id from portal_ids where id_group="foo_bar"' query = 'select last_id from portal_ids where id_group="foo_bar"'
self.assertRaises(ProgrammingError, sql_connection.manage_test, query) self.assertRaises(ProgrammingError, sql_connection.manage_test, query)
generator.rebuildSqlTable() generator.rebuildSqlTable()
......
...@@ -511,7 +511,7 @@ class TestNotificationToolWithCRM(TestNotificationTool): ...@@ -511,7 +511,7 @@ class TestNotificationToolWithCRM(TestNotificationTool):
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type="Person", portal_type="Person",
default_email_text="userA@example.invalid") default_email_text="userA@example.invalid")
self.stepTic()
self.portal.portal_notifications.sendMessage( self.portal.portal_notifications.sendMessage(
store_as_event=True, store_as_event=True,
recipient=person, recipient=person,
......
...@@ -549,6 +549,7 @@ class TestTask(TestTaskMixin, ERP5TypeTestCase): ...@@ -549,6 +549,7 @@ class TestTask(TestTaskMixin, ERP5TypeTestCase):
def afterSetUp(self): def afterSetUp(self):
self.validateRules() self.validateRules()
self.stepTic()
def getTitle(self): def getTitle(self):
return "Task" return "Task"
......
...@@ -52,7 +52,7 @@ class TestTemplate(ERP5TypeTestCase): ...@@ -52,7 +52,7 @@ class TestTemplate(ERP5TypeTestCase):
def createUserAndLogin(self, name=None, additional_role_list=[]): def createUserAndLogin(self, name=None, additional_role_list=[]):
"""login with Member, Author and specified roles.""" """login with Member, Author and specified roles."""
uf = self.getPortal().acl_users uf = self.getPortal().acl_users
role_list = ['Member', 'Author'] role_list = ['Member', 'Author', 'Auditor']
role_list.extend(additional_role_list) role_list.extend(additional_role_list)
uf._doAddUser(name, '', role_list, []) uf._doAddUser(name, '', role_list, [])
user = uf.getUserById(name).__of__(uf) user = uf.getUserById(name).__of__(uf)
...@@ -66,10 +66,6 @@ class TestTemplate(ERP5TypeTestCase): ...@@ -66,10 +66,6 @@ class TestTemplate(ERP5TypeTestCase):
self.tic() self.tic()
self.portal.portal_types.Preference._setTypeAllowedContentTypeList( self.portal.portal_types.Preference._setTypeAllowedContentTypeList(
('Foo', 'Knowledge Pad')) ('Foo', 'Knowledge Pad'))
self.portal.foo_module.manage_role(role_to_manage='Author',
permissions=[Permissions.AddPortalContent,
Permissions.CopyOrMove,
])
def test_Template(self): def test_Template(self):
self.createUserAndLogin(self.id()) self.createUserAndLogin(self.id())
......
...@@ -269,7 +269,7 @@ class TestWebDavSupport(ERP5TypeTestCase): ...@@ -269,7 +269,7 @@ class TestWebDavSupport(ERP5TypeTestCase):
self.assertEquals(DateTime(xml_metadata.find('{DAV:}response/'\ self.assertEquals(DateTime(xml_metadata.find('{DAV:}response/'\
'{DAV:}propstat/{DAV:}prop/{DAV:}getlastmodified')\ '{DAV:}propstat/{DAV:}prop/{DAV:}getlastmodified')\
.text).ISO8601(), .text).ISO8601(),
document.getModificationDate().toZone('UTC').ISO8601()) document.bobobase_modification_time().toZone('UTC').ISO8601())
@expectedFailure @expectedFailure
def test_PROPFIND_on_document_bis(self): def test_PROPFIND_on_document_bis(self):
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# #
############################################################################## ##############################################################################
import transaction
import unittest import unittest
from Testing import ZopeTestCase from Testing import ZopeTestCase
...@@ -209,7 +210,7 @@ class TestArchive(InventoryAPITestCase): ...@@ -209,7 +210,7 @@ class TestArchive(InventoryAPITestCase):
portal_catalog.manage_renameObject(id=archive_id,new_id=archive_catalog_id) portal_catalog.manage_renameObject(id=archive_id,new_id=archive_catalog_id)
# Create an archive # Create an archive
archive = portal_archive.newContent(portal_typ="Archive", archive = portal_archive.newContent(portal_type="Archive",
catalog_id=self.archive_catalog_id, catalog_id=self.archive_catalog_id,
connection_id=self.archive_connection_id, connection_id=self.archive_connection_id,
deferred_connection_id=self.archive_deferred_connection_id, deferred_connection_id=self.archive_deferred_connection_id,
...@@ -221,7 +222,7 @@ class TestArchive(InventoryAPITestCase): ...@@ -221,7 +222,7 @@ class TestArchive(InventoryAPITestCase):
) )
archive.ready() archive.ready()
# Create an archive for destination catalog # Create an archive for destination catalog
dest = portal_archive.newContent(portal_typ="Archive", dest = portal_archive.newContent(portal_type="Archive",
catalog_id=self.new_catalog_id, catalog_id=self.new_catalog_id,
connection_id=self.new_connection_id, connection_id=self.new_connection_id,
deferred_connection_id=self.new_deferred_connection_id, deferred_connection_id=self.new_deferred_connection_id,
...@@ -231,6 +232,9 @@ class TestArchive(InventoryAPITestCase): ...@@ -231,6 +232,9 @@ class TestArchive(InventoryAPITestCase):
) )
dest.ready() dest.ready()
# make sure to commit to release any lock on tables
transaction.commit()
# Do archive # Do archive
portal_archive.manage_archive(destination_archive_id=dest.getId(), portal_archive.manage_archive(destination_archive_id=dest.getId(),
archive_id=archive.getId(), archive_id=archive.getId(),
......
...@@ -121,6 +121,7 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -121,6 +121,7 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
def beforeTearDown(self): def beforeTearDown(self):
# restore default_catalog # restore default_catalog
self.portal.portal_catalog.default_sql_catalog_id = 'erp5_mysql_innodb' self.portal.portal_catalog.default_sql_catalog_id = 'erp5_mysql_innodb'
self.portal.portal_catalog.hot_reindexing_state = None
# clear Modules # clear Modules
for module in [ self.getPersonModule(), for module in [ self.getPersonModule(),
self.getOrganisationModule(), self.getOrganisationModule(),
......
...@@ -2616,6 +2616,19 @@ return 1 ...@@ -2616,6 +2616,19 @@ return 1
self.assertEqual('archived', document_nolang_005.getValidationState()) self.assertEqual('archived', document_nolang_005.getValidationState())
self.assertEqual('shared_alive', document_nolang_006.getValidationState()) self.assertEqual('shared_alive', document_nolang_006.getValidationState())
def testFileWithNotDefinedMimeType(self):
upload_file = makeFileUpload('TEST-001-en.dummy')
kw = dict(file=upload_file, synchronous_metadata_discovery=True,
portal_type='File')
document = self.portal.Base_contribute(**kw)
document.setReference('TEST')
request = self.app.REQUEST
download_file = document.index_html(REQUEST=request, format=None)
self.assertEquals(download_file, 'foo\n')
document_format = None
self.assertEquals('TEST-001-en.dummy', document.getStandardFilename(
document_format))
class TestDocumentWithSecurity(TestDocumentMixin): class TestDocumentWithSecurity(TestDocumentMixin):
username = 'yusei' username = 'yusei'
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
# #
############################################################################## ##############################################################################
from Acquisition import aq_base
from Products.ERP5Type.PsycoWrapper import psyco from Products.ERP5Type.PsycoWrapper import psyco
from Base import Getter as BaseGetter, Setter as BaseSetter from Base import Getter as BaseGetter, Setter as BaseSetter
from warnings import warn from warnings import warn
...@@ -120,3 +121,16 @@ class TranslatedTitleGetter(TitleGetter): ...@@ -120,3 +121,16 @@ class TranslatedTitleGetter(TitleGetter):
return result.encode('utf8') return result.encode('utf8')
psyco.bind(__call__) psyco.bind(__call__)
def SerializeGetter(id, key):
def serialize(self):
"""Prevent concurrent transaction from changing of state of this object
"""
try:
self = aq_base(self).workflow_history
self = self[key]
except (AttributeError, KeyError):
pass
self._p_changed = 1
serialize.__name__ = id
return serialize
...@@ -518,7 +518,9 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow): ...@@ -518,7 +518,9 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
('getTranslated%s' % UpperCase(state_var), ('getTranslated%s' % UpperCase(state_var),
WorkflowState.TranslatedGetter), WorkflowState.TranslatedGetter),
('getTranslated%sTitle' % UpperCase(state_var), ('getTranslated%sTitle' % UpperCase(state_var),
WorkflowState.TranslatedTitleGetter)): WorkflowState.TranslatedTitleGetter),
('serialize%s' % UpperCase(state_var), WorkflowState.SerializeGetter),
):
if not hasattr(ptype_klass, method_id): if not hasattr(ptype_klass, method_id):
method = getter(method_id, wf_id) method = getter(method_id, wf_id)
# Attach to portal_type # Attach to portal_type
...@@ -1434,43 +1436,42 @@ class Base( CopyContainer, ...@@ -1434,43 +1436,42 @@ class Base( CopyContainer,
# We only change if the value is different # We only change if the value is different
# This may be very long... # This may be very long...
if force_update: if force_update:
update = True
old_value = None old_value = None
else: else:
try: try:
old_value = getProperty(key, evaluate=0) old_value = getProperty(key, evaluate=0)
except TypeError: except TypeError:
old_value = getProperty(key) old_value = getProperty(key)
update = old_value != kw[key] if old_value == kw[key]:
not_modified_list.append(key)
if update: continue
# We keep in a thread var the previous values
# this can be useful for interaction workflow to implement lookups # We keep in a thread var the previous values
# XXX If iteraction workflow script is triggered by edit and calls # this can be useful for interaction workflow to implement lookups
# edit itself, this is useless as the dict will be overwritten # XXX If iteraction workflow script is triggered by edit and calls
# If the keep_existing flag is set to 1, we do not update properties which are defined # edit itself, this is useless as the dict will be overwritten
if not keep_existing or not hasProperty(key): # If the keep_existing flag is set to 1, we do not update properties which are defined
if restricted: if keep_existing and hasProperty(key):
accessor_name = 'set' + UpperCase(key) continue
if accessor_name in restricted_method_set: if restricted:
# will raise Unauthorized when not allowed accessor_name = 'set' + UpperCase(key)
guarded_getattr(self, accessor_name) if accessor_name in restricted_method_set:
modified_property_dict[key] = old_value # will raise Unauthorized when not allowed
if key != 'id': guarded_getattr(self, accessor_name)
modified_object_list = _setProperty(key, kw[key]) modified_property_dict[key] = old_value
# BBB: if the setter does not return anything, assume if key != 'id':
# that self has been modified. modified_object_list = _setProperty(key, kw[key])
if modified_object_list is None: # BBB: if the setter does not return anything, assume
modified_object_list = (self,) # that self has been modified.
for o in modified_object_list: if modified_object_list is None:
# XXX using id is not quite nice, but getUID causes a modified_object_list = (self,)
# problem at the bootstrap of an ERP5 site. Therefore, for o in modified_object_list:
# objects themselves cannot be used as keys. # XXX using id is not quite nice, but getUID causes a
modified_object_dict[id(o)] = o # problem at the bootstrap of an ERP5 site. Therefore,
else: # objects themselves cannot be used as keys.
self.setId(kw['id'], reindex=reindex_object) modified_object_dict[id(o)] = o
else: else:
not_modified_list.append(key) self.setId(kw['id'], reindex=reindex_object)
return not_modified_list return not_modified_list
unmodified_key_list = setChangedPropertyList(unordered_key_list) unmodified_key_list = setChangedPropertyList(unordered_key_list)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
############################################################################## ##############################################################################
import string import string
import re
# Import everything right now, not after # Import everything right now, not after
# or new patch will not work # or new patch will not work
...@@ -21,6 +22,7 @@ from Shared.DC.xml.ppml import * ...@@ -21,6 +22,7 @@ from Shared.DC.xml.ppml import *
from Shared.DC.xml import ppml from Shared.DC.xml import ppml
from marshal import dumps as mdumps from marshal import dumps as mdumps
from zLOG import LOG
# For converting to a more readable expression. # For converting to a more readable expression.
reprs = {} reprs = {}
...@@ -305,14 +307,34 @@ class Object(Sequence): ...@@ -305,14 +307,34 @@ class Object(Sequence):
ppml.Object = Object ppml.Object = Object
blanck_line_expression = re.compile('^ +$')
# For optmization. # For optmization.
class NoBlanks: class NoBlanks:
previous_stack_end = None
previous_discarded_data = None
def handle_data(self, data): def handle_data(self, data):
if data.strip(): if data.strip():
# Horrible conditions to try fixing some weird removal of spaces.
# It happened that javascript files with a line like
# " ];\n" was replaced by "];\n", so the indent was lost.
# Indeed the parser was calling this handle_data function first
# for " ", then for "];". So original code was dropping the " ".
# Disabling the above if was the initial idea, but it give
# other troubles, so such conditions were introduced.
if data.startswith(']') \
and self.previous_discarded_data \
and blanck_line_expression.match(self.previous_discarded_data) \
and self._stack[-1] == self.previous_stack_end:
data = self.previous_discarded_data + data
if isinstance(data, unicode): if isinstance(data, unicode):
data = data.encode('raw_unicode_escape') data = data.encode('raw_unicode_escape')
self.append(data) self.append(data)
else:
self.previous_stack_end = self._stack[-1]
self.previous_discarded_data = data
ppml.NoBlanks = NoBlanks ppml.NoBlanks = NoBlanks
......
...@@ -335,6 +335,7 @@ class ERP5TypeFunctionalTestCase(ERP5TypeTestCase): ...@@ -335,6 +335,7 @@ class ERP5TypeFunctionalTestCase(ERP5TypeTestCase):
return "Zelenium" return "Zelenium"
def afterSetUp(self): def afterSetUp(self):
super(ERP5TypeFunctionalTestCase, self).afterSetUp()
# create browser_id_manager # create browser_id_manager
if not "browser_id_manager" in self.portal.objectIds(): if not "browser_id_manager" in self.portal.objectIds():
self.portal.manage_addProduct['Sessions'].constructBrowserIdManager() self.portal.manage_addProduct['Sessions'].constructBrowserIdManager()
......
...@@ -75,11 +75,19 @@ install_product_quiet = 1 ...@@ -75,11 +75,19 @@ install_product_quiet = 1
# Quiet messages when installing business templates # Quiet messages when installing business templates
install_bt5_quiet = 0 install_bt5_quiet = 0
from App.config import getConfiguration
config = getConfiguration()
instancehome = config.instancehome
# Make sure we can call manage_debug_threads on a test instance
if getattr(config, 'product_config', None) is None:
config.product_config = {}
config.product_config['deadlockdebugger'] = {'dump_url':'/manage_debug_threads'}
import OFS.Application import OFS.Application
OFS.Application.import_products() OFS.Application.import_products()
# Std Zope Products # Std Zope Products
ZopeTestCase.installProduct('ExtFile', quiet=install_product_quiet)
ZopeTestCase.installProduct('Photo', quiet=install_product_quiet) ZopeTestCase.installProduct('Photo', quiet=install_product_quiet)
ZopeTestCase.installProduct('Formulator', quiet=install_product_quiet) ZopeTestCase.installProduct('Formulator', quiet=install_product_quiet)
ZopeTestCase.installProduct('FCKeditor', quiet=install_product_quiet) ZopeTestCase.installProduct('FCKeditor', quiet=install_product_quiet)
...@@ -194,9 +202,6 @@ ZopeTestCase.installProduct('ParsedXML', quiet=install_product_quiet) ...@@ -194,9 +202,6 @@ ZopeTestCase.installProduct('ParsedXML', quiet=install_product_quiet)
# Install everything else which looks like related to ERP5 # Install everything else which looks like related to ERP5
from OFS.Application import get_products from OFS.Application import get_products
from App.config import getConfiguration
instancehome = getConfiguration().instancehome
for priority, product_name, index, product_dir in get_products(): for priority, product_name, index, product_dir in get_products():
# XXX very heuristic # XXX very heuristic
if os.path.isdir(os.path.join(product_dir, product_name, 'Document')) \ if os.path.isdir(os.path.join(product_dir, product_name, 'Document')) \
...@@ -1027,10 +1032,6 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin): ...@@ -1027,10 +1032,6 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin):
if len(setup_done) == 1: # make sure it is run only once if len(setup_done) == 1: # make sure it is run only once
self._setUpDummyMailHost() self._setUpDummyMailHost()
try:
from Products import DeadlockDebugger
except ImportError:
pass
self.serverhost, self.serverport = self.startZServer(verbose=True) self.serverhost, self.serverport = self.startZServer(verbose=True)
self._registerNode(distributing=1, processing=1) self._registerNode(distributing=1, processing=1)
......
...@@ -213,7 +213,8 @@ class ERP5TypeTestSuite(TestSuite): ...@@ -213,7 +213,8 @@ class ERP5TypeTestSuite(TestSuite):
(instance_number-1) * self.mysql_db_count: (instance_number-1) * self.mysql_db_count:
(instance_number) * self.mysql_db_count] (instance_number) * self.mysql_db_count]
if len(mysql_db_list) > 1: if len(mysql_db_list) > 1:
kw['extra_sql_connection_string_list'] = ','.join(mysql_db_list[1:]) args = ('--extra_sql_connection_string_list=%s' % \
','.join(mysql_db_list[1:]),) + args
try: try:
runUnitTest = os.environ.get('RUN_UNIT_TEST', runUnitTest = os.environ.get('RUN_UNIT_TEST',
'runUnitTest') 'runUnitTest')
......
...@@ -224,6 +224,10 @@ class ProcessingNodeTestCase(backportUnittest.TestCase, ZopeTestCase.TestCase): ...@@ -224,6 +224,10 @@ class ProcessingNodeTestCase(backportUnittest.TestCase, ZopeTestCase.TestCase):
count -= 1 count -= 1
if count == 0 or (message_count and set([x.processing_node for x in if count == 0 or (message_count and set([x.processing_node for x in
message_list]).issubset(set([-2, -3]))): message_list]).issubset(set([-2, -3]))):
# We're about to raise RuntimeError, but maybe we've reached
# the stop condition, so check just once more:
if stop_condition(message_list):
break
error_message = 'tic is looping forever. ' error_message = 'tic is looping forever. '
try: try:
self.assertNoPendingMessage() self.assertNoPendingMessage()
......
...@@ -39,7 +39,7 @@ def safeRpcCall(function, *args): ...@@ -39,7 +39,7 @@ def safeRpcCall(function, *args):
while True: while True:
try: try:
return function(*xmlrpc_arg_list) return function(*xmlrpc_arg_list)
except (socket.error, xmlrpclib.ProtocolError), e: except (socket.error, xmlrpclib.ProtocolError, xmlrpclib.Fault), e:
print >>sys.stderr, e print >>sys.stderr, e
pprint.pprint(args, file(function._Method__name, 'w')) pprint.pprint(args, file(function._Method__name, 'w'))
time.sleep(retry) time.sleep(retry)
......
...@@ -1246,34 +1246,39 @@ from Products.ERP5Type.mixin.component import ComponentMixin ...@@ -1246,34 +1246,39 @@ from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase
from App.config import getConfiguration from App.config import getConfiguration
class _TestZodbComponent(SecurityTestCase): class TestDeveloperMixin:
"""
Abstract class which defined convenient methods used by any Component Test
and tests ran for all Component Test classes
"""
__metaclass__ = abc.ABCMeta
def getBusinessTemplateList(self):
return ('erp5_base',)
def login(self, user_name='ERP5TypeTestCase', quiet=0): def login(self, user_name='ERP5TypeTestCase', quiet=0):
""" """
Make sure that the test user has Developer Role, otherwise the user cannot Make sure that the test user has Developer Role, otherwise the user cannot
do anything on Components... do anything on Components...
""" """
product_config = getattr(getConfiguration(), 'product_config', None) config = getConfiguration()
product_config = getattr(config, 'product_config', None)
if product_config is None: if product_config is None:
product_config = config.product_config = {}
if product_config.get('erp5') is None:
class DummyDeveloperConfig(object): class DummyDeveloperConfig(object):
pass pass
dummy_developer_config = DummyDeveloperConfig() dummy_developer_config = DummyDeveloperConfig()
dummy_developer_config.developer_list = [user_name] dummy_developer_config.developer_list = [user_name]
getConfiguration().product_config = {'erp5': dummy_developer_config} product_config['erp5'] = dummy_developer_config
elif user_name not in product_config['erp5'].developer_list: elif user_name not in product_config['erp5'].developer_list:
product_config['erp5'].developer_list.append(user_name) product_config['erp5'].developer_list.append(user_name)
return super(_TestZodbComponent, self).login(user_name, quiet) return ERP5TypeTestCase.login(self, user_name, quiet)
class _TestZodbComponent(TestDeveloperMixin, SecurityTestCase):
"""
Abstract class which defined convenient methods used by any Component Test
and tests ran for all Component Test classes
"""
__metaclass__ = abc.ABCMeta
def getBusinessTemplateList(self):
return ('erp5_base',)
def afterSetUp(self): def afterSetUp(self):
self._component_tool = self.getPortal().portal_components self._component_tool = self.getPortal().portal_components
......
...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages ...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import glob import glob
import os import os
version = '0.4.1' version = '0.4.3'
name = 'erp5.util' name = 'erp5.util'
long_description = open("README.erp5.util.txt").read() + "\n" long_description = open("README.erp5.util.txt").read() + "\n"
......
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