This commit is contained in:
Анатолий Богомолов 2024-03-08 16:39:04 +10:00
parent dd1518b69c
commit 2f67e1cea6
11 changed files with 111 additions and 61 deletions

View File

@ -5,6 +5,26 @@ from app.extensions import db
collections = Blueprint("collections", __name__, url_prefix="/collections", template_folder="templates") collections = Blueprint("collections", __name__, url_prefix="/collections", template_folder="templates")
@collections.route('/', methods=["POST"])
def create_collection():
data = request.form
name = data.get('collection_name')
if not name:
return render_template('collections/create_form.j2', collections_error='Введите название базы!')
if Collection.exists(name):
return render_template('collections/create_form.j2', collections_error='База уже существует!')
swap = 'afterbegin' if len(Collection.query.all()) > 0 else 'innerHTML'
collection = Collection(name=name)
db.session.add(collection)
db.session.commit()
return f"<option value=\"{collection.id}\" selected>{ collection.name }</option>", 200, {'Hx-Reswap': swap, 'HX-Retarget': '#collection-select'}
@collections.route("/<int:id>", methods=["DELETE"]) @collections.route("/<int:id>", methods=["DELETE"])
def delete_collection(id: int): def delete_collection(id: int):
@ -18,4 +38,4 @@ def delete_collection(id: int):
if length <= 0: if length <= 0:
return "<small class=\"form-text\">Здесь ничего нет</small>", 200 return "<small class=\"form-text\">Здесь ничего нет</small>", 200
return "", 204 return "", 200

View File

@ -1,18 +1,20 @@
<div data-collection-id="{{ collection.id }}" class="card"> <div data-collection-id="{{ collection.id }}" class="col mb-3">
<div class="card-header"><h5>{{ collection.name }}</h5></div> <div class="card">
<ul class="list-group list-group-flush"> <div class="card-header"><h5>{{ collection.name }}</h5></div>
<li class="list-group-item">Кол-во пользрвателей: {{ collection.users|length }}</li> <ul class="list-group list-group-flush">
</ul> <li class="list-group-item">Кол-во пользрвателей: {{ collection.users|length }}</li>
<form action="/api/collections/{{ collection.id }}" method="DELETE" class="card-footer px-2 pt-2"> </ul>
<button <form action="/api/collections/{{ collection.id }}" method="DELETE" class="card-footer px-2 pt-2">
type="submit" <button
hx-delete="/api/collections/{{ collection.id }}" type="submit"
hx-swap="outerHTML" hx-delete="/api/collections/{{ collection.id }}"
hx-target='[data-collection-id="{{ collection.id }}"]' hx-swap="outerHTML"
hx-confirm="Вы уверены, что хотите удалить коллекцию?" hx-target='[data-collection-id="{{ collection.id }}"]'
class="btn btn-outline-danger" hx-confirm="Вы уверены, что хотите удалить коллекцию?"
> class="btn btn-outline-danger"
Удалить >
</button> Удалить
</form> </button>
</form>
</div>
</div> </div>

View File

@ -0,0 +1,2 @@
{% include "collections/create_form.j2" %}
{% include "collections/select.j2" %}

View File

@ -0,0 +1,33 @@
<div id="collection-create-form" class="input-group has-validation">
<input
type="text"
{% if collections_error is defined %}
class="form-control is-invalid"
{% else %}
class="form-control"
{% endif %}
name="collection_name"
id="collection-name-input"
placeholder="Название базы"
aria-describedby="collection-feedback"
required
>
<button
type="submit"
class="btn btn-outline-primary"
hx-post="/api/collections"
hx-swap="outerHTML"
hx-target="#collection-create-form"
hx-indicator="#indicator"
>
Добавить
</button>
{% if collections_error is defined %}
<div id="collection-feedback" class="invalid-feedback">
{{ collections_error }}
</div>
{% endif %}
</div>

View File

@ -1,8 +1,6 @@
<div id="cards-grid" class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4"> <div id="cards-grid" class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4">
{% for collection in collections %} {% for collection in collections %}
<div class="col mb-3"> {% include "collections/card.j2" %}
{% include "collections/card.j2" %}
</div>
{% else %} {% else %}
<small class="form-text">Здесь ничего нет.</small> <small class="form-text">Здесь ничего нет.</small>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,7 @@
<select name="collection" id="collection-select" class="form-select flex-fill" size="3">
{% for collection in collections %}
<option value="{{collection.id}}">{{ collection.name }}</option>
{% else %}
<option disabled>Добавьте новую базу пользователей</option>
{% endfor %}
</select>

View File

@ -16,10 +16,6 @@ def get_tasks():
return render_template("tasks_cards.j2", tasks=tasks, sessions=sessions) return render_template("tasks_cards.j2", tasks=tasks, sessions=sessions)
@tasks.route("/<int:task_id>", methods=["GET"])
def get_task(task_id: int):
...
@tasks.route("/session/<int:session_id>", methods=["POST"]) @tasks.route("/session/<int:session_id>", methods=["POST"])
def create_task(session_id: int): def create_task(session_id: int):
info = request.form info = request.form

View File

@ -1,6 +1,5 @@
from flask import Blueprint, render_template from flask import Blueprint, render_template
from app.blueprints.api.sessions.routes import get_sessions from app.blueprints.api.sessions.routes import get_sessions
from app.blueprints.api.users.routes import get_users
from app.blueprints.api.tasks.routes import get_tasks from app.blueprints.api.tasks.routes import get_tasks
from app.models.collection import Collection from app.models.collection import Collection
@ -21,7 +20,8 @@ def tasks():
@frontend.route("/parse/<int:id>") @frontend.route("/parse/<int:id>")
def parse(id: int): def parse(id: int):
return render_template("parse.j2", session_id=id, users_template=get_users(id)) collections = Collection.query.all()
return render_template("parse.j2", session_id=id, collections=collections)
@frontend.route("/collections") @frontend.route("/collections")
def collections(): def collections():

View File

@ -5,12 +5,19 @@
{% endblock title %} {% endblock title %}
{% block main %} {% block main %}
<form method="post" action="/test" class="container"> <form method="post" action="/api/tasks/session/{{ session_id }}" class="container">
<div class="row"> <div class="row">
<!-- Actions --> <!-- Actions -->
<section class="col-lg mb-3"> <section class="col-lg mb-3">
<div class="separator"> <div class="separator">
<h2>Действия</h2> <div class="d-flex gap-2">
<h2>Действия</h2>
<div id="indicator" class="htmx-indicator">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<hr class="divider"> <hr class="divider">
</div> </div>
<nav class="mb-3"> <nav class="mb-3">
@ -24,14 +31,14 @@
<section class="tab-pane fade show active" id="actions-parse-section"> <section class="tab-pane fade show active" id="actions-parse-section">
<div class="form-floating"> <div class="form-floating">
<input type="text" class="form-control" name="group" id="group-from-input" placeholder="Группа для парсинга"> <input type="text" class="form-control" name="parse" id="group-from-input" placeholder="Группа для парсинга">
<label for="group-from-input">Группа для парсинга</label> <label for="group-from-input">Группа для парсинга</label>
</div> </div>
</section> </section>
<section class="tab-pane fade" id="actions-add-section"> <section class="tab-pane fade" id="actions-add-section">
<div class="form-floating"> <div class="form-floating">
<input type="text" name="url" class="form-control" id="group-to-input" <input type="text" name="url" name="add" class="form-control" id="group-to-input"
placeholder="Группа для добавлнеия"> placeholder="Группа для добавлнеия">
<label for="group-to-input">Группа для добавления</label> <label for="group-to-input">Группа для добавления</label>
</div> </div>
@ -63,7 +70,7 @@
<input <input
type="text" type="text"
class="form-control" class="form-control"
name="collection" name="task_name"
id="task-name-input" id="task-name-input"
placeholder="Название задачи" placeholder="Название задачи"
> >
@ -71,29 +78,9 @@
</div> </div>
<section class="d-flex flex-column gap-3 mb-3"> <section class="d-flex flex-column gap-3 mb-3">
<div class="input-group"> {% include "collections/collections_section.j2" %}
<div class="form-floating">
<input
type="text"
class="form-control"
name="collection"
id="collection-name-input"
placeholder="Группа для парсинга"
>
<label for="collection-name-input">Название базы пользователей</label>
</div>
<button type="submit" class="btn btn-outline-primary">Добавить</button>
</div>
<select class="form-select flex-fill" size="3">
{% for collection in collections %}
<option value="{{collection.id}}">{{ collection.name }}</option>
{% else %}
<option disabled>Добавьте новую базу пользователей</option>
{% endfor %}
</select>
</section> </section>
<button type="submit" class="w-100 btn btn-primary">Создать задачу</button> <button type="submit" hx-post="/api/tasks/session/{{ session_id }}" hx-indicator="#indicator" class="w-100 btn btn-primary">Создать задачу</button>
</section> </section>
</div> </div>
</form> </form>

View File

@ -10,3 +10,8 @@ class Collection(db.Model):
tasks: Mapped[List['Task']] = relationship("Task", back_populates="collection") tasks: Mapped[List['Task']] = relationship("Task", back_populates="collection")
users: Mapped[List['User']] = relationship("User", cascade="all, delete-orphan", back_populates="collection") users: Mapped[List['User']] = relationship("User", cascade="all, delete-orphan", back_populates="collection")
def exists(name: str):
collections = Collection.query.filter_by(name=name).all()
return len(collections) > 0

View File

@ -1,11 +1,9 @@
import asyncio import asyncio
import os
from loguru import logger from loguru import logger
from paper.client import PaperClient from paper.client import PaperClient
from paper.errors import IgnoreException, NeedPasswordException, UserPrivacyException from paper.errors import IgnoreException, NeedPasswordException, UserPrivacyException
from paper.models import Message
class PaperParser: class PaperParser:
@ -17,7 +15,7 @@ class PaperParser:
self.users_to_delete = [] self.users_to_delete = []
async def invite_users(self, users, group, task = None): async def invite_users(self, users, group, task):
await self.client.invite_self(group) await self.client.invite_self(group)
group_participants = await self.client.get_participants(group) group_participants = await self.client.get_participants(group)
@ -33,7 +31,7 @@ class PaperParser:
await self.client.invite_user(user, group) await self.client.invite_user(user, group)
except (UserPrivacyException, IgnoreException) as e: except (UserPrivacyException, IgnoreException):
self.users_to_delete.append(user) self.users_to_delete.append(user)
logger.warning("Exception occurred. Skipping user...") logger.warning("Exception occurred. Skipping user...")
@ -47,6 +45,8 @@ class PaperParser:
# if dialog.is_user: # if dialog.is_user:
# messages = tuple(filter(lambda chat_message: message.text == chat_message.text, await self.client.get_messages(dialog))) # messages = tuple(filter(lambda chat_message: message.text == chat_message.text, await self.client.get_messages(dialog)))
# print(messages) # print(messages)
if not task:
return
for user in users: for user in users:
try: try:
@ -55,7 +55,7 @@ class PaperParser:
await self.client.send_message(user, message, file) await self.client.send_message(user, message, file)
except (UserPrivacyException, IgnoreException) as e: except (UserPrivacyException, IgnoreException):
self.users_to_delete.append(user) self.users_to_delete.append(user)
logger.warning("Exception occurred. Skipping user...") logger.warning("Exception occurred. Skipping user...")