Задать вопрос
  • Как посмотреть письмо перед отправкой в Bitrix?

    gromdron
    @gromdron
    Работаю с Bitrix24
    boris tyrepharm, к сожалению вы не можете посмотреть "будущие" письма, так как такая генерация очень сложна.
    Но вы можете посмотреть существующее письмо в новом дизайне. К тому же - вы можете увидеть только как будет выглядеть ваше письмо, если его вывести в браузере, но это не одно и то же, как если оно пройдет через MTA и будет отображаться в Outlook/Thundebird/OWA и т.п.

    Например я хочу посмотреть как приблизительно(*) будет выглядеть сообщение с ID 336020 (в таблице b_event), после изменения дизайна в существующем шаблоне.
    use Bitrix\Main\Mail;
    
    /**
     * Get from b_event table
     * @var integer Existed event id
     */
    $displayedEventId = 336020;
    
    /**
     * List of site ids, for event theme generation
     * must be replaced by current site id in public
     * @var array
     */
    $arSites = [
    	's1'
    ];
    
    try
    {
    	/**
    	 * First, try to find event
    	 */
    	$arEvent = Mail\Internal\EventTable::getRow([
    		'filter' => [
    			'=ID' => $displayedEventId,
    		]
    	]);
    
    	if ( !$arEvent )
    	{
    		throw new \Exception('Event not found');
    	}
    
    	$arEvent['FIELDS'] = $arEvent['C_FIELDS'];
    
    	/**
    	 * Try to find all message templates for 
    	 * sites. In event handler we send for one letter
    	 * per site.
    	 */
    	$arEventMessageFilter = [
    		'=ACTIVE' => 'Y',
    		'=EVENT_NAME' => $arEvent["EVENT_NAME"],
    		'=EVENT_MESSAGE_SITE.SITE_ID' => $arSites,
    	];
    
    	$messageDb = Mail\Internal\EventMessageTable::getList([
    		'select' => ['ID'],
    		'filter' => $arEventMessageFilter,
    		'group' => ['ID']
    	]);
    
    	foreach ($messageDb as $arMessage)
    	{
    		$eventMessage = Mail\Internal\EventMessageTable::getRowById($arMessage['ID']);
    
    		$eventMessage['FILES'] = array();
    		$attachmentDb = Mail\Internal\EventMessageAttachmentTable::getList(array(
    			'select' => array('FILE_ID'),
    			'filter' => array('=EVENT_MESSAGE_ID' => $arMessage['ID']),
    		));
    		while($arAttachmentDb = $attachmentDb->fetch())
    		{
    			$eventMessage['FILE'][] = $arAttachmentDb['FILE_ID'];
    		}
    
    		$arFields = $arEvent['FIELDS'];
    
    		// get message object for send mail
    		$arMessageParams = array(
    			'EVENT' => $arEvent,
    			'FIELDS' => $arFields,
    			'MESSAGE' => $eventMessage,
    			'SITE' => $arSites,
    			'CHARSET' => $charset,
    		);
    		$message = Mail\EventMessageCompiler::createInstance($arMessageParams);
    		$message->compile();
    		echo $message->getMailBody();
    	}
    }
    catch( \Exception $e )
    {
    	var_dump($e);
    }
    Ответ написан
    Комментировать
  • Как спрятать scrollbar в div и отставить возможность скроллинга?

    standy
    @standy
    Если делать как посоветовали выше, то пострадают мобильные браузеры. У них скролл не занимает место, как на десктопах, поэтому текст будет уходить за правую границу.

    Есть еще одно решение:
    /* хром, сафари */
    .element::-webkit-scrollbar { width: 0; }
    
    /* ie 10+ */
    .element { -ms-overflow-style: none; }
    
    /* фф (свойство больше не работает, других способов тоже нет)*/
    .element { overflow: -moz-scrollbars-none; }

    Отсюда: hiding-vertical-scrollbars-with-pure-css-in-chrome...
    Ответ написан
    5 комментариев
  • Как в Битрикс реализовать AI поиск по фото?

    @rPman
    Задача получения текстового описания по картинке CLIP (что то типа обратная stable diffusion):

    https://github.com/mlfoundations/open_clip
    https://huggingface.co/laion/CLIP-ViT-H-14-laion2B...

    гуглить сразу CLIP image classification, тьма моделей начиная с openai, разбираться долго

    p.s. еще про анализ объектов на изображении начни копать от сюда или лучше segment-anything фейсбук много чего выкладывает

    Соответственно после запилить интерфейс и интеграцию в битрикс
    Ответ написан
    1 комментарий
  • Как отрыть доступ пользователю к конкретной папке по sftp?

    @luka1sv
    Web, Swift, Servers
    Вот небольшая инфа

    Создаем нового пользователя:

    useradd -m -s /sbin/nologin crazyadmin
    -m - указывает необходимость создать домашнюю директорию пользователя в каталоге /home;
    -s - задает оболочку пользователя - /sbin/nologin запрещает пользователю использовать shell.
    crazyadmin - имя пользователя

    Устанавливаем созданному пользователю пароль:

    passwd crazyadmin
    Если что-то пошло не так, то всегда можно удалить пользователя командой userdel username, например:

    userdel crazyadmin
    И создадим для нового пользователя папку chroot, о её предназначении будет рассказано ниже.

    mkdir /home/crazysadmin/chroot
    Настройка сервера SSH
    Теперь отправляемся в конфиг SSH - /etc/ssh/sshd_config

    Ищем следующую строчку:

    Subsystem sftp /usr/lib/openssh/sftp-server
    и меняем на

    Subsystem sftp internal-sftp
    Теперь отправляемся в самый конец конфига, и там дописываем:



    Match User crazyadmin
            X11Forwarding no
            AllowTcpForwarding no
            AllowAgentForwarding no
            PermitTunnel no
            ForceCommand internal-sftp
            ChrootDirectory %h/chroot

    ChrootDirectory - родительский каталог той папки, к которой мы хотим открыть доступ по SFTP. В данном примере используется директория chroot, которая лежит в папке пользователя.

    Если на вашем сервере настроен доступ по SSH только через файл ключа, а нужно сделать возможность заходить по паролю, то тогда дописываем еще следующее:

    PasswordAuthentication yes
    Если на сервере установлен метод авторизации по паролю, а есть желание сделать более надежную авторизацию через файл ключа, то можно воспользоваться данной статьей.
    После завершения всех манипуляций с SSH сервером, его нужно перезагрузить:

    service ssh restart
    Настройка директорий для пользователя SFTP
    Отправляемся в директорию /home и там ищем папку свежесозданного пользователя, а в ней папку chroot. Устанавливаем её владельцем пользователя root:

    chown root:root /home/crazyadmin/chroot
    Устанавливаем нужные права на папку:

    chmod 755 /home/crazyadmin
    Внимание! Ни в коем случае не следует выставлять ChrootDirectory какие-либо другие права, в таком случае будет выскакивать следующая ошибка: fatal: bad ownership or modes for chroot directory component.
    Теперь представим, что нам нужно предоставить доступ к нескольким папкам, и они все лежат за пределами ChrootDirectory. Выход из ситуации следующий:

    Допустим нам нужно разрешить доступ к папке /var/www/sysadmin.ru. Создаем в домашнем каталоге пользователя /home/crazyadmin папку с названием sysadmin.ru.

    mkdir /home/crazyadmin/sysadmin.ru
    Теперь смонтируем в эту папку ту директорию, доступ к которой нам нужно обеспечить:

    mount --bind /var/www/sysadmin.ru/ /home/crazyadmin/sysadmin.ru/chroot

    Выставляем необходимые для редактирования права для нашей директории /var/www/sysadmin.ru:

    chmod 777 /var/www/sysadmin.ru
    find /var/www/sysadmin.ru -type f -exec chmod 664 {} +
    find /var/www/sysadmin.ru -type d -exec chmod 777 {} +

    Если в процессе монтирования директории что-то пошло не так, то можно убрать монтирование командой unmount:

    umount /home/crazysyadmin/sysadmin.ru
    На этом настройка SFTP сервера завершена.

    Частые ошибки
    fatal: bad ownership or modes for chroot directory component
    - как писалось выше, данная ошибка появляется тогда, когда владельцем ChrootDirectory является не пользователь root, и права не равны 755.
    No supported authentication methods available (server sent public key)
    - сервер настроен на авторизацию по ключу. Если нужна авторизация по паролю, то в конфиге /etc/ssh/sshd_config нужно поменять значение у переменной PasswordAuthentication с no на yes, а после перезапустить сервер командой service ssh restart.
    Ответ написан
    2 комментария
  • Не отображается :before, в чем ошибка?

    Не хватает символа в content: ""; Просто ради интереса любой добавьте и :before появится
    Ответ написан
    3 комментария
  • Какой оптимальный способ получения статистики по продажам определенного товара в 1С-Битрикс Малый бизнес?

    dmitriy_novikov
    @dmitriy_novikov
    Занимаюсь web-разработкой с 2010г. http://dmnv.ru
    Заходите в админку -> магазин -> отчеты -> товары
    Там вас ждет вся статистика по продажам, фильтры по интервалам дат и прочие вкусности.
    И ничего придумывать не надо:)
    Ответ написан
    3 комментария
  • Как получить корневой раздел элемента инфоблока?

    htmaker
    @htmaker
    Столкнулся недавно с подобной задачей, возможно кому пригодится такое решение:
    Как получить корневой раздел элемента инфоблока?
    Ответ написан
    Комментировать
  • Нужно сделать свою кнопку play у тега video?

    rockfeeler
    @rockfeeler
    Фронтендер, дизайнер, верстальщик-перфекционист
    По сути все просто. Нужно только обратиться к API html5 video, и можно творить все что угодно.
    Ответ написан
    1 комментарий
  • Почему не инвалидируется тегированный кэш?

    Suntechnic
    @Suntechnic Автор вопроса
    Сам спросил - сам отвечай:
    Тегированный кэш не работает если константа BX_COMP_MANAGED_CACHE не установлена. Причем не работает именно тегирование, в том числе и очистка.

    Т.е. никакой вызов StartTagCache не запускает тегированный кэш если не установлена константа BX_COMP_MANAGED_CACHE.

    в dbconn.php или куда вам удобно:
    define('BX_COMP_MANAGED_CACHE', true);
    Ответ написан
    Комментировать
  • Нужен софт для автоматического затирания номеров у авто на фото, как реализовать?

    @iakdrugyelena Автор вопроса
    Нашёл вот такой софт для распознавания номеров zapishemvse.ru/openalpr-programma-dlya-raspoznavan...

    Код открытый
    Ответ написан
    Комментировать
  • Как я могу отправить такой Curl запрос при помощи VueJS или JS?

    @d-sem
    Fetch
    var myHeaders = new Headers();
    myHeaders.append("Cookie", "csrftoken=lsDzlik5lO5y33cshMhIgMYIOzmh3CLv; rur=FTW");
    
    var formdata = new FormData();
    formdata.append("client_id", "990602627938098");
    formdata.append("client_secret", "eb8c7...");
    formdata.append("grant_type", "authorization_code");
    formdata.append("redirect_uri", "https://socialsizzle.herokuapp.com/auth/");
    formdata.append("code", "AQBx-hBsH3...");
    
    var requestOptions = {
      method: 'POST',
      headers: myHeaders,
      body: formdata,
      redirect: 'follow'
    };
    
    fetch("https://api.instagram.com/oauth/access_token", requestOptions)
      .then(response => response.text())
      .then(result => console.log(result))
      .catch(error => console.log('error', error));


    XHR
    var data = new FormData();
    data.append("client_id", "990602627938098");
    data.append("client_secret", "eb8c7...");
    data.append("grant_type", "authorization_code");
    data.append("redirect_uri", "https://socialsizzle.herokuapp.com/auth/");
    data.append("code", "AQBx-hBsH3...");
    
    var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;
    
    xhr.addEventListener("readystatechange", function() {
      if(this.readyState === 4) {
        console.log(this.responseText);
      }
    });
    
    xhr.open("POST", "https://api.instagram.com/oauth/access_token");
    xhr.setRequestHeader("Cookie", "csrftoken=lsDzlik5lO5y33cshMhIgMYIOzmh3CLv; rur=FTW");
    
    xhr.send(data);


    jQuery
    var form = new FormData();
    form.append("client_id", "990602627938098");
    form.append("client_secret", "eb8c7...");
    form.append("grant_type", "authorization_code");
    form.append("redirect_uri", "https://socialsizzle.herokuapp.com/auth/");
    form.append("code", "AQBx-hBsH3...");
    
    var settings = {
      "url": "https://api.instagram.com/oauth/access_token",
      "method": "POST",
      "timeout": 0,
      "headers": {
        "Cookie": "csrftoken=lsDzlik5lO5y33cshMhIgMYIOzmh3CLv; rur=FTW"
      },
      "processData": false,
      "mimeType": "multipart/form-data",
      "contentType": false,
      "data": form
    };
    
    $.ajax(settings).done(function (response) {
      console.log(response);
    });
    Ответ написан
    1 комментарий
  • PHP Simple HTML DOM Parser. Почему не могу получить элемент?

    alekciy
    @alekciy
    Вёбных дел мастер
    Use XPath, Luke.
    <?php
    
    // [1- Скачиваем файл
    // Создаем поток
    $opts = array(
    	'http' => array(
    		'method'  => 'GET',
    		'timeout' => 10,
    	),
    );
    
    $context = stream_context_create($opts);
    
    // Открываем файл с помощью установленных выше HTTP-заголовков
    $page_content = file_get_contents('http://lubematch.shell.com/ru/ru/equipment/100_2_8i_avant_001755', false, $context);
    // -1]
    
    // [2- Парсим данные
    // [3- Строим DOM
    // по сути - отключаем вывод ошибок валидации
    libxml_use_internal_errors(true);
    $page_dom = new \DOMDocument();
    
    $page_dom->strictErrorChecking = false;
    $page_dom->preserveWhiteSpace  = false;
    $page_dom->validateOnParse     = true;
    
    $page_dom = new \DOMDocument();
    
    // [4- loadHTML не дает использовать utf-8, делаем хаком http://php.net/manual/en/domdocument.loadhtml.php#95251
    $page_dom->loadHTML('<?xml encoding="UTF-8">' . $page_content);
    
    foreach ($page_dom->childNodes as $node) {
    	if ($node->nodeType == XML_PI_NODE) {
    		$page_dom->removeChild($node);
    	}
    }
    $page_dom->encoding = 'UTF-8';
    // -4]
    
    $page_xpath = new \DOMXPath($page_dom);
    // -3]
    
    // Вытаскиваем Standard
    $param_1 = $page_xpath->query('//table[@id="recommendation"]//tr[2]/th')->item(0)->nodeValue;
    // Вытаскиваем Spirax S4 ATF HDX
    $param_2 = $page_xpath->query('//table[@id="recommendation"]//tr[5]/td[1]')->item(0)->nodeValue;
    // -2]
    
    var_dump($param_1, $param_2);
    Ответ написан
  • Последовательная проверка условий с вложенностью?

    KornevaViktoria
    @KornevaViktoria
    Frontend Developer
    1) Создаете функцию
    2) Создаете переменную, которая будет хранить итоговый результат
    3) Делаете проверки с помощью if, else if, которые переопределяют переменную
    4) Возвращаете переменную созданную на 2 этапе

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

    const blabla = this.nameFunction();
    
    function nameFunction () {
        let result = false;
    
        if (Условие1 && Условие2) { переопределяем result}
        else if (Условие3 && (условие4 || условие 5)) {переопределяем result}
        else {переопределяем result}
    
        return result;
    }
    Ответ написан
    Комментировать
  • Как переключить раскладку клавиатуры в Raspberry PI из HTML страницы?

    VoidVolker
    @VoidVolker Куратор тега JavaScript
    Dark side eye. А у нас печеньки! А у вас?
    Использовать NWJS в качестве браузера и через АПИ операционной системы переключать язык.
    Ответ написан
    Комментировать
  • Как остановить элемент в определённых точках координат SVG?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Делаем массив объектов - точки остановки и длительность. На каждом шаге проверяем, есть ли в массиве элемент с текущей координатой и если да - добавляем к дефолтному таймауту длительность из найденного элемента. Типа так.

    UPD. Вынесено из комментариев:

    а как добавить классы к движущемуся объекту в местах остановки?

    Добавляем элементам массива остановок ещё одно свойство - имя класса. При остановке делаем classList.add, после окончания остановки classList.remove (если надо) - ничего сложного.
    Ответ написан
    6 комментариев
  • Как исправить проблему с отображения фона лендинга на ios?

    Kiriniy
    @Kiriniy
    Графический и веб-дизайнер
    Очень старая проблема и не только на iOS, а на большинстве браузеров для мобильных устройств в принципе. Суть в том, что использование background-attachment: fixed; сказывается на производительности и он тупо отключён в мобильных устройствах. Может однажды всё будет работать, но пока так. После нескольких лет поиска решения я пришёл к следующим выводам.

    Если эффект крайне необходим, вы можете использовать технологию параллакса (есть бесплатные плагины), когда позиционирование элемента изменяется динамически во время прокрутки, либо использовать отдельный пустой div, где вместо background-attachment: fixed; ставите position: fixed; этому пустому блоку и регулируете всё через z-index.

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

    HTML
    Тут ваша разметка шапки, но с разложенными по классам свойствами CSS.
    <header class="main-header bg-cover bg-fixed">...</header>


    CSS
    Из своего основного класса убираете всё, что касается фона, кроме картинки. Естественно, если вам там ещё что-то нужно, вроде высоты, флоатов и тд., сами решите. Теперь добавляете два класса, которые пойдут как фреймворк и могут использоваться многократно. Один растягивает картинку (центрует и без повторений), другой делает тот самый эффект fixed.
    .main-header {background-image: url(img/picjumbo-bg5.jpg);}
    .bg-cover {background-repeat: no-repeat; background-position: center center; background-size: cover; -webkit-background-size: cover;}
    .bg-fixed {background-attachment: fixed;}


    JS
    Добавляете этот код в шаблон или в файл скриптов. Если ваш сайт открывают на мобильных устройствах, скрипт находит все блоки по классу bg-cover и убирает из них класс bg-fixed, если он есть. Фоновая картинка просто будет скролиться со всем остальным.
    var device = navigator.userAgent.toLowerCase();
    var mob = device.match(/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/);
            if (mob) {
                $(".bg-cover").removeClass("bg-fixed");
            }
    Ответ написан
    8 комментариев
  • Как убрать элемент с яндекс.карт?

    @trefferr
    В инициализации конструктора карт, присваиваешь свойству пустой массив.
    controls: []
    ymaps.ready(function(){
            moscow_map = new ymaps.Map("banner_map", {
                center: [56.34820425, 41.30735193],
                controls: [],
                zoom: 17
            });
    Ответ написан
    Комментировать
  • Как убрать элемент с яндекс.карт?

    forgotten
    @forgotten
    Руководитель разработки API Яндекс.Карт
    Выношу из комментов:

    В документации нет removeControl ;)
    Вообще элементы управления удаляются через map.controls.remove('searchControl').
    Но в вашем случае, насколько я понимаю, достаточно задать список нужных контролов прямо в конструкторе карты.
    https://tech.yandex.ru/maps/jsbox/2.1/customSet_co...
    https://tech.yandex.ru/maps/doc/jsapi/2.1/ref/refe...
    Хотя я не очень понимаю, зачем убирать стандартные элементы управления.
    Ответ написан
    1 комментарий