Всем привет, меня зовут Вячеслав — я пользователь ispmanager и руководитель отдела маркетинга. Не знаю, зачем вам нужны Google-карты, «Яндекс Музыка» или Spotify прямо в панели — если вы знаете зачем, пишите в комментариях. А я пока расскажу, как затащить iframe в ispmanager. Разберу два варианта, как это сделать, на примере интеграции с «Яндекс Метрикой» — простой и со звездочкой. 

Поехали →

Зачем нужен iframe в ispmanager 

В ispmanager можно писать модули, но иногда хочется расширить их функциональность или настроить под конкретную задачу. Для этого можно использовать iframe — HTML-элемент, чтобы вставлять один сайт внутрь другого. Способ упрощает разработку и быстро расширяет функциональность, а пользователей не приходится перенаправлять на другие сайты. 

Как обычно выглядит iframe:

<iframe src="URL_встраиваемой_страницы"></iframe>

Основные атрибуты:

  • src: этот атрибут определяет URL веб-страницы или внешнего ресурса, который загружаем внутрь <iframe>.

  • width и height: определяют ширину и высоту iframe. Можно задать размеры в пикселях (px) или процентах (%).

Например, можно встроить видео с YouTube. Я указал URL видео в атрибуте src и задал размеры iframe в пикселях:

<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="560" height="315"></iframe>

Сложный путь — ручная установка

  1. Добавляем новый пункт в меню ispmanager.

  2. Интегрируем «Яндекс Метрику» в ispmanager.

  3. Выгружаем готовый отчет из «Яндекс Метрики» с помощью Python.

  4. Запускаем скрипт на Python в ispmanager.

Добавляем новый пункт в меню ispmanager

Этот блок — подготовка к интеграции с «Яндекс Метрикой». Чтобы в меню появился кастомный раздел, добавляем несколько файлов в разные директории — здесь опираюсь на документацию продукта

Как добавить новый пункт в меню ispmanager:

  1.  В папке  /usr/local/mgr5/etc/xml создаем файл  ispmgr_mod_testframe.xml с содержимым:

<?xml version="1.0" encoding="UTF-8"?>

<mgrdata>
  <mainmenu level="admin+">
    <modernmenu>
      <node name="my_group">
      <node name="testframe" />
      </node>
    </modernmenu>
  </mainmenu>

<handler name="testframe.sh" type="xml">
  <func name="testframe" />
</handler>

<lang name="ru">
  <messages name="desktop">
  <msg name="modernmenu_my_group">Test</msg>
  <msg name="modernmenu_testframe">Test Form Frame</msg>
  </messages>
</lang>

</mgrdata>
В результате в меню слева появится группа «Test» и пункт «Test Form Frame»
В результате в меню слева появится группа «Test» и пункт «Test Form Frame»

Если вам нужны пункты на нескольких языках, блок <lang name="ru"> нужно продублировать. Для этого поменяйте ru на нужную локаль.

  1.  В папке /usr/local/mgr5/addon/ создаем файл testframe.sh. Это простейший обработчик, он возвращает статичное содержимое следующего файла, который мы создадим. 

Добавляем в него код:

#!/bin/bash
cat /usr/local/mgr5/addon/testframe.xml
Так выглядит файл testframe.sh
Так выглядит файл testframe.sh
  1. Выдаем файлу права для обработчиков плагинов с помощью команды в shell-клиенте:

    chmod 755 /usr/local/mgr5/addon/testframe.sh
  1. В папке /usr/local/mgr5/addon/ создаем файл testframe.xml В этом файле будет содержаться самое важное — информация о том, что будет показываться во фрейме.

Добавляем код:

<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="testframe" binary="/ispmgr">
  <metadata name="testframe" type="form" mgr="ispmgr">
    <form>
      <field name="frame" fullwidth="yes">
        <frame name="roundcubeframe" forcetheme="yes" fullpage="yes" keepalive="yes" />
      </field>
    </form>
  </metadata>

  <messages name="testframe" checked="6b49a92f5cc5153c76b78446d0d74eb4">
    <msg name="title">Test Form Frame</msg>
    <msg name="frame">Frame</msg>
  </messages>

  <roundcubeframe>https://x.x.x.x:1501/roundcube/?_task=mail&amp;_mbox=INBOX</roundcubeframe>
</doc>
В файле testframe.xmсодержится информация о том, что будет показываться во фрейме
В файле testframe.xmсодержится информация о том, что будет показываться во фрейме

Теперь можно подтянуть сюда нужный вам адрес вместо roundcubeframe. Для примера я возьму «Яндекс». 

  1. Перезагружаем панель командой killall core в shell-клиенте или с помощью контекстной кнопки на дашборде. Так я получил карту прямо в ispmanager и теперь могу узнать, где пробки прямо сейчас =)

Фрейм подтянулся сразу в темной теме. Для этого в коде я добавил параметр «force theme» со значением «уеs»
Фрейм подтянулся сразу в темной теме. Для этого в коде я добавил параметр «force theme» со значением «уеs»

Интегрируем «Яндекс Метрику» в ispmanager 

Интегрируем «Яндекс Метрику» по API через Google Sheets. Вставка метрики через iframe технически запрещена. Поэтому мы выгрузим данные по API и протолкнем их в продукт через Google Sheets: таблицы без проблем можно вставить через iframe.

Как интегрировать «Яндекс Метрику» через Google Sheets: 

  1. Формируем графики в Google Sheets. Можно вставлять их отдельно, без остальной таблицы. Для этого в настройках публикации выберите «График».

Как выглядят настройки публикации таблицы
Как выглядят настройки публикации таблицы
  1. Встраиваем Google Sheets через URL: «Файл» → «Поделиться» → «Опубликовать в сети» → «Link». 

Google-файлы, встроенные через iframe, не индексируются поисковиками, потому что доступ к файлу классическими методами закрыт.

Попробуйте в поисковиках найти документ «Test для yid — статья на Хабр от Ave_Ls». Если получится, напишите об этом в комментариях =)
Попробуйте в поисковиках найти документ «Test для yid — статья на Хабр от Ave_Ls». Если получится, напишите об этом в комментариях =)
  1. Вставляем полученный адрес в файле testframe.xml 

<roundcubeframe>https://docs.google.com/spreadsheets/d/e/УНИКАЛЬНЫЙБЛОК/pubchart?oid=&amp;format=interactive</roundcubeframe>
Так выглядит график внутри продукта 
Так выглядит график внутри продукта 

Выгружаем готовый отчет из «Яндекс Метрики» с помощью Python

Получаем OAuth-токен в «Яндексе». Вот последовательность действий:

  • Переходим на страницу создания внешних приложений.

  • Заполняем «Название», если авторизация будет только по API.

  • Пропускаем раздел «Иконка».

  • Указываем «web-сервисы» в разделе «Платформа приложения».

  • Прописываем адрес https://oauth.yandex.ru/verification_code в поле «redirect url».

  • Указываем metrika:read и metrika:write в поле «Доступ к данным» для простейшей работы со счетчиками. Эти параметры позволяют делать всё, кроме загрузки расходов в счетчики, передачи пользовательских параметров и загрузки офлайн-данных. Как включить эти возможности — в документации.

  • Нажимаем «Создать приложение». Откроется экран — находим поле «ClientID» и копируем его.

Так выглядит ClientID на странице создания внешних приложений
Так выглядит ClientID на странице создания внешних приложений

Вставляем «ClientID» в ссылку вида: 

https://oauth.yandex.ru/authorize?response_type=token&client_id=<ВАШ ID>

Получаем токен.

Как он выглядит:

Значение OAuth-токена нужно передавать в Header’е каждый раз, когда обращаемся в API
Значение OAuth-токена нужно передавать в Header’е каждый раз, когда обращаемся в API

Для дальнейшей работы нам понадобятся библиотеки Python:

▫ requests,

▫ datetime,

▫ time,

▫ gspread.

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

Передаем запрос в счетчик метрики с нужными параметрами:

API_token = 'OAuth {Токен}'
counter_id = '{ID счетчика метрики}'
api_metrika_url = 'https://api-metrika.yandex.net/stat/v1/data/bytime'

params = {
'date1': {Дата от},
'date2': {Дата до},
'group' : 'day', #Группировка по дням
'dimensions' : 'ym:s:lastsignTrafficSource', #Атрибуция по последнему значимому источнику
'ids' : counter_id,
'metrics': 'ym:s:visits', #выгружаем визиты
}

res = requests.get(api_metrika_url, params = params, headers={'Authorization': API_token})

В ответе получаем последовательность, в которой скрываются нужные данные:

{
  "query":
    {
    "ids":[IDсчетчика],
    "dimensions":["ym:s:lastsignTrafficSource"],
    "metrics":["ym:s:visits"],
    "sort":["-ym:s:visits"],
    "date1":"2024-03-03","date2":"2024-03-03",
    "group":"day",
    "auto_group_size":"1",
    "attr_name":"",
    "quantile":"50",
    "offline_window":"21",
    "attribution":"LastSign",
    "currency":"RUB",
    "adfox_event_id":"0",
    "auto_group_type":"day"
    },
  "Data":
  [
    {"dimensions":[{"icon_id":"2","icon_type":"traffic-source","name":"Search engine traffic","id":"organic"}],"metrics":[[ЗНАЧЕНИЕ.0]]},
    {"dimensions":[{"icon_id":"0","icon_type":"traffic-source","name":"Direct traffic","id":"direct"}],"metrics":[[ЗНАЧЕНИЕ.0]]},
    {"dimensions":[{"icon_id":"1","icon_type":"traffic-source","name":"Link traffic","id":"referral"}],"metrics":[[ЗНАЧЕНИЕ.0]]},
    {"dimensions":[{"icon_id":"3","icon_type":"traffic-source","name":"Ad traffic","id":"ad"}],"metrics":[[ЗНАЧЕНИЕ.0]]},
    {"dimensions":[{"icon_id":"-1","icon_type":"traffic-source","name":"Internal traffic","id":"internal"}],"metrics":[[25.0]]},
    {"dimensions":[{"icon_id":"7","icon_type":"traffic-source","name":"Mailing traffic","id":"email"}],"metrics":[[ЗНАЧЕНИЕ.0]]},
    {"dimensions":[{"icon_id":"8","icon_type":"traffic-source","name":"Social network traffic","id":"social"}],"metrics":[[ЗНАЧЕНИЕ.0]]}
  ],
  "total_rows":1,
  "total_rows_rounded":false,
  "sampled":false,
  "contains_sensitive_data":false,
  "sample_share":1.0,
  "sample_size":ЗНАЧЕНИЕ,
  "sample_space":ЗНАЧЕНИЕ,
  "data_lag":0,
  "totals":[[ЗНАЧЕНИЕ.0]],
  "time_intervals":[["2024-03-03","2024-03-03"]]
}

Чтобы с ней дальше работать, нужно превратить последовательность в словарь и выделить только нужную информацию: это все, что находится в квадратных скобках после «Data».

json_res = res.json()
data = json_res["data"]

Далее нужно обработать полученную информацию и передать в таблицу. 

Нюансы:

  • Сопоставить источник и объем у меня сразу не получилось, поэтому пришлось сделать техническую страницу, где будут сверяться данные. В моем случае — tech.

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

Авторизуемся для работы с Google Sheets. Мне потребуются параметры gspread.service_account и gs.open_by_key. В статье «Как настроить сбор статистики и автоматическое отключение пользователей WireGuard» даю подробную инструкцию, как получить эти параметры в Google cloud console.

gs = gspread.service_account(filename='ПУТЬ ДО ФАЙЛА/yandex-ispmgr.json')
sh = gs.open_by_key('КЛЮЧ')

Обрабатываем полученную информацию — обращаемся к словарям dimensions и metrics:

a = 2 #строчка
b = 1 #столбик
for metrics in data:
  dimensions = metrics["dimensions"]
  for id in dimensions:
    name = id["name"]
    worksheet = sh.worksheet("tech")#подключаемся к технической таблице
    worksheet = worksheet.update_cell(a, b, name)
    a += 1

Вот так я добавил в техническую страницу информацию об источниках трафика в порядке их получения в запросе.

a = 2
for dimensions in data:
  metrics = dimensions["metrics"]
  for id in metrics:
    b = current_date.day+1
    for key in id:
      worksheet = sh.worksheet("tech")
      worksheet = worksheet.update_cell(a, b, key)
      b += 1
    a += 1

Эта часть кода помогла нам передать информацию об объеме трафика в порядке его получения в запросе. А значит, теперь у нас готовы строчки для сопоставления. Получаю данные из текущей таблицы и технической, сравниваю, добавляю новые данные в пункты в актуальной таблице. В моем случае актуальная — current.

worksheet = sh.worksheet("current")
gs_val_current = worksheet.col_values(1)
gs_val_current.remove("Current month")
i2 = 0
a = 2

for word in gs_val_current:
  worksheet = sh.worksheet("tech")
  gs_val_tech = worksheet.col_values(1)
  i = 0
  for word in gs_val_tech:
    if gs_val_tech[i] == gs_val_current[i2]:
      a = i+1
      gs_val_transfer = worksheet.cell(a, 2).value
      worksheet = sh.worksheet("current")
      b = current_date.day
      a = i2+2
      worksheet = worksheet.update_cell(a, b, gs_val_transfer)
    i += 1
  i2 += 1

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

Саму таблицу я построил по такому принципу: строки — источники, столбцы — даты. Скрипт автоматически понимает, какой сейчас день, и записывает в ячейку нужную информацию
Саму таблицу я построил по такому принципу: строки — источники, столбцы — даты. Скрипт автоматически понимает, какой сейчас день, и записывает в ячейку нужную информацию

Запускаем скрипт на Python в ispmanager

  1. Загружаем файл скрипта и yandex-ispmgr.json через файловый менеджер, yandex-ispmgr.json помогает подключиться к Google Sheets.

  2. Заходим в «Конфигурацию ПО» → выделяем Python → «Установить».

  3. Переходим в shell-клиент и прописываем команды:

    /opt/ispmanager/python3.11/bin/python3.11 -m venv <имя-вашего-окружения>
  1. Активируем окружение:

    source <имя-вашего-окружения>/bin/activate
  1. Устанавливаем библиотеки через pip или pip3 на выбор:

    <имя-вашего-окружения>/bin/python3.11 pip3 install <Имя-вашей-библиотеки>
  1. Загружаем файл скрипта на сервер.

  2. Тестово активируем скрипт:

    <имя-вашего-окружения>/bin/python3.11 <путь до файла>

Если сделали всё правильно, запуск пройдет удачно: в таблице появится статистика, а в ispmanager — графики.

  1. Переходим в cron. Вводим команду в формате:

    <имя-вашего-окружения>/bin/python3.11 <путь до файла>

Теперь каждый день добавляется информация за прошедший.

Простая установка — используем скрипт

Я написал скрипт установки iframe в ispmanager — подойдет тем, кому лень писать код руками или хочется поставить iframe для интеграции с другими сайтами. С помощью этого файла вы сможете установить модуль «Яндекс Метрики» без знания кода — работать он будет через iframe. 

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

Как использовать скрипт:

  1. Заходим в «Конфигурацию ПО» → выделяем «Python» → «Установить».

  2. Переходим в shell-клиент и прописываем команды:

    /opt/ispmanager/python3.11/bin/python3.11 -m venv <имя-вашего-окружения>
  1. Активируем окружение:

    source <имя-вашего-окружения>/bin/activate
  1. Скачиваем лаунчер с помощью команды:

    wget https://raw.githubusercontent.com/AveTavern/ispmanager-iframe-launcher/Production/launcher.py

 5. Запускаем скрипт с помощью команды <имя_вашего_окружения>/bin/python3.11 /USERNAME/launcher.py и следуем инструкциям на экране.

Если хотите изучить вопрос подробнее — держите ссылку на репозиторий

Как работает интеграция «Яндекс Метрики» и ispmanager

  • Скрипт по cron авторизуется в «Яндекс Метрике» и скачивает оттуда данные.

  • Данные фильтруются и передаются в Google Sheets, где сопоставляются источники, отрисовываются графики и складируется информация.

  • Iframe, полученный из Google Sheets, подтягивается в ispmanager.

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

Комментарии (0)