def save_client(self, client: VKinderClient, force_country_update=False):
     """
     Manual UPSERT of single client in DB
     """
     log(f'[{client.fname} {client.lname}] Saving client\'s info to DB',
         is_debug_msg=self.debug_mode)
     client_db = self.__session.query(Clients).filter(
         Clients.vk_id == client.vk_id).first()
     if not client_db:
         client_db = Clients()
     client_db.vk_id = client.vk_id
     client_db.fname = client.fname
     client_db.lname = client.lname
     client_db.domain = client.domain
     # preserve country_id and country_name, restore them in case client revisit
     if not client_db.id or force_country_update:
         client_db.country_id = client.country_id
         client_db.country_name = client.country_name
     elif client_db.id:
         client.country_id = client_db.country_id
         client.country_name = client_db.country_name
     client_db.city_id = client.city_id
     client_db.city_name = client.city_name
     client_db.hometown = client.hometown
     client_db.birth_date = client.birth_date
     client_db.birth_day = client.birth_day
     client_db.birth_month = client.birth_month
     client_db.birth_year = client.birth_year
     client_db.sex_id = client.sex_id
     client_db.updated = client.last_contact
     self.__session.add(client_db)
     self.__session.commit()
     # load new id from base if client was just created
     client.db_id = client_db.id
     client.searches = self.load_searches(client)
示例#2
0
 def do_show_next_user(self, client: VKinderClient):
     self.send_typing_activity(client)
     client.status = STATUSES['decision_wait']
     client.active_user = client.get_next_user()
     # if we already showed all pairs
     if not client.active_user:
         self.do_send_to_start_due_to_reach_end(client)
         self.do_propose_start_search(client)
         return
     client.active_user.photos = self.vk_personal.get_user_photos(
         client.active_user.vk_id)
     if not client.active_user.photos:
         client.active_user.photos = self.vk_personal.get_user_photos(
             client.active_user.vk_id, album_id='wall')
     photos = [
         f'photo{photo.owner_id}_{photo.id}'
         for photo in client.active_user.photos
     ]
     photos_str = ','.join(photos)
     log(
         f'[{client.fname} {client.lname}] Showing user: {client.active_user.fname} '
         f'{client.active_user.lname} with {len(client.active_user.photos)} photos',
         self.debug_mode)
     age_str = f', возраст: {client.active_user.age}' if client.active_user.age else ''
     user_info = f'{client.active_user.fname} {client.active_user.lname} '
     user_info += f'({client.active_user.city_name}{age_str})'
     user_info += f'{last_seen(client.active_user.last_seen_time)}\nhttps://vk.com/{client.active_user.domain}'
     keyboard = self.cmd.kb(['yes', 'no', 'ban', None, 'back', 'quit'])
     self.send_msg(client,
                   user_info,
                   attachment=photos_str,
                   keyboard=keyboard)
     self.send_msg(client, PHRASES['do_you_like_it'])
     self.db.save_photos(client)
    def save_search(self, client: VKinderClient):
        """
        Saves customs search, with delete old searches (more than search_history_limit)
        """
        log(f'[{client.fname} {client.lname}] Saving client\'s search to DB',
            is_debug_msg=self.debug_mode)
        # pass search saving if it was already loaded from history
        if client.search.id:
            return
        search_history = self.__session.query(
            Searches.id).filter(Searches.client_id == client.db_id).order_by(
                Searches.updated.desc()).limit(self.search_history_limit -
                                               1).all()
        delete_expr = delete(Searches).where(
            and_(not_(Searches.id.in_(search_history)),
                 Searches.client_id == client.db_id))
        self.__session.execute(delete_expr)
        self.__session.commit()
        search = Searches(client_id=client.db_id,
                          min_age=client.search.min_age,
                          max_age=client.search.max_age,
                          sex_id=client.search.sex_id,
                          status_id=client.search.status_id,
                          city_id=client.search.city_id,
                          city_name=client.search.city_name,
                          updated=func.now())
        self.__session.add(search)
        self.__session.commit()

        # load new id from base because new search was just created
        client.search.id = search.id
        client.searches.append(client.search)
 def load_client_from_db(self, vk_id: str):
     """
     Gets client by its VK id
     """
     log(f'Loading client info from DB', is_debug_msg=self.debug_mode)
     client = self.__session.query(Clients).filter(
         Clients.vk_id == vk_id).first()
     if client:
         return client.convert_to_ApiUser()
 def load_searches(self, client: VKinderClient) -> list[VKinderSearch]:
     """
     Loads all search history parameters
     """
     log(f'[{client.fname} {client.lname}] Loading all client\'s searches from DB',
         is_debug_msg=self.debug_mode)
     result = self.__session.query(Searches).filter(
         Searches.client_id == client.db_id).order_by(
             Searches.updated.desc()).all()
     return result
 def load_users_from_db(self, client: VKinderClient):
     """
     Gets all rated users by client, using rating as filter
     """
     log(f'[{client.fname} {client.lname}] Loading users from DB with rating {client.rating_filter}',
         is_debug_msg=self.debug_mode)
     users = self.__session.query(Users).join(ClientsUsers).filter(
         ClientsUsers.client_id == client.db_id).filter(
             ClientsUsers.rating_id == client.rating_filter).all()
     client.found_users = []
     for user in users:
         client.found_users.append(
             user.convert_to_ApiUser(client.rating_filter))
     log(f'[{client.fname} {client.lname}] Loaded {len(client.found_users)} users from DB',
         is_debug_msg=self.debug_mode)
示例#7
0
 def __init__(self,
              group_token: str,
              person_token: str,
              group_id: str,
              app_id: str,
              db_name: str,
              db_login: str,
              db_password: str,
              db_driver: str,
              db_host: str,
              db_port: int,
              retry_timeout: int = 1,
              retry_attempts: int = sys.maxsize,
              debug_mode=False):
     self.client_activity_timeout = 300
     self.debug_mode = debug_mode
     self.clients_pool = {}
     self.group_id = group_id
     self.cmd = Commands(COMMANDS)
     # countries received once per application launch (by request), as they almost doesn't changes
     self.countries = []
     self.rebuild_tables = False
     self.retry_timeout = retry_timeout
     self.retry_attempts = retry_attempts
     self.vk_personal = VkApiClient(person_token,
                                    app_id,
                                    debug_mode=debug_mode)
     self.db = VKinderDb(db_name,
                         db_login,
                         db_password,
                         db_driver=db_driver,
                         db_host=db_host,
                         db_port=db_port,
                         debug_mode=debug_mode)
     self.__initialized = self.vk_personal.is_initialized and self.db.is_initialized
     self.vk_group = vk_api.VkApi(token=group_token)
     try:
         self.long_poll = VkBotLongPoll(self.vk_group, self.group_id)
         self.vk_api = self.vk_group.get_api()
     except BaseException as e:
         self.__initialized = False
         log(f'{type(self).__name__} init failed: {e.error["error_msg"]}',
             self.debug_mode)
     if self.__initialized:
         log(f'{type(self).__name__} initialised successfully',
             self.debug_mode)
示例#8
0
 def get_user_photos(self, owner_id: str = None, album_id='profile', rev: bool = True, extended: bool = True,
                     photo_sizes: bool = True, sort_by: str = 'popularity', needed_qty: int = 3) -> list[ApiPhoto]:
     """
     Getting all user photos with sorting and returning limited quantity. For external use.
     https://vk.com/dev/photos.get
     :param owner_id: ID of user, if None - your token's account ID will be taken
     :param album_id: one of album type: wall, profile, saved
     :param rev: reversed chronological order
     :param photo_sizes: True, if needed additional info abt photos
     :param extended: True, if needed likes, comments, tags, reposts
     :param needed_qty: max quantity to be returned
     :param sort_by: 'popularity' or 'date'
     :return: list of ApiPhoto objects or empty list
     """
     result = []
     if not self.__initialized:
         log(f'Error in get_user_photos: {type(self).__name__} not initialized', self.debug_mode)
         return result
     owner_id = owner_id if owner_id else self.__user_id
     offset = 0
     count = 1000
     log(f'Getting user {owner_id} photos from {album_id}...', self.debug_mode)
     while True:
         photos = self.__get_user_photos(count=count, offset=offset, owner_id=owner_id, album_id=album_id, rev=rev,
                                         extended=extended, photo_sizes=photo_sizes)
         if not photos.success:
             log(f'Loading photos failed: {photos.message}', self.debug_mode)
             break
         items_count = len(photos.json_object['items'])
         log(f'Loaded {items_count} photos more...', self.debug_mode)
         # if we reached the end
         if items_count == 0:
             break
         result += photos.json_object['items']
         # if returned less items than requested, suppose that we reached the end
         # or if next iteration will return more items than we requested
         if items_count < count:
             break
         offset += count
         # prevent ban from service
         time.sleep(self.request_delay)
     log(f'Loaded totally {len(result)} photos', self.debug_mode)
     result = self.__process_photos(result, sort_by=sort_by, needed_qty=needed_qty)
     result = [ApiPhoto(row) for row in result]
     return result
示例#9
0
 def __init__(self, token: str, app_id: str, user_id=None, version: str = '5.124', debug_mode=False, base_url=None):
     super().__init__()
     self.API_BASE_URL = base_url if base_url else BASE_URL
     self.debug_mode = debug_mode
     self.__vksite = 'https://vk.com/'
     self.token = token
     self.app_id = app_id
     self.__version = version
     self.__required_user_fields = ['sex', 'bdate', 'domain', 'country', 'city', 'last_seen', 'home_town']
     self.__headers = {'User-Agent': 'Netology'}
     self.__params = {'access_token': self.token, 'v': self.__version}
     self.__img_types = {'s': 1, 'm': 2, 'x': 3, 'o': 4, 'p': 5, 'q': 6, 'r': 7, 'y': 8, 'z': 9, 'w': 10}
     self.request_delay = 0.33
     # below line needed for get_users only
     self.__initialized = True
     # try to instantiate
     user = self.__get_users(user_ids=user_id)
     is_deactivated = False
     if user.success:
         is_deactivated = user.json_object[0].get('deactivated', False)
     if user.success and not is_deactivated:
         self.__initialized = True
         self.__user_id = str(user.json_object[0]['id'])
         self.__first_name = user.json_object[0]['first_name']
         self.__last_name = user.json_object[0]['last_name']
         self.__domain = user.json_object[0]['domain']
         self.__status = f'{type(self).__name__} initialised with user: {self.__first_name} {self.__last_name} ' \
                         f'(#{self.__user_id})'
     else:
         self.__initialized = False
         self.__user_id = None
         self.__first_name = None
         self.__last_name = None
         self.__domain = None
         if is_deactivated:
             user.message = 'User is deactivated'
         # error message will be in status
         self.__status = f'{type(self).__name__} init failed: ' + user.message
         self.__status += f'\nPls check a personal token via this URL:' \
                          f'\n{self.get_auth_link(self.app_id, "offline,photos,status,groups")}'
     log(self.__status, debug_mode)
 def __init__(self,
              db_name,
              db_login,
              db_password,
              db_driver='postgresql',
              db_host='localhost',
              db_port=5432,
              debug_mode=False):
     self.debug_mode = debug_mode
     self.__sqlalchemy = sa
     self.search_history_limit = 10
     self.rebuild = self.load_config()['rebuild_tables']
     try:
         self.__engine = sa.create_engine(
             f'{db_driver}://{db_login}:{db_password}@{db_host}:{db_port}/{db_name}'
         )
         self.__engine.connect().close()
         self.__session = sessionmaker(bind=self.__engine)()
         log(f'{type(self).__name__} successfully connected to DB',
             self.debug_mode)
         if self.rebuild:
             log(f'Rebuilding tables...', self.debug_mode)
             clear_db(sa, self.__engine)
             Base.metadata.create_all(self.__engine)
         self.__initialized = True
     except OperationalError as e:
         log(f'{type(self).__name__} unable connect to DB: {e}',
             self.debug_mode)
         self.__initialized = False
         self.__session = None
 def save_user_rating(self, client: VKinderClient):
     """
     Saves user rating (when client liked/disliked/banned), updates exist rating
     """
     log(f'[{client.fname} {client.lname}] Saving user rating to DB',
         is_debug_msg=self.debug_mode)
     client_db = self.__session.query(Clients).filter(
         Clients.vk_id == client.vk_id).first()
     user_db = self.__session.query(Users).filter(
         Users.vk_id == client.active_user.vk_id).first()
     clients_user = self.__session.query(ClientsUsers).filter(
         and_(ClientsUsers.client_id == client_db.id,
              ClientsUsers.user_id == user_db.id)).first()
     if not clients_user:
         clients_user = ClientsUsers(client_id=client_db.id,
                                     user_id=user_db.id,
                                     rating_id=client.active_user.rating_id)
     else:
         clients_user.rating_id = client.active_user.rating_id
         clients_user.updated = func.now()
     self.__session.add(clients_user)
     self.__session.commit()
 def save_users(self, client: VKinderClient):
     """
     Making manual batch UPSERT of users with relations to search using many-to-many relations
     """
     if not client.found_users:
         log(f'[{client.fname} {client.lname}] No users to save in DB',
             is_debug_msg=self.debug_mode)
         return
     log(f'[{client.fname} {client.lname}] Saving users info to DB',
         is_debug_msg=self.debug_mode)
     search = self.__session.query(Searches).filter(
         Searches.id == client.search.id).first()
     vk_ids = [client.vk_id for client in client.found_users]
     users = self.__session.query(Users).filter(
         Users.vk_id.in_(vk_ids)).all()
     matches = {user.vk_id: user for user in users}
     users_list = []
     for found_user in client.found_users:
         user = matches.get(found_user.vk_id, Users())
         user.vk_id = found_user.vk_id
         user.fname = found_user.fname
         user.lname = found_user.lname
         user.domain = found_user.domain
         user.country_id = found_user.country_id
         user.country_name = found_user.country_name
         user.city_id = found_user.city_id
         user.city_name = found_user.city_name
         user.hometown = found_user.hometown
         user.birth_date = found_user.birth_date
         user.birth_day = found_user.birth_day
         user.birth_month = found_user.birth_month
         user.birth_year = found_user.birth_year
         user.sex_id = found_user.sex_id
         user.updated = func.now()
         user.searches.append(search)
         users_list.append(user)
     self.__session.add_all(users_list)
     self.__session.commit()
 def save_photos(self, client: VKinderClient):
     """
     Saves users photo information, with clearance of all previously saved photo
     """
     log(f'[{client.fname} {client.lname}] Saving photo\'s info to DB',
         is_debug_msg=self.debug_mode)
     # let's clear all previous user photos
     user_db = self.__session.query(Users).filter(
         Users.vk_id == client.active_user.vk_id).first()
     self.__session.query(Photos).filter(
         and_(Photos.owner_id == user_db.id)).delete()
     self.__session.commit()
     photos_list = []
     for photo in client.active_user.photos:
         photo_db = Photos(url=photo.url,
                           likes_count=photo.likes_count,
                           comments_count=photo.comments_count,
                           reposts_count=photo.reposts_count,
                           photo_id=photo.id,
                           owner_db_id=user_db.id)
         photos_list.append(photo_db)
     self.__session.add_all(photos_list)
     self.__session.commit()
示例#14
0
 def search_users(self, city_id: int = None, sex_id: int = None, love_status_id: int = None, age_from: int = None,
                  age_to: int = None, q: str = None, has_photo: bool = True, hometown: str = None,
                  sort: bool = True) -> list[ApiUser]:
     """
     Search for VK users by different parameters. For external use.
     https://vk.com/dev/users.search
     :param city_id: country ID from catalog VK
     :param sex_id: sex ID from catalog VK
     :param love_status_id: love status from catalog BK
     :param age_from: any positive integer
     :param age_to: any positive integer
     :param q: search string
     :param hometown: city name
     :param has_photo: True or False
     :param sort: True or False
     :return: list of ApiUser objects or empty list
     """
     result = []
     if not self.__initialized:
         log(f'Error in search_users: {type(self).__name__} not initialized', self.debug_mode)
         return result
     offset = 0
     count = 1000
     log(f'\nSearching users...', self.debug_mode)
     while True:
         users = self.__search_users(count=count, offset=offset, city_id=city_id, sex_id=sex_id,
                                     love_status_id=love_status_id, age_from=age_from, age_to=age_to, q=q,
                                     has_photo=has_photo, hometown=hometown, sort=sort)
         if not users.success:
             log(f'Loading users failed: {users.message}', self.debug_mode)
             break
         items_count = len(users.json_object['items'])
         log(f'Loaded {items_count} users', self.debug_mode)
         # if we reached the end
         if items_count == 0:
             break
         result += users.json_object['items']
         # if returned less items than requested, suppose that we reached the end
         # or if next iteration will return more items than we requested
         if items_count < count:
             break
         offset += count
         # prevent ban from service
         time.sleep(self.request_delay)
     result = [ApiUser(dict(row)) for row in result]
     return result
示例#15
0
 def get_users(self, user_ids=None, fields: [str] = None) -> list[ApiUser]:
     """
     This method receive users info by their ID's. For external use.
     Description here: https://vk.com/dev/users.get
     :param fields: list additional fields of users in strings to be requested
     :param user_ids: list of one or more user IDs in strings form
     :return: list of ApiUser objects or empty list
     """
     result = []
     if not self.__initialized:
         log(f'Error in get_users: {type(self).__name__} not initialized', self.debug_mode)
         return result
     log(f'Getting users...', self.debug_mode)
     users = self.__get_users(user_ids=user_ids, fields=fields)
     if not users.success:
         log(f'Getting users failed: {users.message}', self.debug_mode)
         return result
     items_count = len(users.json_object)
     log(f'Got {items_count} users', self.debug_mode)
     result += users.json_object
     result = [ApiUser(dict(row)) for row in result]
     return result
示例#16
0
 def search_cities(self, country_id: int = None, city_name: str = None) -> list[ApiCity]:
     """
     Searching all cities by name. For external use.
     https://vk.com/dev/database.getCities
     :param city_name: search name (might be partial)
     :param country_id: country ID from catalog VK
     :return: list of ApiCity objects or empty list
     """
     result = []
     if not self.__initialized:
         log(f'Error in search_cities: {type(self).__name__} not initialized', self.debug_mode)
         return result
     offset = 0
     count = 1000
     log(f'\nSearching city name: "{city_name}" at country {country_id} ...', self.debug_mode)
     while True:
         if city_name:
             cities = self.__search_cities(count=count, offset=offset, country_id=country_id, q=city_name)
         else:
             cities = self.__search_cities(count=count, offset=offset, country_id=country_id, need_all=True)
         if not cities.success:
             log(f'Loading cities failed: {cities.message}', self.debug_mode)
             break
         items_count = len(cities.json_object['items'])
         log(f'Loaded {items_count} cities', self.debug_mode)
         # if we reached the end
         if items_count == 0:
             break
         result += cities.json_object['items']
         # if returned less items than requested, suppose that we reached the end
         # or if next iteration will return more items than we requested
         if items_count < count:
             break
         offset += count
         # prevent ban from service
         time.sleep(self.request_delay)
     result = [ApiCity(dict(row)) for row in result]
     return result
示例#17
0
 def get_countries(self, code: str = None) -> list[ApiCountry]:
     """
     Full list of countries or specific country byt its code
     https://vk.com/dev/database.getCountries
     :param code: coma separated ISO 3166-1 alpha-2 codes - RU,UA,BY
     :return:  list of ApiCountry objects or empty list
     """
     result = []
     if not self.__initialized:
         log(f'Error in get_countries: {type(self).__name__} not initialized', self.debug_mode)
         return result
     offset = 0
     count = 1000
     log(f'\nRequesting max {count} countries at once from VK...', self.debug_mode)
     while True:
         if code:
             countries = self.__get_countries(count=count, offset=offset, code=code)
         else:
             countries = self.__get_countries(count=count, offset=offset, need_all=True)
         if not countries.success:
             log(f'Loading countries failed: {countries.message}', self.debug_mode)
             break
         items_count = len(countries.json_object['items'])
         log(f'Loaded {items_count} countries', self.debug_mode)
         # if we reached the end
         if items_count == 0:
             break
         result += countries.json_object['items']
         # if returned less items than requested, suppose that we reached the end
         # or if next iteration will return more items than we requested
         if items_count < count:
             break
         offset += count
         # prevent ban from service
         time.sleep(self.request_delay)
     result = [ApiCountry(dict(row)) for row in result]
     return result
示例#18
0
    def start(self):
        retries = 0
        if not self.__initialized:
            log(f'Can\'t start: {type(self).__name__} not initialized',
                self.debug_mode)
            return
        while True and retries < self.retry_attempts:
            try:
                retries += 1
                log(
                    f'Listening for messages in group {self.group_id}...(retry #{retries})',
                    self.debug_mode)
                self.long_poll.update_longpoll_server()
                for event in self.long_poll.listen():
                    if event.type == VkBotEventType.MESSAGE_NEW:
                        client = self.get_client(
                            str(event.object.message['from_id']))
                        msg = event.object.message['text']
                        log(f'[{client.fname} {client.lname}] typed "{msg}"',
                            self.debug_mode)
                        msg = msg.lower()

                        # obligatory exit from conversation, works at any page, highest priority,
                        # one exception: if this command not very first one
                        if msg in self.cmd.get(
                                'quit'
                        ) and client.status != STATUSES['has_contacted']:
                            self.do_say_goodbye(client)
                            continue

                        # imitation of custom search - works at any page, highest priority
                        if msg == 'test':
                            client.reset_search()
                            client.search.sex_id = randrange(0, 2, 1)
                            client.search.status_id = randrange(1, 8, 1)
                            client.search.city_id = 1
                            client.search.city_name = 'Москва'
                            client.search.min_age = randrange(0, 60, 1)
                            client.search.max_age = randrange(
                                client.search.min_age, 127, 1)
                            client.rating_filter = RATINGS['new']
                            self.do_users_search(client)
                            continue

                        # if client prints/press something at "Welcome screen" page
                        if client.status in (STATUSES['invited'], STATUSES['has_contacted']) \
                                and (msg in self.cmd.get('yes') or msg in self.cmd.get('new search')):
                            self.do_start_search_creating(client)

                        elif client.status in (STATUSES['invited'], STATUSES['has_contacted']) \
                                and msg in self.cmd.get('show history'):
                            self.do_show_search_history(client)

                        elif client.status in (STATUSES['invited'], STATUSES['has_contacted']) \
                                and (msg in self.cmd.get('liked') or msg in self.cmd.get('disliked') or msg in
                                     self.cmd.get('banned')):
                            self.do_show_rated_users(msg, client)

                        elif client.status in (STATUSES['invited'],
                                               STATUSES['has_contacted']
                                               ) and msg in self.cmd.get('no'):
                            self.do_say_goodbye(client)

                        elif client.status == STATUSES['has_contacted']:
                            self.do_propose_start_search(client)

                        # if client prints/press something in "Select search history" page
                        elif client.status == STATUSES[
                                'search_history_input_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_start_search(client)

                        # if client prints/press something in "Select search history" page
                        elif client.status == STATUSES[
                                'search_history_input_wait']:
                            self.on_search_history_choose(msg, client)

                        # if client prints/press something in "Search country" page
                        elif client.status == STATUSES[
                                'country_input_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_start_search_creating(client)

                        # if client prints/press something in "Search country" page
                        elif client.status == STATUSES['country_input_wait']:
                            self.on_country_name_input(msg, client)

                        # if client prints/press something in "Select country" page
                        elif client.status == STATUSES[
                                'country_choose_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_country_name_input(client)

                        # if client prints/press something in "Select country" page
                        elif client.status == STATUSES['country_choose_wait']:
                            self.on_country_name_choose(msg, client)

                        # if client prints/press something in "Search city" page
                        elif client.status == STATUSES[
                                'city_input_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_start_search(client)

                        # if client prints/press something in "Search city" page
                        elif client.status == STATUSES[
                                'city_input_wait'] and msg in self.cmd.get(
                                    'country'):
                            self.do_propose_country_name_input(client)

                        # if client prints/press something in "Search city" page
                        elif client.status == STATUSES['city_input_wait']:
                            self.do_propose_city_name_choose(msg, client)

                        # if client prints/press something in "Select city" page
                        elif client.status == STATUSES[
                                'city_choose_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_start_search_creating(client)

                        # if client prints/press something in "Select city" page
                        elif client.status == STATUSES['city_choose_wait']:
                            self.on_city_name_choose(msg, client)

                        # if client prints/press something in "Select sex" page
                        elif client.status == STATUSES[
                                'sex_choose_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_start_search_creating(client)

                        # if client prints/press something in "Select sex" page
                        elif client.status == STATUSES['sex_choose_wait']:
                            self.on_sex_choose(msg, client)

                        # if client prints/press something in "Select love status" page
                        elif client.status == STATUSES[
                                'status_choose_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_sex_choose(client)

                        # if client prints/press something in "Select love status" page
                        elif client.status == STATUSES['status_choose_wait']:
                            self.on_status_choose(msg, client)

                        # if client prints/press something in "Min age" page
                        elif client.status == STATUSES[
                                'min_age_input_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_status_choose(client)

                        # if client prints/press something in "Min age" page
                        elif client.status == STATUSES['min_age_input_wait']:
                            self.on_min_age_enter(msg, client)

                        # if client prints/press something in "Max age" page
                        elif client.status == STATUSES[
                                'max_age_input_wait'] and msg in self.cmd.get(
                                    'back'):
                            self.do_propose_min_age_enter(client)

                        # if client prints/press something in "Max age" page
                        elif client.status == STATUSES['max_age_input_wait']:
                            self.on_max_age_enter(msg, client)

                        # if client prints/press something in "User profile view" page
                        elif client.status == STATUSES[
                                'decision_wait'] and msg in self.cmd.get(
                                    'back'):
                            if client.rating_filter == RATINGS['new']:
                                self.do_propose_min_age_enter(client)
                            else:
                                self.do_propose_start_search(client)

                        # if client prints/press something in "User profile view" page
                        elif client.status == STATUSES['decision_wait']:
                            self.on_decision_made(msg, client)

                        # if command is unexpected or not recognized
                        else:
                            self.do_inform_about_unknown_command(client)
            except (requests.exceptions.ConnectionError,
                    requests.exceptions.ReadTimeout,
                    urllib3.exceptions.ReadTimeoutError):
                if retries < self.retry_attempts:
                    log(
                        f'Error in connection. Retry in {self.retry_timeout} seconds...',
                        self.debug_mode)
                    sleep(self.retry_timeout)
                else:
                    log(f'Error in connection. Bot shutting down.',
                        self.debug_mode)