make commands modular

This commit is contained in:
Hirad 2025-07-17 11:50:52 +03:30
parent 138eeb468a
commit 30ed2ef72c
3 changed files with 196 additions and 165 deletions

View file

@ -1,11 +1,8 @@
from typing import Optional
import click
from synclean.api.rooms import RoomAPI
from synclean.api.synapse import SynapseApiClient
from synclean.api.users import UserAPI
from synclean.config.settings import SettingsManager
from synclean.models.enums import RoomOrderBy, Direction, UserOrderBy
from synclean.models.pagination import PaginationParams, RoomPaginationParams, UserPaginationParams
from synclean.cli.room_commands import room
from synclean.cli.user_commands import user
pass_api = click.make_pass_decorator(SynapseApiClient)
@ -18,163 +15,5 @@ def cli(ctx):
ctx.obj = SynapseApiClient(config)
@cli.group()
def room():
"""Room commands."""
pass
@cli.group()
def user():
"""User commands."""
pass
@room.command("ls")
@click.option("--limit", "-l", default=100, help="Number of rooms to display per page.")
@click.option("--offset", "-o", default=0, help="Number of the room to start from.")
@click.option("--search", "-s", help="Search term to filter rooms by.")
@click.option("--order-by", "-O",
type=click.Choice(["name", "joined_members", "canonical_alias", "creator", "version",]),
default="name", help="Field to order result by.")
@click.option("--direction", "-d",
type=click.Choice(["f", "b"]),
default="b", help="Direction to order result by. (f=forward, b=backward)")
@pass_api
def room_ls(
api: SynapseApiClient,
limit: int,
offset: int,
search: Optional[str],
order_by: str,
direction: str
):
order_by_enum = RoomOrderBy(order_by)
direction_enum = Direction(direction)
rooms_api = RoomAPI(api)
while True:
pagination_params = RoomPaginationParams(limit, offset, order_by_enum, direction_enum, search)
rooms = rooms_api.get_rooms_list(pagination_params)
if rooms:
for r in rooms.rooms:
click.echo(f"Name: {r.name}")
click.echo(f"ID: {r.room_id}")
click.echo(f"Joined Members: {r.joined_members}")
click.echo("=" * 50)
else:
click.echo("No rooms found.")
offset += limit
choice = input("Next page? (y/n): ")
if choice.lower() != "y":
break
@room.command("show")
@click.argument("room_id")
@click.option("--media", is_flag=True, help="List media in the room")
@click.option("--rm-all", is_flag=True, help="Remove all media in the room")
@click.option("--rm", "remove_media_id", help="Remove media by ID")
@click.option("--avatar", is_flag=True, help="Show avatar URI")
@pass_api
def show_room(
api: SynapseApiClient,
room_id: str,
media: bool,
rm_all: bool,
remove_media_id: Optional[str],
avatar: bool
):
if room_id is None:
click.echo("You must specify a room ID.", err=True)
return
if rm_all or remove_media_id:
if not media:
click.echo("You must specify --media to remove media.")
return
room_api = RoomAPI(api)
room_details = room_api.get_room_details(room_id)
if not room_details:
click.echo(f"Error: Room {room_id} not found.", err=True)
return
if avatar:
if not room_details.avatar:
click.echo("Room has no avatar.")
return
click.echo(room_details.avatar)
# TODO: implement adding avatar to blacklist
if rm_all:
if click.confirm("Are you sure you want to remove all media in this room?"):
# TODO: implement removing all media from the room
pass
if remove_media_id:
if click.confirm(f"Are you sure you want to remove media {remove_media_id} from the room?"):
# TODO: implement removing media by ID
pass
if not media:
click.echo(f"Room details: {room_id}")
click.echo("=" * 40)
click.echo(f"Name: {room_details.name}")
click.echo(f"Avatar: {room_details.avatar}")
click.echo(f"ID: {room_details.room_id}")
click.echo(f"Members: {room_details.joined_members} (Local: {room_details.joined_local_members})")
click.echo(f"Creator: {room_details.creator}")
click.echo(f"Encryption: {room_details.encryption}")
click.echo(f"Public: {room_details.public}")
click.echo(f"Guest Access: {room_details.guest_access}")
click.echo(f"History Visibility: {room_details.history_visibility}")
click.echo(f"State Events: {room_details.state_events}")
click.echo(f"Room Type: {room_details.room_type}")
else:
room_media = room_api.get_media_from_room(room_id)
if room_media:
for uri in room_media.all_uris:
click.echo(f"URI: {uri}")
@user.command("ls")
@click.option("--limit", "-l", default=10, help="Number of users to list.")
@click.option("--offset", "-o", default=0, help="Number of the room to start from.")
@click.option("--search", "-s", help="Search term to filter by.")
@click.option("--order-by", "-O",
type=click.Choice(["user_id", "display_name", "media_length", "media_count"]),
default="media_length", help="Field to order result by.")
@click.option("--direction", "-d",
type=click.Choice(["f", "b"]),
default="b", help="Direction to order result by. (f=forward, b=backward)")
@pass_api
def user_ls(
api: SynapseApiClient,
limit: int,
offset: int,
search: Optional[str],
order_by: str,
direction: str
):
order_by_enum = UserOrderBy(order_by)
direction_enum = Direction(direction)
users_api = UserAPI(api)
while True:
pagination_params = UserPaginationParams(limit, offset, order_by_enum, direction_enum, search)
users = users_api.get_users_list_by_media(pagination_params)
if users:
for u in users.users:
click.echo(f"Display name: {u.display_name}")
click.echo(f"Media count: {u.media_count}")
click.echo(f"Media length: {u.media_length_mb()}MB")
click.echo(f"User ID: {u.user_id}")
click.echo("=" * 40)
cli.add_command(room)
cli.add_command(user)

View file

@ -0,0 +1,136 @@
from typing import Optional
import click
from synclean.api.rooms import RoomAPI
from synclean.api.synapse import SynapseApiClient
from synclean.models.enums import Direction, RoomOrderBy
from synclean.models.pagination import RoomPaginationParams
from synclean.service.room_service import RoomService
pass_api = click.make_pass_decorator(SynapseApiClient)
room = click.Group(name="room", help="Room commands.")
@room.command("ls")
@click.option("--limit", "-l", default=10, help="Number of rooms to display per page.")
@click.option("--offset", "-o", default=0, help="Number of the room to start from.")
@click.option("--search", "-s", help="Search term to filter rooms by.")
@click.option("--order-by", "-O",
type=click.Choice(["name", "joined_members", "canonical_alias", "creator", "version",]),
default="name", help="Field to order result by.")
@click.option("--direction", "-d",
type=click.Choice(["f", "b"]),
default="b", help="Direction to order result by. (f=forward, b=backward)")
@pass_api
def room_ls(
api: SynapseApiClient,
limit: int,
offset: int,
search: Optional[str],
order_by: str,
direction: str
):
rooms_api = RoomAPI(api)
room_service = RoomService(rooms_api)
while True:
rooms_list = room_service.get_room_list(limit, offset, search, order_by, direction)
if rooms_list:
for i, r in enumerate(rooms_list):
click.echo(f"Room {i + 1}")
click.echo(f"Name: {r.name}")
click.echo(f"ID: {r.room_id}")
click.echo(f"Joined Members: {r.joined_members}")
click.echo("=" * 50)
try:
choice = click.prompt("Enter room number to view details (or 'n' for next page, 'q' to quit", type=str)
if choice.lower() == 'q':
break
elif choice.lower() == 'n':
offset += limit
continue
else:
room_num = int(choice)
if 1 <= room_num <= len(rooms_list):
selected_room = rooms_list[room_num - 1]
room_service.get_room_details(selected_room.room_id)
break
else:
click.echo("Invalid room number. Try again.")
continue
except ValueError:
click.echo("Invalid input. Please enter a number or 'n' for next page, 'q' to quit.")
continue
else:
click.echo("No rooms found.")
break
@room.command("show")
@click.argument("room_id")
@click.option("--media", is_flag=True, help="List media in the room")
@click.option("--rm-all", is_flag=True, help="Remove all media in the room")
@click.option("--rm", "remove_media_id", help="Remove media by ID")
@click.option("--avatar", is_flag=True, help="Show avatar URI")
@pass_api
def show_room(
api: SynapseApiClient,
room_id: str,
media: bool,
rm_all: bool,
remove_media_id: Optional[str],
avatar: bool
):
if room_id is None:
click.echo("You must specify a room ID.", err=True)
return
if rm_all or remove_media_id:
if not media:
click.echo("You must specify --media to remove media.")
return
room_api = RoomAPI(api)
room_details = room_api.get_room_details(room_id)
if not room_details:
click.echo(f"Error: Room {room_id} not found.", err=True)
return
if avatar:
if not room_details.avatar:
click.echo("Room has no avatar.")
return
click.echo(room_details.avatar)
# TODO: implement adding avatar to blacklist
if rm_all:
if click.confirm("Are you sure you want to remove all media in this room?"):
# TODO: implement removing all media from the room
pass
if remove_media_id:
if click.confirm(f"Are you sure you want to remove media {remove_media_id} from the room?"):
# TODO: implement removing media by ID
pass
if not media:
click.echo(f"Room details: {room_id}")
click.echo("=" * 40)
click.echo(f"Name: {room_details.name}")
click.echo(f"Avatar: {room_details.avatar}")
click.echo(f"ID: {room_details.room_id}")
click.echo(f"Members: {room_details.joined_members} (Local: {room_details.joined_local_members})")
click.echo(f"Creator: {room_details.creator}")
click.echo(f"Encryption: {room_details.encryption}")
click.echo(f"Public: {room_details.public}")
click.echo(f"Guest Access: {room_details.guest_access}")
click.echo(f"History Visibility: {room_details.history_visibility}")
click.echo(f"State Events: {room_details.state_events}")
click.echo(f"Room Type: {room_details.room_type}")
else:
room_media = room_api.get_media_from_room(room_id)
if room_media:
for uri in room_media.all_uris:
click.echo(f"URI: {uri}")

View file

@ -0,0 +1,56 @@
from typing import Optional
import click
from synclean.api.synapse import SynapseApiClient
from synclean.api.users import UserAPI
from synclean.models.enums import UserOrderBy, Direction
from synclean.models.pagination import UserPaginationParams
pass_api = click.make_pass_decorator(SynapseApiClient)
user = click.Group(name="user", help="User commands.")
@user.command("ls")
@click.option("--limit", "-l", default=10, help="Number of users to list.")
@click.option("--offset", "-o", default=0, help="Number of the room to start from.")
@click.option("--search", "-s", help="Search term to filter by.")
@click.option("--order-by", "-O",
type=click.Choice(["user_id", "display_name", "media_length", "media_count"]),
default="media_length", help="Field to order result by.")
@click.option("--direction", "-d",
type=click.Choice(["f", "b"]),
default="b", help="Direction to order result by. (f=forward, b=backward)")
@pass_api
def user_ls(
api: SynapseApiClient,
limit: int,
offset: int,
search: Optional[str],
order_by: str,
direction: str
):
order_by_enum = UserOrderBy(order_by)
direction_enum = Direction(direction)
users_api = UserAPI(api)
while True:
pagination_params = UserPaginationParams(limit, offset, order_by_enum, direction_enum, search)
users = users_api.get_users_list_by_media(pagination_params)
if users:
for u in users.users:
click.echo(f"Display name: {u.display_name}")
click.echo(f"Media count: {u.media_count}")
click.echo(f"Media length: {u.media_length_mb()}MB")
click.echo(f"User ID: {u.user_id}")
click.echo("=" * 40)
else:
click.echo("No users found.")
offset += limit
if not click.confirm("Show more users?", default=True):
break