Merge remote-tracking branch 'origin/main'

This commit is contained in:
Анатолий Богомолов 2024-02-18 23:02:33 +10:00
commit 0cb92510b8
10 changed files with 81 additions and 41 deletions

1
.gitignore vendored
View File

@ -164,3 +164,4 @@ cython_debug/
*.session *.session
.vscode/settings.json .vscode/settings.json
*session_journal *session_journal
uploads

View File

@ -1,16 +1,23 @@
from flask import Blueprint, Response, jsonify, request import os
from flask import Blueprint, jsonify, request, current_app, redirect
from werkzeug.utils import secure_filename
from app.extensions import db from app.extensions import db
from app.models.session import Session from app.models.session import Session
from app.models.task import Task
from paper.errors import NeedPasswordException from paper.errors import NeedPasswordException
from paper.parser import PaperParser from paper.parser import PaperParser
sessions = Blueprint("sessions", __name__, url_prefix="/sessions") sessions = Blueprint("sessions", __name__, url_prefix="/sessions")
@sessions.route("/", methods=["POST"]) ALLOWED_EXTENSIONS = ['zip']
async def create_session(**kwargs):
data = kwargs or request.json or request.form def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
async def create_session_form():
data = request.json
data["name"] = data["name"].replace("/", "").replace("\\", "") data["name"] = data["name"].replace("/", "").replace("\\", "")
session = Session.query.filter_by(name=data.get("name")).first() session = Session.query.filter_by(name=data.get("name")).first()
@ -57,6 +64,36 @@ async def create_session(**kwargs):
return jsonify(response) return jsonify(response)
def create_session_from_file():
archive = request.files['archive']
if archive.filename == '':
return 'Not Found', 404
if not allowed_file(archive.filename):
return 'File Extension Not Allowed', 406
session_upload_path = os.path.join(current_app.config['UPLOAD_DIR'], "sessions")
if not os.path.exists(session_upload_path):
os.makedirs(session_upload_path)
filename = secure_filename(archive.filename)
file_path = os.path.join(session_upload_path, filename)
archive.save(file_path)
return 'Ok', 200
# return redirect('/')
@sessions.route("/", methods=["POST"])
async def create_session():
files = request.files
if not 'archive' in files:
return await create_session_form()
else:
return create_session_from_file()
@sessions.route("/", methods=["GET"]) @sessions.route("/", methods=["GET"])
def get_sessions(**kwargs): def get_sessions(**kwargs):
return Session.query.filter_by(authorized=True).all() return Session.query.filter_by(authorized=True).all()
@ -72,10 +109,11 @@ async def remove_session(id: int):
try: try:
await parser.client.log_out() await parser.client.log_out()
db.session.delete(session)
db.session.commit()
except Exception as e: except Exception as e:
return Response(e, 500) return str(e), 500
db.session.delete(session) return 'ok', 200
db.session.commit()
return Response('ok', status=200)

View File

@ -2,18 +2,18 @@ from app.extensions import db
from app.models.task import Task from app.models.task import Task
def success_state(task_id): def success_state(task_id):
task = Task.query.filter_by(task_id=task_id).one() task = Task.query.get(task_id)
task.status = "SUCCESS" task.status = "SUCCESS"
task.status_message = "Задача выполнена успешно" task.status_message = "задача выполнена успешно"
db.session.commit() db.session.commit()
def failure_state(task_id, exception): def failure_state(task_id, exception):
task = Task.query.filter_by(task_id=task_id).one() task = Task.query.get(task_id)
task.status = "FAILURE" task.status = "FAILURE"
task.status_message = f"Произошла ошибка: {str(exception)}" task.status_message = f"произошла ошибка {str(exception)}"
db.session.commit() db.session.commit()
@ -22,6 +22,6 @@ def run_state(task_id, task_record_id):
task.task_id = task_id task.task_id = task_id
task.status = "RUNNING" task.status = "RUNNING"
task.status_message = "Задача запущена" task.status_message = "задача запущена"
db.session.commit() db.session.commit()

View File

@ -12,7 +12,7 @@ tasks = Blueprint("tasks", __name__, url_prefix="/tasks", template_folder="templ
@tasks.route("/", methods=["GET"]) @tasks.route("/", methods=["GET"])
def get_tasks(): def get_tasks():
tasks = Task.query.all() tasks = Task.query.all()
sessions = Session.query.all() sessions = Session.query.filter_by(authorized=True).all()
return render_template("tasks_cards.j2", tasks=tasks, sessions=sessions) return render_template("tasks_cards.j2", tasks=tasks, sessions=sessions)

View File

@ -31,11 +31,11 @@ def add_to_group_task(self, task_id):
) )
except Exception as e: except Exception as e:
failure_state(self.request.id, e) failure_state(task_id, e)
raise e raise e
else: else:
success_state(self.request.id) success_state(task_id)

View File

@ -91,10 +91,11 @@ PaperParser: Вход в аккаунт
<button type="submit" class="btn btn-primary">Отправить код</button> <button type="submit" class="btn btn-primary">Отправить код</button>
</form> </form>
<hr> <hr>
<form action="/api/sessions/file" method="POST"> <form hx-post="/api/sessions" hx-encoding='multipart/form-data' hx-swap="none">
<label for="open-file-btn" class="form-label">Архив с аккаунтом (или .session файл)</label> <label for="open-file-btn" class="form-label">Архив с аккаунтом</label>
<div class="mb-3"> <div class="input-group mb-3">
<button id="open-file-btn" type="submit" class="btn btn-secondary mt-3 disabled">Открыть файл</button> <input class="form-control" type="file" name="archive" accept=".zip">
<button class="btn btn-primary" type="submit">Отправить</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -13,8 +13,9 @@ class ProductionConfig:
) )
class DebugConfig: class DebugConfig:
SQLALCHEMY_DATABASE_URI = f"postgresql://postgres:123456789@localhost:5432/paper" SQLALCHEMY_DATABASE_URI = f"postgresql://paper:123456789@localhost:5432/paper"
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_DIR = 'uploads'
CELERY = dict( CELERY = dict(
broker_url="redis://localhost:6379/0", broker_url="redis://localhost:6379/0",
result_backend="redis://localhost:6379/0", result_backend="redis://localhost:6379/0",

View File

@ -23,7 +23,8 @@ from telethon.errors.rpcerrorlist import (
UsersTooMuchError, UsersTooMuchError,
UserChannelsTooMuchError, UserChannelsTooMuchError,
UserIsBlockedError, UserIsBlockedError,
YouBlockedUserError YouBlockedUserError,
UsernameInvalidError,
) )
class PaperClient(TelegramClient): class PaperClient(TelegramClient):
@ -93,11 +94,13 @@ class PaperClient(TelegramClient):
return await super().get_participants(group, *args, **kwargs) return await super().get_participants(group, *args, **kwargs)
async def __cast_to_entity(self, entity: Entity | EntityLike) -> Entity: async def __cast_to_entity(self, entity: Entity | EntityLike) -> Entity:
if not isinstance(entity, Entity): try:
if hasattr(entity, "username"): if not isinstance(entity, Entity):
entity = await self.get_entity(entity.username) if hasattr(entity, "username"):
else: entity = await self.get_entity(entity.username)
entity = await self.get_entity(entity) else:
entity = await self.get_entity(entity)
return entity # type: ignore
return entity # type: ignore
except UsernameInvalidError as e:
raise IgnoreException(e)

View File

@ -18,8 +18,9 @@ class FloodException(Exception):
def __init__(self, error, *args: object): def __init__(self, error, *args: object):
self.error = error self.error = error
self.seconds = self.error.seconds if hasattr(self.error, "seconds") else -1 #type: ignore self.seconds = self.error.seconds if hasattr(self.error, "seconds") else -1 #type: ignore
self.message = f"Flood wait for {self.seconds}" if self.seconds > 0 else "Flood error"
super().__init__(*args) super().__init__(self.message, *args)
class IgnoreException(Exception): class IgnoreException(Exception):
def __init__(self, error, *args): def __init__(self, error, *args):

View File

@ -35,15 +35,11 @@ class PaperParser:
except (UserPrivacyException, IgnoreException) as e: except (UserPrivacyException, IgnoreException) as e:
self.users_to_delete.append(user) self.users_to_delete.append(user)
logger.exception(e)
logger.warning("Exception occurred. Skipping user...") logger.warning("Exception occurred. Skipping user...")
except Exception as e:
logger.exception(e)
finally: finally:
if not task.is_aborted(): if not task.is_aborted():
await asyncio.sleep(50) # FIXME: Change to config value await asyncio.sleep(70) # FIXME: Change to config value
async def send_messages(self, users, message: str, file: str | None = None, task = None): async def send_messages(self, users, message: str, file: str | None = None, task = None):
# TODO: Filter users, that already get this message # TODO: Filter users, that already get this message
@ -61,12 +57,11 @@ class PaperParser:
except (UserPrivacyException, IgnoreException) as e: except (UserPrivacyException, IgnoreException) as e:
self.users_to_delete.append(user) self.users_to_delete.append(user)
logger.exception(e)
logger.warning("Exception occurred. Skipping user...") logger.warning("Exception occurred. Skipping user...")
finally: finally:
if not task.is_aborted(): if not task.is_aborted():
await asyncio.sleep(50) # FIXME: Change to config value await asyncio.sleep(70) # FIXME: Change to config value
async def get_participants(self, group): async def get_participants(self, group):
await self.client.invite_self(group) await self.client.invite_self(group)