Друпалургия

Drupal: Показать форму входа при попытке анонимного пользователя поставить флаг

Плагин для модуля Flag, который при попытке анонимного пользователя поставить флаг покажет в диалоге форму входа.

src/Plugin/ActionLink/AjaxOrLoginActionLink.php:

/** * @ActionLinkType( * id = "ajax_login_link", * label = @Translation("AJAX link (for loged users)"), * description = "An AJAX JavaScript request will be made without reloading the page." * ) */ class AjaxOrLoginActionLink extends AJAXactionLink {   /** * {@inheritDoc} */ public function getAsFlagLink(FlagInterface $flag, EntityInterface $entity) {

Читать дальше →

Похожие записи:

Категории: Друпалургия

Устойчивое развитие Drupal: вклад, признание заслуг и отдача

Drupal в рунете - чт, 20/02/2020 - 18:26
Перевод статьи «Drupal Sustainability: Contribution, Credit and Impact» (автор Tiffany Farriss)

Увеличение числа компаний, работающих с Drupal, — нужная и важная задача. Но это требует от нас улучшения того, как мы привлекаем людей к поддержке и развитию Drupal, а также то, как мы признаем их вклад в общее дело.

Несколько недель назад я получила свое первое признание вклада в Drupal за программную речь на DrupalCamp Colorado. Несмотря на то, что я необычайно взволнована произошедшим, все же нахожу это несколько забавным, так как этот доклад — не первый мой вклад в Drupal.

На странице моего профиля на Drupal.org можно увидеть, что я являюсь участником сообщества уже более двенадцати лет. К тому времени я уже выступала с программными докладами на трех других друпалкемпах, выступала на сессиях и участвовала в рабочих группах во время конференции DrupalCon Boston 2008, руководила разработкой технического задания по редизайну Drupal.org, была председателем DrupalCon Chicago 2011, на протяжении девяти лет являлась членом правления Drupal Association, а совсем недавно входила в состав Комиссии по выбору Исполнительного директора Ассоциации. Это лишь часть моего личного вклада и, кроме того, компания Palantir.net, совладельцем которой я являюсь, сделала значительный вклад временем, творческим потенциалом и другими ресурсами за все эти годы.

Признание заслуг не является для меня движущей силой. Как и многие участники проектов с открытым исходным кодом, я делаю свой вклад в Drupal, потому что готова оказывать поддержку, когда я вижу в этом необходимость или перспективу. Раньше, когда я была еще новичком в сообществе, о вкладе в развитие Drupal (и кодом и не кодом) могли знать только в узком кругу. Я постоянно ощущала, что заслужила доверие и поддержку тех, с кем тесно сотрудничала в решении все новых и новых задач.

В итоге Drupal стал крупнейшим независимым проектом с открытым исходным кодом, управляемым сообществом. И многие из нас верили, что нашего коллективного успеха и того влияния, которое мы оказывали, было достаточно для дальнейшего раскручивания спирали успеха открытого программного обеспечения. Но так ли это было?

Open source победил, и сегодня множество людей и компаний доверяют Drupal и другим инструментам и продуктам с открытым исходным кодом. Но эти компании могли сделать свой выбор в пользу инструмента с открытым исходным кодом не до конца осознавая возможности, которые открывает Open Source. Двенадцать лет назад сообщество Drupal было достаточно маленьким, чтобы устоявшиеся нормы и надежды передавались от человека к человеку, как легенды и предания. Прежние способы формирования поведения и обеспечения соблюдения норм через социальное взаимодействие (так называемое товарищеское воздействие) не являются достаточно действенными для новых участников сообщества.

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

В своей программной речи в Амстердаме в 2014 году Дрис отметил, что в мире Open Source уже давно есть механизм признание заслуг отдельных разработчиков (за вклад кодом), но для компаний и организаций пока не выработаны соответствующие методы признания (и поощрения) их заслуг и вклада, который они делают. Он предложил для этого простой способ признания заслуг организаций, которые участвовали в работе над проблемами ядра Drupal либо непосредственно кодом, либо финансируя разработку, о чем было сообщено в докладе Drupal Association в конце 2015 года. С течением времени эта система была расширена, чтобы охватить больше, чем только участие вкладом в код.

Однако, система признания заслуг еще не полностью заменила личную репутацию. Как показывает мой собственный опыт, большая часть работы, которая жизненно важна для Drupal, до сих пор не получила должного внимания в системе признания заслуг. Вследствие моего особого положения (отсутствие необходимости искать работу, налаженные связи в сообществе и т. д.), недостаточная известность в сообществе о моем личном вкладе не была проблемой.

Однако, будучи исполнительным директором компании Palantir, я поняла, что невозможность в полной мере отразить вклад, который делают компании (и который от них ожидают), гораздо более проблематична с точки зрения долгосрочных перспектив развития проекта. Некоторые из основополагающих направлений работы сообщества (Совет директоров Ассоциации Drupal, Общественная рабочая группа (CWG), Команда безопасности и другие виды деятельности команды ядра Drupal, не связанные с написанием кода, включая управление релизами, обеспечение взаимодействия, организацию спринтов, а также общую координацию проектов и инициатив) серьезно недооценены или полностью проигнорированы системой признания заслуг. Деятельность Джорджа ДеМета как председателя CWG в среднем занимает от четверти до половины его рабочего времени (и больше в наиболее загруженные периоды), а за последний год он получил только четыре упоминания в системе признания заслуг (остальные члены CWG получили даже меньше!). Сообщество и проект испытывают серьезные трудности из-за подобной неизвестности, которая затушевывает, а со временем и вовсе обесценивает ожидания и надежды сообщества. Это происходит из-за того, что мерилом вклада становится лишь активность, легко поддающаяся измерению, а не то, что имеет действительное значение.

После выхода Drupal 7, компании, принимавшие участие в его разработке, получили конкурентное преимущество, поскольку те, кто хотел использовать Drupal, знали, какие компании внесли существенный вклад в его создание, и почему это имеет значение. Однако, за последние пять лет, экосистема Drupal расширилась и теперь включает в себя много новых, более крупных компаний, которые приобрели свою репутацию в мире Drupal благодаря партнерским и спонсорским программам.

Эти программы и привлеченные с их помощью новые интеграторы и агентства существенно влияют на развитие и распространение Drupal. Для экосистемы Drupal они представляют собой долгожданное пополнение. Тем не менее, существуют серьезные проблемы с тем, как эти программы были организованы до настоящего времени, и в непредвиденном воздействии на нашу культуру внесения вклада:

  • Получения статуса в рамках этих программ изначально является платным и нефинансовый вклад в проект не требуются.
  • Эти программы ни прямо, ни косвенно не поддерживают и не побуждают вкладывать время или творческий капитал, от которых зависит Drupal.
  • Финансовые поступления от таких программ приносят пользу инфраструктурным инициативам (Drupal.org и, в более широком плане, Ассоциации), а также способствуют повышению узнаваемости на рынке, которые отнюдь не являются наиболее востребованными для Drupal или сообщества.
  • Эти программы подорвали репутационную систему, в которой предпочтение отдавалось достижениям (успешные внедрения и вклад в Drupal), и заменили ее такой, где предпочтение отдается показателям (финансовый успех и список клиентов).

Предоставление компаниям возможности позиционировать себя в качестве ведущих экспертов в Drupal без подтверждения того, что они вносят свой вклад, соизмеримый с выгодами, полученными от Drupal, негативно сказалось на устойчивости проекта. В результате это косвенно способствовало исчезновению дифференциации между провайдерами Drupal-услуг, девальвировало конкурентное преимущество, полученное от прямого вклада, и одновременно стимулировало увеличение косвенного вклада через спонсорство, оплату рекламы на Drupal.org и мероприятиях, включая конференции DrupalCon.

Как я отметила во время дискуссии на конференции OSCON, я вижу во всем этом угрозу на пути достижения прогресса. Наличие большего количества компаний, в том числе крупных интеграторов и агентств, работающих с Drupal — это хорошо и полезно для сообщества. Что нам необходимо совершенствовать, так это методы привлечения людей к развитию и улучшению Drupal и, что особенно важно, найти способы подчеркнуть их деятельное участие в проекте, чтобы восстановить культуру внесения вклада в Drupal. Для достижения этой цели необходимо создать новые и доступные способы внесения вклада, соответствующие как значимым целям Drupal и сообщества, так и ресурсам, которыми располагают компании, будь то время, творческий капитал или иной вклад, который они могут внести в проект. Сосредоточение внимания на том, что имеет существенное значение, укрепит Drupal на пути долгосрочного устойчивого развития.

Расскажите, как вы участвуете в развитии Drupal и сообщества? Какую поддержку вам оказывает компания, в которой вы работаете?

  • Есть вопрос
  • Статьи и публикации
  • Категории: Друпалургия

    Может быть, это уже не управление контентом. Может быть, это управление контекстом.

    Drupal в рунете - сб, 15/02/2020 - 22:09

    Перевод статьи «Maybe It’s Not Content Management Anymore. Maybe It’s Context Management.» (автор Ernie Smith)

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

    Устарела ли сама концепция систем управления контентом?

    Так можно подумать, основываясь на недавнем решении компании Gartner, известной прогнозами технологических тенденций, которая ежегодно публикует исследования рынка CMS в отчете Magic Quadrant for Web Content Management (магический квадрант управления веб-контентом). Точнее... публиковала до недавнего времени... Спустя два десятка лет Gartner решила отказаться от этого отчета в 2020 году.

    Эти 20 с лишним лет охватывали множество тенденций — взрывной рост блогов, растущее влияние открытого программного обеспечения на индустрию онлайн-паблишинга (в частности, WordPress и Drupal), появление Web 2.0 и отзывчивого дизайна, а также более современные подходы к управлению контентом, такие как JAMstack и headless CMS. Однако в 2020 году компания Gartner решила, что нужен новый термин для обозначения пространства цифрового контента, который бы лучше соответствовал текущему состоянию рынка. Как отмечает CMSWire, Gartner теперь применила более широкий подход с помощью своего нового отчета Magic Quadrant for Digital Experience Platforms (магический квадрант платформ цифрового взаимодействия).

    Другими словами, контент, представленный в интернете, больше не является конечной точкой цифрового взаимодействия.

    «Теперь это не только веб, и, безусловно, мы должны управлять новыми каналами распространения информации: Alexa, чат-боты и различные устройства», — сказала ведущий аналитик Gartner Ирина Гусева изданию CMSWire. «Контент не умирает. Он просто превращается в исходную сущность систем управления контентом, которые были предназначены для разных типов контента, а теперь и для разных каналов.»

    Содержание и контекст повсюду

    В значительной степени пересмотр отчета Magic Quadrant связан с ростом влияния таких игроков, как компания Acquia, основного разработчика Drupal, и Adobe, которая недавно приобрела Magento и Marketo, чтобы увеличить свое присутствие в цифровом маркетинге.

    Новый отчет в основном обходит стороной вопросы о роли открытого исходного кода в современном управлении контентом. Так, например, компания Automattic, которая управляет разработкой невероятно популярного WordPress, отсутствует в новом исследовании, хотя в отчете Magic Quadrant for Web Content Management, вышедшем прошлой осенью, она была упомянута. Ребрендинг отчета дает понять, что, по мнению Gartner, все более важной становится поддержка крупной компании.

    Я, по правде говоря, скептически отношусь к этому. Вы можете получить довольно хорошую поддержку от организаций, которые управляют платформами CMS с открытым исходным кодом. Но я думаю, что в Gartner правы: если мы ограничимся управлением контентом только в интернете, то это существенно сузит наши возможности. Мы живем в мире, где дистрибуция контента стала важна как никогда. Искусственный интеллект и голосовые помощники — инструменты, которые не были существенными десять лет назад, теперь стали повсеместно распространенными. И в какой-то момент ваша организация должна начать учитывать их в стратегическом плане и, если не сегодня, то в ближайшем будущем.

    Во многих компаниях контентная часть управления контентом слабо развита. Но очень важно, чтобы контент был везде, или хотя бы во множестве мест. Контент должен появляться в приложениях, на смарт-часах, в имейл-рассылках, в социальных сетях и, возможно, даже на устройствах интернета вещей. Нам нужно создавать инструменты для новых условий и новых контекстов. Цифровой мир меняется вместе с нашим контентом, и мы должны управлять этим.

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

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

    Сегодня контекст стал важнее, чем когда-либо.

  • Предлагаю решение
  • Статьи и публикации
  • Категории: Друпалургия

    Drupal: Создать свою ajax команду (8)

    Пример создания ajax команды для вывода сообщений в консоль браузера.

    src/Ajax/ConsoleLogCommand.php:

    namespace Drupal\modulename\Ajax;   use Drupal\Core\Ajax\CommandInterface;   class ConsoleLogCommand implements CommandInterface {   protected $message;   /** * Command constructor. */ public function __construct($message) { $this->message = $message; }   /** * {@inheritDoc} */ public function render() { return [ 'command' => 'consoleLog', 'message' => $this->message, ]; }   }

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Создать свой ajax индикатор прогресса

    Пример создания индикатора прогресса с именем toggleClass, который добавляет/удаляет класс у элемента:

    (function ($, Drupal) {   /** * Create custom progress type "toggleClass". * @see Drupal.Ajax.prototype.beforeSend() */ Drupal.Ajax.prototype.setProgressIndicatorToggleclass = function () { var $progressTarget = this.progress.target ? $(this.progress.target) : $(this.element); var progressClass = this.progress.class ? this.progress.class : 'ajax-progress-animation';   // Add class $progressTarget.addClass(progressClass);

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Красивые release notes на drupal.org

    Drupal в рунете - вс, 02/02/2020 - 22:20

    Задался я сегодня вопросом, как на drupal.org делают "красивые" release notes. Например https://www.drupal.org/project/jsonapi/releases/8.x-2.1

    Красивость в том, что номер issue является ссылкой на issue, а имя пользователя ссылкой на пользователя. Плюс есть разделение по типу issue (bug, task, feature)

    Выяснилось, что есть инструмент помогающий в этом. Это drupalorg-cli

    Пример использования:

    1) Переходим в каталог, где находится .git вашего модуля
    2) Запускаем drupalorg rn 8.x-1.0, где 8.x-1.0 это номер ПРЕДЫДУЩЕЙ версии
    3) Получаем в ответ что-то вроде

    <p><em>Add a summary hereem>p>
    <h3>Contributors (1)h3>
    <p><a href="https://www.drupal.org/u/ivnish">ivnisha>p>
    <h3>Changelogh3>
    <p><strong>Issues:strong> 2 issues resolved.p>
    <p>Changes since <a href="https://www.drupal.org/project/visually_impaired_module/releases/8.x-1.0">8.x-1.0a>:p>
    <h4>Featureh4>
    <ul>
      <li><a href="https://www.drupal.org/node/3110474">#3110474 by ivnish:">https://www.drupal.org/u/ivnish">ivnish: Allow choose image or text in the block
    ul>
    <h4>Taskh4>
    <ul>
      <li><a href="https://www.drupal.org/node/3025823">#3025823 by ivnish:">https://www.drupal.org/u/ivnish">ivnish: Fix coding standards
    ul>

    4) Вставляем этот код в release notes вашего модуля на drupal.org при создании нового релиза.

    Выглядит это примерно вот так

  • Drupal 8
  • Drupal 7
  • Разработчикам Автор ivnish Разработка, поддержка и лечение сайтов после заражения
    Категории: Друпалургия

    Drupal: Отправить уведомление о новом заказе в Commerce 2

    Во втором комерце практически все хуки заменили на события, поэтому теперь вместо реализации hook_commerce_checkout_complete() надо подписаться на событие commerce_order.place.post_transition:

    src/EventSubscriber/ModulenameEventSubscriber.php:

    namespace Drupal\modulename\EventSubscriber;   use Drupal\commerce_order\Entity\OrderInterface; use Drupal\state_machine\Event\WorkflowTransitionEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface;   class ModulenameEventSubscriber implements EventSubscriberInterface {   /**

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Функции для работы с адресами в twig

    Функция file_url($uri)

    Возвращает относительный адрес к файлу по его uri. Умеет работать с путями без схемы.

    {{ file_url('public://images/example.jpg') }} {# /sites/default/files/images/example.jpg #} {{ file_url('/images/example.jpg') }} {# /images/example.jpg #} {{ file_url('images/example.jpg') }} {# /images/example.jpg #}

    Функция path($name, $parameters, $options)

    Возвращает относительный адрес по роуту.

    {{ path('entity.node.canonical', {'node':123}) }} {# /node/123 #}

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Добавить в основные настройки сайта свою опцию

    Пример добавления в основные настройки сайта поля для ввода телефона:

    1. MODULENAME.module:

    /** * Implements hook_form_FORM_ID_alter(): system_site_information_settings. */ function MODULENAME_form_system_site_information_settings_alter(array &$form, FormStateInterface $form_state) { $form['site_information']['site_phone'] = [ '#type' => 'textfield', '#title' => t('Phone'),

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    С девятнадцаткой! Дру!

    Drupal в рунете - ср, 15/01/2020 - 21:17

    С днем рождения, капелька! Ты все лучшеешь. Совершенствуешься.

    Не останавливайся!
    А мы - прикроем.

    Какоой же славныый паа-арень! Та-тара-та-там-там... Друпал.

    ЗЫ - Дрисовы поздравления тут: https://dri.es/happy-nineteenth-birthday-drupal

  • Есть вопрос
  • Статьи и публикации
  • Категории: Друпалургия

    Drupal: Как сделать чтобы все письма отправлялись в html формате (8)

    1. Скачиваем модуль Swift Mailer — composer require drupal/swiftmailer

    2. Включаем — vendor/bin/drush en swiftmailer

    3. На странице admin/config/swiftmailer/messages выбираем формат сообщений HTML и убираем галочку с опции Respect provided e-mail format:

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Программно наполнить меню ссылками на термины таксономии

    Пример программного наполнения меню main ссылками на категории из словаря category (повторение функционала модуля Taxonomy Menu).

    src/Plugin/Derivative/TermLinks.php:

    class TermLinks extends DeriverBase {   /** * {@inheritDoc} */ public function getDerivativeDefinitions($base_plugin_definition) { /** @var TermStorageInterface $term_storage */ $term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Добавить в меню динамическую ссылку

    Пример добавления в меню main ссылки с динамическим заголовком и адресом. В ней для залогинённых пользователей будем выводить имя пользователя с ссылкой на профиль, а для анонимов ссылку на страницу регистрации.

    src/Plugin/Menu/MyDynamicMenuLink.php:

    class MyDynamicMenuLink extends MenuLinkDefault {   /** * {@inheritDoc} */ public function getTitle() { $current_user = \Drupal::currentUser(); return $current_user->isAuthenticated() ? $current_user->getAccountName() : t('Registration'); }   /** * {@inheritDoc} */

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Программная реализация ЧПУ

    Задача — из адреса в формате /catalog/notebooks?price_from=xxx&price_to=yyy, в котором /catalog/notebooks это синоним термина, а ?price_from=xxx&price_to=yyy динамические параметры, сделать человекопонятный адрес в формате /catalog/notebooks/price-xxx-yyy.

    Теория есть у niklan'a, поэтому сразу к коду.

    Для решения надо создать сервис с двумя методами:
    processOutbound() — изменяет исходящие адреса в новый формат

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Модуль EAV Field — хранение большого числа характеристик сущности в одном поле

    Несколько лет назад я описывал способы реализации каталога с большим количеством атрибутов товара и одним из способов было использование модели EAV, когда все значения атрибутов хранятся в одной колонке таблицы (в простейшем случае). Есть несколько модулей разной свежести, пытающиеся реализовать это в друпале, но меня ни один не устроил, поэтому родился EAV Field.

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Как расширить функционал фильтр-плагина Views? (добавляем возможность фильтровать числовые поля по нескольким значениям)

    Пример добавления возможности фильтровать числовые поля по нескольким значениями (добавления оператора "in").

    1. В папке своего модуля src/Plugin/views/filter создаём класс и наследуем его от класса, который нужно расширить. В этом классе переопределяем нужные методы и по необходимости добавляем свои. Аннотацию плагина добавлять не нужно.

    class ExtendedNumericFilter extends NumericFilter {   /** * {@inheritDoc} */ public function operators() { $operators = parent::operators();   $operators['in'] = [ 'title' => $this->t('Is one of'),

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: AJAX добавление товара в корзину в Commerce 2

    /** * Implements hook_form_BASE_FORM_ID_alter(): commerce_order_item_add_to_cart_form(). */ function MODULENAME_form_commerce_order_item_add_to_cart_form_alter(array &$form, FormStateInterface $form_state) { $product = $form_state->get('product'); /** @var ProductInterface $product */   $form['actions']['submit']['#id'] = 'add-to-cart-button-' . $product->id(); $form['actions']['submit']['#ajax'] = [ 'callback' => 'MODULENAME_add_to_cart_ajax', 'event' => 'click', 'selector' => ':input[data-drupal-selector="add-to-cart-button-' . $product->id() . '"]',

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Выполнить очередь с помощью Batch API

    Пример выполнения очереди products_import с помощью Batch API:

    class ProductsImportForm extends FormBase {   /** * {@inheritDoc} */ public function getFormId() { return 'products_import_form'; }   /** * {@inheritDoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form['submit'] = [ '#type' => 'submit', '#value' => $this->t('Start'), ];   return $form; }   /** * {@inheritDoc} */ public function submitForm(array &$form, FormStateInterface $form_state) {

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Drupal: Добавить сторонней сущности своё базовое поле

    Пример добавления терминам базового поля stored_depth:

    modulename.module

    /** * Implements hook_entity_base_field_info(). */ function modulename_entity_base_field_info(EntityTypeInterface $entity_type) { if ($entity_type->id() == 'taxonomy_term') { $fields = [];   $fields['stored_depth'] = BaseFieldDefinition::create('integer') ->setLabel(t('Depth')) ->setSetting('unsigned', TRUE) ->setDefaultValue(0);   return $fields; } }

    modulename.install

    /**

    Читать дальше →

    Похожие записи:

    Категории: Друпалургия

    Черная пятница — время скидок от TemplateMonster

    Drupal в рунете - сб, 23/11/2019 - 01:29

    В TemplateMonster не могли пропустить главный день скидок! В честь Черной пятницы получите скидку 50% на все шаблоны для дизайна сайтов. С ними вам не нужно быть профессиональным разработчиком, ведь интуитивный интерфейс позволит создать страницы с собственным видением и стилем. Это отличный шанс выбрать тему для своего ресурса по лучшей цене и вывести его в ТОП.

    Получить скидку 50%

    Не медлите, предложение действует с 21 ноября по 3 декабря.

  • Предлагаю решение
  • Сайт и проект Drupal.ru
  • 0 Thanks
    Категории: Друпалургия

    Страницы

    Подписка на Друпалургия сбор новостей - Друпалургия