mirror of
https://github.com/matrix-org/synapse.git
synced 2025-02-10 17:25:48 +00:00
Allow to edit external_ids
by Edit User admin API (#10598)
Signed-off-by: Dirk Klimpel dirk@klimpel.org
This commit is contained in:
parent
58f0d97275
commit
3bcd525b46
1
changelog.d/10598.feature
Normal file
1
changelog.d/10598.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Allow editing a user's `external_ids` via the "Edit User" admin API. Contributed by @dklimpel.
|
@ -81,6 +81,16 @@ with a body of:
|
|||||||
"address": "<user_mail_2>"
|
"address": "<user_mail_2>"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"external_ids": [
|
||||||
|
{
|
||||||
|
"auth_provider": "<provider1>",
|
||||||
|
"external_id": "<user_id_provider_1>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"auth_provider": "<provider2>",
|
||||||
|
"external_id": "<user_id_provider_2>"
|
||||||
|
}
|
||||||
|
],
|
||||||
"avatar_url": "<avatar_url>",
|
"avatar_url": "<avatar_url>",
|
||||||
"admin": false,
|
"admin": false,
|
||||||
"deactivated": false
|
"deactivated": false
|
||||||
@ -90,26 +100,34 @@ with a body of:
|
|||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
server admin: [Admin API](../usage/administration/admin_api)
|
||||||
|
|
||||||
|
Returns HTTP status code:
|
||||||
|
- `201` - When a new user object was created.
|
||||||
|
- `200` - When a user was modified.
|
||||||
|
|
||||||
URL parameters:
|
URL parameters:
|
||||||
|
|
||||||
- `user_id`: fully-qualified user id: for example, `@user:server.com`.
|
- `user_id`: fully-qualified user id: for example, `@user:server.com`.
|
||||||
|
|
||||||
Body parameters:
|
Body parameters:
|
||||||
|
|
||||||
- `password`, optional. If provided, the user's password is updated and all
|
- `password` - string, optional. If provided, the user's password is updated and all
|
||||||
devices are logged out.
|
devices are logged out.
|
||||||
|
- `displayname` - string, optional, defaults to the value of `user_id`.
|
||||||
- `displayname`, optional, defaults to the value of `user_id`.
|
- `threepids` - array, optional, allows setting the third-party IDs (email, msisdn)
|
||||||
|
- `medium` - string. Kind of third-party ID, either `email` or `msisdn`.
|
||||||
- `threepids`, optional, allows setting the third-party IDs (email, msisdn)
|
- `address` - string. Value of third-party ID.
|
||||||
belonging to a user.
|
belonging to a user.
|
||||||
|
- `external_ids` - array, optional. Allow setting the identifier of the external identity
|
||||||
- `avatar_url`, optional, must be a
|
provider for SSO (Single sign-on). Details in
|
||||||
|
[Sample Configuration File](../usage/configuration/homeserver_sample_config.html)
|
||||||
|
section `sso` and `oidc_providers`.
|
||||||
|
- `auth_provider` - string. ID of the external identity provider. Value of `idp_id`
|
||||||
|
in homeserver configuration.
|
||||||
|
- `external_id` - string, user ID in the external identity provider.
|
||||||
|
- `avatar_url` - string, optional, must be a
|
||||||
[MXC URI](https://matrix.org/docs/spec/client_server/r0.6.0#matrix-content-mxc-uris).
|
[MXC URI](https://matrix.org/docs/spec/client_server/r0.6.0#matrix-content-mxc-uris).
|
||||||
|
- `admin` - bool, optional, defaults to `false`.
|
||||||
- `admin`, optional, defaults to `false`.
|
- `deactivated` - bool, optional. If unspecified, deactivation state will be left
|
||||||
|
|
||||||
- `deactivated`, optional. If unspecified, deactivation state will be left
|
|
||||||
unchanged on existing accounts and set to `false` for new accounts.
|
unchanged on existing accounts and set to `false` for new accounts.
|
||||||
A user cannot be erased by deactivating with this API. For details on
|
A user cannot be erased by deactivating with this API. For details on
|
||||||
deactivating users see [Deactivate Account](#deactivate-account).
|
deactivating users see [Deactivate Account](#deactivate-account).
|
||||||
|
@ -196,20 +196,57 @@ class UserRestServletV2(RestServlet):
|
|||||||
user = await self.admin_handler.get_user(target_user)
|
user = await self.admin_handler.get_user(target_user)
|
||||||
user_id = target_user.to_string()
|
user_id = target_user.to_string()
|
||||||
|
|
||||||
|
# check for required parameters for each threepid
|
||||||
|
threepids = body.get("threepids")
|
||||||
|
if threepids is not None:
|
||||||
|
for threepid in threepids:
|
||||||
|
assert_params_in_dict(threepid, ["medium", "address"])
|
||||||
|
|
||||||
|
# check for required parameters for each external_id
|
||||||
|
external_ids = body.get("external_ids")
|
||||||
|
if external_ids is not None:
|
||||||
|
for external_id in external_ids:
|
||||||
|
assert_params_in_dict(external_id, ["auth_provider", "external_id"])
|
||||||
|
|
||||||
|
user_type = body.get("user_type", None)
|
||||||
|
if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES:
|
||||||
|
raise SynapseError(400, "Invalid user type")
|
||||||
|
|
||||||
|
set_admin_to = body.get("admin", False)
|
||||||
|
if not isinstance(set_admin_to, bool):
|
||||||
|
raise SynapseError(
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
"Param 'admin' must be a boolean, if given",
|
||||||
|
Codes.BAD_JSON,
|
||||||
|
)
|
||||||
|
|
||||||
|
password = body.get("password", None)
|
||||||
|
if password is not None:
|
||||||
|
if not isinstance(password, str) or len(password) > 512:
|
||||||
|
raise SynapseError(400, "Invalid password")
|
||||||
|
|
||||||
|
deactivate = body.get("deactivated", False)
|
||||||
|
if not isinstance(deactivate, bool):
|
||||||
|
raise SynapseError(400, "'deactivated' parameter is not of type boolean")
|
||||||
|
|
||||||
|
# convert into List[Tuple[str, str]]
|
||||||
|
if external_ids is not None:
|
||||||
|
new_external_ids = []
|
||||||
|
for external_id in external_ids:
|
||||||
|
new_external_ids.append(
|
||||||
|
(external_id["auth_provider"], external_id["external_id"])
|
||||||
|
)
|
||||||
|
|
||||||
if user: # modify user
|
if user: # modify user
|
||||||
if "displayname" in body:
|
if "displayname" in body:
|
||||||
await self.profile_handler.set_displayname(
|
await self.profile_handler.set_displayname(
|
||||||
target_user, requester, body["displayname"], True
|
target_user, requester, body["displayname"], True
|
||||||
)
|
)
|
||||||
|
|
||||||
if "threepids" in body:
|
if threepids is not None:
|
||||||
# check for required parameters for each threepid
|
|
||||||
for threepid in body["threepids"]:
|
|
||||||
assert_params_in_dict(threepid, ["medium", "address"])
|
|
||||||
|
|
||||||
# remove old threepids from user
|
# remove old threepids from user
|
||||||
threepids = await self.store.user_get_threepids(user_id)
|
old_threepids = await self.store.user_get_threepids(user_id)
|
||||||
for threepid in threepids:
|
for threepid in old_threepids:
|
||||||
try:
|
try:
|
||||||
await self.auth_handler.delete_threepid(
|
await self.auth_handler.delete_threepid(
|
||||||
user_id, threepid["medium"], threepid["address"], None
|
user_id, threepid["medium"], threepid["address"], None
|
||||||
@ -220,18 +257,39 @@ class UserRestServletV2(RestServlet):
|
|||||||
|
|
||||||
# add new threepids to user
|
# add new threepids to user
|
||||||
current_time = self.hs.get_clock().time_msec()
|
current_time = self.hs.get_clock().time_msec()
|
||||||
for threepid in body["threepids"]:
|
for threepid in threepids:
|
||||||
await self.auth_handler.add_threepid(
|
await self.auth_handler.add_threepid(
|
||||||
user_id, threepid["medium"], threepid["address"], current_time
|
user_id, threepid["medium"], threepid["address"], current_time
|
||||||
)
|
)
|
||||||
|
|
||||||
if "avatar_url" in body and type(body["avatar_url"]) == str:
|
if external_ids is not None:
|
||||||
|
# get changed external_ids (added and removed)
|
||||||
|
cur_external_ids = await self.store.get_external_ids_by_user(user_id)
|
||||||
|
add_external_ids = set(new_external_ids) - set(cur_external_ids)
|
||||||
|
del_external_ids = set(cur_external_ids) - set(new_external_ids)
|
||||||
|
|
||||||
|
# remove old external_ids
|
||||||
|
for auth_provider, external_id in del_external_ids:
|
||||||
|
await self.store.remove_user_external_id(
|
||||||
|
auth_provider,
|
||||||
|
external_id,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# add new external_ids
|
||||||
|
for auth_provider, external_id in add_external_ids:
|
||||||
|
await self.store.record_user_external_id(
|
||||||
|
auth_provider,
|
||||||
|
external_id,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if "avatar_url" in body and isinstance(body["avatar_url"], str):
|
||||||
await self.profile_handler.set_avatar_url(
|
await self.profile_handler.set_avatar_url(
|
||||||
target_user, requester, body["avatar_url"], True
|
target_user, requester, body["avatar_url"], True
|
||||||
)
|
)
|
||||||
|
|
||||||
if "admin" in body:
|
if "admin" in body:
|
||||||
set_admin_to = bool(body["admin"])
|
|
||||||
if set_admin_to != user["admin"]:
|
if set_admin_to != user["admin"]:
|
||||||
auth_user = requester.user
|
auth_user = requester.user
|
||||||
if target_user == auth_user and not set_admin_to:
|
if target_user == auth_user and not set_admin_to:
|
||||||
@ -239,29 +297,18 @@ class UserRestServletV2(RestServlet):
|
|||||||
|
|
||||||
await self.store.set_server_admin(target_user, set_admin_to)
|
await self.store.set_server_admin(target_user, set_admin_to)
|
||||||
|
|
||||||
if "password" in body:
|
if password is not None:
|
||||||
if not isinstance(body["password"], str) or len(body["password"]) > 512:
|
logout_devices = True
|
||||||
raise SynapseError(400, "Invalid password")
|
new_password_hash = await self.auth_handler.hash(password)
|
||||||
else:
|
|
||||||
new_password = body["password"]
|
|
||||||
logout_devices = True
|
|
||||||
|
|
||||||
new_password_hash = await self.auth_handler.hash(new_password)
|
await self.set_password_handler.set_password(
|
||||||
|
target_user.to_string(),
|
||||||
await self.set_password_handler.set_password(
|
new_password_hash,
|
||||||
target_user.to_string(),
|
logout_devices,
|
||||||
new_password_hash,
|
requester,
|
||||||
logout_devices,
|
)
|
||||||
requester,
|
|
||||||
)
|
|
||||||
|
|
||||||
if "deactivated" in body:
|
if "deactivated" in body:
|
||||||
deactivate = body["deactivated"]
|
|
||||||
if not isinstance(deactivate, bool):
|
|
||||||
raise SynapseError(
|
|
||||||
400, "'deactivated' parameter is not of type boolean"
|
|
||||||
)
|
|
||||||
|
|
||||||
if deactivate and not user["deactivated"]:
|
if deactivate and not user["deactivated"]:
|
||||||
await self.deactivate_account_handler.deactivate_account(
|
await self.deactivate_account_handler.deactivate_account(
|
||||||
target_user.to_string(), False, requester, by_admin=True
|
target_user.to_string(), False, requester, by_admin=True
|
||||||
@ -285,36 +332,24 @@ class UserRestServletV2(RestServlet):
|
|||||||
return 200, user
|
return 200, user
|
||||||
|
|
||||||
else: # create user
|
else: # create user
|
||||||
password = body.get("password")
|
|
||||||
password_hash = None
|
|
||||||
if password is not None:
|
|
||||||
if not isinstance(password, str) or len(password) > 512:
|
|
||||||
raise SynapseError(400, "Invalid password")
|
|
||||||
password_hash = await self.auth_handler.hash(password)
|
|
||||||
|
|
||||||
admin = body.get("admin", None)
|
|
||||||
user_type = body.get("user_type", None)
|
|
||||||
displayname = body.get("displayname", None)
|
displayname = body.get("displayname", None)
|
||||||
|
|
||||||
if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES:
|
password_hash = None
|
||||||
raise SynapseError(400, "Invalid user type")
|
if password is not None:
|
||||||
|
password_hash = await self.auth_handler.hash(password)
|
||||||
|
|
||||||
user_id = await self.registration_handler.register_user(
|
user_id = await self.registration_handler.register_user(
|
||||||
localpart=target_user.localpart,
|
localpart=target_user.localpart,
|
||||||
password_hash=password_hash,
|
password_hash=password_hash,
|
||||||
admin=bool(admin),
|
admin=set_admin_to,
|
||||||
default_display_name=displayname,
|
default_display_name=displayname,
|
||||||
user_type=user_type,
|
user_type=user_type,
|
||||||
by_admin=True,
|
by_admin=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if "threepids" in body:
|
if threepids is not None:
|
||||||
# check for required parameters for each threepid
|
|
||||||
for threepid in body["threepids"]:
|
|
||||||
assert_params_in_dict(threepid, ["medium", "address"])
|
|
||||||
|
|
||||||
current_time = self.hs.get_clock().time_msec()
|
current_time = self.hs.get_clock().time_msec()
|
||||||
for threepid in body["threepids"]:
|
for threepid in threepids:
|
||||||
await self.auth_handler.add_threepid(
|
await self.auth_handler.add_threepid(
|
||||||
user_id, threepid["medium"], threepid["address"], current_time
|
user_id, threepid["medium"], threepid["address"], current_time
|
||||||
)
|
)
|
||||||
@ -334,6 +369,14 @@ class UserRestServletV2(RestServlet):
|
|||||||
data={},
|
data={},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if external_ids is not None:
|
||||||
|
for auth_provider, external_id in new_external_ids:
|
||||||
|
await self.store.record_user_external_id(
|
||||||
|
auth_provider,
|
||||||
|
external_id,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
|
||||||
if "avatar_url" in body and isinstance(body["avatar_url"], str):
|
if "avatar_url" in body and isinstance(body["avatar_url"], str):
|
||||||
await self.profile_handler.set_avatar_url(
|
await self.profile_handler.set_avatar_url(
|
||||||
target_user, requester, body["avatar_url"], True
|
target_user, requester, body["avatar_url"], True
|
||||||
|
@ -599,6 +599,28 @@ class RegistrationWorkerStore(CacheInvalidationWorkerStore):
|
|||||||
desc="record_user_external_id",
|
desc="record_user_external_id",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def remove_user_external_id(
|
||||||
|
self, auth_provider: str, external_id: str, user_id: str
|
||||||
|
) -> None:
|
||||||
|
"""Remove a mapping from an external user id to a mxid
|
||||||
|
|
||||||
|
If the mapping is not found, this method does nothing.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
auth_provider: identifier for the remote auth provider
|
||||||
|
external_id: id on that system
|
||||||
|
user_id: complete mxid that it is mapped to
|
||||||
|
"""
|
||||||
|
await self.db_pool.simple_delete(
|
||||||
|
table="user_external_ids",
|
||||||
|
keyvalues={
|
||||||
|
"auth_provider": auth_provider,
|
||||||
|
"external_id": external_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
},
|
||||||
|
desc="remove_user_external_id",
|
||||||
|
)
|
||||||
|
|
||||||
async def get_user_by_external_id(
|
async def get_user_by_external_id(
|
||||||
self, auth_provider: str, external_id: str
|
self, auth_provider: str, external_id: str
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
|
@ -1240,6 +1240,101 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
|||||||
self.assertEqual(404, channel.code, msg=channel.json_body)
|
self.assertEqual(404, channel.code, msg=channel.json_body)
|
||||||
self.assertEqual("M_NOT_FOUND", channel.json_body["errcode"])
|
self.assertEqual("M_NOT_FOUND", channel.json_body["errcode"])
|
||||||
|
|
||||||
|
def test_invalid_parameter(self):
|
||||||
|
"""
|
||||||
|
If parameters are invalid, an error is returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# admin not bool
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"admin": "not_bool"},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.BAD_JSON, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# deactivated not bool
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"deactivated": "not_bool"},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# password not str
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"password": True},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# password not length
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"password": "x" * 513},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# user_type not valid
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"user_type": "new type"},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# external_ids not valid
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={
|
||||||
|
"external_ids": {"auth_provider": "prov", "wrong_external_id": "id"}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.MISSING_PARAM, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"external_ids": {"external_id": "id"}},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.MISSING_PARAM, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# threepids not valid
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"threepids": {"medium": "email", "wrong_address": "id"}},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.MISSING_PARAM, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"threepids": {"address": "value"}},
|
||||||
|
)
|
||||||
|
self.assertEqual(400, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.MISSING_PARAM, channel.json_body["errcode"])
|
||||||
|
|
||||||
def test_get_user(self):
|
def test_get_user(self):
|
||||||
"""
|
"""
|
||||||
Test a simple get of a user.
|
Test a simple get of a user.
|
||||||
@ -1255,43 +1350,6 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
|||||||
self.assertEqual("User", channel.json_body["displayname"])
|
self.assertEqual("User", channel.json_body["displayname"])
|
||||||
self._check_fields(channel.json_body)
|
self._check_fields(channel.json_body)
|
||||||
|
|
||||||
def test_get_user_with_sso(self):
|
|
||||||
"""
|
|
||||||
Test get a user with SSO details.
|
|
||||||
"""
|
|
||||||
self.get_success(
|
|
||||||
self.store.record_user_external_id(
|
|
||||||
"auth_provider1", "external_id1", self.other_user
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.get_success(
|
|
||||||
self.store.record_user_external_id(
|
|
||||||
"auth_provider2", "external_id2", self.other_user
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
channel = self.make_request(
|
|
||||||
"GET",
|
|
||||||
self.url_other_user,
|
|
||||||
access_token=self.admin_user_tok,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(200, channel.code, msg=channel.json_body)
|
|
||||||
self.assertEqual("@user:test", channel.json_body["name"])
|
|
||||||
self.assertEqual(
|
|
||||||
"external_id1", channel.json_body["external_ids"][0]["external_id"]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
"auth_provider1", channel.json_body["external_ids"][0]["auth_provider"]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
"external_id2", channel.json_body["external_ids"][1]["external_id"]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
"auth_provider2", channel.json_body["external_ids"][1]["auth_provider"]
|
|
||||||
)
|
|
||||||
self._check_fields(channel.json_body)
|
|
||||||
|
|
||||||
def test_create_server_admin(self):
|
def test_create_server_admin(self):
|
||||||
"""
|
"""
|
||||||
Check that a new admin user is created successfully.
|
Check that a new admin user is created successfully.
|
||||||
@ -1353,6 +1411,12 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
|||||||
"admin": False,
|
"admin": False,
|
||||||
"displayname": "Bob's name",
|
"displayname": "Bob's name",
|
||||||
"threepids": [{"medium": "email", "address": "bob@bob.bob"}],
|
"threepids": [{"medium": "email", "address": "bob@bob.bob"}],
|
||||||
|
"external_ids": [
|
||||||
|
{
|
||||||
|
"external_id": "external_id1",
|
||||||
|
"auth_provider": "auth_provider1",
|
||||||
|
},
|
||||||
|
],
|
||||||
"avatar_url": "mxc://fibble/wibble",
|
"avatar_url": "mxc://fibble/wibble",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1368,6 +1432,12 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
|||||||
self.assertEqual("Bob's name", channel.json_body["displayname"])
|
self.assertEqual("Bob's name", channel.json_body["displayname"])
|
||||||
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
|
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
|
||||||
self.assertEqual("bob@bob.bob", channel.json_body["threepids"][0]["address"])
|
self.assertEqual("bob@bob.bob", channel.json_body["threepids"][0]["address"])
|
||||||
|
self.assertEqual(
|
||||||
|
"external_id1", channel.json_body["external_ids"][0]["external_id"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
"auth_provider1", channel.json_body["external_ids"][0]["auth_provider"]
|
||||||
|
)
|
||||||
self.assertFalse(channel.json_body["admin"])
|
self.assertFalse(channel.json_body["admin"])
|
||||||
self.assertEqual("mxc://fibble/wibble", channel.json_body["avatar_url"])
|
self.assertEqual("mxc://fibble/wibble", channel.json_body["avatar_url"])
|
||||||
self._check_fields(channel.json_body)
|
self._check_fields(channel.json_body)
|
||||||
@ -1632,6 +1702,103 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
|||||||
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
|
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
|
||||||
self.assertEqual("bob3@bob.bob", channel.json_body["threepids"][0]["address"])
|
self.assertEqual("bob3@bob.bob", channel.json_body["threepids"][0]["address"])
|
||||||
|
|
||||||
|
def test_set_external_id(self):
|
||||||
|
"""
|
||||||
|
Test setting external id for an other user.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Add two external_ids
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={
|
||||||
|
"external_ids": [
|
||||||
|
{
|
||||||
|
"external_id": "external_id1",
|
||||||
|
"auth_provider": "auth_provider1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"external_id": "external_id2",
|
||||||
|
"auth_provider": "auth_provider2",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual("@user:test", channel.json_body["name"])
|
||||||
|
self.assertEqual(2, len(channel.json_body["external_ids"]))
|
||||||
|
# result does not always have the same sort order, therefore it becomes sorted
|
||||||
|
self.assertEqual(
|
||||||
|
sorted(channel.json_body["external_ids"], key=lambda k: k["auth_provider"]),
|
||||||
|
[
|
||||||
|
{"auth_provider": "auth_provider1", "external_id": "external_id1"},
|
||||||
|
{"auth_provider": "auth_provider2", "external_id": "external_id2"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self._check_fields(channel.json_body)
|
||||||
|
|
||||||
|
# Set a new and remove an external_id
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={
|
||||||
|
"external_ids": [
|
||||||
|
{
|
||||||
|
"external_id": "external_id2",
|
||||||
|
"auth_provider": "auth_provider2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"external_id": "external_id3",
|
||||||
|
"auth_provider": "auth_provider3",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual("@user:test", channel.json_body["name"])
|
||||||
|
self.assertEqual(2, len(channel.json_body["external_ids"]))
|
||||||
|
self.assertEqual(
|
||||||
|
channel.json_body["external_ids"],
|
||||||
|
[
|
||||||
|
{"auth_provider": "auth_provider2", "external_id": "external_id2"},
|
||||||
|
{"auth_provider": "auth_provider3", "external_id": "external_id3"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self._check_fields(channel.json_body)
|
||||||
|
|
||||||
|
# Get user
|
||||||
|
channel = self.make_request(
|
||||||
|
"GET",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual("@user:test", channel.json_body["name"])
|
||||||
|
self.assertEqual(
|
||||||
|
channel.json_body["external_ids"],
|
||||||
|
[
|
||||||
|
{"auth_provider": "auth_provider2", "external_id": "external_id2"},
|
||||||
|
{"auth_provider": "auth_provider3", "external_id": "external_id3"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self._check_fields(channel.json_body)
|
||||||
|
|
||||||
|
# Remove external_ids
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
self.url_other_user,
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
content={"external_ids": []},
|
||||||
|
)
|
||||||
|
self.assertEqual(200, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual("@user:test", channel.json_body["name"])
|
||||||
|
self.assertEqual(0, len(channel.json_body["external_ids"]))
|
||||||
|
|
||||||
def test_deactivate_user(self):
|
def test_deactivate_user(self):
|
||||||
"""
|
"""
|
||||||
Test deactivating another user.
|
Test deactivating another user.
|
||||||
|
Loading…
Reference in New Issue
Block a user