core/resolvers/admin.py
2025-07-03 00:20:10 +03:00

356 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Админ-резолверы - тонкие GraphQL обёртки над AdminService
"""
from typing import Any
from graphql import GraphQLResolveInfo
from graphql.error import GraphQLError
from auth.decorators import admin_auth_required
from services.admin import admin_service
from services.schema import mutation, query
from utils.logger import root_logger as logger
def handle_error(operation: str, error: Exception) -> GraphQLError:
"""Обрабатывает ошибки в резолверах"""
logger.error(f"Ошибка при {operation}: {error}")
return GraphQLError(f"Не удалось {operation}: {error}")
# === ПОЛЬЗОВАТЕЛИ ===
@query.field("adminGetUsers")
@admin_auth_required
async def admin_get_users(
_: None, _info: GraphQLResolveInfo, limit: int = 20, offset: int = 0, search: str = ""
) -> dict[str, Any]:
"""Получает список пользователей"""
try:
return admin_service.get_users(limit, offset, search)
except Exception as e:
raise handle_error("получении списка пользователей", e) from e
@mutation.field("adminUpdateUser")
@admin_auth_required
async def admin_update_user(_: None, _info: GraphQLResolveInfo, user: dict[str, Any]) -> dict[str, Any]:
"""Обновляет данные пользователя"""
try:
return admin_service.update_user(user)
except Exception as e:
logger.error(f"Ошибка обновления пользователя: {e}")
return {"success": False, "error": str(e)}
# === ПУБЛИКАЦИИ ===
@query.field("adminGetShouts")
@admin_auth_required
async def admin_get_shouts(
_: None,
_info: GraphQLResolveInfo,
limit: int = 20,
offset: int = 0,
search: str = "",
status: str = "all",
community: int = None,
) -> dict[str, Any]:
"""Получает список публикаций"""
try:
return admin_service.get_shouts(limit, offset, search, status, community)
except Exception as e:
raise handle_error("получении списка публикаций", e) from e
@mutation.field("adminUpdateShout")
@admin_auth_required
async def admin_update_shout(_: None, info: GraphQLResolveInfo, shout: dict[str, Any]) -> dict[str, Any]:
"""Обновляет публикацию через editor.py"""
try:
from resolvers.editor import update_shout
shout_id = shout.get("id")
if not shout_id:
return {"success": False, "error": "ID публикации не указан"}
shout_input = {k: v for k, v in shout.items() if k != "id"}
result = await update_shout(None, info, shout_id, shout_input)
if result.error:
return {"success": False, "error": result.error}
logger.info(f"Публикация {shout_id} обновлена через админ-панель")
return {"success": True}
except Exception as e:
logger.error(f"Ошибка обновления публикации: {e}")
return {"success": False, "error": str(e)}
@mutation.field("adminDeleteShout")
@admin_auth_required
async def admin_delete_shout(_: None, info: GraphQLResolveInfo, shout_id: int) -> dict[str, Any]:
"""Удаляет публикацию через editor.py"""
try:
from resolvers.editor import delete_shout
result = await delete_shout(None, info, shout_id)
if result.error:
return {"success": False, "error": result.error}
logger.info(f"Публикация {shout_id} удалена через админ-панель")
return {"success": True}
except Exception as e:
logger.error(f"Ошибка удаления публикации: {e}")
return {"success": False, "error": str(e)}
@mutation.field("adminRestoreShout")
@admin_auth_required
async def admin_restore_shout(_: None, _info: GraphQLResolveInfo, shout_id: int) -> dict[str, Any]:
"""Восстанавливает удаленную публикацию"""
try:
return admin_service.restore_shout(shout_id)
except Exception as e:
logger.error(f"Ошибка восстановления публикации: {e}")
return {"success": False, "error": str(e)}
# === ПРИГЛАШЕНИЯ ===
@query.field("adminGetInvites")
@admin_auth_required
async def admin_get_invites(
_: None, _info: GraphQLResolveInfo, limit: int = 20, offset: int = 0, search: str = "", status: str = "all"
) -> dict[str, Any]:
"""Получает список приглашений"""
try:
return admin_service.get_invites(limit, offset, search, status)
except Exception as e:
raise handle_error("получении списка приглашений", e) from e
@mutation.field("adminUpdateInvite")
@admin_auth_required
async def admin_update_invite(_: None, _info: GraphQLResolveInfo, invite: dict[str, Any]) -> dict[str, Any]:
"""Обновляет приглашение"""
try:
return admin_service.update_invite(invite)
except Exception as e:
logger.error(f"Ошибка обновления приглашения: {e}")
return {"success": False, "error": str(e)}
@mutation.field("adminDeleteInvite")
@admin_auth_required
async def admin_delete_invite(
_: None, _info: GraphQLResolveInfo, inviter_id: int, author_id: int, shout_id: int
) -> dict[str, Any]:
"""Удаляет приглашение"""
try:
return admin_service.delete_invite(inviter_id, author_id, shout_id)
except Exception as e:
logger.error(f"Ошибка удаления приглашения: {e}")
return {"success": False, "error": str(e)}
# === ТОПИКИ ===
@query.field("adminGetTopics")
@admin_auth_required
async def admin_get_topics(_: None, _info: GraphQLResolveInfo, community_id: int) -> list[dict[str, Any]]:
"""Получает все топики сообщества для админ-панели"""
try:
from orm.topic import Topic
from services.db import local_session
with local_session() as session:
# Получаем все топики сообщества без лимитов
topics = session.query(Topic).filter(Topic.community == community_id).order_by(Topic.id).all()
# Сериализуем топики в простой формат для админки
result: list[dict[str, Any]] = [
{
"id": topic.id,
"title": topic.title or "",
"slug": topic.slug or f"topic-{topic.id}",
"body": topic.body or "",
"community": topic.community,
"parent_ids": topic.parent_ids or [],
"pic": topic.pic,
"oid": getattr(topic, "oid", None),
"is_main": getattr(topic, "is_main", False),
}
for topic in topics
]
logger.info("Загружено топиков для сообщества", len(result))
return result
except Exception as e:
raise handle_error("получении списка топиков", e) from e
# === ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ ===
@query.field("getEnvVariables")
@admin_auth_required
async def get_env_variables(_: None, _info: GraphQLResolveInfo) -> list[dict[str, Any]]:
"""Получает переменные окружения"""
try:
return await admin_service.get_env_variables()
except Exception as e:
logger.error("Ошибка получения переменных окружения", e)
raise GraphQLError("Не удалось получить переменные окружения", e) from e
@mutation.field("updateEnvVariable")
@admin_auth_required
async def update_env_variable(_: None, _info: GraphQLResolveInfo, key: str, value: str) -> dict[str, Any]:
"""Обновляет переменную окружения"""
return await admin_service.update_env_variable(key, value)
@mutation.field("updateEnvVariables")
@admin_auth_required
async def update_env_variables(_: None, _info: GraphQLResolveInfo, variables: list[dict[str, Any]]) -> dict[str, Any]:
"""Массовое обновление переменных окружения"""
return await admin_service.update_env_variables(variables)
# === РОЛИ ===
@query.field("adminGetRoles")
@admin_auth_required
async def admin_get_roles(_: None, _info: GraphQLResolveInfo, community: int = None) -> list[dict[str, Any]]:
"""Получает список ролей"""
try:
return admin_service.get_roles(community)
except Exception as e:
logger.error("Ошибка получения ролей", e)
raise GraphQLError("Не удалось получить роли", e) from e
# === ЗАГЛУШКИ ДЛЯ ОСТАЛЬНЫХ РЕЗОЛВЕРОВ ===
# [предположение] Эти резолверы пока оставляем как есть, но их тоже нужно будет упростить
@query.field("adminGetUserCommunityRoles")
@admin_auth_required
async def admin_get_user_community_roles(
_: None, _info: GraphQLResolveInfo, author_id: int, community_id: int
) -> dict[str, Any]:
"""Получает роли пользователя в сообществе"""
# [непроверенное] Временная заглушка - нужно вынести в сервис
from orm.community import CommunityAuthor
from services.db import local_session
try:
with local_session() as session:
community_author = (
session.query(CommunityAuthor)
.filter(CommunityAuthor.author_id == author_id, CommunityAuthor.community_id == community_id)
.first()
)
roles = []
if community_author and community_author.roles:
roles = [role.strip() for role in community_author.roles.split(",") if role.strip()]
return {"author_id": author_id, "community_id": community_id, "roles": roles}
except Exception as e:
raise handle_error("получении ролей пользователя в сообществе", e) from e
@query.field("adminGetCommunityMembers")
@admin_auth_required
async def admin_get_community_members(
_: None, _info: GraphQLResolveInfo, community_id: int, limit: int = 20, offset: int = 0
) -> dict[str, Any]:
"""Получает участников сообщества"""
# [непроверенное] Временная заглушка - нужно вынести в сервис
from sqlalchemy.sql import func
from auth.orm import Author
from orm.community import CommunityAuthor
from services.db import local_session
try:
with local_session() as session:
members_query = (
session.query(Author, CommunityAuthor)
.join(CommunityAuthor, Author.id == CommunityAuthor.author_id)
.filter(CommunityAuthor.community_id == community_id)
.offset(offset)
.limit(limit)
)
members = []
for author, community_author in members_query:
roles = []
if community_author.roles:
roles = [role.strip() for role in community_author.roles.split(",") if role.strip()]
members.append(
{
"id": author.id,
"name": author.name,
"email": author.email,
"slug": author.slug,
"roles": roles,
}
)
total = (
session.query(func.count(CommunityAuthor.author_id))
.filter(CommunityAuthor.community_id == community_id)
.scalar()
)
return {"members": members, "total": total, "community_id": community_id}
except Exception as e:
logger.error(f"Ошибка получения участников сообщества: {e}")
return {"members": [], "total": 0, "community_id": community_id}
@query.field("adminGetCommunityRoleSettings")
@admin_auth_required
async def admin_get_community_role_settings(_: None, _info: GraphQLResolveInfo, community_id: int) -> dict[str, Any]:
"""Получает настройки ролей сообщества"""
# [непроверенное] Временная заглушка - нужно вынести в сервис
from orm.community import Community
from services.db import local_session
try:
with local_session() as session:
community = session.query(Community).filter(Community.id == community_id).first()
if not community:
return {
"community_id": community_id,
"default_roles": ["reader"],
"available_roles": ["reader", "author", "artist", "expert", "editor", "admin"],
"error": "Сообщество не найдено",
}
return {
"community_id": community_id,
"default_roles": community.get_default_roles(),
"available_roles": community.get_available_roles(),
"error": None,
}
except Exception as e:
logger.error(f"Ошибка получения настроек ролей: {e}")
return {
"community_id": community_id,
"default_roles": ["reader"],
"available_roles": ["reader", "author", "artist", "expert", "editor", "admin"],
"error": str(e),
}