- Implemented the initial version of the web interface. refactor: Begin Telegram bot refactoring - Started restructuring the bot’s code for better maintainability. chore: Migrate to Flask project structure - Reorganized the application to follow Flask's project structure. cleanup: Extensive code cleanup - Removed redundant code and improved readability. Signed-off-by: UdoChudo <stream@udochudo.ru>
300 lines
12 KiB
Python
300 lines
12 KiB
Python
from flask import current_app
|
||
from sqlalchemy import desc, asc
|
||
import logging
|
||
from app import Regions, db, Users, Subscriptions
|
||
from app.extensions.audit_logger import AuditLogger
|
||
|
||
|
||
auditlog = AuditLogger(db.session)
|
||
logger = logging.getLogger(__name__)
|
||
logger.setLevel(logging.DEBUG)
|
||
|
||
class RegionService:
|
||
def __init__(self):
|
||
self.db = db
|
||
self.auditlog = auditlog
|
||
self.logger = logger
|
||
|
||
def get_regions(self, page=1, per_page=10, sort_field='region_id', sort_order='asc'):
|
||
self.logger.info(f"Получение регионов: page={page}, per_page={per_page}, sort_field={sort_field}, sort_order={sort_order}")
|
||
|
||
# Определение порядка сортировки
|
||
sort_func = asc if sort_order == 'asc' else desc
|
||
|
||
# Получение атрибута модели для сортировки
|
||
if sort_field:
|
||
sort_attr = getattr(Regions, sort_field, Regions.region_id) # По умолчанию сортируем по region_id
|
||
else:
|
||
sort_attr = Regions.region_id
|
||
|
||
# Запрос к базе данных с учетом сортировки и пагинации
|
||
if sort_field == 'region_id':
|
||
regions_query = Regions.query.order_by(sort_func(Regions.region_id.cast(db.Integer))).paginate(page=page, per_page=per_page, error_out=False)
|
||
elif sort_field == 'name':
|
||
regions_query = Regions.query.order_by(sort_func(Regions.region_name)).paginate(page=page, per_page=per_page, error_out=False)
|
||
else:
|
||
regions_query = Regions.query.order_by(sort_func(sort_attr)).paginate(page=page, per_page=per_page, error_out=False)
|
||
|
||
regions_list = [{
|
||
'region_id': r.region_id,
|
||
'name': r.region_name,
|
||
'active': r.active
|
||
} for r in regions_query.items]
|
||
|
||
# bf.app.logger.info(f"Получены регионы: {len(regions_list)} элементов")
|
||
|
||
return {
|
||
'regions': regions_list,
|
||
'total_regions': regions_query.total,
|
||
'total_pages': regions_query.pages,
|
||
'current_page': regions_query.page,
|
||
'per_page': regions_query.per_page
|
||
}
|
||
|
||
def get_region_by_id(self, region_id):
|
||
# bf.app.logger.info(f"Поиск региона по ID: {region_id}")
|
||
|
||
# Получение региона по его ID
|
||
region = Regions.query.filter_by(region_id=region_id).first()
|
||
|
||
if region:
|
||
# bf.app.logger.info(f"Найден регион: {region.region_name}")
|
||
return region.region_name
|
||
else:
|
||
# bf.app.logger.warning(f"Регион с ID {region_id} не найден.")
|
||
return None
|
||
|
||
def get_region_subscribers(self, region_id):
|
||
# bf.app.logger.info(f"Получение подписчиков региона: region_id={region_id}")
|
||
|
||
try:
|
||
region = Regions.query.get(region_id)
|
||
if not region:
|
||
# bf.app.logger.warning(f"Регион с ID {region_id} не найден")
|
||
return {'status': 'error', 'message': 'Регион не найден'}, 404
|
||
|
||
subscribers = self.db.session.query(
|
||
Users).join(Subscriptions).filter(Subscriptions.region_id == region_id).all()
|
||
|
||
subscribers_list = [{
|
||
'chat_id': user.chat_id,
|
||
'telegram_id': user.telegram_id,
|
||
'email': user.user_email
|
||
} for user in subscribers]
|
||
|
||
# bf.app.logger.info(f"Получены подписчики региона {region_id}: {len(subscribers_list)} элементов")
|
||
|
||
return {'status': 'success', 'subscribers': subscribers_list}, 200
|
||
except Exception as e:
|
||
# bf.app.logger.error(f"Ошибка при получении подписчиков региона: {e}")
|
||
return {'status': 'error', 'message': str(e)}, 500
|
||
|
||
def add_region(self, data, user):
|
||
region_id = data.get('region_id')
|
||
name = data.get('name')
|
||
active = data.get('active', True)
|
||
|
||
self.logger.info(f"Добавление региона: region_id={region_id}, name={name}, active={active}")
|
||
|
||
try:
|
||
if not region_id.isdigit():
|
||
self.logger.warning(f"ID региона {region_id} содержит нечисловые символы")
|
||
error_msg = 'ID региона должен содержать только числа.'
|
||
self.auditlog.regions(
|
||
action_type="add",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
name=name,
|
||
region_id=region_id,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 400
|
||
|
||
existing_region = Regions.query.get(region_id)
|
||
if existing_region:
|
||
self.logger.warning(f"Регион с ID {region_id} уже существует")
|
||
error_msg = 'Регион с таким ID уже существует'
|
||
self.auditlog.regions(
|
||
action_type="add",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
name=name,
|
||
region_id=region_id,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 409
|
||
|
||
region = Regions(region_id=region_id, region_name=name, active=active)
|
||
self.db.session.add(region)
|
||
self.db.session.commit()
|
||
|
||
self.logger.info(f"Регион {region_id} успешно добавлен")
|
||
self.auditlog.regions(
|
||
action_type="add",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
name=name,
|
||
region_id=region_id
|
||
)
|
||
return {'status': 'success', 'message': 'Регион добавлен'}, 201
|
||
|
||
except Exception as e:
|
||
self.db.session.rollback()
|
||
error_msg = str(e)
|
||
self.logger.error(f"Ошибка при добавлении региона: {error_msg}")
|
||
self.auditlog.regions(
|
||
action_type="add",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
name=name,
|
||
region_id=region_id,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 500
|
||
|
||
def update_region_status(self, data, user):
|
||
region_id = data.get('region_id')
|
||
new_status = data.get('active')
|
||
|
||
self.logger.info(f"Изменение статуса региона: region_id={region_id}, new_status={new_status}")
|
||
|
||
try:
|
||
region = Regions.query.get(region_id)
|
||
if region:
|
||
old_status = region.active
|
||
region.active = new_status
|
||
self.db.session.commit()
|
||
|
||
self.logger.info(f"Статус региона {region_id} изменён: {old_status} → {new_status}")
|
||
self.auditlog.regions(
|
||
action_type="toggle",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
old_active=old_status,
|
||
active=new_status
|
||
)
|
||
|
||
return {'status': 'success', 'message': 'Статус региона обновлён'}, 200
|
||
else:
|
||
error_msg = f"Регион с ID {region_id} не найден"
|
||
self.logger.warning(error_msg)
|
||
self.auditlog.regions(
|
||
action_type="toggle",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
active=new_status,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': 'Регион не найден'}, 404
|
||
except Exception as e:
|
||
self.db.session.rollback()
|
||
error_msg = str(e)
|
||
self.logger.error(f"Ошибка при изменении статуса региона: {error_msg}")
|
||
self.auditlog.regions(
|
||
action_type="toggle",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
active=new_status,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 500
|
||
|
||
|
||
|
||
def update_region_name(self, data, user):
|
||
region_id = data.get('region_id')
|
||
name = data.get('name')
|
||
|
||
self.logger.info(f"Изменение названия региона: region_id={region_id}, name={name}")
|
||
|
||
try:
|
||
region = Regions.query.get(region_id)
|
||
if region:
|
||
old_name = region.region_name
|
||
region.region_name = name
|
||
self.db.session.commit()
|
||
|
||
self.logger.info(f"Название региона {region_id} изменено с {old_name} на {name}")
|
||
self.auditlog.regions(
|
||
action_type="rename",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
new_name=name,
|
||
old_name=old_name
|
||
)
|
||
|
||
return {'status': 'success', 'message': 'Название региона изменено'}, 200
|
||
else:
|
||
error_msg = f"Регион с ID {region_id} не найден"
|
||
self.logger.warning(error_msg)
|
||
self.auditlog.regions(
|
||
action_type="rename",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
new_name=name,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': 'Регион не найден'}, 404
|
||
except Exception as e:
|
||
self.db.session.rollback()
|
||
error_msg = str(e)
|
||
self.logger.error(f"Ошибка при изменении названия региона: {error_msg}")
|
||
self.auditlog.regions(
|
||
action_type="rename",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
new_name=name,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 500
|
||
|
||
def delete_region(self, region_id, user):
|
||
self.logger.info(f"Удаление региона: region_id={region_id}")
|
||
|
||
try:
|
||
region = Regions.query.get(region_id)
|
||
if region:
|
||
name = region.region_name
|
||
self.db.session.delete(region)
|
||
self.db.session.commit()
|
||
|
||
self.logger.info(f"Регион {region_id} успешно удалён")
|
||
self.auditlog.regions(
|
||
action_type="delete",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
new_name=name
|
||
)
|
||
|
||
return {'status': 'success', 'message': 'Регион удалён'}, 200
|
||
else:
|
||
error_msg = f"Регион с ID {region_id} не найден"
|
||
self.logger.warning(error_msg)
|
||
self.auditlog.regions(
|
||
action_type="delete",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': 'Регион не найден'}, 404
|
||
except Exception as e:
|
||
self.db.session.rollback()
|
||
error_msg = str(e)
|
||
self.logger.error(f"Ошибка при удалении региона: {error_msg}")
|
||
self.auditlog.regions(
|
||
action_type="delete",
|
||
actor_display_name=user.display_name,
|
||
ldap_user_id=user.id,
|
||
region_id=region_id,
|
||
error=error_msg
|
||
)
|
||
return {'status': 'error', 'message': error_msg}, 500
|