refactor
This commit is contained in:
@@ -383,7 +383,14 @@ class Postgres(DatabaseBase):
|
||||
query = domain.Placement.filter(project__workspace_id=workspace_id, project_id=project_id)
|
||||
|
||||
if not include_archived:
|
||||
query = query.filter(status__in=[domain.PlacementStatus.APPROVED, domain.PlacementStatus.IN_PROGRESS])
|
||||
query = query.filter(
|
||||
status__in=[
|
||||
domain.PlacementStatus.PLANNED,
|
||||
domain.PlacementStatus.APPROVED,
|
||||
domain.PlacementStatus.IN_PROGRESS,
|
||||
domain.PlacementStatus.COMPLETED,
|
||||
]
|
||||
)
|
||||
|
||||
return (
|
||||
await query.prefetch_related('project', 'project__channel', 'channel', 'creative')
|
||||
|
||||
@@ -40,22 +40,25 @@ class Creative(TimestampedModel):
|
||||
MAX_CREATIVE_MEDIA_BYTES = 20 * 1024 * 1024
|
||||
|
||||
|
||||
_INVITE_LINK_HTML = re.compile(r'<a\s+href=["\']https?://t\.me/\+[a-zA-Z0-9_-]+["\']>([^<]*)</a>', re.IGNORECASE)
|
||||
_INVITE_LINK_PLAIN = re.compile(r'https?://t\.me/\+[a-zA-Z0-9_-]+', re.IGNORECASE)
|
||||
_INVITE_LINK_HTML = re.compile(r'<a\s+href=["\']https?://t\.me/(?:\+|joinchat/)[a-zA-Z0-9_-]+["\']>([^<]*)</a>', re.IGNORECASE)
|
||||
_INVITE_LINK_PLAIN = re.compile(r'https?://t\.me/(?:\+|joinchat/)[a-zA-Z0-9_-]+', re.IGNORECASE)
|
||||
_INVITE_LINK_REPLACED = re.compile(r'<a\s+class=["\']tg-link["\']>([^<]*)</a>', re.IGNORECASE)
|
||||
_INVITE_LINK_REPLACED_URL = re.compile(
|
||||
r'<a\s+class=["\']tg-link["\']>\s*https?://t\.me/(?:\+|joinchat/)[a-zA-Z0-9_-]+\s*</a>',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def replace_invite_link_with_tag(text: str) -> str:
|
||||
"""Replace Telegram invite link (t.me/+xxx) with tracking tag."""
|
||||
|
||||
# Проверяем, есть ли уже замененная ссылка
|
||||
replaced_count = len(_INVITE_LINK_REPLACED.findall(text))
|
||||
|
||||
html_count = len(_INVITE_LINK_HTML.findall(text))
|
||||
|
||||
# Сначала удаляем HTML-ссылки из текста, чтобы не считать их дважды
|
||||
text_without_html_links = _INVITE_LINK_HTML.sub('', text)
|
||||
plain_count = len(_INVITE_LINK_PLAIN.findall(text_without_html_links))
|
||||
# Сначала удаляем HTML-ссылки и tg-link теги, чтобы не считать их дважды
|
||||
text_without_links = _INVITE_LINK_HTML.sub('', text)
|
||||
text_without_links = _INVITE_LINK_REPLACED.sub('', text_without_links)
|
||||
plain_count = len(_INVITE_LINK_PLAIN.findall(text_without_links))
|
||||
|
||||
total = replaced_count + html_count + plain_count
|
||||
|
||||
@@ -64,12 +67,19 @@ def replace_invite_link_with_tag(text: str) -> str:
|
||||
if total > 1:
|
||||
raise CreativeMultipleInviteLinks()
|
||||
|
||||
# Если ссылка уже заменена, возвращаем текст как есть
|
||||
# Если ссылка уже заменена, нормализуем текст если внутри был URL
|
||||
if replaced_count == 1:
|
||||
return text
|
||||
return _INVITE_LINK_REPLACED_URL.sub('<a class="tg-link"></a>', text)
|
||||
|
||||
if html_count == 1:
|
||||
return _INVITE_LINK_HTML.sub(r'<a class="tg-link">\1</a>', text)
|
||||
def _replace_html(match: re.Match) -> str:
|
||||
inner = match.group(1).strip()
|
||||
if _INVITE_LINK_PLAIN.fullmatch(inner):
|
||||
return '<a class="tg-link"></a>'
|
||||
return f'<a class="tg-link">{inner}</a>'
|
||||
|
||||
return _INVITE_LINK_HTML.sub(_replace_html, text)
|
||||
|
||||
return _INVITE_LINK_PLAIN.sub('<a class="tg-link"></a>', text)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from src import dto
|
||||
from src import domain, dto
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .. import Usecase
|
||||
@@ -12,6 +12,44 @@ log = logging.getLogger(__name__)
|
||||
async def get_channels(self: 'Usecase', input: dto.GetChannelsInput) -> list[dto.ChannelOutput]:
|
||||
channels = await self.database.search_channels(username_query=input.username)
|
||||
|
||||
if not channels and input.username:
|
||||
try:
|
||||
parser_response = await self.parser.fetch_telegram_channel(input.username)
|
||||
except Exception as exc:
|
||||
log.warning('Parser fetch failed for username query %s: %s', input.username, exc)
|
||||
parser_response = None
|
||||
|
||||
if parser_response:
|
||||
channel = await self.database.get_channel(telegram_id=parser_response.telegram_id)
|
||||
if not channel:
|
||||
channel = await self.database.get_channel(username=parser_response.username)
|
||||
|
||||
if channel:
|
||||
updated = False
|
||||
if channel.username != parser_response.username:
|
||||
channel.username = parser_response.username
|
||||
updated = True
|
||||
if channel.title != parser_response.title:
|
||||
channel.title = parser_response.title
|
||||
updated = True
|
||||
if channel.telegram_id != parser_response.telegram_id:
|
||||
channel.telegram_id = parser_response.telegram_id
|
||||
updated = True
|
||||
|
||||
if updated:
|
||||
await self.database.update_channel(channel)
|
||||
log.info('Updated channel @%s from parser response', channel.username)
|
||||
else:
|
||||
channel = domain.Channel(
|
||||
username=parser_response.username,
|
||||
telegram_id=parser_response.telegram_id,
|
||||
title=parser_response.title,
|
||||
)
|
||||
await self.database.create_channel(channel)
|
||||
log.info('Created channel @%s from parser response', channel.username)
|
||||
|
||||
channels = [channel]
|
||||
|
||||
log.debug('Found %s channels for username query: %s', len(channels), input.username)
|
||||
|
||||
return [
|
||||
|
||||
@@ -46,7 +46,12 @@ async def fetch_placement_post_cycle(self: 'Usecase', interval_seconds: int) ->
|
||||
|
||||
placement_post = domain.PlacementPost(
|
||||
placement_id=placement.id,
|
||||
project_id=placement.project_id,
|
||||
creative_id=placement.creative_id,
|
||||
post_id=post.id,
|
||||
wanted_placement_date=placement.placement_at or post.created_at,
|
||||
cost=placement.cost_value,
|
||||
comment=placement.comment,
|
||||
status=domain.PlacementPostStatus.ACTIVE,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user