diff --git a/itmoapp/commands/help.py b/itmoapp/commands/help.py index ba7c490..75f54ef 100644 --- a/itmoapp/commands/help.py +++ b/itmoapp/commands/help.py @@ -6,8 +6,13 @@ class CommandHelp(CommandBase): async def __call__(self, payload): self.sdk.log("/itmo_help handler fired with payload {}".format(payload)) - message = "Этот бот помогает абитуриенту отслеживать состояние поступления " \ - "в Университет ИТМО и подбирать направления по результатам ЕГЭ.\n" \ + # message = "Бот помогает абитуриенту отслеживать состояние поступления " \ + # "в Университет ИТМО и подбирать направления по результатам ЕГЭ.\n" \ + # "\n" \ + # "Техподдержка team@ifmo.su" + + message = "Бот помогает абитуриенту отслеживать состояние поступления " \ + "в Университет ИТМО.\n" \ "\n" \ "Техподдержка team@ifmo.su" diff --git a/itmoapp/components/methods.py b/itmoapp/components/methods.py index 61b68c2..36ec9a1 100644 --- a/itmoapp/components/methods.py +++ b/itmoapp/components/methods.py @@ -1,4 +1,5 @@ from . import ApiServer +import random class Methods: @@ -6,14 +7,26 @@ class Methods: def __init__(self, sdk): self.sdk = sdk - def check_rating_positions(self, student_id): - ratings = ApiServer().request('getUserPositions', {'id': student_id}) + def check_rating_positions(self, payload): + """ + Check ratings positions update for target student - # todo get user positions from db - old_position = 19 + :param string student_id: + :param payload: + :return list ratings: + """ + from models import Student - self.sdk.log("RATINGING: {}".format(ratings)) - for idx, program in enumerate(ratings): + # Get Student's data from db + student = Student(self.sdk, payload, chat=payload['chat']) + + # Send request to api server + ratings = ApiServer().request('getUserPositions', {'id': student.id}) + + # Prepare new ratings dictionary + new_ratings = {} + + for program in ratings: """ { 'program': 'Прикладная и компьютерная оптика', @@ -23,24 +36,92 @@ def check_rating_positions(self, student_id): 'value': 120 } """ + program_id = program['id'] + + program['position_diff'] = 0 + + try: + # Get user's last position + last_position = student.programs[str(program_id)]['position'] + + program['position_diff'] = last_position - program['position'] + except Exception as e: + pass + + new_ratings[str(program_id)] = program + + student.programs = new_ratings + student.save() - # todo compare positions with saved in db - program['position_diff'] = old_position - program['position'] + return new_ratings - ratings[idx] = program + async def report_ratings(self, payload): + from queries import Query + from components import Utils - self.sdk.log("APROGRAM: {}".format(program)) + ratings = self.check_rating_positions(payload) + self.sdk.log("API Server response for getUserPositions: {}".format(ratings)) - self.sdk.log("RATINGING: {}".format(ratings)) + # Prepare data + programs_data = [] - return ratings + # Prepare text for each program + for program_id, program in ratings.items(): + # Compose link + link = "http://abit.ifmo.ru/program/{}/".format(program_id) - async def loggy(self, payload): - self.sdk.log("Scheduled function loggy() with payload {}".format(payload)) - message = "[daily report]" + program_value = "{} {}".format( + program['value'], + Utils.endings( + int(program['value']), + "бюджетное место", + "бюджетных места", + "бюджетных мест" + ) + ) + + chance = min(int(float(program['value']) / float(program['position']) * 100), 100) + + if program['position_diff'] > 0: + diff = "+{} ⬆️️".format(program['position_diff']) + elif program['position_diff'] < 0: + diff = "{} 🔻".format(program['position_diff']) + else: + diff = None + + program_message = "{}\n".format(link, program['program']) + \ + "Ваше заявление {} из {}{}.\n".format( + program['position'], + program['users'], + " ({})".format(diff) if diff else "" + ) + \ + "{}\n".format(program_value) + \ + "Вероятность поступления: {}% {}\n".format(chance, Utils.satisfaction_emoji(chance)) + \ + "\n" + + programs_data.append(program_message) + + # Send message with buttons + await Query(self.sdk).create(payload, programs_data, 'pagination') + + async def evening_digest(self, payload): + self.sdk.log("Run scheduled function evening_digest() with payload {}".format(payload)) + + messages = [ + "Вечерний дайджест.", + "Пришло время для вечернего дайджеста.", + "Привет. Вот статус ваших заявлений на сегодняшний день.", + "Информация о поданных заявлениях к этому часу.", + "Добрейшего вечерочка. Так обстоят дела с вашими заявлениями:", + "Самое время узнать, как обстоят дела с вашими заявлениями.", + "По итогам дня ваши заявления имеют такие позиции.", + "Привет. Посмотрим, что с вашими позициями." + ] await self.sdk.send_text_to_chat( payload["chat"], - message, + random.choice(messages), bot=payload.get('bot', None) ) + + await self.report_ratings(payload) diff --git a/itmoapp/components/utils.py b/itmoapp/components/utils.py index 6762b22..56b1e61 100644 --- a/itmoapp/components/utils.py +++ b/itmoapp/components/utils.py @@ -18,10 +18,10 @@ def endings(count, form1, form2, form5): n = count % 100 n1 = count % 10 - if n > 10 and n < 20: + if 10 < n < 20: return form5 - if n1 > 1 and n1 < 5: + if 1 < n1 < 5: return form2 if n1 == 1: @@ -51,8 +51,8 @@ def satisfaction_emoji(percentage): emoji = { "100": "😎", "90": "😄", - "80": "😏", - "70": "🙂", + "80": "🙂", + "70": "😏", "60": "😐", "50": "🙁", "40": "😒", diff --git a/itmoapp/main.py b/itmoapp/main.py index 38ade93..79b4b9e 100644 --- a/itmoapp/main.py +++ b/itmoapp/main.py @@ -44,7 +44,7 @@ def __init__(self): self.sdk.set_callback_query_handler(self.process_callback_query) # Restore jobs in scheduler - self.sdk.scheduler.restore(Methods(self.sdk).loggy) + self.sdk.scheduler.restore(Methods(self.sdk).evening_digest) # Set up and run webserver self.webserver = Webserver(self.sdk) diff --git a/itmoapp/models/student.py b/itmoapp/models/student.py index 36c3aeb..4c7b29f 100644 --- a/itmoapp/models/student.py +++ b/itmoapp/models/student.py @@ -10,6 +10,7 @@ def __init__(self, sdk, payload, data=None, chat=None): self.id = None self.name = None self.scores = None + self.programs = None self.collection = Utils.create_collection_name(STUDENTS_COLLECTION_NAME, payload) if chat is not None: @@ -22,7 +23,8 @@ def save(self): 'chat': self.chat, 'id': self.id, 'name': self.name, - 'scores': self.scores + 'scores': self.scores, + 'programs': self.programs } self.sdk.db.update( @@ -30,7 +32,7 @@ def save(self): self.collection, # Find params - {'chat_id': self.chat}, + {'chat': self.chat}, # Data to be saved data_to_save, @@ -52,7 +54,7 @@ def __get(self, chat): """ Get user data from db - :param string chat: + :param string chat: chat_hash from payload :return: """ result = self.sdk.db.find_one(self.collection, {'chat': chat}) @@ -67,6 +69,4 @@ def __fill_model(self, data): self.id = data.get('id') self.name = data.get('name') self.scores = data.get('scores') - - # def get_positions(self): - # pass + self.programs = data.get('programs') diff --git a/itmoapp/states/ask_auth_correctness.py b/itmoapp/states/ask_auth_correctness.py index f3a2c27..84c6f44 100644 --- a/itmoapp/states/ask_auth_correctness.py +++ b/itmoapp/states/ask_auth_correctness.py @@ -25,7 +25,7 @@ async def before(self, payload, data): # Go back to auth state return await self.controller.goto(payload, "auth") - message = "Тебя зовут {}?".format(user_name) + message = "Вас зовут {}?".format(user_name) buttons = [ [ @@ -64,17 +64,18 @@ async def process(self, payload, data): # Add checking for User's positions in ratings self.sdk.log("Scheduler for {}:{} was added".format(payload['bot'], payload['chat'])) self.sdk.scheduler.add( - Methods(self.sdk).loggy, + Methods(self.sdk).evening_digest, payload, args=[payload], trigger_params={'hour': '21'} + # trigger_params={'minute': '*/1'} ) # Go to menu return await self.controller.goto(payload, "menu") # If user answer "no" - message = "Попробуй авторизоваться еще раз." + message = "Попробуйте авторизоваться еще раз." await self.sdk.send_text_to_chat( payload["chat"], diff --git a/itmoapp/states/ask_scores.py b/itmoapp/states/ask_scores.py index 3c439fd..e201b98 100644 --- a/itmoapp/states/ask_scores.py +++ b/itmoapp/states/ask_scores.py @@ -4,7 +4,7 @@ class StateAskScores(Base): async def before(self, payload, data): - message = "Пришли мне список своих баллов в формате:\n" \ + message = "Пришлите мне список своих баллов в формате:\n" \ "\n" \ "Математика 80\n" \ "Русский язык 78\n" \ diff --git a/itmoapp/states/auth.py b/itmoapp/states/auth.py index b77e021..90b3a02 100644 --- a/itmoapp/states/auth.py +++ b/itmoapp/states/auth.py @@ -5,7 +5,7 @@ class StateAuth(Base): async def before(self, payload, data): - message = "Введи номер заявления" + message = "Введите номер заявления" await self.sdk.send_text_to_chat( payload["chat"], @@ -23,7 +23,7 @@ async def process(self, payload, data): try: user_id = int(user_id) except Exception as e: - message = "Номер состоит только из цифры" + message = "Номер должен состоять только из цифр" await self.sdk.send_text_to_chat( payload["chat"], diff --git a/itmoapp/states/calc.py b/itmoapp/states/calc.py index cfcfb56..b5a17e4 100644 --- a/itmoapp/states/calc.py +++ b/itmoapp/states/calc.py @@ -6,7 +6,7 @@ class StateCalc(Base): async def before(self, payload, data): - message = "Минутку." + message = "Минутку" await self.sdk.send_text_to_chat( payload["chat"], @@ -23,7 +23,7 @@ async def before(self, payload, data): await self.controller.process(payload, programs) async def process(self, payload, data): - message = "Я подобрал несколько направлений, куда у тебя есть возможность поступить." + message = "Я подобрал несколько направлений, куда у вас есть возможность поступить." await self.sdk.send_text_to_chat( payload["chat"], @@ -46,15 +46,26 @@ async def process(self, payload, data): program_value = "{} {}".format( program['value'], - Utils.endings(int(program['value']), "место", "места", "мест") + Utils.endings( + int(program['value']), + "бюджетное место", + "бюджетных места", + "бюджетных мест" + ) ) - chance = int(float(program['value']) / float(program['possible_place']) * 100) + chance = min(int(float(program['value']) / float(program['possible_place']) * 100), 100) program_message = "{}\n".format(link, program['name']) + \ "Проходной балл: {}\n".format(program['score']) + \ + "Ваше заявление было бы {} из {}\n".format( + program['possible_place'], + program['requests'] + ) + \ + "{}\n".format( + program_value + ) + \ "Вероятность поступления: {}% {}\n".format(chance, Utils.satisfaction_emoji(chance)) + \ - "Твое заявление было бы {} из {} в рейтинге на {}\n".format(program['possible_place'], program['requests'], program_value) + \ "\n" programs_data.append(program_message) @@ -62,7 +73,7 @@ async def process(self, payload, data): # Send message with buttons await self.queries.create(payload, programs_data, 'pagination') - message = "Для возврата в меню нажми /itmo_start." + message = "Нажмите /itmo_start для возврата в меню" await self.sdk.send_text_to_chat( payload["chat"], diff --git a/itmoapp/states/greeting.py b/itmoapp/states/greeting.py index dd774ed..aa7ddc0 100644 --- a/itmoapp/states/greeting.py +++ b/itmoapp/states/greeting.py @@ -19,7 +19,7 @@ def __init__(self, state_controller): } async def before(self, payload, data): - message = "Ты уже подал заявление?" + message = "Вы уже подали заявление?" buttons = [ [ @@ -45,7 +45,6 @@ async def before(self, payload, data): async def process(self, payload, data): self.sdk.log("State Greeting processor fired with payload {}".format(payload)) - # TODO remove keyboard text = payload['text'] @@ -53,17 +52,17 @@ async def process(self, payload, data): # Go to auth return await self.controller.goto(payload, 'auth') - elif text in self.response_phrases['no']: - message = 'Я могу помочь подобрать направления по твоим результатам ЕГЭ.' - - await self.sdk.send_text_to_chat( - payload["chat"], - message, - bot=payload.get('bot', None) - ) - - # Ask scores - return await self.controller.goto(payload, 'ask_scores') + # elif text in self.response_phrases['no']: + # message = 'Я могу помочь подобрать направления по вашим результатам ЕГЭ.' + # + # await self.sdk.send_text_to_chat( + # payload["chat"], + # message, + # bot=payload.get('bot', None) + # ) + # + # # Ask scores + # return await self.controller.goto(payload, 'ask_scores') message = 'Не понимаю' diff --git a/itmoapp/states/menu.py b/itmoapp/states/menu.py index 964952a..1e0b457 100644 --- a/itmoapp/states/menu.py +++ b/itmoapp/states/menu.py @@ -12,7 +12,7 @@ def __init__(self, state_controller): self.response_phrases = { "ratings": [ - "Мои позиции в рейтингах" + "Мои вступительные заявления" ], "EGE_calc": [ @@ -29,7 +29,7 @@ def __init__(self, state_controller): } async def before(self, payload, data): - message = "Что тебя интересует?" + message = "Что вас интересует?" buttons = [ [ @@ -87,7 +87,7 @@ async def process(self, payload, data): self.sdk.scheduler.remove(payload) # Send message - message = "Если понадоблюсь, выполни команду /itmo_start." + message = "Если понадоблюсь, выполните /itmo_start" await self.sdk.send_text_to_chat( payload["chat"], diff --git a/itmoapp/states/ratings.py b/itmoapp/states/ratings.py index f39c386..f4f5dea 100644 --- a/itmoapp/states/ratings.py +++ b/itmoapp/states/ratings.py @@ -1,12 +1,11 @@ from .base import Base -from components import ApiServer, Methods, Utils -from models import Student +from components import Methods, Utils class StateRatings(Base): async def before(self, payload, data): - message = "Минутку." + message = "Минутку" await self.sdk.send_text_to_chat( payload["chat"], @@ -18,12 +17,8 @@ async def before(self, payload, data): await self.controller.process(payload, data) async def process(self, payload, data): - student = Student(self.sdk, payload, chat=payload['chat']) - ratings = Methods(self.sdk).check_rating_positions(student.id) - self.sdk.log("API Server response for getUserPositions: {}".format(ratings)) - - message = "Список направлений, куда ты подал документы на поступление" + message = "Направления, на которые вы подали документы." await self.sdk.send_text_to_chat( payload["chat"], @@ -31,44 +26,9 @@ async def process(self, payload, data): bot=payload.get('bot', None) ) - # Prepare data - programs_data = [] - - # Prepare text for each program - for program in ratings: - # Compose link - link = "http://abit.ifmo.ru/program/{}/".format(program['id']) - - # program_requests = "{} {}".format( - # program['users'], - # Utils.endings(int(program['users']), "заявление", "заявления", "заявлений") - # ) - - program_value = "{} {}".format( - program['value'], - Utils.endings(int(program['value']), "место", "места", "мест") - ) - - chance = int(float(program['value']) / float(program['position']) * 100) - - if program['position_diff'] > 0: - diff = "+{} 👍".format(program['position_diff']) - elif program['position_diff'] < 0: - diff = "{} 🔻".format(program['position_diff']) - else: - diff = "0 🔸" - - program_message = "{}\n".format(link, program['program']) + \ - "Вероятность поступления: {}% {}\n".format(chance, Utils.satisfaction_emoji(chance)) + \ - "Твое заявление {} ({}) из {} в рейтинге на {}\n".format(program['position'], diff, program['users'], program_value) + \ - "\n" - - programs_data.append(program_message) - - # Send message with buttons - await self.queries.create(payload, programs_data, 'pagination') + await Methods(self.sdk).report_ratings(payload) - message = "Для возврата в меню нажми /itmo_start." + message = "Нажмите /itmo_start для возврата в меню" await self.sdk.send_text_to_chat( payload["chat"], diff --git a/itmoapp/states/settings.py b/itmoapp/states/settings.py index 4c11fa4..c542be8 100644 --- a/itmoapp/states/settings.py +++ b/itmoapp/states/settings.py @@ -20,47 +20,6 @@ async def before(self, payload, data): async def process(self, payload, data): # todo - # message = "Я подобрал несколько направлений, куда у тебя есть возможность поступить.\n" \ - # "Для возврата в меню нажми /itmo_start." - # - # await self.sdk.send_text_to_chat( - # payload["chat"], - # message - # ) - # - # # Prepare data - # programs_data = [] - # - # # Prepate text for each program - # for program in data: - # # Compose link - # link = "http://abit.ifmo.ru/program/{}/".format(program['id']) - # - # program_requests = "{} {}".format( - # program['requests'], - # Utils.endings(int(program['requests']), "заявление", "заявления", "заявлений") - # ) - # - # program_value = "{} {}".format( - # program['value'], - # Utils.endings(int(program['value']), "место", "места", "мест") - # ) - # - # program_message = "{}\n" \ - # "Проходной балл: {}\n" \ - # "{} на {}\n" \ - # "\n".format( - # link, - # program['name'], - # program['score'], - # program_requests, - # program_value - # ) - # - # programs_data.append(program_message) - # - # # Send message with buttons - # await self.queries.create(payload, programs_data, 'pagination') # Go to start await self.controller.goto(payload, "menu") diff --git a/itmoapp/states/start.py b/itmoapp/states/start.py index a32d6de..e1c57ee 100644 --- a/itmoapp/states/start.py +++ b/itmoapp/states/start.py @@ -17,7 +17,7 @@ async def process(self, payload, data): return await self.controller.goto(payload, 'menu') # User is not authorized - message = "Привет. Я буду держать тебя в курсе твоего состояния поступления в ИТМО." + message = "Привет. Я расскажу про статус ваших вступительных заявлений." await self.sdk.send_text_to_chat( payload["chat"], diff --git a/sample-api-server/app/routes.js b/sample-api-server/app/routes.js index 3355194..b1cfeed 100644 --- a/sample-api-server/app/routes.js +++ b/sample-api-server/app/routes.js @@ -95,21 +95,21 @@ const getUserPositions = (req, res) => { { "program": "Прикладная и компьютерная оптика", "id": 10555, - "position": 13, + "position": random(1, 67), "users": 67, "value": 120 }, { "program": "Световая инженерия", - "id": 10555, - "position": 88, + "id": 10556, + "position": random(1, 430), "users": 430, "value": 25 }, { "program": "Интеллектуальная робототехника", - "id": 10555, - "position": 17, + "id": 10557, + "position": random(1, 125), "users": 125, "value": 56 } @@ -208,7 +208,8 @@ const getProgramsByScores = (req, res) => { programs = []; for (let i = 0; i < 64; i++) { - let name = Math.random().toString(36).replace(/w+/g, '').substr(0, 25), + // let name = Math.random().toString(36).replace(/w+/g, '').substr(0, 25), + let name = "Название направления №" + i + "", id = random(10500, 10600), score = random(180, 310), requests = random(10, 400),