mirror of
https://github.com/element-hq/synapse.git
synced 2025-03-31 03:45:13 +00:00
Admin api to add an email address (#6789)
This commit is contained in:
parent
f4884444c3
commit
56ca93ef59
6 changed files with 78 additions and 2 deletions
1
changelog.d/6769.feature
Normal file
1
changelog.d/6769.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Admin API to add or modify threepids of user accounts.
|
|
@ -15,6 +15,16 @@ with a body of:
|
||||||
{
|
{
|
||||||
"password": "user_password",
|
"password": "user_password",
|
||||||
"displayname": "User",
|
"displayname": "User",
|
||||||
|
"threepids": [
|
||||||
|
{
|
||||||
|
"medium": "email",
|
||||||
|
"address": "<user_mail_1>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"medium": "email",
|
||||||
|
"address": "<user_mail_2>"
|
||||||
|
}
|
||||||
|
],
|
||||||
"avatar_url": "<avatar_url>",
|
"avatar_url": "<avatar_url>",
|
||||||
"admin": false,
|
"admin": false,
|
||||||
"deactivated": false
|
"deactivated": false
|
||||||
|
@ -23,6 +33,7 @@ with a body of:
|
||||||
including an ``access_token`` of a server admin.
|
including an ``access_token`` of a server admin.
|
||||||
|
|
||||||
The parameter ``displayname`` is optional and defaults to ``user_id``.
|
The parameter ``displayname`` is optional and defaults to ``user_id``.
|
||||||
|
The parameter ``threepids`` is optional.
|
||||||
The parameter ``avatar_url`` is optional.
|
The parameter ``avatar_url`` is optional.
|
||||||
The parameter ``admin`` is optional and defaults to 'false'.
|
The parameter ``admin`` is optional and defaults to 'false'.
|
||||||
The parameter ``deactivated`` is optional and defaults to 'false'.
|
The parameter ``deactivated`` is optional and defaults to 'false'.
|
||||||
|
|
|
@ -58,8 +58,10 @@ class AdminHandler(BaseHandler):
|
||||||
ret = await self.store.get_user_by_id(user.to_string())
|
ret = await self.store.get_user_by_id(user.to_string())
|
||||||
if ret:
|
if ret:
|
||||||
profile = await self.store.get_profileinfo(user.localpart)
|
profile = await self.store.get_profileinfo(user.localpart)
|
||||||
|
threepids = await self.store.user_get_threepids(user.to_string())
|
||||||
ret["displayname"] = profile.display_name
|
ret["displayname"] = profile.display_name
|
||||||
ret["avatar_url"] = profile.avatar_url
|
ret["avatar_url"] = profile.avatar_url
|
||||||
|
ret["threepids"] = threepids
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
async def export_user_data(self, user_id, writer):
|
async def export_user_data(self, user_id, writer):
|
||||||
|
|
|
@ -816,6 +816,14 @@ class AuthHandler(BaseHandler):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def add_threepid(self, user_id, medium, address, validated_at):
|
def add_threepid(self, user_id, medium, address, validated_at):
|
||||||
|
# check if medium has a valid value
|
||||||
|
if medium not in ["email", "msisdn"]:
|
||||||
|
raise SynapseError(
|
||||||
|
code=400,
|
||||||
|
msg=("'%s' is not a valid value for 'medium'" % (medium,)),
|
||||||
|
errcode=Codes.INVALID_PARAM,
|
||||||
|
)
|
||||||
|
|
||||||
# 'Canonicalise' email addresses down to lower case.
|
# 'Canonicalise' email addresses down to lower case.
|
||||||
# We've now moving towards the homeserver being the entity that
|
# We've now moving towards the homeserver being the entity that
|
||||||
# is responsible for validating threepids used for resetting passwords
|
# is responsible for validating threepids used for resetting passwords
|
||||||
|
|
|
@ -136,6 +136,8 @@ class UserRestServletV2(RestServlet):
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
self.auth = hs.get_auth()
|
self.auth = hs.get_auth()
|
||||||
self.admin_handler = hs.get_handlers().admin_handler
|
self.admin_handler = hs.get_handlers().admin_handler
|
||||||
|
self.store = hs.get_datastore()
|
||||||
|
self.auth_handler = hs.get_auth_handler()
|
||||||
self.profile_handler = hs.get_profile_handler()
|
self.profile_handler = hs.get_profile_handler()
|
||||||
self.set_password_handler = hs.get_set_password_handler()
|
self.set_password_handler = hs.get_set_password_handler()
|
||||||
self.deactivate_account_handler = hs.get_deactivate_account_handler()
|
self.deactivate_account_handler = hs.get_deactivate_account_handler()
|
||||||
|
@ -163,6 +165,7 @@ class UserRestServletV2(RestServlet):
|
||||||
raise SynapseError(400, "This endpoint can only be used with local users")
|
raise SynapseError(400, "This endpoint can only be used with local users")
|
||||||
|
|
||||||
user = await self.admin_handler.get_user(target_user)
|
user = await self.admin_handler.get_user(target_user)
|
||||||
|
user_id = target_user.to_string()
|
||||||
|
|
||||||
if user: # modify user
|
if user: # modify user
|
||||||
if "displayname" in body:
|
if "displayname" in body:
|
||||||
|
@ -170,6 +173,29 @@ class UserRestServletV2(RestServlet):
|
||||||
target_user, requester, body["displayname"], True
|
target_user, requester, body["displayname"], True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "threepids" in body:
|
||||||
|
# check for required parameters for each threepid
|
||||||
|
for threepid in body["threepids"]:
|
||||||
|
assert_params_in_dict(threepid, ["medium", "address"])
|
||||||
|
|
||||||
|
# remove old threepids from user
|
||||||
|
threepids = await self.store.user_get_threepids(user_id)
|
||||||
|
for threepid in threepids:
|
||||||
|
try:
|
||||||
|
await self.auth_handler.delete_threepid(
|
||||||
|
user_id, threepid["medium"], threepid["address"], None
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to remove threepids")
|
||||||
|
raise SynapseError(500, "Failed to remove threepids")
|
||||||
|
|
||||||
|
# add new threepids to user
|
||||||
|
current_time = self.hs.get_clock().time_msec()
|
||||||
|
for threepid in body["threepids"]:
|
||||||
|
await self.auth_handler.add_threepid(
|
||||||
|
user_id, threepid["medium"], threepid["address"], current_time
|
||||||
|
)
|
||||||
|
|
||||||
if "avatar_url" in body:
|
if "avatar_url" in body:
|
||||||
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
|
||||||
|
@ -221,6 +247,7 @@ class UserRestServletV2(RestServlet):
|
||||||
admin = body.get("admin", None)
|
admin = body.get("admin", None)
|
||||||
user_type = body.get("user_type", None)
|
user_type = body.get("user_type", None)
|
||||||
displayname = body.get("displayname", None)
|
displayname = body.get("displayname", None)
|
||||||
|
threepids = body.get("threepids", None)
|
||||||
|
|
||||||
if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES:
|
if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES:
|
||||||
raise SynapseError(400, "Invalid user type")
|
raise SynapseError(400, "Invalid user type")
|
||||||
|
@ -232,6 +259,18 @@ class UserRestServletV2(RestServlet):
|
||||||
default_display_name=displayname,
|
default_display_name=displayname,
|
||||||
user_type=user_type,
|
user_type=user_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "threepids" in body:
|
||||||
|
# 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()
|
||||||
|
for threepid in body["threepids"]:
|
||||||
|
await self.auth_handler.add_threepid(
|
||||||
|
user_id, threepid["medium"], threepid["address"], current_time
|
||||||
|
)
|
||||||
|
|
||||||
if "avatar_url" in body:
|
if "avatar_url" in body:
|
||||||
await self.profile_handler.set_avatar_url(
|
await self.profile_handler.set_avatar_url(
|
||||||
user_id, requester, body["avatar_url"], True
|
user_id, requester, body["avatar_url"], True
|
||||||
|
|
|
@ -407,7 +407,13 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
||||||
"""
|
"""
|
||||||
self.hs.config.registration_shared_secret = None
|
self.hs.config.registration_shared_secret = None
|
||||||
|
|
||||||
body = json.dumps({"password": "abc123", "admin": True})
|
body = json.dumps(
|
||||||
|
{
|
||||||
|
"password": "abc123",
|
||||||
|
"admin": True,
|
||||||
|
"threepids": [{"medium": "email", "address": "bob@bob.bob"}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# Create user
|
# Create user
|
||||||
request, channel = self.make_request(
|
request, channel = self.make_request(
|
||||||
|
@ -421,6 +427,8 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
||||||
self.assertEqual(201, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(201, int(channel.result["code"]), msg=channel.result["body"])
|
||||||
self.assertEqual("@bob:test", channel.json_body["name"])
|
self.assertEqual("@bob:test", channel.json_body["name"])
|
||||||
self.assertEqual("bob", channel.json_body["displayname"])
|
self.assertEqual("bob", channel.json_body["displayname"])
|
||||||
|
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
|
||||||
|
self.assertEqual("bob@bob.bob", channel.json_body["threepids"][0]["address"])
|
||||||
|
|
||||||
# Get user
|
# Get user
|
||||||
request, channel = self.make_request(
|
request, channel = self.make_request(
|
||||||
|
@ -449,7 +457,13 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
||||||
|
|
||||||
# Modify user
|
# Modify user
|
||||||
body = json.dumps({"displayname": "foobar", "deactivated": True})
|
body = json.dumps(
|
||||||
|
{
|
||||||
|
"displayname": "foobar",
|
||||||
|
"deactivated": True,
|
||||||
|
"threepids": [{"medium": "email", "address": "bob2@bob.bob"}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
request, channel = self.make_request(
|
request, channel = self.make_request(
|
||||||
"PUT",
|
"PUT",
|
||||||
|
@ -463,6 +477,7 @@ class UserRestTestCase(unittest.HomeserverTestCase):
|
||||||
self.assertEqual("@bob:test", channel.json_body["name"])
|
self.assertEqual("@bob:test", channel.json_body["name"])
|
||||||
self.assertEqual("foobar", channel.json_body["displayname"])
|
self.assertEqual("foobar", channel.json_body["displayname"])
|
||||||
self.assertEqual(True, channel.json_body["deactivated"])
|
self.assertEqual(True, channel.json_body["deactivated"])
|
||||||
|
# the user is deactivated, the threepid will be deleted
|
||||||
|
|
||||||
# Get user
|
# Get user
|
||||||
request, channel = self.make_request(
|
request, channel = self.make_request(
|
||||||
|
|
Loading…
Add table
Reference in a new issue