-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Admin API implementation #253
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# -*- coding: utf-8 -*- | ||
from matrix_client.api import MatrixHttpApi | ||
try: | ||
basestring | ||
except NameError: | ||
basestring = str | ||
|
||
|
||
class MatrixHttpAdminApi(MatrixHttpApi): | ||
"""Extends Matrix API with admin calls. | ||
|
||
Examples: | ||
Create a client and send a message:: | ||
|
||
matrix = MatrixHttpAdminApi("https://matrix.org", token="foobar") | ||
response = admin_api.shutdown_room( | ||
"!DgvjtOljKujDBrxyHk:matrix.org", | ||
"@admin:matrix.org", | ||
room_name="New room", | ||
message="Old room closed by admin" | ||
) | ||
""" | ||
def purge_history(self, room_id, event_id): | ||
"""Perform /admin/purge_hostory. | ||
Admin api part. | ||
Args: | ||
room_id (str): Room_id to purge. | ||
event_id (str or int): Event_id or ts to purge before. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not simply have two optional arguments? It would look clearer to me, and simplify the code. |
||
""" | ||
if isinstance(event_id, basestring): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not relevant if you choose to follow the comment above, but it looks like swapping the |
||
content = { | ||
"delete_local_events": True, | ||
"purge_up_to_event_id": event_id | ||
} | ||
else: | ||
content = { | ||
"delete_local_events": True, | ||
"purge_up_to_ts": int(event_id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to the docstring, this is already an |
||
} | ||
return self._send("POST", "/admin/purge_history/%s" % room_id, content) | ||
|
||
def purge_history_status(self, purge_id): | ||
"""Perform /admin/purge_history_status. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be a newline after this one (applies to most of the docstrings here). |
||
Admin api part. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I doubt this line is useful, but if you want to keep it it needs a newline after (applies to every docstrings). |
||
Args: | ||
purge_id (str): Purge_id to query status. | ||
""" | ||
return self._send("GET", "/admin/purge_history_status/%s" % purge_id) | ||
|
||
def media_in_room(self, room_id, event_id=None): | ||
"""List remote and local media in room. | ||
Args: | ||
room_id (str): Room_id to purge. | ||
""" | ||
return self._send("GET", "/admin/room/%s/media" % room_id) | ||
|
||
def whois(self, user_id): | ||
"""Query server for user information (ip, UA, last seen). | ||
Admin api part. | ||
Args: | ||
user_id (str): user_id to query. | ||
""" | ||
return self._send("GET", "/admin/whois/%s" % user_id) | ||
|
||
def deactivate(self, user_id, erase=False): | ||
"""Deactivate user account. | ||
Admin api part. | ||
Args: | ||
user_id (str): user_id to deactivate. | ||
erase (bool): erase user data. Default no. | ||
""" | ||
content = { | ||
"erase": erase | ||
} | ||
return self._send("POST", "/admin/deactivate/%s" % user_id, content) | ||
|
||
def reset_password(self, user_id, password): | ||
"""Reset users's password to provided. | ||
Admin api part. | ||
Args: | ||
user_id (str): user_id to deactivate. | ||
password (str): password to set. | ||
""" | ||
content = { | ||
"new_password": password | ||
} | ||
return self._send("POST", "/admin/reset_password/%s" % user_id, content) | ||
|
||
def quarantine_media(self, room_id): | ||
"""Quarantine all media in room so that no one can download it via thi server. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
Admin api part. | ||
Args: | ||
room_id (str): room_id to quarantine. | ||
""" | ||
return self._send("POST", "/admin/quarantine_media/%s" % room_id) | ||
|
||
def shutdown_room(self, room_id, new_room_user_id, room_name=False, message=False): | ||
"""Shuts down a room by removing all local users from the room and blocking | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first line of a docstring should be a single sentence, ie not split across multiple lines. |
||
all future invites and joins to the room. Any local aliases will be repointed | ||
to a new room created by `new_room_user_id` and kicked users will be auto | ||
joined to the new room | ||
Admin api part. | ||
Args: | ||
room_id (str): room_id to quarantine. | ||
new_room_user_id (str): new room creator user_id. | ||
room_name (str): new room name. | ||
message (str): information message for new room. | ||
""" | ||
content = { | ||
"new_room_user_id": new_room_user_id | ||
} | ||
if room_name: | ||
content["room_name"] = room_name | ||
if message: | ||
content["message"] = message | ||
return self._send("POST", "/admin/shutdown_room/%s" % room_id, content) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
import responses | ||
import json | ||
from matrix_client.admin_api import MatrixHttpAdminApi | ||
|
||
|
||
class TestAdminApi: | ||
admin_api = MatrixHttpAdminApi("http://example.com") | ||
user_id = "@alice:matrix.org" | ||
room_id = "!gveUzqBzXPqmwvDaCZ:example.org" | ||
event_id = "$153119074937XoqNn::example.org" | ||
up_to_ts = 1531190749090 | ||
purge_id = "dLVEjckmfggyQduS" | ||
|
||
@responses.activate | ||
def test_purge_history_eventid(self): | ||
purge_history_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/purge_history/%s" % self.room_id | ||
responses.add( | ||
responses.POST, | ||
purge_history_url, | ||
body='{"purge_id": "%s"}' % self.purge_id | ||
) | ||
self.admin_api.purge_history(self.room_id, self.event_id) | ||
req = responses.calls[0].request | ||
assert req.url == purge_history_url | ||
assert req.method == 'POST' | ||
j = json.loads(req.body) | ||
assert j["delete_local_events"] | ||
assert j["purge_up_to_event_id"] == self.event_id | ||
|
||
@responses.activate | ||
def test_purge_history_up_to_ts(self): | ||
purge_history_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/purge_history/%s" % self.room_id | ||
responses.add( | ||
responses.POST, | ||
purge_history_url, | ||
body='{"purge_id": "%s"}' % self.purge_id | ||
) | ||
self.admin_api.purge_history(self.room_id, self.up_to_ts) | ||
req = responses.calls[0].request | ||
j = json.loads(req.body) | ||
assert j["delete_local_events"] | ||
assert j["purge_up_to_ts"] == self.up_to_ts | ||
|
||
@responses.activate | ||
def test_purge_history_status(self): | ||
purge_history_status_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/purge_history_status/%s" % self.purge_id | ||
responses.add( | ||
responses.GET, | ||
purge_history_status_url, | ||
body='{"status": "complete"}' | ||
) | ||
self.admin_api.purge_history_status(self.purge_id) | ||
req = responses.calls[0].request | ||
assert req.url == purge_history_status_url | ||
|
||
@responses.activate | ||
def test_media_in_room(self): | ||
media_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/room/%s/media" % self.room_id | ||
responses.add( | ||
responses.GET, | ||
media_url, | ||
body='{"local": ["mxc://example.com/xwvutsrqponmlkjihgfedcba"],' | ||
' "remote": ["mxc://matrix.org/xwtttsrqponmlkjihgfedcba"]}' | ||
) | ||
resp = self.admin_api.media_in_room(self.room_id) | ||
req = responses.calls[0].request | ||
assert req.url == media_url | ||
assert req.method == 'GET' | ||
assert "local" in resp | ||
assert "remote" in resp | ||
|
||
@responses.activate | ||
def test_whois(self): | ||
whois_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/whois/%s" % self.user_id | ||
responses.add( | ||
responses.GET, | ||
whois_url, | ||
body='{"user_id": "%s", "devices": {}}' % self.user_id | ||
) | ||
self.admin_api.whois(self.user_id) | ||
req = responses.calls[0].request | ||
assert req.url == whois_url | ||
assert req.method == 'GET' | ||
|
||
@responses.activate | ||
def test_deactivate_no_erase(self): | ||
erase_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/deactivate/%s" % self.user_id | ||
responses.add(responses.POST, erase_url, body='{}') | ||
self.admin_api.deactivate(self.user_id) | ||
req = responses.calls[0].request | ||
assert req.url == erase_url | ||
assert req.method == 'POST' | ||
|
||
@responses.activate | ||
def test_deactivate(self): | ||
erase_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/deactivate/%s" % self.user_id | ||
responses.add(responses.POST, erase_url, body='{}') | ||
self.admin_api.deactivate(self.user_id, erase=True) | ||
req = responses.calls[0].request | ||
assert req.url == erase_url | ||
assert req.method == 'POST' | ||
j = json.loads(req.body) | ||
assert j["erase"] | ||
|
||
@responses.activate | ||
def test_reset_password(self): | ||
reset_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/reset_password/%s" % self.user_id | ||
responses.add(responses.POST, reset_url, body='{}') | ||
self.admin_api.reset_password(self.user_id, 'secret') | ||
req = responses.calls[0].request | ||
assert req.url == reset_url | ||
assert req.method == 'POST' | ||
j = json.loads(req.body) | ||
assert j["new_password"] == 'secret' | ||
|
||
@responses.activate | ||
def test_quarantine_media(self): | ||
quarantine_media_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/quarantine_media/%s" % self.room_id | ||
responses.add( | ||
responses.POST, | ||
quarantine_media_url, | ||
body='{"num_quarantined": 1}' | ||
) | ||
self.admin_api.quarantine_media(self.room_id) | ||
req = responses.calls[0].request | ||
assert req.url == quarantine_media_url | ||
assert req.method == 'POST' | ||
|
||
@responses.activate | ||
def test_shutdown_room(self): | ||
shutdown_room_url = \ | ||
"http://example.com/_matrix/client/r0/" \ | ||
"admin/shutdown_room/%s" % self.room_id | ||
responses.add( | ||
responses.POST, | ||
shutdown_room_url, | ||
body='{"kicked_users": 2, ' | ||
'"local_aliases": [], ' | ||
'"new_room_id": "!hepuyalbwtkjapqdhq:example.org"}' | ||
) | ||
self.admin_api.shutdown_room( | ||
self.room_id, | ||
self.user_id, | ||
room_name="New room", | ||
message="Old room closed by admin" | ||
) | ||
req = responses.calls[0].request | ||
assert req.url == shutdown_room_url | ||
assert req.method == 'POST' | ||
j = json.loads(req.body) | ||
assert j["new_room_user_id"] == self.user_id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo