Commit 57efc7e2 authored by Romain Courteaud's avatar Romain Courteaud

Revert "ZODB Components: Preparation of erp5_base migration from FS: One Mixin per source file."

This reverts commit 66f30ebb.
parent 7f47efa1
from Products.ERP5.Document.DeliverySimulationRule import DeliverySimulationRule from Products.ERP5.Document.DeliverySimulationRule import DeliverySimulationRule
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin from Products.ERP5.mixin.rule import MovementGeneratorMixin
class ProductionSimulationRule(DeliverySimulationRule): class ProductionSimulationRule(DeliverySimulationRule):
""" """
......
...@@ -31,7 +31,7 @@ from AccessControl import ClassSecurityInfo ...@@ -31,7 +31,7 @@ from AccessControl import ClassSecurityInfo
from Acquisition import aq_base from Acquisition import aq_base
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
from Products.ERP5.mixin.document_extensible_traversable import DocumentExtensibleTraversableMixin from Products.ERP5.mixin.extensible_traversable import DocumentExtensibleTraversableMixin
from Products.ERP5.Document.WebSection import WebSection from Products.ERP5.Document.WebSection import WebSection
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5.mixin.configurable_property_solver import ConfigurablePropertySolverMixin from Products.ERP5.mixin.solver import ConfigurablePropertySolverMixin
class AcceptSolver(ConfigurablePropertySolverMixin): class AcceptSolver(ConfigurablePropertySolverMixin):
"""Target solver that accepts the values from the decision on the prevision. """Target solver that accepts the values from the decision on the prevision.
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5.mixin.configurable_property_solver import ConfigurablePropertySolverMixin from Products.ERP5.mixin.solver import ConfigurablePropertySolverMixin
class AdoptSolver(ConfigurablePropertySolverMixin): class AdoptSolver(ConfigurablePropertySolverMixin):
"""Target solver that adopts the values from the prevision on the decision. """Target solver that adopts the values from the prevision on the decision.
......
...@@ -41,7 +41,7 @@ from Products.ERP5Type.XMLObject import XMLObject ...@@ -41,7 +41,7 @@ from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.mixin.simulable import SimulableMixin from Products.ERP5.mixin.rule import SimulableMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod, \ from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod, \
unrestricted_apply unrestricted_apply
from zLOG import LOG, PROBLEM from zLOG import LOG, PROBLEM
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -206,7 +206,7 @@ class DocumentConversionServerProxy(): ...@@ -206,7 +206,7 @@ class DocumentConversionServerProxy():
def __getattr__(self, attr): def __getattr__(self, attr):
return partial(self._proxy_function, attr) return partial(self._proxy_function, attr)
from Products.ERP5.mixin.document_extensible_traversable import DocumentExtensibleTraversableMixin from Products.ERP5.mixin.extensible_traversable import DocumentExtensibleTraversableMixin
class Document(DocumentExtensibleTraversableMixin, XMLObject, UrlMixin, class Document(DocumentExtensibleTraversableMixin, XMLObject, UrlMixin,
CachedConvertableMixin, CrawlableMixin, TextConvertableMixin, CachedConvertableMixin, CrawlableMixin, TextConvertableMixin,
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
from Products.ERP5.Document.PredicateMatrix import PredicateMatrix from Products.ERP5.Document.PredicateMatrix import PredicateMatrix
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -33,8 +33,7 @@ from AccessControl import ClassSecurityInfo ...@@ -33,8 +33,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.Item import Item from Products.ERP5.Document.Item import Item
from Products.ERP5.mixin.composition import CompositionMixin from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.mixin.simulable import SimulableMixin from Products.ERP5.mixin.rule import MovementGeneratorMixin, SimulableMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.periodicity import PeriodicityMixin from Products.ERP5.mixin.periodicity import PeriodicityMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.Base import Base from Products.ERP5Type.Base import Base
......
...@@ -30,8 +30,7 @@ import zope.interface ...@@ -30,8 +30,7 @@ import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import aq_base from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -31,8 +31,7 @@ from AccessControl import ClassSecurityInfo ...@@ -31,8 +31,7 @@ from AccessControl import ClassSecurityInfo
from Acquisition import aq_base from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -30,8 +30,7 @@ import zope.interface ...@@ -30,8 +30,7 @@ import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import aq_base from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.mixin.rule import RuleMixin from Products.ERP5.mixin.rule import RuleMixin, MovementGeneratorMixin
from Products.ERP5.mixin.movement_generator import MovementGeneratorMixin
from Products.ERP5.mixin.movement_collection_updater import \ from Products.ERP5.mixin.movement_collection_updater import \
MovementCollectionUpdaterMixin MovementCollectionUpdaterMixin
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.Domain import Domain from Products.ERP5.Document.Domain import Domain
from Products.ERP5.mixin.document_extensible_traversable import DocumentExtensibleTraversableMixin from Products.ERP5.mixin.extensible_traversable import DocumentExtensibleTraversableMixin
from Acquisition import aq_base, aq_inner from Acquisition import aq_base, aq_inner
from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
from AccessControl import Unauthorized from AccessControl import Unauthorized
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import zope.interface
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.mixin.solver import SolverMixin
from Products.ERP5.mixin.configurable import ConfigurableMixin
class ConfigurablePropertySolverMixin(SolverMixin,
ConfigurableMixin,
XMLObject):
"""
Base class for Target Solvers that can be applied to many
solver-decisions of a solver process, and need to accumulate the
tested_property_list configuration among all solver-decisions
"""
add_permission = Permissions.AddPortalContent
isIndexable = 0 # We do not want to fill the catalog with objects on which we need no reporting
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
zope.interface.implements(interfaces.ISolver,
interfaces.IConfigurable,)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.TargetSolver
)
def updateConfiguration(self, **kw):
# This method is called once for each 'Solver Decision' of a
# 'Solver Process' that maps into this solver for the same
# Simulation Movement, so we need to take care not to lose
# information by overwriting.
configuration = self._getConfigurationPropertyDict()
tested_property_list = configuration.get('tested_property_list')
if tested_property_list is not None:
tested_property_set = set(tested_property_list)
tested_property_set.update(kw.get('tested_property_list', ()))
kw['tested_property_list'] = list(tested_property_set)
super(ConfigurablePropertySolverMixin, self).updateConfiguration(**kw)
def getTestedPropertyList(self):
configuration_dict = self.getConfigurationPropertyDict()
tested_property_list = configuration_dict.get('tested_property_list')
if tested_property_list is None:
portal_type = self.getPortalObject().portal_types.getTypeInfo(self)
tested_property_list = portal_type.getTestedPropertyList()
return tested_property_list
InitializeClass(ConfigurablePropertySolverMixin)
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@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 Acquisition import aq_base
from AccessControl import Unauthorized
from AccessControl.SecurityManagement import setSecurityManager
from Products.ERP5.mixin.base_extensible_traversable import BaseExtensibleTraversableMixin
from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
class DocumentExtensibleTraversableMixin(BaseExtensibleTraversableMixin):
"""
This class provides a implementation of IExtensibleTraversable for Document classed based documents.
"""
def getExtensibleContent(self, request, name):
old_manager, user = self._forceIdentification(request)
# Next get the document per name
portal = self.getPortalObject()
document = self.getDocumentValue(name=name, portal=portal)
# restore original security context if there's a logged in user
if user is not None:
setSecurityManager(old_manager)
if document is not None:
document = aq_base(document.asContext(id=name, # Hide some properties to permit locating the original
original_container=document.getParentValue(),
original_id=document.getId(),
editable_absolute_url=document.absolute_url()))
return document.__of__(self)
# no document found for current user, still such document may exists
# in some cases user (like Anonymous) can not view document according to portal catalog
# but we may ask him to login if such a document exists
isAuthorizationForced = getattr(self, 'isAuthorizationForced', None)
if isAuthorizationForced is not None and isAuthorizationForced():
if unrestricted_apply(self.getDocumentValue, (name, portal)) is not None:
# force user to login as specified in Web Section
raise Unauthorized
...@@ -27,22 +27,26 @@ ...@@ -27,22 +27,26 @@
# #
############################################################################## ##############################################################################
from warnings import warn
from base64 import decodestring
from zLOG import LOG from zLOG import LOG
from AccessControl import ClassSecurityInfo, getSecurityManager from Acquisition import aq_base
from AccessControl.SecurityManagement import newSecurityManager, setSecurityManager from Products.ERP5Type.Globals import get_request
from Products.CMFCore.utils import getToolByName from AccessControl import Unauthorized
from Products.ERP5Type.ExtensibleTraversable import ExtensibleTraversableMixIn from Products.ERP5Type.ExtensibleTraversable import ExtensibleTraversableMixIn
from Products.ERP5Type.Cache import getReadOnlyTransactionCache from Products.ERP5Type.Cache import getReadOnlyTransactionCache
from AccessControl import ClassSecurityInfo, getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager, setSecurityManager
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import get_request from Products.CMFCore.utils import getToolByName, _checkConditionalGET, _setCacheHeaders, _ViewEmulator
from OFS.Image import File as OFSFile
from warnings import warn
from base64 import decodestring
from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
from Products.ERP5.Document.Document import ConversionError, NotConvertedError
# XXX: these duplicate ones in ERP5.Document # XXX: these duplicate ones in ERP5.Document
_MARKER = [] _MARKER = []
EMBEDDED_FORMAT = '_embedded'
class BaseExtensibleTraversableMixin(ExtensibleTraversableMixIn): class BaseExtensibleTraversableMixin(ExtensibleTraversableMixIn):
""" """
...@@ -166,3 +170,61 @@ class BaseExtensibleTraversableMixin(ExtensibleTraversableMixIn): ...@@ -166,3 +170,61 @@ class BaseExtensibleTraversableMixin(ExtensibleTraversableMixIn):
return document.__of__(self) return document.__of__(self)
InitializeClass(BaseExtensibleTraversableMixin) InitializeClass(BaseExtensibleTraversableMixin)
class DocumentExtensibleTraversableMixin(BaseExtensibleTraversableMixin):
"""
This class provides a implementation of IExtensibleTraversable for Document classed based documents.
"""
def getExtensibleContent(self, request, name):
old_manager, user = self._forceIdentification(request)
# Next get the document per name
portal = self.getPortalObject()
document = self.getDocumentValue(name=name, portal=portal)
# restore original security context if there's a logged in user
if user is not None:
setSecurityManager(old_manager)
if document is not None:
document = aq_base(document.asContext(id=name, # Hide some properties to permit locating the original
original_container=document.getParentValue(),
original_id=document.getId(),
editable_absolute_url=document.absolute_url()))
return document.__of__(self)
# no document found for current user, still such document may exists
# in some cases user (like Anonymous) can not view document according to portal catalog
# but we may ask him to login if such a document exists
isAuthorizationForced = getattr(self, 'isAuthorizationForced', None)
if isAuthorizationForced is not None and isAuthorizationForced():
if unrestricted_apply(self.getDocumentValue, (name, portal)) is not None:
# force user to login as specified in Web Section
raise Unauthorized
class OOoDocumentExtensibleTraversableMixin(BaseExtensibleTraversableMixin):
"""
This class provides a implementation of IExtensibleTraversable for OOoDocument classed based documents.
"""
def getExtensibleContent(self, request, name):
# Be sure that html conversion is done,
# as it is required to extract extensible content
old_manager, user = self._forceIdentification(request)
web_cache_kw = {'name': name,
'format': EMBEDDED_FORMAT}
try:
self._convert(format='html')
view = _ViewEmulator().__of__(self)
# If we have a conditional get, set status 304 and return
# no content
if _checkConditionalGET(view, web_cache_kw):
return ''
# call caching policy manager.
_setCacheHeaders(view, web_cache_kw)
mime, data = self.getConversion(format=EMBEDDED_FORMAT, filename=name)
document = OFSFile(name, name, data, content_type=mime).__of__(self.aq_parent)
except (NotConvertedError, ConversionError, KeyError):
document = DocumentExtensibleTraversableMixin.getExtensibleContent(self, request, name)
# restore original security context if there's a logged in user
if user is not None:
setSecurityManager(old_manager)
return document
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 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 adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
class MovementGeneratorMixin(object):
"""
This class provides a generic implementation of IMovementGenerator
which can be used together the Rule mixin class bellow. It does not
have any pretention to provide more than that.
TODO:
- _getInputMovementList is still not well defined. Should input
be an amount (_getInputAmountList) or a movement? This
requires careful thiking.
"""
# Default values
_applied_rule = None
_rule = None
_trade_phase_list = None
_explanation = None
def __init__(self, applied_rule, explanation=None, rule=None, trade_phase_list=None):
self._trade_phase_list = trade_phase_list # XXX-JPS Why a list ?
self._applied_rule = applied_rule
if rule is None and applied_rule is not None:
self._rule = applied_rule.getSpecialiseValue()
else:
self._rule = rule # for rule specific stuff
if explanation is None:
self._explanation = applied_rule
else:
# A good example of explicit explanation can be getRootExplanationLineValue
# since different lines could have different dates
# such an explicit root explanation only works if
# indexing of simulation has already happened
self._explanation = explanation
# XXX-JPS handle delay_mode
# Implementation of IMovementGenerator
def getGeneratedMovementList(self, movement_list=None, rounding=False):
"""
Returns a list of movements generated by that rule.
movement_list - optional IMovementList which can be passed explicitely
rounding - boolean argument, which controls if rounding shall be applied on
generated movements or not
NOTE:
- implement rounding appropriately (True or False seems
simplistic)
"""
# Default implementation below can be overriden by subclasses
# however it should be generic enough not to be overriden
# by most classes
# Results will be appended to result
result = []
# Build a list of movement and business path
input_movement_list = self._getInputMovementList(
movement_list=movement_list, rounding=rounding)
for input_movement in input_movement_list:
# Merge movement and business path properties (core implementation)
# Lookup Business Process through composition (NOT UNION)
business_process = input_movement.asComposedDocument()
explanation = self._applied_rule # We use applied rule as local explanation
trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
update_property_dict = self._getUpdatePropertyDict(input_movement)
result.extend(business_process.getTradePhaseMovementList(explanation, input_movement,
trade_phase=trade_phase, delay_mode=None,
update_property_dict=update_property_dict))
# And return list of generated movements
return result
def _getUpdatePropertyDict(self, input_movement):
# XXX Wouldn't it better to return {} or {'delivery': None} ?
# Below code is mainly for root applied rules.
# Other movement generators usually want to reset delivery.
return {'delivery': input_movement.getRelativeUrl()}
def _getTradePhaseList(self, input_movement, business_process): # XXX-JPS WEIRD
if self._trade_phase_list:
return self._trade_phase_list
if self._rule is not None:
trade_phase_list = self._rule.getTradePhaseList()
if trade_phase_list:
return trade_phase_list
return input_movement.getTradePhaseList() or \
business_process.getTradePhaseList()
def _getInputMovementList(self, movement_list=None, rounding=None): #XXX-JPS should it be amount or movement ?
raise NotImplementedError
# Default implementation takes amounts ?
# Use TradeModelRuleMovementGenerator._getInputMovementList as default implementation
# and potentially use trade phase for that.... as a way to filter out
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@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.SecurityManagement import setSecurityManager
from Products.CMFCore.utils import _checkConditionalGET, _setCacheHeaders, _ViewEmulator
from OFS.Image import File as OFSFile
from Products.ERP5.Document.Document import ConversionError, NotConvertedError
from Products.ERP5.mixin.base_extensible_traversable import BaseExtensibleTraversableMixin
from Products.ERP5.mixin.document_extensible_traversable import DocumentExtensibleTraversableMixin
# XXX: these duplicate ones in ERP5.Document
EMBEDDED_FORMAT = '_embedded'
class OOoDocumentExtensibleTraversableMixin(BaseExtensibleTraversableMixin):
"""
This class provides a implementation of IExtensibleTraversable for OOoDocument classed based documents.
"""
def getExtensibleContent(self, request, name):
# Be sure that html conversion is done,
# as it is required to extract extensible content
old_manager, user = self._forceIdentification(request)
web_cache_kw = {'name': name,
'format': EMBEDDED_FORMAT}
try:
self._convert(format='html')
view = _ViewEmulator().__of__(self)
# If we have a conditional get, set status 304 and return
# no content
if _checkConditionalGET(view, web_cache_kw):
return ''
# call caching policy manager.
_setCacheHeaders(view, web_cache_kw)
mime, data = self.getConversion(format=EMBEDDED_FORMAT, filename=name)
document = OFSFile(name, name, data, content_type=mime).__of__(self.aq_parent)
except (NotConvertedError, ConversionError, KeyError):
document = DocumentExtensibleTraversableMixin.getExtensibleContent(self, request, name)
# restore original security context if there's a logged in user
if user is not None:
setSecurityManager(old_manager)
return document
...@@ -26,12 +26,20 @@ ...@@ -26,12 +26,20 @@
# #
############################################################################## ##############################################################################
import transaction
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Acquisition import aq_base
from Products.ERP5Type import Permissions, interfaces from Products.ERP5Type import Permissions, interfaces
from Products.ERP5Type.Base import Base
from Products.ERP5Type.Core.Predicate import Predicate from Products.ERP5Type.Core.Predicate import Predicate
from Products.ERP5Type.Errors import SimulationError
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.ExpandPolicy import policy_dict from Products.ERP5.ExpandPolicy import policy_dict
from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList
from zLOG import LOG
def _compare(tester_list, prevision_movement, decision_movement): def _compare(tester_list, prevision_movement, decision_movement):
for tester in tester_list: for tester in tester_list:
...@@ -39,6 +47,99 @@ def _compare(tester_list, prevision_movement, decision_movement): ...@@ -39,6 +47,99 @@ def _compare(tester_list, prevision_movement, decision_movement):
return False return False
return True return True
class MovementGeneratorMixin(object):
"""
This class provides a generic implementation of IMovementGenerator
which can be used together the Rule mixin class bellow. It does not
have any pretention to provide more than that.
TODO:
- _getInputMovementList is still not well defined. Should input
be an amount (_getInputAmountList) or a movement? This
requires careful thiking.
"""
# Default values
_applied_rule = None
_rule = None
_trade_phase_list = None
_explanation = None
def __init__(self, applied_rule, explanation=None, rule=None, trade_phase_list=None):
self._trade_phase_list = trade_phase_list # XXX-JPS Why a list ?
self._applied_rule = applied_rule
if rule is None and applied_rule is not None:
self._rule = applied_rule.getSpecialiseValue()
else:
self._rule = rule # for rule specific stuff
if explanation is None:
self._explanation = applied_rule
else:
# A good example of explicit explanation can be getRootExplanationLineValue
# since different lines could have different dates
# such an explicit root explanation only works if
# indexing of simulation has already happened
self._explanation = explanation
# XXX-JPS handle delay_mode
# Implementation of IMovementGenerator
def getGeneratedMovementList(self, movement_list=None, rounding=False):
"""
Returns a list of movements generated by that rule.
movement_list - optional IMovementList which can be passed explicitely
rounding - boolean argument, which controls if rounding shall be applied on
generated movements or not
NOTE:
- implement rounding appropriately (True or False seems
simplistic)
"""
# Default implementation below can be overriden by subclasses
# however it should be generic enough not to be overriden
# by most classes
# Results will be appended to result
result = []
# Build a list of movement and business path
input_movement_list = self._getInputMovementList(
movement_list=movement_list, rounding=rounding)
for input_movement in input_movement_list:
# Merge movement and business path properties (core implementation)
# Lookup Business Process through composition (NOT UNION)
business_process = input_movement.asComposedDocument()
explanation = self._applied_rule # We use applied rule as local explanation
trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
update_property_dict = self._getUpdatePropertyDict(input_movement)
result.extend(business_process.getTradePhaseMovementList(explanation, input_movement,
trade_phase=trade_phase, delay_mode=None,
update_property_dict=update_property_dict))
# And return list of generated movements
return result
def _getUpdatePropertyDict(self, input_movement):
# XXX Wouldn't it better to return {} or {'delivery': None} ?
# Below code is mainly for root applied rules.
# Other movement generators usually want to reset delivery.
return {'delivery': input_movement.getRelativeUrl()}
def _getTradePhaseList(self, input_movement, business_process): # XXX-JPS WEIRD
if self._trade_phase_list:
return self._trade_phase_list
if self._rule is not None:
trade_phase_list = self._rule.getTradePhaseList()
if trade_phase_list:
return trade_phase_list
return input_movement.getTradePhaseList() or \
business_process.getTradePhaseList()
def _getInputMovementList(self, movement_list=None, rounding=None): #XXX-JPS should it be amount or movement ?
raise NotImplementedError
# Default implementation takes amounts ?
# Use TradeModelRuleMovementGenerator._getInputMovementList as default implementation
# and potentially use trade phase for that.... as a way to filter out
class RuleMixin(Predicate): class RuleMixin(Predicate):
""" """
Provides generic methods and helper methods to implement Provides generic methods and helper methods to implement
...@@ -378,3 +479,142 @@ class RuleMixin(Predicate): ...@@ -378,3 +479,142 @@ class RuleMixin(Predicate):
movement_collection_diff.addNewMovement(new_movement) movement_collection_diff.addNewMovement(new_movement)
InitializeClass(RuleMixin) InitializeClass(RuleMixin)
class SimulableMixin(Base):
security = ClassSecurityInfo()
def updateSimulation(self, **kw):
"""Create/update related simulation trees by activity
This method is used to maintain related objects in simulation trees:
- hiding complexity of activity dependencies
- avoiding duplicate work
Repeated calls of this method for the same delivery will result in a single
call to _updateSimulation. Grouping may happen at the end of the transaction
or by the grouping method.
See _updateSimulation for accepted parameters.
"""
tv = getTransactionalVariable()
key = 'SimulableMixin.updateSimulation', self.getUid()
item_list = kw.items()
try:
kw, ignore = tv[key]
kw.update(item_list)
except KeyError:
ignore_key = key + ('ignore',)
ignore = tv.pop(ignore_key, set())
tv[key] = kw, ignore
def before_commit():
if kw:
path = self.getPath()
if aq_base(self.unrestrictedTraverse(path, None)) is aq_base(self):
self.activate(
activity='SQLQueue',
group_method_id='portal_rules/updateSimulation',
tag='build:' + path,
priority=3,
)._updateSimulation(**kw)
del tv[key]
ignore.update(kw)
tv[ignore_key] = ignore
transaction.get().addBeforeCommitHook(before_commit)
for k, v in item_list:
if not v:
ignore.add(k)
elif k not in ignore:
continue
del kw[k]
def _updateSimulation(self, create_root=0, expand_root=0,
expand_related=0, index_related=0):
"""
Depending on set parameters, this method will:
create_root -- if a root applied rule is missing, create and expand it
expand_root -- expand related root applied rule,
create it before if missing
expand_related -- expand related simulation movements
index_related -- reindex related simulation movements (recursively)
"""
if create_root or expand_root:
applied_rule = self._getRootAppliedRule()
if applied_rule is None:
applied_rule = self._createRootAppliedRule()
expand_root = applied_rule is not None
activate_kw = {'tag': 'build:'+self.getPath()}
if expand_root:
applied_rule.expand(activate_kw=activate_kw)
else:
applied_rule = None
if expand_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
# XXX: make sure this will also reindex of all sub-objects recursively
movement.expand(activate_kw=activate_kw)
elif index_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
movement.recursiveReindexObject(activate_kw=activate_kw)
security.declareProtected( Permissions.AccessContentsInformation,
'getRuleReference')
def getRuleReference(self):
"""Returns an appropriate rule reference
XXX: Using reference to select a rule (for a root applied rule) is wrong
and should be replaced by predicate and workflow state.
"""
method = self._getTypeBasedMethod('getRuleReference')
if method is None:
raise SimulationError("Missing type-based 'getRuleReference' script for "
+ repr(self))
return method()
def _getRootAppliedRule(self):
"""Get related root applied rule if it exists"""
applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
if len(applied_rule_list) == 1:
return applied_rule_list[0]
elif applied_rule_list:
raise SimulationError('%r has more than one applied rule.' % self)
def _createRootAppliedRule(self):
"""Create a root applied rule"""
# XXX: Consider moving this first test to Delivery
if self.isSimulated():
# No need to have a root applied rule
# if we are already in the simulation process
return
rule_reference = self.getRuleReference()
if rule_reference:
portal = self.getPortalObject()
rule_list = portal.portal_catalog.unrestrictedSearchResults(
portal_type=portal.getPortalRuleTypeList(),
validation_state="validated", reference=rule_reference,
sort_on='version', sort_order='descending')
if rule_list:
applied_rule = rule_list[0].constructNewAppliedRule(
portal.portal_simulation, is_indexable=False)
applied_rule._setCausalityValue(self)
del applied_rule.isIndexable
# To prevent duplicate root Applied Rule, we reindex immediately and
# lock ZODB, and we rely on the fact that ZODB is committed after
# catalog. This way, we guarantee the catalog is up-to-date as soon as
# ZODB is unlocked.
applied_rule.immediateReindexObject()
self.serialize() # prevent duplicate root Applied Rule
return applied_rule
raise SimulationError("No such rule as %r is found" % rule_reference)
security.declarePrivate('manage_beforeDelete')
def manage_beforeDelete(self, item, container):
"""Delete related Applied Rule"""
for o in self.getCausalityRelatedValueList(portal_type='Applied Rule'):
o.getParentValue().deleteContent(o.getId())
super(SimulableMixin, self).manage_beforeDelete(item, container)
InitializeClass(SimulableMixin)
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 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 adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import transaction
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Base import Base
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Type.Errors import SimulationError
class SimulableMixin(Base):
security = ClassSecurityInfo()
def updateSimulation(self, **kw):
"""Create/update related simulation trees by activity
This method is used to maintain related objects in simulation trees:
- hiding complexity of activity dependencies
- avoiding duplicate work
Repeated calls of this method for the same delivery will result in a single
call to _updateSimulation. Grouping may happen at the end of the transaction
or by the grouping method.
See _updateSimulation for accepted parameters.
"""
tv = getTransactionalVariable()
key = 'SimulableMixin.updateSimulation', self.getUid()
item_list = kw.items()
try:
kw, ignore = tv[key]
kw.update(item_list)
except KeyError:
ignore_key = key + ('ignore',)
ignore = tv.pop(ignore_key, set())
tv[key] = kw, ignore
def before_commit():
if kw:
path = self.getPath()
if aq_base(self.unrestrictedTraverse(path, None)) is aq_base(self):
self.activate(
activity='SQLQueue',
group_method_id='portal_rules/updateSimulation',
tag='build:' + path,
priority=3,
)._updateSimulation(**kw)
del tv[key]
ignore.update(kw)
tv[ignore_key] = ignore
transaction.get().addBeforeCommitHook(before_commit)
for k, v in item_list:
if not v:
ignore.add(k)
elif k not in ignore:
continue
del kw[k]
def _updateSimulation(self, create_root=0, expand_root=0,
expand_related=0, index_related=0):
"""
Depending on set parameters, this method will:
create_root -- if a root applied rule is missing, create and expand it
expand_root -- expand related root applied rule,
create it before if missing
expand_related -- expand related simulation movements
index_related -- reindex related simulation movements (recursively)
"""
if create_root or expand_root:
applied_rule = self._getRootAppliedRule()
if applied_rule is None:
applied_rule = self._createRootAppliedRule()
expand_root = applied_rule is not None
activate_kw = {'tag': 'build:'+self.getPath()}
if expand_root:
applied_rule.expand(activate_kw=activate_kw)
else:
applied_rule = None
if expand_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
# XXX: make sure this will also reindex of all sub-objects recursively
movement.expand(activate_kw=activate_kw)
elif index_related:
for movement in self._getAllRelatedSimulationMovementList():
movement = movement.getObject()
if not movement.aq_inContextOf(applied_rule):
movement.recursiveReindexObject(activate_kw=activate_kw)
security.declareProtected( Permissions.AccessContentsInformation,
'getRuleReference')
def getRuleReference(self):
"""Returns an appropriate rule reference
XXX: Using reference to select a rule (for a root applied rule) is wrong
and should be replaced by predicate and workflow state.
"""
method = self._getTypeBasedMethod('getRuleReference')
if method is None:
raise SimulationError("Missing type-based 'getRuleReference' script for "
+ repr(self))
return method()
def _getRootAppliedRule(self):
"""Get related root applied rule if it exists"""
applied_rule_list = self.getCausalityRelatedValueList(
portal_type='Applied Rule')
if len(applied_rule_list) == 1:
return applied_rule_list[0]
elif applied_rule_list:
raise SimulationError('%r has more than one applied rule.' % self)
def _createRootAppliedRule(self):
"""Create a root applied rule"""
# XXX: Consider moving this first test to Delivery
if self.isSimulated():
# No need to have a root applied rule
# if we are already in the simulation process
return
rule_reference = self.getRuleReference()
if rule_reference:
portal = self.getPortalObject()
rule_list = portal.portal_catalog.unrestrictedSearchResults(
portal_type=portal.getPortalRuleTypeList(),
validation_state="validated", reference=rule_reference,
sort_on='version', sort_order='descending')
if rule_list:
applied_rule = rule_list[0].constructNewAppliedRule(
portal.portal_simulation, is_indexable=False)
applied_rule._setCausalityValue(self)
del applied_rule.isIndexable
# To prevent duplicate root Applied Rule, we reindex immediately and
# lock ZODB, and we rely on the fact that ZODB is committed after
# catalog. This way, we guarantee the catalog is up-to-date as soon as
# ZODB is unlocked.
applied_rule.immediateReindexObject()
self.serialize() # prevent duplicate root Applied Rule
return applied_rule
raise SimulationError("No such rule as %r is found" % rule_reference)
security.declarePrivate('manage_beforeDelete')
def manage_beforeDelete(self, item, container):
"""Delete related Applied Rule"""
for o in self.getCausalityRelatedValueList(portal_type='Applied Rule'):
o.getParentValue().deleteContent(o.getId())
super(SimulableMixin, self).manage_beforeDelete(item, container)
InitializeClass(SimulableMixin)
...@@ -30,8 +30,10 @@ ...@@ -30,8 +30,10 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.UnrestrictedMethod import super_user from Products.ERP5Type.UnrestrictedMethod import super_user
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.mixin.configurable import ConfigurableMixin
class SolverMixin(object): class SolverMixin(object):
""" """
...@@ -71,3 +73,53 @@ class SolverMixin(object): ...@@ -71,3 +73,53 @@ class SolverMixin(object):
return solver_list return solver_list
InitializeClass(SolverMixin) InitializeClass(SolverMixin)
class ConfigurablePropertySolverMixin(SolverMixin,
ConfigurableMixin,
XMLObject):
"""
Base class for Target Solvers that can be applied to many
solver-decisions of a solver process, and need to accumulate the
tested_property_list configuration among all solver-decisions
"""
add_permission = Permissions.AddPortalContent
isIndexable = 0 # We do not want to fill the catalog with objects on which we need no reporting
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
zope.interface.implements(interfaces.ISolver,
interfaces.IConfigurable,)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.TargetSolver
)
def updateConfiguration(self, **kw):
# This method is called once for each 'Solver Decision' of a
# 'Solver Process' that maps into this solver for the same
# Simulation Movement, so we need to take care not to lose
# information by overwriting.
configuration = self._getConfigurationPropertyDict()
tested_property_list = configuration.get('tested_property_list')
if tested_property_list is not None:
tested_property_set = set(tested_property_list)
tested_property_set.update(kw.get('tested_property_list', ()))
kw['tested_property_list'] = list(tested_property_set)
super(ConfigurablePropertySolverMixin, self).updateConfiguration(**kw)
def getTestedPropertyList(self):
configuration_dict = self.getConfigurationPropertyDict()
tested_property_list = configuration_dict.get('tested_property_list')
if tested_property_list is None:
portal_type = self.getPortalObject().portal_types.getTypeInfo(self)
tested_property_list = portal_type.getTestedPropertyList()
return tested_property_list
InitializeClass(ConfigurablePropertySolverMixin)
...@@ -30,7 +30,7 @@ import zope.interface ...@@ -30,7 +30,7 @@ import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.skin_configurator_item import \ from Products.ERP5Configurator.mixin.configurator_item import \
SkinConfiguratorItemMixin SkinConfiguratorItemMixin
class SecurityCategoryMappingConfiguratorItem(SkinConfiguratorItemMixin, class SecurityCategoryMappingConfiguratorItem(SkinConfiguratorItemMixin,
......
...@@ -29,7 +29,9 @@ ...@@ -29,7 +29,9 @@
############################################################################## ##############################################################################
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
from Products.ERP5Type.Base import Base
from zLOG import LOG, INFO from zLOG import LOG, INFO
import time
class ConfiguratorItemMixin: class ConfiguratorItemMixin:
""" This is the base class for all configurator item. """ """ This is the base class for all configurator item. """
...@@ -62,3 +64,53 @@ class ConfiguratorItemMixin: ...@@ -62,3 +64,53 @@ class ConfiguratorItemMixin:
current_template_path_list = list(bt5_obj.getTemplatePathList()) current_template_path_list = list(bt5_obj.getTemplatePathList())
current_template_path_list.extend(template_path_list) current_template_path_list.extend(template_path_list)
bt5_obj.edit(template_path_list=current_template_path_list) bt5_obj.edit(template_path_list=current_template_path_list)
class SkinConfiguratorItemMixin(ConfiguratorItemMixin):
""" Mixin which allows to create python scripts and/or skin
elements during the configuration.
"""
def install(self, skinfolder, business_configuration):
"""
"""
bt5_obj = business_configuration.getSpecialiseValue()
if bt5_obj is None:
LOG('ConfiguratorItem', INFO,
'Unable to find related business template to %s' % \
business_configuration.getRelativeUrl())
return
template_skin_id_list = list(bt5_obj.getTemplateSkinIdList())
if skinfolder.getId() not in template_skin_id_list:
template_skin_id_list.append(skinfolder.getId())
bt5_obj.edit(template_skin_id_list=template_skin_id_list)
def _createSkinFolder(self, folder_id="custom"):
""" Creates a new skin folder id if it do not exists and
update Skin information """
folder = getattr(self.portal_skins, folder_id, None)
if folder is not None:
return folder
folder = self.portal_skins.manage_addProduct['OFSP'].manage_addFolder(folder_id)
# Register on all skin selections.
raise NotImplementedError
def _createZODBPythonScript(self, container, script_id, script_params,
script_content):
"""Creates a Python script `script_id` in the given `container`, with
`script_params` and `script_content`.
If the container already contains an object with id `script_id`, this
object is removed first.
"""
if script_id in container.objectIds():
container.manage_delObjects([script_id])
container.manage_addProduct['PythonScripts']\
.manage_addPythonScript(id = script_id)
script = container._getOb(script_id)
script.ZPythonScript_edit(script_params, script_content)
container.portal_url.getPortalObject().changeSkin(None)
return script
##############################################################################
#
# Copyright (c) 2006-2012 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
# Rafael Monnerat <rafael@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 zLOG import LOG, INFO
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class SkinConfiguratorItemMixin(ConfiguratorItemMixin):
""" Mixin which allows to create python scripts and/or skin
elements during the configuration.
"""
def install(self, skinfolder, business_configuration):
"""
"""
bt5_obj = business_configuration.getSpecialiseValue()
if bt5_obj is None:
LOG('ConfiguratorItem', INFO,
'Unable to find related business template to %s' % \
business_configuration.getRelativeUrl())
return
template_skin_id_list = list(bt5_obj.getTemplateSkinIdList())
if skinfolder.getId() not in template_skin_id_list:
template_skin_id_list.append(skinfolder.getId())
bt5_obj.edit(template_skin_id_list=template_skin_id_list)
def _createSkinFolder(self, folder_id="custom"):
""" Creates a new skin folder id if it do not exists and
update Skin information """
folder = getattr(self.portal_skins, folder_id, None)
if folder is not None:
return folder
folder = self.portal_skins.manage_addProduct['OFSP'].manage_addFolder(folder_id)
# Register on all skin selections.
raise NotImplementedError
def _createZODBPythonScript(self, container, script_id, script_params,
script_content):
"""Creates a Python script `script_id` in the given `container`, with
`script_params` and `script_content`.
If the container already contains an object with id `script_id`, this
object is removed first.
"""
if script_id in container.objectIds():
container.manage_delObjects([script_id])
container.manage_addProduct['PythonScripts']\
.manage_addPythonScript(id = script_id)
script = container._getOb(script_id)
script.ZPythonScript_edit(script_params, script_content)
container.portal_url.getPortalObject().changeSkin(None)
return script
...@@ -43,7 +43,7 @@ from Products.ERP5Type.Utils import fill_args_from_request ...@@ -43,7 +43,7 @@ from Products.ERP5Type.Utils import fill_args_from_request
# Mixin Import # Mixin Import
from Products.ERP5.mixin.base_convertable import BaseConvertableFileMixin from Products.ERP5.mixin.base_convertable import BaseConvertableFileMixin
from Products.ERP5.mixin.text_convertable import TextConvertableMixin from Products.ERP5.mixin.text_convertable import TextConvertableMixin
from Products.ERP5.mixin.ooo_document_extensible_traversable import OOoDocumentExtensibleTraversableMixin from Products.ERP5.mixin.extensible_traversable import OOoDocumentExtensibleTraversableMixin
EMBEDDED_FORMAT = '_embedded' EMBEDDED_FORMAT = '_embedded'
......
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