Перейти к содержанию

Взаимодействие через виджет (widget_channel)🔗

Назначение🔗

Приложение widget_channel отвечает за реализацию веб-виджета, который можно встроить на сторонние сайты для общения с пользователями. Система включает:

  • профили виджетов (WidgetSettings) с параметрами отображения;

Внимание

Надо бы поменять название на WidgetProfile как везде, а то от варианта стиля осталось

  • управление доменами;
  • выбор иконок (кастомных и базовых);
  • сохранение чатов и сообщений;
  • API для CRUD-операций, загрузки и отображения иконок;
  • защиту по домену.

Все данные предоставляются через API под префиксом /api/v1/widget/.


Основные модели и сущности🔗

WidgetSettings🔗

Наследуется от BaseProfile.

class WidgetSettings(BaseProfile):
    tg_token = models.CharField(...)
    manager_tg_id = ArrayField(...)
    welcome_text = models.TextField(...)
    start_hints = ArrayField(...)
    widget_left = models.BooleanField(...)
    icon = models.ForeignKey(UserIcon, ...)
    base_icon = models.ForeignKey(BaseIcon, ...)
Поле Назначение
tg_token Токен Telegram-бота для оповещений
manager_tg_id Telegram ID менеджеров, получающих уведомления
welcome_text Приветствие при открытии чата
start_hints Стартовые подсказки в окне чата
widget_left Расположение на экране (True = слева)
icon Пользовательская иконка (приоритет ниже)
base_icon Базовая иконка (имеет приоритет, если выбраны обе (что по идее невозможно))

При выборе обеих иконок используется base_icon, icon автоматически сбрасывается.


Domain🔗

class Domain(models.Model):
    owner = models.ForeignKey(WidgetSettings, ...)
    name = models.CharField(unique=True, ...)
Поле Назначение
name Домен, на котором разрешено использовать скрипт

При инициализации виджета клиентская часть передаёт домен, и он сверяется с Domain.name.


UserIcon / BaseIcon🔗

class UserIcon(models.Model):
    owner = models.ForeignKey(CustomUser, ...)
    url = models.CharField(...)
class BaseIcon(models.Model):
    name = models.CharField(...)
    url = models.CharField(...)
  • UserIcon — иконки, загружаемые пользователями. Доступны только владельцу;
  • BaseIcon — предзагруженные иконки, доступны всем.

Chats🔗

class Chats(models.Model):
    widget_owner = models.ForeignKey(WidgetSettings, ...)
    user_id = models.CharField(unique=True, ...)
    date_last_message = models.DateTimeField(...)
    is_favorite = models.BooleanField(...)
    note = models.TextField(...)

user_id — ID клиента (анонимный посетитель), хранимый на фронте; widget_owner.user — владелец чата. Все фильтрации выполняются по widget_owner__user.


Messages🔗

class Messages(models.Model):
    chat = models.ForeignKey(Chats, ...)
    message = models.TextField(...)
    sender = models.CharField(...)
    date = models.DateTimeField(...)

Сообщения сохраняются автоматически при обращении клиента к виджету. Используются в API и в админке.


Связи и использование🔗

  • WidgetSettings создаётся вручную через API или админку;
  • Domain добавляется для защиты по источнику скрипта;
  • При инициализации скрипт обращается к data_service, который проверяет:
    • домен;
    • активность профиля;
    • параметры отображения (welcome_text, icon, и т.д.);
  • Chats и Messages формируются в процессе общения с виджетом;
  • Все обращения к данным через API фильтруются по request.user.

Особенности🔗

  • base_icon имеет приоритет над icon — логика enforced на уровне сериализатора;
  • Все иконки можно загружать, переименовывать и удалять (при удалении физический файл стирается);
  • Чаты привязаны к WidgetSettings, и фильтруются по его user;
  • Виджеты, домены, иконки — строго ограничены по пользователю, доступ к чужим объектам невозможен;
  • Telegram и OpenAI-поля заполняются вручную и используются микросервисом data_service;
  • В админке отключено удаление виджетов, ограничено добавление, и скрыты неиспользуемые поля (BaseProfile).

Приписка

Изначально проект был заточен только под виджет, после переделки на новый вариант основной упор был на интеграции ватсап, вк и тд. когда принялся за виджет то BaseProfile был не адаптирован под виджет и там были лишние поля, поэтому я скрыл лишние поля из админки, в будущем может быть что то придумаю


Админка🔗

WidgetSettings🔗

  • Поля из BaseProfile + специфичные поля только для виджета;
  • service нельзя изменить после создания;
  • DomainInline встроен в форму;
  • Удаление отключено (has_delete_permission = False).

Chats🔗

  • Содержит MessagesInline;
  • Поддерживает фильтрацию по дате, избранному, владельцу;
  • Заметки (note) можно редактировать.

Domains, Icons🔗

  • Все стандартные: фильтры, поиск, отображение;
  • Для UserIcon реализован жёсткий контроль по владельцу.

API🔗

Общая информация🔗

Все эндпоинты доступны по префиксу: /api/v1/widget/ Требуется авторизация по сессии (sessionid + CSRF).

Совет

Подробную документацию энпоинтов можете найти в разделе - API


Эндпоинты🔗

Виджеты🔗

POST /api/v1/widget/settings/create/
PATCH /api/v1/widget/settings/<widget_id>/update/
DELETE /api/v1/widget/settings/<widget_id>/delete/
GET   /api/v1/widget/info/
GET   /api/v1/widget/info/<widget_id>/

Домены🔗

POST /api/v1/widget/settings/<widget_id>/domains/create/
DELETE /api/v1/widget/domains/<domain_id>/delete/

Иконки🔗

GET    /api/v1/widget/settings/user-icons/
GET    /api/v1/widget/settings/base-icons/
POST   /api/v1/widget/settings/user-icon/upload/
PATCH  /api/v1/widget/settings/user-icons/<icon_id>/update-name/
DELETE /api/v1/widget/settings/user-icons/<icon_id>/

Чаты и сообщения🔗

GET /api/v1/widget/chats/
GET /api/v1/widget/messages/<chat_id>/

Использование🔗

  • Фронтенд пользователя использует все CRUD-эндпоинты для управления виджетами, доменами, иконками;
  • Интерфейс админки/личного кабинета обращается к чату и сообщениям;
  • data_service — использует модель WidgetSettings для получения параметров при генерации ответа и проверки авторизации.