| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- from django.conf import settings
- from urllib.parse import parse_qs, urlparse
- from django.conf import settings as django_settings
- from django.core.exceptions import ValidationError
- from django.db import models
- from landing.rich_text import render_rich_html, sanitize_rich_html
- class LandingPage(models.Model):
- title = models.CharField(max_length=150)
- slug = models.SlugField(unique=True)
- content = models.TextField(blank=True, null=True)
- def clean(self):
- super().clean()
- self.content = sanitize_rich_html(self.content)
- def save(self, *args, **kwargs):
- self.content = sanitize_rich_html(self.content)
- return super().save(*args, **kwargs)
- @property
- def rendered_content(self):
- return render_rich_html(self.content)
- def __str__(self) -> str:
- return self.title
- class Meta:
- verbose_name = 'Простая страница'
- verbose_name_plural = 'Простые страницы'
- class FAQmodel(models.Model):
- question = models.TextField(blank=True)
- answer = models.TextField(blank=True)
- def __str__(self) -> str:
- return self.question
- class Meta:
- verbose_name = 'FAQ'
- class LandingMainPageSettings(models.Model):
- title = models.CharField(
- 'Название набора настроек',
- max_length=150,
- default='Главная страница',
- )
- is_active = models.BooleanField(
- 'Активно',
- default=True,
- )
- hero_title = models.CharField(
- 'Главный заголовок',
- max_length=255,
- blank=True,
- default='Цифровой сервис для управления услугами',
- )
- hero_text = models.TextField(
- 'Текст главного блока',
- blank=True,
- default='Подключайте услуги, управляйте предложениями и показывайте клиентам понятную информацию о сервисе.',
- )
- hero_image = models.ImageField(
- 'Базовое изображение лендинга',
- upload_to='landing/main/',
- blank=True,
- null=True,
- )
- services_title = models.CharField(
- 'Заголовок блока услуг',
- max_length=255,
- blank=True,
- default='Наши услуги',
- )
- services_text = models.TextField(
- 'Текст блока услуг',
- blank=True,
- default='Раздел объединяет основные категории услуг сервиса и помогает пользователям быстро перейти к подходящему предложению.',
- )
- about_title = models.CharField(
- 'Заголовок блока о компании',
- max_length=255,
- blank=True,
- default='О компании',
- )
- about_text = models.TextField(
- 'Текст блока о компании',
- blank=True,
- default='Опишите здесь компанию, ее сервис, подход к работе и преимущества для пользователей и партнеров.',
- )
- video_url = models.URLField(
- 'Ссылка для видео',
- max_length=500,
- blank=True,
- )
- extra_section_title = models.CharField(
- 'Заголовок дополнительного раздела',
- max_length=255,
- blank=True,
- default='Дополнительные возможности сервиса',
- )
- image_block_title = models.CharField(
- 'Подзаголовок блока с изображением',
- max_length=255,
- blank=True,
- default='Как это работает',
- )
- image_block_text = models.TextField(
- 'Текст блока с изображением',
- blank=True,
- default='Используйте этот блок, чтобы рассказать о подключении, особенностях работы сервиса или преимуществах для партнеров и клиентов.',
- )
- image_block_image = models.ImageField(
- 'Изображение дополнительного блока',
- upload_to='landing/main/',
- blank=True,
- null=True,
- )
- faq_csv = models.FileField(
- 'CSV-файл с вопросами и ответами FAQ',
- upload_to='landing/faq/',
- blank=True,
- null=True,
- help_text=(
- 'Необязательный файл для раздела FAQ. Рекомендуемый формат CSV: '
- 'question;answer;keywords. Первая строка может быть заголовком. '
- 'question — вопрос, answer — готовый ответ, keywords — ключевые слова '
- 'через запятую или точку с запятой. Если подходящий ответ в файле не найден, '
- 'будет использован ответ нейросети.'
- ),
- )
- team_title = models.CharField(
- 'Заголовок блока команды',
- max_length=255,
- blank=True,
- default='Наша команда',
- )
- team_text = models.TextField(
- 'Текст блока команды',
- blank=True,
- default='Добавьте участников команды, которые отвечают за развитие, поддержку и сопровождение сервиса.',
- )
- updated_at = models.DateTimeField(
- 'Обновлено',
- auto_now=True,
- )
- @classmethod
- def get_current(cls):
- return (
- cls.objects
- .filter(is_active=True)
- .order_by('-updated_at', '-id')
- .first()
- )
- @property
- def video_embed_url(self):
- video_url = str(self.video_url or '').strip()
- if not video_url:
- return ''
- parsed_url = urlparse(video_url)
- hostname = parsed_url.hostname or ''
- path_parts = [part for part in parsed_url.path.split('/') if part]
- if 'youtube.com' in hostname:
- if path_parts[:1] == ['embed'] and len(path_parts) > 1:
- return video_url
- video_id = parse_qs(parsed_url.query).get('v', [''])[0]
- if video_id:
- return f'https://www.youtube.com/embed/{video_id}'
- if 'youtu.be' in hostname and path_parts:
- return f'https://www.youtube.com/embed/{path_parts[0]}'
- if 'rutube.ru' in hostname and len(path_parts) >= 2 and path_parts[0] == 'video':
- return f'https://rutube.ru/play/embed/{path_parts[1]}'
- return video_url
- @property
- def header_title(self):
- return self.hero_title
- @property
- def header_slogan(self):
- return self.hero_text
- @property
- def header_image(self):
- return self.hero_image
- @property
- def about_video_url(self):
- return self.video_url
- @property
- def show_about_video(self):
- return bool(self.video_url)
- @property
- def about_video_embed_url(self):
- return self.video_embed_url
- @property
- def extra_title(self):
- return self.image_block_title
- @property
- def extra_text(self):
- return self.image_block_text
- def __str__(self):
- return self.title
- class Meta:
- verbose_name = 'Настройки главной страницы лендинга'
- verbose_name_plural = 'Настройки главной страницы лендинга'
- class LandingTeamMember(models.Model):
- user = models.ForeignKey(
- settings.AUTH_USER_MODEL,
- on_delete=models.CASCADE,
- related_name='landing_team_members',
- verbose_name='Пользователь',
- )
- caption = models.CharField(
- 'Подпись',
- max_length=255,
- blank=True,
- )
- sort_order = models.PositiveIntegerField(
- 'Порядок',
- default=100,
- )
- is_active = models.BooleanField(
- 'Показывать на лендинге',
- default=True,
- )
- @property
- def display_name(self):
- full_name = ' '.join(
- value
- for value in [
- getattr(self.user, 'last_name', ''),
- getattr(self.user, 'first_name', ''),
- ]
- if str(value or '').strip()
- ).strip()
- return full_name or str(self.user)
- @property
- def avatar_src(self):
- avatar_base64 = str(getattr(self.user, 'avatar_base64', '') or '').strip()
- if not avatar_base64:
- return ''
- if avatar_base64.startswith('data:image'):
- return avatar_base64
- return f'data:image/jpeg;base64,{avatar_base64}'
-
- @property
- def full_name(self):
- return self.display_name
- @property
- def position(self):
- return self.caption
- def __str__(self):
- return self.display_name
- class Meta:
- verbose_name = 'Участник команды лендинга'
- verbose_name_plural = 'Участники команды лендинга'
- ordering = ('sort_order', 'id')
|