Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
0cb92510b8
|
@ -164,3 +164,4 @@ cython_debug/
|
||||||
*.session
|
*.session
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
*session_journal
|
*session_journal
|
||||||
|
uploads
|
|
@ -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)
|
|
|
@ -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()
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue