Commit 024c42aa authored by Jérome Perrin's avatar Jérome Perrin

Merge remote-tracking branch 'upstream/master' into zope4py3

parents 7bd7e01f bc9b6328
Pipeline #38547 failed with stage
in 0 seconds
......@@ -33,7 +33,9 @@
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
<tuple>
<string>document</string>
</tuple>
</value>
</item>
<item>
......
......@@ -19,6 +19,8 @@ preference.setTitle(translateString('Preference for ${name}',
mapping=dict(name=context.getTitle())))
for assignment in context.contentValues(portal_type='Assignment'):
if assignment.getValidationState() != 'open':
continue
group = assignment.getGroup(base=True)
if group:
preference.setPreferredSectionCategory(group)
......
......@@ -1309,6 +1309,12 @@ class TestERP5Base(ERP5TypeTestCase):
site='distibution/tokyo')
self.assertNotEqual(None, assignment.getGroupValue())
assignment.open()
# unrelated assignment that should be ignored
person.newContent(
portal_type='Assignment',
group='nexedi/rentalinux',
site='distibution/new_york',
)
login = person.newContent(
portal_type="ERP5 Login",
reference="user_login",
......
......@@ -291,17 +291,14 @@ class TestDocumentConversionCache(TestDocumentMixin):
def test_08_check_conversion_cache_with_portal_document_type_list(self):
"""Check cache conversion for all Portal Document Types
"""
portal_type_list = list(self.portal.getPortalDocumentTypeList())
portal_type_set = set(self.portal.getPortalDocumentTypeList())
# Some conversions are not implemented
portal_type_set.discard('File')
portal_type_set.discard('Notification Message')
portal_type_set.discard('Web Illustration')
portal_type_set.discard('Web Table')
if 'File' in portal_type_list:
#File conversion is not implemented
portal_type_list.remove('File')
if 'Web Illustration' in portal_type_list:
#Web Illustration conversion is not implemented
portal_type_list.remove('Web Illustration')
if 'Web Table' in portal_type_list:
#Web Table conversion is not implemented
portal_type_list.remove('Web Table')
data_mapping = {'Drawing': 'TEST-en-002.sxd',
'Text': 'TEST-en-002.doc',
'Spreadsheet': 'TEST-en-002.sxc',
......@@ -311,8 +308,8 @@ class TestDocumentConversionCache(TestDocumentMixin):
'File': 'TEST-en-002.rtf',
'PDF': 'TEST-en-002.pdf'}
#Check that all portal_types are handled by test
self.assertEqual(len(portal_type_list), len([pt for pt in portal_type_list if pt in data_mapping]))
for portal_type in portal_type_list:
self.assertEqual(len(portal_type_set), len([pt for pt in portal_type_set if pt in data_mapping]))
for portal_type in portal_type_set:
module = self.portal.getDefaultModule(portal_type=portal_type)
upload_file = self.makeFileUpload(data_mapping[portal_type])
document = module.newContent(portal_type=portal_type)
......
......@@ -69,6 +69,9 @@
schema.description = " (default: " + schema.default + ")";
}
}
if (schema.default !== undefined) {
delete schema.default;
}
return schema;
};
......
......@@ -96,11 +96,12 @@ class GoogleConnector(XMLObject):
Used by Products.ERP5Security.ERP5ExternalOauth2ExtractionPlugin
"""
refresh_token = token['refresh_token']
body = self._getOAuthlibClient().prepare_refresh_body(
client_id=self.getClientId(),
client_secret=self.getSecretKey(),
access_type="offline",
refresh_token=token['refresh_token'],
refresh_token=refresh_token,
)
resp = requests.post(
TOKEN_URL,
......@@ -110,7 +111,9 @@ class GoogleConnector(XMLObject):
)
if not resp.ok:
return {}
return self._getGoogleTokenFromJSONResponse(resp.json())
new_token = resp.json()
new_token.setdefault('refresh_token', refresh_token)
return self._getGoogleTokenFromJSONResponse(new_token)
@security.private
def getUserEntry(self, access_token):
......
......@@ -310,7 +310,7 @@ class TestGoogleLogin(GoogleLoginTestCase):
resp = self.publish(self.portal.getPath(), env=env)
self.assertEqual(resp.getStatus(), six.moves.http_client.OK)
def token_callback(request):
def _check_token_callback_request(request, refresh_token):
self.assertEqual(
request.headers['Content-Type'],
'application/x-www-form-urlencoded')
......@@ -321,33 +321,78 @@ class TestGoogleLogin(GoogleLoginTestCase):
'client_id': self.client_id,
'client_secret': self.secret_key,
'grant_type': 'refresh_token',
'refresh_token': self.refresh_token,
'refresh_token': refresh_token,
}
)
def _userinfo_callback(request, access_token):
self.assertEqual(
request.headers['Authorization'],
'Bearer ' + access_token)
return 200, {}, json.dumps({
"first_name": "John",
"last_name": "Doe",
"email": self.default_google_login_email_address,
})
def token_callback_1(request):
# First refresh, the refresh token is still valid, so it is not
# included in the response, the client gets a new access_token
# and will re-use the same refresh_token
_check_token_callback_request(request, self.refresh_token)
return 200, {}, json.dumps({
'access_token': 'new' + self.access_token,
'expires_in': 3600,
})
def userinfo_callback_1(request):
return _userinfo_callback(request, 'new' + self.access_token)
def token_callback_2(request):
# Second refresh, the refresh token is no longer valid and a new
# token is included in the response, the client gets a new access_token
# and and a new refresh_token
_check_token_callback_request(request, self.refresh_token)
return 200, {}, json.dumps({
'access_token': 'newnew' + self.access_token,
'refresh_token': 'new' + self.refresh_token,
'expires_in': 3600,
})
def userinfo_callback_2(request):
return _userinfo_callback(request, 'newnew' + self.access_token)
def token_callback_3(request):
# Third refresh, we check that the refresh is made with the new refresh
# token from second refresh.
_check_token_callback_request(request, 'new' + self.refresh_token)
return 200, {}, json.dumps({
'access_token': 'newnewnew' + self.access_token,
'expires_in': 3600,
})
def userinfo_callback_3(request):
return _userinfo_callback(request, 'newnewnew' + self.access_token)
for i, (token_callback, userinfo_callback) in enumerate(
zip(
(token_callback_1, token_callback_2, token_callback_3),
(userinfo_callback_1, userinfo_callback_2, userinfo_callback_3),
), 1):
with mock.patch(
'Products.ERP5Security.ERP5ExternalOauth2ExtractionPlugin.time.time',
return_value=time.time() + 5000), \
return_value=time.time() + i * 5000), \
responses.RequestsMock() as rsps:
rsps.add_callback(
responses.POST,
'https://accounts.google.com/o/oauth2/token',
token_callback,
)
# refreshing the token calls userinfo again
rsps.add(
method='GET',
url='https://www.googleapis.com/oauth2/v1/userinfo',
json={
"first_name": "John",
"last_name": "Doe",
"email": self.default_google_login_email_address,
}
# refreshing the token calls userinfo again, with the new access token
rsps.add_callback(
responses.GET,
'https://www.googleapis.com/oauth2/v1/userinfo',
userinfo_callback,
)
resp = self.publish(self.portal.getPath(), env=env)
self.assertEqual(resp.getStatus(), six.moves.http_client.OK)
......
......@@ -57,7 +57,9 @@
</tal:block>
<!-- field value -->
<tal:block tal:define="value python: field.get_value('default'); style_prefix string:with_border_">
<tal:block tal:define="value python: field.get_value('default');
style_prefix string:with_border_;
merge_cells python: True">
<tal:block metal:use-macro="here/field_ods_macro/macros/cell_value" />
</tal:block>
......@@ -74,7 +76,8 @@
<tal:block tal:define="is_list python:same_type(value, []) or same_type(value, ());
is_float python: isinstance(value, modules['six'].integer_types + (float, ));">
<tal:block tal:condition="python: is_list">
<table:table-cell tal:attributes="table:style-name string:${style_prefix}text">
<table:table-cell tal:attributes="table:style-name string:${style_prefix}text;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)">
<tal:block tal:condition="python: field is None" tal:repeat="item value">
<text:p tal:content="item"/>
</tal:block>
......@@ -87,7 +90,8 @@
<tal:block tal:condition="is_float">
<tal:block tal:condition="python: isinstance(value, modules['six'].integer_types)">
<table:table-cell tal:attributes="office:value value;
table:style-name string:${style_prefix}figure"
table:style-name string:${style_prefix}figure;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
office:value-type="float"
table:style-name="figure">
<text:p tal:condition="python: field is None"
......@@ -107,13 +111,15 @@
">
<table:table-cell tal:attributes="office:value value;
table:style-name style_name;
office:value-type python: ('%' in input_style) and 'percentage' or 'float'"
office:value-type python: ('%' in input_style) and 'percentage' or 'float';
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="figure">
<text:p tal:content="python: field.render_pdf(value)" />
</table:table-cell>
</tal:block>
<tal:block tal:condition="python:field.meta_type not in ['FloatField','IntegerField'] and field.meta_type!='ProxyField'">
<table:table-cell tal:attributes="table:style-name string:${style_prefix}string;"
<table:table-cell tal:attributes="table:style-name string:${style_prefix}string;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="string"
office:value-type="string">
<text:p>Error: field is not a FloatField nor an IntegerField</text:p>
......@@ -123,7 +129,8 @@
</tal:block>
<tal:block tal:condition="python: field is None">
<table:table-cell tal:attributes="office:value value;
table:style-name string:${style_prefix}figure"
table:style-name string:${style_prefix}figure;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
office:value-type="float"
table:style-name="figure">
<text:p tal:condition="python: field is None"
......@@ -139,7 +146,8 @@
<tal:block tal:condition="python: isinstance(value, DateTime)">
<tal:block tal:condition="python: field is None">
<table:table-cell tal:attributes="office:date-value python: context.ERP5Site_formatDateForODF(value);
table:style-name string:${style_prefix}date;"
table:style-name string:${style_prefix}date;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="date"
office:value-type="date">
<text:p tal:content="python: value"/>
......@@ -149,7 +157,8 @@
<tal:block tal:condition="python:field.meta_type=='DateTimeField' or (field.meta_type == 'ProxyField' and field.getRecursiveTemplateField().meta_type == 'DateTimeField')">
<tal:block tal:condition="python:field.get_value('date_only')" tal:define="input_order python:field.get_value('input_order') or 'ymd'">
<table:table-cell tal:attributes="office:date-value python: context.ERP5Site_formatDateForODF(value);
table:style-name string:${style_prefix}date_${input_order};"
table:style-name string:${style_prefix}date_${input_order};
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="date"
office:value-type="date">
<text:p tal:content="python: field.render_pdf(value)"/>
......@@ -157,7 +166,8 @@
</tal:block>
<tal:block tal:condition="python:not field.get_value('date_only')" tal:define="input_order python:field.get_value('input_order') or 'ymd'">
<table:table-cell tal:attributes="office:date-value python: context.ERP5Site_formatDateForODF(value);
table:style-name string:${style_prefix}date_with_time_${input_order};"
table:style-name string:${style_prefix}date_with_time_${input_order};
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="date_with_time"
office:value-type="date">
<text:p tal:content="python: field.render_pdf(value)"/>
......@@ -165,7 +175,8 @@
</tal:block>
</tal:block>
<tal:block tal:condition="python:field.meta_type!='DateTimeField' and field.meta_type!='ProxyField'">
<table:table-cell tal:attributes="table:style-name string:${style_prefix}string;"
<table:table-cell tal:attributes="table:style-name string:${style_prefix}string;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="string"
office:value-type="string">
<text:p>Error: field is not a DateTimeField</text:p>
......@@ -174,7 +185,8 @@
</tal:block>
</tal:block>
<tal:block tal:condition="python:not isinstance(value, DateTime)">
<table:table-cell tal:attributes="table:style-name string:${style_prefix}text"
<table:table-cell tal:attributes="table:style-name string:${style_prefix}text;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name="text">
<text:p tal:condition="python: field is None"
tal:content="python: value"/>
......@@ -187,7 +199,8 @@
</tal:block>
<tal:block tal:condition="python: value is None">
<table:table-cell office:value-type='string'
tal:attributes="table:style-name string:${style_prefix}text"
tal:attributes="table:style-name string:${style_prefix}text;
table:number-columns-spanned python:exists('merge_cells') and max(column_len-1, 1)"
table:style-name='text'>
<text:p tal:content="python: ''">
</text:p>
......
......@@ -104,7 +104,7 @@ class TestSupportRequestCreateNewSupportRequest(SupportRequestTestCase):
p for p in self.portal.getPortalDocumentTypeList() \
if p not in ("Sound", "Video", "Web Page", 'Video', 'Web Illustration',
'Web Manifest', 'Web Page', 'Web Script', 'Web Style',
'Web Table', 'Notebook')]
'Web Table', 'Notebook', 'Notification Message')]
# Should not happens but we never know
assert portal_type_list, portal_type_list
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Category" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_folders_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Copy_or_Move_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Delete_objects_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>trade_condition_type</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transformation_type</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Category</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Transformation Type</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
......@@ -23,6 +23,9 @@
<portal_type id="Service Module">
<item>business_application</item>
</portal_type>
<portal_type id="Transformation">
<item>transformation_type</item>
</portal_type>
<portal_type id="Transformation Module">
<item>business_application</item>
</portal_type>
......
......@@ -12,6 +12,8 @@
<list>
<string>all_columns</string>
<string>columns</string>
<string>domain_root_list</string>
<string>domain_tree</string>
<string>portal_types</string>
<string>selection_name</string>
<string>sort</string>
......@@ -88,6 +90,14 @@
<string>translated_description</string>
<string>Translated Description</string>
</tuple>
<tuple>
<string>specialise_title</string>
<string>Transformation Template</string>
</tuple>
<tuple>
<string>transformation_type_translated_title</string>
<string>Transformation Type</string>
</tuple>
<tuple>
<string>owner_title</string>
<string>Owner</string>
......@@ -136,6 +146,21 @@
</list>
</value>
</item>
<item>
<key> <string>domain_root_list</string> </key>
<value>
<list>
<tuple>
<string>transformation_type</string>
<string>Transformation Type</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>domain_tree</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_mode_listbox</string> </value>
......
......@@ -112,7 +112,7 @@
<value>
<list>
<string>my_title</string>
<string>my_reference</string>
<string>my_transformation_type</string>
<string>my_resource_title</string>
<string>my_template_transformation_title_list</string>
</list>
......@@ -122,6 +122,7 @@
<key> <string>right</string> </key>
<value>
<list>
<string>my_reference</string>
<string>my_version</string>
<string>my_variation_base_category_list</string>
<string>my_variation_category_list</string>
......
<?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>my_transformation_type</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>
</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>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_category</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Transformation Type</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -15,5 +15,6 @@ pricing
segment
shape
tariff_nomenclature
transformation_type
variation
visual_pattern
\ No newline at end of file
......@@ -7,3 +7,4 @@ Quantity Unit Conversion Module | business_application
Sale Supply Module | business_application
Service Module | business_application
Transformation Module | business_application
Transformation | transformation_type
\ No newline at end of file
......@@ -28,23 +28,16 @@
##############################################################################
from warnings import warn
import six
if six.PY2:
from base64 import decodestring as decodebytes
else:
from base64 import decodebytes
from zLOG import LOG
from zLOG import LOG, WARNING
from AccessControl import ClassSecurityInfo, getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager
from Products.CMFCore.utils import getToolByName
from erp5.component.mixin.ExtensibleTraversableMixin import ExtensibleTraversableMixin
from Products.ERP5Type.Cache import getReadOnlyTransactionCache
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import get_request
from Products.ERP5Type.Utils import str2bytes, bytes2str
# XXX: these duplicate ones in ERP5.Document
_MARKER = []
......@@ -71,73 +64,74 @@ class BaseExtensibleTraversableMixin(ExtensibleTraversableMixin):
def _forceIdentification(self, request):
# force identification (usable for extensible content)
# This is normally called from __bobo_traverse__ during publication.
# Publication works in two phases (for what matters here):
# - phase 1: traverse the entire path (request URL path)
# - phase 2: locate a user folder and find a user allowed to access
# published document
# This does not work for extensible traversable: here, we must look the
# document up, typically using catalog, and we need to have an
# authenticated user to do so.
# Because we do not expect to have multiple layers of user_folders (only
# one at the portal and one at zope root), and we are below both, we can
# already reliably look for the user up, authenticating the request and
# setting up a reasonable security context to use in catalog lookup
# (or executing other restricted code).
# XXX: this is certainly not the most elegant way of doing so.
old_manager = getSecurityManager()
cache = getReadOnlyTransactionCache()
if cache is not None:
if cache is None:
cache = {}
key = ('__bobo_traverse__', self, 'user')
try:
user = cache[key]
except KeyError:
user = _MARKER
else:
user = _MARKER
old_user = getSecurityManager().getUser()
if user is _MARKER:
old_user = old_manager.getUser()
user = None # By default, do nothing
if old_user is None or old_user.getUserName() == 'Anonymous User':
portal_membership = getToolByName(self.getPortalObject(),
'portal_membership')
if portal_membership is not None:
try:
if request.get('PUBLISHED', _MARKER) is _MARKER:
# request['PUBLISHED'] is required by validate
request['PUBLISHED'] = self
has_published = False
else:
has_published = True
try:
auth = request._auth
except AttributeError:
# This kind of error happens with unrestrictedTraverse,
# because the request object is a fake, and it is just
# a dict object.
# a dict object. Nothing can be done with such an object.
user = None
else:
name = None
acl_users = self.getPortalObject().acl_users
user_list = acl_users._extractUserIds(request, acl_users.plugins)
if len(user_list) > 0:
name = user_list[0][0]
else:
# this logic is copied from identify() in
# AccessControl.User.BasicUserFolder.
if auth and auth.lower().startswith('basic '):
name = bytes2str(decodebytes(str2bytes(auth.split(' ')[-1]))).split(':', 1)[0]
if name is not None:
user = portal_membership._huntUser(name, self)
else:
user = None
if not has_published:
need_published = 'PUBLISHED' not in request.other
try:
del request.other['PUBLISHED']
except AttributeError:
# The same here as above. unrestrictedTraverse provides
# just a plain dict, so request.other does not exist.
del request['PUBLISHED']
if need_published:
# request['PUBLISHED'] is required by validate
request['PUBLISHED'] = self
portal = self.getPortalObject()
# XXX: this is a simplification of the user validation logic from ZPublisher
# - only two specific locations are checked for user folder existence
# - user folder name is hardcoded (instead of going though __allow_groups__)
# - no request.role handling
for user_folder_parent in (
portal,
portal.aq_parent,
):
user = user_folder_parent.acl_users.validate(request, auth)
if user is not None:
if user.getUserName() == 'Anonymous User':
# If the user which is connected is anonymous, do not try to change SecurityManager
user = None
continue
break
except Exception:
LOG("ERP5 WARNING",0,
LOG("ERP5 WARNING", WARNING,
"Failed to retrieve user in __bobo_traverse__ of WebSection %s" % self.getPath(),
error=True)
user = None
if user is not None and user.getUserName() == 'Anonymous User':
user = None # If the user which is connected is anonymous,
# do not try to change SecurityManager
if cache is not None:
finally:
if need_published:
del request.other['PUBLISHED']
cache[key] = user
if user is None:
old_manager = None
if user is not None:
else:
# We need to perform identification
old_manager = getSecurityManager()
newSecurityManager(get_request(), user)
return old_manager, user
......
......@@ -3,6 +3,7 @@ Set up an Workflow with defaults variables needed by ERP5
"""
state = context.newContent(portal_type='Workflow State', reference='draft', title='Draft')
context.setSourceValue(state)
context.setManagerBypass(True)
for v, property_dict in (
('action', {
......
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