core/docs/admin-panel.md
Untone 82111ed0f6
All checks were successful
Deploy on push / deploy (push) Successful in 7s
Squashed new RBAC
2025-07-02 22:30:21 +03:00

15 KiB
Raw Blame History

Администраторская панель Discours

Обзор

Администраторская панель — это комплексная система управления платформой Discours, предоставляющая полный контроль над пользователями, публикациями, сообществами и их ролями.

Архитектура системы доступа

Уровни доступа

  1. Системные администраторы — email в переменной ADMIN_EMAILS (управление системой через переменные среды)
  2. 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 и полным стектрейсом.

Лучшие практики

  1. Всегда проверяйте роли перед назначением
  2. Используйте транзакции для групповых операций
  3. Логируйте критические изменения
  4. Валидируйте права доступа на каждом этапе
  5. Применяйте принцип минимальных привилегий

Расширение функциональности

Для добавления новых административных функций:

  1. Создайте резолвер с соответствующим декоратором
  2. Добавьте GraphQL схему в schema/admin.graphql
  3. Реализуйте логику с переиспользованием существующих компонентов
  4. Добавьте тесты и документацию
  5. Обновите права доступа при необходимости