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
=======
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)
----------------
......
......@@ -18,6 +18,7 @@ def generateBarcodeImage(self, barcode_type, data):
elif barcode_type == 'code128':
from hubarcode.code128 import Code128Encoder
encoder = Code128Encoder(data)
encoder.text = '' # get barcode image only
output = encoder.get_imagedata()
elif barcode_type == 'qrcode':
import qrcode
......
......@@ -57,7 +57,10 @@ event = portal.restrictedTraverse(event_relative_url)\n
subject = event.getTitle()\n
body = event.getTextContent()\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
else:\n
from_url = portal.portal_preferences.getPreferredEventSenderEmail()\n
......
1020
\ No newline at end of file
1022
\ No newline at end of file
......@@ -110,8 +110,15 @@ if portal_preferences.getPreferredCredentialAlarmAutomaticCall():\n
message_str = "Credential Request Created."\n
else:\n
if portal_preferences.isPreferredEmailVerificationCheck():\n
# Send email to subscriber in order to check email\'s address\n
credential_request.activate(activity=\'SQLQueue\').CredentialRequest_sendSubmittedNotification(\n
# after_path_and_method_id argument is used below to not activate when\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
notification_reference=\'erp5-subscription.notification\')\n
message_str = "Thanks for your registration. You will be receive an email to activate your account."\n
......
412
\ No newline at end of file
413
\ No newline at end of file
......@@ -73,6 +73,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Acknowledgement</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -80,6 +80,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -80,6 +80,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -80,6 +80,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -75,6 +75,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Ticket</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -80,6 +80,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -80,6 +80,10 @@
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Event</string> </value>
</item>
</dictionary>
</pickle>
</record>
......
......@@ -99,22 +99,31 @@ elif direction == \'incoming\':\n
else:\n
raise NotImplementedError, \'The specified direction is not handled: %r\' % (direction,)\n
\n
event_kw = {}\n
event_kw[\'portal_type\'] = portal_type\n
event_kw[\'title\'] = title\n
event_kw[\'resource\'] = resource\n
event_kw[\'source\'] = source_url\n
event_kw[\'source_section\'] = source_section_url\n
event_kw[\'destination\'] = destination_url\n
event_kw[\'destination_section\'] = destination_section_url\n
event_kw[\'start_date\'] = start_date\n
event_kw[\'follow_up\'] = follow_up\n
event_kw[\'text_content\'] = text_content\n
event_kw[\'content_type\'] = portal.portal_preferences.getPreferredTextEditor() and \'text/html\' or \'text/plain\'\n
\n
event_kw = {\n
\'portal_type\' : portal_type,\n
\'title\' : title,\n
\'resource\' : resource,\n
\'source\' : source_url,\n
\'source_section\' : source_section_url,\n
\'destination\' : destination_url,\n
\'destination_section\' : destination_section_url,\n
\'start_date\' : start_date,\n
\'follow_up\' : follow_up,\n
\'text_content\' : text_content,\n
\'content_type\' : portal.portal_preferences.getPreferredTextEditor() and \'text/html\' or \'text/plain\',\n
}\n
# Create event\n
module = portal.getDefaultModule(portal_type=portal_type)\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
if batch_mode:\n
return event\n
......@@ -126,7 +135,7 @@ event.Base_redirect(keep_items={\'portal_status_message\': message})\n
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -82,6 +82,7 @@
<value>
<list>
<string>your_text_content</string>
<string>your_keep_draft</string>
</list>
</value>
</item>
......@@ -99,6 +100,8 @@
<string>your_portal_type</string>
<string>your_resource</string>
<string>your_direction</string>
<string>your_source</string>
<string>your_destination</string>
</list>
</value>
</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
operator_list = event.getDestinationList()\n
try:\n
source_value = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if source_value:\n
operator_list.append(source_value.getRelativeUrl())\n
except ValueError:\n
source_value = None\n
if source_value is not None:\n
source_section_value = source_value.getDefaultCareerSubordinationValue()\n
operator_list.append(source_value.getRelativeUrl())\n
else:\n
source_section_value = None\n
source_section = portal.portal_preferences.getPreferredSection(),\n
\n
\n
resource_kw = {\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
module = portal.getDefaultModule(follow_up_ticket_type)\n
ticket = module.newContent(\n
......@@ -71,20 +82,25 @@ ticket = module.newContent(\n
title=follow_up_ticket_title,\n
start_date=event.getStartDate(),\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_value=source_value,\n
source_section_value=source_section_value,\n
source_section=source_section,\n
resource=resource,\n
)\n
\n
follow_up_list = event.getFollowUpList()\n
follow_up_list.append(ticket.getRelativeUrl())\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>
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -51,17 +51,22 @@
<item>
<key> <string>_body</string> </key>
<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
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
</string> </value>
</item>
<item>
<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>
<key> <string>description</string> </key>
......
......@@ -95,6 +95,11 @@
<list>
<string>your_follow_up_ticket_title</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>
</value>
</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 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>default</string>
<string>required</string>
</list>
</value>
......@@ -52,6 +53,12 @@
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
......@@ -60,6 +67,10 @@
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
......@@ -71,6 +82,10 @@
<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_title</string> </value>
......@@ -93,4 +108,17 @@
</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/getTitle</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -148,7 +148,9 @@
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>external_validator</string> </key>
......@@ -304,4 +306,17 @@
</dictionary>
</pickle>
</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>
......@@ -54,18 +54,21 @@
arrow = portal.portal_property_sheets.get("Arrow")\n
\n
value_list = [(\'\', \'\'),]\n
value_list_append = value_list.append\n
\n
# add current user\n
user = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if user is not None:\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
value_list_append((user.getTitle(), user.getRelativeUrl()))\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
value_list.sort(key=lambda x: x[0])\n
\n
return value_list\n
</string> </value>
......
......@@ -59,23 +59,26 @@ from zExceptions import Unauthorized\n
from Products.ERP5Type.Cache import CachingMethod\n
portal = context.getPortalObject()\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
\'use_uid\': portal.portal_categories.getCategoryUid(portal.portal_preferences.getPreference(preference_id), base_category=\'use\'),\n
\'validation_state\': \'validated\',\n
\'sort_on\': \'title\'}\n
\n
def getResourceItemList():\n
def getResourceItemList(portal_type):\n
return [(\'\', \'\')] + [(result.getTitle(), result.getRelativeUrl()) for result in portal.portal_catalog(**sql_kw)]\n
\n
getResourceItemList = CachingMethod(getResourceItemList, \n
id=(script.id, context.Localizer.get_selected_language()), \n
cache_factory=\'erp5_ui_long\')\n
\n
result_list = getResourceItemList()[:]\n
result_list = getResourceItemList(portal_type)[:]\n
\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
resource_value = portal.portal_categories.getCategoryValue(context.getResource(), base_category=\'resource\')\n
if resource_value is not None:\n
......@@ -94,7 +97,7 @@ return result_list\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>portal_type=None, include_context=True</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -77,14 +77,15 @@ event = module.newContent(portal_type=portal_type, \n
follow_up=context.getRelativeUrl())\n
\n
# Trigger appropriate workflow action\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
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
# Redirect to event\n
portal_status_message = translateString(\n
......@@ -95,7 +96,7 @@ return event.Base_redirect(\'view\', keep_items = dict(portal_status_message=por
</item>
<item>
<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>
<key> <string>id</string> </key>
......
......@@ -76,6 +76,7 @@
<value>
<list>
<string>your_text_content</string>
<string>your_keep_draft</string>
</list>
</value>
</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
\ No newline at end of file
593
\ No newline at end of file
......@@ -68,6 +68,8 @@
<key> <string>Add portal content</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
......@@ -76,6 +78,8 @@
<key> <string>Delete objects</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
......@@ -84,6 +88,8 @@
<key> <string>Modify portal content</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
......
9
\ No newline at end of file
10
\ 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
* Extract messages from constraints in ZODB property sheets for POT.
......
665
\ No newline at end of file
666
\ No newline at end of file
......@@ -34,4 +34,5 @@ Glossary Term | view
Preference | vcs
Template Tool | bt_vcs_history
Template Tool | search_portal_type
Types Tool | role_information_list_view
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
\ No newline at end of file
2
\ No newline at end of file
......@@ -12,7 +12,7 @@
</item>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34058349.94</string> </value>
<value> <string>ts34651695.58</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
......@@ -75,6 +75,16 @@ var LocalStorageCachePlugin = {\n
}\n
\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
hasLocalStorage: function() {\n
/*\n
......@@ -91,6 +101,7 @@ var Cache = {\n
\n
get: function(cache_id, default_value){\n
/* Get cache key value */\n
cache_id = Cache.getCacheId(cache_id);\n
if (Cache.hasLocalStorage()){\n
return LocalStorageCachePlugin.get(cache_id, default_value);}\n
else{\n
......@@ -99,6 +110,7 @@ var Cache = {\n
\n
set: function(cache_id, data){\n
/* Set cache key value */\n
cache_id = Cache.getCacheId(cache_id);\n
if (Cache.hasLocalStorage()){\n
LocalStorageCachePlugin.set(cache_id, data);}\n
else{\n
......@@ -300,8 +312,9 @@ var Form = {\n
column_title_list.push(title);\n
column = {\'name\': index,\n
\'index\': index,\n
\'width\': 150,\n
\'align\': \'left\'}\n
\'width\': 185,\n
\'align\': \'left\'\n
}\n
colModel.push(column);\n
});\n
\n
......@@ -314,6 +327,11 @@ var Form = {\n
sortname: \'id\',\n
viewrecords: true,\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
listbox_table.jqGrid(\'navGrid\', \'#\'+navigation_id, {edit:false,add:false,del:false});\n
return listbox_table;\n
......@@ -535,7 +553,7 @@ var RenderJs = {\n
</item>
<item>
<key> <string>size</string> </key>
<value> <int>18537</int> </value>
<value> <int>19314</int> </value>
</item>
<item>
<key> <string>title</string> </key>
......
2
\ No newline at end of file
5
\ No newline at end of file
......@@ -58,17 +58,20 @@
breadcrumb_list python: current_web_section.getBreadcrumbItemList(current_web_document);">\n
<ul class="breadcrumb">\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
title python:breadcrumb[2];"\n
tal:content="python:breadcrumb[0]">Title</a>\n
<tal:block tal:condition="not: repeat/breadcrumb/end">\n
<img class="breadcrumb_separator" src="../km_img/crumb.png" alt="&gt;"\n
tal:attributes="src string:${portal_path}/km_img/crumb.png"/>\n
<tal:block tal:define="is_last repeat/breadcrumb/end">\n
<a href="#"\n
tal:attributes="href python:current_web_section.getPermanentURL(breadcrumb[1]);\n
title python:breadcrumb[2];\n
class python: test(is_last, \'last-breadcrumb\', \'breadcrumb\')"\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
</li>\n
</ul>\n
</tal:block>\n
</tal:block>
]]></unicode> </value>
</item>
......@@ -86,7 +89,7 @@
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
<value> <string>iso-8859-15</string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
......@@ -122,6 +122,7 @@
<list>
<string>left_menu_widget</string>
<string>listbox_action_widget</string>
<string>analytics_widget</string>
</list>
</value>
</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 @@
<tal:block tal:repeat="menu_item menu_item_list">\n
\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
<tal:block tal:replace="menu_item/compact_translated_title | menu_item/translated_title">Menu</tal:block>\n
</a>\n
......
......@@ -90,6 +90,7 @@
<value>
<list>
<string>footer_widget</string>
<string>analytics_widget</string>
</list>
</value>
</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 @@
<value>
<list>
<string>footer_widget</string>
<string>analytics_widget</string>
</list>
</value>
</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 @@
<value>
<list>
<string>footer_widget</string>
<string>analytics_widget</string>
</list>
</value>
</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
<tal:block tal:condition="preferred_html_style_developper_mode">\n
<tal:block metal:use-macro="developper_shortcut_render/macros/form" />\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:define="gid group/gid;">\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
</fieldset>\n
</tal:block>\n
</tal:block>\n
</div>\n
<p class="clear"></p>\n
</tal:block>\n
</tal:block>\n
</tal:block>\n
</tal:block>
]]></unicode> </value>
</item>
......@@ -108,7 +109,7 @@ It is possible to specify a group id and a group title by naming a group followi
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
<value> <string>iso-8859-15</string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
......@@ -84,7 +84,6 @@ div {\n
margin:0;\n
padding:0;\n
float:none;\n
width:100%;\n
position:relative;\n
}\n
\n
......@@ -171,7 +170,11 @@ fieldset.hidden_fieldset { \n
padding-bottom:35px;\n
padding-top: 5px;\n
}\n
\n
#master,\n
.document,\n
.content{\n
width:100%;\n
}\n
#wrapper_right{\n
float: left;\n
width:22.5%;\n
......@@ -227,7 +230,7 @@ div#wrapper_headline div.header_title {\n
}\n
\n
#wrapper_path {\n
float:left;\n
/* float:left; */\n
width: 100%;\n
}\n
\n
......@@ -249,11 +252,14 @@ div#wrapper_headline div.header_title {\n
height:100%;\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
padding-right: 0px;\n
}\n
\n
\n
\n
\n
#menu ul li.non-collapse-menu{\n
background: none;\n
padding-right: 0px;\n
......@@ -567,10 +573,12 @@ fieldset.right{\n
*/\n
\n
fieldset.registration {\n
width:36%;\n
width:auto;\n
background-color: #FFFFFF;\n
margin-right: 0.5%;\n
height: auto;\n
margin-bottom:2em;\n
padding:10px;\n
}\n
\n
\n
......@@ -934,7 +942,7 @@ fieldset.right h4 {\n
padding:5px;\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
margin:0 0 0.3em 2px;\n
padding:0 0 0 12px;\n
......@@ -1075,7 +1083,7 @@ table tbody tr td {\n
top:0;\n
padding-top:30px;\n
left:0;\n
width:205px;\n
width:auto;\n
opacity: <tal:block tal:replace="menu_opacity">0.80</tal:block>;\n
}\n
\n
......
1854
\ No newline at end of file
1860
\ No newline at end of file
......@@ -92,7 +92,7 @@
<dictionary>
<item>
<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>
</dictionary>
</pickle>
......
......@@ -11,7 +11,6 @@
<value>
<list>
<string>description</string>
<string>enabled</string>
<string>title</string>
<string>whitespace_preserve</string>
</list>
......@@ -56,10 +55,8 @@
<value>
<dictionary>
<item>
<key> <string>enabled</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
......@@ -96,10 +93,6 @@
<key> <string>description</string> </key>
<value> <string>Name of the Web Page you would like to review.</string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
......@@ -130,17 +123,4 @@
</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>not:here/isExternalDocument</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -82,6 +82,7 @@
<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/sale_packing_list_builder</string>
<string>delivery_builder/portal_deliveries/task_report_builder</string>
</tuple>
</value>
</item>
......
34
\ No newline at end of file
35
\ No newline at end of file
<module>
<id>foo_module</id>
<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'>
<name>View</name>
<role>Assignee</role>
......@@ -9,6 +81,15 @@
<role>Auditor</role>
<role>Manager</role>
</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>
<portal_type>Foo Module</portal_type>
<title>Foos</title>
......
683
\ No newline at end of file
683
##############################################################################
#
# 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
class SlapOSControler(object):
def __init__(self, config, log, process_group_pid_set=None,
slapproxy_log=None):
def __init__(self, config, log,
slapproxy_log=None, process_manager=None, reset_software=False):
log('SlapOSControler, initialize, reset_software: %r' % reset_software)
self.log = log
self.config = config
self.process_manager = process_manager
# By erasing everything, we make sure that we are able to "update"
# existing profiles. This is quite dirty way to do updates...
if os.path.exists(config['proxy_database']):
......@@ -51,7 +53,7 @@ class SlapOSControler(object):
kwargs['stderr'] = slapproxy_log_fp
proxy = subprocess.Popen([config['slapproxy_binary'],
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
# connections
time.sleep(10)
......@@ -63,21 +65,33 @@ class SlapOSControler(object):
self.software_profile,
computer_guid=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):
# create partition and configure computer
# 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
partition_reference = '%s-%s' %(config['partition_reference'], i)
partition_path = os.path.join(config['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)
partition_path = os.path.join(instance_root, partition_reference)
os.mkdir(partition_path)
os.chmod(partition_path, 0750)
computer.updateConfiguration(xml_marshaller.xml_marshaller.dumps({
'address': config['ipv4_address'],
'instance_root': config['instance_root'],
'instance_root': instance_root,
'netmask': '255.255.255.255',
'partition_list': [{'address_list': [{'addr': config['ipv4_address'],
'netmask': '255.255.255.255'},
......@@ -91,37 +105,23 @@ class SlapOSControler(object):
'reference': config['computer_id'],
'software_root': config['software_root']}))
def runSoftwareRelease(self, config, environment, process_group_pid_set=None,
stdout=None, stderr=None):
def spawn(self, *args, **kw):
return self.process_manager.spawn(*args, **kw)
def runSoftwareRelease(self, config, environment):
self.log("SlapOSControler.runSoftwareRelease")
cpu_count = os.sysconf("SC_NPROCESSORS_ONLN")
os.putenv('MAKEFLAGS', '-j%s' % cpu_count)
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)
# so be tolerant and run it a few times before giving up
for runs in range(0, MAX_SR_RETRIES):
slapgrid = subprocess.Popen(command,
stdout=stdout, stderr=stderr,
close_fds=True, preexec_fn=os.setsid)
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()
status_dict = self.spawn(config['slapgrid_software_binary'], '-v', '-c',
config['slapos_config'], raise_error_if_fail=False,
log_prefix='slapgrid_sr', get_output=False)
return status_dict
def runComputerPartition(self, config, environment,
process_group_pid_set=None,
stdout=None, stderr=None):
self.log("SlapOSControler.runComputerPartition")
slap = slapos.slap.slap()
......@@ -130,26 +130,12 @@ class SlapOSControler(object):
slap.registerOpenOrder().request(self.software_profile,
partition_reference='testing partition',
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
# this not always is required but curently no way to know how "tree" of partitions
# may "expand"
for runs in range(0, MAX_PARTIONS):
slapgrid = subprocess.Popen(command,
stdout=stdout, stderr=stderr,
close_fds=True, preexec_fn=os.setsid)
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()
status_dict = self.spawn(config['slapgrid_partition_binary'], '-v', '-c',
config['slapos_config'], raise_error_if_fail=False,
log_prefix='slapgrid_cp', get_output=False)
return status_dict
......@@ -36,48 +36,6 @@ from testnode import SubprocessError
SVN_UP_REV = re.compile(r'^(?:At|Updated to) revision (\d+).$')
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'
SVN_TYPE = 'svn'
......@@ -88,13 +46,14 @@ class Updater(object):
stdin = file(os.devnull)
def __init__(self, repository_path, log, revision=None, git_binary=None,
realtime_output=True):
realtime_output=True, process_manager=None):
self.log = log
self.revision = revision
self._path_list = []
self.repository_path = repository_path
self.git_binary = git_binary
self.realtime_output = realtime_output
self.process_manager = process_manager
def getRepositoryPath(self):
return self.repository_path
......@@ -128,25 +87,10 @@ class Updater(object):
raise
def spawn(self, *args, **kw):
quiet = kw.pop('quiet', False)
env = kw and dict(os.environ, **kw) or None
command = format_command(*args, **kw)
self.log('$ ' + command)
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
return self.process_manager.spawn(*args,
log_prefix='git',
cwd=self.getRepositoryPath(),
**kw)
def _git(self, *args, **kw):
return self.spawn(self.git_binary, *args, **kw)['stdout'].strip()
......
......@@ -30,12 +30,12 @@ import logging
import os
import pkg_resources
import testnode
from testnode import TestNode
CONFIG = dict(
computer_id='COMPUTER',
partition_reference='test0',
)
CONFIG = {
'computer_id': 'COMPUTER',
'partition_reference': 'test0',
}
def main(*args):
parser = argparse.ArgumentParser()
......@@ -48,15 +48,21 @@ def main(*args):
parsed_argument = parser.parse_args(list(args))
else:
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')
if parsed_argument.console or parsed_argument.logfile:
logger.setLevel(logging.INFO)
if parsed_argument.console:
logger.addHandler(logging.StreamHandler())
logger.info('Activated console output.')
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)
CONFIG['log_file'] = parsed_argument.logfile
else:
logger.addHandler(logging.NullHandler())
CONFIG['logger'] = logger.info
......@@ -64,40 +70,33 @@ def main(*args):
# do not change case of option keys
config.optionxform = str
config.readfp(parsed_argument.configuration_file[0])
def geto(o):
return config.get('testnode', o)
CONFIG['slapos_directory'] = geto('slapos_directory')
CONFIG['working_directory'] = geto('working_directory')
CONFIG['test_suite_directory'] = geto('test_suite_directory')
CONFIG['log_directory'] = geto('log_directory')
CONFIG['run_directory'] = geto('run_directory')
for d in CONFIG['slapos_directory'], CONFIG['working_directory'], \
CONFIG['test_suite_directory'], CONFIG['log_directory'], \
CONFIG['run_directory']:
for key in ('slapos_directory', 'working_directory', 'test_suite_directory',
'log_directory', 'run_directory', 'proxy_host', 'proxy_port',
'git_binary', 'zip_binary', 'test_suite_title', 'test_node_title',
'test_suite', 'project_title', 'node_quantity', 'ipv4_address',
'ipv6_address', 'test_suite_master_url', 'slapgrid_partition_binary',
'slapgrid_software_binary', 'slapproxy_binary'):
CONFIG[key] = config.get('testnode', key)
for key in ('slapos_directory', 'working_directory', 'test_suite_directory',
'log_directory', 'run_directory'):
d = CONFIG[key]
if not os.path.isdir(d):
raise ValueError('Directory %r does not exists.' % d)
CONFIG['software_root'] = os.path.join(CONFIG['slapos_directory'],
'software')
CONFIG['instance_root'] = os.path.join(CONFIG['slapos_directory'],
'instance')
for d in CONFIG['software_root'], CONFIG['instance_root']:
if not os.path.lexists(d):
os.mkdir(d)
CONFIG['proxy_database'] = os.path.join(CONFIG['slapos_directory'],
'proxy.db')
CONFIG['proxy_host'] = geto('proxy_host')
CONFIG['proxy_port'] = geto('proxy_port')
slapos_directory = CONFIG['slapos_directory']
CONFIG['software_root'] = software_root = os.path.join(slapos_directory,
'software')
CONFIG['instance_root'] = instance_root = os.path.join(slapos_directory,
'instance')
CONFIG['proxy_database'] = os.path.join(slapos_directory, 'proxy.db')
CONFIG['slapos_config'] = slapos_config = os.path.join(slapos_directory,
'slapos.cfg')
if not os.path.lexists(software_root):
os.mkdir(software_root)
CONFIG['master_url'] = 'http://%s:%s' % (CONFIG['proxy_host'],
CONFIG['proxy_port'])
slapos_config = pkg_resources.resource_string('erp5.util.testnode',
'template/slapos.cfg.in')
slapos_config = slapos_config % CONFIG
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'],
open(slapos_config, 'w').write(pkg_resources.resource_string(
'erp5.util.testnode', 'template/slapos.cfg.in') % CONFIG)
CONFIG['runTestSuite'] = os.path.join(instance_root,
CONFIG['partition_reference'], 'bin', 'runTestSuite')
# generate vcs_repository_list
......@@ -113,24 +112,16 @@ def main(*args):
CONFIG['bt5_path'] = bt5_path
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():
bot_environment = dict(config.items('bot_environment'))
else:
bot_environment = {}
CONFIG['bot_environment'] = bot_environment
CONFIG['environment'] = dict(config.items('environment'))
CONFIG['slapproxy_binary'] = geto('slapproxy_binary')
instance_dict = {}
if 'instance_dict' in config.sections():
instance_dict = dict(config.items('instance_dict'))
else:
instance_dict = {}
CONFIG['instance_dict'] = instance_dict
testnode.run(CONFIG)
testnode = TestNode(logger.info, CONFIG)
testnode.run()
......@@ -24,8 +24,8 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from datetime import datetime
import os
import pprint
import signal
import socket
import subprocess
......@@ -34,121 +34,164 @@ import time
import xmlrpclib
import glob
import SlapOSControler
import logging
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
import threading
from ProcessManager import SubprocessError, ProcessManager, CancellationError
from Updater import Updater
supervisord_pid_file = None
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)
DEFAULT_SLEEP_TIMEOUT = 120 # time in seconds to sleep
signal.signal(signal.SIGTERM, sigterm_handler)
supervisord_pid_file = None
def safeRpcCall(proxy, function_id, *args):
# XXX: this method will try infinitive calls to backend
def safeRpcCall(log, proxy, function_id, retry, *args):
# this method will try infinitive calls to backend
# this can cause testnode to looked "stalled"
retry = 64
retry_time = 64
while True:
try:
# 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
log('safeRpcCall called with method : %s' % function_id)
function = getattr(proxy, function_id)
return function(*args)
except (socket.error, xmlrpclib.ProtocolError, xmlrpclib.Fault), e:
logging.warning(e)
pprint.pprint(args, file(function._Method__name, 'w'))
time.sleep(retry)
retry += retry >> 1
log('Exception in safeRpcCall when trying %s with %r' % (function_id, args),
exc_info=sys.exc_info())
if not(retry):
return
log('will retry safeRpcCall in %i seconds' % retry_time)
time.sleep(retry_time)
retry_time += retry_time >> 1
def getInputOutputFileList(config, command_name):
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)
class RemoteLogger(object):
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():
for pgpid in process_group_pid_set:
try:
os.killpg(pgpid, signal.SIGTERM)
except:
pass
try:
if os.path.exists(supervisord_pid_file):
os.kill(int(open(supervisord_pid_file).read().strip()), signal.SIGTERM)
except:
pass
def update(self, portal, test_result_path):
self.portal = portal
self.test_result_path = test_result_path
def getSize(self):
erp5testnode_log = open(self.log_file, 'r')
erp5testnode_log.seek(0, 2)
size = erp5testnode_log.tell()
erp5testnode_log.close()
return size
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'
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
# Write our own software.cfg to use the local repository
custom_profile_path = os.path.join(config['working_directory'], 'software.cfg')
config['custom_profile_path'] = custom_profile_path
vcs_repository_list = config['vcs_repository_list']
profile_content = ''
assert len(vcs_repository_list), "we must have at least one repository"
try:
# 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:
pass
else:
vcs_repository_list[0][PROFILE_PATH_KEY] = profile_path
profile_path_count = 0
for vcs_repository in vcs_repository_list:
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
class TestNode(object):
def __init__(self, log, config):
self.log = log
self.config = config
self.process_manager = ProcessManager(log)
self.process_manager.supervisord_pid_file = os.path.join(config['instance_root'], 'var', 'run',
'supervisord.pid')
def run(self):
log = self.log
process_manager = self.process_manager
config = self.config
slapgrid = None
previous_revision = None
run_software = True
# Write our own software.cfg to use the local repository
custom_profile_path = os.path.join(config['working_directory'], 'software.cfg')
config['custom_profile_path'] = custom_profile_path
vcs_repository_list = config['vcs_repository_list']
profile_content = ''
assert len(vcs_repository_list), "we must have at least one repository"
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:
pass
else:
profile_path_count += 1
if profile_path_count > 1:
raise ValueError(PROFILE_PATH_KEY + ' defined more than once')
profile_content = """
vcs_repository_list[0][PROFILE_PATH_KEY] = profile_path
profile_path_count = 0
for vcs_repository in vcs_repository_list:
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]
extends = %(software_config_path)s
""" % {'software_config_path': os.path.join(repository_path, profile_path)}
if not(buildout_section_id is None):
profile_content += """
if not(buildout_section_id is None):
profile_content += """
[%(buildout_section_id)s]
repository = %(repository_path)s
branch = %(branch)s
......@@ -156,145 +199,176 @@ branch = %(branch)s
'repository_path' : repository_path,
'branch' : vcs_repository.get('branch','master')}
if not profile_path_count:
raise ValueError(PROFILE_PATH_KEY + ' not defined')
custom_profile = open(custom_profile_path, 'w')
custom_profile.write(profile_content)
custom_profile.close()
config['repository_path'] = repository_path
sys.path.append(repository_path)
test_suite_title = config['test_suite_title'] or config['test_suite']
if not profile_path_count:
raise ValueError(PROFILE_PATH_KEY + ' not defined')
custom_profile = open(custom_profile_path, 'w')
custom_profile.write(profile_content)
custom_profile.close()
config['repository_path'] = repository_path
sys.path.append(repository_path)
test_suite_title = config['test_suite_title'] or config['test_suite']
retry_software = False
try:
while True:
remote_test_result_needs_cleanup = False
# kill processes from previous loop if any
try:
killPreviousRun()
process_group_pid_set.clear()
full_revision_list = []
# Make sure we have local repository
for vcs_repository in vcs_repository_list:
repository_path = vcs_repository['repository_path']
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))
retry = False
retry_software_count = 0
same_revision_count = 0
try:
while True:
remote_test_result_needs_cleanup = False
remote_logger = None
remote_logger_thread = None
try:
# kill processes from previous loop if any
process_manager.killPreviousRun()
full_revision_list = []
# Make sure we have local repository
updater = Updater(repository_path, git_binary=config['git_binary'],
log=log, realtime_output=False)
updater.checkout()
revision = "-".join(updater.getRevision())
full_revision_list.append('%s=%s' % (repository_id, revision))
revision = ','.join(full_revision_list)
if previous_revision == revision:
log('Sleeping a bit')
time.sleep(DEFAULT_SLEEP_TIMEOUT)
if not(retry_software):
continue
log('Retrying install')
retry_software = False
previous_revision = revision
portal_url = config['test_suite_master_url']
test_result_path = None
test_result = (test_result_path, revision)
if portal_url:
if portal_url[-1] != '/':
portal_url += '/'
portal = xmlrpclib.ServerProxy("%s%s" %
(portal_url, 'portal_task_distribution'),
allow_none=1)
assert safeRpcCall(portal, "getProtocolRevision") == 1
test_result = safeRpcCall(portal, "createTestResult",
config['test_suite'], revision, [],
False, test_suite_title,
config['test_node_title'], config['project_title'])
remote_test_result_needs_cleanup = True
log("testnode, test_result : %r" % (test_result, ))
if test_result:
test_result_path, test_revision = test_result
if 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,
realtime_output=False)
updater.checkout()
for vcs_repository in vcs_repository_list:
repository_path = vcs_repository['repository_path']
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
updater = Updater(repository_path, git_binary=config['git_binary'],
log=log, process_manager=process_manager)
updater.checkout()
revision = "-".join(updater.getRevision())
full_revision_list.append('%s=%s' % (repository_id, revision))
revision = ','.join(full_revision_list)
if previous_revision == revision:
log('Same Revision')
same_revision_count += 1
if not(retry) and same_revision_count <= 2:
log('Sleeping a bit since same revision')
time.sleep(DEFAULT_SLEEP_TIMEOUT)
continue
same_revision_count = 0
log('Retrying install or checking if previous test was cancelled')
retry = False
previous_revision = revision
portal_url = config['test_suite_master_url']
test_result_path = None
test_result = (test_result_path, revision)
if portal_url:
if portal_url[-1] != '/':
portal_url += '/'
portal = xmlrpclib.ServerProxy("%s%s" %
(portal_url, 'portal_task_distribution'),
allow_none=1)
assert safeRpcCall(log, portal, "getProtocolRevision", True) == 1
test_result = safeRpcCall(log, portal, "createTestResult", True,
config['test_suite'], revision, [],
False, test_suite_title,
config['test_node_title'], config['project_title'])
remote_test_result_needs_cleanup = True
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
slapproxy_log = os.path.join(config['log_directory'],
'slapproxy.log')
log('Configured slapproxy log to %r' % slapproxy_log)
slapos_controler = SlapOSControler.SlapOSControler(config,
process_group_pid_set=process_group_pid_set, log=log,
slapproxy_log=slapproxy_log)
for method_name in ("runSoftwareRelease", "runComputerPartition",):
stdout, stderr = getInputOutputFileList(config, method_name)
slapos_method = getattr(slapos_controler, method_name)
status_dict = slapos_method(config,
environment=config['environment'],
process_group_pid_set=process_group_pid_set,
stdout=stdout, stderr=stderr
)
if status_dict['status_code'] != 0:
retry_software = True
raise SubprocessError(status_dict)
# Give some time so computer partitions may start
# as partitions can be of any kind we have and likely will never have
# a reliable way to check if they are up or not ...
time.sleep(20)
# Now prepare the installation of SlapOS and create instance
slapproxy_log = os.path.join(config['log_directory'],
'slapproxy.log')
log('Configured slapproxy log to %r' % slapproxy_log)
log('testnode, retry_software_count : %r' % retry_software_count)
slapos_controler = SlapOSControler.SlapOSControler(config,
log=log, slapproxy_log=slapproxy_log, process_manager=process_manager,
reset_software=(retry_software_count>0 and retry_software_count%10 == 0))
for method_name in ("runSoftwareRelease", "runComputerPartition",):
slapos_method = getattr(slapos_controler, method_name)
status_dict = slapos_method(config,
environment=config['environment'],
)
if status_dict['status_code'] != 0:
retry = True
retry_software_count += 1
raise SubprocessError(status_dict)
else:
retry_software_count = 0
# Give some time so computer partitions may start
# as partitions can be of any kind we have and likely will never have
# 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'])
if not len(run_test_suite_path_list):
raise ValueError('No runTestSuite provided in installed partitions.')
run_test_suite_path = run_test_suite_path_list[0]
run_test_suite_revision = revision
if isinstance(revision, tuple):
revision = ','.join(revision)
# Deal with Shebang size limitation
line = open(run_test_suite_path, 'r').readline()
invocation_list = []
if line[:2] == '#!':
invocation_list = line[2:].split()
invocation_list.extend([run_test_suite_path,
'--test_suite', config['test_suite'],
'--revision', revision,
'--test_suite_title', test_suite_title,
'--node_quantity', config['node_quantity'],
'--master_url', portal_url])
bt5_path_list = config.get("bt5_path")
if bt5_path_list not in ('', None,):
invocation_list.extend(["--bt5_path", bt5_path_list])
# From this point, test runner becomes responsible for updating test
# result. We only do cleanup if the test runner itself is not able
# to run.
log("call process : %r", (invocation_list,))
run_test_suite = subprocess.Popen(invocation_list,
preexec_fn=os.setsid, cwd=config['test_suite_directory'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
process_group_pid_set.add(run_test_suite.pid)
log(run_test_suite.communicate()[0])
process_group_pid_set.remove(run_test_suite.pid)
except SubprocessError, e:
if remote_test_result_needs_cleanup:
safeRpcCall(portal, "reportTaskFailure",
test_result_path, e.status_dict, config['test_node_title'])
time.sleep(DEFAULT_SLEEP_TIMEOUT)
continue
finally:
# Nice way to kill *everything* generated by run process -- process
# groups working only in POSIX compilant systems
# Exceptions are swallowed during cleanup phase
killPreviousRun()
run_test_suite_path_list = glob.glob("%s/*/bin/runTestSuite" %config['instance_root'])
if not len(run_test_suite_path_list):
raise ValueError('No runTestSuite provided in installed partitions.')
run_test_suite_path = run_test_suite_path_list[0]
run_test_suite_revision = revision
if isinstance(revision, tuple):
revision = ','.join(revision)
# Deal with Shebang size limitation
line = open(run_test_suite_path, 'r').readline()
invocation_list = []
if line[:2] == '#!':
invocation_list = line[2:].split()
invocation_list.extend([run_test_suite_path,
'--test_suite', config['test_suite'],
'--revision', revision,
'--test_suite_title', test_suite_title,
'--node_quantity', config['node_quantity'],
'--master_url', portal_url])
bt5_path_list = config.get("bt5_path")
if bt5_path_list not in ('', None,):
invocation_list.extend(["--bt5_path", bt5_path_list])
# From this point, test runner becomes responsible for updating test
# result. We only do cleanup if the test runner itself is not able
# to run.
process_manager.spawn(*invocation_list,
cwd=config['test_suite_directory'],
log_prefix='runTestSuite', get_output=False)
if remote_logger:
remote_logger.quit = True
remote_logger_thread.join()
except SubprocessError, e:
log("SubprocessError", exc_info=sys.exc_info())
if remote_logger:
remote_logger.finish = True
remote_logger_thread.join()
if remote_test_result_needs_cleanup:
safeRpcCall(log, portal, "reportTaskFailure", True,
test_result_path, e.status_dict, config['test_node_title'])
log("SubprocessError, going to sleep %s" % DEFAULT_SLEEP_TIMEOUT)
time.sleep(DEFAULT_SLEEP_TIMEOUT)
continue
except CancellationError, e:
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):
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]
date_list = [message.activity_kw.get('at_date', None) for message in registered_message_list]
group_method_id_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', ''))
group_method_id_list = [m.getGroupId() for m 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]
order_validation_text_list = [self.getOrderValidationText(message) for message in registered_message_list]
......
......@@ -66,13 +66,7 @@ class SQLQueue(SQLBase):
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]
date_list = [m.activity_kw.get('at_date', None) for m in registered_message_list]
group_method_id_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', ''))
group_method_id_list = [m.getGroupId() 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]
dumped_message_list = [self.dumpMessage(m) for m in registered_message_list]
......
......@@ -203,6 +203,13 @@ class Message(BaseMessage):
request.environ['HTTP_ACCEPT_LANGUAGE']
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):
"""return the object referenced in this message."""
return activity_tool.unrestrictedTraverse(self.object_path)
......
......@@ -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
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
-------------
......
......@@ -28,24 +28,19 @@ You MUST configure zope.conf before use.
from zLOG import LOG, INFO, ERROR
from App.config import getConfiguration
try:
import threadframe
except ImportError:
LOG('DeadlockDebugger', ERROR, "Incorrectly installed threadframe module")
else:
config = getConfiguration()
if getattr(config, 'product_config', None) is not None:
deadlockdebugger = config.product_config.get('deadlockdebugger')
dump_url = ''
secret = ''
if deadlockdebugger is None:
LOG('DeadlockDebugger', ERROR, 'Missing configuration statement '
'<product-config deadlockdebugger>, not activated')
config = getConfiguration()
if getattr(config, 'product_config', None) is not None:
deadlockdebugger = config.product_config.get('deadlockdebugger')
dump_url = ''
secret = ''
if deadlockdebugger is None:
LOG('DeadlockDebugger', ERROR, 'Missing configuration statement '
'<product-config deadlockdebugger>, not activated')
else:
if not 'dump_url' in deadlockdebugger:
LOG('DeadlockDebugger', ERROR, 'Please configure dump_url and '
'optionally secret in <product-config deadlockdebugger>, not '
'activated')
else:
if not 'dump_url' in deadlockdebugger:
LOG('DeadlockDebugger', ERROR, 'Please configure dump_url and '
'optionally secret in <product-config deadlockdebugger>, not '
'activated')
else:
import dumper
LOG('DeadlockDebugger', INFO, "Installed")
import dumper
LOG('DeadlockDebugger', INFO, "Installed")
......@@ -23,7 +23,7 @@ ZServer hook to dump a traceback of the running python threads.
"""
import thread
import threadframe
from sys import _current_frames
import traceback
import time
from cStringIO import StringIO
......@@ -36,11 +36,10 @@ def dump_threads():
Returns a string with the tracebacks.
"""
frames = threadframe.dict()
this_thread_id = thread.get_ident()
now = time.strftime("%Y-%m-%d %H:%M:%S")
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:
continue
......@@ -68,7 +67,6 @@ def dump_threads():
res.append("Thread %s%s:\n%s" %
(thread_id, reqinfo, output.getvalue()))
frames = None
res.append("End of dump")
result = '\n'.join(res)
if isinstance(result, unicode):
......
......@@ -339,18 +339,12 @@ class Delivery(XMLObject, ImmobilisationDelivery,
security.declareProtected(Permissions.AccessContentsInformation, 'isSimulated')
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
"""
for m in self.getMovementList():
#LOG('Delivery.isSimulated m',0,m.getPhysicalPath())
#LOG('Delivery.isSimulated m.isSimulated',0,m.isSimulated())
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
if m.getQuantity() and not m.isSimulated():
return 0
return 1
security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent')
......@@ -844,21 +838,21 @@ class Delivery(XMLObject, ImmobilisationDelivery,
This method will look at the causality and check if the
causality has already a causality
"""
causality_value_list = [x for x in self.getCausalityValueList()
if x is not self]
initial_list = []
if len(causality_value_list)==0:
initial_list = [self]
else:
causality_value_list = self.getCausalityValueList()
if causality_value_list:
initial_list = []
for causality in causality_value_list:
# The causality may be something which has not this method
# (e.g. item)
if hasattr(causality, 'getRootCausalityValueList'):
tmp_causality_list = causality.getRootCausalityValueList()
initial_list.extend([x for x in tmp_causality_list
if x not in initial_list])
return initial_list
try:
getRootCausalityValueList = causality.getRootCausalityValueList
except AttributeError:
continue
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
# the order/delivery builder will be reviewed. It might
......@@ -982,6 +976,7 @@ class Delivery(XMLObject, ImmobilisationDelivery,
"""
divergent_tester_list = []
for simulation_movement in self._getAllRelatedSimulationMovementList():
simulation_movement = simulation_movement.getObject()
rule = simulation_movement.getParentValue().getSpecialiseValue()
for tester in rule._getDivergenceTesterList(exclude_quantity=False):
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):
if old_delivery is None:
# from scratch
new_delivery_id = str(delivery_module.generateNewId())
delivery = delivery_module.newContent(
portal_type=self.getDeliveryPortalType(),
id=new_delivery_id,
created_by_builder=1,
activate_kw=activate_kw)
delivery = super(SimulatedDeliveryBuilder, self)._createDelivery(
delivery_module, movement_list, activate_kw)
else:
# from duplicated original delivery
cp = tryMethodCallWithTemporaryPermission(
......@@ -383,10 +380,8 @@ class SimulatedDeliveryBuilder(BuilderMixin):
old_delivery_line = None
if old_delivery_line is None:
# from scratch
new_delivery_line_id = str(delivery.generateNewId())
delivery_line = delivery.newContent(
portal_type=self.getDeliveryLinePortalType(),
id=new_delivery_line_id,
variation_category_list=[],
activate_kw=activate_kw)
else:
......
......@@ -193,7 +193,7 @@ class IdTool(BaseTool):
last_generator = self._getLatestGeneratorValue(id_generator)
new_id_list = last_generator.generateNewIdList(id_group=id_group,
id_count=id_count, default=default)
except KeyError:
except (KeyError, ValueError):
template_tool = getattr(self, 'portal_templates', None)
revision = template_tool.getInstalledBusinessTemplateRevision('erp5_core')
# XXX backward compatiblity
......
......@@ -256,3 +256,26 @@ class TaskDistributionTool(BaseTool):
break
else:
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 @@
<value>
<list>
<string>listbox</string>
<string>listbox_modification_date</string>
</list>
</value>
</item>
......
......@@ -310,7 +310,12 @@
<item>
<key> <string>all_columns</string> </key>
<value>
<list/>
<list>
<tuple>
<string>modification_date</string>
<string>Modification Date</string>
</tuple>
</list>
</value>
</item>
<item>
......@@ -376,6 +381,10 @@
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default_display_style</string> </key>
<value> <string>table</string> </value>
</item>
<item>
<key> <string>default_params</string> </key>
<value>
......@@ -409,7 +418,12 @@
<item>
<key> <string>editable_columns</string> </key>
<value>
<list/>
<list>
<tuple>
<string>modification_date</string>
<string></string>
</tuple>
</list>
</value>
</item>
<item>
......@@ -430,6 +444,10 @@
<list/>
</value>
</item>
<item>
<key> <string>global_search_column</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
......@@ -477,6 +495,10 @@
</list>
</value>
</item>
<item>
<key> <string>page_navigation_template</string> </key>
<value> <string>ListBox_viewSliderPageNavigationRenderer</string> </value>
</item>
<item>
<key> <string>page_template</string> </key>
<value> <string></string> </value>
......@@ -584,6 +606,10 @@
<string>revision</string>
<string>Revision</string>
</tuple>
<tuple>
<string>modification_date</string>
<string>Modification Date</string>
</tuple>
</list>
</value>
</item>
......@@ -597,6 +623,12 @@
<key> <string>stat_method</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>style_columns</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<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):
security.declarePublic('build')
def build(self, applied_rule_uid=None, movement_relative_url_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
......@@ -143,7 +143,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
delivery_list = self.buildDeliveryList(
root_group_node,
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
self.callAfterBuildingScript(delivery_list, movement_list, **kw)
return delivery_list
......@@ -163,7 +164,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
"""
delivery_module_before_building_script_id = \
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())
getattr(delivery_module, delivery_module_before_building_script_id)()
......@@ -368,13 +369,10 @@ class BuilderMixin(XMLObject, Amount, Predicate):
Create a new delivery in case where a builder may not update
an existing one.
"""
new_delivery_id = str(delivery_module.generateNewId())
delivery = delivery_module.newContent(
return delivery_module.newContent(
portal_type=self.getDeliveryPortalType(),
id=new_delivery_id,
created_by_builder=1,
activate_kw=activate_kw)
return delivery
def _processDeliveryGroup(self, delivery_module, movement_group_node,
collect_order_list, movement_group_node_list=None,
......@@ -452,13 +450,10 @@ class BuilderMixin(XMLObject, Amount, Predicate):
Create a new delivery line in case where a builder may not update
an existing one.
"""
new_delivery_line_id = str(delivery.generateNewId())
delivery_line = delivery.newContent(
return delivery.newContent(
portal_type=self.getDeliveryLinePortalType(),
id=new_delivery_line_id,
created_by_builder=1,
activate_kw=activate_kw)
return delivery_line
def _processDeliveryLineGroup(self, delivery, movement_group_node,
collect_order_list, movement_group_node_list=None,
......@@ -685,42 +680,33 @@ class BuilderMixin(XMLObject, Amount, Predicate):
delivery_movement._edit(force_update=1, **property_dict)
@UnrestrictedMethod
def callAfterBuildingScript(self, delivery_list, movement_list=None, **kw):
def callAfterBuildingScript(self, delivery_list, movement_list=(), **kw):
"""
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 = \
self.getDeliveryAfterGenerationScriptId()
related_simulation_movement_path_list = \
[x.getPath() for x in movement_list]
if delivery_after_generation_script_id not in ["", None]:
if delivery_after_generation_script_id:
related_simulation_movement_path_list = \
[x.getPath() for x in movement_list]
for delivery in delivery_list:
script = getattr(delivery, delivery_after_generation_script_id)
# BBB: Only Python Scripts were used in the past, and they might not
# accept an arbitrary argument. So to keep compatibility,
# check if it can take the new parameter safely, only when
# the callable object is a Python Script.
safe_to_pass_parameter = True
meta_type = getattr(script, 'meta_type', None)
if meta_type == 'Script (Python)':
# check if the script accepts related_simulation_movement_path_list
safe_to_pass_parameter = False
for param in script.params().split(','):
param = param.split('=', 1)[0].strip()
if param == 'related_simulation_movement_path_list' \
or param.startswith('**'):
safe_to_pass_parameter = True
break
if safe_to_pass_parameter:
script(related_simulation_movement_path_list=related_simulation_movement_path_list)
else:
script()
else:
script()
continue
script(related_simulation_movement_path_list=related_simulation_movement_path_list)
security.declareProtected(Permissions.AccessContentsInformation,
'getMovementGroupList')
......
......@@ -86,16 +86,17 @@ class DownloadableMixin:
output_format = None
if not format:
# Guess the format from original mimetype
mimetypes_registry = getToolByName(self.getPortalObject(),
'mimetypes_registry')
mimetype_object_list = mimetypes_registry.lookup(mime)
for mimetype_object in mimetype_object_list:
if mimetype_object.extensions:
output_format = mimetype_object.extensions[0]
break
elif mimetype_object.globs:
output_format = mimetype_object.globs.strip('*.')
break
if mime:
mimetypes_registry = getToolByName(self.getPortalObject(),
'mimetypes_registry')
mimetype_object_list = mimetypes_registry.lookup(mime)
for mimetype_object in mimetype_object_list:
if mimetype_object.extensions:
output_format = mimetype_object.extensions[0]
break
elif mimetype_object.globs:
output_format = mimetype_object.globs.strip('*.')
break
else:
output_format = format
......
......@@ -1301,12 +1301,14 @@ class TestClosingPeriod(AccountingTestCase):
self.assertEquals(1, q(
"SELECT count(*) FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q(
self.assertAlmostEquals(3.3, q(
"SELECT total_price FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q(
"'Balance Transaction Line'")[0][0],
accounting_currency_precision)
self.assertAlmostEquals(3.3, q(
"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(
"SELECT resource_uid FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
......@@ -1438,12 +1440,14 @@ class TestClosingPeriod(AccountingTestCase):
self.assertEquals(1, q(
"SELECT count(*) FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q(
self.assertAlmostEquals(3.3, q(
"SELECT total_price FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
self.assertEquals(3.3, q(
"'Balance Transaction Line'")[0][0],
accounting_currency_precision)
self.assertAlmostEquals(3.3, q(
"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(
"SELECT resource_uid FROM stock WHERE portal_type="
"'Balance Transaction Line'")[0][0])
......
......@@ -42,6 +42,7 @@ from Products.CMFCore.Expression import Expression
from Products.ERP5Type.tests.utils import LogInterceptor
from Products.ERP5Type.Workflow import addWorkflowByType
from Products.ERP5Type.tests.backportUnittest import expectedFailure, skip
from Products.ERP5Type.tests.testDynamicClassGeneration import TestDeveloperMixin
from Products.ERP5VCS.WorkingCopy import getVcsTool
import shutil
import os
......@@ -58,7 +59,7 @@ from Products.PortalTransforms.Transform import Transform
Transform_tr_init = Transform._tr_init
Transform_manage_beforeDelete = Transform.manage_beforeDelete
class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
class BusinessTemplateMixin(TestDeveloperMixin, ERP5TypeTestCase, LogInterceptor):
def getBusinessTemplateList(self):
return ('erp5_base',
'erp5_csv_style',
......@@ -6963,25 +6964,6 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
component_module = DocumentComponent._getDynamicModuleNamespace()
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):
document_id = self.component_module + '.erp5.' + self.document_title
self.getPortalObject().portal_components.newContent(
......
......@@ -81,7 +81,6 @@ class TestERP5Credential(ERP5TypeTestCase):
system_preference = self.portal.portal_preferences.newContent(
portal_type='System Preference')
system_preference.enable()
system_preference.edit(preferred_event_sender_email=['Sample s@s.com',])
@reindex
def enableAlarm(self):
......
......@@ -273,7 +273,9 @@ class TestIdTool(ERP5TypeTestCase):
generator.generateNewId(id_group='foo_bar', default=4)
self.assertEquals(generator.last_max_id_dict['foo_bar'].value, 4)
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"'
self.assertRaises(ProgrammingError, sql_connection.manage_test, query)
generator.rebuildSqlTable()
......
......@@ -511,7 +511,7 @@ class TestNotificationToolWithCRM(TestNotificationTool):
person = self.portal.person_module.newContent(
portal_type="Person",
default_email_text="userA@example.invalid")
self.stepTic()
self.portal.portal_notifications.sendMessage(
store_as_event=True,
recipient=person,
......
......@@ -549,6 +549,7 @@ class TestTask(TestTaskMixin, ERP5TypeTestCase):
def afterSetUp(self):
self.validateRules()
self.stepTic()
def getTitle(self):
return "Task"
......
......@@ -52,7 +52,7 @@ class TestTemplate(ERP5TypeTestCase):
def createUserAndLogin(self, name=None, additional_role_list=[]):
"""login with Member, Author and specified roles."""
uf = self.getPortal().acl_users
role_list = ['Member', 'Author']
role_list = ['Member', 'Author', 'Auditor']
role_list.extend(additional_role_list)
uf._doAddUser(name, '', role_list, [])
user = uf.getUserById(name).__of__(uf)
......@@ -66,10 +66,6 @@ class TestTemplate(ERP5TypeTestCase):
self.tic()
self.portal.portal_types.Preference._setTypeAllowedContentTypeList(
('Foo', 'Knowledge Pad'))
self.portal.foo_module.manage_role(role_to_manage='Author',
permissions=[Permissions.AddPortalContent,
Permissions.CopyOrMove,
])
def test_Template(self):
self.createUserAndLogin(self.id())
......
......@@ -269,7 +269,7 @@ class TestWebDavSupport(ERP5TypeTestCase):
self.assertEquals(DateTime(xml_metadata.find('{DAV:}response/'\
'{DAV:}propstat/{DAV:}prop/{DAV:}getlastmodified')\
.text).ISO8601(),
document.getModificationDate().toZone('UTC').ISO8601())
document.bobobase_modification_time().toZone('UTC').ISO8601())
@expectedFailure
def test_PROPFIND_on_document_bis(self):
......
......@@ -27,6 +27,7 @@
#
##############################################################################
import transaction
import unittest
from Testing import ZopeTestCase
......@@ -209,7 +210,7 @@ class TestArchive(InventoryAPITestCase):
portal_catalog.manage_renameObject(id=archive_id,new_id=archive_catalog_id)
# Create an archive
archive = portal_archive.newContent(portal_typ="Archive",
archive = portal_archive.newContent(portal_type="Archive",
catalog_id=self.archive_catalog_id,
connection_id=self.archive_connection_id,
deferred_connection_id=self.archive_deferred_connection_id,
......@@ -221,7 +222,7 @@ class TestArchive(InventoryAPITestCase):
)
archive.ready()
# 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,
connection_id=self.new_connection_id,
deferred_connection_id=self.new_deferred_connection_id,
......@@ -231,6 +232,9 @@ class TestArchive(InventoryAPITestCase):
)
dest.ready()
# make sure to commit to release any lock on tables
transaction.commit()
# Do archive
portal_archive.manage_archive(destination_archive_id=dest.getId(),
archive_id=archive.getId(),
......
......@@ -121,6 +121,7 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
def beforeTearDown(self):
# restore default_catalog
self.portal.portal_catalog.default_sql_catalog_id = 'erp5_mysql_innodb'
self.portal.portal_catalog.hot_reindexing_state = None
# clear Modules
for module in [ self.getPersonModule(),
self.getOrganisationModule(),
......
......@@ -2616,6 +2616,19 @@ return 1
self.assertEqual('archived', document_nolang_005.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):
username = 'yusei'
......
......@@ -26,6 +26,7 @@
#
##############################################################################
from Acquisition import aq_base
from Products.ERP5Type.PsycoWrapper import psyco
from Base import Getter as BaseGetter, Setter as BaseSetter
from warnings import warn
......@@ -120,3 +121,16 @@ class TranslatedTitleGetter(TitleGetter):
return result.encode('utf8')
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):
('getTranslated%s' % UpperCase(state_var),
WorkflowState.TranslatedGetter),
('getTranslated%sTitle' % UpperCase(state_var),
WorkflowState.TranslatedTitleGetter)):
WorkflowState.TranslatedTitleGetter),
('serialize%s' % UpperCase(state_var), WorkflowState.SerializeGetter),
):
if not hasattr(ptype_klass, method_id):
method = getter(method_id, wf_id)
# Attach to portal_type
......@@ -1434,43 +1436,42 @@ class Base( CopyContainer,
# We only change if the value is different
# This may be very long...
if force_update:
update = True
old_value = None
else:
try:
old_value = getProperty(key, evaluate=0)
except TypeError:
old_value = getProperty(key)
update = old_value != kw[key]
if update:
# We keep in a thread var the previous values
# this can be useful for interaction workflow to implement lookups
# XXX If iteraction workflow script is triggered by edit and calls
# edit itself, this is useless as the dict will be overwritten
# If the keep_existing flag is set to 1, we do not update properties which are defined
if not keep_existing or not hasProperty(key):
if restricted:
accessor_name = 'set' + UpperCase(key)
if accessor_name in restricted_method_set:
# will raise Unauthorized when not allowed
guarded_getattr(self, accessor_name)
modified_property_dict[key] = old_value
if key != 'id':
modified_object_list = _setProperty(key, kw[key])
# BBB: if the setter does not return anything, assume
# that self has been modified.
if modified_object_list is None:
modified_object_list = (self,)
for o in modified_object_list:
# XXX using id is not quite nice, but getUID causes a
# problem at the bootstrap of an ERP5 site. Therefore,
# objects themselves cannot be used as keys.
modified_object_dict[id(o)] = o
else:
self.setId(kw['id'], reindex=reindex_object)
if old_value == kw[key]:
not_modified_list.append(key)
continue
# We keep in a thread var the previous values
# this can be useful for interaction workflow to implement lookups
# XXX If iteraction workflow script is triggered by edit and calls
# edit itself, this is useless as the dict will be overwritten
# If the keep_existing flag is set to 1, we do not update properties which are defined
if keep_existing and hasProperty(key):
continue
if restricted:
accessor_name = 'set' + UpperCase(key)
if accessor_name in restricted_method_set:
# will raise Unauthorized when not allowed
guarded_getattr(self, accessor_name)
modified_property_dict[key] = old_value
if key != 'id':
modified_object_list = _setProperty(key, kw[key])
# BBB: if the setter does not return anything, assume
# that self has been modified.
if modified_object_list is None:
modified_object_list = (self,)
for o in modified_object_list:
# XXX using id is not quite nice, but getUID causes a
# problem at the bootstrap of an ERP5 site. Therefore,
# objects themselves cannot be used as keys.
modified_object_dict[id(o)] = o
else:
not_modified_list.append(key)
self.setId(kw['id'], reindex=reindex_object)
return not_modified_list
unmodified_key_list = setChangedPropertyList(unordered_key_list)
......
......@@ -14,6 +14,7 @@
##############################################################################
import string
import re
# Import everything right now, not after
# or new patch will not work
......@@ -21,6 +22,7 @@ from Shared.DC.xml.ppml import *
from Shared.DC.xml import ppml
from marshal import dumps as mdumps
from zLOG import LOG
# For converting to a more readable expression.
reprs = {}
......@@ -305,14 +307,34 @@ class Object(Sequence):
ppml.Object = Object
blanck_line_expression = re.compile('^ +$')
# For optmization.
class NoBlanks:
previous_stack_end = None
previous_discarded_data = None
def handle_data(self, data):
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):
data = data.encode('raw_unicode_escape')
self.append(data)
else:
self.previous_stack_end = self._stack[-1]
self.previous_discarded_data = data
ppml.NoBlanks = NoBlanks
......
......@@ -335,6 +335,7 @@ class ERP5TypeFunctionalTestCase(ERP5TypeTestCase):
return "Zelenium"
def afterSetUp(self):
super(ERP5TypeFunctionalTestCase, self).afterSetUp()
# create browser_id_manager
if not "browser_id_manager" in self.portal.objectIds():
self.portal.manage_addProduct['Sessions'].constructBrowserIdManager()
......
......@@ -75,11 +75,19 @@ install_product_quiet = 1
# Quiet messages when installing business templates
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
OFS.Application.import_products()
# Std Zope Products
ZopeTestCase.installProduct('ExtFile', quiet=install_product_quiet)
ZopeTestCase.installProduct('Photo', quiet=install_product_quiet)
ZopeTestCase.installProduct('Formulator', quiet=install_product_quiet)
ZopeTestCase.installProduct('FCKeditor', quiet=install_product_quiet)
......@@ -194,9 +202,6 @@ ZopeTestCase.installProduct('ParsedXML', quiet=install_product_quiet)
# Install everything else which looks like related to ERP5
from OFS.Application import get_products
from App.config import getConfiguration
instancehome = getConfiguration().instancehome
for priority, product_name, index, product_dir in get_products():
# XXX very heuristic
if os.path.isdir(os.path.join(product_dir, product_name, 'Document')) \
......@@ -1027,10 +1032,6 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin):
if len(setup_done) == 1: # make sure it is run only once
self._setUpDummyMailHost()
try:
from Products import DeadlockDebugger
except ImportError:
pass
self.serverhost, self.serverport = self.startZServer(verbose=True)
self._registerNode(distributing=1, processing=1)
......
......@@ -213,7 +213,8 @@ class ERP5TypeTestSuite(TestSuite):
(instance_number-1) * self.mysql_db_count:
(instance_number) * self.mysql_db_count]
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:
runUnitTest = os.environ.get('RUN_UNIT_TEST',
'runUnitTest')
......
......@@ -224,6 +224,10 @@ class ProcessingNodeTestCase(backportUnittest.TestCase, ZopeTestCase.TestCase):
count -= 1
if count == 0 or (message_count and set([x.processing_node for x in
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. '
try:
self.assertNoPendingMessage()
......
......@@ -39,7 +39,7 @@ def safeRpcCall(function, *args):
while True:
try:
return function(*xmlrpc_arg_list)
except (socket.error, xmlrpclib.ProtocolError), e:
except (socket.error, xmlrpclib.ProtocolError, xmlrpclib.Fault), e:
print >>sys.stderr, e
pprint.pprint(args, file(function._Method__name, 'w'))
time.sleep(retry)
......
......@@ -1246,34 +1246,39 @@ from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase
from App.config import getConfiguration
class _TestZodbComponent(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',)
class TestDeveloperMixin:
def login(self, user_name='ERP5TypeTestCase', quiet=0):
"""
Make sure that the test user has Developer Role, otherwise the user cannot
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:
product_config = config.product_config = {}
if product_config.get('erp5') is None:
class DummyDeveloperConfig(object):
pass
dummy_developer_config = DummyDeveloperConfig()
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:
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):
self._component_tool = self.getPortal().portal_components
......
......@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import glob
import os
version = '0.4.1'
version = '0.4.3'
name = 'erp5.util'
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