import html
import logging
from datetime import datetime
from aiogram import Dispatcher, F, types
from aiogram.fsm.context import FSMContext
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.models import User
from app.localization.texts import get_texts
from app.services.faq_service import FaqService
from app.states import AdminStates
from app.utils.decorators import admin_required, error_handler
from app.utils.validators import get_html_help_text, validate_html_tags
logger = logging.getLogger(__name__)
def _format_timestamp(value: datetime | None) -> str:
if not value:
return ""
try:
return value.strftime("%d.%m.%Y %H:%M")
except Exception:
return ""
async def _build_overview(
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
normalized_language = FaqService.normalize_language(db_user.language)
setting = await FaqService.get_setting(
db,
db_user.language,
fallback=False,
)
pages = await FaqService.get_pages(
db,
db_user.language,
include_inactive=True,
fallback=False,
)
total_pages = len(pages)
active_pages = sum(1 for page in pages if page.is_active)
description = texts.t(
"ADMIN_FAQ_DESCRIPTION",
"FAQ отображается в разделе «Инфо».",
)
if setting and not setting.is_enabled:
status_text = texts.t(
"ADMIN_FAQ_STATUS_DISABLED",
"⚠️ Показ FAQ выключен.",
)
elif active_pages:
status_text = texts.t(
"ADMIN_FAQ_STATUS_ENABLED",
"✅ FAQ включён. Активных страниц: {count}.",
).format(count=active_pages)
elif total_pages:
status_text = texts.t(
"ADMIN_FAQ_STATUS_ENABLED_EMPTY",
"⚠️ FAQ включён, но нет активных страниц.",
)
else:
status_text = texts.t(
"ADMIN_FAQ_STATUS_EMPTY",
"⚠️ FAQ ещё не настроен.",
)
pages_overview = texts.t(
"ADMIN_FAQ_PAGES_EMPTY",
"Страницы ещё не созданы.",
)
if pages:
rows: list[str] = []
for index, page in enumerate(pages, start=1):
title = (page.title or "").strip()
if not title:
title = texts.t("FAQ_PAGE_UNTITLED", "Без названия")
if len(title) > 60:
title = f"{title[:57]}..."
status_label = texts.t(
"ADMIN_FAQ_PAGE_STATUS_ACTIVE",
"✅ Активна",
)
if not page.is_active:
status_label = texts.t(
"ADMIN_FAQ_PAGE_STATUS_INACTIVE",
"🚫 Выключена",
)
updated = _format_timestamp(getattr(page, "updated_at", None))
updated_block = f" ({updated})" if updated else ""
rows.append(
f"{index}. {html.escape(title)} — {status_label}{updated_block}"
)
pages_list_header = texts.t(
"ADMIN_FAQ_PAGES_OVERVIEW",
"Список страниц:\n{items}",
)
pages_overview = pages_list_header.format(items="\n".join(rows))
language_block = texts.t(
"ADMIN_FAQ_LANGUAGE",
"Язык: {lang}",
).format(lang=normalized_language)
stats_block = texts.t(
"ADMIN_FAQ_PAGE_STATS",
"Всего страниц: {total}",
).format(total=total_pages)
header = texts.t("ADMIN_FAQ_HEADER", "❓ FAQ")
actions_prompt = texts.t(
"ADMIN_FAQ_ACTION_PROMPT",
"Выберите действие:",
)
message_parts = [
header,
description,
language_block,
status_text,
stats_block,
pages_overview,
actions_prompt,
]
overview_text = "\n\n".join(part for part in message_parts if part)
buttons: list[list[types.InlineKeyboardButton]] = []
buttons.append([
types.InlineKeyboardButton(
text=texts.t(
"ADMIN_FAQ_ADD_PAGE_BUTTON",
"➕ Добавить страницу",
),
callback_data="admin_faq_create",
)
])
for page in pages[:25]:
title = (page.title or "").strip()
if not title:
title = texts.t("FAQ_PAGE_UNTITLED", "Без названия")
if len(title) > 40:
title = f"{title[:37]}..."
buttons.append([
types.InlineKeyboardButton(
text=f"{page.display_order}. {title}",
callback_data=f"admin_faq_page:{page.id}",
)
])
toggle_text = texts.t(
"ADMIN_FAQ_ENABLE_BUTTON",
"✅ Включить показ",
)
if setting and setting.is_enabled:
toggle_text = texts.t(
"ADMIN_FAQ_DISABLE_BUTTON",
"🚫 Отключить показ",
)
buttons.append([
types.InlineKeyboardButton(
text=toggle_text,
callback_data="admin_faq_toggle",
)
])
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_HTML_HELP", "ℹ️ HTML помощь"),
callback_data="admin_faq_help",
)
])
buttons.append([
types.InlineKeyboardButton(
text=texts.BACK,
callback_data="admin_submenu_settings",
)
])
return overview_text, types.InlineKeyboardMarkup(inline_keyboard=buttons)
@admin_required
@error_handler
async def show_faq_management(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
overview_text, markup = await _build_overview(db_user, db)
await callback.message.edit_text(
overview_text,
reply_markup=markup,
)
await callback.answer()
@admin_required
@error_handler
async def toggle_faq(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
setting = await FaqService.toggle_enabled(db, db_user.language)
if setting.is_enabled:
alert_text = texts.t(
"ADMIN_FAQ_ENABLED_ALERT",
"✅ FAQ включён.",
)
else:
alert_text = texts.t(
"ADMIN_FAQ_DISABLED_ALERT",
"🚫 FAQ отключён.",
)
overview_text, markup = await _build_overview(db_user, db)
await callback.message.edit_text(
overview_text,
reply_markup=markup,
)
await callback.answer(alert_text, show_alert=True)
@admin_required
@error_handler
async def start_create_faq_page(
callback: types.CallbackQuery,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
await state.set_state(AdminStates.creating_faq_title)
await state.update_data(faq_language=db_user.language)
await callback.message.edit_text(
texts.t(
"ADMIN_FAQ_ENTER_TITLE",
"Введите заголовок для новой страницы FAQ:",
),
reply_markup=types.InlineKeyboardMarkup(
inline_keyboard=[
[
types.InlineKeyboardButton(
text=texts.t(
"ADMIN_FAQ_CANCEL_BUTTON",
"⬅️ Отмена",
),
callback_data="admin_faq_cancel",
)
]
]
),
)
await callback.answer()
@admin_required
@error_handler
async def cancel_faq_creation(
callback: types.CallbackQuery,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
await state.clear()
await show_faq_management(callback, db_user, db)
@admin_required
@error_handler
async def process_new_faq_title(
message: types.Message,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
title = (message.text or "").strip()
if not title:
await message.answer(
texts.t(
"ADMIN_FAQ_TITLE_EMPTY",
"❌ Заголовок не может быть пустым.",
)
)
return
if len(title) > 255:
await message.answer(
texts.t(
"ADMIN_FAQ_TITLE_TOO_LONG",
"❌ Заголовок слишком длинный. Максимум 255 символов.",
)
)
return
await state.update_data(faq_title=title)
await state.set_state(AdminStates.creating_faq_content)
await message.answer(
texts.t(
"ADMIN_FAQ_ENTER_CONTENT",
"Отправьте содержимое страницы FAQ. Допускается HTML.",
)
)
@admin_required
@error_handler
async def process_new_faq_content(
message: types.Message,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
content = message.text or ""
if len(content) > 6000:
await message.answer(
texts.t(
"ADMIN_FAQ_CONTENT_TOO_LONG",
"❌ Текст слишком длинный. Максимум 6000 символов.",
)
)
return
if not content.strip():
await message.answer(
texts.t(
"ADMIN_FAQ_CONTENT_EMPTY",
"❌ Текст не может быть пустым.",
)
)
return
is_valid, error_message = validate_html_tags(content)
if not is_valid:
await message.answer(
texts.t(
"ADMIN_FAQ_HTML_ERROR",
"❌ Ошибка в HTML: {error}",
).format(error=error_message)
)
return
data = await state.get_data()
title = data.get("faq_title") or texts.t("FAQ_PAGE_UNTITLED", "Без названия")
language = data.get("faq_language", db_user.language)
await FaqService.create_page(
db,
language=language,
title=title,
content=content,
)
logger.info(
"Админ %s создал страницу FAQ (%d символов)",
db_user.telegram_id,
len(content),
)
await state.clear()
success_text = texts.t(
"ADMIN_FAQ_PAGE_CREATED",
"✅ Страница FAQ создана.",
)
reply_markup = types.InlineKeyboardMarkup(
inline_keyboard=[
[
types.InlineKeyboardButton(
text=texts.t(
"ADMIN_FAQ_BACK_TO_LIST",
"⬅️ К настройкам FAQ",
),
callback_data="admin_faq",
)
]
]
)
await message.answer(success_text, reply_markup=reply_markup)
@admin_required
@error_handler
async def show_faq_page_details(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
raw_id = (callback.data or "").split(":", 1)[-1]
try:
page_id = int(raw_id)
except ValueError:
await callback.answer()
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await callback.answer(
texts.t(
"ADMIN_FAQ_PAGE_NOT_FOUND",
"⚠️ Страница не найдена.",
),
show_alert=True,
)
return
header = texts.t("ADMIN_FAQ_PAGE_HEADER", "📄 Страница FAQ")
title = (page.title or "").strip() or texts.t("FAQ_PAGE_UNTITLED", "Без названия")
status_label = texts.t(
"ADMIN_FAQ_PAGE_STATUS_ACTIVE",
"✅ Активна",
)
if not page.is_active:
status_label = texts.t(
"ADMIN_FAQ_PAGE_STATUS_INACTIVE",
"🚫 Выключена",
)
updated_at = _format_timestamp(getattr(page, "updated_at", None))
updated_block = ""
if updated_at:
updated_block = texts.t(
"ADMIN_FAQ_PAGE_UPDATED",
"Обновлено: {timestamp}",
).format(timestamp=updated_at)
preview = (page.content or "").strip()
preview_text = texts.t(
"ADMIN_FAQ_PAGE_PREVIEW_EMPTY",
"Текст ещё не задан.",
)
if preview:
preview_trimmed = preview[:400]
if len(preview) > 400:
preview_trimmed += "..."
preview_text = (
texts.t("ADMIN_FAQ_PAGE_PREVIEW", "Превью:\n{content}")
.format(content=html.escape(preview_trimmed))
)
message_parts = [
header,
texts.t(
"ADMIN_FAQ_PAGE_TITLE",
"Заголовок: {title}",
).format(title=html.escape(title)),
texts.t(
"ADMIN_FAQ_PAGE_STATUS",
"Статус: {status}",
).format(status=status_label),
preview_text,
updated_block,
]
message_text = "\n\n".join(part for part in message_parts if part)
buttons: list[list[types.InlineKeyboardButton]] = []
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_EDIT_TITLE_BUTTON", "✏️ Изменить заголовок"),
callback_data=f"admin_faq_edit_title:{page.id}",
)
])
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_EDIT_CONTENT_BUTTON", "📝 Изменить текст"),
callback_data=f"admin_faq_edit_content:{page.id}",
)
])
toggle_text = texts.t("ADMIN_FAQ_PAGE_ENABLE_BUTTON", "✅ Включить страницу")
if page.is_active:
toggle_text = texts.t(
"ADMIN_FAQ_PAGE_DISABLE_BUTTON",
"🚫 Выключить страницу",
)
buttons.append([
types.InlineKeyboardButton(
text=toggle_text,
callback_data=f"admin_faq_toggle_page:{page.id}",
)
])
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_PAGE_MOVE_UP", "⬆️ Выше"),
callback_data=f"admin_faq_move:{page.id}:up",
),
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_PAGE_MOVE_DOWN", "⬇️ Ниже"),
callback_data=f"admin_faq_move:{page.id}:down",
),
])
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_PAGE_DELETE_BUTTON", "🗑️ Удалить"),
callback_data=f"admin_faq_delete:{page.id}",
)
])
buttons.append([
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_BACK_TO_LIST", "⬅️ К настройкам FAQ"),
callback_data="admin_faq",
)
])
await callback.message.edit_text(
message_text,
reply_markup=types.InlineKeyboardMarkup(inline_keyboard=buttons),
)
await callback.answer()
@admin_required
@error_handler
async def start_edit_faq_title(
callback: types.CallbackQuery,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
raw_id = (callback.data or "").split(":", 1)[-1]
try:
page_id = int(raw_id)
except ValueError:
await callback.answer()
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await callback.answer(
texts.t(
"ADMIN_FAQ_PAGE_NOT_FOUND",
"⚠️ Страница не найдена.",
),
show_alert=True,
)
return
await state.set_state(AdminStates.editing_faq_title)
await state.update_data(faq_page_id=page.id)
await callback.message.edit_text(
texts.t(
"ADMIN_FAQ_EDIT_TITLE_PROMPT",
"Введите новый заголовок для страницы:",
),
reply_markup=types.InlineKeyboardMarkup(
inline_keyboard=[
[
types.InlineKeyboardButton(
text=texts.t(
"ADMIN_FAQ_CANCEL_BUTTON",
"⬅️ Отмена",
),
callback_data=f"admin_faq_page:{page.id}",
)
]
]
),
)
await callback.answer()
@admin_required
@error_handler
async def process_edit_faq_title(
message: types.Message,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
title = (message.text or "").strip()
if not title:
await message.answer(
texts.t(
"ADMIN_FAQ_TITLE_EMPTY",
"❌ Заголовок не может быть пустым.",
)
)
return
if len(title) > 255:
await message.answer(
texts.t(
"ADMIN_FAQ_TITLE_TOO_LONG",
"❌ Заголовок слишком длинный. Максимум 255 символов.",
)
)
return
data = await state.get_data()
page_id = data.get("faq_page_id")
if not page_id:
await state.clear()
await message.answer(texts.t("ADMIN_FAQ_UNEXPECTED_STATE", "⚠️ Состояние сброшено."))
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await message.answer(
texts.t("ADMIN_FAQ_PAGE_NOT_FOUND", "⚠️ Страница не найдена."),
)
await state.clear()
return
await FaqService.update_page(db, page, title=title)
await state.clear()
await message.answer(
texts.t("ADMIN_FAQ_TITLE_UPDATED", "✅ Заголовок обновлён."),
reply_markup=types.InlineKeyboardMarkup(
inline_keyboard=[[types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_BACK_TO_LIST", "⬅️ К настройкам FAQ"),
callback_data="admin_faq",
)]]
),
)
@admin_required
@error_handler
async def start_edit_faq_content(
callback: types.CallbackQuery,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
raw_id = (callback.data or "").split(":", 1)[-1]
try:
page_id = int(raw_id)
except ValueError:
await callback.answer()
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await callback.answer(
texts.t("ADMIN_FAQ_PAGE_NOT_FOUND", "⚠️ Страница не найдена."),
show_alert=True,
)
return
await state.set_state(AdminStates.editing_faq_content)
await state.update_data(faq_page_id=page.id)
await callback.message.edit_text(
texts.t(
"ADMIN_FAQ_EDIT_CONTENT_PROMPT",
"Отправьте новый текст для страницы FAQ.",
),
reply_markup=types.InlineKeyboardMarkup(
inline_keyboard=[
[
types.InlineKeyboardButton(
text=texts.t(
"ADMIN_FAQ_CANCEL_BUTTON",
"⬅️ Отмена",
),
callback_data=f"admin_faq_page:{page.id}",
)
]
]
),
)
await callback.answer()
@admin_required
@error_handler
async def process_edit_faq_content(
message: types.Message,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
content = message.text or ""
if len(content) > 6000:
await message.answer(
texts.t(
"ADMIN_FAQ_CONTENT_TOO_LONG",
"❌ Текст слишком длинный. Максимум 6000 символов.",
)
)
return
if not content.strip():
await message.answer(
texts.t(
"ADMIN_FAQ_CONTENT_EMPTY",
"❌ Текст не может быть пустым.",
)
)
return
is_valid, error_message = validate_html_tags(content)
if not is_valid:
await message.answer(
texts.t(
"ADMIN_FAQ_HTML_ERROR",
"❌ Ошибка в HTML: {error}",
).format(error=error_message)
)
return
data = await state.get_data()
page_id = data.get("faq_page_id")
if not page_id:
await state.clear()
await message.answer(texts.t("ADMIN_FAQ_UNEXPECTED_STATE", "⚠️ Состояние сброшено."))
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await message.answer(
texts.t("ADMIN_FAQ_PAGE_NOT_FOUND", "⚠️ Страница не найдена."),
)
await state.clear()
return
await FaqService.update_page(db, page, content=content)
await state.clear()
await message.answer(
texts.t("ADMIN_FAQ_CONTENT_UPDATED", "✅ Текст страницы обновлён."),
reply_markup=types.InlineKeyboardMarkup(
inline_keyboard=[[types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_BACK_TO_LIST", "⬅️ К настройкам FAQ"),
callback_data="admin_faq",
)]]
),
)
@admin_required
@error_handler
async def toggle_faq_page(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
parts = (callback.data or "").split(":")
try:
page_id = int(parts[1])
except (ValueError, IndexError):
await callback.answer()
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await callback.answer(
texts.t("ADMIN_FAQ_PAGE_NOT_FOUND", "⚠️ Страница не найдена."),
show_alert=True,
)
return
updated_page = await FaqService.update_page(db, page, is_active=not page.is_active)
alert_text = texts.t(
"ADMIN_FAQ_PAGE_ENABLED_ALERT",
"✅ Страница включена.",
)
if not updated_page.is_active:
alert_text = texts.t(
"ADMIN_FAQ_PAGE_DISABLED_ALERT",
"🚫 Страница выключена.",
)
await callback.answer(alert_text, show_alert=True)
await show_faq_page_details(callback, db_user, db)
@admin_required
@error_handler
async def delete_faq_page(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
parts = (callback.data or "").split(":")
try:
page_id = int(parts[1])
except (ValueError, IndexError):
await callback.answer()
return
page = await FaqService.get_page(
db,
page_id,
db_user.language,
fallback=False,
include_inactive=True,
)
if not page:
await callback.answer(
texts.t("ADMIN_FAQ_PAGE_NOT_FOUND", "⚠️ Страница не найдена."),
show_alert=True,
)
return
await FaqService.delete_page(db, page.id)
remaining_pages = await FaqService.get_pages(
db,
db_user.language,
include_inactive=True,
fallback=False,
)
if remaining_pages:
remaining_sorted = sorted(
remaining_pages,
key=lambda item: (item.display_order, item.id),
)
await FaqService.reorder_pages(db, db_user.language, remaining_sorted)
await callback.answer(
texts.t("ADMIN_FAQ_PAGE_DELETED", "🗑️ Страница удалена."),
show_alert=True,
)
await show_faq_management(callback, db_user, db)
@admin_required
@error_handler
async def move_faq_page(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
texts = get_texts(db_user.language)
parts = (callback.data or "").split(":")
try:
page_id = int(parts[1])
direction = parts[2]
except (ValueError, IndexError):
await callback.answer()
return
pages = await FaqService.get_pages(
db,
db_user.language,
include_inactive=True,
fallback=False,
)
if not pages:
await callback.answer()
return
pages_sorted = sorted(pages, key=lambda item: (item.display_order, item.id))
index = next((i for i, page in enumerate(pages_sorted) if page.id == page_id), None)
if index is None:
await callback.answer()
return
if direction == "up" and index > 0:
pages_sorted[index - 1], pages_sorted[index] = (
pages_sorted[index],
pages_sorted[index - 1],
)
elif direction == "down" and index < len(pages_sorted) - 1:
pages_sorted[index + 1], pages_sorted[index] = (
pages_sorted[index],
pages_sorted[index + 1],
)
else:
await callback.answer()
return
await FaqService.reorder_pages(db, db_user.language, pages_sorted)
await callback.answer(
texts.t("ADMIN_FAQ_PAGE_REORDERED", "✅ Порядок обновлён."),
show_alert=True,
)
await show_faq_page_details(callback, db_user, db)
@admin_required
@error_handler
async def show_faq_html_help(
callback: types.CallbackQuery,
db_user: User,
state: FSMContext,
db: AsyncSession,
):
texts = get_texts(db_user.language)
help_text = get_html_help_text()
buttons = [[
types.InlineKeyboardButton(
text=texts.t("ADMIN_FAQ_BACK_TO_LIST", "⬅️ К настройкам FAQ"),
callback_data="admin_faq",
)
]]
await callback.message.edit_text(
help_text,
reply_markup=types.InlineKeyboardMarkup(inline_keyboard=buttons),
)
await callback.answer()
def register_handlers(dp: Dispatcher) -> None:
dp.callback_query.register(
show_faq_management,
F.data == "admin_faq",
)
dp.callback_query.register(
toggle_faq,
F.data == "admin_faq_toggle",
)
dp.callback_query.register(
start_create_faq_page,
F.data == "admin_faq_create",
)
dp.callback_query.register(
cancel_faq_creation,
F.data == "admin_faq_cancel",
)
dp.callback_query.register(
show_faq_page_details,
F.data.startswith("admin_faq_page:"),
)
dp.callback_query.register(
start_edit_faq_title,
F.data.startswith("admin_faq_edit_title:"),
)
dp.callback_query.register(
start_edit_faq_content,
F.data.startswith("admin_faq_edit_content:"),
)
dp.callback_query.register(
toggle_faq_page,
F.data.startswith("admin_faq_toggle_page:"),
)
dp.callback_query.register(
delete_faq_page,
F.data.startswith("admin_faq_delete:"),
)
dp.callback_query.register(
move_faq_page,
F.data.startswith("admin_faq_move:"),
)
dp.callback_query.register(
show_faq_html_help,
F.data == "admin_faq_help",
)
dp.message.register(
process_new_faq_title,
AdminStates.creating_faq_title,
)
dp.message.register(
process_new_faq_content,
AdminStates.creating_faq_content,
)
dp.message.register(
process_edit_faq_title,
AdminStates.editing_faq_title,
)
dp.message.register(
process_edit_faq_content,
AdminStates.editing_faq_content,
)