Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Admin api to add an email address (#6789)
Browse files Browse the repository at this point in the history
  • Loading branch information
dklimpel authored Feb 7, 2020
1 parent f488444 commit 56ca93e
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.d/6769.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Admin API to add or modify threepids of user accounts.
11 changes: 11 additions & 0 deletions docs/admin_api/user_admin_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ with a body of:
{
"password": "user_password",
"displayname": "User",
"threepids": [
{
"medium": "email",
"address": "<user_mail_1>"
},
{
"medium": "email",
"address": "<user_mail_2>"
}
],
"avatar_url": "<avatar_url>",
"admin": false,
"deactivated": false
Expand All @@ -23,6 +33,7 @@ with a body of:
including an ``access_token`` of a server admin.

The parameter ``displayname`` is optional and defaults to ``user_id``.
The parameter ``threepids`` is optional.
The parameter ``avatar_url`` is optional.
The parameter ``admin`` is optional and defaults to 'false'.
The parameter ``deactivated`` is optional and defaults to 'false'.
Expand Down
2 changes: 2 additions & 0 deletions synapse/handlers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ async def get_user(self, user):
ret = await self.store.get_user_by_id(user.to_string())
if ret:
profile = await self.store.get_profileinfo(user.localpart)
threepids = await self.store.user_get_threepids(user.to_string())
ret["displayname"] = profile.display_name
ret["avatar_url"] = profile.avatar_url
ret["threepids"] = threepids
return ret

async def export_user_data(self, user_id, writer):
Expand Down
8 changes: 8 additions & 0 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,14 @@ def delete_access_tokens_for_user(

@defer.inlineCallbacks
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.
# We've now moving towards the homeserver being the entity that
# is responsible for validating threepids used for resetting passwords
Expand Down
39 changes: 39 additions & 0 deletions synapse/rest/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ def __init__(self, hs):
self.hs = hs
self.auth = hs.get_auth()
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.set_password_handler = hs.get_set_password_handler()
self.deactivate_account_handler = hs.get_deactivate_account_handler()
Expand Down Expand Up @@ -163,13 +165,37 @@ async def on_PUT(self, request, user_id):
raise SynapseError(400, "This endpoint can only be used with local users")

user = await self.admin_handler.get_user(target_user)
user_id = target_user.to_string()

if user: # modify user
if "displayname" in body:
await self.profile_handler.set_displayname(
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:
await self.profile_handler.set_avatar_url(
target_user, requester, body["avatar_url"], True
Expand Down Expand Up @@ -221,6 +247,7 @@ async def on_PUT(self, request, user_id):
admin = body.get("admin", None)
user_type = body.get("user_type", 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:
raise SynapseError(400, "Invalid user type")
Expand All @@ -232,6 +259,18 @@ async def on_PUT(self, request, user_id):
default_display_name=displayname,
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:
await self.profile_handler.set_avatar_url(
user_id, requester, body["avatar_url"], True
Expand Down
19 changes: 17 additions & 2 deletions tests/rest/admin/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,13 @@ def test_requester_is_admin(self):
"""
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": "[email protected]"}],
}
)

# Create user
request, channel = self.make_request(
Expand All @@ -421,6 +427,8 @@ def test_requester_is_admin(self):
self.assertEqual(201, int(channel.result["code"]), msg=channel.result["body"])
self.assertEqual("@bob:test", channel.json_body["name"])
self.assertEqual("bob", channel.json_body["displayname"])
self.assertEqual("email", channel.json_body["threepids"][0]["medium"])
self.assertEqual("[email protected]", channel.json_body["threepids"][0]["address"])

# Get user
request, channel = self.make_request(
Expand Down Expand Up @@ -449,7 +457,13 @@ def test_requester_is_admin(self):
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])

# Modify user
body = json.dumps({"displayname": "foobar", "deactivated": True})
body = json.dumps(
{
"displayname": "foobar",
"deactivated": True,
"threepids": [{"medium": "email", "address": "[email protected]"}],
}
)

request, channel = self.make_request(
"PUT",
Expand All @@ -463,6 +477,7 @@ def test_requester_is_admin(self):
self.assertEqual("@bob:test", channel.json_body["name"])
self.assertEqual("foobar", channel.json_body["displayname"])
self.assertEqual(True, channel.json_body["deactivated"])
# the user is deactivated, the threepid will be deleted

# Get user
request, channel = self.make_request(
Expand Down

0 comments on commit 56ca93e

Please sign in to comment.