def info(self, add_flag=None): phrases_db_objects = models.IntervalPhrase.objects.filter( chat_id=self.chat_db_object).order_by('id') bot_response = self.usertext_dict["saved_entries"].substitute( number=len(phrases_db_objects)) for el in phrases_db_objects: new_line = f'id: {el.id}. Фраза: {el.phrase}\n' if len(bot_response) + len(new_line) > 4100: code_logger.info( 'In IntervalPhraseCommandHandler.info, len(info_message) + len(new_line) > 4100 ' ) helpers.make_request_vk('messages.send', random_id=helpers.randomid(), message=bot_response, peer_id=self.message.peer_id) bot_response = new_line else: bot_response += new_line code_logger.info( f'In IntervalPhraseCommandHandler.info, len last info_message {len(bot_response)}' ) event_code = "INTERVAL_PHRASE_INFO" if add_flag: event_code = "INTERVAL_PHRASE_ADD_INFO" return BotAnswer(event_code, self.message, bot_response=bot_response)
def info(self, add_flag=None): bot_response = self.usertext_dict[ "on"] if self.chat_db_object.smart_mode else self.usertext_dict[ "off"] phrases_db_objects = models.SmartReply.objects.filter( chat_id=self.chat_db_object).order_by('id') bot_response += self.usertext_dict["saved_entries"].substitute( number=len(phrases_db_objects)) for el in phrases_db_objects: new_line = f'ID: {el.id}.{" REGEX" if el.regex else ""} Сообщение-триггер: {el.trigger} . Smart-ответ: {el.reply}\n' if len(bot_response) + len(new_line) > 4100: code_logger.info( 'In SmartCommandHandler.info, len(info_message) + len(new_line) > 4100 ' ) helpers.make_request_vk('messages.send', random_id=helpers.randomid(), message=bot_response, peer_id=self.message.peer_id) bot_response = new_line else: bot_response += new_line code_logger.info( f'In SmartCommandHandler.info. len last info_message {len(bot_response)}' ) event_code = "SMART_ADD_INFO" if add_flag else "SMART_INFO" return BotAnswer(event_code, self.message, bot_response=bot_response)
def pipeline_part_dict( self, peer_id, from_id, input_text, event_code, expected_bot_response_dict, event_description=None, ): """ Here we compare only part of bot_response dictionary. First we create expected_answer without bot_response, then we compare only those bot_response dictionary values which we passed in expected_bot_response_dict.""" input_message_object = self.create_input_message_instance( input_text, peer_id=peer_id, from_id=from_id) expected_answer = BotAnswer(event_code, input_message_object, event_description=event_description) returned_answer = self.event_object.process() returned_bot_response_dict = returned_answer.bot_response for key, item in expected_bot_response_dict.items(): self.assertEqual(item, returned_bot_response_dict.get(key)) self.assertEqual(expected_answer.event_code, returned_answer.event_code) self.assertEqual(expected_answer.input_message, returned_answer.input_message) self.assertEqual(expected_answer.event_description, returned_answer.event_description)
def core_pipeline( self, peer_id, from_id, input_text, event_code, event_description=None, bot_response=None, ): """ We create expected_answer before actual processing, 'cause initializing InputMessage object we call 'getConversationsById' method to get conversation_dict, and there are such fields as response__items__last_message_id and response__items__in_read in that dict which will be different after event_object.process(), 'cause bot sends a message in that process.""" input_message_object = self.create_input_message_instance( input_text, peer_id=peer_id, from_id=from_id) expected_answer = BotAnswer(event_code, input_message_object, event_description=event_description, bot_response=bot_response) # print("EXPECTED_ANSWER", expected_answer) returned_answer = self.event_object.process() # print("RETURNED_ANSWER", returned_answer) self.assertEqual(expected_answer, returned_answer)
def turn_on(self): if self.chat_db_object.interval_mode: raise AlreadyDoneError(self.message, bot_response=f"Режим {self.command_word} уже включен," \ f" интервал между фразами {self.chat_db_object.interval}, " \ f"следующую фразу бот отправит через {self.chat_db_object.messages_till_endpoint}" \ f" {declention_message(self.chat_db_object.messages_till_endpoint)}.") else: if self.chat_db_object.interval: phrases_from_db = models.IntervalPhrase.objects.filter( chat_id=self.chat_db_object) if len(phrases_from_db) > 0: self.chat_db_object.interval_mode = True self.chat_db_object.messages_till_endpoint = self.chat_db_object.interval self.chat_db_object.save() return BotAnswer( "INTERVAL_ON", self.message, bot_response=f"Режим {self.command_word} включен.") else: raise PrerequisitesError( self.message, bot_response= f"Сначала добавьте фразы командой {interval_phrase} add', после этого можно включить режим интервал." ) else: raise PrerequisitesError( self.message, bot_response= f"Сначала установите интервал командой {self.command_word}, например '{self.command_word} 10'." )
def process(self): reply_object = self.choose_reply() if not reply_object: return BotAnswer("SMART_NOT_TRIGGER", self.input_message) reply_text = reply_object.reply if "@имя@" in reply_object.reply: name = self.get_name() reply_text = re.sub("@имя@", name, reply_text) code_logger.info("In SmartAction.process. Name changed.") reply_object.last_used = timezone.now() reply_object.save() return BotAnswer("SMART_REPLY_SENT", self.input_message, bot_response=reply_text, )
def delete_all_phrases(self, phrases_from_db): bot_response = self.usertext_dict["all_db_entries_deleted"] if self.chat_db_object.interval_mode: super().set_interval_to_off() bot_response += " " + self.usertext_dict["off"] phrases_from_db.delete() return BotAnswer("INTERVAL_PHRASE_REMOVE_ALL", self.message, bot_response=bot_response)
def delete_all_smart_entries(self, smart_entries_from_db): bot_response = self.usertext_dict['all_db_entries_deleted'] if self.chat_db_object.smart_mode: self.chat_db_object.smart_mode = False self.chat_db_object.save() bot_response += " " + self.usertext_dict["off"] smart_entries_from_db.delete() return BotAnswer("SMART_REMOVE_ALL", self.message, bot_response=bot_response)
def process(self): if self.count == 0: phrases_from_db = models.IntervalPhrase.objects.filter(chat_id=self.chat_id) message = random.choice(phrases_from_db).phrase self.chat_db_object.messages_till_endpoint = self.chat_db_object.interval self.chat_db_object.save() code_logger.info( f'In IntervalAction.process. new_till_endpoint = {self.chat_db_object.interval} saved to db. ' f'Interval message will be sent.') bot_answer = BotAnswer("INTERVAL_MESSAGE_SENT", self.input_message, bot_response=message,) else: self.chat_db_object.messages_till_endpoint = self.count self.chat_db_object.save() bot_answer = BotAnswer("INTERVAL_COUNTER", self.input_message) code_logger.info(f'In IntervalAction.process. new_till_endpoint = {self.count} saved to db.') return bot_answer
def set_interval(self): if self.chat_db_object.interval_mode: self.chat_db_object.interval = self.option self.chat_db_object.messages_till_endpoint = self.option self.chat_db_object.save() return BotAnswer( "INTERVAL_SET", self.message, bot_response= f"Режим {self.command_word} включен, интервал между фразами {self.chat_db_object.interval}." ) else: self.chat_db_object.interval = self.option self.chat_db_object.save() return BotAnswer( "INTERVAL_SET", self.message, bot_response= f"Интервал между фразами установлен. Режим {self.command_word} выключен." )
def turn_off(self): if self.chat_db_object.interval_mode: super().set_interval_to_off() return BotAnswer( "INTERVAL_OFF", self.message, bot_response=f'Режим {self.command_word} выключен.') else: raise AlreadyDoneError( self.message, bot_response=f'Режим {self.command_word} уже выключен.')
def user_process(self): models.UserMessage(text=self.message.text, from_id=self.message.from_id).save() text = vk.text_parser.TextParser(self.message) if text.status == 'command': return text.command_handler_caller() if text.status == 'wrong command': raise WrongCommandError(self.message, bot_response="Такой команды нет.") if text.status == "call": return BotAnswer( 'BOT_CALL', self.message, event_description="bot was called in private chat with user.") else: return BotAnswer( 'PLAIN_MESSAGE', self.message, event_description="just a message in private chat with " "user.")
def test_one_time_not_owner(self): for i in range(3): returned_answer = self.pipeline_process(12345678) expected_answer = BotAnswer("INTERVAL_COUNTER", self.input_message_object) self.assertEqual(expected_answer, returned_answer) returned_answer = self.pipeline_process(12345678) self.assertEqual( "INTERVAL_MESSAGE_SENT", returned_answer.event_code, ) self.assertEqual('phrase1', returned_answer.bot_response)
def info(self): if self.chat_db_object.interval_mode: return BotAnswer("INTERVAL_INFO", self.message, bot_response=f"Режим {self.command_word} включен," \ f" интервал между фразами {self.chat_db_object.interval}, " \ f"следующую фразу бот отправит через {self.chat_db_object.messages_till_endpoint}" \ f" {declention_message(self.chat_db_object.messages_till_endpoint)}.") else: if self.chat_db_object.interval: return BotAnswer( "INTERVAL_INFO", self.message, bot_response= f"Режим {self.command_word} выключен. Сохраненные настройки: интервал между фразами бота " f"- {self.chat_db_object.interval} {declention_message(self.chat_db_object.interval)}." ) else: return BotAnswer( "INTERVAL_INFO", self.message, bot_response= f"Режим {self.command_word} выключен. Сохраненные настройки: интервал не установлен." )
def command(self): if self.option == option_off: models.NewPostSetting.objects.filter( chat_id=self.chat_db_object).update(newpost_mode=False, newpost_group_link="", newpost_group_id=None) models.KickNonMembersSetting.objects.filter( chat_id=self.chat_db_object).update( kick_nonmembers_mode=False, kick_nonmembers_group_link="", kick_nonmembers_group_id=None) models.RandomPostSetting.objects.filter( chat_id=self.chat_db_object).update(random_post_mode=False, random_post_group_link="", random_post_group_id=None) self.chat_db_object.interval_mode = False self.chat_db_object.interval = None self.chat_db_object.messages_till_endpoint = None self.chat_db_object.smart_mode = False self.chat_db_object.conversation_is_registered = False self.chat_db_object.save() return BotAnswer( 'REGISTRATION_OFF', self.message, bot_response= 'Регистрация отменена: бот будет игнорировать вас и ваши команды.' ) if self.option == option_info: return BotAnswer( 'REGISTRATION_INFO', self.message, bot_response=f'ID вашей беседы {self.chat_db_object.chat_id}')
def off(self): if self.chat_db_object.smart_mode: self.chat_db_object.smart_mode = False self.chat_db_object.save() models.SmartReply.objects.filter( chat_id=self.chat_db_object).update( last_used=helpers.five_minutes_ago()) return BotAnswer("SMART_OFF", self.message, bot_response=self.usertext_dict['off']) else: raise AlreadyDoneError( self.message, bot_response=self.usertext_dict['already_off'])
def process(self): code_logger.info('=======================') code_logger.info( f"In EventHandler.process. self.event_dict: {self.event_dict}") if self.event_type == 'message_new': input_message = InputMessage(self.event_dict) try: result = MessageHandler(input_message).process() except VKBotException as e: result = BotAnswer.exception_to_answer(e) for answer in result: if answer.check_if_need_send(): answer.send_message() return result else: return self.event_type
def remove(self): phrases_from_db = models.IntervalPhrase.objects.filter( chat_id=self.chat_db_object) self.check_for_phrases_to_remove(phrases_from_db) ids_from_db = {phrase.id for phrase in phrases_from_db} code_logger.info(f"All the phrases' ids from database: {ids_from_db}") absent_ids = self.ids_to_remove.difference(ids_from_db) actual_ids_to_remove = ids_from_db.intersection(self.ids_to_remove) if len(actual_ids_to_remove) == 0: bot_response = self.usertext_dict[ "cannot_remove_wrong_id"].substitute(ids=', '.join( str(i) for i in self.ids_to_remove)) raise PrerequisitesError(self.message, bot_response=bot_response) if len(ids_from_db) == len(actual_ids_to_remove): if len(absent_ids) == 0: return self.delete_all_phrases(phrases_from_db) else: bot_response = self.usertext_dict[ "cannot_remove_absent_ids"].substitute(ids=', '.join( str(i) for i in absent_ids )) + " " + self.usertext_dict["all_db_entries_deleted"] if self.chat_db_object.interval_mode: super().set_interval_to_off() bot_response += " " + self.usertext_dict["off"] else: if len(absent_ids) == 0: bot_response = self.usertext_dict["remove_ids"].substitute( ids=', '.join(str(i) for i in self.ids_to_remove)) else: bot_response = self.usertext_dict[ "cannot_remove_absent_ids"].substitute(ids=', '.join( str(i) for i in absent_ids )) + " " + self.usertext_dict["remove_ids"].substitute( ids=', '.join(str(i) for i in actual_ids_to_remove)) phrases_from_db.filter(id__in=actual_ids_to_remove).delete() return BotAnswer("INTERVAL_PHRASE_REMOVE", self.message, bot_response=bot_response)
def process(self): self.workgroup = '-' + str(self.setting_db_object.random_post_group_id) code_logger.info(f'In RandomPostAction.process. ID of the workgroup: {self.workgroup}') post_quantity = self.get_post_quantity() code_logger.debug( f'In RandomPostAction.process. Number of posts on the workgroup wall: {post_quantity}') if post_quantity == 0: raise PrerequisitesError(self.input_message, bot_response="Стена пуста.") one_post = self.choose_post(post_quantity) attachment = self.prepare_attachment(one_post) return BotAnswer("RANDOM_POST_SENT", self.input_message, bot_response={ "attachment": attachment, "peer_id": self.chat_id, # /post command can be called from user chat, that's why we have to use chat_id })
def chat_registration(self): self.chat_db_object.conversation_is_registered = True self.chat_db_object.save() models.NewPostSetting.objects.update_or_create( chat_id=self.chat_db_object) models.KickNonMembersSetting.objects.update_or_create( chat_id=self.chat_db_object) models.RandomPostSetting.objects.update_or_create( chat_id=self.chat_db_object) code_logger.info( f"Conversation is registered with id {self.chat_db_object.chat_id}" ) return BotAnswer('REGISTRATION_SUCCESSFUL', self.message, bot_response=f'Беседа успешно зарегистрирована, ' f'ID вашей беседы: {self.chat_db_object.chat_id}')
def on(self): if self.chat_db_object.smart_mode: raise AlreadyDoneError( self.message, bot_response=self.usertext_dict['already_on']) else: smart_messages_from_db = models.SmartReply.objects.filter( chat_id=self.chat_db_object) if len(smart_messages_from_db) > 0: self.chat_db_object.smart_mode = True self.chat_db_object.save() return BotAnswer("SMART_ON", self.message, bot_response=self.usertext_dict['on']) else: raise PrerequisitesError( self.message, bot_response=self.usertext_dict['zero_entries'])
def remove(self): phrases_from_db = models.SmartReply.objects.filter( chat_id=self.chat_db_object) self.check_for_phrases_to_remove(phrases_from_db) ids_from_db = {phrase.id for phrase in phrases_from_db} absent_ids = self.ids_to_remove.difference(ids_from_db) actual_ids_to_remove = ids_from_db.intersection(self.ids_to_remove) if len(actual_ids_to_remove) == 0: bot_response = self.usertext_dict[ "cannot_remove_wrong_id"].substitute(ids=', '.join( str(i) for i in self.ids_to_remove)) raise PrerequisitesError(self.message, bot_response=bot_response) if len(ids_from_db) == len(actual_ids_to_remove): if len(absent_ids) == 0: return self.delete_all_smart_entries(phrases_from_db) else: bot_response = self.usertext_dict["cannot_remove_absent_ids"].substitute(ids= ', '.join(str(i) for i in absent_ids)) + " " + \ self.usertext_dict["all_db_entries_deleted"] if self.chat_db_object.smart_mode: self.chat_db_object.smart_mode = False self.chat_db_object.save() bot_response += " " + self.usertext_dict["off"] else: if len(absent_ids) == 0: bot_response = self.usertext_dict["remove_ids"].substitute( ids=', '.join(str(i) for i in self.ids_to_remove)) else: bot_response = self.usertext_dict[ "cannot_remove_absent_ids"].substitute(ids=', '.join( str(i) for i in absent_ids )) + " " + self.usertext_dict["remove_ids"].substitute( ids=', '.join(str(i) for i in actual_ids_to_remove)) phrases_from_db.filter(id__in=actual_ids_to_remove).delete() return BotAnswer("SMART_REMOVE", self.message, bot_response=bot_response)
def command(self): """ Method "wall.get" is available only with personal tokens or with service tokens. Group tokens aren't allowed. """ if self.option == 'post': if self.setting_db_object.random_post_mode: return RandomPostAction(self.setting_db_object, self.chat_db_object, self.message).process() else: raise PrerequisitesError( self.message, bot_response= f"Чтобы включить команду {self.command_word}, воспользуйтесь командой {random_post} {option_on}." ) elif self.option == option_delete: if self.setting_db_object.random_post_group_link: self.setting_db_object.random_post_mode = False self.setting_db_object.random_post_group_link = "" self.setting_db_object.random_post_group_id = None self.setting_db_object.save() bot_response = random_post_dict['delete'] return BotAnswer("RANDOM_POST_DELETE", self.message, bot_response=bot_response) else: raise PrerequisitesError( self.message, bot_response=random_post_dict['delete_cannot']) elif self.option == option_off: if self.setting_db_object.random_post_mode: self.setting_db_object.random_post_mode = False self.setting_db_object.save() return BotAnswer("RANDOM_POST_OFF", self.message, bot_response=random_post_dict['off']) else: raise AlreadyDoneError( self.message, bot_response=random_post_dict['off_already']) elif self.option == option_on: self.check_for_personal_token() if self.setting_db_object.random_post_group_link: group = self.setting_db_object.random_post_group_link if not self.setting_db_object.random_post_mode: self.setting_db_object.random_post_mode = True self.setting_db_object.save() bot_response = random_post_dict['on'].substitute( group_link=group) return BotAnswer("RANDOM_POST_ON", self.message, bot_response=bot_response) else: bot_response = random_post_dict['on_already'].substitute( group_link=group) raise AlreadyDoneError(self.message, bot_response=bot_response) else: bot_response = random_post_dict['on_cannot'] raise PrerequisitesError(self.message, bot_response=bot_response) elif self.option == option_info: if self.setting_db_object.random_post_group_link: group = self.setting_db_object.random_post_group_link if self.setting_db_object.random_post_mode: bot_response = random_post_dict['info_on'].substitute( group_link=group) else: bot_response = random_post_dict['info_off'].substitute( group_link=group) else: bot_response = random_post_dict['info_no_group'] return BotAnswer("RANDOM_POST_INFO", self.message, bot_response=bot_response) else: group_screen_name, group_id = self.option random_post_group_link = "https://vk.com/" + group_screen_name self.setting_db_object.random_post_group_link = random_post_group_link self.setting_db_object.random_post_group_id = group_id self.setting_db_object.save() if not self.setting_db_object.random_post_mode: bot_response = random_post_dict['group_saved_off'].substitute( group_link=random_post_group_link) else: bot_response = random_post_dict['group_saved_on'].substitute( group_link=random_post_group_link) return BotAnswer("RANDOM_POST_GROUP", self.message, bot_response=bot_response)
def command(self): self.setting_db_object = models.NewPostSetting.objects.get( chat_id=self.chat_db_object) if self.option == option_off: if self.setting_db_object.newpost_mode: self.setting_db_object.newpost_mode = False self.setting_db_object.save() return BotAnswer("NEWPOST_OFF", self.message, bot_response=newpost_dict["off"]) else: raise AlreadyDoneError( self.message, bot_response=newpost_dict["off_already"]) elif self.option == option_on: self.check_for_personal_token() if self.setting_db_object.newpost_group_link: group = self.setting_db_object.newpost_group_link if self.setting_db_object.newpost_mode: bot_response = newpost_dict["on_already"].substitute( group_link=group) raise AlreadyDoneError(self.message, bot_response=bot_response) else: self.setting_db_object.newpost_mode = True self.setting_db_object.save() bot_response = newpost_dict["on"].substitute( group_link=group) return BotAnswer("NEWPOST_ON", self.message, bot_response=bot_response) else: bot_response = newpost_dict["on_cannot"] raise PrerequisitesError(self.message, bot_response=bot_response) elif self.option == option_info: if self.setting_db_object.newpost_group_link: group = self.setting_db_object.newpost_group_link if self.setting_db_object.newpost_mode: bot_response = newpost_dict["info_on"].substitute( group_link=group) else: bot_response = newpost_dict["info_off"].substitute( group_link=group) else: bot_response = newpost_dict["info_no_group"] return BotAnswer("NEWPOST_INFO", self.message, bot_response=bot_response) elif self.option == option_delete: if self.setting_db_object.newpost_group_link: self.setting_db_object.newpost_mode = False self.setting_db_object.newpost_group_link = "" self.setting_db_object.newpost_group_id = None self.setting_db_object.latest_newpost_timestamp = 0 self.setting_db_object.save() bot_response = newpost_dict["delete"] return BotAnswer("NEWPOST_DELETE", self.message, bot_response=bot_response) else: raise PrerequisitesError( self.message, bot_response=newpost_dict["delete_cannot"]) else: group_screen_name, group_id = self.option newpost_group_link = "https://vk.com/" + group_screen_name self.setting_db_object.newpost_group_link = newpost_group_link self.setting_db_object.newpost_group_id = group_id self.setting_db_object.latest_newpost_timestamp = 0 self.setting_db_object.save() if not self.setting_db_object.newpost_mode: bot_response = newpost_dict["group_saved_off"].substitute( group_link=newpost_group_link) else: bot_response = newpost_dict["group_saved_on"].substitute( group_link=newpost_group_link) return BotAnswer("NEWPOST_GROUP", self.message, bot_response=bot_response)
def pipeline_check(self, from_id): returned_answer = self.pipeline_process(from_id) expected_answer = BotAnswer("INTERVAL_COUNTER", self.input_message_object) self.assertEqual(expected_answer, returned_answer)
def chat_process(self): chat_info = references.ChatReference(self.message.conversation_dict) chat_db_object, created = models.Chat.objects.update_or_create( chat_id=self.message.peer_id, defaults={ 'local_id': chat_info.local_id, 'owner_id': chat_info.owner_id, 'title': chat_info.title, 'members_count': chat_info.members_count, 'last_contact': timezone.now() }, ) models.ChatMessage(text=self.message.text, chat_id=chat_db_object, from_user_id=self.message.from_id).save() # !!! text_object = vk.text_parser.TextParser(self.message) if not chat_db_object.conversation_is_registered: registration = RegistrationCommandHandler(text_object.wordlist, self.message, chat_db_object) if registration.is_asking_for_registration(): bot_answer = registration.chat_registration() else: raise NotRegisteredError( self.message, error_description=common_dict["not_registered"]) elif text_object.status == 'command': return text_object.command_handler_caller(chat_db_object) elif text_object.status == 'wrong command': if 'варя' in BOT_NAME1: raise WrongCommandError(self.message, bot_response="Такой команды нет.") else: raise WrongCommandError( self.message, error_description="wrong command in chat.") else: if not self.message.service_message: if not chat_db_object.smart_mode and not chat_db_object.interval_mode: bot_answer = BotAnswer('PLAIN_MESSAGE', self.message) else: bot_answer_smart = None bot_answer_interval = None if chat_db_object.smart_mode: # we don't want to propagate any exception here 'cause we need to process both modes. try: if not self.message.text or len( self.message.text) > helpers.SMART_MAX_LEN: raise LimitError( self.message, error_description=actions_dict[ "smart_wrong_message_length"]) else: smart_action = SmartAction( chat_db_object, self.message) bot_answer_smart = smart_action.process() except VKBotException as e: bot_answer_smart = BotAnswer.exception_to_answer(e) if chat_db_object.interval_mode: try: interval_action = IntervalAction( chat_db_object, self.message) bot_answer_interval = interval_action.process() except VKBotException as e: bot_answer_interval = BotAnswer.exception_to_answer( e) if bot_answer_interval and not bot_answer_smart: bot_answer = bot_answer_interval elif bot_answer_smart and not bot_answer_interval: bot_answer = bot_answer_smart else: bot_answer = (bot_answer_smart, bot_answer_interval) else: bot_answer = BotAnswer( 'SERVICE_MESSAGE', self.message, event_description="It was a service message. " "Nothing will be sent.") return bot_answer