diff --git a/data/vk_bot.db b/data/vk_bot.db index cd82bfa..b684e56 100644 Binary files a/data/vk_bot.db and b/data/vk_bot.db differ diff --git a/src/__pycache__/analyse_and_bot_functions.cpython-38.pyc b/src/__pycache__/analyse_and_bot_functions.cpython-38.pyc index 5f1a8a5..37c808a 100644 Binary files a/src/__pycache__/analyse_and_bot_functions.cpython-38.pyc and b/src/__pycache__/analyse_and_bot_functions.cpython-38.pyc differ diff --git a/src/analyse_and_bot_functions.py b/src/analyse_and_bot_functions.py index ffb70e0..80ce63c 100644 --- a/src/analyse_and_bot_functions.py +++ b/src/analyse_and_bot_functions.py @@ -2,14 +2,17 @@ import datetime import requests import json +import random # from new_main import vk_api2 as vk_api2 # from new_main import month_length as month_length +# import matplotlib import group_class as gc import time import random import math +# top-secret information token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" analyse_group_id = 'memkn' @@ -25,8 +28,16 @@ days_of_the_week = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] -def get_message(group_id, server_, ts_, key_): - # gets the message from the user +# THE FUNCTION WHICH REALISE INTERACTION WITH SERVER +def get_message(server_, ts_, key_): + """ + this function gets message from a user + :param server_: + :param ts_: something technical + :param key_: also something technical + :return: + """ + response = requests.get('{server}?act=a_check&key={key}&ts={ts}&wait=25'.format (server=server_, key=key_, ts=ts_)).json() if 'updates' in response and len(response['updates']) > 0: @@ -34,10 +45,13 @@ def get_message(group_id, server_, ts_, key_): return "", -1, response['ts'] +# THE BLOCK OF FUNCTIONS WHICH PROCESS MESSAGES FROM A USER AND CHECK IF GIVEN PARAMETERS ARE CORRECT def process_input_message(message): - # gets the massage from the user and returns a code which depends on the message type. Also returns the group id - # and needed frequency. These fields will be used afterwards only if the message is: group_id: ...; period: ... """ + gets the massage from the user and returns a code which depends on the message type. Also returns the group id + and needed period. These fields will be used afterwards only if the message is: group_id: ...; period: ... + :param message: the massage got from the server + :return: special code, group id and period code -1: mistake code 0: no message code 1: user wants to cancel the task @@ -52,10 +66,8 @@ def process_input_message(message): code 10: the user needs the advice how to give a task code 11: user wants to set time and has pressed the button code 12: user wants to set recommendation time and has entered this time already - - :param message: the message that was sent by the user - :return: special code, string - the group id or "" - and a number - the period of analysing or -1 """ + if message == "": return 0, "", -1 if message[0] == '~': @@ -109,66 +121,143 @@ def process_input_message(message): return -1, "", -1 +def check_recommend_time(time_string): + """ + the option 'set time' asks the user to enter the time ant this function checks if it is correct + :param time_string: string with that time + :return: + """ + if time_string[3] != ':' or not time_string[1: 3].isdigit() or not time_string[4: 6].isdigit(): + return 0 + hours = int(time_string[1: 3]) + if 0 <= hours < 24: + return 1 + return 0 + + +def check_for_correct(group_id_to_check): + """ + this function check if the group which the user asked to analyze, exists + :param group_id_to_check: that group's id + :return: + """ + your_group_info = vk_api2.groups.getById(group_id=group_id_to_check, fields='members_count', count=5) + if your_group_info[0]['id'] == my_number_group_id and group_id_to_check != 'memkn_funclub': + return 0 + return 1 + + +def check_period_for_correct(period): + """ + checks if the period value is OK, not 17 minutes, for example. We have special rules for this + :param period: + :return: + """ + if period < 15 or period > 1440: + return 0 + if period < 60 and 60 % period != 0: + return 0 + if 1440 % period != 0: + return 0 + return 1 + + +# THE BLOCK OF FUNCTIONS FOR COMMUNICATING def get_new_random_id(): + """ + random id is a special id of the message to send this message, it has to be unique during the hour + :return: counted random (not random!!!) id + """ t = datetime.datetime.now() - random_id = t.minute * 60000 + t.second * 1000 + t.microsecond + random_id = t.minute * 60000000 + t.second * 1000000 + t.microsecond return random_id -def switch_off(current_user_id, begin_file_): - # switches the bot off, the special password is needed +def switch_off(current_user_id, file_name): + """ + switches the bot off, the special password is needed + :param current_user_id: + :param file_name: file with the information about the current task, we need to rewrite it + :return: + """ r_id = get_new_random_id() - file_ = open(begin_file_, "w") - file_.write(f"-1 0 0 0") - file_.close() + file = open(file_name, "w") + file.write("-1 0 0 0") + file.close() vk_api2.messages.send(user_id=current_user_id, message="Goodbye!", random_id=r_id) - return + return 0 def incorrect_id(current_user_id): - # informs about the mistake + # informs about the mistake in group id r_id = get_new_random_id() - vk_api2.messages.send(user_id=current_user_id, message="Wrong group id!", random_id=r_id) + vk_api2.messages.send( + user_id=current_user_id, message="Ummmm... Something went wrong! Incorrect group id!", random_id=r_id + ) return def incorrect_period_value(current_user_id): - # informs about the mistake + # informs about the mistake in a period value r_id = get_new_random_id() - s = "Period should be not less than 15 and should divide 1440!" + s = "Bro, listen here! If your period is less than an hour, in should divide 60. And anyway, it should divide 1440)" vk_api2.messages.send(user_id=current_user_id, message=s, random_id=r_id) return -def cancel_the_task(have_a_task, current_user_id, master_id, begin_file_): - # Cancels the current task, it is is asked by the user who gave the task earlier +def cancel_the_task(have_a_task, current_user_id, master_id, file_name): + """ + Cancels the current task, it is is asked by the user who gave the task earlier + :param have_a_task: 1 if bot has a task already, 0 if it hasn't + :param current_user_id: id of the user who wants to cancel the task + :param master_id: id of the user who had given a task + :param file_name: file with the information about the current task, we need to change it + :return: + """ r_id = get_new_random_id() - file_ = open(begin_file_, "w") - file_.write(f"-1 0 0 0") - file_.close() if have_a_task and current_user_id == master_id: + file = open(file_name, "w") + file.write("-1 0 0 0") + file.close() vk_api2.messages.send(user_id=current_user_id, message="Your task is cancelled!", random_id=r_id) - return + return 0 elif have_a_task: vk_api2.messages.send(user_id=current_user_id, message="Sorry, I am working on the other user's task!", random_id=r_id) - return + return 1 else: vk_api2.messages.send(user_id=current_user_id, message="Я сделал ничего, не благодари!", random_id=r_id) - return + return 0 def say_hello(current_user_id): # sends a message 'Ну привет, ....' r_id = get_new_random_id() - string = "Ну привет, " + greetings = [ + "Ну привет, ", "Здарова бандит-", "Hi, bro ", "Здрасьте. Кто тут лох? Ага - ", "Приветики, ты просто космос, " + ] + index = random.randint(0, 4) + string = greetings[index] value = vk_api2.users.get(user_ids=current_user_id, fields='first_name') string += value[0]['first_name'] - something = vk_api2.messages.send(user_id=current_user_id, message=string, random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, message=string, random_id=r_id) return +def send_last_upload(current_user_id): + """ + in development + :param current_user_id: + :return: + """ + r_id = get_new_random_id() + some = vk_api.photos.get(owner_id=-200698416, album_id='278041850', rev=1, count=1) + ph_id = some['items'][0]['id'] + string = "photo-200698416_" + str(ph_id) + vk_api2.messages.send(user_id=current_user_id, attachment=string, random_id=r_id + 1) + + def instruction_message(current_user_id): # sends the message if user did send us the message of an unknown format r_id = get_new_random_id() @@ -181,16 +270,12 @@ def instruction_message(current_user_id): return -def check_recommend_time(time_string): - if time_string[3] != ':' or not time_string[1: 3].isdigit() or not time_string[4: 6].isdigit(): - return 0 - hours = int(time_string[1: 3]) - if 0 <= hours < 24: - return 1 - return 0 - - def set_time(current_user_id): + """ + sends the keyboard with some variants of time when to send recommendations + :param current_user_id: id of the user who wants to set time + :return: + """ r_id = get_new_random_id() kb = \ @@ -201,52 +286,52 @@ def set_time(current_user_id): { "action": { "type": "text", - "payload": "{\"button\": \"2\"}", - "label": "~19:00" + "payload": "{\"button\": \"1\"}", + "label": "~22:00" }, - "color": "positive" + "color": "primary" }, { "action": { "type": "text", "payload": "{\"button\": \"2\"}", - "label": "~20:00" + "label": "~23:00" }, - "color": "primary" + "color": "positive" }, { "action": { "type": "text", "payload": "{\"button\": \"2\"}", - "label": "~21:00" + "label": "~00:00" }, - "color": "positive" + "color": "primary" } ], [ { "action": { "type": "text", - "payload": "{\"button\": \"1\"}", - "label": "~22:00" + "payload": "{\"button\": \"2\"}", + "label": "~19:00" }, - "color": "primary" + "color": "positive" }, { "action": { "type": "text", "payload": "{\"button\": \"2\"}", - "label": "~23:00" + "label": "~20:00" }, - "color": "positive" + "color": "primary" }, { "action": { "type": "text", "payload": "{\"button\": \"2\"}", - "label": "~00:00" + "label": "~21:00" }, - "color": "primary" + "color": "positive" } ] ] @@ -342,34 +427,43 @@ def send_big_instruction(current_user_id): return -def check_for_correct(group_id_to_check): - your_group_info = vk_api2.groups.getById(group_id=group_id_to_check, fields='members_count', count=5) - if your_group_info[0]['id'] == my_number_group_id and group_id_to_check != 'memkn_funclub': - return 0 - return 1 - - -def check_period_for_correct(period): - if period < 15 or period > 1440: - return 0 - if period < 60 and 60 % period != 0: - return 0 - if 1440 % period != 0: - return 0 - return 1 +def not_available(current_user_id): + r_id = get_new_random_id() + vk_api2.messages.send(user_id=current_user_id, message="Not available now, give a task at first!", random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, sticker_id=4331, random_id=(r_id + 1)) + return -def not_available(current_user_id): +def not_available_i_am_busy(current_user_id): r_id = get_new_random_id() - vk_api2.messages.send(user_id=current_user_id, message="Not available now!", random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, message="Impossible because... i am busy!", random_id=r_id) vk_api2.messages.send(user_id=current_user_id, sticker_id=4331, random_id=(r_id + 1)) return def task_by_button(current_user_id): + # gives the instruction how to give a task r_id = get_new_random_id() vk_api2.messages.send( user_id=current_user_id, - message="Send the group_id and the period with a whitespace between them and '$' in the beginning", + message="Send the id of the group and the period with a whitespace between them and the '$' in the beginning", random_id=r_id ) + + +def continue_the_old_task(file_name): + file = open(file_name, "r") + task_from_the_previous_session = list(file.readline().split()) + gr_id = -1 + have_a_task = 0 + usr_id = -1 + prd = 0 + rec_hr = -1 + if len(task_from_the_previous_session) > 0 and task_from_the_previous_session[0] != '-1': + gr_id = task_from_the_previous_session[0] + usr_id = int(task_from_the_previous_session[1]) + prd = int(task_from_the_previous_session[2]) + rec_hr = int(task_from_the_previous_session[3]) + have_a_task = 1 + return gr_id, prd, usr_id, rec_hr, have_a_task + file.close() diff --git a/src/group_class_with_db.py b/src/group_class_with_db.py index 6dd1eae..716beaa 100644 --- a/src/group_class_with_db.py +++ b/src/group_class_with_db.py @@ -7,12 +7,12 @@ import src.analyse_and_bot_functions as func import math -# from new_main import vk_api2 as vk_api2 -# from new_main import days_of_the_week as days_of_the_week con = sql.connect('../data/vk_bot.db') cur = con.cursor() + +# top secret information, close your eyes... token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" analyse_group_id = 'memkn' @@ -49,10 +49,8 @@ def __init__(self, group_id, freq, master_id): self.period = freq self.analyses_per_day = 1440 // self.period - # con = sql.connect('vk_bot.db') name = "stats" + str(self.master_id) with con: - # cur = con.cursor() cur.execute(f"CREATE TABLE IF NOT EXISTS {name} (" "'analyse_number' INTEGER, " "'average_percent' INTEGER, " @@ -70,24 +68,32 @@ def __init__(self, group_id, freq, master_id): con.commit() if table_existed is None or table_existed == []: for j in range(7): - for i in range(self.analyses_per_day * j, self.analyses_per_day * (j + 1)): - s = days_of_the_week[j] + ", " - hours = (i % self.analyses_per_day) * self.period // 60 - minutes = (i % self.analyses_per_day) * self.period % 60 - if hours < 10: - s += "0" - s += str(hours) + ":" - if minutes < 10: - s += "0" - s += str(minutes) - stats = (i, 0, 0, 0, 0, 0, 0, s) - cur.execute(f"""INSERT OR REPLACE INTO {name} VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", stats) - con.commit() + self.fill_the_database(j) + + def fill_the_database(self, week_day): + """ + fills the database in '__init__' + :param week_day: + :return: + """ + name = "stats" + str(self.master_id) + for i in range(self.analyses_per_day * week_day, self.analyses_per_day * (week_day + 1)): + s = days_of_the_week[week_day] + ", " + hours = (i % self.analyses_per_day) * self.period // 60 + minutes = (i % self.analyses_per_day) * self.period % 60 + if hours < 10: + s += "0" + s += str(hours) + ":" + if minutes < 10: + s += "0" + s += str(minutes) + stats = (i, 0, 0, 0, 0, 0, 0, s) + cur.execute(f"""INSERT OR REPLACE INTO {name} VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", stats) + con.commit() def del_table(self): - # con = sql.connect('vk_bot.db') + # deletes data from the table name = "stats" + str(self.master_id) - # cur = con.cursor() cur.execute(f"""DELETE FROM {name}""") con.commit() @@ -104,9 +110,11 @@ def count_online_proportion(self): number_of_members1 = number_of_members already_count = 0 while already_count < number_of_members: + # if we haven't checked all members yet group_members_ids = vk_api.groups.getMembers(group_id=self.group_id, offset=already_count, fields='online') for x in group_members_ids['items']: if 'online' in x: + # if the information about the online status is available online += x['online'] else: number_of_members1 -= 1 @@ -128,8 +136,12 @@ def group_analyse(self): return percent def update_data(self, new_one, cell_to_update): - # con = sql.connect('vk_bot.db') - # cur = con.cursor() + """ + updates the database after the analyze + :param new_one: the new value of online percent + :param cell_to_update: the cell of the database which we need to update + :return: + """ name = "stats" + str(self.master_id) sq = f"SELECT * FROM {name} WHERE analyse_number={cell_to_update}" @@ -159,26 +171,27 @@ def update_data(self, new_one, cell_to_update): def recommendation_for_this_day_of_the_week(self): """ + average stats and recommendation for this day of the week past 4 last weeks this function runs at about 00:00 daily and recommends: when it is going to be the best time for posts this day. :return: returns nothing, just sends a message with recommendation """ - # average stats and recommendation for this day of the week past 4 last weeks - # con = sql.connect('vk_bot.db') - # cur = con.cursor() name = "stats" + str(self.master_id) r_id = func.get_new_random_id() + # высняем, за сегодн давать рекомендацию или за завтра today_or_tomorrow = "today" day = datetime.datetime.now().weekday() if self.recommend_hour != 0: day = (day + 1) % 7 today_or_tomorrow = "tomorrow" + # выяснили start = day * self.analyses_per_day finish = (day + 1) * self.analyses_per_day + # если за нужный день нет данных, даём рекомендацию за другой, то есть основанную на сегодншней статистике sq = f"SELECT weeks_passed FROM {name} WHERE analyse_number={start}" cur.execute(sq) checker = cur.fetchone() @@ -187,6 +200,7 @@ def recommendation_for_this_day_of_the_week(self): start = day * self.analyses_per_day finish = (day + 1) * self.analyses_per_day + # начинаем обрабатывать статистику recommend_message = f"Possibly, {today_or_tomorrow} the best time will be " max_online, best_time = 0, 0 for i in range(start, finish): @@ -252,8 +266,6 @@ def get_one_day_information_v2( """ # needed for 'recommendation_for_this_week' - # con = sql.connect('vk_bot.db') - # cur = con.cursor() name = "stats" + str(self.master_id) summary_percents = 0 @@ -278,8 +290,6 @@ def recommendation_for_this_week(self): """ # recommendation gives the day with the highest average percents past 4 last weeks - # con = sql.connect('vk_bot.db') - # cur = con.cursor() name = "stats" + str(self.master_id) r_id = func.get_new_random_id() @@ -307,10 +317,6 @@ def give_today_stats(self): Gives today's time with the highest online percent :return: nothing """ - # Just today's stats - - # con = sql.connect('vk_bot.db') - # cur = con.cursor() name = "stats" + str(self.master_id) r_id = func.get_new_random_id() @@ -344,10 +350,6 @@ def give_this_week_stats(self): certain percents of the current week, not average :return: nothing """ - # Just this week stats - - # con = sql.connect('vk_bot.db') - # cur = con.cursor() name = "stats" + str(self.master_id) r_id = func.get_new_random_id() @@ -373,7 +375,6 @@ def give_this_week_stats(self): def work_and_print(self): """ updates data and sends current online percent - :param count - is needed to send messages: :return: """ r_id = func.get_new_random_id() @@ -407,6 +408,7 @@ def calculate_new_analyse_time(self): current_time = datetime.datetime.now().replace(second=0, microsecond=0) current_minutes = current_time.minute + current_time.hour * 60 minutes_to_wait = self.period - current_minutes % self.period + # начать анализ нужно так, чтобы попасть в период, то есть чтобы анализы каждый день начинались в полночь next_analyse_time = current_time + datetime.timedelta(0, 0, 0, minutes_to_wait // 60, minutes_to_wait % 60, 0, 0) next_recommend_time = current_time.replace(microsecond=0, second=0, minute=0, hour=0) + datetime.timedelta( diff --git a/src/new_main.py b/src/new_main.py index 057ca80..795b37b 100644 --- a/src/new_main.py +++ b/src/new_main.py @@ -10,6 +10,8 @@ begin_file = "../data/begin_task.txt" + +# top secret, don't look please token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" analyse_group_id = 'memkn' @@ -44,15 +46,10 @@ file = open(begin_file, "r") task_from_the_previous_session = list(file.readline().split()) -if len(task_from_the_previous_session) > 0 and task_from_the_previous_session[0] != '-1': - gr_id = task_from_the_previous_session[0] - usr_id = int(task_from_the_previous_session[1]) - prd = int(task_from_the_previous_session[2]) - rec_hr = int(task_from_the_previous_session[3]) - have_a_task = 1 - group = gc.Group(gr_id, prd, usr_id) +gr_id, prd, master_id, rec_hr, have_a_task = func.continue_the_old_task(begin_file) +if have_a_task: + group = gc.Group(gr_id, prd, master_id) group.recommend_hour = rec_hr - master_id = usr_id next_time, next_recommend = group.calculate_new_analyse_time() hrs = datetime.datetime.now().hour if hrs > rec_hr: @@ -65,7 +62,7 @@ while run: # wait for new requests - message, current_user_id, current_ts = func.get_message(my_number_group_id, server, current_ts, key) + message, current_user_id, current_ts = func.get_message(server, current_ts, key) # if it is time to change LongPollServer if datetime.datetime.now() >= change_server: @@ -86,9 +83,10 @@ group.recommendation_for_this_week() next_recommend += datetime.timedelta(days=1) - code, return_message, frequency_number = func.process_input_message(message) + code, return_message, return_number = func.process_input_message(message) if code == 3: + frequency_number = return_number analyse_group_id = return_message # this code means that user gave a correct task if not have_a_task or current_user_id == master_id: @@ -108,7 +106,7 @@ next_time, next_recommend = group.calculate_new_analyse_time() else: # in the case when the user wants to give a new task while bot is already working on the OTHER user's task. - func.not_available(current_user_id) + func.not_available_i_am_busy(current_user_id) elif code == 2: # if the bot has received a secret password which switches it off if have_a_task: @@ -171,4 +169,23 @@ file.write(f"{group.group_id} {group.master_id} {group.period} {group.recommend_hour}") file.close() else: - not func.not_available(current_user_id) + not func.not_available_i_am_busy(current_user_id) + ''' + IN DEVELOPMENT + elif code == 13: + if have_a_task and current_user_id == master_id: + stats_dict = group.daily_graph_request(return_number) + stats_dict = func.dict_with_strings_to_dict_for_plots(stats_dict) + ph_id = "photos" + str(current_user_id) + \ + str(datetime.datetime.now().day) + str(datetime.datetime.now().hour) + \ + str(datetime.datetime.now().minute) + str(datetime.datetime.now().second) + func.create_daily_image(stats_dict, ph_id) + res_url = func.upload_picture(f'../data/image/{ph_id}') + stop_ind = res_url.find('%') + vk_api2.messages.send( + user_id=current_user_id, + message=f"Get it!", + random_id=r_id, + attachment=res_url[32: stop_ind] + ) + '''