2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
|
|
|
|
Модуль для проверки разрешений пользователей в контексте сообществ.
|
|
|
|
|
|
|
|
|
|
Позволяет проверять доступ пользователя к определенным операциям в сообществе
|
|
|
|
|
на основе его роли в этом сообществе.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
2025-07-02 22:30:21 +03:00
|
|
|
|
from auth.orm import Author
|
|
|
|
|
from orm.community import Community, CommunityAuthor
|
2025-05-29 12:37:39 +03:00
|
|
|
|
from settings import ADMIN_EMAILS as ADMIN_EMAILS_LIST
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
|
|
|
|
ADMIN_EMAILS = ADMIN_EMAILS_LIST.split(",")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ContextualPermissionCheck:
|
|
|
|
|
"""
|
|
|
|
|
Класс для проверки контекстно-зависимых разрешений.
|
|
|
|
|
|
|
|
|
|
Позволяет проверять разрешения пользователя в контексте сообщества,
|
|
|
|
|
учитывая как глобальные роли пользователя, так и его роли внутри сообщества.
|
|
|
|
|
"""
|
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
@classmethod
|
2025-07-02 22:30:21 +03:00
|
|
|
|
async def check_community_permission(
|
2025-07-31 18:55:59 +03:00
|
|
|
|
cls, session: Session, author_id: int, community_slug: str, resource: str, operation: str
|
2025-05-16 09:23:48 +03:00
|
|
|
|
) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Проверяет наличие разрешения у пользователя в контексте сообщества.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
session: Сессия SQLAlchemy
|
|
|
|
|
author_id: ID автора/пользователя
|
|
|
|
|
community_slug: Slug сообщества
|
|
|
|
|
resource: Ресурс для доступа
|
|
|
|
|
operation: Операция над ресурсом
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
bool: True, если пользователь имеет разрешение, иначе False
|
|
|
|
|
"""
|
|
|
|
|
# 1. Проверка глобальных разрешений (например, администратор)
|
2025-07-31 18:55:59 +03:00
|
|
|
|
author = session.query(Author).where(Author.id == author_id).one_or_none()
|
2025-05-16 09:23:48 +03:00
|
|
|
|
if not author:
|
|
|
|
|
return False
|
2025-07-02 22:30:21 +03:00
|
|
|
|
# Если это администратор (по списку email)
|
|
|
|
|
if author.email in ADMIN_EMAILS:
|
2025-05-16 09:23:48 +03:00
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# 2. Проверка разрешений в контексте сообщества
|
|
|
|
|
# Получаем информацию о сообществе
|
2025-07-31 18:55:59 +03:00
|
|
|
|
community = session.query(Community).where(Community.slug == community_slug).one_or_none()
|
2025-05-16 09:23:48 +03:00
|
|
|
|
if not community:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# Если автор является создателем сообщества, то у него есть полные права
|
|
|
|
|
if community.created_by == author_id:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# Проверяем наличие разрешения для этих ролей
|
|
|
|
|
permission_id = f"{resource}:{operation}"
|
2025-07-31 18:55:59 +03:00
|
|
|
|
ca = CommunityAuthor.find_author_in_community(author_id, community.id, session)
|
|
|
|
|
return bool(ca.has_permission(permission_id)) if ca else False
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
@classmethod
|
|
|
|
|
def get_user_community_roles(cls, session: Session, author_id: int, community_slug: str) -> list[str]:
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
|
|
|
|
Получает список ролей пользователя в сообществе.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
session: Сессия SQLAlchemy
|
|
|
|
|
author_id: ID автора/пользователя
|
|
|
|
|
community_slug: Slug сообщества
|
|
|
|
|
|
|
|
|
|
Returns:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
List[str]: Список ролей пользователя в сообществе
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
|
|
|
|
# Получаем информацию о сообществе
|
2025-07-31 18:55:59 +03:00
|
|
|
|
community = session.query(Community).where(Community.slug == community_slug).one_or_none()
|
2025-05-16 09:23:48 +03:00
|
|
|
|
if not community:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
# Если автор является создателем сообщества, то у него есть роль владельца
|
|
|
|
|
if community.created_by == author_id:
|
2025-07-02 22:30:21 +03:00
|
|
|
|
return ["editor", "author", "expert", "reader"]
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Находим связь автор-сообщество
|
|
|
|
|
ca = CommunityAuthor.find_author_in_community(author_id, community.id, session)
|
2025-07-02 22:30:21 +03:00
|
|
|
|
return ca.role_list if ca else []
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
@classmethod
|
|
|
|
|
def check_permission(
|
|
|
|
|
cls, session: Session, author_id: int, community_slug: str, resource: str, operation: str
|
|
|
|
|
) -> bool:
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
2025-07-31 18:55:59 +03:00
|
|
|
|
Проверяет наличие разрешения у пользователя в контексте сообщества.
|
|
|
|
|
Синхронный метод для обратной совместимости.
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
session: Сессия SQLAlchemy
|
|
|
|
|
author_id: ID автора/пользователя
|
|
|
|
|
community_slug: Slug сообщества
|
2025-07-31 18:55:59 +03:00
|
|
|
|
resource: Ресурс для доступа
|
|
|
|
|
operation: Операция над ресурсом
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
|
|
|
|
Returns:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
bool: True, если пользователь имеет разрешение, иначе False
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Используем тот же алгоритм, что и в асинхронной версии
|
|
|
|
|
author = session.query(Author).where(Author.id == author_id).one_or_none()
|
|
|
|
|
if not author:
|
|
|
|
|
return False
|
|
|
|
|
# Если это администратор (по списку email)
|
|
|
|
|
if author.email in ADMIN_EMAILS:
|
|
|
|
|
return True
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
|
|
|
|
# Получаем информацию о сообществе
|
2025-07-31 18:55:59 +03:00
|
|
|
|
community = session.query(Community).where(Community.slug == community_slug).one_or_none()
|
2025-05-16 09:23:48 +03:00
|
|
|
|
if not community:
|
|
|
|
|
return False
|
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Если автор является создателем сообщества, то у него есть полные права
|
|
|
|
|
if community.created_by == author_id:
|
|
|
|
|
return True
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Проверяем наличие разрешения для этих ролей
|
|
|
|
|
permission_id = f"{resource}:{operation}"
|
|
|
|
|
ca = CommunityAuthor.find_author_in_community(author_id, community.id, session)
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Возвращаем результат проверки разрешения
|
|
|
|
|
return bool(ca and ca.has_permission(permission_id))
|
|
|
|
|
|
|
|
|
|
async def can_delete_community(self, user_id: int, community: Community, session: Session) -> bool:
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
2025-07-31 18:55:59 +03:00
|
|
|
|
Проверяет, может ли пользователь удалить сообщество.
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
|
|
|
|
Args:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
user_id: ID пользователя
|
|
|
|
|
community: Объект сообщества
|
2025-05-16 09:23:48 +03:00
|
|
|
|
session: Сессия SQLAlchemy
|
|
|
|
|
|
|
|
|
|
Returns:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
bool: True, если пользователь может удалить сообщество, иначе False
|
2025-05-16 09:23:48 +03:00
|
|
|
|
"""
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Если пользователь - создатель сообщества
|
|
|
|
|
if community.created_by == user_id:
|
|
|
|
|
return True
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Проверяем, есть ли у пользователя роль администратора или редактора
|
|
|
|
|
author = session.query(Author).where(Author.id == user_id).first()
|
|
|
|
|
if not author:
|
2025-05-16 09:23:48 +03:00
|
|
|
|
return False
|
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Проверка по email (глобальные администраторы)
|
|
|
|
|
if author.email in ADMIN_EMAILS:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# Проверка ролей в сообществе
|
|
|
|
|
community_author = CommunityAuthor.find_author_in_community(user_id, community.id, session)
|
|
|
|
|
if community_author:
|
|
|
|
|
return "admin" in community_author.role_list or "editor" in community_author.role_list
|
2025-05-16 09:23:48 +03:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
return False
|