5d06d4d3ce
Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
3.8 KiB
Python
87 lines
3.8 KiB
Python
from django.db import models
|
||
from django.utils.translation import gettext_lazy as _
|
||
from django.core.exceptions import ValidationError
|
||
from .base import BaseModel
|
||
from .fields import EncryptedCharField
|
||
|
||
|
||
class ConnectorConfig(BaseModel):
|
||
CONNECTOR_TYPES = [
|
||
('mattermost', 'Mattermost'),
|
||
('ad', 'Active Directory'),
|
||
('carbonio', 'Carbonio CE'),
|
||
('mail', 'Почта (IMAP/SMTP)'),
|
||
('nextcloud', 'Nextcloud'),
|
||
('onlyoffice', 'OnlyOffice'),
|
||
('asterisk', 'Asterisk AMI'),
|
||
]
|
||
|
||
connector_type = models.CharField(
|
||
_('Тип коннектора'), max_length=20,
|
||
choices=CONNECTOR_TYPES, unique=True
|
||
)
|
||
is_enabled = models.BooleanField(_('Включён'), default=False)
|
||
|
||
# Подключение
|
||
host = models.CharField(_('Хост'), max_length=255, blank=True)
|
||
port = models.PositiveIntegerField(_('Порт'), null=True, blank=True)
|
||
use_ssl = models.BooleanField(_('Использовать SSL'), default=True)
|
||
|
||
# Аутентификация
|
||
username = models.CharField(_('Логин'), max_length=255, blank=True)
|
||
# password/token хранятся в БД зашифрованными (Fernet). max_length задан с
|
||
# запасом под шифртекст, который длиннее открытого текста.
|
||
password = EncryptedCharField(_('Пароль'), max_length=512, blank=True)
|
||
token = EncryptedCharField(
|
||
_('Токен / API Key'), max_length=1024, blank=True,
|
||
help_text=_('Bearer-токен или API-ключ, если используется вместо логина/пароля')
|
||
)
|
||
|
||
# Дополнительные параметры коннектора
|
||
extra_config = models.JSONField(
|
||
_('Дополнительные параметры'), default=dict, blank=True,
|
||
help_text=_(
|
||
'JSON. Nextcloud: verify_ssl, timeout. '
|
||
'OnlyOffice: public_url, callback_base, verify_ssl. '
|
||
'Asterisk AMI: originate_context (from-internal), '
|
||
'sip_channel (PJSIP/{exten}), analog_channel (DAHDI/{exten}), timeout.'
|
||
),
|
||
)
|
||
|
||
notes = models.TextField(_('Примечания'), blank=True)
|
||
|
||
class Meta:
|
||
verbose_name = _('Настройки коннектора')
|
||
verbose_name_plural = _('Настройки коннекторов')
|
||
ordering = ['connector_type']
|
||
|
||
def __str__(self):
|
||
status = '✓' if self.is_enabled else '✗'
|
||
return f'{status} {self.get_connector_type_display()}'
|
||
|
||
def clean(self):
|
||
super().clean()
|
||
if self.is_enabled and not self.host:
|
||
raise ValidationError({'host': _('Хост обязателен для включённого коннектора')})
|
||
if self.connector_type == 'asterisk' and self.is_enabled:
|
||
errors = {}
|
||
if not self.username:
|
||
errors['username'] = _('Для AMI нужен логин менеджера')
|
||
if not self.password:
|
||
errors['password'] = _('Для AMI нужен секрет (password)')
|
||
if errors:
|
||
raise ValidationError(errors)
|
||
elif self.is_enabled and not self.token and not self.username:
|
||
raise ValidationError(
|
||
_('Для включённого коннектора необходимо указать токен или логин')
|
||
)
|
||
|
||
@classmethod
|
||
def get_for(cls, connector_type: str) -> 'ConnectorConfig | None':
|
||
"""Получить конфиг коннектора. Возвращает None если не найден или отключён."""
|
||
try:
|
||
cfg = cls.objects.get(connector_type=connector_type)
|
||
return cfg if cfg.is_enabled else None
|
||
except cls.DoesNotExist:
|
||
return None
|