Commit 93e30e5e authored by Vincent Pelletier's avatar Vincent Pelletier

Person: Store user id in new user_id property.

reference has two meanings (now that it lost the "login" meaning):
- technical user identifier
- regular ERP5 document reference
This change moves the former to the new "user_id" property.
The latter remains in the "reference" property.
parent 82235674
......@@ -45,7 +45,7 @@ class TestERP5AccessTokenSkins(ERP5TypeTestCase):
indexing is done. """
person_module = self.getPersonModule()
person = person_module.newContent(portal_type='Person',
reference='TESTP-' + new_id)
user_id='TESTP-' + new_id)
person.newContent(portal_type = 'Assignment').open()
transaction.commit()
return person
......
......@@ -83,7 +83,9 @@ class TestERP5Administration(InventoryAPITestCase):
def test_check_consistency_alarm(self):
alarm = self.portal.portal_alarms.check_consistency
person = self.portal.person_module.newContent(portal_type='Person')
# Here we disable user_id so that Person_createUserPreference will not be called
# automatically.
person = self.portal.person_module.newContent(portal_type='Person', user_id=None)
# this document will be non consistent, for PropertyTypeValidity
person.title = 3
# tic right now to make sure the person is indexed, indeed the alarm
......
......@@ -2,8 +2,10 @@ def migrateToERP5Login(self):
assert self.getPortalType() == 'Person'
reference = self.getReference()
if not reference:
# no login is required
# no user id and no login is required
return
if not self.hasUserId() or self.getUserId() == reference:
self.setUserId(reference)
if not self.hasPassword():
# no login is required, but possibly another Login type object is required if implemented
return
......
......@@ -8,6 +8,7 @@
</portal_type>
<portal_type id="Person">
<item>DefaultImage</item>
<item>ERP5User</item>
</portal_type>
<portal_type id="Preference">
<item>TelephonePreference</item>
......
......@@ -10,7 +10,8 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>enabled</string>
<string>description</string>
<string>title</string>
</list>
</value>
</item>
......@@ -52,10 +53,6 @@
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
......@@ -76,21 +73,25 @@
<value>
<dictionary>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
<key> <string>description</string> </key>
<value> <string>The username this person will use to log in the system. The system will check that there isn\'t another user with the same username.</string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary>
</value>
</item>
......
......@@ -146,7 +146,7 @@
</tuple>
<tuple>
<string>reference</string>
<string>Username</string>
<string>Reference</string>
</tuple>
<tuple>
<string>product_line_translated_title</string>
......@@ -343,7 +343,7 @@ Role & Region
</tuple>
<tuple>
<string>reference</string>
<string>Username</string>
<string>Reference</string>
</tuple>
<tuple>
<string>product_line_translated_title</string>
......@@ -406,7 +406,7 @@ Role & Region
</tuple>
<tuple>
<string>reference</string>
<string>Username</string>
<string>Reference</string>
</tuple>
<tuple>
<string>owner_title</string>
......
"""Hook called when a person object is closed.
We want to reset the reference, which is the user login in ERP5Security.
We want to reset reference, which is the user login in ERP5Security.
One exception is when a person object is installed from business template.
"""
is_business_template_installation = context.REQUEST.get('is_business_template_installation', 0)
if not is_business_template_installation:
context.setUserId(None)
context.Person_initUserId()
if not context.REQUEST.get('is_business_template_installation', 0):
context.setReference(None)
......@@ -57,6 +57,7 @@
<value>
<tuple>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
......
return context.getReference()
user_id = context.getUserId()
if user_id is None:
# BBB: ERP5User-style user ?
user_id = context.getReference()
return user_id
# this script can be overridden as you wish.
# this script can be overridden, but always call it when doing so (use skinSuper).
context.Person_initUserId()
......@@ -52,6 +52,15 @@
<key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
......
if not context.hasUserId():
context.setUserId(
'P%i' % (
context.getPortalObject().portal_ids.generateNewId(
id_group='user_id',
id_generator='non_continuous_integer_increasing',
),
),
)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_initUserId</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Guard" module="Products.DCWorkflow.Guard"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>roles</string> </key>
<value>
<tuple>
<string>Owner</string>
</tuple>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -90,7 +90,7 @@
<value>
<list>
<string>my_title</string>
<string>my_reference</string>
<string>my_user_id</string>
</list>
</value>
</item>
......
......@@ -10,14 +10,13 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>editable</string>
<string>enabled</string>
<string>default</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_reference</string> </value>
<value> <string>my_user_id</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......@@ -54,7 +53,7 @@
<value>
<dictionary>
<item>
<key> <string>enabled</string> </key>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
......@@ -79,12 +78,8 @@
<value>
<dictionary>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
......@@ -106,19 +101,13 @@
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.TALESField</string>
<string>TALESMethod</string>
</tuple>
<none/>
</tuple>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: request.AUTHENTICATED_USER.has_permission(\'Manage users\', here)</string> </value>
<value> <string>python: context.Person_getUserId()</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -10,9 +10,9 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>enabled</string>
<string>editable</string>
<string>description</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
......@@ -79,21 +79,13 @@
\n
The system will check that there isn\'t another user with the same username.</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
......
......@@ -10,8 +10,10 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
<string>description</string>
<string>editable</string>
<string>enabled</string>
<string>title</string>
</list>
</value>
</item>
......@@ -88,7 +90,15 @@
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string>The username this person will use to log in the system. The system will check that there isn\'t another user with the same username.</string> </value>
<value> <string>The user id this person has in the system. Used to track ownership and local roles. The system will check that there isn\'t another user with the same id.</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
......@@ -104,7 +114,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
<value> <string>User ID</string> </value>
</item>
</dictionary>
</value>
......
......@@ -40,7 +40,7 @@
</item>
<item>
<key> <string>description</string> </key>
<value> <string>set a login</string> </value>
<value> <string>set a user id</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
......@@ -56,7 +56,7 @@
<key> <string>method_id</string> </key>
<value>
<list>
<string>_setReference</string>
<string>_setUserId</string>
</list>
</value>
</item>
......
kwargs = state_change['kwargs']
person = state_change['object']
if not person.hasReference():
person.edit(reference=kwargs['reference'])
if not person.hasUserId():
person.edit(user_id=kwargs['reference'])
person.newContent(
portal_type='ERP5 Login',
password=kwargs['password'],
......
......@@ -9,4 +9,4 @@ if password != password_confirm:
reference = kwargs['reference']
if not reference:
raise ValidationFailed(translateString('User ID is not specified.'))
raise ValidationFailed(translateString('User Login is not specified.'))
......@@ -2,6 +2,7 @@ Notification Message | ItemAggregation
Notification Message | Reference
Organisation | DefaultImage
Person | DefaultImage
Person | ERP5User
Preference | TelephonePreference
Previous Causality Movement Group | PreviousCausalityMovementGroup
Query | TextDocument
......
......@@ -4,10 +4,9 @@ value -- field value (string)
REQUEST -- standard REQUEST variable"""
if value:
# Same tag is used as in Document.Person._setReference, in order to protect against
# concurrency between Credential Request and Person object too
tag = 'Person_setReference_%s' % value.encode('hex')
if context.getPortalObject().portal_activities.countMessageWithTag(tag):
# Same tag is used as in ERP5 Login _setReference, in order to protect against
# concurrency between Credential Request and ERP5 Login object too
if context.getPortalObject().portal_activities.countMessageWithTag('set_login_' + value.encode('hex')):
return False
def getRealContext():
......@@ -29,6 +28,12 @@ context = getRealContext()
if context.getPortalType() == "Credential Request":
related_person = context.getDestinationDecisionValue(portal_type="Person")
if related_person is not None:
for erp5_login_value in related_person.objectValues(
portal_type=self.getPortalObject().getPortalLoginTypeList(),
):
if erp5_login_value.getValidationState() == 'validated' and erp5_login_value.getReference() == value:
return True
# BBB: for Persons who still use their reference as login
if related_person.getReference() == value:
return True
......
......@@ -29,10 +29,8 @@ if not login.hasReference():
if not reference:
raise ValueError, "Impossible to create an account without login"
login.setReference(reference)
if not person.hasReference():
person.setReference(reference)
else:
reference = person.getReference()
if not user_id:
person.setUserId(reference)
password = None
# Set password if no password on the Login
......
......@@ -37,9 +37,9 @@ credential_request = module.newContent(
date_of_birth=date_of_birth)
credential_request.setCategoryList(category_list)
# Same tag is used as in Document.Person._setReference, in order to protect against
# Same tag is used as in ERP5 Login._setReference, in order to protect against
# concurrency between Credential Request and Person object too
credential_request.reindexObject(activate_kw=dict(tag='Person_setReference_%s' % reference.encode('hex')))
credential_request.reindexObject(activate_kw=dict(tag='set_login_%s' % reference.encode('hex')))
#We attach the current user to the credential request if not anonymous
if not context.portal_membership.isAnonymousUser():
......
......@@ -47,8 +47,7 @@ else:
# if we are changing password for current logged in user then do it
# within same transaction and update client side credentials cookie
username = person.getReference()
if password and username == str(portal.portal_membership.getAuthenticatedMember()):
if password:
# The password is updated synchronously and the the rest of the credential Update is done later
login_reference = credential_update.Credential_updatePersonPassword()
portal.cookie_authentication.credentialsChanged(
......
......@@ -10,7 +10,9 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>description</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
......@@ -75,13 +77,17 @@
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string>The username this person will use to log in the system. The system will check that there isn\'t another user with the same username.</string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
......@@ -91,6 +97,10 @@
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary>
</value>
</item>
......
......@@ -10,7 +10,9 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>description</string>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
......@@ -75,22 +77,30 @@
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string>The username this person will use to log in the system. The system will check that there isn\'t another user with the same username.</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary>
</value>
</item>
......
......@@ -14095,9 +14095,6 @@ msgstr "L'utilisateur ${user} n'existe pas."
msgid "User Account Workflow"
msgstr "Workflow du compte utilisateur"
msgid "User ID is not specified."
msgstr "L'identifiant de l'utilisateur n'es pas spécifié."
msgid "User Interface"
msgstr "Interface utilisateur"
......@@ -14107,6 +14104,9 @@ msgstr "Langues de l'interface utilisateur"
msgid "User Login"
msgstr "Nom d'utilisateur"
msgid "User Login is not specified."
msgstr "Le nom d'utilisateur n'est pas spécifié."
msgid "User Name"
msgstr "Nom d'utilisateur"
......
......@@ -7153,15 +7153,15 @@ msgstr "존재하지 않는 이용자: ${user}"
msgid "User Account Workflow"
msgstr "사용자 계정 워크플로우"
msgid "User ID is not specified."
msgstr "이용자 ID가 지정되지 않았습니다."
msgid "User Interface"
msgstr "이용자 인터페이스"
msgid "User Login"
msgstr "이용자 로그인"
msgid "User Login is not specified."
msgstr "이용자 로그인 가 지정되지 않았습니다."
msgid "User Password"
msgstr "이용자 패스워드"
......
......@@ -6489,9 +6489,6 @@ msgstr "Usuário ${user} não existe."
msgid "User Account Workflow"
msgstr "Workflow de Contas de Usuários"
msgid "User ID is not specified."
msgstr "ID do Usuário não esta especificado."
msgid "User Interface"
msgstr "Interface do Usuário"
......@@ -6501,6 +6498,9 @@ msgstr "Idiomas do Usuário (UI)"
msgid "User Login"
msgstr "Usuário"
msgid "User Login is not specified."
msgstr "Usuário não esta especificado."
msgid "User Name"
msgstr "Usuário"
......
......@@ -34,6 +34,8 @@ from Products.ERP5.Document.Node import Node
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.mixin.encrypted_password import EncryptedPasswordMixin
from Products.ERP5.mixin.login_account_provider import LoginAccountProviderMixin
from Products.ERP5.mixin.erp5_user import ERP5UserMixin
from Products.DCWorkflow.DCWorkflow import ValidationFailed
try:
from Products import PluggableAuthService
......@@ -42,7 +44,11 @@ try:
except ImportError:
PluggableAuthService = None
class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin):
class UserExistsError(ValidationFailed):
def __init__(self, user_id):
super(UserExistsError, self).__init__('user id %s already exists' % (user_id, ))
class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin, ERP5UserMixin):
"""
An Person object holds the information about
an person (ex. you, me, someone in the company,
......@@ -122,6 +128,56 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin):
self.hasMiddleName() or \
self._baseHasTitle()
def __checkUserIdAvailability(self, pas_plugin_class, user_id=None, login=None):
# Encode reference to hex to prevent uppercase/lowercase conflict in
# activity table (when calling countMessageWithTag)
if user_id:
tag = 'set_userid_' + user_id.encode('hex')
else:
tag = 'set_login_' + login.encode('hex')
# Check that there no existing user
acl_users = getattr(self, 'acl_users', None)
if PluggableAuthService is not None and isinstance(acl_users,
PluggableAuthService.PluggableAuthService.PluggableAuthService):
plugin_name_set = {
plugin_name for plugin_name, plugin_value in acl_users.plugins.listPlugins(
PluggableAuthService.interfaces.plugins.IUserEnumerationPlugin,
) if isinstance(plugin_value, pas_plugin_class)
}
if plugin_name_set:
if any(
user['pluginid'] in plugin_name_set
for user in acl_users.searchUsers(
id=user_id,
login=login,
exact_match=True,
)
):
raise UserExistsError(user_id)
else:
# PAS is used, without expected enumeration plugin: property has no
# effect on user enumeration, skip checks.
# XXX: what if desired plugin becomes active later ?
return
# Check that there is no reindexation related to reference indexation
if self.getPortalObject().portal_activities.countMessageWithTag(tag):
raise UserExistsError(user_id)
# Prevent concurrent transaction to set the same reference on 2
# different persons
# XXX: person_module is rather large because of all permission
# declarations, it would be better to find a smaller document to use
# here.
self.getParentValue().serialize()
# Prevent to set the same reference on 2 different persons during the
# same transaction
transactional_variable = getTransactionalVariable()
if tag in transactional_variable:
raise UserExistsError(user_id)
else:
transactional_variable[tag] = None
self.reindexObject(activate_kw={'tag': tag})
def _setReference(self, value):
"""
Set the user id. This method is defined explicitly, because:
......@@ -129,47 +185,34 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin):
- we want to apply a different permission
- we want to prevent duplicated user ids, but only when
PAS _AND_ (ERP5UserManager or ERP5LoginUserManager) are used
PAS _AND_ ERP5UserManager are used
"""
activate_kw = {}
portal = self.getPortalObject()
if value:
# Encode reference to hex to prevent uppercase/lowercase conflict in
# activity table (when calling countMessageWithTag)
activate_kw['tag'] = tag = 'Person_setReference_' + value.encode('hex')
# Check that there no existing user
acl_users = portal.acl_users
if PluggableAuthService is not None and isinstance(acl_users,
PluggableAuthService.PluggableAuthService.PluggableAuthService):
plugin_list = acl_users.plugins.listPlugins(
PluggableAuthService.interfaces.plugins.IUserEnumerationPlugin)
for plugin_name, plugin_value in plugin_list:
if isinstance(plugin_value, (ERP5UserManager, ERP5LoginUserManager)):
user_list = acl_users.searchUsers(id=value,
exact_match=True)
if len(user_list) > 0:
raise RuntimeError, 'user id %s already exist' % (value,)
break
# Check that there is no reindexation related to reference indexation
if portal.portal_activities.countMessageWithTag(tag):
raise RuntimeError, 'user id %s already exist' % (value,)
# Prevent concurrent transaction to set the same reference on 2
# different persons
self.getParentValue().serialize()
# Prevent to set the same reference on 2 different persons during the
# same transaction
transactional_variable = getTransactionalVariable()
if tag in transactional_variable:
raise RuntimeError, 'user id %s already exist' % (value,)
else:
transactional_variable[tag] = None
if value != self.getUserId():
if value:
self.__checkUserIdAvailability(
pas_plugin_class=ERP5UserManager,
login=value,
)
self._baseSetReference(value)
# invalid the cache for ERP5Security
self.getPortalObject().portal_caches.clearCache(cache_factory_list=('erp5_content_short', ))
def _setUserId(self, value):
"""
Set the user id. This method is defined explicitly, because:
- we want to apply a different permission
self._baseSetReference(value)
self.reindexObject(activate_kw=activate_kw)
# invalid the cache for ERP5Security
portal_caches = portal.portal_caches
portal_caches.clearCache(cache_factory_list=('erp5_content_short', ))
- we want to prevent duplicated user ids, but only when
PAS _AND_ ERP5LoginUserManager are used
"""
if value != self.getUserId():
if value:
self.__checkUserIdAvailability(
pas_plugin_class=ERP5LoginUserManager,
user_id=value,
)
self._baseSetUserId(value)
# Time management
security.declareProtected(Permissions.AccessContentsInformation,
......
<catalog_method>
<item key="sql_clear_catalog" type="int">
<value>1</value>
</item>
</catalog_method>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z0_drop_user</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<catalog_method>
<item key="sql_uncatalog_object" type="int">
<value>1</value>
</item>
</catalog_method>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z0_uncatalog_user</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<catalog_method>
<item key="sql_catalog_object_list" type="int">
<value>1</value>
</item>
<item key="_is_filtered_archive" type="int">
<value>1</value>
</item>
<item key="_filter_expression_archive" type="str">
<value>python: 'ERP5User' in getattr(getattr(context.getPortalObject().portal_types, context.getPortalType(), None), 'getTypePropertySheetList', lambda: ())()</value>
</item>
<item key="_filter_expression_cache_key_archive" type="tuple">
<value>portal_type</value>
</item>
</catalog_method>
REPLACE INTO `user` (`uid`, `user_id`) VALUES
<dtml-in prefix="loop" expr="_.range(_.len(uid))">
(
<dtml-sqlvar expr="uid[loop_item]" type="int">,
<dtml-sqlvar expr="getUserId[loop_item]" type="string">
)
<dtml-if sequence-end><dtml-else>,</dtml-if>
</dtml-in>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid\r\n
getUserId</string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z_catalog_user_list</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<catalog_method>
<item key="sql_clear_catalog" type="int">
<value>1</value>
</item>
</catalog_method>
CREATE TABLE `user` (
`uid` BIGINT UNSIGNED NOT NULL,
`user_id` varchar(255) binary default '',
PRIMARY KEY (`uid`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB;
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z_create_user</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -9,5 +9,6 @@
<key>roles_and_users</key>
<key>stock</key>
<key>subject</key>
<key>user</key>
<key>versioning</key>
</key_list>
\ No newline at end of file
......@@ -19,6 +19,7 @@ erp5_mysql_innodb/z0_drop_stock
erp5_mysql_innodb/z0_drop_subject
erp5_mysql_innodb/z0_drop_transformation
erp5_mysql_innodb/z0_drop_translation
erp5_mysql_innodb/z0_drop_user
erp5_mysql_innodb/z0_drop_versioning
erp5_mysql_innodb/z0_uncatalog_alarm
erp5_mysql_innodb/z0_uncatalog_category
......@@ -29,6 +30,7 @@ erp5_mysql_innodb/z0_uncatalog_predicate_category
erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion
erp5_mysql_innodb/z0_uncatalog_stock
erp5_mysql_innodb/z0_uncatalog_transformation
erp5_mysql_innodb/z0_uncatalog_user
erp5_mysql_innodb/z0_uncatalog_versioning
erp5_mysql_innodb/z_catalog_alarm_list
erp5_mysql_innodb/z_catalog_delivery_list
......@@ -47,6 +49,7 @@ erp5_mysql_innodb/z_catalog_stock_list_without_delete_for_inventory_virtual_move
erp5_mysql_innodb/z_catalog_subject_list
erp5_mysql_innodb/z_catalog_transformation_list
erp5_mysql_innodb/z_catalog_translation_list
erp5_mysql_innodb/z_catalog_user_list
erp5_mysql_innodb/z_catalog_versioning_list
erp5_mysql_innodb/z_clear_reserved
erp5_mysql_innodb/z_count_results
......@@ -65,6 +68,7 @@ erp5_mysql_innodb/z_create_stock
erp5_mysql_innodb/z_create_subject
erp5_mysql_innodb/z_create_transformation
erp5_mysql_innodb/z_create_translation
erp5_mysql_innodb/z_create_user
erp5_mysql_innodb/z_create_versioning
erp5_mysql_innodb/z_delete_recorded_object_list
erp5_mysql_innodb/z_delete_translation_list
......
......@@ -8,4 +8,5 @@ predicate_category
roles_and_users
stock
subject
user
versioning
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<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>id</string> </key>
<value> <string>ERP5User</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</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>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The user ID required to login</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>user_id_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>rw</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2016 Nexedi SA and Contributors. All Rights Reserved.
# Vincent Pelletier <vincent@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions
class ERP5UserMixin:
"""
Makes reference acquire from user_id.
Intended to be only used on documents having the ERP5User property sheet.
"""
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declareProtected(Permissions.AccessContentsInformation, 'getReference')
def getReference(self, default=None):
"""
Fallback on user id
"""
return self._baseGetReference() or self.getUserId(default)
security.declareProtected(Permissions.AccessContentsInformation, 'hasReference')
def hasReference(self):
"""
Fallback on user id
"""
return self._baseHasReference() or self.hasUserId()
InitializeClass(ERP5UserMixin)
......@@ -52,51 +52,52 @@ class TestCertificateAuthority(ERP5TypeTestCase):
person.newContent(portal_type='Assignment').open()
person.newContent(portal_type='ERP5 Login', reference=login).validate()
self.tic()
return login
return person.getUserId(), login
def test_person_request_certificate(self):
login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate'])
self.assertTrue('CN=%s' % user_id in certificate['certificate'])
def test_person_revoke_certificate(self):
login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
self.assertRaises(ValueError, person.revokeCertificate)
def test_person_request_revoke_certificate(self):
login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate'])
self.assertTrue('CN=%s' % user_id in certificate['certificate'])
person.revokeCertificate()
def test_person_request_certificate_twice(self):
login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate'])
self.assertTrue('CN=%s' % user_id in certificate['certificate'])
self.assertRaises(ValueError, person.getCertificate)
def test_person_request_certificate_for_another(self):
login = self._createPerson()
login2 = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
user_id2, login2 = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
self.loginByUserName(login2)
self.assertRaises(Unauthorized, person.getCertificate)
def test_person_revoke_certificate_for_another(self):
login = self._createPerson()
login2 = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
user_id, login = self._createPerson()
user_id2, login2 = self._createPerson()
self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate'])
self.assertTrue('CN=%s' % user_id in certificate['certificate'])
self.loginByUserName(login2)
self.assertRaises(Unauthorized, person.revokeCertificate)
......
......@@ -76,8 +76,8 @@ class TestPerson(ERP5TypeTestCase):
person_copy_id = person_module.manage_pasteObjects(person_copy)[0]['new_id']
person_copy_obj = person_module[person_copy_id]
## because we copy/paste Person object in the same ERP5
## instance its reference must be resetted
self.assertEqual(person_copy_obj.getReference(), None)
## instance its user_id must be reset
self.assertNotEqual(person_copy_obj.getUserId(), person.getUserId())
## set object as if installed from bt5 (simulate it)
request = self.app.REQUEST
......@@ -88,6 +88,8 @@ class TestPerson(ERP5TypeTestCase):
## because we setup Person object from business template
## its reference must NOT be resetted
self.assertEqual(person_copy_obj.getReference(), person.getReference())
# User id must still be different
self.assertNotEqual(person_copy_obj.getUserId(), person.getUserId())
def test_PersonGetTitleDefined(self):
p = self._makeOne(title="title")
......@@ -95,20 +97,20 @@ class TestPerson(ERP5TypeTestCase):
# title & first_name, last_name
def testEmptyTitleFallbackOnId(self):
p = self._makeOne(id=self.id())
self.assertEqual(self.id(), p.getTitle())
p = self._makeOne()
self.assertEqual(p.getUserId(), p.getTitle())
def testEmptyTranslatedTitleFallbackOnId(self):
p = self._makeOne(id=self.id())
self.assertEqual(self.id(), p.getTranslatedTitle())
p = self._makeOne()
self.assertEqual(p.getUserId(), p.getTranslatedTitle())
def testEmptyCompactTitleFallbackOnId(self):
p = self._makeOne(id=self.id())
self.assertEqual(self.id(), p.getCompactTitle())
p = self._makeOne()
self.assertEqual(p.getUserId(), p.getCompactTitle())
def testEmptyCompactTranslatedTitleFallbackOnId(self):
p = self._makeOne(id=self.id())
self.assertEqual(self.id(), p.getCompactTranslatedTitle())
p = self._makeOne()
self.assertEqual(p.getUserId(), p.getCompactTranslatedTitle())
def testEmptyTitleFallbackOnReference(self):
p = self._makeOne(reference='reference')
......@@ -183,9 +185,13 @@ class TestPerson(ERP5TypeTestCase):
self.assertEqual('first middle last', p.getTitle())
def testGetTitleOrId(self):
p = self._makeOne(id='person')
self.assertEqual('person', p.getTitleOrId())
self.assertEqual('person', p.title_or_id())
p = self._makeOne()
self.assertEqual(p.getUserId(), p.getTitleOrId())
self.assertEqual(p.getUserId(), p.title_or_id())
p.edit(reference='reference')
self.assertEqual('reference', p.getTitleOrId())
self.assertEqual('reference', p.title_or_id())
p.edit( first_name='first',
last_name='last', )
......
......@@ -85,14 +85,14 @@ class TestQueryModule(ERP5TypeTestCase):
def test_reply_query_with_persons(self):
owner_person = self.portal.person_module.newContent(
portal_type='Person',
reference='owner_user',
user_id='owner_user',
password='secret',
default_email_text='owner_user@example.invalid')
assignment = owner_person.newContent(portal_type='Assignment')
assignment.validate()
question_person = self.portal.person_module.newContent(
portal_type='Person',
reference='question_user',
user_id='question_user',
password='secret',
default_email_text='question_user@example.invalid')
assignment = question_person.newContent(portal_type='Assignment')
......
......@@ -105,7 +105,7 @@ class TestWorklist(ERP5TypeTestCase):
self.logMessage("Create user: %s" % user_login)
person = module.newContent(
portal_type='Person',
reference=user_login,
user_id=user_login,
password='hackme',
)
# Create the Assignment.
......
......@@ -106,7 +106,7 @@ class ERP5LoginUserManager(BasePlugin):
if login_value is None:
return
user_value = login_value.getParentValue()
if not user_value.hasReference():
if not user_value.hasUserId():
return
if user_value.getValidationState() == 'deleted':
return
......@@ -136,7 +136,7 @@ class ERP5LoginUserManager(BasePlugin):
return
if login_value.isLoginBlocked():
return
return (user_value.getReference(), login_value.getReference())
return (user_value.getUserId(), login_value.getReference())
def _getLoginValueFromLogin(self, login, login_portal_type=None):
user_list = self.enumerateUsers(
......@@ -166,8 +166,7 @@ class ERP5LoginUserManager(BasePlugin):
login_portal_type = portal.getPortalLoginTypeList()
unrestrictedSearchResults = portal.portal_catalog.unrestrictedSearchResults
searchUser = lambda **kw: unrestrictedSearchResults(
select_list=('reference', ),
portal_type='Person',
select_list=('user_id', ),
**kw
).dictionaries()
searchLogin = lambda **kw: unrestrictedSearchResults(
......@@ -190,13 +189,13 @@ class ERP5LoginUserManager(BasePlugin):
requested = lambda x: True
user_list = [
x for x in searchUser(
reference={
user_id={
'query': id,
'key': 'ExactMatch' if exact_match else 'Keyword',
},
limit=max_results,
)
if requested(x['reference'])
if requested(x['user_id'])
]
else:
user_list = []
......@@ -235,7 +234,7 @@ class ERP5LoginUserManager(BasePlugin):
plugin_id = self.getId()
result = [
{
'id': user['reference'],
'id': user['user_id'],
# Note: PAS forbids us from returning more than one entry per given id,
# so take any available login.
'login': login_dict.get(user['uid'], [{'reference': None}])[0]['reference'],
......@@ -253,7 +252,7 @@ class ERP5LoginUserManager(BasePlugin):
for login in login_dict.get(user['uid'], [])
],
}
for user in user_list if user['reference']
for user in user_list if user['user_id']
]
for special_user_name in special_user_name_set:
# Note: special users are a bastard design in Zope: they are expected to
......
......@@ -270,7 +270,7 @@ class TestUserManagement(ERP5TypeTestCase):
substring = 'person_id'
user_id_set = {substring + '1', '1' + substring}
for user_id in user_id_set:
self._makePerson(reference=user_id)
self._makePerson(user_id=user_id)
self.assertEqual(
user_id_set,
{x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=False)},
......@@ -288,9 +288,9 @@ class TestUserManagement(ERP5TypeTestCase):
def test_searchUsersIdExactMatch(self):
substring = 'person2_id'
self._makePerson(reference=substring)
self._makePerson(reference=substring + '1')
self._makePerson(reference='1' + substring)
self._makePerson(user_id=substring)
self._makePerson(user_id=substring + '1')
self._makePerson(user_id='1' + substring)
self.assertEqual(
[substring],
[x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=True)],
......@@ -309,7 +309,7 @@ class TestUserManagement(ERP5TypeTestCase):
def test_MultipleUsers(self):
"""Tests that it's refused to create two Persons with same user id."""
user_id, login, _ = self._makePerson()
self.assertRaises(ValidationFailed, self._makePerson, reference=user_id)
self.assertRaises(ValidationFailed, self._makePerson, user_id=user_id)
self.assertRaises(ValidationFailed, self._makePerson, login=login)
def test_MultiplePersonReferenceWithoutCommit(self):
......@@ -319,9 +319,9 @@ class TestUserManagement(ERP5TypeTestCase):
"""
person_module = self.getPersonModule()
new_person = person_module.newContent(
portal_type='Person', reference='new_person')
portal_type='Person', user_id='new_person')
self.assertRaises(ValidationFailed, person_module.newContent,
portal_type='Person', reference='new_person')
portal_type='Person', user_id='new_person')
def test_MultiplePersonReferenceWithoutTic(self):
"""
......@@ -330,10 +330,10 @@ class TestUserManagement(ERP5TypeTestCase):
"""
person_module = self.getPersonModule()
new_person = person_module.newContent(
portal_type='Person', reference='new_person')
portal_type='Person', user_id='new_person')
self.commit()
self.assertRaises(ValidationFailed, person_module.newContent,
portal_type='Person', reference='new_person')
portal_type='Person', user_id='new_person')
def test_MultiplePersonReferenceConcurrentTransaction(self):
"""
......@@ -359,13 +359,13 @@ class TestUserManagement(ERP5TypeTestCase):
person_module = self.getPersonModule()
try:
self.assertRaises(DummyTestException, person_module.newContent,
portal_type='Person', reference='new_person')
portal_type='Person', user_id='new_person')
finally:
Base.serialize = Base.serialize_call
def test_PersonCopyAndPaste(self):
"""If we copy and paste a person, login must not be copyied."""
user_id, _, _ = self._makePerson(reference='new_person')
user_id, _, _ = self._makePerson(user_id='new_person')
user, = self.portal.acl_users.searchUsers(id=user_id, exact_match=True)
user_value = self.portal.restrictedTraverse(user['path'])
container = user_value.getParentValue()
......@@ -451,7 +451,7 @@ class TestUserManagement(ERP5TypeTestCase):
pers = self.portal.person_module.newContent(
portal_type='Person',
reference='the_user',
reference=None,
user_id=None,
)
pers.newContent(
portal_type='Assignment',
......@@ -543,13 +543,13 @@ class TestUserManagement(ERP5TypeTestCase):
user_id, login, password = self._makePerson()
acl_user, = self.portal.acl_users.searchUsers(id=user_id, exact_match=True)
person = self.portal.restrictedTraverse(acl_user['path'])
person.setReference(None)
person.setUserId(None)
self.tic()
self.assertEqual(None, person.Person_getUserId())
def test_duplicatePersonUserId(self):
user_id, _, _ = self._makePerson()
self.assertRaises(ValidationFailed, self._makePerson, reference=user_id)
self.assertRaises(ValidationFailed, self._makePerson, user_id=user_id)
def test_duplicateLoginReference(self):
_, login1, _ = self._makePerson()
......@@ -684,7 +684,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
self.username = 'usérn@me'
# create a user and open an assignement
pers = self.getPersonModule().newContent(portal_type='Person',
reference=self.username)
user_id=self.username)
assignment = pers.newContent( portal_type='Assignment',
group='subcat',
site='subcat',
......@@ -892,7 +892,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
first_name='First',
last_name='Last')
loginable_person = self.getPersonModule().newContent(portal_type='Person',
reference='guest',
user_id='guest',
password='guest')
assignment = loginable_person.newContent(portal_type='Assignment',
function='another_subcat')
......@@ -1138,7 +1138,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
# But non-module objects, with subobjects that acquire local
# roles, should reindex their security recursively:
person, = [rec.getObject()
for rec in person_module.searchFolder(reference=self.username)]
for rec in person_module.searchFolder(user_id=self.username)]
self.assertTrue(len(person.objectIds()))
person.reindexObjectSecurity()
self.commit()
......
......@@ -88,7 +88,15 @@ def Base_asXML(object, root=None):
# We have to find every property
for prop_id in set(self.propertyIds()):
# In most case, we should not synchronize acquired properties
if prop_id not in ('uid', 'workflow_history', 'id', 'portal_type',):
if prop_id not in ('uid', 'workflow_history', 'id', 'portal_type') and (prop_id != 'user_id' or 'ERP5User' not in getattr(
getattr(
self.getPortalObject().portal_types,
self.getPortalType(),
None,
),
'getTypePropertySheetList',
lambda: (),
)()):
value = self.getProperty(prop_id)
if value is None:
prop_type = 'None'
......
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