Если вы владеете Telegram-каналом (или несколькими), раскрученным аккаунтом в Instagram или любой другой социальной сети, то уже наверняка задавались вопросом: А как мне планировать посты заранее? Существует очень много разных сервисов, которые решают эту задачу. Но по тем или иным причинам они могут не подходить: где-то цена большая, где-то функционал беден, а где-то вообще страшно оставлять логин-пароль от своего раскрученного аккаунта. Сегодня я расскажу и покажу как на основе нашей платформы для разработки бизнес приложений с открытым кодом Orienteer сделать свой собственный сервис буквально за 60 минут! Заинтересовал? Проваливаемся под кат.

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

Шаг 1: Запускаем Orienteer


Нам понадобится docker, а еще лучше вместе с docker-compose. Можно его использовать как на локальном компьютере, так и на любом доступном хостинге, включая AWS или DigitalOcean. Если не знакомы с docker, то крайне рекомендую потратить 3-5 часов своей жизни и изучить основы. Хабр, medium или даже первоисточник вам в помощь.

Запускаем сам Orienteer, например вот так:

docker run -p 8080:8080 orienteer/orienteer

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

docker run -p 8080:8080 -v <runtime>:/app/runtime -e ORIENTDB_ADMIN_PASSWORD=<password> -e ORIENTDB_GUEST_PASSWORD=<password> orienteer/orienteer

Если же вы любите docker-compose, то вот вам шаблон для старта:

version: '2.1'
services:
   orienteer:
      image: orienteer/orienteer:latest
      container_name: my_posting_service
      network_mode: 'bridge'
      ports:
          - "8080:8080"
      volumes:
          - ./runtime:/app/runtime
          - ./maven-repository:/app/repository
      environment:
          - ORIENTDB_ADMIN_PASSWORD=<Admin Password>
          - ORIENTDB_GUEST_PASSWORD=<Guest Password>
          - JAVA_TOOL_OPTIONS= -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/runtime/heapdump.bin

Если вы всё сделали правильно, то при открытии localhost:8080 вы должны увидеть что-то вроде снимка ниже. Да, по умолчанию вы попадаете в Orienteer как пользователь `reader`, который умеет всё читать, но не изменять. Права у reader'а можно позже отнять, чтобы backend могли видеть только пользователи, вошедшие в систему.



Кликаем на правый верхний угол и входим в систему как `admin` (по умолчанию пароль тоже `admin`).



Шаг 2: Подключаем необходимые модули и зависимости


Для того чтобы превратить Orienteer в сервис по отложенному постингу нам понадобится:

  • java-telegram-bot-api — простая java библиотека для работы с Telegram
  • orienteer-architect — модуль для проектирования предметной области
  • orienteer-devutils — модуль для удобного отлаживания скриптов

После разработки, последние 2 модуля, кстати, можно будет отключить.

Идем на страницу Schema, затем на вкладку Artifacts. Нажимаем Add. Для добавления библиотеки java-telegram-bot-api вводим все так же, как если бы подключали обычную Java библиотеку:

<dependency>
   <groupId>com.github.pengrad</groupId>
   <artifactId>java-telegram-bot-api</artifactId>
   <version>5.0.0</version>
</dependency>

Должно получиться вот так:



А чтобы добавить 2 последних модуля, нажимаем вновь Add, а затем на кнопку Available Orienteer Modules. После загрузки списка выбираем нужный модуль и нажимаем Install as Trusted. После добавления всех нужных зависимостей жмем оранжевую кнопку Reload Orienteer. После перезагрузки можем двигаться дальше.



Шаг 3: Моделируем нашу предметную область


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

  • Контент (или пост) — то что мы собираемся послать в нужный канал в определенное время
  • Канал — то куда мы собираемся послать наш контент
  • Бот — сущность, осуществляющая посылку контента

Прошу обратить внимание, что в этой предметной области нет специфики Telegram. Под каналом может подразумеваться аккаунт Instagram или Вконтакте. Вся специфика будет скрываться под Ботом, — сущностью осуществляющей саму посылку: а именно, в скриптах, которые мы проассоциируем с сущностью Бот.

Для моделирования предметной области рекомендую использовать модуль orienteer-architect. Идем в ODataModel по кнопке Browse, нажимаем Create, вписываем `Scheduler Data Model` в поле Name и нажимаем Save. А дальше чистое творчество! Но думаю, в конце у вас должно получиться что-то вроде данной картинки:



Рекомендую после сохранения и применения вашей предметной области (кнопки Save Data Model и Apply Changes) пройтись по созданным классам и их полям и доконфигурировать для большего комфорта такие вещи, как:

  • Поле определяющее имя документа (Document Name Property)
  • Поле определяющее ссылку на документ более высокого уровня (Parent Document Property) — влияет на строчку навигации
  • Тип визуализации (Visualization) — как именно отображать значения

Шаг 4: Оживляем наш сервис скриптами


Нам понадобится всего 2 скрипта.

  1. Scheduler — скрипт, который по запуску каждую минуту будет искать следующую порцию сообщений на отправку, находить по ссылке конкретный скрипт по отправке сообщения и вызывать его, передавая сообщение, которое надо отправить, как аргумент
  2. SendToTelegram — скрипт, который получает сообщение как аргумент и, используя Telegram API, отправляет его в нужный канал или чат

Скрипты в Orienteer (и OrientDb) — это объекты класса OFunction. Соответственно, вам надо будет создать объект данного класса с нужным именем, кодом и языком, на котором последний написан. Я рекомендую указывать nashorn — это Java реализация языка JavaScript.
Не буду сильно томить объяснениями: Лучше один раз увидеть код, чем 100 раз его обсудить.

Scheduler


var db = orient.getDatabase(); //Получаем базу данных OrientDB
var resultSet = db.query("select from SContent where published!=true and when < sysdate()"); //Запрашиваем все сообщения, которые еще не опубликованы, но ожидаемая дата публикации уже в прошлом
for(var i in resultSet) { //Итерируемся по результатам
   var content = resultSet[i]; //Очередное сообщение на отправку
   var sendFunction = content.field("channel.bot.sendFunction.name"); //Через цепочку ссылок получаем имя скрипта, который ответстеннен за отправку
   if(sendFunction) {
      db.getMetadata().getFunctionLibrary().getFunction(sendFunction).execute(content); //Вызываем функцию по имени и передаем наше сообщение на отправку как аргумент
      content.field("published", true); //Помечаем наше сообщение как отправленное
      content.save(); //Сохраняем
   }
}

Как видно, скрипт очень простой, и в нем нет никакой специфики Telegram: все скрыто в скрипте, который мы указываем при конфигурации бота.

SendToTelegram


Помните, мы раньше подключили библиотеку java-telegram-bot-api? Теперь самое время её задействовать для посылки сообщения в Telegram!

var content = orient.getDatabase().load(content); //На случай, если в качестве аргумента пришла ссылка, а не сам объект, подгружаем объект из базы
var channel = content.field("channel"); //Получаем наш канал (или чат), куда будем отправлять сообщение
var botDoc = channel.field("bot");//Получаем документ с конфигурацией бота. Именно с этого документа ранее мы считали "sendFunction" - скрипт по отсылке сообщения
var botKey = "Bot"+botDoc.getIdentity(); //Генерируем уникальный ключ для сохранения в окружении TelegramBot
var app = org.orienteer.core.OrienteerWebApplication.lookupApplication(); //Находим Orienteer Web Application как Java объект
var bot = app.getMetaData(botKey); //Пытаемся получить бота по ключу
if(!bot) { //Если бот не найдет - инициализируем его
bot = new com.pengrad.telegrambot.TelegramBot(botDoc.field("token")); //Создаем объект TelegramBot и передаем ему token нужный для работы
app.setMetaData(botKey, bot); //Сохраняем бота под Orienteer Web Application, чтобы следующий раз не создавать его заново
}
bot.execute(new com.pengrad.telegrambot.request.SendMessage(channel.field("chatId"), content.field("content"))); //Отсылаем сообщение, передавая в API само сообщение и chatId

Но как же нам вызывать скрипт Scheduler каждую минуту? Для этого в Orienteer (и OrientDB) используются объекты класса OSchedule. Создаем объект данного класса, указываем произвольное имя, выбираем наш скрипт Scheduler в поле Function, а затем указываем следующее значние в поле Rule: `0 * * * * ?`. Данная запись означает вызов скрипта в нулевую секунду каждой минуты, каждого часа и т.д.

Шаг 5: Тестируем наше творение


А теперь самое интересное! Приступаем к тестам.

Создаем бота


Нам надо создать самого бота в Telegram, а затем сконфигурировать объект бота с его конфигурацией в Orienteer.

Как создать бота в Telegram и получить token для него можно почитать здесь. Если коротко:

  1. Связываемся с BotFather
  2. Посылаем команду /newbot
  3. Указываем отображаемое имя для бота
  4. Указываем имя пользователя для бота

Как результат мы получаем token. Рекомендую добавить созданного бота к себе в список контактов, так как нам надо будет добавить его в нужные каналы и группы.

Далее идем в наш Orienteer и создаем документ класса SBot, который мы смоделировали прежде в шаге №3. Указываем имя, ссылку на наш скрипт SendToTelegram и непосредственно token, который мы получили из общения с BotFather прежде.



Создаем канал


Я предполагаю, что в Telegram у вас уже создан канал или чат. Если нет, то уверен, что вы с легкостью справитесь с этим. Для того чтобы правильно сконфигурировать канал в Orienteer, нам понадобится так называемый chatId. Проще всего это сделать с помощью бота GetIDs Bot. Если вы настраиваете своего бота для канала, то просто перешлите ему любое сообщение из канала. А если для группы, то добавьте данного бота в группу и первым сообщением он вам выдаст ChatId, затем его можно из группы удалить.





Если вы всё сделали правильно, то у вас есть ChatId, и всё, что осталось сделать, это пойти в Orienteer, создать объект из нашей предметной области SChannel, указать имя и данный ChatId. Ну и не забываем добавить Telegram бота в канал или чат, а так же указать ссылку на бота в Orienteer, который мы уже сконфигурировали.

Создаем сообщения


А теперь момент истины: создаём сообщения и тестируем их появление в канале или группе. Для сообщений мы уже создали класс SContent. В объекте этого класса указываем название (не публикуется в Telegram), ссылку на желаемый канал или чат, время публикации, ну и, собственно, само сообщение.



Если все сделали правильно, то в обозначенное время сообщение будет послано.



Ура! Нашим сервисом можно пользоваться!

На этом на сегодня всё!

Если вам нравятся наши статьи, то дайте, пожалуйста, нам знать об этом плюсом или комментарием.

P.S. Если что-то не получилось по данной инструкции или же хотите воспользоваться уже сконфигуренным Orienteer'ом, то пишите нам: либо здесь, либо в Telegram.

P.P.S. Нам в проект Orienteer нужны люди! Даже если вы только учитесь и еще толком не погрузились в Java или JavaScript, но хотели бы поучаствовать — то ничего страшного — пишите! А мы научим!