remove old banners and dependings

remotes/origin/1203
Nazar Kotjuk 10 years ago
parent 00d4420bc8
commit bed7a1ca71
  1. 49
      article/managers.py
  2. 131
      article/models.py
  3. 2
      article/urls.py
  4. 0
      banners/__init__.py
  5. 15
      banners/models.py
  6. 16
      banners/tests.py
  7. 7
      banners/urls.py
  8. 10
      banners/views.py
  9. 17
      exposition/admin.py
  10. 3
      exposition/admin_urls.py
  11. 8
      exposition/forms.py
  12. 8
      exposition/models.py
  13. 1
      proj/settings.py
  14. 1
      proj/urls.py
  15. 59
      templates/admin/exposition/paid.html
  16. 14
      templates/client/base_page.html
  17. 8
      templates/client/popups/auto_banner.html
  18. 23
      templates/client/popups/auto_modal.html
  19. 8
      templates/client/popups/cemat_banner1.html
  20. 8
      templates/client/popups/cemat_banner2.html
  21. 24
      templates/client/popups/cemat_modal.html

@ -0,0 +1,49 @@
from django.utils import translation
from django.core.cache import cache
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
class ArticleManager(TranslationManager):
cache_time = 60
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
def news(self):
"""
return queryset of news
"""
model = self.model
return self.language().filter(type=model.news)
def blogs(self):
"""
return queryset of blogs
"""
model = self.model
return self.language().filter(type=model.blog)
def main_page_news(self):
lang = translation.get_language()
key = 'main_page_news_%s'%lang
cached_news = cache.get(key)
if cached_news:
return cached_news
else:
news = list(self.news().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date', '-modified')[:3])
cache.set(key, news, self.cache_time)
return news
def main_page_blogs(self):
lang = translation.get_language()
key = 'main_page_blogs_%s'%lang
cached_blogs = cache.get(key)
if cached_blogs:
return cached_blogs
else:
blogs = list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3])
cache.set(key, blogs, self.cache_time)
return blogs

@ -1,63 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import copy
from django.db import models from django.db import models
from django.contrib.contenttypes import generic from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import translation
from django.utils.timezone import now from django.utils.timezone import now
from django.db.models.signals import post_save
from functions.signal_handlers import post_save_handler
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
from django.utils.html import strip_tags
from sorl.thumbnail import ImageField from sorl.thumbnail import ImageField
from functions.url_utils import slugify, unique_slug from functions.url_utils import slugify, unique_slug
from functions.model_utils import base_concrete_model from functions.model_utils import base_concrete_model
from functions.form_check import translit_with_separator from functions.form_check import translit_with_separator
from django.core.cache import cache from article.managers import ArticleManager
class ArticleManager(TranslationManager):
cache_time = 60
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
def news(self):
"""
return queryset of news
"""
model = self.model
return self.language().filter(type=model.news)
def blogs(self):
"""
return queryset of blogs
"""
model = self.model
return self.language().filter(type=model.blog)
def main_page_news(self):
lang = translation.get_language()
key = 'main_page_news_%s'%lang
cached_news = cache.get(key)
if cached_news:
return cached_news
else:
news = list(self.news().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date', '-modified')[:3])
cache.set(key, news, self.cache_time)
return news
def main_page_blogs(self):
lang = translation.get_language()
key = 'main_page_blogs_%s'%lang
cached_blogs = cache.get(key)
if cached_blogs:
return cached_blogs
else:
blogs = list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3])
cache.set(key, blogs, self.cache_time)
return blogs
class Article(TranslatableModel): class Article(TranslatableModel):
@ -67,36 +20,36 @@ class Article(TranslatableModel):
Uses hvad.TranslatableModel which is child of django.db.models class Uses hvad.TranslatableModel which is child of django.db.models class
""" """
MAX_ON_MAIN_PAGE = 3 MAX_ON_MAIN_PAGE = 3
# types of article # types of article
blog = 1 blog = 1
news = 2 news = 2
#set manager of this model
objects = ArticleManager() objects = ArticleManager()
slug = models.SlugField(unique=True, max_length=255) slug = models.SlugField(verbose_name=_(u'Url'), unique=True, max_length=255)
old_id = models.IntegerField(blank=True, null=True) # fields provides importing and reindexing new articles from previous site
logo = ImageField(upload_to='articles_preview', blank=True) old_id = models.IntegerField(verbose_name=_(u'Id из старой базы'), blank=True, null=True)
theme = models.ManyToManyField('theme.Theme') logo = ImageField(verbose_name=_(u'Логотип'), upload_to='articles_preview', blank=True)
blog_theme = models.ManyToManyField('theme.ThemeBlog') theme = models.ManyToManyField('theme.Theme', verbose_name=_(u'Тематики'))
tag = models.ManyToManyField('theme.Tag', blank=True, null=True) blog_theme = models.ManyToManyField('theme.ThemeBlog', verbose_name=_(u'Тематики для блогов'), )
author = models.ForeignKey('accounts.User', verbose_name='Автор', tag = models.ManyToManyField('theme.Tag', blank=True, null=True, verbose_name=_(u'Теги'), )
author = models.ForeignKey('accounts.User', verbose_name=_(u'Автор'),
on_delete=models.PROTECT, related_name='articles') on_delete=models.PROTECT, related_name='articles')
exposition = models.ForeignKey('exposition.Exposition', blank=True, null=True) exposition = models.ForeignKey('exposition.Exposition', blank=True, null=True, verbose_name=_(u'Выставка'))
conference = models.ForeignKey('conference.Conference', blank=True, null=True) conference = models.ForeignKey('conference.Conference', blank=True, null=True, verbose_name=_(u'Конференция'))
type = models.PositiveSmallIntegerField(default=1) # type can be blog or news
allow_comments = models.BooleanField(default=True) type = models.PositiveSmallIntegerField(verbose_name=_(u'Тип'), default=1, db_index=True)
# do not use anywhere now
allow_comments = models.BooleanField(verbose_name=_(u'Позволить коментарии'), default=True)
# fields that provides features of a visible page on the website # fields that provides features of a visible page on the website
publish_date = models.DateTimeField(blank=True, null=True) publish_date = models.DateTimeField(verbose_name=_(u'Дата публикации'), blank=True, null=True, db_index=True)
expiry_date = models.DateTimeField(_("Expires on"), expiry_date = models.DateTimeField(_("Expires on"),
help_text=_("With Published chosen, won't be shown after this time"), help_text=_("With Published chosen, won't be shown after this time"),
blank=True, null=True) blank=True, null=True)
in_sitemap = models.BooleanField(_("Show in sitemap"), default=False) in_sitemap = models.BooleanField(_("Show in sitemap"), default=False)
# fields that provides features of a visible on main page # fields that provides features of a visible on main page
main_page = models.BooleanField(default=False) main_page = models.BooleanField(verbose_name=_(u'Показывать на главной'), default=False, db_index=True)
main_page_time = models.DateTimeField(blank=True, null=True) main_page_time = models.DateTimeField(blank=True, null=True)
# field that check if need generate description # field that check if need generate description
@ -104,23 +57,22 @@ class Article(TranslatableModel):
help_text=_("If checked, the description will be automatically " help_text=_("If checked, the description will be automatically "
"generated from content. Uncheck if you want to manually " "generated from content. Uncheck if you want to manually "
"set a custom description."), default=False) "set a custom description."), default=False)
# published = models.
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)
#translated fields #translated fields
translations = TranslatedFields( translations = TranslatedFields(
main_title = models.CharField(max_length=255), main_title=models.CharField(verbose_name=_(u'Заголовок'), max_length=255),
preview = models.TextField(), preview=models.TextField(verbose_name=_(u'Превью'), ),
description = models.TextField(blank=False), description=models.TextField(verbose_name=_(u'Основной текст'), blank=False),
#-----meta #-----meta
title = models.CharField(max_length=255, blank=True), title=models.CharField(max_length=255, blank=True),
descriptions = models.CharField(max_length=255, blank=True), descriptions=models.CharField(max_length=255, blank=True),
keywords = models.CharField(max_length=255, blank=True), keywords=models.CharField(max_length=255, blank=True),
) )
files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id')
class Meta: class Meta:
ordering = ['-publish_date'] ordering = ['-publish_date']
@ -130,8 +82,10 @@ class Article(TranslatableModel):
def translation_model(self): def translation_model(self):
return self._meta.translations_model return self._meta.translations_model
def publish(self): def publish(self):
"""
set publish date. uses when publish date is none
"""
self.in_sitemap = True self.in_sitemap = True
if not self.publish_date: if not self.publish_date:
# save time only first time # save time only first time
@ -141,6 +95,10 @@ class Article(TranslatableModel):
return self return self
def get_event(self): def get_event(self):
"""
get event connected to article
exposition has priority
"""
if self.exposition: if self.exposition:
return self.exposition return self.exposition
elif self.conference: elif self.conference:
@ -182,8 +140,10 @@ class Article(TranslatableModel):
return slugify(self.get_available_title()) return slugify(self.get_available_title())
def get_available_title(self): def get_available_title(self):
#print self.lazy_translation_getter('main_title', self.pk) """
return u'%s'%self.lazy_translation_getter('main_title', self.pk) get title from current language
"""
return u'%s' % self.lazy_translation_getter('main_title', self.pk)
def _get_next_or_previous_by_publish_date(self, is_next, **kwargs): def _get_next_or_previous_by_publish_date(self, is_next, **kwargs):
""" """
@ -216,21 +176,19 @@ class Article(TranslatableModel):
""" """
return self._get_next_or_previous_by_publish_date(False, **kwargs) return self._get_next_or_previous_by_publish_date(False, **kwargs)
def admin_url(self): def admin_url(self):
if self.type == 1: if self.type == 1:
return '/admin/article/blog/%s'%self.slug return '/admin/article/blog/%s' % self.slug
elif self.type == 2: elif self.type == 2:
return '/admin/article/news/%s'%self.slug return '/admin/article/news/%s' % self.slug
def get_permanent_url(self): def get_permanent_url(self):
if self.type == 1: if self.type == 1:
return '/blogs/%s/'%self.slug return '/blogs/%s/' % self.slug
elif self.type == 2: elif self.type == 2:
return '/news/%s/'%self.slug return '/news/%s/' % self.slug
def get_blog_preview(self): def get_blog_preview(self):
preview = self.files.filter(purpose='preview') preview = self.files.filter(purpose='preview')
if preview: if preview:
return preview[0] return preview[0]
@ -238,7 +196,6 @@ class Article(TranslatableModel):
return None return None
def get_blog_preview2(self): def get_blog_preview2(self):
preview = self.files.filter(purpose='preview2') preview = self.files.filter(purpose='preview2')
if preview: if preview:
return preview[0] return preview[0]
@ -252,12 +209,8 @@ class Article(TranslatableModel):
return '/news/' return '/news/'
def similar(self): def similar(self):
themes = [item ['id'] for item in self.theme.all().values('id')] themes = [item['id'] for item in self.theme.all().values('id')]
return list(Article.objects.language().exclude(id=self.id).filter(type=self.type, publish_date__isnull=False, theme__in=themes).distinct().order_by('-publish_date')[:3]) return list(Article.objects.language().exclude(id=self.id).filter(type=self.type, publish_date__isnull=False, theme__in=themes).distinct().order_by('-publish_date')[:3])
from django.db.models.signals import post_save
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Article) post_save.connect(post_save_handler, sender=Article)

@ -3,7 +3,7 @@ from django.conf.urls import patterns, url
from views import BlogList, NewsList, BlogDetail, NewsDetail, NewsTagCatalog, BlogsFilterCatalog from views import BlogList, NewsList, BlogDetail, NewsDetail, NewsTagCatalog, BlogsFilterCatalog
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^blogs/tag/(?P<slug>.*)/page/(?P<page>\d+)/$', BlogsFilterCatalog.as_view(), {'meta_id':75, 'filter':'tag'}), url(r'^blogs/tag/(?P<slug>.*)/page/(?P<page>\d+)/$', BlogsFilterCatalog.as_view(), {'meta_id': 75, 'filter':'tag'}),
url(r'^blogs/theme/(?P<slug>.*)/page/(?P<page>\d+)/$', BlogsFilterCatalog.as_view(), {'filter':'theme'}), url(r'^blogs/theme/(?P<slug>.*)/page/(?P<page>\d+)/$', BlogsFilterCatalog.as_view(), {'filter':'theme'}),
url(r'^blogs/page/(?P<page>\d+)/$', BlogList.as_view(), {'meta_id':79}), url(r'^blogs/page/(?P<page>\d+)/$', BlogList.as_view(), {'meta_id':79}),
url(r'^blogs/tag/(?P<slug>.*)/$', BlogsFilterCatalog.as_view(), {'meta_id':75, 'filter':'tag'}), url(r'^blogs/tag/(?P<slug>.*)/$', BlogsFilterCatalog.as_view(), {'meta_id':75, 'filter':'tag'}),

@ -1,15 +0,0 @@
from django.db import models
# Create your models here.
class Redirect(models.Model):
redirect = models.URLField()
count = models.PositiveIntegerField(default=0)
views = models.PositiveIntegerField(default=0)
def __unicode__(self):
return self.redirect
def get_object_url(self):
return '/redirect/redirect/%d/'%self.id

@ -1,16 +0,0 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

@ -1,7 +0,0 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'redirect/(?P<id>.*)/$', 'banners.views.redirect'),
)

@ -1,10 +0,0 @@
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from banners.models import Redirect
from django.db.models import F
def redirect(request, id):
redirect = get_object_or_404(Redirect, id=id)
Redirect.objects.filter(id=id).update(count=F('count')+1)
return HttpResponseRedirect(redirect.redirect)

@ -387,23 +387,6 @@ def search_expo(request):
return HttpResponse(json.dumps(result), content_type='application/json') return HttpResponse(json.dumps(result), content_type='application/json')
from django.views.generic import FormView
from forms import PaidForm
class PaidView(FormView):
form_class = PaidForm
success_url = '/admin/exposition/all/'
template_name = 'admin/exposition/paid.html'
def form_valid(self, form):
expo = Exposition.objects.get(url=self.kwargs.get('url'))
paid = form.save(commit=False)
paid.expo = expo
paid.save()
return HttpResponseRedirect(self.success_url)
def expo_copy(request): def expo_copy(request):
response = {'redirect': ''} response = {'redirect': ''}
expo = Exposition.objects.get(id=request.GET['id']) expo = Exposition.objects.get(id=request.GET['id'])

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url from django.conf.urls import patterns, include, url
from admin import ExpositionListView, ExpositionView, PaidView from admin import ExpositionListView, ExpositionView
urlpatterns = patterns('exposition.admin', urlpatterns = patterns('exposition.admin',
url(r'^upload-photo/(?P<expo_id>.*)/$', 'upload_exposition_photo'), url(r'^upload-photo/(?P<expo_id>.*)/$', 'upload_exposition_photo'),
url(r'^copy/$', 'expo_copy'), url(r'^copy/$', 'expo_copy'),
url(r'^(?P<url>.*)/paid/$', PaidView.as_view()),
#url(r'^add.*/$', 'exposition_add'), #url(r'^add.*/$', 'exposition_add'),
url(r'^delete/(?P<url>.*)/$', 'exposition_delete'), url(r'^delete/(?P<url>.*)/$', 'exposition_delete'),

@ -616,11 +616,3 @@ class ExpositionFilterForm(AdminFilterForm):
qs = qs.filter(data_begin__month=month) qs = qs.filter(data_begin__month=month)
return qs return qs
from exposition.models import Paid
class PaidForm(forms.ModelForm):
class Meta:
model = Paid
exclude = ('expo',)

@ -386,14 +386,6 @@ def logo_name(instance, filename):
url = instance.expo.url url = instance.expo.url
return '/'.join(['exposition', url, url+'_org_logo.jpg']) return '/'.join(['exposition', url, url+'_org_logo.jpg'])
class Paid(models.Model):
expo = models.OneToOneField(Exposition)
org_logo = models.ImageField(upload_to=logo_name, blank=True, max_length=255)
oficial_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_oficial')
participation_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_participation')
tickets_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_tickets')
organiser = models.EmailField(blank=True)
pre_save.connect(pre_save_handler, sender=Exposition) pre_save.connect(pre_save_handler, sender=Exposition)
post_save.connect(post_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=Exposition)

@ -338,7 +338,6 @@ INSTALLED_APPS = (
'translator', 'translator',
'webinar', 'webinar',
'meta', 'meta',
'banners',
#django modules #django modules
'sorl.thumbnail', # for logos 'sorl.thumbnail', # for logos
'photologue', # photogallery 'photologue', # photogallery

@ -72,7 +72,6 @@ urlpatterns = patterns('',
url(r'^accounts/', include('registration.backends.default.urls')), url(r'^accounts/', include('registration.backends.default.urls')),
url(r'^', include('password_reset.urls')), url(r'^', include('password_reset.urls')),
url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^redirect/', include('banners.urls')),
url(r'^', include('settings.old_urls')), url(r'^', include('settings.old_urls')),
url(r'^', include('service.urls')), url(r'^', include('service.urls')),
) )

@ -1,59 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load thumbnail %}
{% block scripts %}
<link href="{% static 'js/select/select2.css' %}" rel="stylesheet"/>
<script src="{% static 'js/select/select2.js' %}"></script>
{% endblock %}
{% block body %}
<form method="post" class="form-horizontal" enctype="multipart/form-data" name="form1" id="form1"> {% csrf_token %}
<fieldset>
<legend><i class="icon-edit"></i>{% if object %} Изменить {% else %} Добавить {% endif %}выставку{% if object %}(<a target="_blank" href="{{ object.get_permanent_url }}">на сайте</a>){% endif %}</legend>
<div class="box span8" >
<div class="box-header well">
<h2><i class="icon-pencil"></i> Основная информация</h2>
</div>
<div class="box-content">
<div class="control-group {% if form.org_logo.errors %}error{% endif %}">
<label class="control-label">{{ form.org_logo.label }}:</label>
<div class="controls">{{ form.org_logo }}
<span class="help-inline">{{ form.org_logo.errors }}</span>
</div>
</div>
<div class="control-group {% if form.oficial_link.errors %}error{% endif %}">
<label class="control-label">{{ form.oficial_link.label }}:</label>
<div class="controls">{{ form.oficial_link }}
<span class="help-inline">{{ form.oficial_link.errors }}</span>
</div>
</div>
<div class="control-group {% if form.participation_link.errors %}error{% endif %}">
<label class="control-label">{{ form.participation_link.label }}:</label>
<div class="controls">{{ form.participation_link }}
<span class="help-inline">{{ form.participation_link.errors }}</span>
</div>
</div>
<div class="control-group {% if form.tickets_link.errors %}error{% endif %}">
<label class="control-label">{{ form.tickets_link.label }}:</label>
<div class="controls">{{ form.tickets_link }}
<span class="help-inline">{{ form.tickets_link.errors }}</span>
</div>
</div>
</div>
</div>
<div class="controls">
<input class="btn btn-large btn-primary" type="submit" value="Добавить">
<input class="btn btn-large" type="reset" value="Отмена">
</div>
</fieldset>
</form>
{% endblock %}

@ -37,19 +37,7 @@
{% block asside_banner2 %} {% block asside_banner2 %}
<!-- task EXPO-145--> {% endblock %}
{% comment %}
<div class="sbnr">
<div class="sbnr-wrap">
<a href="/redirect/redirect/11/">
<img src="{% static 'client/img/partners/imgo.jpg' %}" alt="" />
</a>
</div>
</div>
{% endcomment %}
{% endblock %}
{% include 'client/includes/side_confs.html' %} {% include 'client/includes/side_confs.html' %}
<hr /> <hr />
<div class="s-news-list"> <div class="s-news-list">

@ -1,8 +0,0 @@
<div id="expo-ad-popup" data-rdr="51" class="popup-window" style="width:800px;">
<header class="clearfix">
<div class="pw-title"></div>
</header>
<div class="pw-body clearfix">
<a href="/redirect/redirect/51/"><img src="/static/client/img/expo_b/mims15.gif"/></a>
</div>
</div>

@ -1,23 +0,0 @@
<div id="expo-ad-popup" data-rdr="52" class="popup-window" style="width:500px;">
<header class="clearfix">
<div class="pw-title">Вы планируете посещение MIMS Automechanika Moscow в Экспоцентре?</div>
</header>
<div class="pw-body clearfix">
<form id="expo-form-popup" class="pw-form simple-validate" action="/redirect/redirect/52/">
<div class="pwf-line">
С 24 по 27 августа 2015 г. в Экспоцентре будут представлены лучшие предложения производителей и поставщиков автозапчастей, оборудования и товаров для технического обслуживания автомобилей.
</div>
<div class="pwf-line">
<a href="/redirect/redirect/52/">
<img src="/static/client/img/expo_b/mims.png">
</a>
</div>
<button>Узнать подробнее</button>
</form>
</div>
</div>

@ -1,8 +0,0 @@
<div id="expo-ad-popup" data-rdr="49" class="popup-window" style="width:800px;">
<header class="clearfix">
<div class="pw-title"></div>
</header>
<div class="pw-body clearfix">
<a href="/redirect/redirect/49/"><img src="/static/client/img/expo_b/cemat15.gif"/></a>
</div>
</div>

@ -1,8 +0,0 @@
<div id="expo-ad-popup" data-rdr="50" class="popup-window" style="width:800px;">
<header class="clearfix">
<div class="pw-title"></div>
</header>
<div class="pw-body clearfix">
<a href="/redirect/redirect/50/"><img src="/static/client/img/expo_b/cemat15_v2.gif"/></a>
</div>
</div>

@ -1,24 +0,0 @@
<div id="expo-ad-popup" data-rdr="53" class="popup-window">
<header class="clearfix">
<div class="pw-title">Ваш логист пойдет на выставку CEMAT?</div>
</header>
<div class="pw-body clearfix">
<form id="expo-form-popup" class="pw-form simple-validate" action="/redirect/redirect/53/">
<div class="pwf-line">
С 22 по 25 сентября 2015 г. в Крокус Экспо производители складского оборудования и техники представят свои выгодные предложения.
</div>
<div class="pwf-line">
<a href="/redirect/redirect/53/">
<img src="/static/client/img/expo_b/cemat_modal1.png">
</a>
<a href="/redirect/redirect/53. /" style="margin-left: 10px;">
<img src="/static/client/img/expo_b/cemat_modal2.png">
</a>
</div>
<button>Узнать подробнее</button>
</form>
</div>
</div>
Loading…
Cancel
Save