This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Mount /_synapse/admin/v1/users/{userId}/media admin API on media workers only #10628
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2f02609
Mount /_synapse/admin/v1/users/{userId}/media admin API on media work…
anoadragon453 339b0be
Update worker documentation
anoadragon453 eeda958
Add an entry to docs/upgrade.md to reflect the change
anoadragon453 0de2c24
reuse the changelog from #10558
anoadragon453 8602d79
Lint
clokep dce3d2e
Clarify worker documentation
anoadragon453 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Admin API to delete several media for a specific user. Contributed by @dklimpel. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,14 +18,15 @@ | |
|
||
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError | ||
from synapse.http.server import HttpServer | ||
from synapse.http.servlet import RestServlet, parse_boolean, parse_integer | ||
from synapse.http.servlet import RestServlet, parse_boolean, parse_integer, parse_string | ||
from synapse.http.site import SynapseRequest | ||
from synapse.rest.admin._base import ( | ||
admin_patterns, | ||
assert_requester_is_admin, | ||
assert_user_is_admin, | ||
) | ||
from synapse.types import JsonDict | ||
from synapse.storage.databases.main.media_repository import MediaSortOrder | ||
from synapse.types import JsonDict, UserID | ||
|
||
if TYPE_CHECKING: | ||
from synapse.server import HomeServer | ||
|
@@ -314,6 +315,165 @@ async def on_POST( | |
return 200, {"deleted_media": deleted_media, "total": total} | ||
|
||
|
||
class UserMediaRestServlet(RestServlet): | ||
""" | ||
Gets information about all uploaded local media for a specific `user_id`. | ||
With DELETE request you can delete all this media. | ||
|
||
Example: | ||
http://localhost:8008/_synapse/admin/v1/users/@user:server/media | ||
|
||
Args: | ||
The parameters `from` and `limit` are required for pagination. | ||
By default, a `limit` of 100 is used. | ||
Returns: | ||
A list of media and an integer representing the total number of | ||
media that exist given for this user | ||
""" | ||
|
||
PATTERNS = admin_patterns("/users/(?P<user_id>[^/]+)/media$") | ||
|
||
def __init__(self, hs: "HomeServer"): | ||
self.is_mine = hs.is_mine | ||
self.auth = hs.get_auth() | ||
self.store = hs.get_datastore() | ||
self.media_repository = hs.get_media_repository() | ||
|
||
async def on_GET( | ||
self, request: SynapseRequest, user_id: str | ||
) -> Tuple[int, JsonDict]: | ||
# This will always be set by the time Twisted calls us. | ||
assert request.args is not None | ||
|
||
await assert_requester_is_admin(self.auth, request) | ||
|
||
if not self.is_mine(UserID.from_string(user_id)): | ||
raise SynapseError(400, "Can only look up local users") | ||
|
||
user = await self.store.get_user_by_id(user_id) | ||
if user is None: | ||
raise NotFoundError("Unknown user") | ||
|
||
start = parse_integer(request, "from", default=0) | ||
limit = parse_integer(request, "limit", default=100) | ||
|
||
if start < 0: | ||
raise SynapseError( | ||
400, | ||
"Query parameter from must be a string representing a positive integer.", | ||
errcode=Codes.INVALID_PARAM, | ||
) | ||
|
||
if limit < 0: | ||
raise SynapseError( | ||
400, | ||
"Query parameter limit must be a string representing a positive integer.", | ||
errcode=Codes.INVALID_PARAM, | ||
) | ||
|
||
# If neither `order_by` nor `dir` is set, set the default order | ||
# to newest media is on top for backward compatibility. | ||
if b"order_by" not in request.args and b"dir" not in request.args: | ||
order_by = MediaSortOrder.CREATED_TS.value | ||
direction = "b" | ||
else: | ||
order_by = parse_string( | ||
request, | ||
"order_by", | ||
default=MediaSortOrder.CREATED_TS.value, | ||
allowed_values=( | ||
MediaSortOrder.MEDIA_ID.value, | ||
MediaSortOrder.UPLOAD_NAME.value, | ||
MediaSortOrder.CREATED_TS.value, | ||
MediaSortOrder.LAST_ACCESS_TS.value, | ||
MediaSortOrder.MEDIA_LENGTH.value, | ||
MediaSortOrder.MEDIA_TYPE.value, | ||
MediaSortOrder.QUARANTINED_BY.value, | ||
MediaSortOrder.SAFE_FROM_QUARANTINE.value, | ||
), | ||
) | ||
direction = parse_string( | ||
request, "dir", default="f", allowed_values=("f", "b") | ||
) | ||
|
||
media, total = await self.store.get_local_media_by_user_paginate( | ||
start, limit, user_id, order_by, direction | ||
) | ||
|
||
ret = {"media": media, "total": total} | ||
if (start + limit) < total: | ||
ret["next_token"] = start + len(media) | ||
|
||
return 200, ret | ||
|
||
async def on_DELETE( | ||
self, request: SynapseRequest, user_id: str | ||
) -> Tuple[int, JsonDict]: | ||
# This will always be set by the time Twisted calls us. | ||
assert request.args is not None | ||
|
||
await assert_requester_is_admin(self.auth, request) | ||
|
||
if not self.is_mine(UserID.from_string(user_id)): | ||
raise SynapseError(400, "Can only look up local users") | ||
|
||
user = await self.store.get_user_by_id(user_id) | ||
if user is None: | ||
raise NotFoundError("Unknown user") | ||
|
||
start = parse_integer(request, "from", default=0) | ||
limit = parse_integer(request, "limit", default=100) | ||
|
||
if start < 0: | ||
raise SynapseError( | ||
400, | ||
"Query parameter from must be a string representing a positive integer.", | ||
errcode=Codes.INVALID_PARAM, | ||
) | ||
|
||
if limit < 0: | ||
raise SynapseError( | ||
400, | ||
"Query parameter limit must be a string representing a positive integer.", | ||
errcode=Codes.INVALID_PARAM, | ||
) | ||
|
||
# If neither `order_by` nor `dir` is set, set the default order | ||
# to newest media is on top for backward compatibility. | ||
if b"order_by" not in request.args and b"dir" not in request.args: | ||
order_by = MediaSortOrder.CREATED_TS.value | ||
direction = "b" | ||
else: | ||
order_by = parse_string( | ||
request, | ||
"order_by", | ||
default=MediaSortOrder.CREATED_TS.value, | ||
allowed_values=( | ||
MediaSortOrder.MEDIA_ID.value, | ||
MediaSortOrder.UPLOAD_NAME.value, | ||
MediaSortOrder.CREATED_TS.value, | ||
MediaSortOrder.LAST_ACCESS_TS.value, | ||
MediaSortOrder.MEDIA_LENGTH.value, | ||
MediaSortOrder.MEDIA_TYPE.value, | ||
MediaSortOrder.QUARANTINED_BY.value, | ||
MediaSortOrder.SAFE_FROM_QUARANTINE.value, | ||
), | ||
) | ||
direction = parse_string( | ||
request, "dir", default="f", allowed_values=("f", "b") | ||
) | ||
|
||
media, _ = await self.store.get_local_media_by_user_paginate( | ||
start, limit, user_id, order_by, direction | ||
) | ||
|
||
deleted_media, total = await self.media_repository.delete_local_media_ids( | ||
([row["media_id"] for row in media]) | ||
) | ||
|
||
return 200, {"deleted_media": deleted_media, "total": total} | ||
|
||
|
||
def register_servlets_for_media_repo(hs: "HomeServer", http_server: HttpServer) -> None: | ||
""" | ||
Media repo specific APIs. | ||
|
@@ -328,3 +488,4 @@ def register_servlets_for_media_repo(hs: "HomeServer", http_server: HttpServer) | |
ListMediaInRoom(hs).register(http_server) | ||
DeleteMediaByID(hs).register(http_server) | ||
DeleteMediaByDateSize(hs).register(http_server) | ||
UserMediaRestServlet(hs).register(http_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. Weirdly I think this means this will be available when a I don't think that's a huge deal, although we should probably clean all that up at some point... |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
(I actually wanted to comment on line 418...)
I think this change is saying that this endpoint must be handled by the media repo? "It can handle all endpoints start with..." makes it sound like an optional thing.
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.
Good spot! Well, the main process can also handle it; but not when media workers are in use, as media repository functionality is typically disabled on the main process in that case.
I've added a line to help clarify things.