summaryrefslogtreecommitdiff
path: root/src/mailman/rest/users.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/rest/users.py')
-rw-r--r--src/mailman/rest/users.py54
1 files changed, 38 insertions, 16 deletions
diff --git a/src/mailman/rest/users.py b/src/mailman/rest/users.py
index 2242c3ab7..700e4179d 100644
--- a/src/mailman/rest/users.py
+++ b/src/mailman/rest/users.py
@@ -117,8 +117,9 @@ def create_user(arguments, request, response):
password = generate(int(config.passwords.password_length))
user.password = config.password_context.encrypt(password)
user.is_server_owner = is_server_owner
- location = path_to('users/{}'.format(user.user_id.int),
- request.context['api_version'])
+ api_version = request.context['api_version']
+ user_id = getattr(user.user_id, 'int' if api_version == '3.0' else 'hex')
+ location = path_to('users/{}'.format(user_id), api_version)
created(response, location)
return user
@@ -127,13 +128,17 @@ def create_user(arguments, request, response):
class _UserBase(CollectionMixin):
"""Shared base class for user representations."""
+ def _get_uuid(self, user):
+ return getattr(user.user_id,
+ 'int' if self.api_version == '3.0' else 'hex')
+
def _resource_as_dict(self, user):
"""See `CollectionMixin`."""
# The canonical URL for a user is their unique user id, although we
# can always look up a user based on any registered and validated
# email address associated with their account. The user id is a UUID,
# but we serialize its integer equivalent.
- user_id = user.user_id.int
+ user_id = self._get_uuid(user)
resource = dict(
created_on=user.created_on,
is_server_owner=user.is_server_owner,
@@ -177,24 +182,29 @@ class AllUsers(_UserBase):
class AUser(_UserBase):
"""A user."""
- def __init__(self, user_identifier):
+ def __init__(self, api_version, user_identifier):
"""Get a user by various type of identifiers.
:param user_identifier: The identifier used to retrieve the user. The
- identifier may either be an integer user-id, or an email address
- controlled by the user. The type of identifier is auto-detected
+ identifier may either be an email address controlled by the user
+ or the UUID of the user. The type of identifier is auto-detected
by looking for an `@` symbol, in which case it's taken as an email
- address, otherwise it's assumed to be an integer.
+ address, otherwise it's assumed to be a UUID. However, UUIDs in
+ API 3.0 are integers, while in 3.1 are hex.
:type user_identifier: string
"""
+ self.api_version = api_version
user_manager = getUtility(IUserManager)
if '@' in user_identifier:
self._user = user_manager.get_user(user_identifier)
else:
- # The identifier is the string representation of an integer that
- # must be converted to a UUID.
+ # The identifier is the string representation of a UUID, either an
+ # int in API 3.0 or a hex in API 3.1.
try:
- user_id = UUID(int=int(user_identifier))
+ if api_version == '3.0':
+ user_id = UUID(int=int(user_identifier))
+ else:
+ user_id = UUID(hex=user_identifier)
except ValueError:
self._user = None
else:
@@ -227,14 +237,14 @@ class AUser(_UserBase):
@child()
def preferences(self, request, segments):
- """/addresses/<email>/preferences"""
+ """/users/<id>/preferences"""
if len(segments) != 0:
return BadRequest(), []
if self._user is None:
return NotFound(), []
child = Preferences(
self._user.preferences,
- 'users/{0}'.format(self._user.user_id.int))
+ 'users/{}'.format(self._get_uuid(self._user)))
return child, []
def on_patch(self, request, response):
@@ -309,13 +319,14 @@ class AddressUser(_UserBase):
if self._user:
conflict(response)
return
+ api_version = request.context['api_version']
# When creating a linked user by POSTing, the user either must already
# exist, or it can be automatically created, if the auto_create flag
# is given and true (if missing, it defaults to true). However, in
# this case we do not accept 'email' as a POST field.
fields = CREATION_FIELDS.copy()
del fields['email']
- fields['user_id'] = int
+ fields['user_id'] = (int if api_version == '3.0' else str)
fields['auto_create'] = as_boolean
fields['_optional'] = fields['_optional'] + (
'user_id', 'auto_create', 'is_server_owner')
@@ -328,7 +339,12 @@ class AddressUser(_UserBase):
user_manager = getUtility(IUserManager)
if 'user_id' in arguments:
raw_uid = arguments['user_id']
- user_id = UUID(int=raw_uid)
+ kws = {('int' if api_version == '3.0' else 'hex'): raw_uid}
+ try:
+ user_id = UUID(**kws)
+ except ValueError as error:
+ bad_request(response, str(error))
+ return
user = user_manager.get_user_by_id(user_id)
if user is None:
not_found(response, b'No user with ID {}'.format(raw_uid))
@@ -348,11 +364,12 @@ class AddressUser(_UserBase):
def on_put(self, request, response):
"""Set or replace the addresses's user."""
+ api_version = request.context['api_version']
if self._user:
self._user.unlink(self._address)
# Process post data and check for an existing user.
fields = CREATION_FIELDS.copy()
- fields['user_id'] = int
+ fields['user_id'] = (int if api_version == '3.0' else str)
fields['_optional'] = fields['_optional'] + (
'user_id', 'email', 'is_server_owner')
try:
@@ -364,7 +381,12 @@ class AddressUser(_UserBase):
user_manager = getUtility(IUserManager)
if 'user_id' in arguments:
raw_uid = arguments['user_id']
- user_id = UUID(int=raw_uid)
+ kws = {('int' if api_version == '3.0' else 'hex'): raw_uid}
+ try:
+ user_id = UUID(**kws)
+ except ValueError as error:
+ bad_request(response, str(error))
+ return
user = user_manager.get_user_by_id(user_id)
if user is None:
not_found(response, b'No user with ID {}'.format(raw_uid))