15 KiB
Администраторская панель Discours
Обзор
Администраторская панель — это комплексная система управления платформой Discours, предоставляющая полный контроль над пользователями, публикациями, сообществами и их ролями.
Архитектура системы доступа
Уровни доступа
- Системные администраторы — email в переменной
ADMIN_EMAILS
(управление системой через переменные среды) - RBAC роли в сообществах —
reader
,author
,artist
,expert
,editor
,admin
(управляемые через админку)
ВАЖНО:
- Роль
admin
в RBAC — это обычная роль в сообществе, управляемая через админку - "Системный администратор" — синтетическая роль, которая НЕ хранится в базе данных
- Синтетическая роль добавляется только в API ответы для пользователей из
ADMIN_EMAILS
- На фронте в сообществах синтетическая роль НЕ отображается
Декораторы безопасности
@admin_auth_required # Доступ только системным админам (ADMIN_EMAILS)
@editor_or_admin_required # Доступ редакторам и админам сообщества (RBAC роли)
Модули администрирования
1. Управление пользователями
Получение списка пользователей
query AdminGetUsers(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
) {
adminGetUsers(limit: $limit, offset: $offset, search: $search) {
authors {
id
email
name
slug
roles
created_at
last_seen
}
total
page
perPage
totalPages
}
}
Особенности:
- Поиск по email, имени и ID
- Пагинация с ограничением 1-100 записей
- Роли получаются из основного сообщества (ID=1)
- Автоматическое добавление синтетической роли "Системный администратор" для email из
ADMIN_EMAILS
Обновление пользователя
mutation AdminUpdateUser($user: AdminUserUpdateInput!) {
adminUpdateUser(user: $user) {
success
error
}
}
Поддерживаемые поля:
email
— с проверкой уникальностиname
— имя пользователяslug
— с проверкой уникальностиroles
— массив ролей для основного сообщества
2. Система ролей и разрешений (RBAC)
Иерархия ролей
reader → author → artist → expert → editor → admin
Каждая роль наследует права предыдущих только при инициализации сообщества.
Получение ролей
query AdminGetRoles($community: Int) {
adminGetRoles(community: $community) {
id
name
description
}
}
- Без
community
— все системные роли - С
community
— роли конкретного сообщества + счетчик разрешений
Управление ролями в сообществах
Получение ролей пользователя:
query AdminGetUserCommunityRoles(
$author_id: Int!
$community_id: Int!
) {
adminGetUserCommunityRoles(
author_id: $author_id
community_id: $community_id
) {
author_id
community_id
roles
}
}
Назначение ролей:
mutation AdminSetUserCommunityRoles(
$author_id: Int!
$community_id: Int!
$roles: [String!]!
) {
adminSetUserCommunityRoles(
author_id: $author_id
community_id: $community_id
roles: $roles
) {
success
error
author_id
community_id
roles
}
}
Добавление отдельной роли:
mutation AdminAddUserToRole(
$author_id: Int!
$role_id: String!
$community_id: Int!
) {
adminAddUserToRole(
author_id: $author_id
role_id: $role_id
community_id: $community_id
) {
success
error
}
}
Удаление роли:
mutation AdminRemoveUserFromRole(
$author_id: Int!
$role_id: String!
$community_id: Int!
) {
adminRemoveUserFromRole(
author_id: $author_id
role_id: $role_id
community_id: $community_id
) {
success
removed
}
}
3. Управление сообществами
Участники сообщества
query AdminGetCommunityMembers(
$community_id: Int!
$limit: Int = 20
$offset: Int = 0
) {
adminGetCommunityMembers(
community_id: $community_id
limit: $limit
offset: $offset
) {
members {
id
name
email
slug
roles
}
total
community_id
}
}
Настройки ролей сообщества
Получение настроек:
query AdminGetCommunityRoleSettings($community_id: Int!) {
adminGetCommunityRoleSettings(community_id: $community_id) {
community_id
default_roles
available_roles
error
}
}
Обновление настроек:
mutation AdminUpdateCommunityRoleSettings(
$community_id: Int!
$default_roles: [String!]!
$available_roles: [String!]!
) {
adminUpdateCommunityRoleSettings(
community_id: $community_id
default_roles: $default_roles
available_roles: $available_roles
) {
success
error
community_id
default_roles
available_roles
}
}
Создание пользовательской роли
mutation AdminCreateCustomRole($role: CustomRoleInput!) {
adminCreateCustomRole(role: $role) {
success
error
role {
id
name
description
}
}
}
Удаление пользовательской роли
mutation AdminDeleteCustomRole(
$role_id: String!
$community_id: Int!
) {
adminDeleteCustomRole(
role_id: $role_id
community_id: $community_id
) {
success
error
}
}
4. Управление публикациями
Получение списка публикаций
query AdminGetShouts(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
$status: String = "all"
$community: Int
) {
adminGetShouts(
limit: $limit
offset: $offset
search: $search
status: $status
community: $community
) {
shouts {
id
title
slug
body
lead
subtitle
# ... остальные поля
created_by {
id
email
name
slug
}
community {
id
name
slug
}
authors {
id
email
name
slug
}
topics {
id
title
slug
}
}
total
page
perPage
totalPages
}
}
Статусы публикаций:
all
— все публикации (включая удаленные)published
— опубликованныеdraft
— черновикиdeleted
— удаленные
Операции с публикациями
Обновление:
mutation AdminUpdateShout($shout: AdminShoutUpdateInput!) {
adminUpdateShout(shout: $shout) {
success
error
}
}
Удаление (мягкое):
mutation AdminDeleteShout($shout_id: Int!) {
adminDeleteShout(shout_id: $shout_id) {
success
error
}
}
Восстановление:
mutation AdminRestoreShout($shout_id: Int!) {
adminRestoreShout(shout_id: $shout_id) {
success
error
}
}
5. Управление приглашениями
Получение списка приглашений
query AdminGetInvites(
$limit: Int = 20
$offset: Int = 0
$search: String = ""
$status: String = "all"
) {
adminGetInvites(
limit: $limit
offset: $offset
search: $search
status: $status
) {
invites {
inviter_id
author_id
shout_id
status
inviter {
id
email
name
slug
}
author {
id
email
name
slug
}
shout {
id
title
slug
created_by {
id
email
name
slug
}
}
}
total
page
perPage
totalPages
}
}
Статусы приглашений:
PENDING
— ожидает ответаACCEPTED
— принятоREJECTED
— отклонено
Операции с приглашениями
Обновление статуса:
mutation AdminUpdateInvite($invite: AdminInviteUpdateInput!) {
adminUpdateInvite(invite: $invite) {
success
error
}
}
Удаление:
mutation AdminDeleteInvite(
$inviter_id: Int!
$author_id: Int!
$shout_id: Int!
) {
adminDeleteInvite(
inviter_id: $inviter_id
author_id: $author_id
shout_id: $shout_id
) {
success
error
}
}
Пакетное удаление:
mutation AdminDeleteInvitesBatch($invites: [AdminInviteIdInput!]!) {
adminDeleteInvitesBatch(invites: $invites) {
success
error
}
}
6. Переменные окружения
Системные администраторы могут управлять переменными окружения:
query GetEnvVariables {
getEnvVariables {
name
description
variables {
key
value
description
type
isSecret
}
}
}
mutation UpdateEnvVariable($key: String!, $value: String!) {
updateEnvVariable(key: $key, value: $value) {
success
error
}
}
Особенности реализации
Принцип DRY
- Переиспользование логики из
reader.py
,editor.py
- Общие утилиты в
_get_user_roles()
- Централизованная обработка ошибок
Новая RBAC система
- Роли хранятся в CSV формате в
CommunityAuthor.roles
- Методы модели:
add_role()
,remove_role()
,set_roles()
,has_role()
- Права наследуются только при инициализации
- Redis кэширование развернутых прав
Синтетические роли
- "Системный администратор" — добавляется автоматически для пользователей из
ADMIN_EMAILS
- НЕ хранится в базе данных, только в API ответах
- НЕ отображается на фронте в интерфейсах управления сообществами
- Используется только для индикации системных прав доступа
Безопасность
- Валидация всех входных данных
- Проверка существования сущностей
- Контроль доступа через декораторы
- Логирование всех административных действий
Производительность
- Пагинация для всех списков
- Индексы по ключевым полям
- Ограничения на размер выборки (max 100)
- Оптимизированные SQL запросы с
joinedload
Миграция данных
При переходе на новую RBAC систему используется функция:
from orm.community import migrate_old_roles_to_community_author
migrate_old_roles_to_community_author()
Функция автоматически переносит роли из старых таблиц в новый формат CSV.
Мониторинг и логирование
Все административные действия логируются с уровнем INFO:
- Изменение ролей пользователей
- Обновление настроек сообществ
- Операции с публикациями
- Управление приглашениями
Ошибки логируются с уровнем ERROR и полным стектрейсом.
Лучшие практики
- Всегда проверяйте роли перед назначением
- Используйте транзакции для групповых операций
- Логируйте критические изменения
- Валидируйте права доступа на каждом этапе
- Применяйте принцип минимальных привилегий
Расширение функциональности
Для добавления новых административных функций:
- Создайте резолвер с соответствующим декоратором
- Добавьте GraphQL схему в
schema/admin.graphql
- Реализуйте логику с переиспользованием существующих компонентов
- Добавьте тесты и документацию
- Обновите права доступа при необходимости