diff --git a/__init__.py b/__init__.py index 1a1298d..e69de29 100644 --- a/__init__.py +++ b/__init__.py @@ -1,140 +0,0 @@ -import hashlib -import os -from re import match - -from flask import render_template, request, redirect, url_for -from flask_login import LoginManager, login_user, login_required, logout_user, current_user - -import db_routing -from db_init import db_fill -from db_routing import app, db -from scenario_manager import Executor - -login_manager = LoginManager(app) - - -@login_manager.user_loader -def load_user(user_id): - return db_routing.get_user(id=user_id) - - -@app.route('/', methods=['GET']) -def index(): - return render_template('index.html') - - -@app.route('/registration', methods=['GET', 'POST']) -def registration(): - if current_user.is_authenticated: - return redirect(url_for('universal_error')) - if request.method == 'POST': - userName = request.form['RegUserLogin'] - userPassw = request.form['RegUserPassw'] - if string_check(userName) and string_check(userPassw): - if db_routing.add_user(userName, passw_hash(userPassw)): - login_user(db_routing.get_user(username=userName)) - return redirect(url_for('workshop')) - return render_template('registration.html') - - -@app.route('/login', methods=['POST']) -def login(): - userName = request.form['LogUserLogin'] - userPassw = request.form['LogUserPassw'] - if string_check(userName) and string_check(userPassw): - user = verify_password(userName, userPassw) - if user: - login_user(user) - return redirect(url_for('workshop')) - else: - return redirect(url_for('registration')) - - else: - return redirect(url_for('registration')) - - -@app.route('/logout') -def logout(): - logout_user() - return redirect(url_for('index')) - - -@app.route('/workshop', methods=['GET', 'POST']) -@login_required -def workshop(): - if request.method == 'POST': - if 'NewScenarioName' in request.form: - newScenarioName = request.form['NewScenarioName'] - triggerID = request.form['TriggerID'] - triggerArgs = request.form['TriggerArgs'] - actionID = request.form['ActionID'] - actionArgs = request.form['ActionArgs'] - new_scenario = db_routing.add_scenario(current_user.get_id(), newScenarioName, triggerID, triggerArgs, - actionID, - actionArgs) - activeScenario = Executor(new_scenario, current_user.get_tg_id()) - activeScenario.start() - return redirect(url_for('workshop')) - - if 'TGID' in request.form: - new_tg_id = request.form['TGID'] - db_routing.tg_id_update(current_user.get_id(), new_tg_id) - return redirect(url_for('workshop')) - - if 'ScenarioID' in request.form: - scnarioID = request.form['ScenarioID'] - db_routing.delete_scenario(scnarioID) - return redirect(url_for('workshop')) - - triggers_list = db_routing.get_trigers() - actions_list = db_routing.get_actions() - user_scripts_list = db_routing.get_user_scripts(current_user.get_id()) - User = db_routing.get_user(id=current_user.get_id()) - if User: - tg_id = User.tg_id - else: - tg_id = None - return render_template('workshop.html', triggers_list=triggers_list, actions_list=actions_list, - user_scripts_list=user_scripts_list, tg_id=tg_id) - - -@app.errorhandler(Exception) -def universal_error(error): - return render_template('error.html'), 404 - - -def string_check(string): - if 2 < len(string) < 7: - if match('^[0-9A-Za-z]*$', string) and not ('\\' in string): - return True - else: - print( - 'Некорректный ввод! Строка должно включать только английские буквы или цифры. Содержать не менее 3 и не ' - 'более 6 символов') - return False - - -def passw_hash(user_passw, salt=os.urandom(32)): - key = hashlib.pbkdf2_hmac('sha256', user_passw.encode('utf-8'), salt, 100000) - storage = salt + key - # salt_from_storage = storage[:32] # 32 длина соли - # key_from_storage = storage[32:] - return storage - - -def verify_password(username, password): - User = db_routing.get_user(username=username) - if User: - userSalt = User.password[:32] - if passw_hash(password, userSalt) == User.password: - return User - else: - print('Неверный пароль') - return False - - -if __name__ == '__main__': - if not os.path.exists('./data.db'): - db.create_all() - db_fill() - app.run() diff --git a/actions.py b/actions.py index b9c3a30..b6fba02 100644 --- a/actions.py +++ b/actions.py @@ -11,20 +11,21 @@ def test_action(var, tg_id): # Ответ на письмо # формат строки (логин#пароль#адресат#текст) -# send_mail_config='login@gmail.com#Password123#myfriend@gmail.com#Текст сообщения' +# send_mail_config= +# 'login@gmail.com#Password123#myfriend@gmail.com#Текст сообщения' def send_mail(send_mail_config, tg_id): - send_mail_list = send_mail_config.split('#') + send_mail_list = send_mail_config.split("#") mail_sender = send_mail_list[0] # отправитель mail_receiver = send_mail_list[2] # адресат username = send_mail_list[0] # имя пользователя password = send_mail_list[1] # пароль от почты - server = smtplib.SMTP('smtp.gmail.com:587') + server = smtplib.SMTP("smtp.gmail.com:587") # Формируем тело письма - subject = u'J.a.r.v.i.s.' + subject = u"J.a.r.v.i.s." body = send_mail_list[3] - msg = MIMEText(body, 'plain', 'utf-8') - msg['Subject'] = Header(subject, 'utf-8') + msg = MIMEText(body, "plain", "utf-8") + msg["Subject"] = Header(subject, "utf-8") # Отправляем письмо server.starttls() diff --git a/db_init.py b/db_init.py index d8154ad..999a554 100644 --- a/db_init.py +++ b/db_init.py @@ -2,10 +2,10 @@ from db_routing import add_trigger, add_action def db_fill(): - add_trigger('Тест', 'test_trigger') - add_trigger('Будильник', 'alarm_clock') - add_trigger('Проверить почту', 'check_email') + add_trigger("Тест", "test_trigger") + add_trigger("Будильник", "alarm_clock") + add_trigger("Проверить почту", "check_email") - add_action('Тест', 'test_action') - add_action('Отправить письмо', 'send_mail') - add_action('Отправить сообщение в ТГ', 'send_message_tg') + add_action("Тест", "test_action") + add_action("Отправить письмо", "send_mail") + add_action("Отправить сообщение в ТГ", "send_message_tg") diff --git a/db_routing.py b/db_routing.py index b436cad..b16de75 100644 --- a/db_routing.py +++ b/db_routing.py @@ -2,14 +2,14 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import ForeignKey -app = Flask('Jarvis', static_folder='static', template_folder='templates') -app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db' -app.config['SECRET_KEY'] = 'Radius' +app = Flask("Jarvis", static_folder="static", template_folder="templates") +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.db" +app.config["SECRET_KEY"] = "Radius" db = SQLAlchemy(app) class User(db.Model): - __tablename__ = 'Users' + __tablename__ = "Users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False) @@ -34,27 +34,27 @@ class User(db.Model): class Trigger(db.Model): - __tablename__ = 'Triggers' + __tablename__ = "Triggers" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), unique=True, nullable=False) def_name = db.Column(db.String(200)) class Action(db.Model): - __tablename__ = 'Actions' + __tablename__ = "Actions" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), unique=True, nullable=False) def_name = db.Column(db.String(200)) class Scenario(db.Model): - __tablename__ = 'Scenarios' + __tablename__ = "Scenarios" id = db.Column(db.Integer, primary_key=True) - owner_id = db.Column(db.Integer, ForeignKey('Users.id')) + owner_id = db.Column(db.Integer, ForeignKey("Users.id")) scenario_name = db.Column(db.String(80), nullable=False) - trigger_id = db.Column(db.Integer, ForeignKey('Triggers.id')) + trigger_id = db.Column(db.Integer, ForeignKey("Triggers.id")) trigger_args = db.Column(db.String(200)) - action_id = db.Column(db.Integer, ForeignKey('Actions.id')) + action_id = db.Column(db.Integer, ForeignKey("Actions.id")) action_args = db.Column(db.String(200)) @@ -65,7 +65,7 @@ def add_user(user_name, passw_hash): db.session.commit() return new_user else: - print('Логин занят') + print("Логин занят") return False @@ -83,9 +83,17 @@ def add_action(name, def_name): return new_action -def add_scenario(owner_id, scenario_name, trigger_id, trigger_args, action_id, action_args): - new_scenario = Scenario(owner_id=owner_id, scenario_name=scenario_name, trigger_id=trigger_id, - trigger_args=trigger_args, action_id=action_id, action_args=action_args) +def add_scenario( + owner_id, scenario_name, trigger_id, trigger_args, action_id, action_args +): + new_scenario = Scenario( + owner_id=owner_id, + scenario_name=scenario_name, + trigger_id=trigger_id, + trigger_args=trigger_args, + action_id=action_id, + action_args=action_args, + ) db.session.add(new_scenario) db.session.commit() return new_scenario @@ -117,7 +125,9 @@ def get_actions(id=None): def get_user_scripts(current_user_id): - user_scripts_list = Scenario.query.filter_by(owner_id=current_user_id).all() + user_scripts_list = Scenario.query.filter_by( + owner_id=current_user_id + ).all() return user_scripts_list diff --git a/jarvis.py b/jarvis.py new file mode 100644 index 0000000..06cfc66 --- /dev/null +++ b/jarvis.py @@ -0,0 +1,159 @@ +import hashlib +import os +from re import match + +from flask import render_template, request, redirect, url_for +from flask_login import ( + LoginManager, + login_user, + login_required, + logout_user, + current_user, +) + +import db_routing +from db_init import db_fill +from db_routing import app, db +from scenario_manager import Executor + +login_manager = LoginManager(app) + + +@login_manager.user_loader +def load_user(user_id): + return db_routing.get_user(id=user_id) + + +@app.route("/", methods=["GET"]) +def index(): + return render_template("index.html") + + +@app.route("/registration", methods=["GET", "POST"]) +def registration(): + if current_user.is_authenticated: + return redirect(url_for("universal_error")) + if request.method == "POST": + userName = request.form["RegUserLogin"] + userPassw = request.form["RegUserPassw"] + if string_check(userName) and string_check(userPassw): + if db_routing.add_user(userName, passw_hash(userPassw)): + login_user(db_routing.get_user(username=userName)) + return redirect(url_for("workshop")) + return render_template("registration.html") + + +@app.route("/login", methods=["POST"]) +def login(): + userName = request.form["LogUserLogin"] + userPassw = request.form["LogUserPassw"] + if string_check(userName) and string_check(userPassw): + user = verify_password(userName, userPassw) + if user: + login_user(user) + return redirect(url_for("workshop")) + else: + return redirect(url_for("registration")) + + else: + return redirect(url_for("registration")) + + +@app.route("/logout") +def logout(): + logout_user() + return redirect(url_for("index")) + + +@app.route("/workshop", methods=["GET", "POST"]) +@login_required +def workshop(): + if request.method == "POST": + if "NewScenarioName" in request.form: + newScenarioName = request.form["NewScenarioName"] + triggerID = request.form["TriggerID"] + triggerArgs = request.form["TriggerArgs"] + actionID = request.form["ActionID"] + actionArgs = request.form["ActionArgs"] + new_scenario = db_routing.add_scenario( + current_user.get_id(), + newScenarioName, + triggerID, + triggerArgs, + actionID, + actionArgs, + ) + activeScenario = Executor(new_scenario, current_user.get_tg_id()) + activeScenario.start() + return redirect(url_for("workshop")) + + if "TGID" in request.form: + new_tg_id = request.form["TGID"] + db_routing.tg_id_update(current_user.get_id(), new_tg_id) + return redirect(url_for("workshop")) + + if "ScenarioID" in request.form: + scnarioID = request.form["ScenarioID"] + db_routing.delete_scenario(scnarioID) + return redirect(url_for("workshop")) + + triggers_list = db_routing.get_trigers() + actions_list = db_routing.get_actions() + user_scripts_list = db_routing.get_user_scripts(current_user.get_id()) + User = db_routing.get_user(id=current_user.get_id()) + if User: + tg_id = User.tg_id + else: + tg_id = None + return render_template( + "workshop.html", + triggers_list=triggers_list, + actions_list=actions_list, + user_scripts_list=user_scripts_list, + tg_id=tg_id, + ) + + +@app.errorhandler(Exception) +def universal_error(error): + return render_template("error.html"), 404 + + +def string_check(string): + if 2 < len(string) < 7: + if match("^[0-9A-Za-z]*$", string) and not ("\\" in string): + return True + else: + print( + "Некорректный ввод! Строка должно включать только английские буквы" + " или цифры. Содержать не менее 3 и не более 6 символов" + ) + return False + + +def passw_hash(user_passw, salt=os.urandom(32)): + key = hashlib.pbkdf2_hmac( + "sha256", user_passw.encode("utf-8"), salt, 100000 + ) + storage = salt + key + # salt_from_storage = storage[:32] # 32 длина соли + # key_from_storage = storage[32:] + return storage + + +def verify_password(username, password): + User = db_routing.get_user(username=username) + if User: + userSalt = User.password[:32] + if passw_hash(password, userSalt) == User.password: + return User + else: + print("Неверный пароль") + return False + + +if __name__ == "__main__": + if not os.path.exists("./data.db"): + db.create_all() + db_fill() + app.run() diff --git a/telegram.py b/telegram.py index 88e10dc..4fbc841 100644 --- a/telegram.py +++ b/telegram.py @@ -1,18 +1,22 @@ import telebot -botToken = '' +botToken = "" bot = telebot.TeleBot(botToken) -# telebot.apihelper.proxy = {'Socks5': '247398282:247398282@orbtl.s5.opennetwork.cc:999'} # - прокси, если нужен в +# telebot.apihelper.proxy = {} +# прокси, если нужен, в # формате {'https': 'login:password@address:port'} -@bot.message_handler(commands=['start']) # Реакция на команду start +@bot.message_handler(commands=["start"]) # Реакция на команду start def start_message(message): - bot.send_message(message.chat.id, - 'Добро пожаловать в Jarvis!\nЭто помощник, сценарии поведения которого настраиваются через ' - 'web-приложение на Flask\n') + bot.send_message( + message.chat.id, + "Добро пожаловать в Jarvis!\n" + "Это помощник, сценарии поведения которого настраиваются через ", + "web-приложение на Flask\n", + ) def send_message(user_id, text): diff --git a/triggers.py b/triggers.py index 0fdae21..687a4e1 100644 --- a/triggers.py +++ b/triggers.py @@ -12,41 +12,51 @@ def test_trigger(var, tg_id): # Формат строки (год месяц день час минута секунда) # Config_time='2020#3#22#15#20#0' def alarm_clock(config_time, tg_id): - config_list = config_time.split('#') - dt = datetime.datetime(int(config_list[0]), int(config_list[1]), int(config_list[2]), int(config_list[3]), - int(config_list[4]), - int(config_list[5])) + config_list = config_time.split("#") + dt = datetime.datetime( + int(config_list[0]), + int(config_list[1]), + int(config_list[2]), + int(config_list[3]), + int(config_list[4]), + int(config_list[5]), + ) diff = (dt - datetime.datetime.now()).total_seconds() try: time.sleep(diff) - except: - print('Нельзя поставить будильник в прошлое') + except Exception: + print("Нельзя поставить будильник в прошлое") return # проверка почты на новое письмо gmail -# Нужно включить https://myaccount.google.com/lesssecureapps и https://mail.google.com/mail/u/2/#settings/fwdandpop +# Нужно включить https://myaccount.google.com/lesssecureapps и +# https://mail.google.com/mail/u/2/#settings/fwdandpop # Формат строки (логин#пароль) # check_mail_config='login@gmail.com Password123' def check_email(check_mail_config, tg_id): - mail_config_list = check_mail_config.split('#') - mail = imaplib.IMAP4_SSL('imap.gmail.com', 993) + mail_config_list = check_mail_config.split("#") + mail = imaplib.IMAP4_SSL("imap.gmail.com", 993) mail.login(mail_config_list[0], mail_config_list[1]) mail.list() - count_Email_Start = (mail.select("inbox")[1][0]).decode('utf-8') + count_Email_Start = (mail.select("inbox")[1][0]).decode("utf-8") while True: mail.list() - count_Email_Current = (mail.select("inbox")[1][0]).decode('utf-8') + count_Email_Current = (mail.select("inbox")[1][0]).decode("utf-8") if count_Email_Current > count_Email_Start: result, data = mail.search(None, "ALL") ids = data[0] # Получаем сроку номеров писем id_list = ids.split() # Разделяем ID писем latest_email_id = id_list[-1] # Берем последний ID - result, data = mail.fetch(latest_email_id, "(RFC822)") # Получаем тело письма (RFC822) для данного ID + result, data = mail.fetch( + latest_email_id, "(RFC822)" + ) # Получаем тело письма (RFC822) для данного ID raw_email = data[0][1] email_message = email.message_from_bytes(raw_email) - email_message_From = email_message['From'] - email_message_From = email_message_From[email_message_From.index('<'):email_message_From.index('>')] + email_message_From = email_message["From"] + email_message_From = email_message_From[ + email_message_From.index("<") : email_message_From.index(">") + ] email_message_From = email_message_From[1:] return # count_Email_Start = count_Email_Current