Initial commit

parents
Включить inline mode у бота
\ No newline at end of file
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
class BotError(Exception):
pass
\ No newline at end of file
import os
API_TOKEN=os.environ['API_TOKEN']
mail_sender='bot@zolotoykod.ru'
mail_to='jondoll@yandex.ru'
mail_subject='mail from bot'
rm_user=os.environ['rm_user']
project_id=os.environ['project_id']
rm_url=os.environ['rm_url']
rm_pw=os.environ['rm_pw']
#MAIL_PARAMS = {'TLS': True, 'host': 'xxxxxxxx', 'password': 'xxxxxxxx', 'user': 'xxxxxxxx', 'port': 587}
operator_name=os.environ['operator_name']
from aiogram import types
from bot.handlers.form_state import Form
from bot.main import dp, bot
from bot.user import users
async def chat(message: types.Message, state):
operator_id=users[message.from_user.id].operator_id
await bot.send_message(operator_id
, f'{message.from_user.id}:{message.text}')
dp.register_message_handler(chat, state=Form.chat_start)
from aiogram.dispatcher.filters.state import StatesGroup, State
class Form(StatesGroup):
name = State()
phone = State()
object = State()
truble= State()
chat_ask=State()
chat_start=State()
import asyncio
import concurrent
from functools import partial
from .. import conf
from ..redmine import Rm
import hashlib
from aiogram.types import InlineQuery, \
InputTextMessageContent, InlineQueryResultArticle
from aiogram import types
from bot.main import dp, bot
import re
from ..classes.errors import BotError
task_re = re.compile(r'-task=(\w+)')
projectId_re = re.compile(r'\-projektId=([\d\-?]+)')
subject_re = re.compile(r'\-subject=\"(.+)\"')
firstname_re = re.compile(r'\-firstname=((?i)[a-zа-я]+)')
lastname_re = re.compile(r'\-lastname=((?i)[a-zа-я]+)')
mobile_re = re.compile(r'\-mobile=\+?(\d+)')
class BotError(Exception):
pass
@dp.message_handler()
async def cats(message: types.Message):
try:
if(message.chat['type'] == "group"):
if(message['from']['username'] != conf.operator_name):
raise BotError("Только оператор может посылать боту команды в групповом чате. Для создания задачи, напишите боту в ЛС или свяжитесь с оператором.")
task = task_re.search(message.text)
if not task or not task.group(1):
raise BotError("В качестве параметра -task передайте боту информацию о том что он должен сделать.")
if(task == 'new'):
new_task = {
'projectId': None,
'subject': None,
'firstname': None,
'lastname': None,
'mobile': None,
}
projectId = projectId_re.search(message.text)
if projectId:
new_task['projectId'] = projectId.group(1)
subject = subject_re.search(message.text)
if subject:
new_task['subject'] = subject.group(1)
firstname = firstname_re.search(message.text)
if firstname:
new_task['firstname'] = firstname.group(1)
lastname = lastname_re.search(message.text)
if lastname:
new_task['lastname'] = lastname.group(1)
mobile = mobile_re.search(message.text)
if mobile:
new_task['mobile'] = mobile.group(1)
#Если все параметры переданны
if(new_task['projectId'] and new_task['subject'] and new_task['firstname'] and new_task['lastname'] and new_task['mobile']):
rm=Rm(conf.rm_url,conf.rm_user,conf.rm_pw)
if not rm:
raise BotError("Ошибка в конфигурации бота.")
with concurrent.futures.ThreadPoolExecutor() as pool:
custom_fields = [
{'id': 1, 'name': 'Имя заявителя', 'value': new_task['firstname']},
{'id': 2, 'name': 'Фамилия заявителя', 'value': new_task['lastname']},
{'id': 3, 'name': 'Телефон заявителя', 'value': new_task['mobile']}
]
partial_result = partial(rm.search_project_create_task, new_task['projectId'], new_task['subject'], custom_fields)#0 - id проекта, 1 - название задачи
if not partial_result:
raise BotError(f"Проект с Id: {new_task['projectId']} не найден")
issue = await asyncio.get_event_loop().run_in_executor(pool, partial_result)
if issue:
await message.answer(f'Задача {issue.id} создана, тема - "{issue.subject}"')
else:
raise BotError("Задача не создана")
#если какой то параметр не передан
else:
raise BotError("Для создания задачи необходимо задать значение следующим флагам: -projectId, -subject, -firstname, -lastname, -mobile.")
except BotError as error:
await message.answer(f"Ошибка! {error}")
# Создать телеграм бота для тех. поддержки со следующими возможностями:
# 1. При нативном входе в бот выходит меню с приветствием и кнопками
# - Создать новую задачу -> Форма ввода в поля "Фамилии Имени и Телефона" -> Форма ввода названия компании "Например Ресторан "Скрябин" или Компания "Вознесение" -> Форма ввода описания проблемы и кнопка "Отправить в тех. поддержку"
# - При нажатии кнопки "Отправить в тех. поддержку" выходит номер созаднной задачи из системы к которой привязан бот (платформа либо редмайн) и сообщение "Спасибо за Ваше обращение в тех. поддержку! Номер Вашей задачи #27273"
# - Посмотреть существующую задачу
# Поле для ввода номера задачи - по факту ввода задачи система отображает текущий статус задачи, ФИ исполнителя а также выводит текст первоначального обращения
#
# Viktor, [09.06.21 16:49]
# [Forwarded from Дмитрий Сабуров ЗолотойКод]
# также данные функции может вызвать любой пользователь в любом телеграм канале при помощи вызова бота с опциями, например
# @zk_supprot_bot -task=new -name="Не печатает принтер в зале" -firstname=Анна -lastname=Петрова -mobile="+7927xxxyyzzz"
#
# Viktor, [09.06.21 16:49]
# [Forwarded from Дмитрий Сабуров ЗолотойКод]
# сразу лучше предусмотреть защиту от ботов и накрутки а также через внешний сервис проверять валидность телефона либо отправлять код смс
# dp.register_inline_handler(inline_echo)
# dp.register_message_handler(user_id_set, is_oper,
# commands=['setid'],
# )
# dp.register_message_handler(user_id_get, is_oper,state=Form.user_id_get)
# #if operator then only send to client
# dp.register_message_handler(send_msg, is_oper)
from aiogram import types
from aiogram.dispatcher.filters.state import StatesGroup, State
from bot.main import dp, bot
from bot.operator_my import operators
from bot.user import users
from aiogram.types import KeyboardButton, ReplyKeyboardMarkup,ReplyKeyboardRemove
class Form(StatesGroup):
user_id_get = State()
user_id=None
def make_reply_markup():
if users:
buttons = [KeyboardButton(i) for i in users]
reply = ReplyKeyboardMarkup()
reply.add(*buttons)
return reply
#output to telega in keyboard clients id
async def user_id_set(message: types.Message):
operator=operators[message.from_user.id]
if reply:=make_reply_markup():
await message.reply('введите ИД', reply_markup=reply)
operator.user_id=None
await Form.user_id_get.set()
else:
await message.reply('никого нет')
#wait when opertator enter client id to talk with
async def user_id_get(message: types.Message,state):
operator=operators[message.from_user.id]
operator.user_id=None
try:
operator.user_id = int(message.text)
await message.reply(f'Ид телеги {operator.user_id}',reply_markup=ReplyKeyboardRemove())
except BaseException:
await message.reply('Не верный Ид только числа')
return
await state.finish()
#send message from operator to client - if no user to send ask to enter client id
async def send_msg(message: types.Message, state):
user_id=operators[message.from_user.id].user_id
if not user_id:
await user_id_set(message)
return
msg=message.text
await bot.send_message(user_id, msg)
is_oper=lambda message: message.from_user.id in operators
dp.register_message_handler(user_id_set, is_oper,
commands=['setid'],
)
dp.register_message_handler(user_id_get, is_oper,state=Form.user_id_get)
#if operator then only send to client
dp.register_message_handler(send_msg, is_oper)
from aiogram import types
from aiogram.types import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
import asyncio
from bot.handlers.form_state import Form
from bot.main import dp, bot
from bot.operator_my import find_operator_for_user, operators
from bot.user import users, User
loop = asyncio.get_event_loop()
chat_close_com= 'закрыть чат'
async def cmd_start(message: types.Message):
await message.reply("Внесите телефон \n",
# reply_markup=await self.makeReplyMarkup()
)
await Form.phone.set()
async def phone_get(message: types.Message):
try:
# phone = int(message.contact['phone_number'])
phone = int(message.text)
except BaseException:
await message.reply('Телефон неверен',
reply=False,
# reply_markup=await self.makeReplyMarkup()
)
return
if phone:
users.setdefault(message.from_user.id,User()).phone = phone
await message.reply('Телефон принят,введите имя',
reply=False,
# reply_markup=await self.makeReplyMarkup()
)
await Form.name.set()
async def name_get(message: types.Message, state):
await message.reply('Имя запомнил ,введите обьект',
reply=False,
# reply_markup=await self.makeReplyMarkup()
)
async with state.proxy() as data:
users.setdefault(message.from_user.id, User()).name = message.text
await Form.object.set()
async def object_get(message: types.Message, state):
async with state.proxy() as data:
users.setdefault(message.from_user.id, User()).object = message.text
_:User =users[message.from_user.id]
await message.reply(f'Обект запомнил, что у вас случилось,задачу надо принять',
reply=False,
# reply_markup=await self.makeReplyMarkup()
)
await Form.truble.set()
async def truble_get(message: types.Message, state):
async with state.proxy() as data:
users.setdefault(message.from_user.id, User()).truble = message.text
_: User = users[message.from_user.id]
msg = f'{_.name} {_.phone} {_.object} \n {_.truble}'
await message.reply(f'Обект запомнил, ваши данные \n {msg} \n переданы компетентным органам \n'
f' вам нужен чат с сотрудником да/нет ?',
reply=False,
# reply_markup=await self.makeReplyMarkup()
)
await Form.chat_ask.set()
# await self.mail(msg)
async def chat_start(message: types.Message, state):
if 'да' in message.text:
user_id=message.from_user.id
user=users[user_id]
button = KeyboardButton(chat_close_com)
reply = ReplyKeyboardMarkup()
reply.add(button)
await message.reply('соеденяю',reply_markup=reply)
await Form.chat_start.set()
if await find_operator_for_user(user_id):
await bot.send_message(user.operator_id, f'{user_id}:запрос чата ')
else:
await message.reply('ок - решаем')
await state.finish()
users.pop(message.from_user.id)
async def chat_stop(message: types.Message, state):
user=users.pop(message.from_user.id)
operators[user.operator_id].user_id=None
await message.reply('чат закрыт',reply_markup=ReplyKeyboardRemove())
await state.finish()
dp.register_message_handler(cmd_start,commands='start')
dp.register_message_handler(phone_get,state=Form.phone)
dp.register_message_handler(name_get,state=Form.name)
dp.register_message_handler(object_get, state=Form.object)
dp.register_message_handler(truble_get, state=Form.truble)
dp.register_message_handler(chat_stop,lambda msg : chat_close_com in msg.text,state=Form.chat_start)
dp.register_message_handler(chat_start, state=Form.chat_ask)
import asyncio
import aiosmtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
async def send_mail_async(sender, to, subject, text, text_type='plain',MAIL_PARAMS=None, **params):
"""Send an outgoing email with the given parameters.
:param sender: From whom the email is being sent
:type sender: str
:param to: A list of recipient email addresses.
:type to: list
:param subject: The subject of the email.
:type subject: str
:param text: The text of the email.
:type text: str
:param text_type: Mime subtype of text, defaults to 'plain' (can be 'html').
:type text: str
:param params: An optional set of parameters. (See below)
:type params; dict
Optional Parameters:
:cc: A list of Cc email addresses.
:bcc: A list of Bcc email addresses.
"""
# Default Parameters
cc = params.get("cc", [])
bcc = params.get("bcc", [])
mail_params = MAIL_PARAMS
# Prepare Message
msg = MIMEMultipart()
msg.preamble = subject
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = ', '.join(to)
if len(cc): msg['Cc'] = ', '.join(cc)
if len(bcc): msg['Bcc'] = ', '.join(bcc)
msg.attach(MIMEText(text, text_type, 'utf-8'))
# Contact SMTP server and send Message
host = mail_params.get('host', 'localhost')
isSSL = mail_params.get('SSL', False);
isTLS = mail_params.get('TLS', False);
port = mail_params.get('port', 465 if isSSL else 25)
smtp = aiosmtplib.SMTP(hostname=host, port=port, use_tls=isSSL)
await smtp.connect()
if isTLS:
await smtp.starttls()
if 'user' in mail_params:
await smtp.login(mail_params['user'], mail_params['password'])
await smtp.send_message(msg)
await smtp.quit()
if __name__ == "__main__":
email = "xxxxxxxx";
co1 = send_mail_async(email,
[email],
"Test 1",
'Test 1 Message',
text_type="plain")
co2 = send_mail_async(email,
[email],
"Test 2",
'Test 2 Message',
text_type="plain")
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(co1, co2))
loop.close()
\ No newline at end of file
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram import Bot, Dispatcher
from . import conf
from .mail import send_mail_async
bot=Bot(conf.API_TOKEN)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
async def mail(msg):
await send_mail_async(conf.mail_sender,subject=conf.mail_subject,text=msg)
from .handlers import inline
# from .handlers import operator_my,start, chat ,inline
import asyncio
from bot import conf
from bot.user import users
class Operator:
__slots__ = 'user_id'
def __init__(self):
self.user_id=None
operators={int(k):Operator() for k in conf.operator_ids.split(';') if k}
async def find_operator_for_user(user_id):
while users.get(user_id):
await asyncio.sleep(1)
for id,operator in operators.items():
if not operator.user_id:
users[user_id].operator_id=id
operator.user_id=int(user_id)
return operator
import datetime
from redminelib import Redmine
import sys
try:
from ..conf import project_id
except:
sys.path.append('..')
from conf import project_id
#='zolotoykod-imp-1-111',
class Rm:
def __init__(self, rm_url, rm_user, rm_pw):
self.rm = Redmine(rm_url, username=rm_user, password=rm_pw)
def add_time(self,issue_id,hours,):
_=datetime.date.today()
time_entry = self.rm.time_entry.create(
issue_id = issue_id,
spent_on = datetime.date(_.year, _.month, _.day),
hours = hours,
activity_id = 10,
comments = 'hello'
)
def getUser(self, id):
return self.rm.user.get(id)
def create_task(self,project_id,subj, custom_fields):
try:
return self.rm.issue.create(subject=subj, project_id=project_id,
custom_fields=custom_fields#(
#{'id': project_id,
# 'name': 'Тариф Внедрения (SLA)',
# 'value': 'Внедрение по договору (IMP)'},
#{'id': 27, 'name': 'Оценка оператора', 'value': ''},
#{'id': 29, 'name': 'Счет', 'value': ''},
#{'id': 30, 'name': 'Счет выставлен', 'value': '0'},
#{'id': 34, 'name': 'Обратная связь', 'value': '0'},
#{'id': 45, 'name': 'Обратная связь без ответа', 'value': '0'},
#{'id': 35, 'name': 'Обратная связь не требуется', 'value': '0'}
#)
)
except:
pass
def proj_search(self,query):
try:
return self.rm.project.search(query)[0]
except:
return None
def search_project_create_task(self,pr_search,task_subj, custom_fields):
if not (project:=self.proj_search(pr_search)):
return False
return self.create_task(project_id=project.id,subj=task_subj, custom_fields=custom_fields)
if __name__=='__main__':
import os
rm_user = os.environ['rm_user']
rm_url = os.environ['rm_url']
rm_pw = os.environ['rm_pw']
rm=Rm(rm_url,rm_user,rm_pw)
a=rm.proj_search('659-4')
rm.create_task(project_id=a.id,subj='test2 test tbot')
\ No newline at end of file
class User:
__slots__ = ('phone','name','object','truble','operator_id')
users={}
#!/bin/bash
export rm_url=https://redminenew.zolotoykod.ru
export rm_user=1135
export rm_pw=123123Dd
export project_id=115-1
export API_TOKEN=1927439613:AAFo7OBH4mwKbMtm2u414IQcBL_spHqd_j4
export operator_name=Brotiger63
\ No newline at end of file
This diff is collapsed.
aiogram==2.11.2
aiohttp==3.7.4.post0
async-timeout==3.0.1
attrs==20.3.0
Babel==2.9.0
backcall==0.2.0
certifi==2020.12.5
chardet==4.0.0
decorator==5.0.9
deepdiff==5.2.3
graphviz==0.16
h11==0.12.0
httpcore==0.12.3
httpx==0.16.1
idna==2.10
ipdb==0.13.4
ipython==7.25.0
ipython-genutils==0.2.0
jedi==0.18.0
matplotlib-inline==0.1.2
multidict==5.1.0
objgraph==3.5.0
parso==0.8.2
pexpect==4.8.0
pickleshare==0.7.5
prompt-toolkit==3.0.19
ptyprocess==0.7.0
Pygments==2.9.0
python-redmine==2.3.0
pytz==2021.1
requests==2.25.1
rfc3986==1.4.0
sniffio==1.2.0
suds-jurko==0.6
traitlets==5.0.5
typing-extensions==3.7.4.3
urllib3==1.26.5
wcwidth==0.2.5
yarl==1.6.3
aiosmtplib
\ No newline at end of file
from aiogram.utils import executor
from bot.main import dp
executor.start_polling(dp, skip_updates=True)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment