Пример #1
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Change whether a user is an admin or not.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"users/@{arg.user}:{yaml.get('server', 'api','domain')}/admin",
        api_version="v1",
        method="PUT",
        json={"admin": arg.admin.lower() == "promote"},
    )
    try:
        request(req)
    except InternalResponseError:
        logger.error("The user could not be promoted or demoted.")
        return 1

    return 0
Пример #2
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Add a User to the jitsi instance.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    address = (yaml.get("server", "ssh", "address") if yaml.get(
        "server", "ssh", "address") else
               f"matrix.{yaml.get('server', 'api', 'domain')}")
    with SSH(
            address,
            yaml.get("server", "ssh", "user"),
            yaml.get("server", "ssh", "port"),
    ) as ssh:

        passwd: str = create_user(arg.user)

        cmd: str = ("sudo docker exec matrix-jitsi-prosody prosodyctl "
                    f"--config /config/prosody.cfg.lua register "
                    f'"{arg.user}" {JID_EXT} "{passwd}"')

        ssh.run_cmd(cmd)

        return 0
Пример #3
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Delete a user from the the matrix instance.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"deactivate/@{arg.user}:{yaml.get('server', 'api','domain')}",
        api_version="v1",
        method="POST",
        json={"erase": True},
    )
    try:
        request(req)
    except InternalResponseError:
        logger.error("The user was not deleted.")

    return 0
Пример #4
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Add a User to the synapse instance.

    It runs ``ask_password()`` first. If ``ask_password()`` returns ``None``
    it generates a password with ``gen_password()``. Then it gives the user
    a overview of the username, password and if the new user should be
    generated as admin (if you added the ``--admin`` argument). Next, it asks
    a question, if the entered values are correct with the ``ask_question``
    function.

    If the ``ask_question`` function returns True, it continues. If not, it
    starts from the beginning.

    Depending on the ``--ansible`` switch it runs the ``adduser`` command
    via ansible or the API

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    passwd: str = create_user(arg.user, arg.admin)

    if arg.ansible:
        ansible_run(
            playbook=yaml.get("server", "ansible", "playbook"),
            tags="register-user",
            extra_vars={
                "username": arg.user,
                "password": passwd,
                "admin": "yes" if arg.admin else "no",
            },
        )
        return 0

    req: RequestBuilder = RequestBuilder(
        domain=yaml.get("server", "api", "domain"),
        token=yaml.get("server", "api", "token"),
        path=f"users/@{arg.user}:{yaml.get('server', 'api','domain')}",
        json={
            "password": passwd,
            "admin": arg.admin
        },
        method="PUT",
    )
    try:
        request(req)
    except InternalResponseError:
        logger.error("The User was not added.")

    return 0
Пример #5
0
def handle_purge_status(yaml: YAML, purge_id: str) -> int:
    """Check the status of the purge history request.

    Parameters
    ----------
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.
    purge_id: str
        The purge id from a purge history request.

    Returns
    -------
    response: matrixctl.typehints.JsonDict, optional
        The response as dict, containing the status.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"purge_history_status/{purge_id}",
        method="GET",
        api_version="v1",
        timeout=1200.0,
    )

    while True:

        sleep(1)
        try:
            response: JsonDict = request(req).json()
        except InternalResponseError:
            logger.critical(
                "The purge history request was successful but the status "
                "request failed. You just have to wait a bit."
                "If that happens the next time, please hand in a bug report."
            )
            return 1
        # return response

        if response is not None:
            logger.debug(f"{response=}")
            if response["status"] == "complete":
                print("Done...")
                return 0
            if response["status"] == "failed":
                logger.critical(
                    "The server returned, that the purge approach failed."
                )
                break
            if response["status"] == "active":
                logger.info(
                    "The server is still purging historic message content. "
                    "Please wait..."
                )
                sleep(5)
                continue
        break
    return 0
Пример #6
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Join a user to an room.

    Notes
    -----
    - You can only modify the membership of local users.
    - The the token of server administrator used to authenticate against the
      homeserver must be in the room and must have permission to invite users.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    # sanitize
    arg.room = arg.room.strip()
    arg.user = arg.user.strip()

    if not arg.room[0] in {"!", "#"} or ":" not in arg.room:
        logger.error(
            "Make sure, to use the correct room identifier or alias e.g. "
            "!636q39766251:domain.tld or #myroom:domain.tld")
    if not arg.user.startswith("@"):
        arg.user = f"@{arg.user}"

    if ":" not in arg.user:
        arg.user = f"{arg.user}:{yaml.get('server', 'api','domain')}"

    logger.debug("room = %s", arg.room)
    logger.debug("user = %s", arg.user)

    # request
    request_config: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"join/{arg.room}",
        api_version="v1",
        method="POST",
        json={"user_id": arg.user},
    )
    try:
        request(request_config)
    except InternalResponseError:
        logger.error("Unknown Error. The user was not joined to the room.")

    return 0
Пример #7
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Delete local media.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """

    timestamp = handle_timestamp(arg.timestamp, arg.force)

    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"media/{yaml.get('server', 'api', 'domain')}/delete",
        params={
            "before_ts": timestamp,
            "keep_profiles": arg.no_keep_profiles,
            "size_gt": arg.greater_than,
        },
        api_version="v1",
        method="POST",
        timeout=1200,
    )

    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.error("The user could not be promoted or demote.")
        return 1

    try:
        json_response: JsonDict = response.json()
    except json.decoder.JSONDecodeError as e:
        logger.fatal("The JSON response could not be loaded by MatrixCtl.")
        raise InternalResponseError(f"The response was: {response = }") from e

    try:
        print(json.dumps(json_response, indent=4))
        return 0
    except json.decoder.JSONDecodeError:
        logger.error("Unable to process the response data to JSON.")
        return 1

    return 0
Пример #8
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Delete an empty room from the database.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    body: JsonDict = handle_arguments(arg)

    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"rooms/{arg.room}",
        method="DELETE",
        api_version="v2",
        json=body,
        timeout=1200,
    )

    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.error("Could not delete room.")
        return 1

    try:
        json_response: JsonDict = response.json()
    except json.decoder.JSONDecodeError as e:
        logger.fatal("The JSON response could not be loaded by MatrixCtl.")
        raise InternalResponseError(f"The response was: {response = }") from e

    try:
        json_response = handle_status(yaml, json_response["delete_id"])
    except InternalResponseError as e:
        if e.message:
            logger.fatal(e.message)
        logger.fatal(
            "MatrixCtl was not able to verify the status of the request.")
        return 1

    print(json.dumps(json_response, indent=4))

    return 0
Пример #9
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Upload a file or image to the matrix instance.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    file_path: Path = Path(arg.file).absolute()
    logger.debug(f"upload: {file_path=}")
    mime_types: MimeTypes = MimeTypes()
    file_type: str = str(mime_types.guess_type(file_path.name)[0])
    logger.debug(f"upload: {file_type=}")
    try:
        with file_path.open("rb") as fp:
            file: bytes = fp.read()
    except FileNotFoundError:
        print("No such file found. Please check your filepath.")
        return 1

    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="upload/",
        api_path="_matrix/media",
        method="POST",
        api_version="r0",
        headers={"Content-Type": file_type},
        content=file,
    )
    try:
        response: JsonDict = request(req).json()
    except InternalResponseError:
        logger.error("The file was not uploaded.")
        return 1
    try:
        print("Content URI: ", response["content_uri"])
    except KeyError as e:
        raise InternalResponseError(
            "Upload was successful, but no content_uri was found.",
            response) from e
    return 0
Пример #10
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Purge historic message events from the Database.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    arg.room_id = arg.room_id.strip()

    request_body: dict[str, str | int] = dialog_input(arg)

    logger.debug(f"{request_body = }")

    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"purge_history/{arg.room_id.strip()}",
        method="POST",
        api_version="v1",
        json=request_body,
        timeout=10,
    )

    try:
        response: JsonDict = request(req).json()
    except InternalResponseError as e:
        with suppress(KeyError):
            if e.payload["errcode"] == "M_UNKNOWN":
                logger.critical(e.payload["error"])
                return 1
        logger.critical(
            "Something went wrong with the request. Please check your data "
            "again.")
        return 1

    logger.debug(f"{response=}")
    return handle_purge_status(yaml, response["purge_id"])
Пример #11
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Send a server notice to a matrix instance.

    Notes
    -----
    - It uses the synapse admin API.
    - Note that "server notices" must be enabled in homeserver.yaml before
      this API can be used.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="send_server_notice",
        method="POST",
        api_version="v1",
        json={
            "user_id": (
                f"@{arg.username}:" f"{yaml.get('server', 'api', 'domain')}"
            ),
            "content": {
                "msgtype": "m.text",
                "body": arg.message,
            },
        },
    )

    try:
        request(req)
    except InternalResponseError:
        logger.error("The server notice was not sent.")

    return 0
Пример #12
0
def yaml() -> YAML:
    """Create a fixture for the YAML class."""
    # Setup
    yaml_: YAML = YAML({Path("tests/matrixctl/handlers/configs/config.yaml")})

    # Exercise - None

    # Verify - None

    # Cleanup -None
    return yaml_
Пример #13
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Delete a user is an admin.

    Notes
    -----
    If a user does not exist it still will return ``"admin": false`` or ``No``.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"users/@{arg.user}:{yaml.get('server', 'api','domain')}/admin",
        api_version="v1",
        method="GET",
    )
    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.error("The user could not be checked.")
        return 1

    response_json: JsonDict = response.json()

    if arg.to_json:
        print(json.dumps(response_json, indent=4))
        return 0

    print(human_readable_bool(response_json["admin"]))
    return 0
Пример #14
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Run the maintenance procedure of the ansible playbook.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    if arg.list:
        print_tasks()
        return 0

    todo = []
    for task in (yaml.get("server", "maintenance", "tasks")
                 if not arg.tasks else arg.tasks):

        try:
            todo.append(Task[task.replace("-", "_").upper()])
        except KeyError:  # task is not in enum
            logger.error(f'The task "{task}" is not supported by MatrixCtl. '
                         "Below, you find a list of all available tasks.")
            print_tasks()
            return 1

    ansible_run(
        playbook=yaml.get("server", "ansible", "playbook"),
        tags=f"{','.join([t.value for t in todo])},start",
    )

    return 0
Пример #15
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Print a table of the reported events.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"event_reports/{arg.report_id}",
        api_version="v1",
    )

    try:
        response: JsonDict = request(req).json()
    except InternalResponseError:
        logger.critical("Could not receive the user information")

        return 1

    try:
        print(json.dumps(response, indent=4))
        return 0
    except json.decoder.JSONDecodeError:
        logger.error("Unable to process the response data to JSON.")
        return 1
    return 0
Пример #16
0
def addon(_: Namespace, yaml: YAML) -> int:
    """Get the version of the Synapse instance.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
        (Unused in this function)
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="server_version",
        api_version="v1",
    )
    try:
        response: JsonDict = request(req).json()
    except InternalResponseError:
        logger.critical("Could not get the server sersion.")

        return 1
    logger.debug(f"{response=}")
    try:
        print(f"Server Version: {response['server_version']}")
        print(f"Python Version: {response['python_version']}")
    except KeyError:
        logger.error("MatrixCtl was not able to read the server version.")

    return 0
Пример #17
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Grant a user room admin status.

    By default the server admin (the caller) is granted power, but another
    user can optionally be specified.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"rooms/{arg.room}/make_room_admin",
        api_version="v1",
        method="POST",
    )

    if arg.user is not None:
        req.json = {"user_id": arg.user}

    try:
        request(req)
    except InternalResponseError:
        logger.error("The user could not be promoted or demote.")
        return 1

    return 0
Пример #18
0
def addon(_: Namespace, yaml: YAML) -> int:
    """Start/Restart the OCI containers.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    ansible_run(yaml.get("server", "ansible", "playbook"), tags="start")
    return 0
Пример #19
0
def addon(_: Namespace, yaml: YAML) -> int:
    """Update the synapse playbook with git.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    git: VCS = VCS(yaml.get("server", "synapse", "playbook"))
    git.pull()

    return 0
Пример #20
0
def addon(_: Namespace, yaml: YAML) -> int:
    """Check the deployment with andible.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    logger.debug("check")

    ansible_run(playbook=yaml.get("server", "ansible", "playbook"),
                tags="check")
    return 0
Пример #21
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Deploy the ansible playbook.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    ansible_run(
        playbook=yaml.get("server", "ansible", "playbook"),
        tags="setup-all,start" if arg.start else "setup-all",
    )

    return 0
Пример #22
0
def main() -> int:
    """Use the ``main`` function as entrypoint to run the application.

    Parameters
    ----------
    None

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    addon_module = "matrixctl.addons"
    addon_dir: Path = Path(__file__).resolve().parent / "addons"

    # Setup Addons
    addon_manager.import_addons_from(str(addon_dir), addon_module, "parser")
    parser: argparse.ArgumentParser = addon_manager.setup(setup_parser)
    # parser = setup_parser()

    args: argparse.Namespace = parser.parse_args()

    setup_logging(args.debug)

    logger.debug(f"{args=}")

    yaml: YAML = YAML(None if args.config is None else (args.config, ),
                      args.server)

    try:
        addon_module_import: str = f"{addon_module}.{args.addon}.addon"
    except AttributeError as e:
        if args.debug:
            logger.error(
                "The parser of the addon which has been called did not have "
                'an arg "args.addon". If you did not enter an subcommand, '
                'e.g. "matrixctl -d" you can ignore this error.')
            raise AttributeError(e) from e
        parser.print_help()
        return 1

    logger.debug(f"{addon_module_import =}")
    addon: ModuleType = import_module(addon_module_import)

    if args.debug:
        logger.debug("Disabing help on AttributeError")  # may not be needed
        logger.warning(
            "In debugging mode help is disabled! If you don't use any "
            "attributes, the program will throw a AttributeError like: "
            "\"AttributeError: 'Namespace' object has no attribute 'func\".'"
            " This is perfectly normal and not a bug. If you want the help "
            'in debug mode, use the "--help" attribute.')

        # Both should fail without catching the error
        return int(addon.addon(args, yaml))  # type: ignore

    try:
        return int(addon.addon(args, yaml))  # type: ignore
    except AttributeError:
        parser.print_help()

        return 1
Пример #23
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Print a table/json of the matrix users.

    This function generates and prints a table of users or uses json as
    output format.

    The table can be modified.

    - If you want guests in the table use the ``--with-guests`` switch.
    - If you want deactivated user in the table use the ``--with-deactivated``
      switch.

    Notes
    -----
    - Needs API version 2 (``synapse`` 1.28 or greater) to work.
    - API version 1 is deprecated. If you encounter problems please upgrade
      to the latest ``synapse`` release.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    len_domain = len(yaml.get("server", "api", "domain")) + 1  # 1 for :
    users: list[JsonDict] = []
    next_token: int | None = None
    total: int | None = None

    # ToDo: API bool
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="users",
        api_version="v2",
        method="GET",
        params={
            "guests": "true" if arg.with_guests or arg.all else "false",
            "from": 0,
            "limit": arg.limit if 0 < arg.limit < 100 else 100,
            "deactivated":
            "true" if arg.with_deactivated or arg.all else "false",
        },
        timeout=10,
        concurrent_limit=yaml.get("server", "api", "concurrent_limit"),
    )

    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.critical("Could not get the data do build the user table.")
        return 1
    response_json: JsonDict = response.json()

    users += response_json["users"]

    with suppress(KeyError):  # Done: No more users
        next_token = int(response_json["next_token"])
        total = int(response_json["total"])
        if 0 < arg.limit < total:
            total = arg.limit

    # New group to not suppress KeyError in here
    if next_token is not None and total is not None and total > 100:
        async_responses = request(
            generate_worker_configs(req, next_token, total), )

        for async_response in async_responses:
            users_list = async_response.json()["users"]
            for user in users_list:
                users.append(user)

    if arg.to_json:
        print(json.dumps(users, indent=4))
    else:
        for line in to_table(users, len_domain):
            print(line)
        print(f"Total number of users: {len(users)}")

    return 0
Пример #24
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Print a table/json of the reported events.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    reports: list[JsonDict] = []
    next_token: int | None = None
    total: int | None = None

    # ToDo: API bool
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="event_reports",
        api_version="v1",
        params={
            "from": 0,
            "limit": arg.limit if 0 < arg.limit < 100 else 100,
        },
        concurrent_limit=yaml.get("server", "api", "concurrent_limit"),
    )

    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.critical("Could not get the data do build the user table.")
        return 1
    response_json: JsonDict = response.json()

    reports += response_json["event_reports"]

    with suppress(KeyError):  # Done: No more users
        next_token = int(response_json["next_token"])
        total = int(response_json["total"])
        if 0 < arg.limit < total:
            total = arg.limit

    # New group to not suppress KeyError in here
    if next_token is not None and total is not None and total > 100:
        async_responses = request(
            generate_worker_configs(req, next_token, total),
        )

        for async_response in async_responses:
            reports_list = async_response.json()["event_reports"]
            for report in reports_list:
                reports.append(report)

    if arg.to_json:
        print(json.dumps(reports, indent=4))
    else:
        for line in to_table(reports):
            print(line)

    return 0
Пример #25
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """Generate a table of the matrix rooms.

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    rooms: list[JsonDict] = []
    next_token: int | None = None
    total: int | None = None

    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path="rooms",
        api_version="v1",
        params={"limit": arg.limit if 0 < arg.limit < 100 else 100},
        concurrent_limit=yaml.get("server", "api", "concurrent_limit"),
    )

    if arg.filter:
        req.params["search_term"] = arg.filter

    if arg.reverse:
        req.params["dir"] = "b"

    if arg.order_by_size:
        req.params["order_by"] = "size"

    try:
        response: Response = request(req)
    except InternalResponseError:
        logger.critical("Could not get the user table.")
        return 1
    response_json: JsonDict = response.json()

    rooms += response_json["rooms"]

    with suppress(KeyError):  # Done: No more users
        next_token = int(response_json["next_batch"])
        total = int(response_json["total_rooms"])
        if 0 < arg.limit < total:
            total = arg.limit

    # New group to not suppress KeyError in here
    if next_token is not None and total is not None and total > 100:
        async_responses = request(
            generate_worker_configs(req, next_token, total), )

        for async_response in async_responses:
            users_list = async_response.json()["rooms"]
            for room in users_list:
                rooms.append(room)

    generate_output(
        filter_empty_rooms(rooms) if arg.empty else rooms,
        arg.to_json,
    )

    return 0
Пример #26
0
def addon(arg: Namespace, yaml: YAML) -> int:
    """List information about an registered user.

    It uses the admin API to get a python dictionary with the information.
    The ``generate_user_tables`` function makes the information human readable.

    Examples
    --------
    .. code-block:: console

       $ matrixctl user dwight
       User:
       +----------------------------+--------------------------------------+
       | Name                       | dwight                               |
       | Password Hash              | $2b$12$9DUNderm1ffL1NincPap3RC       |
       |                            | ompaNY1725.slOUghAvEnu5cranT0n       |
       | Guest                      | False                                |
       | Admin                      | True                                 |
       | Consent Version            |                                      |
       | Consent Server Notice Sent |                                      |
       | Appservice Id              |                                      |
       | Creation Ts                | 2020-04-14 13:04:21                  |
       | User Type                  |                                      |
       | Deactivated                | False                                |
       | Displayname                | Dwight Schrute                       |
       | Avatar Url                 | mxc://dunder-mifflin.com/sCr4        |
       |                            | nt0nsr4ng13rW45Cr33d                 |
       +----------------------------+--------------------------------------+

       Threepid:
       +--------------+-----------------------------------+
       | Medium       | email                             |
       | Address      | [email protected] |
       | Validated At | 2020-04-14 15:30:21.123000        |
       | Added At     | 2020-04-14 15:29:19.100000        |
       +--------------+-----------------------------------+

    If the user does not exist, the return looks like:

    Parameters
    ----------
    arg : argparse.Namespace
        The ``Namespace`` object of argparse's ``parse_args()``.
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.

    Returns
    -------
    err_code : int
        Non-zero value indicates error code, or zero on success.

    """
    len_domain = len(yaml.get("server", "api", "domain")) + 1
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f'users/@{arg.user}:{yaml.get("server", "api","domain")}',
    )

    try:
        user_dict: JsonDict = request(req).json()
    except InternalResponseError:
        logger.critical("Could not receive the user information")

        return 1

    if arg.to_json:
        print(json.dumps(user_dict, indent=4))
    else:
        for line in to_table(user_dict, len_domain):
            print(line)

    return 0
Пример #27
0
def handle_status(yaml: YAML, delete_id: str) -> JsonDict:  # noqa: C901
    """Handle the status of a delete room request.

    Parameters
    ----------
    yaml : matrixctl.handlers.yaml.YAML
        The configuration file handler.
    delete_id: str
        The delete id of a delete room request.

    Returns
    -------
    response: matrixctl.typehints.JsonDict, optional
        The response as dict, containing the status.

    """
    req: RequestBuilder = RequestBuilder(
        token=yaml.get("server", "api", "token"),
        domain=yaml.get("server", "api", "domain"),
        path=f"rooms/delete_status/{delete_id}",
        method="GET",
        api_version="v2",
        timeout=1200.0,
    )

    # Lock messages to only print them once
    msglock_shutting_down: bool = False
    msglock_purging: bool = False

    while True:

        sleep(1)
        try:
            response: Response = request(req)
        except InternalResponseError as e:
            raise InternalResponseError(
                "The delete room request was probably successful but the"
                " status request failed. You just have to wait a bit.") from e

        try:
            json_response: JsonDict = response.json()
        except json.decoder.JSONDecodeError as e:
            logger.fatal(
                "The JSON status response could not be loaded by MatrixCtl.")
            raise InternalResponseError(
                f"The response was: {response = }") from e

        if response is not None:
            logger.debug(f"{response=}")
            # complete
            if json_response["status"] == "complete":
                print(
                    "Status: Complete (the room has been deleted successfully")
                break
            # shutting_down
            if json_response["status"] == "shutting_down":
                if not msglock_shutting_down:
                    print(
                        "Status: Shutting Down (removing users from the room)")
                msglock_shutting_down = True
                logger.info("The server is still shutting_down the room. "
                            "Please wait...")
                sleep(5)
                continue
            # purging
            if json_response["status"] == "purging":
                if not msglock_purging:
                    print(
                        "Status: Purging (purging the room and event data from"
                        " database)")
                msglock_purging = True
                logger.info(
                    "The server is still purging the room. Please wait...")
                sleep(5)
                continue
            # failed
            if json_response["status"] == "failed":
                logger.critical(
                    "The server returned, that the approach failed with the"
                    f" following message: {json_response['status']}.")
                break
        break

    return json_response