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