class AsyncClient(BaseClient):
    def __init__(self, options):
        super().__init__(options)
        self.client = httpx.AsyncClient(
            http2=options.get("http2", False),
            proxies=self._proxies,
            verify=options.get("verify", True),
        )

    async def __aenter__(self):
        await self.client.__aenter__()
        return self

    async def __aexit__(self, *exc_info):
        return await self.client.__aexit__(*exc_info)

    async def make_request(self, method, endpoint, options=None, params=None, data=None, files=None, basepath=None):
        request, url, request_params = self._build_request(method, options, params, data, files, basepath)
        response = await request(url + endpoint, **request_params)

        self._check_response(response)
        return response

    async def get(self, endpoint, options=None, params=None):
        response = await self.make_request("get", endpoint, options=options, params=params)

        if response.headers["Content-Type"] != "application/json":
            log.debug("Response is not application/json, returning raw response")
            return response

        try:
            return response.json()
        except ValueError:
            log.debug("Could not convert response to json, returning raw response")
            return response

    async def post(self, endpoint, options=None, params=None, data=None, files=None):
        response = await self.make_request("post", endpoint, options=options, params=params, data=data, files=files)
        return response.json()

    async def put(self, endpoint, options=None, params=None, data=None):
        response = await self.make_request("put", endpoint, options=options, params=params, data=data)
        return response.json()

    async def delete(self, endpoint, options=None, params=None, data=None):
        response = await self.make_request("delete", endpoint, options=options, params=params, data=data)
        return response.json() class Client(BaseClient):
    def __init__(self, options):
        super().__init__(options)
        self.client = httpx.Client(
            http2=options.get("http2", False),
            proxies=self._proxies,
            verify=options.get("verify", True),
        )

    def make_request(self, method, endpoint, options=None, params=None, data=None, files=None, basepath=None):
        request, url, request_params = self._build_request(method, options, params, data, files, basepath)
        response = request(url + endpoint, **request_params)

        self._check_response(response)
        return response

    def __enter__(self):
        self.client.__enter__()
        return self

    def __exit__(self, *exc_info):
        return self.client.__exit__(*exc_info)

    def get(self, endpoint, options=None, params=None):
        response = self.make_request("get", endpoint, options=options, params=params)

        if response.headers["Content-Type"] != "application/json":
            log.debug("Response is not application/json, returning raw response")
            return response

        try:
            return response.json()
        except ValueError:
            log.debug("Could not convert response to json, returning raw response")
            return response

    def post(self, endpoint, options=None, params=None, data=None, files=None):
        return self.make_request("post", endpoint, options=options, params=params, data=data, files=files).json()

    def put(self, endpoint, options=None, params=None, data=None):
        return self.make_request("put", endpoint, options=options, params=params, data=data).json()

    def delete(self, endpoint, options=None, params=None, data=None):
        return self.make_request("delete", endpoint, options=options, params=params, data=data).json() class Websocket:
    def __init__(self, options, token):
        self.options = options
        if options["debug"]:
            log.setLevel(logging.DEBUG)
        self._token = token
        self._alive = False
        self._last_msg = 0

    async def connect(self, event_handler):
        """
        Connect to the websocket and authenticate it.
        When the authentication has finished, start the loop listening for messages,
        sending a ping to the server to keep the connection alive.

        :param event_handler: Every websocket event will be passed there. Takes one argument.
        :type event_handler: Function(message)
        :return:
        """
        context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
        if not self.options["verify"]:
            context.verify_mode = ssl.CERT_NONE

        scheme = "wss://"
        if self.options["scheme"] != "https":
            scheme = "ws://"
            context = None

        url = "{scheme:s}{url:s}:{port:s}{basepath:s}/websocket".format(
            scheme=scheme, url=self.options["url"], port=str(self.options["port"]), basepath=self.options["basepath"]
        )

        self._alive = True

        while True:
            try:
                kw_args = {}
                if self.options["websocket_kw_args"] is not None:
                    kw_args = self.options["websocket_kw_args"]
                async with aiohttp.ClientSession() as session:
                    async with session.ws_connect(
                        url,
                        ssl=context,
                        proxy=self.options["proxy"],
                        **kw_args,
                    ) as websocket:
                        await self._authenticate_websocket(websocket, event_handler)
                        while self._alive:
                            try:
                                await self._start_loop(websocket, event_handler)
                            except aiohttp.ClientError:
                                break
                        if (not self.options["keepalive"]) or (not self._alive):
                            break
            except Exception as e:
                log.exception(f"Failed to establish websocket connection: {type(e)} thrown")
                await asyncio.sleep(self.options["keepalive_delay"])

    async def _start_loop(self, websocket, event_handler):
        """
        We will listen for websockets events, sending a heartbeats on a timer.
        If we don't the webserver would close the idle connection,
        forcing us to reconnect.
        """
        log.debug("Starting websocket loop")
        # TODO: move to create_task when cpython 3.7 is minimum supported python version
        keep_alive = asyncio.ensure_future(self._do_heartbeats(websocket))
        log.debug("Waiting for messages on websocket")
        while self._alive:
            message = await websocket.receive_str()
            self._last_msg = time.time()
            await event_handler(message)
        log.debug("cancelling heartbeat task")
        keep_alive.cancel()
        try:
            await keep_alive
        except asyncio.CancelledError:
            pass

    async def _do_heartbeats(self, websocket):
        """
        This is a little complicated, but we only need to pong the websocket if
        we haven't recieved a message inside the timeout window.

        Since messages can be received, while we are waiting we need to check
        after sleep.
        """
        timeout = self.options["timeout"]
        while True:
            since_last_msg = time.time() - self._last_msg
            next_timeout = timeout - since_last_msg if since_last_msg <= timeout else timeout
            await asyncio.sleep(next_timeout)
            if time.time() - self._last_msg >= timeout:
                log.debug("sending heartbeat...")
                await websocket.pong()
                self._last_msg = time.time()

    def disconnect(self):
        """Sets `self._alive` to False so the loop in `self._start_loop` will finish."""
        log.info("Disconnecting websocket")
        self._alive = False

    async def _authenticate_websocket(self, websocket, event_handler):
        """
        Sends a authentication challenge over a websocket.
        This is not needed when we just send the cookie we got on login
        when connecting to the websocket.
        """
        log.debug("Authenticating websocket")
        json_data = json.dumps({"seq": 1, "action": "authentication_challenge", "data": {"token": self._token}})
        await websocket.send_str(json_data)
        while True:
            message = await websocket.receive_str()
            status = json.loads(message)
            log.debug(status)
            # We want to pass the events to the event_handler already
            # because the hello event could arrive before the authentication ok response
            await event_handler(message)
            if ("event" in status and status["event"] == "hello") and ("seq" in status and status["seq"] == 0):
                log.info("Websocket authentification OK")
                return True
            log.error("Websocket authentification failed") class Brand(Base):
    endpoint = "/brand"

    def get_brand_image(self):
        return self.client.get(self.endpoint + "/image")

    def upload_brand_image(self, files):
        return self.client.post(self.endpoint + "/image", files=files) class Channels(Base):
    endpoint = "/channels"

    def create_channel(self, options):
        return self.client.post(self.endpoint, options=options)

    def create_direct_message_channel(self, options):
        return self.client.post(self.endpoint + "/direct", options=options)

    def create_group_message_channel(self, options):
        return self.client.post(self.endpoint + "/group", options=options)

    def get_list_of_channels_by_ids(self, team_id, options=None):
        return self.client.post(Teams.endpoint + "/" + team_id + "/channels/ids", options=options)

    def get_channel(self, channel_id):
        return self.client.get(self.endpoint + "/" + channel_id)

    def update_channel(self, channel_id, options):
        return self.client.put(self.endpoint + "/" + channel_id, options=options)

    def delete_channel(self, channel_id):
        return self.client.delete(self.endpoint + "/" + channel_id)

    def patch_channel(self, channel_id, options):
        return self.client.put(self.endpoint + "/" + channel_id + "/patch", options=options)

    def restore_channel(self, channel_id):
        return self.client.post(
            self.endpoint + "/" + channel_id + "/restore",
        )

    def get_channel_statistics(self, channel_id):
        return self.client.get(
            self.endpoint + "/" + channel_id + "/stats",
        )

    def get_channel_pinned_posts(self, channel_id):
        return self.client.get(self.endpoint + "/" + channel_id + "/pinned")

    def get_channel_by_name(self, team_id, channel_name):
        return self.client.get(Teams.endpoint + "/" + team_id + "/channels/name/" + channel_name)

    def get_channel_by_name_and_team_name(self, team_name, channel_name):
        return self.client.get(Teams.endpoint + "/name/" + team_name + "/channels/name/" + channel_name)

    def get_channel_members(self, channel_id, params=None):
        return self.client.get(self.endpoint + "/" + channel_id + "/members", params=params)

    def add_user(self, channel_id, options=None):
        return self.client.post(self.endpoint + "/" + channel_id + "/members", options=options)

    def get_channel_members_by_ids(self, channel_id, options=None):
        return self.client.post(self.endpoint + "/" + channel_id + "/members/ids", options=options)

    def get_channel_member(self, channel_id, user_id):
        return self.client.get(self.endpoint + "/" + channel_id + "/members/" + user_id)

    def remove_channel_member(self, channel_id, user_id):
        return self.client.delete(self.endpoint + "/" + channel_id + "/members/" + user_id)

    def update_channel_roles(self, channel_id, user_id, options):
        return self.client.put(self.endpoint + "/" + channel_id + "/members/" + user_id + "/roles", options=options)

    def update_channel_notifications(self, channel_id, user_id, options=None):
        return self.client.put(
            self.endpoint + "/" + channel_id + "/members/" + user_id + "/notify_props", options=options
        )

    def view_channel(self, user_id, options):
        return self.client.post(self.endpoint + "/members/" + user_id + "/view", options=options)

    def get_channel_members_for_user(self, user_id, team_id):
        return self.client.get(Users.endpoint + "/" + user_id + "/teams/" + team_id + "/channels/members")

    def get_channels_for_user(self, user_id, team_id):
        return self.client.get(Users.endpoint + "/" + user_id + "/teams/" + team_id + "/channels")

    def get_channel_for_user(self, user_id, team_id):
        log.warning(
            "Call to deprecated function get_channel_for_user, "
            "which will be removed in the next major version."
            "Use get_channels_for_user instead."
        )
        return self.get_channels_for_user(user_id, team_id)

    def get_unread_messages(self, user_id, channel_id):
        return self.client.get(Users.endpoint + "/" + user_id + "/channels/" + channel_id + "/unread")

    def get_public_channels(self, team_id, params=None):
        return self.client.get("/teams/" + team_id + "/channels", params=params)

    def get_deleted_channels(self, team_id, params=None):
        return self.client.get("/teams/" + team_id + "/channels/deleted", params=params)

    def search_channels(self, team_id, options=None):
        return self.client.post("/teams/" + team_id + "/channels/search", options=options)

    def autocomplete_channels(self, team_id, params=None):
        return self.client.get("/teams/" + team_id + "/channels/autocomplete", params=params)

    def update_scheme_derived_roles_of_channel_member(self, channel_id, user_id, options=None):
        return self.client.put(
            self.endpoint + "/" + channel_id + "/members/" + user_id + "/schemeRoles", options=options
        )

    def set_channel_scheme(self, channel_id):
        return self.client.put(self.endpoint + "/" + channel_id + "/scheme")

    def convert_channel(self, channel_id):
        return self.client.post(self.endpoint + "/" + channel_id + "/convert") class Cluster(Base):
    endpoint = "/cluster"

    def get_cluster_status(self):
        return self.client.get(self.endpoint + "/status") class Commands(Base):
    endpoint = "/commands"

    def create_command(self, options=None):
        return self.client.post(self.endpoint, options=options)

    def list_commands_for_team(self, params=None):
        return self.client.get(self.endpoint, params=params)

    def list_autocomplete_commands(self, team_id):
        return self.client.get(Teams.endpoint + team_id + "/commands/autocomplete")

    def update_command(self, command_id, options=None):
        return self.client.put(self.endpoint + command_id, options=options)

    def delete_command(self, command_id):
        return self.client.delete(self.endpoint + command_id)

    def generate_new_token(self, command_id):
        return self.client.put(self.endpoint + command_id + "/regen_token")

    def execute_command(self, options=None):
        return self.client.post(self.endpoint + "/execute", options=options) class Compliance(Base):
    endpoint = "/compliance"

    def create_report(self, params):
        return self.client.post(self.endpoint + "/reports", params=params)

    def get_reports(self, params=None):
        return self.client.get(self.endpoint + "/reports", params=params)

    def get_report(self, report_id):
        return self.client.get(self.endpoint + "/reports/" + report_id)

    def download_report(self, report_id):
        return self.client.get(self.endpoint + "/reports/" + report_id + "/download") class Files(Base):
    endpoint = "/files"

    def upload_file(self, channel_id, files):
        return self.client.post(self.endpoint, data={"channel_id": channel_id}, files=files)

    def get_file(self, file_id):
        return self.client.get(
            self.endpoint + "/" + file_id,
        )

    def get_file_thumbnail(self, file_id):
        return self.client.get(
            self.endpoint + "/" + file_id + "/thumbnail",
        )

    def get_file_preview(self, file_id):
        return self.client.get(
            self.endpoint + "/" + file_id + "/preview",
        )

    def get_public_file_link(self, file_id):
        return self.client.get(
            self.endpoint + "/" + file_id + "/link",
        )

    def get_file_metadata(self, file_id):
        return self.client.get(
            self.endpoint + "/" + file_id + "/info",
        ) class LDAP(Base):
    endpoint = "/ldap"

    def sync_ldap(self):
        return self.client.post(self.endpoint + "/sync")

    def test_ldap_config(self):
        return self.client.post(self.endpoint + "/test") class OAuth(Base):
    endpoint = "/oauth"

    def register_oauth_app(self, options):
        return self.client.post(self.endpoint + "/apps", options=options)

    def get_oauth_apps(self, params=None):
        return self.client.get(self.endpoint + "/apps", params=params)

    def get_oauth_app(self, app_id):
        return self.client.get(self.endpoint + "/apps/" + app_id)

    def delete_oauth_app(self, app_id):
        return self.client.delete(self.endpoint + "/apps/" + app_id)

    def regenerate_oauth_app_secret(self, app_id):
        return self.client.post(self.endpoint + "/apps/" + app_id + "/regen_secret")

    def get_info_on_oauth_app(self, app_id):
        return self.client.get(self.endpoint + "/apps/" + app_id + "/info")

    def get_authorized_oauth_apps(self, user_id, params=None):
        return self.client.get(Users.endpoint + user_id + "/oauth/apps/authorized", params=params) class Posts(Base):
    endpoint = "/posts"

    def create_post(self, options):
        return self.client.post(self.endpoint, options=options)

    def create_ephemeral_post(self, options):
        return self.client.post(self.endpoint + "/ephemeral", options=options)

    def get_post(self, post_id):
        return self.client.get(
            self.endpoint + "/" + post_id,
        )

    def delete_post(self, post_id):
        return self.client.delete(
            self.endpoint + "/" + post_id,
        )

    def update_post(self, post_id, options=None):
        return self.client.put(self.endpoint + "/" + post_id, options=options)

    def patch_post(self, post_id, options=None):
        return self.client.put(self.endpoint + "/" + post_id + "/patch", options=options)

    def get_thread(self, post_id):
        return self.client.get(
            self.endpoint + "/" + post_id + "/thread",
        )

    def get_list_of_flagged_posts(self, user_id, params=None):
        return self.client.get(Users.endpoint + "/" + user_id + "/posts/flagged", params=params)

    def get_file_info_for_post(self, post_id):
        return self.client.get(
            self.endpoint + "/" + post_id + "/files/info",
        )

    def get_posts_for_channel(self, channel_id, params=None):
        return self.client.get(Channels.endpoint + "/" + channel_id + "/posts", params=params)

    def search_for_team_posts(self, team_id, options):
        return self.client.post(Teams.endpoint + "/" + team_id + "/posts/search", options=options)

    def pin_post_to_channel(self, post_id):
        return self.client.post(self.endpoint + "/" + post_id + "/pin")

    def unpin_post_to_channel(self, post_id):
        return self.client.post(self.endpoint + "/" + post_id + "/unpin")

    def perform_post_action(self, post_id, action_id):
        return self.client.post(self.endpoint + "/" + post_id + "/actions/" + action_id)

    def get_unread_posts_for_channel(self, user_id, channel_id, params=None):
        return self.client.get(
            Users.endpoint + "/" + user_id + "/channels/" + channel_id + "/posts/unread", params=params
        ) class Preferences(Base):
    """
    This is the endpoint for Preferences.
    It is special in a way, that the endpoint is /user and not /preferences,
    like one might expect at first!
    """

    endpoint = Users.endpoint

    def get_user_preferences(self, user_id):
        return self.client.get(self.endpoint + "/" + user_id + "/preferences")

    def save_user_preferences(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/preferences", options=options)

    def delete_user_preferences(self, user_id, options=None):
        return self.client.post(self.endpoint + "/" + user_id + "/preferences/delete", options=options)

    def list_user_preferences_by_category(self, user_id, category):
        return self.client.get(self.endpoint + "/" + user_id + "/preferences/" + category)

    def get_specific_user_preference(self, user_id, category, preference_name):
        return self.client.get(self.endpoint + "/" + user_id + "/preferences/" + category + "/name/" + preference_name) class Reactions(Base):
    endpoint = "/reactions"

    def create_reaction(self, options=None):
        return self.client.post(self.endpoint, options=options)

    def get_reactions_of_post(self, post_id):
        return self.client.get(
            Posts.endpoint + "/" + post_id + "/" + self.endpoint,
        )

    def delete_reaction(self, user_id, post_id, emoji_name, params=None):
        return self.client.delete(
            Users.endpoint + "/" + user_id + "/posts/" + post_id + "/reactions/" + emoji_name, params=params
        ) class SAML(Base):
    endpoint = "/saml"

    def get_metadata(self):
        return self.client.get(self.endpoint + "/metadata")

    def upload_idp_certificate(self, files):
        return self.client.post(self.endpoint + "/certificate/idp", files=files)

    def remove_idp_certificate(self):
        return self.client.delete(self.endpoint + "/certificate/idp")

    def upload_public_certificate(self, files):
        return self.client.post(self.endpoint + "/certificate/public", files=files)

    def remove_public_certificate(self):
        return self.client.delete(self.endpoint + "/certificate/public")

    def upload_private_key(self, files):
        return self.client.post(self.endpoint + "/certificate/private", files=files)

    def remove_private_key(self):
        return self.client.delete(self.endpoint + "/certificate/private")

    def get_certificate_status(self):
        return self.client.get(self.endpoint + "/certificate/status") class System(Base):
    """
    This endpoint has a mix of different
    endpoints, not only /system
    """

    def check_system_health(self):
        return self.client.get("/system/ping")

    def recycle_database_connection(self):
        return self.client.post("/database/recycle")

    def send_test_email(self, options=None):
        return self.client.post("/email/test", options=options)

    def get_configuration(self):
        return self.client.get("/config")

    def update_configuration(self, options):
        return self.client.put("/config", options=options)

    def reload_configuration(self):
        return self.client.post("/config/reload")

    def get_client_configuration(self, params):
        return self.client.get("/config/client", params=params)

    def upload_license_file(self, files):
        return self.client.post("/license", files=files)

    def remove_license_file(self):
        return self.client.delete("/license")

    def get_client_license(self, params):
        return self.client.get("/license/client", params=params)

    def get_audits(self, params):
        return self.client.get("/audits", params=params)

    def invalidate_all_caches(self):
        return self.client.post(
            "/caches/invalidate",
        )

    def get_logs(self, params):
        return self.client.get("/logs", params=params)

    def add_log_message(self, options):
        return self.client.post("/logs", options=options)

    def get_webrtc_token(self):
        return self.client.get("/webrtc/token")

    def get_analytics(self, params):
        return self.client.get("/analytics/old", params=params)

    def get_configuration_environment(self):
        return self.client.get("/config/environment")

    def test_aws_s3_connection(self, options=None):
        return self.client.post("/file/s3_test", options=options) class Teams(Base):
    endpoint = "/teams"

    def create_team(self, options=None):
        return self.client.post(self.endpoint, options)

    def get_teams(self, params=None):
        return self.client.get(self.endpoint, params=params)

    def get_team(self, team_id):
        return self.client.get(
            self.endpoint + "/" + team_id,
        )

    def update_team(self, team_id, options=None):
        return self.client.put(self.endpoint + "/" + team_id, options)

    def delete_team(self, team_id, params=None):
        return self.client.delete(self.endpoint + "/" + team_id, params=params)

    def patch_team(self, team_id, options=None):
        return self.client.put(self.endpoint + "/" + team_id + "/patch", options)

    def get_team_by_name(self, name):
        return self.client.get(self.endpoint + "/name/" + name)

    def search_teams(self, options=None):
        return self.client.post(self.endpoint + "/search", options)

    def check_team_exists(self, name):
        return self.client.get(self.endpoint + "/name/" + name + "/exists")

    def get_user_teams(self, user_id):
        return self.client.get(Users.endpoint + "/" + user_id + "/teams")

    def get_team_members(self, team_id, params=None):
        return self.client.get(self.endpoint + "/" + team_id + "/members", params=params)

    def add_user_to_team(self, team_id, options=None):
        return self.client.post(self.endpoint + "/" + team_id + "/members", options=options)

    def add_user_to_team_from_invite(self, params=None):
        return self.client.post(self.endpoint + "/members/invite", params=params)

    def add_multiple_users_to_team(self, team_id, options=None):
        return self.client.post(self.endpoint + "/" + team_id + "/members/batch", options=options)

    def get_team_members_for_user(self, user_id):
        return self.client.get(Users.endpoint + "/" + user_id + "/teams/members")

    def get_team_member(self, team_id, user_id):
        return self.client.get(self.endpoint + "/" + team_id + "/members/" + user_id)

    def remove_user_from_team(self, team_id, user_id):
        return self.client.delete(self.endpoint + "/" + team_id + "/members/" + user_id)

    def get_team_members_by_id(self, team_id, options=None):
        return self.client.post(self.endpoint + "/" + team_id + "/members/ids", options)

    def get_team_stats(self, team_id):
        return self.client.get(self.endpoint + "/" + team_id + "/stats")

    def update_team_member_roles(self, team_id, user_id, options=None):
        return self.client.put(self.endpoint + "/" + team_id + "/members/" + user_id + "/roles", options)

    def get_team_unreads_for_user(self, user_id, params=None):
        return self.client.get(Users.endpoint + "/" + user_id + "/teams/unread", params=params)

    def get_unreads_for_team(self, user_id, team_id):
        return self.client.get(
            Users.endpoint + "/" + user_id + "/teams/" + team_id + "/unread",
        )

    def invite_users_to_team_by_mail(self, team_id, options=None):
        return self.client.post(self.endpoint + "/" + team_id + "/invite/email", options)

    def import_team_from_other_app(self, team_id, data=None):
        return self.client.post(self.endpoint + "/" + team_id + "/import", data=data)

    def get_invite_info_for_team(self, invite_id):
        return self.client.get(
            self.endpoint + "/invite/" + invite_id,
        )

    def get_public_channels(self, team_id, params=None):
        warnings.warn(
            "Using deprecated endpoint Teams.get_public_channels(). " + "Use Channels.get_public_channels() instead.",
            DeprecationWarning,
        )
        return self.client.get(self.endpoint + "/" + team_id + "/channels", params=params)

    def get_deleted_channels(self, team_id, params=None):
        warnings.warn(
            "Using deprecated endpoint Teams.get_deleted_channels(). " + "Use Channels.get_deleted_channels() instead.",
            DeprecationWarning,
        )
        return self.client.get(self.endpoint + "/" + team_id + "/channels/deleted", params=params)

    def search_channels(self, team_id, options=None):
        warnings.warn(
            "Using deprecated endpoint Teams.search_channels(). Use Channels.search_channels() instead.",
            DeprecationWarning,
        )
        return self.client.post(self.endpoint + "/" + team_id + "/channels/search", options=options)

    def get_team_icon(self, team_id):
        return self.client.get(self.endpoint + "/" + team_id + "/image")

    def set_team_icon(self, team_id, file):
        return self.client.post(self.endpoint + "/" + team_id + "/image", files=file)

    def update_scheme_derived_roles_of_team_member(self, team_id, user_id, options=None):
        return self.client.put(self.endpoint + "/" + team_id + "/members/" + user_id + "/schemeRoles", options=options)

    def delete_team_icon(self, team_id):
        self.client.delete(self.endpoint + "/" + team_id + "/image")

    def set_team_scheme(self, team_id):
        return self.client.put(self.endpoint + "/" + team_id + "/scheme") class Users(Base):
    endpoint = "/users"

    def login_user(self, options):
        return self.client.make_request("post", self.endpoint + "/login", options)

    def logout_user(self):
        return self.client.post(self.endpoint + "/logout")

    def create_user(self, options=None, params=None):
        return self.client.post(self.endpoint, options=options, params=params)

    def get_users(self, params=None):
        return self.client.get(self.endpoint, params=params)

    def get_users_by_ids(self, options=None):
        return self.client.post(self.endpoint + "/ids", options)

    def get_users_by_usernames(self, options=None):
        return self.client.post(self.endpoint + "/usernames", options)

    def search_users(self, options=None):
        return self.client.post(self.endpoint + "/search", options)

    def autocomplete_users(self, params=None):
        return self.client.get(self.endpoint + "/autocomplete", params=params)

    def get_user(self, user_id):
        return self.client.get(self.endpoint + "/" + user_id)

    def update_user(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id, options)

    def deactivate_user(self, user_id):
        return self.client.delete(self.endpoint + "/" + user_id)

    def patch_user(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/patch", options)

    def update_user_role(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/roles", options)

    def update_user_active_status(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/active", options)

    def get_user_profile_image(self, user_id):
        return self.client.get(self.endpoint + "/" + user_id + "/image")

    def set_user_profile_image(self, user_id, files):
        return self.client.post(self.endpoint + "/" + user_id + "/image", files=files)

    def get_user_by_username(self, username):
        return self.client.get(self.endpoint + "/username/" + username)

    def reset_password(self, options=None):
        return self.client.post(self.endpoint + "/password/reset", options)

    def update_user_mfa(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/mfa", options)

    def generate_mfa(self, user_id):
        return self.client.post(self.endpoint + "/" + user_id + "/mfa/generate")

    def check_mfa(self, options=None):
        return self.client.post(self.endpoint + "/mfa", options)

    def update_user_password(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/password", options)

    def send_password_reset_mail(self, options=None):
        return self.client.post(self.endpoint + "/password/reset/send", options)

    def get_user_by_email(self, email):
        return self.client.get(self.endpoint + "/email/" + email)

    def get_user_sessions(self, user_id):
        return self.client.get(self.endpoint + "/" + user_id + "/sessions")

    def revoke_user_session(self, user_id, options=None):
        return self.client.post(self.endpoint + "/" + user_id + "/sessions/revoke", options)

    def revoke_all_user_sessions(self, user_id):
        return self.client.post(
            self.endpoint + "/" + user_id + "/sessions/revoke/all",
        )

    def attach_mobile_device(self, options=None):
        return self.client.put(self.endpoint + "/sessions/device", options)

    def get_user_audits(self, user_id):
        return self.client.get(self.endpoint + "/" + user_id + "/audits")

    def verify_user_email(self, options=None):
        return self.client.post(self.endpoint + "/email/verify", options)

    def send_verification_mail(self, options=None):
        return self.client.post(self.endpoint + "/email/verify/send", options)

    def switch_login_method(self, options=None):
        return self.client.post(self.endpoint + "/login/switch", options)

    def disable_personal_access_token(self, options=None):
        return self.client.post(self.endpoint + "/tokens/disable", options)

    def enable_personal_access_token(self, options=None):
        return self.client.post(self.endpoint + "/tokens/enable", options)

    def get_user_access_token(self, token_id):
        return self.client.get(self.endpoint + "/tokens/" + token_id)

    def search_tokens(self, options=None):
        return self.client.post(self.endpoint + "/tokens/search", options=options)

    def update_user_authentication_method(self, user_id, options=None):
        return self.client.put(self.endpoint + "/" + user_id + "/auth", options=options)

    def create_user_access_token(self, user_id, options=None):
        return self.client.post(self.endpoint + "/" + user_id + "/tokens", options=options)

    def get_stats(self):
        return self.client.get(self.endpoint + "/stats") class Webhooks(Base):
    endpoint = "/hooks"

    def create_incoming_hook(self, options):
        return self.client.post(self.endpoint + "/incoming", options=options)

    def list_incoming_hooks(self, params):
        return self.client.get(self.endpoint + "/incoming", params=params)

    def get_incoming_hook(self, hook_id):
        return self.client.get(self.endpoint + "/incoming/" + hook_id)

    def update_incoming_hook(self, hook_id, options):
        return self.client.put(self.endpoint + "/incoming/" + hook_id, options=options)

    def create_outgoing_hook(self, options):
        return self.client.post(self.endpoint + "/outgoing", options=options)

    def list_outgoing_hooks(self, params):
        return self.client.get(self.endpoint + "/outgoing", params=params)

    def get_outgoing_hook(self, hook_id):
        return self.client.get(self.endpoint + "/outgoing/" + hook_id)

    def delete_outgoing_hook(self, hook_id):
        return self.client.delete(self.endpoint + "/outgoing/" + hook_id)

    def update_outgoing_hook(self, hook_id, options):
        return self.client.put(self.endpoint + "/outgoing/" + hook_id, options=options)

    def regenerate_token_outgoing_hook(self, hook_id):
        return self.client.put(self.endpoint + "/outgoing/" + hook_id + "/regen_token")

    def call_webhook(self, hook_id, options=None):
        return self.client.make_request("post", "/" + hook_id, options=options, basepath="/hooks") class Elasticsearch(Base):
    endpoint = "/elasticsearch"

    def test_elasticsearch_configuration(self):
        return self.client.post(self.endpoint + "/test")

    def purge_all_elasticsearch_indexes(self):
        return self.client.post(self.endpoint + "/purge_indexes") class Emoji(Base):
    endpoint = "/emoji"

    def create_custom_emoji(self, emoji_name, files):
        emoji = {"name": emoji_name, "creator_id": self.client.userid}
        return self.client.post(self.endpoint, data={"emoji": json.dumps(emoji)}, files=files)

    def get_emoji_list(self, params=None):
        return self.client.get(self.endpoint, params=params)

    def get_custom_emoji(self, emoji_id):
        return self.client.get(self.endpoint + "/" + emoji_id)

    def delete_custom_emoji(self, emoji_id):
        return self.client.delete(self.endpoint + "/" + emoji_id)

    def get_custom_emoji_by_name(self, name):
        return self.client.get(self.endpoint + "/name/" + name)

    def get_custom_emoji_image(self, emoji_id):
        return self.client.get(self.endpoint + "/" + emoji_id + "/image")

    def search_custom_emoji(self, options=None):
        return self.client.post(self.endpoint + "/search", options=options)

    def autocomplete_custom_emoji(self, params=None):
        return self.client.get(self.endpoint + "/autocomplete", params=params) class DataRetention(Base):
    endpoint = "/data_retention"

    def get_data_retention_policy(self):
        return self.client.get(self.endpoint + "/policy") class Roles(Base):
    endpoint = "/roles"

    def get_role_by_id(self, role_id):
        return self.client.get(self.endpoint + "/" + role_id)

    def get_role_by_name(self, role_name):
        return self.client.get(self.endpoint + "/name/" + role_name)

    def patch_role(self, role_id, options=None):
        return self.client.put(self.endpoint + "/" + role_id + "/patch", options=options)

    def get_list_of_roles_by_name(self):
        return self.client.get(
            self.endpoint + "/names",
        ) class Status(Base):
    def get_user_status(self, user_id):
        return self.client.get("/users/" + user_id + "/status")

    def update_user_status(self, user_id, options=None):
        return self.client.put("/users/" + user_id + "/status", options=options)

    def get_user_statuses_by_id(self, options=None):
        return self.client.post("/users/status/ids", options) class Bots(Base):
    endpoint = "/bots"

    def create_bot(self, options):
        return self.client.post(self.endpoint, options=options)

    def get_bots(self, params=None):
        return self.client.get(self.endpoint, params=params)

    def patch_bot(self, bot_id, options):
        return self.client.put(self.endpoint + "/" + bot_id, options=options)

    def get_bot(self, bot_id, params=None):
        return self.client.get(self.endpoint + "/" + bot_id, params=params)

    def disable_bot(self, bot_id):
        return self.client.post(self.endpoint + "/" + bot_id + "/disable")

    def enable_bot(self, bot_id):
        return self.client.post(self.endpoint + "/" + bot_id + "/enable")

    def assign_bot_to_user(self, bot_id, user_id):
        return self.client.post(self.endpoint + "/" + bot_id + "/assign/" + user_id)

    def get_bot_lhs_icon(self, bot_id):
        return self.client.get(self.endpoint + "/" + bot_id + "/icon")

    def set_bot_lhs_icon(self, bot_id, files):
        return self.client.post(self.endpoint + "/" + bot_id + "/icon", files=files)

    def delete_bot_lhs_icon(self, bot_id):
        return self.client.delete(self.endpoint + "/" + bot_id + "/icon") class Opengraph(Base):
    endpoint = "/opengraph"

    def get_opengraph_metadata_for_url(self, options):
        return self.client.post(self.endpoint, options=options) class IntegrationActions(Base):
    endpoint = "/actions"

    def open_dialog(self, options):
        return self.client.post(self.endpoint + "/dialogs/open", options=options)

    def submit_dialog(self, options):
        return self.client.post(self.endpoint + "/dialogs/submit", options=options)
import asyncio
import logging
import warnings
from .client import AsyncClient, Client
from .websocket import Websocket
from .endpoints.brand import Brand
from .endpoints.channels import Channels
from .endpoints.cluster import Cluster
from .endpoints.commands import Commands
from .endpoints.compliance import Compliance
from .endpoints.files import Files
from .endpoints.ldap import LDAP
from .endpoints.oauth import OAuth
from .endpoints.posts import Posts
from .endpoints.preferences import Preferences
from .endpoints.reactions import Reactions
from .endpoints.saml import SAML
from .endpoints.system import System
from .endpoints.teams import Teams
from .endpoints.users import Users
from .endpoints.webhooks import Webhooks
from .endpoints.elasticsearch import Elasticsearch
from .endpoints.emoji import Emoji
from .endpoints.data_retention import DataRetention
from .endpoints.roles import Roles
from .endpoints.status import Status
from .endpoints.bots import Bots
from .endpoints.opengraph import Opengraph
from .endpoints.integration_actions import IntegrationActions

        :return: Instance of :class:`~endpoints.preferences.Preferences`
        """
        return Preferences(self.client)

    @property
    def emoji(self):
        """
        Api endpoint for emoji

        :return: Instance of :class:`~endpoints.emoji.Emoji`
        """
        return Emoji(self.client)

    @property
    def reactions(self):
        """
        Api endpoint for posts' reactions

        :return: Instance of :class:`~endpoints.reactions.Reactions`
        """
        return Reactions(self.client)

    @property
    def system(self):
        """
        Api endpoint for system

        :return: Instance of :class:`~endpoints.system.System`
        """
        return System(self.client)

    @property
    def webhooks(self):
        """
        Api endpoint for webhooks

        :return: Instance of :class:`~endpoints.webhooks.Webhooks`
        """
        return Webhooks(self.client)

    @property
    def compliance(self):
        """
        Api endpoint for compliance

        :return: Instance of :class:`~endpoints.compliance.Compliance`
        """
        return Compliance(self.client)

    @property
    def cluster(self):
        """
        Api endpoint for cluster

        :return: Instance of :class:`~endpoints.cluster.Cluster`
        """
        return Cluster(self.client)

    @property
    def brand(self):
        """
        Api endpoint for brand

        :return: Instance of :class:`~endpoints.brand.Brand`
        """
        return Brand(self.client)

    @property
    def oauth(self):
        """
        Api endpoint for oauth

        :return: Instance of :class:`~endpoints.oauth.OAuth`
        """
        return OAuth(self.client)

    @property
    def saml(self):
        """
        Api endpoint for saml

        :return: Instance of :class:`~endpoints.saml.SAML`
        """
        return SAML(self.client)

    @property
    def ldap(self):
        """
        Api endpoint for ldap

        :return: Instance of :class:`~endpoints.ldap.LDAP`
        """
        return LDAP(self.client)

    @property
    def elasticsearch(self):
        """
        Api endpoint for elasticsearch

        :return: Instance of :class:`~endpoints.elasticsearch.Elasticsearch`
        """
        return Elasticsearch(self.client)

    @property
    def data_retention(self):
        """
        Api endpoint for data_retention

        :return: Instance of :class:`~endpoints.data_retention.DataRetention`
        """
        return DataRetention(self.client)

    @property
    def status(self):
        """
        Api endpoint for status

        :return: Instance of :class:`~endpoints.status.Status`
        """

        return Status(self.client)