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): ...@@ -45,7 +45,7 @@ class TestERP5AccessTokenSkins(ERP5TypeTestCase):
indexing is done. """ indexing is done. """
person_module = self.getPersonModule() person_module = self.getPersonModule()
person = person_module.newContent(portal_type='Person', person = person_module.newContent(portal_type='Person',
reference='TESTP-' + new_id) user_id='TESTP-' + new_id)
person.newContent(portal_type = 'Assignment').open() person.newContent(portal_type = 'Assignment').open()
transaction.commit() transaction.commit()
return person return person
......
...@@ -83,7 +83,9 @@ class TestERP5Administration(InventoryAPITestCase): ...@@ -83,7 +83,9 @@ class TestERP5Administration(InventoryAPITestCase):
def test_check_consistency_alarm(self): def test_check_consistency_alarm(self):
alarm = self.portal.portal_alarms.check_consistency 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 # this document will be non consistent, for PropertyTypeValidity
person.title = 3 person.title = 3
# tic right now to make sure the person is indexed, indeed the alarm # tic right now to make sure the person is indexed, indeed the alarm
......
...@@ -2,8 +2,10 @@ def migrateToERP5Login(self): ...@@ -2,8 +2,10 @@ def migrateToERP5Login(self):
assert self.getPortalType() == 'Person' assert self.getPortalType() == 'Person'
reference = self.getReference() reference = self.getReference()
if not reference: if not reference:
# no login is required # no user id and no login is required
return return
if not self.hasUserId() or self.getUserId() == reference:
self.setUserId(reference)
if not self.hasPassword(): if not self.hasPassword():
# no login is required, but possibly another Login type object is required if implemented # no login is required, but possibly another Login type object is required if implemented
return return
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
</portal_type> </portal_type>
<portal_type id="Person"> <portal_type id="Person">
<item>DefaultImage</item> <item>DefaultImage</item>
<item>ERP5User</item>
</portal_type> </portal_type>
<portal_type id="Preference"> <portal_type id="Preference">
<item>TelephonePreference</item> <item>TelephonePreference</item>
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>enabled</string> <string>description</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -52,10 +53,6 @@ ...@@ -52,10 +53,6 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -76,21 +73,25 @@ ...@@ -76,21 +73,25 @@
<value> <value>
<dictionary> <dictionary>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>description</string> </key>
<value> <int>1</int> </value> <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>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value> <value> <string>my_string_field</string> </value>
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
......
...@@ -146,7 +146,7 @@ ...@@ -146,7 +146,7 @@
</tuple> </tuple>
<tuple> <tuple>
<string>reference</string> <string>reference</string>
<string>Username</string> <string>Reference</string>
</tuple> </tuple>
<tuple> <tuple>
<string>product_line_translated_title</string> <string>product_line_translated_title</string>
...@@ -343,7 +343,7 @@ Role & Region ...@@ -343,7 +343,7 @@ Role & Region
</tuple> </tuple>
<tuple> <tuple>
<string>reference</string> <string>reference</string>
<string>Username</string> <string>Reference</string>
</tuple> </tuple>
<tuple> <tuple>
<string>product_line_translated_title</string> <string>product_line_translated_title</string>
...@@ -406,7 +406,7 @@ Role & Region ...@@ -406,7 +406,7 @@ Role & Region
</tuple> </tuple>
<tuple> <tuple>
<string>reference</string> <string>reference</string>
<string>Username</string> <string>Reference</string>
</tuple> </tuple>
<tuple> <tuple>
<string>owner_title</string> <string>owner_title</string>
......
"""Hook called when a person object is closed. """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. One exception is when a person object is installed from business template.
""" """
is_business_template_installation = context.REQUEST.get('is_business_template_installation', 0) context.setUserId(None)
if not is_business_template_installation: context.Person_initUserId()
if not context.REQUEST.get('is_business_template_installation', 0):
context.setReference(None) context.setReference(None)
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
<value> <value>
<tuple> <tuple>
<string>Manager</string> <string>Manager</string>
<string>Owner</string>
</tuple> </tuple>
</value> </value>
</item> </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 @@ ...@@ -52,6 +52,15 @@
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value> <value> <string>*args, **kw</string> </value>
</item> </item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item> <item>
<key> <string>guard</string> </key> <key> <string>guard</string> </key>
<value> <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 @@ ...@@ -90,7 +90,7 @@
<value> <value>
<list> <list>
<string>my_title</string> <string>my_title</string>
<string>my_reference</string> <string>my_user_id</string>
</list> </list>
</value> </value>
</item> </item>
......
...@@ -10,14 +10,13 @@ ...@@ -10,14 +10,13 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>editable</string> <string>default</string>
<string>enabled</string>
</list> </list>
</value> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>my_reference</string> </value> <value> <string>my_user_id</string> </value>
</item> </item>
<item> <item>
<key> <string>message_values</string> </key> <key> <string>message_values</string> </key>
...@@ -54,7 +53,7 @@ ...@@ -54,7 +53,7 @@
<value> <value>
<dictionary> <dictionary>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>default</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
...@@ -79,12 +78,8 @@ ...@@ -79,12 +78,8 @@
<value> <value>
<dictionary> <dictionary>
<item> <item>
<key> <string>editable</string> </key> <key> <string>default</string> </key>
<value> <int>0</int> </value> <value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item> </item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
...@@ -106,19 +101,13 @@ ...@@ -106,19 +101,13 @@
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle> <pickle>
<tuple> <global name="TALESMethod" module="Products.Formulator.TALESField"/>
<tuple>
<string>Products.Formulator.TALESField</string>
<string>TALESMethod</string>
</tuple>
<none/>
</tuple>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <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> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>enabled</string> <string>description</string>
<string>editable</string>
<string>required</string> <string>required</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -79,21 +79,13 @@ ...@@ -79,21 +79,13 @@
\n \n
The system will check that there isn\'t another user with the same username.</string> </value> The system will check that there isn\'t another user with the same username.</string> </value>
</item> </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> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value> <value> <string>my_string_field</string> </value>
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item> <item>
<key> <string>required</string> </key> <key> <string>required</string> </key>
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>title</string>
<string>description</string> <string>description</string>
<string>editable</string>
<string>enabled</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -88,7 +90,15 @@ ...@@ -88,7 +90,15 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>description</string> </key> <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>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
...@@ -104,7 +114,7 @@ ...@@ -104,7 +114,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>User Login</string> </value> <value> <string>User ID</string> </value>
</item> </item>
</dictionary> </dictionary>
</value> </value>
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
<value> <string>set a login</string> </value> <value> <string>set a user id</string> </value>
</item> </item>
<item> <item>
<key> <string>guard</string> </key> <key> <string>guard</string> </key>
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<key> <string>method_id</string> </key> <key> <string>method_id</string> </key>
<value> <value>
<list> <list>
<string>_setReference</string> <string>_setUserId</string>
</list> </list>
</value> </value>
</item> </item>
......
kwargs = state_change['kwargs'] kwargs = state_change['kwargs']
person = state_change['object'] person = state_change['object']
if not person.hasReference(): if not person.hasUserId():
person.edit(reference=kwargs['reference']) person.edit(user_id=kwargs['reference'])
person.newContent( person.newContent(
portal_type='ERP5 Login', portal_type='ERP5 Login',
password=kwargs['password'], password=kwargs['password'],
......
...@@ -9,4 +9,4 @@ if password != password_confirm: ...@@ -9,4 +9,4 @@ if password != password_confirm:
reference = kwargs['reference'] reference = kwargs['reference']
if not 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 ...@@ -2,6 +2,7 @@ Notification Message | ItemAggregation
Notification Message | Reference Notification Message | Reference
Organisation | DefaultImage Organisation | DefaultImage
Person | DefaultImage Person | DefaultImage
Person | ERP5User
Preference | TelephonePreference Preference | TelephonePreference
Previous Causality Movement Group | PreviousCausalityMovementGroup Previous Causality Movement Group | PreviousCausalityMovementGroup
Query | TextDocument Query | TextDocument
......
...@@ -4,10 +4,9 @@ value -- field value (string) ...@@ -4,10 +4,9 @@ value -- field value (string)
REQUEST -- standard REQUEST variable""" REQUEST -- standard REQUEST variable"""
if value: if value:
# 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 # concurrency between Credential Request and ERP5 Login object too
tag = 'Person_setReference_%s' % value.encode('hex') if context.getPortalObject().portal_activities.countMessageWithTag('set_login_' + value.encode('hex')):
if context.getPortalObject().portal_activities.countMessageWithTag(tag):
return False return False
def getRealContext(): def getRealContext():
...@@ -29,6 +28,12 @@ context = getRealContext() ...@@ -29,6 +28,12 @@ context = getRealContext()
if context.getPortalType() == "Credential Request": if context.getPortalType() == "Credential Request":
related_person = context.getDestinationDecisionValue(portal_type="Person") related_person = context.getDestinationDecisionValue(portal_type="Person")
if related_person is not None: 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: if related_person.getReference() == value:
return True return True
......
...@@ -29,10 +29,8 @@ if not login.hasReference(): ...@@ -29,10 +29,8 @@ if not login.hasReference():
if not reference: if not reference:
raise ValueError, "Impossible to create an account without login" raise ValueError, "Impossible to create an account without login"
login.setReference(reference) login.setReference(reference)
if not person.hasReference(): if not user_id:
person.setReference(reference) person.setUserId(reference)
else:
reference = person.getReference()
password = None password = None
# Set password if no password on the Login # Set password if no password on the Login
......
...@@ -37,9 +37,9 @@ credential_request = module.newContent( ...@@ -37,9 +37,9 @@ credential_request = module.newContent(
date_of_birth=date_of_birth) date_of_birth=date_of_birth)
credential_request.setCategoryList(category_list) 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 # 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 #We attach the current user to the credential request if not anonymous
if not context.portal_membership.isAnonymousUser(): if not context.portal_membership.isAnonymousUser():
......
...@@ -47,8 +47,7 @@ else: ...@@ -47,8 +47,7 @@ else:
# if we are changing password for current logged in user then do it # if we are changing password for current logged in user then do it
# within same transaction and update client side credentials cookie # within same transaction and update client side credentials cookie
username = person.getReference() if password:
if password and username == str(portal.portal_membership.getAuthenticatedMember()):
# The password is updated synchronously and the the rest of the credential Update is done later # The password is updated synchronously and the the rest of the credential Update is done later
login_reference = credential_update.Credential_updatePersonPassword() login_reference = credential_update.Credential_updatePersonPassword()
portal.cookie_authentication.credentialsChanged( portal.cookie_authentication.credentialsChanged(
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>description</string>
<string>required</string> <string>required</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -75,13 +77,17 @@ ...@@ -75,13 +77,17 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <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> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value> <value> <string>my_string_field</string> </value>
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item> <item>
<key> <string>required</string> </key> <key> <string>required</string> </key>
...@@ -91,6 +97,10 @@ ...@@ -91,6 +97,10 @@
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>description</string>
<string>editable</string> <string>editable</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -75,22 +77,30 @@ ...@@ -75,22 +77,30 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <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> <item>
<key> <string>editable</string> </key> <key> <string>editable</string> </key>
<value> <int>0</int> </value> <value> <int>0</int> </value>
</item> </item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_reference</string> </value> <value> <string>my_string_field</string> </value>
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Person_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string>User Login</string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
......
...@@ -14095,9 +14095,6 @@ msgstr "L'utilisateur ${user} n'existe pas." ...@@ -14095,9 +14095,6 @@ msgstr "L'utilisateur ${user} n'existe pas."
msgid "User Account Workflow" msgid "User Account Workflow"
msgstr "Workflow du compte utilisateur" 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" msgid "User Interface"
msgstr "Interface utilisateur" msgstr "Interface utilisateur"
...@@ -14107,6 +14104,9 @@ msgstr "Langues de l'interface utilisateur" ...@@ -14107,6 +14104,9 @@ msgstr "Langues de l'interface utilisateur"
msgid "User Login" msgid "User Login"
msgstr "Nom d'utilisateur" msgstr "Nom d'utilisateur"
msgid "User Login is not specified."
msgstr "Le nom d'utilisateur n'est pas spécifié."
msgid "User Name" msgid "User Name"
msgstr "Nom d'utilisateur" msgstr "Nom d'utilisateur"
......
...@@ -7153,15 +7153,15 @@ msgstr "존재하지 않는 이용자: ${user}" ...@@ -7153,15 +7153,15 @@ msgstr "존재하지 않는 이용자: ${user}"
msgid "User Account Workflow" msgid "User Account Workflow"
msgstr "사용자 계정 워크플로우" msgstr "사용자 계정 워크플로우"
msgid "User ID is not specified."
msgstr "이용자 ID가 지정되지 않았습니다."
msgid "User Interface" msgid "User Interface"
msgstr "이용자 인터페이스" msgstr "이용자 인터페이스"
msgid "User Login" msgid "User Login"
msgstr "이용자 로그인" msgstr "이용자 로그인"
msgid "User Login is not specified."
msgstr "이용자 로그인 가 지정되지 않았습니다."
msgid "User Password" msgid "User Password"
msgstr "이용자 패스워드" msgstr "이용자 패스워드"
......
...@@ -6489,9 +6489,6 @@ msgstr "Usuário ${user} não existe." ...@@ -6489,9 +6489,6 @@ msgstr "Usuário ${user} não existe."
msgid "User Account Workflow" msgid "User Account Workflow"
msgstr "Workflow de Contas de Usuários" 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" msgid "User Interface"
msgstr "Interface do Usuário" msgstr "Interface do Usuário"
...@@ -6501,6 +6498,9 @@ msgstr "Idiomas do Usuário (UI)" ...@@ -6501,6 +6498,9 @@ msgstr "Idiomas do Usuário (UI)"
msgid "User Login" msgid "User Login"
msgstr "Usuário" msgstr "Usuário"
msgid "User Login is not specified."
msgstr "Usuário não esta especificado."
msgid "User Name" msgid "User Name"
msgstr "Usuário" msgstr "Usuário"
......
...@@ -34,6 +34,8 @@ from Products.ERP5.Document.Node import Node ...@@ -34,6 +34,8 @@ from Products.ERP5.Document.Node import Node
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5.mixin.encrypted_password import EncryptedPasswordMixin from Products.ERP5.mixin.encrypted_password import EncryptedPasswordMixin
from Products.ERP5.mixin.login_account_provider import LoginAccountProviderMixin from Products.ERP5.mixin.login_account_provider import LoginAccountProviderMixin
from Products.ERP5.mixin.erp5_user import ERP5UserMixin
from Products.DCWorkflow.DCWorkflow import ValidationFailed
try: try:
from Products import PluggableAuthService from Products import PluggableAuthService
...@@ -42,7 +44,11 @@ try: ...@@ -42,7 +44,11 @@ try:
except ImportError: except ImportError:
PluggableAuthService = None 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 object holds the information about
an person (ex. you, me, someone in the company, an person (ex. you, me, someone in the company,
...@@ -122,6 +128,56 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin): ...@@ -122,6 +128,56 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin):
self.hasMiddleName() or \ self.hasMiddleName() or \
self._baseHasTitle() 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): def _setReference(self, value):
""" """
Set the user id. This method is defined explicitly, because: Set the user id. This method is defined explicitly, because:
...@@ -129,47 +185,34 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin): ...@@ -129,47 +185,34 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin):
- we want to apply a different permission - we want to apply a different permission
- we want to prevent duplicated user ids, but only when - we want to prevent duplicated user ids, but only when
PAS _AND_ (ERP5UserManager or ERP5LoginUserManager) are used PAS _AND_ ERP5UserManager are used
""" """
activate_kw = {} if value != self.getUserId():
portal = self.getPortalObject() if value:
if value: self.__checkUserIdAvailability(
# Encode reference to hex to prevent uppercase/lowercase conflict in pas_plugin_class=ERP5UserManager,
# activity table (when calling countMessageWithTag) login=value,
activate_kw['tag'] = tag = 'Person_setReference_' + value.encode('hex') )
# Check that there no existing user self._baseSetReference(value)
acl_users = portal.acl_users # invalid the cache for ERP5Security
if PluggableAuthService is not None and isinstance(acl_users, self.getPortalObject().portal_caches.clearCache(cache_factory_list=('erp5_content_short', ))
PluggableAuthService.PluggableAuthService.PluggableAuthService):
plugin_list = acl_users.plugins.listPlugins( def _setUserId(self, value):
PluggableAuthService.interfaces.plugins.IUserEnumerationPlugin) """
for plugin_name, plugin_value in plugin_list: Set the user id. This method is defined explicitly, because:
if isinstance(plugin_value, (ERP5UserManager, ERP5LoginUserManager)):
user_list = acl_users.searchUsers(id=value, - we want to apply a different permission
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
self._baseSetReference(value) - we want to prevent duplicated user ids, but only when
self.reindexObject(activate_kw=activate_kw) PAS _AND_ ERP5LoginUserManager are used
# invalid the cache for ERP5Security """
portal_caches = portal.portal_caches if value != self.getUserId():
portal_caches.clearCache(cache_factory_list=('erp5_content_short', )) if value:
self.__checkUserIdAvailability(
pas_plugin_class=ERP5LoginUserManager,
user_id=value,
)
self._baseSetUserId(value)
# Time management # Time management
security.declareProtected(Permissions.AccessContentsInformation, 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 @@ ...@@ -9,5 +9,6 @@
<key>roles_and_users</key> <key>roles_and_users</key>
<key>stock</key> <key>stock</key>
<key>subject</key> <key>subject</key>
<key>user</key>
<key>versioning</key> <key>versioning</key>
</key_list> </key_list>
\ No newline at end of file
...@@ -19,6 +19,7 @@ erp5_mysql_innodb/z0_drop_stock ...@@ -19,6 +19,7 @@ erp5_mysql_innodb/z0_drop_stock
erp5_mysql_innodb/z0_drop_subject erp5_mysql_innodb/z0_drop_subject
erp5_mysql_innodb/z0_drop_transformation erp5_mysql_innodb/z0_drop_transformation
erp5_mysql_innodb/z0_drop_translation erp5_mysql_innodb/z0_drop_translation
erp5_mysql_innodb/z0_drop_user
erp5_mysql_innodb/z0_drop_versioning erp5_mysql_innodb/z0_drop_versioning
erp5_mysql_innodb/z0_uncatalog_alarm erp5_mysql_innodb/z0_uncatalog_alarm
erp5_mysql_innodb/z0_uncatalog_category erp5_mysql_innodb/z0_uncatalog_category
...@@ -29,6 +30,7 @@ erp5_mysql_innodb/z0_uncatalog_predicate_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_quantity_unit_conversion
erp5_mysql_innodb/z0_uncatalog_stock erp5_mysql_innodb/z0_uncatalog_stock
erp5_mysql_innodb/z0_uncatalog_transformation erp5_mysql_innodb/z0_uncatalog_transformation
erp5_mysql_innodb/z0_uncatalog_user
erp5_mysql_innodb/z0_uncatalog_versioning erp5_mysql_innodb/z0_uncatalog_versioning
erp5_mysql_innodb/z_catalog_alarm_list erp5_mysql_innodb/z_catalog_alarm_list
erp5_mysql_innodb/z_catalog_delivery_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 ...@@ -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_subject_list
erp5_mysql_innodb/z_catalog_transformation_list erp5_mysql_innodb/z_catalog_transformation_list
erp5_mysql_innodb/z_catalog_translation_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_catalog_versioning_list
erp5_mysql_innodb/z_clear_reserved erp5_mysql_innodb/z_clear_reserved
erp5_mysql_innodb/z_count_results erp5_mysql_innodb/z_count_results
...@@ -65,6 +68,7 @@ erp5_mysql_innodb/z_create_stock ...@@ -65,6 +68,7 @@ erp5_mysql_innodb/z_create_stock
erp5_mysql_innodb/z_create_subject erp5_mysql_innodb/z_create_subject
erp5_mysql_innodb/z_create_transformation erp5_mysql_innodb/z_create_transformation
erp5_mysql_innodb/z_create_translation erp5_mysql_innodb/z_create_translation
erp5_mysql_innodb/z_create_user
erp5_mysql_innodb/z_create_versioning erp5_mysql_innodb/z_create_versioning
erp5_mysql_innodb/z_delete_recorded_object_list erp5_mysql_innodb/z_delete_recorded_object_list
erp5_mysql_innodb/z_delete_translation_list erp5_mysql_innodb/z_delete_translation_list
......
...@@ -8,4 +8,5 @@ predicate_category ...@@ -8,4 +8,5 @@ predicate_category
roles_and_users roles_and_users
stock stock
subject subject
user
versioning 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): ...@@ -52,51 +52,52 @@ class TestCertificateAuthority(ERP5TypeTestCase):
person.newContent(portal_type='Assignment').open() person.newContent(portal_type='Assignment').open()
person.newContent(portal_type='ERP5 Login', reference=login).validate() person.newContent(portal_type='ERP5 Login', reference=login).validate()
self.tic() self.tic()
return login return person.getUserId(), login
def test_person_request_certificate(self): def test_person_request_certificate(self):
login = self._createPerson() user_id, login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
self.loginByUserName(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate() 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): def test_person_revoke_certificate(self):
login = self._createPerson() user_id, login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
self.loginByUserName(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
self.assertRaises(ValueError, person.revokeCertificate) self.assertRaises(ValueError, person.revokeCertificate)
def test_person_request_revoke_certificate(self): def test_person_request_revoke_certificate(self):
login = self._createPerson() user_id, login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
self.loginByUserName(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate() certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate']) self.assertTrue('CN=%s' % user_id in certificate['certificate'])
person.revokeCertificate() person.revokeCertificate()
def test_person_request_certificate_twice(self): def test_person_request_certificate_twice(self):
login = self._createPerson() user_id, login = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
self.loginByUserName(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate() 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) self.assertRaises(ValueError, person.getCertificate)
def test_person_request_certificate_for_another(self): def test_person_request_certificate_for_another(self):
login = self._createPerson() user_id, login = self._createPerson()
login2 = self._createPerson() user_id2, login2 = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
self.loginByUserName(login2) self.loginByUserName(login2)
self.assertRaises(Unauthorized, person.getCertificate) self.assertRaises(Unauthorized, person.getCertificate)
def test_person_revoke_certificate_for_another(self): def test_person_revoke_certificate_for_another(self):
login = self._createPerson() user_id, login = self._createPerson()
login2 = self._createPerson() user_id2, login2 = self._createPerson()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login)
self.loginByUserName(login) self.loginByUserName(login)
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue()
certificate = person.getCertificate() certificate = person.getCertificate()
self.assertTrue('CN=%s' % login in certificate['certificate']) self.assertTrue('CN=%s' % user_id in certificate['certificate'])
self.loginByUserName(login2) self.loginByUserName(login2)
self.assertRaises(Unauthorized, person.revokeCertificate) self.assertRaises(Unauthorized, person.revokeCertificate)
......
...@@ -76,8 +76,8 @@ class TestPerson(ERP5TypeTestCase): ...@@ -76,8 +76,8 @@ class TestPerson(ERP5TypeTestCase):
person_copy_id = person_module.manage_pasteObjects(person_copy)[0]['new_id'] person_copy_id = person_module.manage_pasteObjects(person_copy)[0]['new_id']
person_copy_obj = person_module[person_copy_id] person_copy_obj = person_module[person_copy_id]
## because we copy/paste Person object in the same ERP5 ## because we copy/paste Person object in the same ERP5
## instance its reference must be resetted ## instance its user_id must be reset
self.assertEqual(person_copy_obj.getReference(), None) self.assertNotEqual(person_copy_obj.getUserId(), person.getUserId())
## set object as if installed from bt5 (simulate it) ## set object as if installed from bt5 (simulate it)
request = self.app.REQUEST request = self.app.REQUEST
...@@ -88,6 +88,8 @@ class TestPerson(ERP5TypeTestCase): ...@@ -88,6 +88,8 @@ class TestPerson(ERP5TypeTestCase):
## because we setup Person object from business template ## because we setup Person object from business template
## its reference must NOT be resetted ## its reference must NOT be resetted
self.assertEqual(person_copy_obj.getReference(), person.getReference()) 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): def test_PersonGetTitleDefined(self):
p = self._makeOne(title="title") p = self._makeOne(title="title")
...@@ -95,20 +97,20 @@ class TestPerson(ERP5TypeTestCase): ...@@ -95,20 +97,20 @@ class TestPerson(ERP5TypeTestCase):
# title & first_name, last_name # title & first_name, last_name
def testEmptyTitleFallbackOnId(self): def testEmptyTitleFallbackOnId(self):
p = self._makeOne(id=self.id()) p = self._makeOne()
self.assertEqual(self.id(), p.getTitle()) self.assertEqual(p.getUserId(), p.getTitle())
def testEmptyTranslatedTitleFallbackOnId(self): def testEmptyTranslatedTitleFallbackOnId(self):
p = self._makeOne(id=self.id()) p = self._makeOne()
self.assertEqual(self.id(), p.getTranslatedTitle()) self.assertEqual(p.getUserId(), p.getTranslatedTitle())
def testEmptyCompactTitleFallbackOnId(self): def testEmptyCompactTitleFallbackOnId(self):
p = self._makeOne(id=self.id()) p = self._makeOne()
self.assertEqual(self.id(), p.getCompactTitle()) self.assertEqual(p.getUserId(), p.getCompactTitle())
def testEmptyCompactTranslatedTitleFallbackOnId(self): def testEmptyCompactTranslatedTitleFallbackOnId(self):
p = self._makeOne(id=self.id()) p = self._makeOne()
self.assertEqual(self.id(), p.getCompactTranslatedTitle()) self.assertEqual(p.getUserId(), p.getCompactTranslatedTitle())
def testEmptyTitleFallbackOnReference(self): def testEmptyTitleFallbackOnReference(self):
p = self._makeOne(reference='reference') p = self._makeOne(reference='reference')
...@@ -183,9 +185,13 @@ class TestPerson(ERP5TypeTestCase): ...@@ -183,9 +185,13 @@ class TestPerson(ERP5TypeTestCase):
self.assertEqual('first middle last', p.getTitle()) self.assertEqual('first middle last', p.getTitle())
def testGetTitleOrId(self): def testGetTitleOrId(self):
p = self._makeOne(id='person') p = self._makeOne()
self.assertEqual('person', p.getTitleOrId()) self.assertEqual(p.getUserId(), p.getTitleOrId())
self.assertEqual('person', p.title_or_id()) 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', p.edit( first_name='first',
last_name='last', ) last_name='last', )
......
...@@ -85,14 +85,14 @@ class TestQueryModule(ERP5TypeTestCase): ...@@ -85,14 +85,14 @@ class TestQueryModule(ERP5TypeTestCase):
def test_reply_query_with_persons(self): def test_reply_query_with_persons(self):
owner_person = self.portal.person_module.newContent( owner_person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
reference='owner_user', user_id='owner_user',
password='secret', password='secret',
default_email_text='owner_user@example.invalid') default_email_text='owner_user@example.invalid')
assignment = owner_person.newContent(portal_type='Assignment') assignment = owner_person.newContent(portal_type='Assignment')
assignment.validate() assignment.validate()
question_person = self.portal.person_module.newContent( question_person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
reference='question_user', user_id='question_user',
password='secret', password='secret',
default_email_text='question_user@example.invalid') default_email_text='question_user@example.invalid')
assignment = question_person.newContent(portal_type='Assignment') assignment = question_person.newContent(portal_type='Assignment')
......
...@@ -105,7 +105,7 @@ class TestWorklist(ERP5TypeTestCase): ...@@ -105,7 +105,7 @@ class TestWorklist(ERP5TypeTestCase):
self.logMessage("Create user: %s" % user_login) self.logMessage("Create user: %s" % user_login)
person = module.newContent( person = module.newContent(
portal_type='Person', portal_type='Person',
reference=user_login, user_id=user_login,
password='hackme', password='hackme',
) )
# Create the Assignment. # Create the Assignment.
......
...@@ -106,7 +106,7 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -106,7 +106,7 @@ class ERP5LoginUserManager(BasePlugin):
if login_value is None: if login_value is None:
return return
user_value = login_value.getParentValue() user_value = login_value.getParentValue()
if not user_value.hasReference(): if not user_value.hasUserId():
return return
if user_value.getValidationState() == 'deleted': if user_value.getValidationState() == 'deleted':
return return
...@@ -136,7 +136,7 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -136,7 +136,7 @@ class ERP5LoginUserManager(BasePlugin):
return return
if login_value.isLoginBlocked(): if login_value.isLoginBlocked():
return return
return (user_value.getReference(), login_value.getReference()) return (user_value.getUserId(), login_value.getReference())
def _getLoginValueFromLogin(self, login, login_portal_type=None): def _getLoginValueFromLogin(self, login, login_portal_type=None):
user_list = self.enumerateUsers( user_list = self.enumerateUsers(
...@@ -166,8 +166,7 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -166,8 +166,7 @@ class ERP5LoginUserManager(BasePlugin):
login_portal_type = portal.getPortalLoginTypeList() login_portal_type = portal.getPortalLoginTypeList()
unrestrictedSearchResults = portal.portal_catalog.unrestrictedSearchResults unrestrictedSearchResults = portal.portal_catalog.unrestrictedSearchResults
searchUser = lambda **kw: unrestrictedSearchResults( searchUser = lambda **kw: unrestrictedSearchResults(
select_list=('reference', ), select_list=('user_id', ),
portal_type='Person',
**kw **kw
).dictionaries() ).dictionaries()
searchLogin = lambda **kw: unrestrictedSearchResults( searchLogin = lambda **kw: unrestrictedSearchResults(
...@@ -190,13 +189,13 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -190,13 +189,13 @@ class ERP5LoginUserManager(BasePlugin):
requested = lambda x: True requested = lambda x: True
user_list = [ user_list = [
x for x in searchUser( x for x in searchUser(
reference={ user_id={
'query': id, 'query': id,
'key': 'ExactMatch' if exact_match else 'Keyword', 'key': 'ExactMatch' if exact_match else 'Keyword',
}, },
limit=max_results, limit=max_results,
) )
if requested(x['reference']) if requested(x['user_id'])
] ]
else: else:
user_list = [] user_list = []
...@@ -235,7 +234,7 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -235,7 +234,7 @@ class ERP5LoginUserManager(BasePlugin):
plugin_id = self.getId() plugin_id = self.getId()
result = [ result = [
{ {
'id': user['reference'], 'id': user['user_id'],
# Note: PAS forbids us from returning more than one entry per given id, # Note: PAS forbids us from returning more than one entry per given id,
# so take any available login. # so take any available login.
'login': login_dict.get(user['uid'], [{'reference': None}])[0]['reference'], 'login': login_dict.get(user['uid'], [{'reference': None}])[0]['reference'],
...@@ -253,7 +252,7 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -253,7 +252,7 @@ class ERP5LoginUserManager(BasePlugin):
for login in login_dict.get(user['uid'], []) 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: for special_user_name in special_user_name_set:
# Note: special users are a bastard design in Zope: they are expected to # Note: special users are a bastard design in Zope: they are expected to
......
...@@ -270,7 +270,7 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -270,7 +270,7 @@ class TestUserManagement(ERP5TypeTestCase):
substring = 'person_id' substring = 'person_id'
user_id_set = {substring + '1', '1' + substring} user_id_set = {substring + '1', '1' + substring}
for user_id in user_id_set: for user_id in user_id_set:
self._makePerson(reference=user_id) self._makePerson(user_id=user_id)
self.assertEqual( self.assertEqual(
user_id_set, user_id_set,
{x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=False)}, {x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=False)},
...@@ -288,9 +288,9 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -288,9 +288,9 @@ class TestUserManagement(ERP5TypeTestCase):
def test_searchUsersIdExactMatch(self): def test_searchUsersIdExactMatch(self):
substring = 'person2_id' substring = 'person2_id'
self._makePerson(reference=substring) self._makePerson(user_id=substring)
self._makePerson(reference=substring + '1') self._makePerson(user_id=substring + '1')
self._makePerson(reference='1' + substring) self._makePerson(user_id='1' + substring)
self.assertEqual( self.assertEqual(
[substring], [substring],
[x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=True)], [x['userid'] for x in self.portal.acl_users.searchUsers(id=substring, exact_match=True)],
...@@ -309,7 +309,7 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -309,7 +309,7 @@ class TestUserManagement(ERP5TypeTestCase):
def test_MultipleUsers(self): def test_MultipleUsers(self):
"""Tests that it's refused to create two Persons with same user id.""" """Tests that it's refused to create two Persons with same user id."""
user_id, login, _ = self._makePerson() 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) self.assertRaises(ValidationFailed, self._makePerson, login=login)
def test_MultiplePersonReferenceWithoutCommit(self): def test_MultiplePersonReferenceWithoutCommit(self):
...@@ -319,9 +319,9 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -319,9 +319,9 @@ class TestUserManagement(ERP5TypeTestCase):
""" """
person_module = self.getPersonModule() person_module = self.getPersonModule()
new_person = person_module.newContent( new_person = person_module.newContent(
portal_type='Person', reference='new_person') portal_type='Person', user_id='new_person')
self.assertRaises(ValidationFailed, person_module.newContent, self.assertRaises(ValidationFailed, person_module.newContent,
portal_type='Person', reference='new_person') portal_type='Person', user_id='new_person')
def test_MultiplePersonReferenceWithoutTic(self): def test_MultiplePersonReferenceWithoutTic(self):
""" """
...@@ -330,10 +330,10 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -330,10 +330,10 @@ class TestUserManagement(ERP5TypeTestCase):
""" """
person_module = self.getPersonModule() person_module = self.getPersonModule()
new_person = person_module.newContent( new_person = person_module.newContent(
portal_type='Person', reference='new_person') portal_type='Person', user_id='new_person')
self.commit() self.commit()
self.assertRaises(ValidationFailed, person_module.newContent, self.assertRaises(ValidationFailed, person_module.newContent,
portal_type='Person', reference='new_person') portal_type='Person', user_id='new_person')
def test_MultiplePersonReferenceConcurrentTransaction(self): def test_MultiplePersonReferenceConcurrentTransaction(self):
""" """
...@@ -359,13 +359,13 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -359,13 +359,13 @@ class TestUserManagement(ERP5TypeTestCase):
person_module = self.getPersonModule() person_module = self.getPersonModule()
try: try:
self.assertRaises(DummyTestException, person_module.newContent, self.assertRaises(DummyTestException, person_module.newContent,
portal_type='Person', reference='new_person') portal_type='Person', user_id='new_person')
finally: finally:
Base.serialize = Base.serialize_call Base.serialize = Base.serialize_call
def test_PersonCopyAndPaste(self): def test_PersonCopyAndPaste(self):
"""If we copy and paste a person, login must not be copyied.""" """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, = self.portal.acl_users.searchUsers(id=user_id, exact_match=True)
user_value = self.portal.restrictedTraverse(user['path']) user_value = self.portal.restrictedTraverse(user['path'])
container = user_value.getParentValue() container = user_value.getParentValue()
...@@ -451,7 +451,7 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -451,7 +451,7 @@ class TestUserManagement(ERP5TypeTestCase):
pers = self.portal.person_module.newContent( pers = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
reference='the_user', reference='the_user',
reference=None, user_id=None,
) )
pers.newContent( pers.newContent(
portal_type='Assignment', portal_type='Assignment',
...@@ -543,13 +543,13 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -543,13 +543,13 @@ class TestUserManagement(ERP5TypeTestCase):
user_id, login, password = self._makePerson() user_id, login, password = self._makePerson()
acl_user, = self.portal.acl_users.searchUsers(id=user_id, exact_match=True) acl_user, = self.portal.acl_users.searchUsers(id=user_id, exact_match=True)
person = self.portal.restrictedTraverse(acl_user['path']) person = self.portal.restrictedTraverse(acl_user['path'])
person.setReference(None) person.setUserId(None)
self.tic() self.tic()
self.assertEqual(None, person.Person_getUserId()) self.assertEqual(None, person.Person_getUserId())
def test_duplicatePersonUserId(self): def test_duplicatePersonUserId(self):
user_id, _, _ = self._makePerson() 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): def test_duplicateLoginReference(self):
_, login1, _ = self._makePerson() _, login1, _ = self._makePerson()
...@@ -684,7 +684,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase): ...@@ -684,7 +684,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
self.username = 'usérn@me' self.username = 'usérn@me'
# create a user and open an assignement # create a user and open an assignement
pers = self.getPersonModule().newContent(portal_type='Person', pers = self.getPersonModule().newContent(portal_type='Person',
reference=self.username) user_id=self.username)
assignment = pers.newContent( portal_type='Assignment', assignment = pers.newContent( portal_type='Assignment',
group='subcat', group='subcat',
site='subcat', site='subcat',
...@@ -892,7 +892,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase): ...@@ -892,7 +892,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
first_name='First', first_name='First',
last_name='Last') last_name='Last')
loginable_person = self.getPersonModule().newContent(portal_type='Person', loginable_person = self.getPersonModule().newContent(portal_type='Person',
reference='guest', user_id='guest',
password='guest') password='guest')
assignment = loginable_person.newContent(portal_type='Assignment', assignment = loginable_person.newContent(portal_type='Assignment',
function='another_subcat') function='another_subcat')
...@@ -1138,7 +1138,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase): ...@@ -1138,7 +1138,7 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
# But non-module objects, with subobjects that acquire local # But non-module objects, with subobjects that acquire local
# roles, should reindex their security recursively: # roles, should reindex their security recursively:
person, = [rec.getObject() 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())) self.assertTrue(len(person.objectIds()))
person.reindexObjectSecurity() person.reindexObjectSecurity()
self.commit() self.commit()
......
...@@ -88,7 +88,15 @@ def Base_asXML(object, root=None): ...@@ -88,7 +88,15 @@ def Base_asXML(object, root=None):
# We have to find every property # We have to find every property
for prop_id in set(self.propertyIds()): for prop_id in set(self.propertyIds()):
# In most case, we should not synchronize acquired properties # 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) value = self.getProperty(prop_id)
if value is None: if value is None:
prop_type = '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