![](https://habrastorage.org/webt/ij/85/bk/ij85bkhootyw9znhr6yhmsdpnoa.png)
Если вы владеете 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 могли видеть только пользователи, вошедшие в систему.
![](https://habrastorage.org/webt/bc/um/ff/bcumff980bky7tsp4armzs53fbc.png)
Кликаем на правый верхний угол и входим в систему как `admin` (по умолчанию пароль тоже `admin`).
![](https://habrastorage.org/webt/jo/ru/qs/joruqsj1u3vsqwjkuxkwadbvhee.png)
Шаг 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>
Должно получиться вот так:
![](https://habrastorage.org/webt/o8/gd/vy/o8gdvyqz9aeks0ibivjaqlvtopg.png)
А чтобы добавить 2 последних модуля, нажимаем вновь Add, а затем на кнопку Available Orienteer Modules. После загрузки списка выбираем нужный модуль и нажимаем Install as Trusted. После добавления всех нужных зависимостей жмем оранжевую кнопку Reload Orienteer. После перезагрузки можем двигаться дальше.
![](https://habrastorage.org/webt/tq/ud/4w/tqud4w0ywlojnh6zcx_uqm2cx1o.png)
Шаг 3: Моделируем нашу предметную область
Считаю, что лучший способ разработки — это разработка по спирали. И первая спираль — это наиболее простое решение, которое дает нужный нам эффект. А на следующих спиралях можно усложнять разработанное решение так как нужно, добавляя гибкости и т.д.
Давайте так и сделаем. В простом варианте нам нужно будет лишь 3 вида сущностей:
- Контент (или пост) — то что мы собираемся послать в нужный канал в определенное время
- Канал — то куда мы собираемся послать наш контент
- Бот — сущность, осуществляющая посылку контента
Прошу обратить внимание, что в этой предметной области нет специфики Telegram. Под каналом может подразумеваться аккаунт Instagram или Вконтакте. Вся специфика будет скрываться под Ботом, — сущностью осуществляющей саму посылку: а именно, в скриптах, которые мы проассоциируем с сущностью Бот.
Для моделирования предметной области рекомендую использовать модуль orienteer-architect. Идем в ODataModel по кнопке Browse, нажимаем Create, вписываем `Scheduler Data Model` в поле Name и нажимаем Save. А дальше чистое творчество! Но думаю, в конце у вас должно получиться что-то вроде данной картинки:
![](https://habrastorage.org/webt/px/pz/5m/pxpz5mkyucyeix0w7ho_nulkvzq.png)
Рекомендую после сохранения и применения вашей предметной области (кнопки Save Data Model и Apply Changes) пройтись по созданным классам и их полям и доконфигурировать для большего комфорта такие вещи, как:
- Поле определяющее имя документа (Document Name Property)
- Поле определяющее ссылку на документ более высокого уровня (Parent Document Property) — влияет на строчку навигации
- Тип визуализации (Visualization) — как именно отображать значения
Шаг 4: Оживляем наш сервис скриптами
Нам понадобится всего 2 скрипта.
- Scheduler — скрипт, который по запуску каждую минуту будет искать следующую порцию сообщений на отправку, находить по ссылке конкретный скрипт по отправке сообщения и вызывать его, передавая сообщение, которое надо отправить, как аргумент
- 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 для него можно почитать здесь. Если коротко:
- Связываемся с BotFather
- Посылаем команду /newbot
- Указываем отображаемое имя для бота
- Указываем имя пользователя для бота
Как результат мы получаем token. Рекомендую добавить созданного бота к себе в список контактов, так как нам надо будет добавить его в нужные каналы и группы.
Далее идем в наш Orienteer и создаем документ класса SBot, который мы смоделировали прежде в шаге №3. Указываем имя, ссылку на наш скрипт SendToTelegram и непосредственно token, который мы получили из общения с BotFather прежде.
![](https://habrastorage.org/webt/yo/3w/ak/yo3waktpfsc1ipkdmvfsthy_hhm.png)
Создаем канал
Я предполагаю, что в Telegram у вас уже создан канал или чат. Если нет, то уверен, что вы с легкостью справитесь с этим. Для того чтобы правильно сконфигурировать канал в Orienteer, нам понадобится так называемый chatId. Проще всего это сделать с помощью бота GetIDs Bot. Если вы настраиваете своего бота для канала, то просто перешлите ему любое сообщение из канала. А если для группы, то добавьте данного бота в группу и первым сообщением он вам выдаст ChatId, затем его можно из группы удалить.
![](https://habrastorage.org/webt/f6/m6/lb/f6m6lbv3m-5jtgbewgi7-ociya0.png)
![](https://habrastorage.org/webt/9n/mq/i7/9nmqi7xfctd3hh9-jew_46yiunq.png)
Если вы всё сделали правильно, то у вас есть ChatId, и всё, что осталось сделать, это пойти в Orienteer, создать объект из нашей предметной области SChannel, указать имя и данный ChatId. Ну и не забываем добавить Telegram бота в канал или чат, а так же указать ссылку на бота в Orienteer, который мы уже сконфигурировали.
Создаем сообщения
А теперь момент истины: создаём сообщения и тестируем их появление в канале или группе. Для сообщений мы уже создали класс SContent. В объекте этого класса указываем название (не публикуется в Telegram), ссылку на желаемый канал или чат, время публикации, ну и, собственно, само сообщение.
![](https://habrastorage.org/webt/rh/h8/yp/rhh8ypkxwutvdnrj2xrhmf6opxg.png)
Если все сделали правильно, то в обозначенное время сообщение будет послано.
![](https://habrastorage.org/webt/dl/mb/e4/dlmbe4a8abqnxedioy48wya4fz0.png)
Ура! Нашим сервисом можно пользоваться!
На этом на сегодня всё!
Если вам нравятся наши статьи, то дайте, пожалуйста, нам знать об этом плюсом или комментарием.
P.S. Если что-то не получилось по данной инструкции или же хотите воспользоваться уже сконфигуренным Orienteer'ом, то пишите нам: либо здесь, либо в Telegram.
P.P.S. Нам в проект Orienteer нужны люди! Даже если вы только учитесь и еще толком не погрузились в Java или JavaScript, но хотели бы поучаствовать — то ничего страшного — пишите! А мы научим!
GlukKazan
Занятно. А можно поподробнее про моделирование предметной области? orienteer-architect по «Save Data Model» классы сам генерит?
DbLogs Автор
Да — так и есть. Orienteer-Architect — это UML-подобный редактор предметной области, но со спецификой свойственной чисто Orienteer'у: например поддержка инверсированных полей, множественное наследование и т.д.
GlukKazan
Инверсированных полей?
DbLogs Автор
К примеру, как в статье, есть класс Content и Channel. В Channel может быть несколько постов/Content. Т.е. отношение между ними как «один ко многим». В обычных БД была бы какая-нибудь channel_id колонка у таблицы Content и все. Но OrientDB имеет такие типы данных как LINKLIST/LINKSET/LINKBAG и т.п.: которые буквально позволяют иметь поле на Channel, которое ссылается сразу на все записи в Content данного канала. (Доступ с канала к записям канала осуществляется за O(1).) Соответственно вот эти поля в ту и в другую сторону называем инверсированными.