From b7cf9a68857a2217005b09376e7ece9955a5c16f Mon Sep 17 00:00:00 2001 From: Noretsa Date: Tue, 8 Sep 2020 17:51:24 +0300 Subject: [PATCH] =?UTF-8?q?new=20knd=5Fbot;=20=D1=80=D0=B0=D0=B7=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BA=D0=B8=20=D1=84=D0=BE=D1=82=D0=BE=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D1=8A=D0=B5=D0=B7=D0=B4=D0=B0=D0=BC=20=D0=B8?= =?UTF-8?q?=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classes/__init__.py | 0 classes/create_photo.py | 244 ++++++++++++++++ classes/desinfection.py | 74 +++++ classes/proverka.py | 137 +++++++++ classes/users.py | 27 ++ data/Oksana-d2007@yandex.ru/img_5.txt | 3 + data/Oksana-d2007@yandex.ru/new_template.docx | Bin 0 -> 9356 bytes data/Oksana-d2007@yandex.ru/pass.txt | 1 + des.py | 264 +++++++++++++++++ knd_bot.py | 263 +++++++++++++++++ knd_bot_assigned.py | 268 ++++++++++++++++++ new_template.docx | Bin 0 -> 9225 bytes requirements.txt | 13 + 13 files changed, 1294 insertions(+) create mode 100644 classes/__init__.py create mode 100644 classes/create_photo.py create mode 100644 classes/desinfection.py create mode 100644 classes/proverka.py create mode 100644 classes/users.py create mode 100644 data/Oksana-d2007@yandex.ru/img_5.txt create mode 100644 data/Oksana-d2007@yandex.ru/new_template.docx create mode 100644 data/Oksana-d2007@yandex.ru/pass.txt create mode 100644 des.py create mode 100644 knd_bot.py create mode 100644 knd_bot_assigned.py create mode 100644 new_template.docx create mode 100644 requirements.txt diff --git a/classes/__init__.py b/classes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/classes/create_photo.py b/classes/create_photo.py new file mode 100644 index 0000000..f66ca43 --- /dev/null +++ b/classes/create_photo.py @@ -0,0 +1,244 @@ +from datetime import datetime, timedelta +import os +import shutil + +from docx import Document +from docx.text.paragraph import Paragraph +from docx.shared import Inches, Pt, RGBColor +from docx.enum.style import WD_STYLE_TYPE + +import sys +import subprocess +import re + +from random import randint +import random + +from pathlib import Path + + +from pdf2image import convert_from_path + +from PIL import Image, ImageFilter, ImageDraw + +from PIL.ImageFilter import ( + BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, + EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, SHARPEN +) + + +def convert_to(folder, source, timeout=None): + args = [libreoffice_exec(), '--headless', '--convert-to', 'pdf', '--outdir', folder, source] + process = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + filename = re.search('-> (.*?) using filter', process.stdout.decode()) + return filename.group(1) + + +def libreoffice_exec(): + # TODO: Provide support for more platforms + if sys.platform == 'darwin': + return '/Applications/LibreOffice.app/Contents/MacOS/soffice' + elif sys.platform == 'win32': + # you need to add libreoffice to path + return 'soffice.exe' + return 'libreoffice' + + +def create_photo(address, user): + month = datetime.now().month + info = get_info(user) + path_to_template = os.path.join(os.path.abspath('.'), 'data', user) + template_docx = os.path.join(path_to_template, 'new_template.docx') + if len(info) > 0: + if not os.path.exists(template_docx): + # print(f"Копируем шаблоны графиков в {user}") + template_in_user = shutil.copyfile('new_template.docx', template_docx) + path_for_photo = os.path.join(path_to_template, str(month), address) + photos = get_photo(address, user) + if len(photos) > 0: + # print(len(photos)) + if len(photos) > 7: + open_document(template_docx, True, info, address, path_for_photo, user) + else: + open_document(template_docx, False, info, address, path_for_photo, user) + return path_for_photo + else: + print(f"Нет фотографий по адресу {address}") + + +def get_info(user): + path = os.path.join(os.path.abspath('.'), 'data', user, 'img_5.txt') + if not os.path.exists(path): + print(f"Нет файла с информацией у пользователя {user}") + return [] + with open(path, 'r') as f: + fd = f.readlines() + return fd + + +def get_photo(address, email): + photos = [] + month = datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data', email, str(month), address) + if not os.path.exists(main_path): + print(f"Нет фотографий по адресу: {address}") + return photos + else: + for images in os.listdir(main_path): + if images.endswith(".jpg") or images.endswith(".jpeg") or images.endswith(".JPG"): + photos.append(main_path + '/' + images) + return photos + + +def open_document(filename, lift, info, address, path_for_photo, user): + # print(f"Наличие лифта по адресу: {address} - {lift}") + # print(f"Начинаем подготавливать график для {address}, шаблон {filename}") + row_for_sign = 0 + document = Document(filename) + styles = document.styles + tables = document.tables + date_now = datetime.today() + first_date = tables[0].rows[1].cells[0].text + first_date = datetime.strptime(first_date, '%d.%m.%y') + if datetime.now().date()-timedelta(12) > first_date.date(): + clear_table(tables, lift, styles, info) + row_for_sign = fill_table(tables) + document.save(filename) + else: + row_for_sign = fill_table(tables) + document.save(filename) + paragraphs = document.paragraphs + fill_info(paragraphs, styles, info, address, lift) + document.save(filename) + make_png_with_sign(filename, row_for_sign, lift, path_for_photo, user) + + +def make_png_with_sign(filename, row_for_sign, lift, path_for_photo, user): + # print(f"Создаем картинку из графика {filename}") + horizontal = 0 + if lift: + start_vertical = 780 + else: + start_vertical = 680 + result = convert_to('.', filename, timeout=15) + pages = convert_from_path(result, 200) + pages[0].save('template.png', 'PNG') + img2 = Image.open('template.png') + img2 = img2.convert("RGBA") + datas = img2.getdata() + newData = [] + for item in datas: + if item[0] == 255 and item[1] == 255 and item[2] == 255: + newData.append((255, 255, 255, 0)) + else: + # if item[0] > 120: + # newData.append((105, 105, 105, 255)) + # else: + newData.append(item) + img2.putdata(newData) + while (row_for_sign+1) > 0: + # if lift: + # horizontal = randint(1320, 1450) + # else: + horizontal = randint(1320, 1450) + vertical = start_vertical + ((row_for_sign) * 100) + # clear_background('my_sign.png') + sign = Image.open(os.path.join(os.path.abspath('.'), 'data', user, 'sign.png')) + width, height = sign.size + sign = sign.resize((int(width*1.5), int(height*1.5))) + # print(horizontal) + img2.paste(sign, (horizontal, vertical), sign) # vertical step = 150 + row_for_sign -= 1 + img2.save('template.png', "PNG") + add_image_to_image('template.png', 'fon2.png', path_for_photo) + + +def add_image_to_image(filename, filename_fon, dst_folder): + # print(f"Накладываем график {filename} на фон") + left = randint(0, 140) + upper = randint(0, 85) + w_rand = random.uniform(0.8, 1) + b_rand = random.uniform(0.5, 0.8) + try: + angle = 0 + # img = img.filter(ImageFilter.GaussianBlur(radius=1)) + background = Image.open(filename_fon) + foreground = Image.open(filename) + width, height = foreground.size + size = int(width*0.25), int(height*0.25) + width_b, height_b = background.size + foreground = foreground.resize(size).rotate(angle) + background.paste(foreground, (195, 290), foreground) + background = background.crop((left, upper, width_b*w_rand, height_b*w_rand)) + background = background.filter(ImageFilter.GaussianBlur(radius=b_rand)) + background.save(os.path.join(dst_folder, 'graph.jpg')) + # print(os.path.join(dst_folder, 'graph.jpg')) + # print(os.path.dirname(dst_folder)) + except IOError: + print(sys.exc_info()[0]) + pass + + +def delete_paragraph(paragraph): + p = paragraph._element + p.getparent().remove(p) + p._p = p._element = None + + +def clear_table(tables, lift, styles, info): + # print(f"Очищаем таблицу в графике") + fio = info[0].split('\n')[0] + count = 0 + while count < len(tables[0].rows)-1: + date_to_add = datetime.now().date()+timedelta(count) + delete_paragraph(tables[0].rows[count+1].cells[0].paragraphs[0]) + delete_paragraph(tables[0].rows[count+1].cells[2].paragraphs[0]) + par = tables[0].rows[count+1].cells[0].add_paragraph() + par_fio = tables[0].rows[count+1].cells[2].add_paragraph() + p = par.add_run(datetime.strftime(date_to_add, '%d.%m.%y')) + p_fio = par_fio.add_run(fio) + par_fio.alignment = 1 + p_fio.bold = True + p.bold = True + font = p.font + count += 1 + + +def fill_table(tables): + # print("Заполняем таблицу в графике") + r_count = 0 + count = 0 + while count < len(tables[0].rows)-1: + date_in_cell = tables[0].rows[count+1].cells[0].text + date_in_cell = datetime.strptime(date_in_cell, '%d.%m.%y') + if date_in_cell.date() == datetime.now().date(): + r_count = count + count += 1 + return r_count + + +def fill_info(paragraphs, styles, info, address, lift): + # print(f"Заполняем шапку графика в {address}") + fio = info[0].split('\n')[0] + dol = info[1].split('\n')[0] + phone_number = info[2].split('\n')[0] + for paragraph in paragraphs: + name_style = paragraph.style.name + if 'по адресу:' in paragraph.text: + # p = paragraph.insert_paragraph_before() + style = styles[name_style] + style.font.size = Pt(14) + paragraph.text = '' + p = paragraph.add_run('по адресу: '+address[:-4]+' Подъезд № ' + address[-2]) + p.bold = True + font = p.font + font.color.rgb = RGBColor(128, 128, 128) + paragraph.style = styles[name_style] + elif 'Должность:' in paragraph.text: + paragraph.text = '' + if lift: + text_for_perechen = 'Перечень обрабатываемых объектов:\n - Первые этажи подъездов: полы, дверные и оконные ручки, почтовые ящики, панели домофонов и кодовых замков, перила лестничных маршей\n - Лифтовые кабины: напольные покрытия, панели управления лифтами, лифтовые вентиляционные решетки' + else: + text_for_perechen = 'Перечень обрабатываемых объектов:\n - Первые этажи подъездов: полы, дверные и оконные ручки, почтовые ящики, панели домофонов и кодовых замков, перила лестничных маршей' + run = paragraph.add_run(' Должность: ' + dol +' Ф.И.О.: ' + fio + '\n тел: ' + phone_number + '\n' + text_for_perechen) + font = run.font diff --git a/classes/desinfection.py b/classes/desinfection.py new file mode 100644 index 0000000..874012e --- /dev/null +++ b/classes/desinfection.py @@ -0,0 +1,74 @@ +import classes.create_photo as cr_photo +import os +import time + + +def assign_task(session, headers, task, address): + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/assign' + task_assign = session.put(url, headers=headers) + if task_assign.status_code == 200: + print(f'Получили задание по адресу: {address}') + complete_task(session, headers, task, address) + else: + print(f"Не смогли получить задание {address} {task['id']}!") + +def complete_task(session, headers, task, address): + photo_path = os.path.join(cr_photo.create_photo(address, headers['uid']), 'graph.jpg') + id_task = task['id'] + # questions = get_questions(id_task, session, headers) + question_components = [] + yes_no = {"id": 23384, "position": 0, "answer": 77, "start_time": int(time.time())} + time.sleep(2) + yes_no.update({"end_time": int(time.time())}) + question_components.append(yes_no) + if not os.path.exists(photo_path): + print(f"Нет фотографии графика по адресу {address}") + else: + img = send_image(session, headers, task['id'], photo_path)#photos.pop(0)) + image_graph = {"id": 23385, "position": 1, "answer": [img['id']], "start_time": int(time.time())} + time.sleep(2) + image_graph.update({"end_time": int(time.time())}) + question_components.append(image_graph) + questions = [{"id": 7956, "question_components": question_components, "position": 0}] + question_chains = [{"id": 7396, "questions": questions}] + ans = {"question_chains": question_chains} + session_t = session + session_t.headers.update( + { + 'referer': 'https://knd.mosreg.ru/executions'+str(task['id'])+'/solve', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + complete = session_t.post('https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/answers', headers=headers, json=ans) + if complete.status_code == 200: + print(f'Задание по адресу {address} выполнено успешно!\n\n') + else: + print(f'Задание по адресу {address} не выполненно! Статус ошибки {complete.status_code}\n\n') + + + +def send_image(session, headers, url, photo): + """Отправляем фото на сервер. Сервер должен вернуть id и url.""" + files = { + 'image': (photo[-5:], open(photo, 'rb')), + } + # print(files) + img = session.post('https://knd.mosreg.ru//api/v1/executions/'+str(url)+'/images', headers=headers, files=files) + if img.status_code == 200: + print(f"Фото {photo} успешно отправлено") + return img.json() + else: + print(f"Не удалось загрузить фото на сервер по заданию {url}, статус ошибки {img.status_code}! Повторная попытка!") + second_img = send_image(session, headers, url, photo) + return second_img + + +# def get_questions(id_task, session, headers): +# url = 'https://knd.mosreg.ru//api/v1/executions/'+str(id_task)+'/questions' +# questions = session.get(url, headers=headers) +# json_quest = questions.json() +# chain = json_quest['question_chains'][0].get('questions') +# print(chain[0].get('question_components')) +# return json_quest['selected_chains'] + diff --git a/classes/proverka.py b/classes/proverka.py new file mode 100644 index 0000000..291de2a --- /dev/null +++ b/classes/proverka.py @@ -0,0 +1,137 @@ +import os +import datetime +import time + + +def assign_task(session, headers, task, address): + # print('assign_task') + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/assign' + task_assign = session.put(url, headers=headers) + if task_assign.status_code == 200: + print(f'Получили задание по адресу: {address}') + complete_task(session, headers, task, address) + else: + print(f"Не смогли получить задание {address} {task['id']}!") + + +def complete_task(session, headers, task, address): + photos = get_photo(address, headers['uid']) + if len(photos) > 0: + photos.sort() + """В папке лежит фото графика, которое отправляется из модуля des, поэтому убираем отсюда""" + if len(photos) == 7 or len(photos) == 9: + photos.pop() + id_task = task['id'] + quest = get_questions(id_task, session, headers) + length_question = get_length_questions(quest) + prepared_answers = [] + if len(photos) == length_question: + prepared_answers = prepare_answer(quest, photos, session, task, headers) + ans = {"question_chains": prepared_answers} + # print(ans) + session_t = session + session_t.headers.update( + { + 'referer': 'https://knd.mosreg.ru/executions'+str(task['id'])+'/solve', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + complete = session_t.post('https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/answers', headers=headers, json=ans) + if complete.status_code == 200: + print(f'Задание по адресу {address} выполнено успешно!\n\n') + else: + print(f'Задание по адресу {address} не выполненно! Статус ошибки {complete.status_code}\n\n') + else: + print(f"\n\n\nНесоответствие количества вопросов и фотографий по адресу {address}!!! \ + Необходимо проверить!!!\n\n\n") + # print(len(quest)) 9 and 13 + + +def get_length_questions(quest): + count = 0 + for main_chain in quest: + for second_chain in main_chain['questions']: + for third_chain in second_chain['question_components']: + question_type = third_chain['type'] + if question_type == "gallery": + count = count + 1 + return count + + +def prepare_answer(quest, photos, session, task, headers): + questions = [] + question_components= [] + question_chains = [] + for main_chain in quest: + for second_chain in main_chain['questions']: + for third_chain in second_chain['question_components']: + question_type = third_chain['type'] + if question_type == 'list': + data = {"id": third_chain['id'], "answer": 77, "answer_status": None, "start_time": int(time.time())} + time.sleep(2) + data.update({"end_time": int(time.time())}) + question_components.append(data) + elif question_type == "geo": + data = {"id": third_chain['id'], "answer": {"location": task['coord']}, "answer_status": None, \ + "start_time": int(time.time())} + time.sleep(2) + data.update({"end_time": int(time.time())}) + question_components.append(data) + elif question_type == "gallery": + img = send_image(session, headers, task['id'], photos.pop(0))#photos.pop(0)) + data = {"id": third_chain['id'], "answer": [img['id']], "answer_status": None, \ + "start_time": int(time.time())} + time.sleep(2) + data.update({"end_time": int(time.time())}) + question_components.append(data) + if len(question_components) > 0: + main_data = { + "id": second_chain['id'], + "question_components": question_components + } + questions.append(main_data) + question_components = [] + if len(questions) > 0: + q_dict = { + "id": main_chain['id'], + "questions" : questions + } + question_chains.append(q_dict) + questions = [] + return question_chains + + +def get_photo(address, email): + photos = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data', email, str(month), address) + if not os.path.exists(main_path): + return photos + else: + for images in os.listdir(main_path): + if images.endswith(".jpg") or images.endswith(".jpeg") or images.endswith(".JPG"): + photos.append(main_path + '/' + images) + return photos + + +def get_questions(id_task, session, headers): + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(id_task)+'/questions' + questions = session.get(url, headers=headers) + json_quest = questions.json() + return json_quest['selected_chains'] + + +def send_image(session, headers, url, photo): + """Отправляем фото на сервер. Сервер должен вернуть id и url.""" + files = { + 'image': (photo[-5:], open(photo, 'rb')), + } + img = session.post('https://knd.mosreg.ru//api/v1/executions/'+str(url)+'/images', headers=headers, files=files) + if img.status_code == 200: + print(f"Фото {photo} успешно отправлено") + return img.json() + else: + print(f"Не удалось загрузить фото на сервер по заданию {url}, статус ошибки {img.status_code}! Повторная попытка!") + second_img = send_image(session, headers, url, photo) + return second_img diff --git a/classes/users.py b/classes/users.py new file mode 100644 index 0000000..f6168b2 --- /dev/null +++ b/classes/users.py @@ -0,0 +1,27 @@ +import os + + +class Users: + def __init__(self): + self.data = [] + self.path = os.path.join(os.path.abspath('.'), 'data') + + def get_users(self): + self.logins = [] + main_dir = os.walk(self.path) + for d, dirs, files in main_dir: + self.logins.append(dirs) + return self.logins[0] + + def get_passwords(self): + if not os.path.exists(self.path): + return "Папка data не существует. Создайте папку с необходимыми параметрами и запустите программу снова!" + self.emails = self.get_users() + if len(self.emails) > 0: + for user in self.emails: + with open(os.path.join(self.path, user, 'pass.txt'), 'r') as f: + log_pass = {'email': user, 'password': f.readline().split('\n')[0]} + self.data.append(log_pass) + else: + return "Нет ни одного пользователя! Заполните папку и запустите программу снова!" + return self.data diff --git a/data/Oksana-d2007@yandex.ru/img_5.txt b/data/Oksana-d2007@yandex.ru/img_5.txt new file mode 100644 index 0000000..c2f7583 --- /dev/null +++ b/data/Oksana-d2007@yandex.ru/img_5.txt @@ -0,0 +1,3 @@ +Драченко Оксана Владимировна +начальник РЭУ +8(985)574-77-92 diff --git a/data/Oksana-d2007@yandex.ru/new_template.docx b/data/Oksana-d2007@yandex.ru/new_template.docx new file mode 100644 index 0000000000000000000000000000000000000000..eb401fd6d6b55ebf3612a4ed3ba749079edb7aeb GIT binary patch literal 9356 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
    l1(Qb5J$suk8P$ zRy+nj=Hh?AO!)r-|BabHMn7hdf6z4q|0()^_~c{sW8(7%EkN`y^kW*NDEkD;lmGxU OsNF!jm 0: +# photos.sort() +# print(task['id']) +# id_task = task['id'] +# questions = get_questions(id_task, session, headers) +# data = [] +# for answers in questions: +# answer_chain = { +# 'id': answers['id'], +# 'questions': [] # answers['questions'] +# } +# if answer_chain['id'] == 6146: # Цепочка без ответов +# continue +# for components in answers['questions']: +# comp = [] +# q_c = { +# 'id': components['id'], +# 'question_components': [] +# } +# if q_c['id'] == 6560: # Вопрос без ответа +# continue +# comp.append(q_c) +# answer_chain.update({'questions': comp}) +# data.append(answer_chain) +# if len(data) == len(photos): +# for chain in data: +# for item in chain['questions']: +# if len(data) == len(photos): +# photo_from_photos = photos.pop(0) +# img = send_image(session, headers, task['id'], photo_from_photos) # photos.pop(0)) +# # count_send_photo = 0 +# # while img['id'] is None: +# # count_send_photo += 1 +# # print("Попытка № " + str(count_send_photo) + "отправить фото" + str(photo_from_photos)) +# # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) +# first = {"id": 18850, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} +# time.sleep(2) +# first.update({'end_time': int(time.time())}) +# second = {"id": 18851, "answer": {"location": task['coord']}, 'answer_status': None, 'start_time': int(time.time())} +# time.sleep(2) +# second.update({'end_time': int(time.time())}) +# item['question_components'].append(first) +# item['question_components'].append(second) +# else: +# # img = send_image(session, headers, task['id'], photos.pop(0)) +# photo_from_photos = photos.pop(0) +# img = send_image(session, headers, task['id'], photo_from_photos) # photos.pop(0)) +# # count_send_photo = 0 +# # while img['id'] is None: +# # count_send_photo += 1 +# # print("Попытка № " + str(count_send_photo) + " отправить фото" + str(photo_from_photos)) +# # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) +# first = {"id": 18856, "answer": 77, 'answer_status': None, 'start_time': int(time.time())} +# time.sleep(2) +# first.update({'end_time': int(time.time())}) +# second = {"id": 18857, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} +# time.sleep(2) +# second.update({'end_time': int(time.time())}) +# item['question_components'].append(first) +# item['question_components'].append(second) +# ans = {"question_chains": data} +# # print(ans) +# session_t = session +# session_t.headers.update( +# { +# 'referer': 'https://knd.mosreg.ru/executions'+str(task['id'])+'/solve', +# 'x-platform': 'wb', +# 'accept': '*/*' +# } +# ) +# complete = session_t.post('https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/answers', headers=headers, json=ans) +# if complete.status_code == 200: +# print(f'Задание по адресу {address} выполнено успешно!') +# else: +# print(f'Задание по адресу {address} не выполненно! Статус ошибки {complete.status_code}') +# else: +# print(f"Несоответствие количества вопросов и количества фотографий по адресу: {address}") +# # send_execution(task,session, headers) + + +def get_photo(address, email): + photos = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data', email, str(month), address) + if not os.path.exists(main_path): + return photos + else: + for images in os.listdir(main_path): + if images.endswith(".jpg") or images.endswith(".jpeg") or images.endswith(".JPG"): + photos.append(main_path + '/' + images) + return photos + + +def get_addresses(email): + addresses = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data') + path = os.walk(os.path.join(main_path, email, str(month))) + if not os.path.exists(os.path.join(main_path, email, str(month))): + return f"Не найдена папка с месяцем у пользователя {email}! Проверьте структуру каталога!" + for d, dirs, files in path: + addresses.append(dirs) + if len(addresses[0]) > 0: + return addresses[0] + else: + return f"Ни одного адреса для пользователя {email} не найдено! Добавьте фото и запустите программу снова!" + + +# def assign_task(session, headers, task, address): +# url = 'https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/assign' +# task_assign = session.put(url, headers=headers) +# if task_assign.status_code == 200: +# print(f'Получили задани по адресу: {address}') +# complete_task(session, headers, task, address) +# else: +# print(f"Не смогли получить задание {address} {task['id']}!") + + +def get_task(session, headers): + """Получаем все доступные задания. Если в переменную search добавить адрес, + то будет искать этот адрес. Он попадет в + json_tasks['executions_available'], + так что надо понять откуда берем задания. Отсюда можно возвращать + все параметры задания: + 1 координаты + 2 адрес + 3 подъезд + 4 id_задания""" + desinfection = 'Дезинфекция подъездов (МОП)' + proverka = 'Систематическая проверка подъездов МКД' + # Получаем адреса + addresses = get_addresses(headers['uid']) + # Если адреса получили + if isinstance(addresses, list): + session_t = session + session_t.headers.update( + {'referer': 'https://knd.mosreg.ru/executions', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + for address in addresses: + # change '-' for '/' + # need split enterance from address + addr = address.replace("Чаиковского", "Чайковского") + addr = address.replace("Маиданово", "Майданово") + search = addr.replace("_", "/")[:-4] + # print(search) + data = {'search': search} + tasks = session_t.post('https://knd.mosreg.ru//api/v1/executions', + headers=headers, + data=data + ) + json_tasks = tasks.json() + # get_t = False + # Если есть доступное задание с таким адресом + exec_assigned = json_tasks['executions_assigned'] # Уже полученные задания + exec_available = json_tasks['executions_available'] # Еще не принятые задания + # print(address) + if len(exec_available) > 0: + for n in exec_available: + coord = n['coord'] + enterances = n['tasks'] + for execution in enterances: + address_from_tasks = execution['dimensions'][0].get('entity_value_name') + name_from_tasks = execution['name'] + enterance = execution['dimensions'][2].get('entity_value_name') + if address_from_tasks == 'Клин г, ' + addr.replace("_", "/")[:-4] and \ + enterance[-1] == address[-2]: + print('\n') + print(name_from_tasks) + print('\n') + task = { + 'id': execution['execution_id'], + 'address': execution['dimensions'][0].get('entity_value_name'), + 'enterance': execution['dimensions'][2].get('entity_value_name'), + 'coord': coord + } + if name_from_tasks == desinfection: + des.assign_task(session, headers, task, address) + elif name_from_tasks == proverka: + pass + # prov.assign_task(session, headers, task, address) + else: + pass + else: + print(f"Нет доступных заданий для пользователя {headers['uid']} по адресу: {address}") + # Если адреса не получили выводим ошибку + else: + print(addresses) + + +def main(): + users = Users() + logins = users.get_passwords() + if isinstance(logins, list): + url = 'https://knd.mosreg.ru//api/v1/auth/sign_in' + for user in logins: + session = requests.Session() + login = { + 'email': user['email'], + 'password': user['password'] + } + response = session.post(url, data=login) + headers = { + 'client': response.headers.get('client'), + 'Access-token': response.headers.get('Access-token'), + 'uid': response.headers.get('uid'), + } + if response.status_code == 200: + get_task(session, headers) + else: + print(f"Отказ в авторизации для пользователя {user['email']}!") + time.sleep(1) + else: + print(users.get_passwords()) + + +if __name__ == "__main__": + main() + k = input("Press ENTER for exit") + + +def random_string(stringLength): + letters = string.ascii_letters + digits = string.digits + return ''.join(random.choice(letters+digits) for i in range(stringLength)) diff --git a/knd_bot.py b/knd_bot.py new file mode 100644 index 0000000..f1dc33a --- /dev/null +++ b/knd_bot.py @@ -0,0 +1,263 @@ +import requests +import random +import string +# import json +import datetime +import time +import os +from classes.users import Users +import classes.desinfection as des +import classes.proverka as prov + + +def get_questions(id_task, session, headers): + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(id_task)+'/questions' + questions = session.get(url, headers=headers) + json_quest = questions.json() + return json_quest['selected_chains'] + + +def send_image(session, headers, url, photo): + """Отправляем фото на сервер. Сервер должен вернуть id и url.""" + files = { + 'image': (photo[-5:], open(photo, 'rb')), + } + # print(files) + img = session.post('https://knd.mosreg.ru//api/v1/executions/'+str(url)+'/images', headers=headers, files=files) + if img.status_code == 200: + print(f"Фото {photo} успешно отправлено") + return img.json() + else: + print(f"Не удалось загрузить фото на сервер по заданию {url}, статус ошибки {img.status_code}! Повторная попытка!") + second_img = send_image(session, headers, url, photo) + return second_img + + +def complete_task(session, headers, task, address): + photos = get_photo(address, headers['uid']) + if len(photos) > 0: + photos.sort() + print(task['id']) + id_task = task['id'] + questions = get_questions(id_task, session, headers) + data = [] + for answers in questions: + answer_chain = { + 'id': answers['id'], + 'questions': [] # answers['questions'] + } + if answer_chain['id'] == 6146: # Цепочка без ответов + continue + for components in answers['questions']: + comp = [] + q_c = { + 'id': components['id'], + 'question_components': [] + } + if q_c['id'] == 6560: # Вопрос без ответа + continue + comp.append(q_c) + answer_chain.update({'questions': comp}) + data.append(answer_chain) + if len(data) == len(photos): + for chain in data: + for item in chain['questions']: + if len(data) == len(photos): + photo_from_photos = photos.pop(0) + img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + # count_send_photo = 0 + # while img['id'] is None: + # count_send_photo += 1 + # print("Попытка № " + str(count_send_photo) + "отправить фото" + str(photo_from_photos)) + # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + first = {"id": 18850, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + first.update({'end_time': int(time.time())}) + second = {"id": 18851, "answer": {"location": task['coord']}, 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + second.update({'end_time': int(time.time())}) + item['question_components'].append(first) + item['question_components'].append(second) + else: + #img = send_image(session, headers, task['id'], photos.pop(0)) + photo_from_photos = photos.pop(0) + img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + # count_send_photo = 0 + # while img['id'] is None: + # count_send_photo += 1 + # print("Попытка № " + str(count_send_photo) + " отправить фото" + str(photo_from_photos)) + # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + first = {"id": 18856, "answer": 77, 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + first.update({'end_time': int(time.time())}) + second = {"id": 18857, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + second.update({'end_time': int(time.time())}) + item['question_components'].append(first) + item['question_components'].append(second) + ans = {"question_chains": data} + # print(ans) + session_t = session + session_t.headers.update( + { + 'referer': 'https://knd.mosreg.ru/executions'+str(task['id'])+'/solve', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + complete = session_t.post('https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/answers', headers=headers, json=ans) + if complete.status_code == 200: + print(f'Задание по адресу {address} выполнено успешно!') + else: + print(f'Задание по адресу {address} не выполненно! Статус ошибки {complete.status_code}') + else: + print(f"Несоответствие количества вопросов и количества фотографий по адресу: {address}") +# send_execution(task,session, headers) + + +def get_photo(address, email): + photos = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data', email, str(month), address) + if not os.path.exists(main_path): + return photos + else: + for images in os.listdir(main_path): + if images.endswith(".jpg") or images.endswith(".jpeg") or images.endswith(".JPG"): + photos.append(main_path + '/' + images) + return photos + + +def get_addresses(email): + addresses = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data') + path = os.walk(os.path.join(main_path, email, str(month))) + if not os.path.exists(os.path.join(main_path, email, str(month))): + return f"Не найдена папка с месяцем у пользователя {email}! Проверьте структуру каталога!" + for d, dirs, files in path: + addresses.append(dirs) + if len(addresses[0]) > 0: + return addresses[0] + else: + return f"Ни одного адреса для пользователя {email} не найдено! Добавьте фото и запустите программу снова!" + + +# def assign_task(session, headers, task, address): +# url = 'https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/assign' +# task_assign = session.put(url, headers=headers) +# if task_assign.status_code == 200: +# print(f'Получили задани по адресу: {address}') +# complete_task(session, headers, task, address) +# else: +# print(f"Не смогли получить задание {address} {task['id']}!") + + +def get_task(session, headers): + """Получаем все доступные задания. Если в переменную search добавить адрес, + то будет искать этот адрес. Он попадет в + json_tasks['executions_available'], + так что надо понять откуда берем задания. Отсюда можно возвращать + все параметры задания: + 1 координаты + 2 адрес + 3 подъезд + 4 id_задания""" + desinfection = 'Дезинфекция подъездов (МОП)' + proverka = 'Систематическая проверка подъездов МКД' + # Получаем адреса + addresses = get_addresses(headers['uid']) + # Если адреса получили + if isinstance(addresses, list): + session_t = session + session_t.headers.update( + {'referer': 'https://knd.mosreg.ru/executions', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + for address in addresses: + # change '-' for '/' + # need split enterance from address + addr = address.replace("Чаиковского", "Чайковского") + addr = address.replace("Маиданово", "Майданово") + search = addr.replace("_", "/")[:-4] + # print(search) + data = {'search': search} + tasks = session_t.post('https://knd.mosreg.ru//api/v1/executions', + headers=headers, + data=data + ) + json_tasks = tasks.json() + get_t = False + # Если есть доступное задание с таким адресом + exec_assigned = json_tasks['executions_assigned'] # Уже полученные задания + exec_available = json_tasks['executions_available'] # Еще не принятые задания + # print(address) + if len(exec_available) > 0: + for n in exec_available: + coord = n['coord'] + enterances = n['tasks'] + for execution in enterances: + address_from_tasks = execution['dimensions'][0].get('entity_value_name') + name_from_tasks = execution['name'] + enterance = execution['dimensions'][2].get('entity_value_name') + if address_from_tasks == 'Клин г, '+ addr.replace("_", "/")[:-4] and \ + enterance[-1] == address[-2]: + print('\n') + print(name_from_tasks) + print('\n') + task = { + 'id': execution['execution_id'], + 'address': execution['dimensions'][0].get('entity_value_name'), + 'enterance': execution['dimensions'][2].get('entity_value_name'), + 'coord': coord + } + if name_from_tasks == desinfection: + des.assign_task(session, headers, task, address) + elif name_from_tasks == proverka: + prov.assign_task(session, headers, task, address) + else: + pass + else: + print(f"Нет доступных заданий для пользователя {headers['uid']} по адресу: {address}") + # Если адреса не получили выводим ошибку + else: + print(addresses) + + +def main(): + users = Users() + logins = users.get_passwords() + if isinstance(logins, list): + url = 'https://knd.mosreg.ru//api/v1/auth/sign_in' + for user in logins: + session = requests.Session() + login = { + 'email': user['email'], + 'password': user['password'] + } + response = session.post(url, data=login) + headers = { + 'client': response.headers.get('client'), + 'Access-token': response.headers.get('Access-token'), + 'uid': response.headers.get('uid'), + } + if response.status_code == 200: + get_task(session, headers) + else: + print(f"Отказ в авторизации для пользователя {user['email']}!") + time.sleep(1) + else: + print(users.get_passwords()) + + +if __name__ == "__main__": + main() + k = input("Press ENTER for exit") + + +def random_string(stringLength): + letters = string.ascii_letters + digits = string.digits + return ''.join(random.choice(letters+digits) for i in range(stringLength)) diff --git a/knd_bot_assigned.py b/knd_bot_assigned.py new file mode 100644 index 0000000..80ae745 --- /dev/null +++ b/knd_bot_assigned.py @@ -0,0 +1,268 @@ +import requests +import random +import string +# import json +import datetime +import time +import os +from classes.users import Users + + +def get_questions(id_task, session, headers): + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(id_task)+'/questions' + questions = session.get(url, headers=headers) + json_quest = questions.json() + return json_quest['selected_chains'] + + +def send_image(session, headers, url, photo): + """Отправляем фото на сервер. Сервер должен вернуть id и url.""" + files = { + 'image': (photo[-5:], open(photo, 'rb')), + } + # print(files) + img = session.post('https://knd.mosreg.ru//api/v1/executions/'+str(url)+'/images', headers=headers, files=files) + if img.status_code == 200: + print(f"Фото {photo} успешно отправлено") + return img.json() + else: + print(f"Не удалось загрузить фото на сервер по заданию {url}, статус ошибки {img.status_code}! Повторная попытка!") + second_img = send_image(session, headers, url, photo) + return second_img + + +def complete_task(session, headers, task, address): + photos = get_photo(address, headers['uid']) + if len(photos) > 0: + photos.sort() + print(task['id']) + id_task = task['id'] + questions = get_questions(id_task, session, headers) + data = [] + for answers in questions: + answer_chain = { + 'id': answers['id'], + 'questions': []#answers['questions'] + } + if answer_chain['id'] == 6146: # Цепочка без ответов + continue + for components in answers['questions']: + comp = [] + q_c = { + 'id': components['id'], + 'question_components': [] + } + if q_c['id'] == 6560: # Вопрос без ответа + continue + comp.append(q_c) + answer_chain.update({'questions': comp}) + data.append(answer_chain) + if len(data) == len(photos): + for chain in data: + for item in chain['questions']: + if len(data) == len(photos): + photo_from_photos = photos.pop(0) + img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + # count_send_photo = 0 + # while img['id'] is None: + # count_send_photo += 1 + # print("Попытка № " + str(count_send_photo) + "отправить фото" + str(photo_from_photos)) + # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + first = {"id": 18850, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + first.update({'end_time': int(time.time())}) + second = {"id": 18851, "answer": {"location": task['coord']}, 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + second.update({'end_time': int(time.time())}) + item['question_components'].append(first) + item['question_components'].append(second) + else: + #img = send_image(session, headers, task['id'], photos.pop(0)) + photo_from_photos = photos.pop(0) + img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + # count_send_photo = 0 + # while img['id'] is None: + # count_send_photo += 1 + # print("Попытка № " + str(count_send_photo) + " отправить фото" + str(photo_from_photos)) + # img = send_image(session, headers, task['id'], photo_from_photos)#photos.pop(0)) + first = {"id": 18856, "answer": 77, 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + first.update({'end_time': int(time.time())}) + second = {"id": 18857, "answer": [img['id']], 'answer_status': None, 'start_time': int(time.time())} + time.sleep(2) + second.update({'end_time': int(time.time())}) + item['question_components'].append(first) + item['question_components'].append(second) + ans = {"question_chains": data} + # print(ans) + session_t = session + session_t.headers.update( + { + 'referer': 'https://knd.mosreg.ru/executions'+str(task['id'])+'/solve', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + complete = session_t.post('https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/answers', headers=headers, json=ans) + if complete.status_code == 200: + print(f'Задание по адресу {address} выполнено успешно!') + else: + print(f'Задание по адресу {address} не выполненно! Статус ошибки {complete.status_code}') + else: + print(f"Несоответствие количества вопросов и количества фотографий по адресу: {address}") +# send_execution(task,session, headers) + + +def get_photo(address, email): + photos = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data', email, str(month), address) + if not os.path.exists(main_path): + return photos + else: + for images in os.listdir(main_path): + if images.endswith(".jpg") or images.endswith(".jpeg") or images.endswith(".JPG"): + photos.append(main_path + '/' + images) + return photos + + +def get_addresses(email): + addresses = [] + month = datetime.datetime.now().month + main_path = os.path.join(os.path.abspath('.'), 'data') + path = os.walk(os.path.join(main_path, email, str(month))) + if not os.path.exists(os.path.join(main_path, email, str(month))): + return f"Не найдена папка с месяцем у пользователя {email}! Проверьте структуру каталога!" + for d, dirs, files in path: + addresses.append(dirs) + if len(addresses[0]) > 0: + return addresses[0] + else: + return f"Ни одного адреса для пользователя {email} не найдено! Добавьте фото и запустите программу снова!" + + +def assign_task(session, headers, task, address): + url = 'https://knd.mosreg.ru//api/v1/executions/'+str(task['id'])+'/assign' + task_assign = session.put(url, headers=headers) + if task_assign.status_code == 200: + print(f'Получили задани по адресу: {address}') + complete_task(session, headers, task, address) + else: + print(f"Не смогли получить задание {address} {task['id']}!") + + +def get_task(session, headers): + """Получаем все доступные задания. Если в переменную search добавить адрес, + то будет искать этот адрес. Он попадет в + json_tasks['executions_available'], + так что надо понять откуда берем задания. Отсюда можно возвращать + все параметры задания: + 1 координаты + 2 адрес + 3 подъезд + 4 id_задания""" + # Получаем адреса + addresses = get_addresses(headers['uid']) + # Если адреса получили + if isinstance(addresses, list): + session_t = session + session_t.headers.update( + {'referer': 'https://knd.mosreg.ru/executions', + 'x-platform': 'wb', + 'accept': '*/*' + } + ) + for address in addresses: + # change '-' for '/' + # need split enterance from address + search = address.replace("_", "/")[:-4] + # print(search) + data = {'search': search} + tasks = session_t.post('https://knd.mosreg.ru//api/v1/executions', + headers=headers, + data=data + ) + json_tasks = tasks.json() + get_t = False + # Если есть доступное задание с таким адресом + exec_assigned = json_tasks['executions_assigned'] + exec_available = json_tasks['executions_available'] + if len(exec_assigned) > 0: + for n in exec_assigned: + coord = n['coord'] + enterances = n['tasks'] + for execution in enterances: + address_from_tasks = execution['dimensions'][0].get('entity_value_name') + # print(address_from_tasks) + # print('Клин г, '+address[:-4]) + enterance = execution['dimensions'][2].get('entity_value_name') + # print(enterance) + # print(address[-2]) + if address_from_tasks == 'Клин г, '+address.replace("_", "/")[:-4] and \ + enterance[-1] == address[-2]: + print(f'Начали выполнение задания по адресу: {address}') + task = { + 'id': execution['execution_id'], + 'address': execution['dimensions'][0].get('entity_value_name'), + 'enterance': execution['dimensions'][2].get('entity_value_name'), + 'coord': coord + } + # Принимаем задание + assign_task(session, headers, task, address) + get_t = True + else: + print(address_from_tasks + f" не соответствует адресу: {address}") + if not get_t: + print(f"Нет доступных заданий для по адресу: {address}!") + # Если нет задания с таким адресом + else: + print(f"Нет доступных заданий для пользователя {headers['uid']} по адресу: {address}") + # Если адреса не получили выводим ошибку + else: + print(addresses) + + +def main(): + users = Users() + logins = users.get_passwords() + if isinstance(logins, list): + url = 'https://knd.mosreg.ru//api/v1/auth/sign_in' + for user in logins: + session = requests.Session() + login = { + 'email': user['email'], + 'password': user['password'] + } + response = session.post(url, data=login) + headers = { + 'client': response.headers.get('client'), + 'Access-token': response.headers.get('Access-token'), + 'uid': response.headers.get('uid'), + } + if response.status_code == 200: + # task = { + # 'id': 23799105, + # 'address': 'Решетниково рп, ОПМС-1 проезд, 13', + # 'enterance': 6, + # 'coord': [56.442503, 36.5596493] + # } + # address = 'Решетниково рп, ОПМС-1 проезд, 13, 6п' + # assign_task(session, headers, task, address) + # break + get_task(session, headers) + else: + print(f"Отказ в авторизации для пользователя {user['email']}!") + time.sleep(1) + else: + print(users.get_passwords()) + + +if __name__ == "__main__": + main() + k = input("Press ENTER for exit") + + +def random_string(stringLength): + letters = string.ascii_letters + digits = string.digits + return ''.join(random.choice(letters+digits) for i in range(stringLength)) diff --git a/new_template.docx b/new_template.docx new file mode 100644 index 0000000000000000000000000000000000000000..afc908e8f155ea863788dbbde07f134f01e39cd4 GIT binary patch literal 9225 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..31c6640 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +certifi==2020.4.5.2 +chardet==3.0.4 +docx==0.2.4 +geographiclib==1.50 +idna==2.9 +lxml==4.5.2 +pdf2image==1.14.0 +Pillow==7.2.0 +python-docx==0.8.10 +requests==2.23.0 +requests-toolbelt==0.9.1 +six==1.15.0 +urllib3==1.25.9