Commit 35e31f67 authored by Vincent Pelletier's avatar Vincent Pelletier

all: Avoid most direct calls to {recursiveI,i}mmediateReindexObject

These methods must not be called synchronously:
- they can break catalog by not being careful enough about other
  reindexations which may happen in parallel. See the serialization_tag
  mechanism for more.
- indexation gets executed in the security context of the user causing the
  call, which may lead to an indexation result different from what happens
  when indexation happens with an all-accesses user.

Also, simplify a few scripts while doing so.
parent b639160e
""" This script reindex all the objects created before updating local roles """ """ This script reindex all the objects created before updating local roles """
module_list = ['document_module',
'image_module',
'knowledge_pad_module',
'organisation_module',
'person_module',
'review_module',
'test_page_module',
'web_page_module',
'web_site_module']
context.portal_types.recursiveImmediateReindexObject()
portal = context.getPortalObject() portal = context.getPortalObject()
for module_id in module_list: portal.portal_types.Folder_reindexAll()
module = getattr(portal, module_id) stack = [
module.recursiveImmediateReindexObject() portal.document_module,
stack = [module] portal.image_module,
for obj in stack: portal.knowledge_pad_module,
for child in obj.objectValues(): portal.organisation_module,
stack.append(child) portal.person_module,
obj.updateLocalRolesOnSecurityGroups() portal.review_module,
obj.reindexObjectSecurity() portal.test_page_module,
portal.web_page_module,
portal.web_site_module,
]
for obj in stack:
stack.extend(obj.objectValues())
obj.updateLocalRolesOnSecurityGroups()
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
changed_object = state_change['object'] changed_object = state_change['object']
portal = changed_object.getPortalObject() portal = changed_object.getPortalObject()
...@@ -28,29 +29,29 @@ else: ...@@ -28,29 +29,29 @@ else:
# create the person wich represent the company # create the person wich represent the company
person_module = portal.getDefaultModule(portal_type='Person') person_module = portal.getDefaultModule(portal_type='Person')
accountant = person_module.newContent(portal_type='Person', with ImmediateReindexContextManager() as immediate_reindex_context_manager:
title=changed_object.getAccountantName(), accountant = person_module.newContent(portal_type='Person',
default_telephone_text=changed_object.getAccountantTelNumber(), immediate_reindex=immediate_reindex_context_manager,
default_fax_text=changed_object.getAccountantFax(), title=changed_object.getAccountantName(),
default_email_text=changed_object.getAccountantEmail(), default_telephone_text=changed_object.getAccountantTelNumber(),
address_street_address=changed_object.getAccountantAddress(), default_fax_text=changed_object.getAccountantFax(),
address_city=changed_object.getAccountantCity(), default_email_text=changed_object.getAccountantEmail(),
career_subordination_value=organisation) address_street_address=changed_object.getAccountantAddress(),
address_city=changed_object.getAccountantCity(),
career_subordination_value=organisation)
# create an assignment to be able to login :
from DateTime import DateTime
assignment = accountant.newContent(portal_type='Assignment') # create an assignment to be able to login :
assignment.setStartDate(DateTime()) assignment = accountant.newContent(portal_type='Assignment')
assignment.setStopDate(DateTime()+365) assignment.setStartDate(DateTime())
assignment.setCareerFunction(changed_object.getAccountantFunction()) assignment.setStopDate(DateTime()+365)
assignment.open() assignment.setCareerFunction(changed_object.getAccountantFunction())
assignment.open()
# set the login and password required a manager role, so a script with a
# proxy role is used # set the login and password required a manager role, so a script with a
login = context.generateNewLogin(text=changed_object.getAccountantName()) # proxy role is used
password = changed_object.Person_generatePassword() login = context.generateNewLogin(text=changed_object.getAccountantName())
context.EGov_setLoginAndPasswordAsManager(accountant, login, password) password = changed_object.Person_generatePassword()
accountant.immediateReindexObject() context.EGov_setLoginAndPasswordAsManager(accountant, login, password)
accountant.Person_sendCrendentialsByEMail() accountant.Person_sendCrendentialsByEMail()
pad = context.knowledge_pad_module.newContent(portal_type='Knowledge Pad', from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
title = pad_title) with ImmediateReindexContextManager() as immediate_reindex_context_manager:
# for web mode pad = context.knowledge_pad_module.newContent(portal_type='Knowledge Pad',
if mode in ('web_front', 'web_section',): immediate_reindex=immediate_reindex_context_manager,
# in Web Mode we can have a temporary Web Site objects created based on current language title = pad_title)
real_context = context.Base_getRealContext() # for web mode
pad.setPublicationSectionValue(real_context) if mode in ('web_front', 'web_section',):
# in Web Mode we can have a temporary Web Site objects created based on current language
real_context = context.Base_getRealContext()
pad.setPublicationSectionValue(real_context)
# set it as active # set it as active
context.ERP5Site_toggleActiveKnowledgePad(pad, mode=mode, redirect=False) context.ERP5Site_toggleActiveKnowledgePad(pad, mode=mode, redirect=False)
# See ERP5Site_createDefaultKnowledgePadListForUser
pad.immediateReindexObject()
if redirect_url: if redirect_url:
return context.REQUEST.RESPONSE.redirect(redirect_url) return context.REQUEST.RESPONSE.redirect(redirect_url)
......
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
knowledge_pad = None knowledge_pad = None
portal = context.getPortalObject() portal = context.getPortalObject()
system_pref = context.portal_preferences.getActiveSystemPreference() system_pref = context.portal_preferences.getActiveSystemPreference()
...@@ -13,61 +14,58 @@ else: ...@@ -13,61 +14,58 @@ else:
# find from preferences for the same context(site, section, page) # find from preferences for the same context(site, section, page)
filter_pad = lambda x: context in x.getPublicationSectionValueList() filter_pad = lambda x: context in x.getPublicationSectionValueList()
# try to find template KnowledgePad from System Preference (and user Preference with ImmediateReindexContextManager() as immediate_reindex_context_manager:
# for backward compatibility only). # try to find template KnowledgePad from System Preference (and user Preference
for pref in (system_pref, user_pref): # for backward compatibility only).
if pref is not None: for pref in (system_pref, user_pref):
# use template from preferences if pref is not None:
for pref_pad in pref.objectValues(portal_type='Knowledge Pad'): # use template from preferences
if filter_pad(pref_pad): for pref_pad in pref.objectValues(portal_type='Knowledge Pad'):
break if filter_pad(pref_pad):
else: break
continue else:
cp = pref.manage_copyObjects(ids=[pref_pad.getId()]) continue
new_id = context.knowledge_pad_module.manage_pasteObjects( new_id = context.knowledge_pad_module.manage_pasteObjects(
cb_copy_data=cp)[0]['new_id'] cb_copy_data=pref.manage_copyObjects(ids=[pref_pad.getId()]),
knowledge_pad = context.knowledge_pad_module[new_id] immediate_reindex=immediate_reindex_context_manager,
knowledge_pad.makeTemplateInstance() )[0]['new_id']
# set each contaned box's state manually to visible knowledge_pad = context.knowledge_pad_module[new_id]
# by default their state as well pads would be invisible (default state) knowledge_pad.makeTemplateInstance()
# pad's visibility is fixed in ERP5Site_toggleActiveKnowledgePad() # set each contaned box's state manually to visible
for box in knowledge_pad.contentValues(portal_type='Knowledge Box'): # by default their state as well pads would be invisible (default state)
box.visible() # pad's visibility is fixed in ERP5Site_toggleActiveKnowledgePad()
break for box in knowledge_pad.contentValues(portal_type='Knowledge Box'):
else: box.visible()
# created empty one because no template found break
knowledge_pad = context.knowledge_pad_module.newContent( else:
portal_type = 'Knowledge Pad', # created empty one because no template found
title = context.Base_translateString('Tab 1')) knowledge_pad = context.knowledge_pad_module.newContent(
if is_web_mode: immediate_reindex=immediate_reindex_context_manager,
# in Web Mode we can have a temporary Web Site objects created based on current language portal_type = 'Knowledge Pad',
real_context = context.Base_getRealContext() title = context.Base_translateString('Tab 1'),
if real_context.getPortalType() == 'Web Site' and not default_pad_group: )
# script is called within Front Page Gadgets view if is_web_mode:
knowledge_pad.setPublicationSectionValue(real_context) # in Web Mode we can have a temporary Web Site objects created based on current language
real_context = context.Base_getRealContext()
# create a default pad for user belonging to respective pad group if real_context.getPortalType() == 'Web Site' and not default_pad_group:
# this pad will be available globally for other contexes using the same # script is called within Front Page Gadgets view
# layout definition knowledge_pad.setPublicationSectionValue(real_context)
knowledge_pad.setGroup(default_pad_group)
knowledge_pad.visible() # create a default pad for user belonging to respective pad group
# set owner # this pad will be available globally for other contexes using the same
if owner is not None: # layout definition
current_user = context.portal_membership.getAuthenticatedMember() knowledge_pad.setGroup(default_pad_group)
knowledge_pad.manage_setLocalRoles(userid=owner, roles=['Owner'])
knowledge_pad.manage_delLocalRoles([current_user.getIdOrUserName()])
knowledge_pad.reindexObject()
# set default gadgets knowledge_pad.visible()
context.ERP5Site_createDefaultKnowledgeBox(knowledge_pad) # set owner
if owner is not None:
current_user = context.portal_membership.getAuthenticatedMember()
knowledge_pad.manage_setLocalRoles(userid=owner, roles=['Owner'])
knowledge_pad.manage_delLocalRoles([current_user.getIdOrUserName()])
knowledge_pad.reindexObject()
# Calling immediateReindexObject explicitly is a coding crime. # set default gadgets
# But it's safe for newly created objects and this script should context.ERP5Site_createDefaultKnowledgeBox(knowledge_pad)
# be called rarely enough to not cause any performance issue.
# Any other solution would be more complicated.
# See also ERP5Site_addNewKnowledgePad
knowledge_pad.immediateReindexObject()
if REQUEST is None: if REQUEST is None:
return knowledge_pad return knowledge_pad
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
follow_up_value = context.getPortalObject().restrictedTraverse(follow_up) follow_up_value = context.getPortalObject().restrictedTraverse(follow_up)
assert follow_up_value.getPortalType() == "Support Request" assert follow_up_value.getPortalType() == "Support Request"
follow_up_value.edit() # update modification date follow_up_value.edit() # update modification date
post = context.PostModule_createHTMLPostFromText( with ImmediateReindexContextManager() as immediate_reindex_context_manager:
follow_up=follow_up, post = context.PostModule_createHTMLPostFromText(
data=data, follow_up=follow_up,
) data=data,
immediate_reindex_context_manager=immediate_reindex_context_manager,
)
if file not in ("undefined", None): # XXX "undefined" ? should also be fixed in javascript side if file not in ("undefined", None): # XXX "undefined" ? should also be fixed in javascript side
document_kw = {'batch_mode': True, document_kw = {'batch_mode': True,
'redirect_to_document': False, 'redirect_to_document': False,
'file': file} 'file': file}
document = context.Base_contribute(**document_kw) document = context.Base_contribute(**document_kw)
# set relation between post and document # set relation between post and document
# XXX successor is used as a way to put a relation between the attachment and the post, # XXX successor is used as a way to put a relation between the attachment and the post,
# the actual way should be to use a proper container like an Event that will have # the actual way should be to use a proper container like an Event that will have
# one or several posts and one or several attachments. # one or several posts and one or several attachments.
post.setSuccessorValueList([document]) post.setSuccessorValueList([document])
# XXX depending on security model this should be changed accordingly # XXX depending on security model this should be changed accordingly
document.publish() document.publish()
post.publish() post.publish()
# XXX in support request web app interface, discussable page reloads right after
# adding a post, searching for new post hoping it is already indexed.
post.immediateReindexObject()
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
portal = context.getPortalObject() portal = context.getPortalObject()
logged_in_user_value = portal.portal_membership.getAuthenticatedMember().getUserValue() logged_in_user_value = portal.portal_membership.getAuthenticatedMember().getUserValue()
...@@ -7,7 +8,13 @@ now = DateTime() ...@@ -7,7 +8,13 @@ now = DateTime()
project_list = portal.portal_catalog(portal_type="Project", id=project) # with id keyword, this function will return a sequence data type which contains one element. project_list = portal.portal_catalog(portal_type="Project", id=project) # with id keyword, this function will return a sequence data type which contains one element.
project_object = project_list[0].getObject() project_object = project_list[0].getObject()
# support_request.Base_getRelatedPostList with ImmediateReindexContextManager() as immediate_reindex_context_manager:
support_request = portal.support_request_module.newContent(
immediate_reindex=immediate_reindex_context_manager,
portal_type='Support Request',
title=title,
resource="service_module/" + resource,
)
# - Reference = automatically generated - already implemented # - Reference = automatically generated - already implemented
# - Requester = current user person # - Requester = current user person
...@@ -17,21 +24,20 @@ project_object = project_list[0].getObject() ...@@ -17,21 +24,20 @@ project_object = project_list[0].getObject()
# - Location = Project related Location # - Location = Project related Location
# - Supervisor = Project related Supervisor # - Supervisor = Project related Supervisor
support_request = portal.support_request_module.newContent( support_request = portal.support_request_module.newContent(
portal_type='Support Request', portal_type='Support Request',
title=title, title=title,
resource="service_module/" + resource, resource="service_module/" + resource,
destination_decision_value=logged_in_user_value, destination_decision_value=logged_in_user_value,
source_decision_value = project_object.getSourceDecisionValue(), source_decision_value = project_object.getSourceDecisionValue(),
source_section_value = project_object.getSourceSectionValue(), source_section_value = project_object.getSourceSectionValue(),
source_project_value = project_object, source_project_value = project_object,
destination_value = project_object.getDestinationValue(), destination_value = project_object.getDestinationValue(),
start_date=now, start_date=now,
) )
support_request.submit() support_request.submit()
support_request.immediateReindexObject()
if description is not None or file is not None: if description is not None or file is not None:
portal.post_module.PostModule_createHTMLPostForSupportRequest( portal.post_module.PostModule_createHTMLPostForSupportRequest(
......
...@@ -13,6 +13,7 @@ if predecessor not in (None, ""): ...@@ -13,6 +13,7 @@ if predecessor not in (None, ""):
predecessor_value, = portal.portal_catalog(relative_url=predecessor, limit=2) predecessor_value, = portal.portal_catalog(relative_url=predecessor, limit=2)
post_edit_kw["predecessor_value"] = predecessor_value.getObject() post_edit_kw["predecessor_value"] = predecessor_value.getObject()
post = post_module.newContent( post = post_module.newContent(
immediate_reindex=immediate_reindex_context_manager,
portal_type='HTML Post', portal_type='HTML Post',
**post_edit_kw **post_edit_kw
) )
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>follow_up, data, predecessor=None</string> </value> <value> <string>follow_up, data, predecessor=None, immediate_reindex_context_manager=None</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
...@@ -2,4 +2,5 @@ return context.PostModule_createHTMLPost( ...@@ -2,4 +2,5 @@ return context.PostModule_createHTMLPost(
follow_up=follow_up, follow_up=follow_up,
predecessor=predecessor, predecessor=predecessor,
data="<p>" + data.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace(" ", " &nbsp;").replace("\n", "<br/>") + "</p>", data="<p>" + data.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace(" ", " &nbsp;").replace("\n", "<br/>") + "</p>",
immediate_reindex_context_manager=immediate_reindex_context_manager,
) )
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>follow_up, data, predecessor=None</string> </value> <value> <string>follow_up, data, predecessor=None, immediate_reindex_context_manager=None</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# key of dict : id of resource # key of dict : id of resource
# item of dict : tuples (resource_value, variation_category_list, quantity) # item of dict : tuples (resource_value, variation_category_list, quantity)
from ZTUtils import make_query from ZTUtils import make_query
from Products.ERP5Type.ImmediateReindexContextManager import ImmediateReindexContextManager
delivery = context delivery = context
next_container_number = next_container_int_index next_container_number = next_container_int_index
...@@ -28,75 +29,77 @@ for listitem in listbox : ...@@ -28,75 +29,77 @@ for listitem in listbox :
(movement.getVariationCategoryList(), (movement.getVariationCategoryList(),
container_quantity)] container_quantity)]
# we build 'container_count' containers with ImmediateReindexContextManager() as immediate_reindex_context_manager:
for container_number in range(container_count) : # we build 'container_count' containers
for container_number in range(container_count):
new_container_id = 'c'+str(next_container_number)
# we use container_type to know which are the resource (and variation) new_container_id = 'c'+str(next_container_number)
# of the container # we use container_type to know which are the resource (and variation)
container = delivery.newContent( # of the container
portal_type="Container", container = delivery.newContent(
title=new_container_id, # Container must be immediately reindexed,
int_index=next_container_number, # in order to see good packed quantity in fast input form
serial_number="%06d%04d" % (int(delivery.getId()), immediate_reindex=immediate_reindex_context_manager,
next_container_number), portal_type="Container",
resource = container_type, title=new_container_id,
gross_weight = gross_weight, int_index=next_container_number,
) serial_number="%06d%04d" % (int(delivery.getId()),
next_container_number),
next_container_number += 1 resource = container_type,
gross_weight = gross_weight,
# now build container_lines
for resource_url in desired_lines.keys():
# compute variation_base_category_list and variation_category_list for this line
line_variation_base_category_dict = {}
line_variation_category_list = []
for variation_category_list, quantity in desired_lines[resource_url]:
for variation_item in variation_category_list:
if not variation_item in line_variation_category_list :
line_variation_category_list.append(variation_item)
variation_base_category_items = variation_item.split('/')
if len(variation_base_category_items) > 0 :
line_variation_base_category_dict[variation_base_category_items[0]] = 1
line_variation_base_category_list = line_variation_base_category_dict.keys()
# construct new content (container_line)
resource_url = resource_url
new_container_line_id = str(container.generateNewId())
container_line = container.newContent(
portal_type="Container Line",
title=new_container_line_id,
resource=resource_url,
quantity_unit=quantity_unit_dict[resource_url],
variation_category_list=line_variation_category_list
) )
for cell_key, quantity in desired_lines[resource_url]: next_container_number += 1
if variation_category_list == []:
container_line.edit(quantity=quantity) # now build container_lines
else: for resource_url in desired_lines.keys():
# create a new cell
base_id = 'movement' # compute variation_base_category_list and variation_category_list for this line
if not container_line.hasCell(base_id=base_id, *cell_key): line_variation_base_category_dict = {}
cell = container_line.newCell( line_variation_category_list = []
base_id=base_id,
portal_type="Container Cell", for variation_category_list, quantity in desired_lines[resource_url]:
*cell_key
) for variation_item in variation_category_list:
cell.setCategoryList(cell_key) if not variation_item in line_variation_category_list:
cell.setMappedValuePropertyList(['quantity']) line_variation_category_list.append(variation_item)
cell.setMembershipCriterionCategoryList(cell_key) variation_base_category_items = variation_item.split('/')
cell.setMembershipCriterionBaseCategoryList( if len(variation_base_category_items) > 0:
line_variation_base_category_list) line_variation_base_category_dict[variation_base_category_items[0]] = 1
cell.edit(quantity=quantity)
line_variation_base_category_list = line_variation_base_category_dict.keys()
# Container must be immediately reindexed,
# in order to see good packed quantity in fast input form # construct new content (container_line)
container.recursiveImmediateReindexObject() resource_url = resource_url
new_container_line_id = str(container.generateNewId())
container_line = container.newContent(
immediate_reindex=immediate_reindex_context_manager,
portal_type="Container Line",
title=new_container_line_id,
resource=resource_url,
quantity_unit=quantity_unit_dict[resource_url],
variation_category_list=line_variation_category_list
)
for cell_key, quantity in desired_lines[resource_url]:
if variation_category_list == []:
container_line.edit(quantity=quantity)
else:
# create a new cell
base_id = 'movement'
if not container_line.hasCell(base_id=base_id, *cell_key):
cell = container_line.newCell(
immediate_reindex=immediate_reindex_context_manager,
base_id=base_id,
portal_type="Container Cell",
*cell_key
)
cell.setCategoryList(cell_key)
cell.setMappedValuePropertyList(['quantity'])
cell.setMembershipCriterionCategoryList(cell_key)
cell.setMembershipCriterionBaseCategoryList(
line_variation_base_category_list)
cell.edit(quantity=quantity)
url_params = make_query(selection_name=selection_name, url_params = make_query(selection_name=selection_name,
dialog_category=dialog_category, dialog_category=dialog_category,
......
...@@ -3262,14 +3262,8 @@ class TestAccessControl(ERP5TypeTestCase): ...@@ -3262,14 +3262,8 @@ class TestAccessControl(ERP5TypeTestCase):
method.setFiltered(1) method.setFiltered(1)
method.setExpression(self.expression) method.setExpression(self.expression)
createZODBPythonScript(self.getSkinsTool().custom,
'Base_immediateReindexObject',
'',
'context.immediateReindexObject()'
).manage_proxy(('Manager',))
def test(self): def test(self):
self.portal.person_module.newContent().Base_immediateReindexObject() self.portal.person_module.newContent(immediate_reindex=True)
def test_suite(): def test_suite():
......
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