Added combined notifications (#639)

If multiple servers go up or down together, you don't get spammed with notifications if you have this option enabled. It will send one combined notification.
This commit is contained in:
Tim 2018-09-05 23:03:29 +02:00 committed by TimZ99
parent d33c891be2
commit cf6f30adfc
No known key found for this signature in database
GPG Key ID: 4D8268DC68E8339D
8 changed files with 570 additions and 343 deletions

View File

@ -5,6 +5,7 @@ Changelog
Not yet released
----------------
* #639: Added combined notifications.
* #626: Added redirect check.
* #627: Latest server output, error and output during a failure will be saved and are shown on the server page.
* #631: Added option to specify the request method.

View File

@ -33,8 +33,9 @@
/**
* Retrieve language settings from the selected language file
* Return false if arg is not found
*
* @return string
* @return string|bool
* @see psm_load_lang()
*/
function psm_get_lang() {
@ -62,7 +63,7 @@ function psm_get_lang() {
$lang = $GLOBALS['sm_lang_default'];
foreach ($args as $translation) {
$lang = $lang[$translation];
$lang = $lang[$translation];
}
return $lang;
}
@ -311,15 +312,20 @@ function psm_log_uptime($server_id, $status, $latency) {
/**
* Parses a string from the language file with the correct variables replaced in the message
*
* @param boolean $status
* @param boolean|null $status
* @param string $type is either 'sms', 'email', 'pushover_title', 'pushover_message' or 'telegram_message'
* @param array $server information about the server which may be placed in a message: %KEY% will be replaced by your value
* @param array $vars server information about the server which may be placed in a message: %KEY% will be replaced by your value
* @param boolean $combi parse other message if notifications need to be send combined
* @return string parsed message
*/
function psm_parse_msg($status, $type, $vars) {
$status = ($status === true) ? 'on' : 'off';
function psm_parse_msg($status, $type, $vars, $combi = false) {
if(is_bool($status)) {
$status = ($status === true) ? 'on_' : 'off_';
}
$message = psm_get_lang('notifications', $status.'_'.$type);
$combi = ($combi === true) ? 'combi_' : '';
$message = psm_get_lang('notifications', $combi.$status.$type);
if (!$message) {
return $message;
@ -817,6 +823,12 @@ class telegram
$this->_user = (string) $user;
}
public function setMessage($message) {
$message = str_replace("<ul>","",$message);
$message = str_replace("</ul>","\n",$message);
$message = str_replace("<li>","- ",$message);
$message = str_replace("</li>","\n",$message);
$message = str_replace("<br>","\n",$message);
$message = str_replace("<br/>","\n",$message);
$this->_message = (string) $message;
}
public function sendurl() {
@ -830,7 +842,9 @@ class telegram
}
public function send() {
if (!Empty($this->_token) && !Empty($this->_user) && !Empty($this->_message)) {
$this->_url = 'https://api.telegram.org/bot'.urlencode($this->_token).'/sendMessage?chat_id='.urlencode($this->_user).'&text='.urlencode($this->_message);
$this->_url = 'https://api.telegram.org/bot'.urlencode($this->_token).
'/sendMessage?chat_id='.urlencode($this->_user).'&text='.
urlencode($this->_message).'&parse_mode=HTML';
}
return $this->sendurl();
}

View File

@ -272,16 +272,18 @@ $sm_lang = array(
'telegram_api_token_description' => 'Before you can use Telegram, you need to get a API token. Visit the <a href="http://docs.phpservermonitor.org/">documentation</a> for help.',
'alert_type' => 'Select when you\'d like to be notified.',
'alert_type_description' => '<b>Status change:</b> '.
'You will receive a notifcation when a server has a change in status. So from online -> offline or offline -> online.<br/>'.
'You will receive a notification when a server has a change in status. So from online -> offline or offline -> online.<br/>'.
'<br /><b>Offline:</b> '.
'You will receive a notification when a server goes offline for the *FIRST TIME ONLY*. For example, '.
'your cronjob is every 15 mins and your server goes down at 1 am and stays down till 6 am. '.
'You will get 1 notification at 1 am and thats it.<br/>'.
'your cronjob is every 15 minutes and your server goes down at 1 am and stays down till 6 am. '.
'You will get 1 notification at 1 am and that\'s it.<br/>'.
'<br><b>Always:</b> '.
'You will receive a notification every time the script runs and a site is down, even if the site has been offline for hours.',
'alert_type_status' => 'Status change',
'alert_type_offline' => 'Offline',
'alert_type_always' => 'Always',
'combine_notifications' => 'Combine notifications',
'combine_notifications_description' => 'Reduces the amount of notification by combining the notifications into 1 single notification. (This does not affect SMS notifications.)',
'alert_proxy' => 'Even if enabled, proxy is never used for services',
'alert_proxy_url' => '<b>Format:</b> Host:Port',
'log_status' => 'Log status',
@ -347,7 +349,18 @@ $sm_lang = array(
'on_email_body' => "Server '%LABEL%' is running again, it was down for %LAST_OFFLINE_DURATION%:<br/><br/>Server: %LABEL%<br/>IP: %IP%<br/>Port: %PORT%<br/>Date: %DATE%",
'on_pushover_title' => 'Server \'%LABEL%\' is RUNNING',
'on_pushover_message' => 'Server \'%LABEL%\' is running again, it was down for %LAST_OFFLINE_DURATION%:<br/><br/>Server: %LABEL%<br/>IP: %IP%<br/>Port: %PORT%<br/>Date: %DATE%',
'on_telegram_message' => 'Server \'%LABEL%\' is running again, it was down for %LAST_OFFLINE_DURATION%:<br/><br/>Server: %LABEL%<br/>IP: %IP%<br/>Port: %PORT%<br/>Date: %DATE%',
'on_telegram_message' => 'Server \'%LABEL%\' is running again, it was down for :<br/><br/>Server: %LABEL%<br/>IP: %IP%<br/>Port: %PORT%<br/>Downtime: %LAST_OFFLINE_DURATION%<br/>Date: %DATE%',
'combi_off_email_message' => "<ul><li>Server: %LABEL%</li><li>IP: %IP%</li><li>Port: %PORT%</li><li>Error: %ERROR%</li><li>Date: %DATE%</li></ul>",
'combi_off_pushover_message' => "<ul><li>Server: %LABEL%</li><li>IP: %IP%</li><li>Port: %PORT%</li><li>Error: %ERROR%</li><li>Date: %DATE%</li></ul>",
'combi_off_telegram_message' => "- Server: %LABEL%<br/>- IP: %IP%<br/>- Port: %PORT%<br/>- Error: %ERROR%<br/>- Date: %DATE%<br/><br/>",
'combi_on_email_message' => "<ul><li>Server: %LABEL%</li><li>IP: %IP%</li><li>Port: %PORT%</li><li>Downtime: %LAST_OFFLINE_DURATION%</li><li>Date: %DATE%</li></ul>",
'combi_on_pushover_message' => '<ul><li>Server: %LABEL%</li><li>IP: %IP%</li><li>Port: %PORT%</li><li>Downtime: %LAST_OFFLINE_DURATION%</li><li>Date: %DATE%</li></ul>',
'combi_on_telegram_message' => '- Server: %LABEL%<br/>- IP: %IP%<br/>- Port: %PORT%<br/>- Downtime: %LAST_OFFLINE_DURATION%<br/>- Date: %DATE%<br/><br/>',
'combi_email_subject' => 'IMPORTANT: \'%UP%\' servers UP again, \'%DOWN%\' servers DOWN',
'combi_pushover_subject' => '\'%UP%\' servers UP again, \'%DOWN%\' servers DOWN',
'combi_email_message' => '<b>The following servers went down:</b><br/>%DOWN_SERVERS%<br/><b>The following servers are up again:</b><br/>%UP_SERVERS%',
'combi_pushover_message' => '<b>The following servers went down:</b><br/>%DOWN_SERVERS%<br/><b>The following servers are up again:</b><br/>%UP_SERVERS%',
'combi_telegram_message' => '<b>The following servers went down:</b><br/>%DOWN_SERVERS%<br/><b>The following servers are up again:</b><br/>%UP_SERVERS%',
),
'login' => array(
'welcome_usermenu' => 'Welcome, %user_name%',

View File

@ -48,6 +48,7 @@ class ConfigController extends AbstractController {
'log_pushover',
'log_telegram',
'show_update',
'combine_notifications',
);
/**
@ -395,6 +396,8 @@ class ConfigController extends AbstractController {
'label_alert_type_status' => psm_get_lang('config', 'alert_type_status'),
'label_alert_type_offline' => psm_get_lang('config', 'alert_type_offline'),
'label_alert_type_always' => psm_get_lang('config', 'alert_type_always'),
'label_combine_notifications' => psm_get_lang('config', 'combine_notifications'),
'label_combine_notifications_description' => psm_get_lang('config', 'combine_notifications_description'),
'label_log_status' => psm_get_lang('config', 'log_status'),
'label_log_status_description' => psm_get_lang('config', 'log_status_description'),
'label_log_email' => psm_get_lang('config', 'log_email'),

View File

@ -560,13 +560,15 @@ class Installer {
* If you have a lot of server that are redirecting,
* this will make sure you're servers stay online.
*/
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `allow_http_status` VARCHAR(255) NOT NULL DEFAULT '' AFTER `pattern_online`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `allow_http_status` VARCHAR(255) NOT NULL DEFAULT '' AFTER `pattern_online`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD `redirect_check` ENUM( 'ok','bad' ) NOT NULL DEFAULT 'ok' AFTER `allow_http_status`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` CHANGE `redirect_check` `redirect_check` ENUM('ok','bad') NOT NULL DEFAULT 'bad';";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `last_error` VARCHAR(255) NULL AFTER `website_password`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `last_error_output` TEXT NULL AFTER `last_error`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `last_output` TEXT NULL AFTER `last_error_output`;";
$queries[] = "ALTER TABLE `".PSM_DB_PREFIX."servers` ADD COLUMN `request_method` varchar(50) NULL AFTER `port`;";
$this->execSQL($queries);
$queries[] = "INSERT INTO `".PSM_DB_PREFIX."config` (`key`, `value`) VALUES ('combine_notifications', '1');";
$this->execSQL($queries);
$this->log('Combined notifications enabled. Check out the config page for more info.');
}
}

View File

@ -79,5 +79,8 @@ class UpdateManager implements ContainerAwareInterface {
$archive->archive($server['server_id']);
$archive->cleanup($server['server_id']);
}
if($notifier->combine){
$notifier->notifyCombined();
}
}
}

View File

@ -72,6 +72,23 @@ class StatusNotifier {
*/
protected $save_logs = false;
/**
* Send multiple notifications as one?
* @var boolean $combine
*/
public $combine = false;
/**
* Notification list
* @var array $combiNotification
*/
protected $combiNotification = array(
'count' => array(),
'users' => array(),
'notifications' => array(),
'userNotifications' => array()
);
/**
* Server id
* @var int $server_id
@ -104,18 +121,26 @@ class StatusNotifier {
$this->send_pushover = psm_get_conf('pushover_status');
$this->send_telegram = psm_get_conf('telegram_status');
$this->save_logs = psm_get_conf('log_status');
$this->combine = psm_get_conf('combine_notifications');
}
/**
* This function initializes the sending (text msg & email) and logging
*
* @param int $server_id
* @param boolean $status_old
* @param boolean $status_new
* @return boolean
*/
/**
* This function initializes the sending (text msg, email, Pushover and Telegram) and logging
*
* @param int $server_id
* @param boolean $status_old
* @param boolean $status_new
* @return boolean
* @throws \PHPMailer\PHPMailer\Exception
*/
public function notify($server_id, $status_old, $status_new) {
if (!$this->send_emails && !$this->send_sms && !$this->save_logs) {
if (
!$this->send_emails &&
!$this->send_sms &&
!$this->send_pushover &&
!$this->send_telegram &&
!$this->save_logs
) {
// seems like we have nothing to do. skip the rest
return false;
}
@ -125,10 +150,12 @@ class StatusNotifier {
$this->status_new = $status_new;
// get server info from db
// only get info that will be put into the notification
// or is needed to check if a notification need to be send
$this->server = $this->db->selectRow(PSM_DB_PREFIX.'servers', array(
'server_id' => $server_id,
), array(
'server_id', 'ip', 'port', 'label', 'type', 'pattern', 'status', 'header_name', 'header_value', 'error', 'active', 'email', 'sms', 'pushover', 'telegram', 'last_online', 'last_offline', 'last_offline_duration',
'server_id', 'ip', 'port', 'label', 'error', 'email', 'sms', 'pushover', 'telegram', 'last_online', 'last_offline', 'last_offline_duration',
));
if (empty($this->server)) {
return false;
@ -177,14 +204,19 @@ class StatusNotifier {
return $notify;
}
if($this->combine){
$this->setCombi('init', $users);
}
// check if email is enabled for this server
if ($this->send_emails && $this->server['email'] == 'yes') {
// send email
$this->notifyByEmail($users);
$this->combine ? $this->setCombi('email') : $this->notifyByEmail($users);
}
// check if sms is enabled for this server
if ($this->send_sms && $this->server['sms'] == 'yes') {
// sms will not be send combined as some gateways don't support long sms / charge extra
// yay lets wake those nerds up!
$this->notifyByTxtMsg($users);
}
@ -192,31 +224,143 @@ class StatusNotifier {
// check if pushover is enabled for this server
if ($this->send_pushover && $this->server['pushover'] == 'yes') {
// yay lets wake those nerds up!
$this->notifyByPushover($users);
$this->combine ? $this->setCombi('pushover') : $this->notifyByPushover($users);
}
// check if telegram is enabled for this server
if ($this->send_telegram && $this->server['telegram'] == 'yes') {
// yay lets wake those nerds up!
$this->notifyByTelegram($users);
$this->combine ? $this->setCombi('telegram') : $this->notifyByTelegram($users);
}
return $notify;
}
/**
* This functions performs the email notifications
*
* @param array $users
* @return boolean
*/
protected function notifyByEmail($users) {
/**
* This functions collects all of the notifications
*
* @param string $method notification method
* @param array $users Users
* @return void
*/
public function setCombi($method, $users = array()) {
$status = $this->status_new ? 'on' : 'off';
if ($method == 'init' && !empty($users)){
foreach($users as $user) {
if(!isset($this->combiNotification['count'][$user['user_id']])){
$this->combiNotification['count'][$user['user_id']] = array('on' => 0, 'off' => 0);
}
$this->combiNotification['userNotifications'][$user['user_id']][] = $this->server_id;
$this->combiNotification['users'][$user['user_id']] = $user;
$this->combiNotification['count'][$user['user_id']][$status] += 1;
}
return;
}
$this->combiNotification['notifications'][$method][$status][$this->server_id] =
psm_parse_msg($this->status_new, $method.'_message', $this->server, true);
return;
}
/**
* This functions returns the subject for a combined notification
*
* @return void
*/
public function notifyCombined() {
if(empty($this->combiNotification['userNotifications'])){
return;
}
// Get the servers the user will get notified of
$this->status_new = true;
foreach ($this->combiNotification['userNotifications'] as $user => $servers) {
$notifications = array();
// Combine all of the messages belonging to the server the user will get notification of
foreach ($servers as $server) {
foreach ($this->combiNotification['notifications'] as $method => $status){
foreach ($status as $the_status => $value) {
if(!key_exists($method, $notifications)){
$notifications[$method] = array('on' => '', 'off' => '');
}
if(key_exists($server, $status[$the_status])){
$notifications[$method][$the_status] .= $status[$the_status][$server];
}
// Set $this->status_new to false if a server is down.
// This is used by Pushover to determine the priority.
if(!empty($notifications[$method]['off'])){
$this->status_new = false;
}
}
}
}
// Send combined notification per user
foreach ($notifications as $method => $notification){
$finalNotification['message'] = $this->createCombiMessage($method, $notification);
$subject = $this->createCombiSubject($method, $user);
if(!is_null($subject)){
$finalNotification['subject'] = $subject;
}
$this->{'notifyBy' . ucwords($method)}
(array($this->combiNotification['users'][$user]), $finalNotification);
}
}
unset($notifications);
return;
}
/**
* This functions returns the message for a combined notification
*
* @param string $method Notification method
* @param array $notification Notification
* @return string
*/
protected function createCombiMessage($method, $notification){
if(empty($notification['off'])){
$notification['off'] = "<ul><li>".psm_get_lang('system', 'none')."</li></ul>";
}
if(empty($notification['on'])){
$notification['on'] = "<ul><li>".psm_get_lang('system', 'none')."</li></ul>";
}
$vars = array('DOWN_SERVERS' => $notification['off'], 'UP_SERVERS' => $notification['on']);
return psm_parse_msg(null, $method.'_message', $vars, true);
}
/**
* This functions returns the subject for a combined notification
*
* @param string $method Notification method
* @param integer $user_id User id
* @return string|null
*/
protected function createCombiSubject($method, $user_id){
//die(var_dump($GLOBALS['sm_lang_default']['notifications']['combi_'.$method.'_subject']));
$vars = array('DOWN' => $this->combiNotification['count'][$user_id]['off'], 'UP' => $this->combiNotification['count'][$user_id]['on']);
$translation = isset($GLOBALS['sm_lang_default']['notifications']['combi_'.$method.'_subject']) ?
psm_parse_msg(null, $method.'_subject', $vars, true) :
null;
return $translation;
}
/**
* This functions performs the email notifications
*
* @param \PDOStatement $users
* @param array $combi contains message and subject (optional)
* @return void
* @throws \PHPMailer\PHPMailer\Exception
*/
protected function notifyByEmail($users, $combi = array()) {
// build mail object with some default values
$mail = psm_build_mail();
$mail->Subject = psm_parse_msg($this->status_new, 'email_subject', $this->server);
$mail->Subject = key_exists('subject', $combi) ?
$combi['subject'] :
psm_parse_msg($this->status_new, 'email_subject', $this->server);
$mail->Priority = 1;
$body = psm_parse_msg($this->status_new, 'email_body', $this->server);
$body = key_exists('message', $combi) ?
$combi['message'] :
psm_parse_msg($this->status_new, 'email_body', $this->server);
$mail->Body = $body;
$mail->AltBody = str_replace('<br/>', "\n", $body);
@ -230,20 +374,22 @@ class StatusNotifier {
psm_add_log_user($log_id, $user['user_id']);
}
// we sent a seperate email to every single user.
// we sent a separate email to every single user.
$mail->AddAddress($user['email'], $user['name']);
$mail->Send();
$mail->ClearAddresses();
}
return;
}
/**
* This functions performs the pushover notifications
*
* @param array $users
* @return boolean
* @param \PDOStatement $users
* @param array $combi contains message and subject (optional)
* @return void
*/
protected function notifyByPushover($users) {
protected function notifyByPushover($users, $combi = array()) {
// Remove users that have no pushover_key
foreach ($users as $k => $user) {
if (trim($user['pushover_key']) == '') {
@ -257,7 +403,10 @@ class StatusNotifier {
}
// Pushover
$message = psm_parse_msg($this->status_new, 'pushover_message', $this->server);
$message = key_exists('message', $combi) ?
$combi['message'] :
psm_parse_msg($this->status_new, 'pushover_message', $this->server);
$pushover = psm_build_pushover();
if ($this->status_new === true) {
$pushover->setPriority(0);
@ -266,7 +415,11 @@ class StatusNotifier {
$pushover->setRetry(300); //Used with Priority = 2; Pushover will resend the notification every 60 seconds until the user accepts.
$pushover->setExpire(3600); //Used with Priority = 2; Pushover will resend the notification every 60 seconds for 3600 seconds. After that point, it stops sending notifications.
}
$pushover->setTitle(psm_parse_msg($this->status_new, 'pushover_title', $this->server));
$title = key_exists('subject', $combi) ?
$combi['subject'] :
psm_parse_msg($this->status_new, 'pushover_title', $this->server);
$pushover->setHtml(1);
$pushover->setTitle($title);
$pushover->setMessage(str_replace('<br/>', "\n", $message));
$pushover->setUrl(psm_build_url());
$pushover->setUrlTitle(psm_get_lang('system', 'title'));
@ -294,7 +447,7 @@ class StatusNotifier {
/**
* This functions performs the text message notifications
*
* @param array $users
* @param \PDOStatement $users
* @return boolean
*/
protected function notifyByTxtMsg($users) {
@ -329,39 +482,44 @@ class StatusNotifier {
/**
* This functions performs the telegram notifications
*
* @param array $users
* @return boolean
* @param \PDOStatement $users
* @param array $combi contains message and subject (optional)
* @return void
*/
protected function notifyByTelegram($users) {
// Remove users that have no telegram_id
foreach ($users as $k => $user) {
if (trim($user['telegram_id']) == '') {
unset($users[$k]);
}
}
protected function notifyByTelegram($users, $combi = array()) {
// Remove users that have no telegram_id
foreach ($users as $k => $user) {
if (trim($user['telegram_id']) == '') {
unset($users[$k]);
}
}
// Validation
if (empty($users)) {
return;
}
// Validation
if (empty($users)) {
return;
}
// Telegram
$message = psm_parse_msg($this->status_new, 'telegram_message', $this->server);
$telegram = psm_build_telegram();
$telegram->setMessage(str_replace('<br/>', "\n", $message));
// Log
if (psm_get_conf('log_telegram')) {
$log_id = psm_add_log($this->server_id, 'telegram', $message);
}
foreach ($users as $user) {
// Log
if (!empty($log_id)) {
psm_add_log_user($log_id, $user['user_id']);
// Telegram
$message = key_exists('message', $combi) ?
$combi['message'] :
psm_parse_msg($this->status_new, 'telegram_message', $this->server);
$telegram = psm_build_telegram();
$telegram->setMessage($message);
// Log
if (psm_get_conf('log_telegram')) {
$log_id = psm_add_log($this->server_id, 'telegram', $message);
}
$telegram->setUser($user['telegram_id']);
$telegram->send();
}
}
foreach ($users as $user) {
// Log
if (!empty($log_id)) {
psm_add_log_user($log_id, $user['user_id']);
}
$telegram->setUser($user['telegram_id']);
$telegram->send();
}
}
/**
* Get all users for the provided server id

View File

@ -1,293 +1,326 @@
{% import 'main/macros.tpl.html' as macro %}
<form class="form-horizontal" name="edit_config" action="index.php?mod=config&amp;action=save" id="edit_config" method="post">
<ul class="nav nav-tabs">
<li class="{{ general_active }}"><a href="#config-general" data-toggle="tab">{{ label_general }}</a></li>
<li class="{{ email_active }}"><a href="#config-email" data-toggle="tab">{{ label_tab_email }}</a></li>
<li class="{{ sms_active }}"><a href="#config-sms" data-toggle="tab">{{ label_tab_sms }}</a></li>
<li class="{{ pushover_active }}"><a href="#config-pushover" data-toggle="tab">{{ label_tab_pushover }}</a></li>
<li class="{{ telegram_active }}"><a href="#config-telegram" data-toggle="tab">{{ label_tab_telegram }}</a></li>
<li class="{{ general_active }}"><a href="#config-general" data-toggle="tab">{{ label_general }}</a></li>
<li class="{{ email_active }}"><a href="#config-email" data-toggle="tab">{{ label_tab_email }}</a></li>
<li class="{{ sms_active }}"><a href="#config-sms" data-toggle="tab">{{ label_tab_sms }}</a></li>
<li class="{{ pushover_active }}"><a href="#config-pushover" data-toggle="tab">{{ label_tab_pushover }}</a></li>
<li class="{{ telegram_active }}"><a href="#config-telegram" data-toggle="tab">{{ label_tab_telegram }}</a></li>
</ul>
<div class="tab-content well">
<div id="config-general" class="tab-pane {{ general_active }}">
<fieldset>
<legend>{{ label_general }}</legend>
<div class="control-group">
<label class="control-label" for="language">{{ label_language }}</label>
<div class="controls">
<select id="language" name="language">
{% for language in languages %}
<option value="{{ language.value }}" {% if language.value == language_current %} selected="selected" {% endif %}>{{ language.label }}</option>
{% endfor %}
</select>
<div class="tab-content well">
<div id="config-general" class="tab-pane {{ general_active }}">
<fieldset>
<legend>{{ label_general }}</legend>
<div class="control-group">
<label class="control-label" for="language">{{ label_language }}</label>
<div class="controls">
<select id="language" name="language">
{% for language in languages %}
<option value="{{ language.value }}" {% if language.value == language_current %} selected="selected" {% endif %}>{{
language.label }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="show_update"><input type="checkbox" id="show_update" name="show_update[]" {{ show_update_checked|raw }} /> {{ label_show_update }}</label>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="show_update"><input type="checkbox" id="show_update" name="show_update[]"
{{ show_update_checked|raw }} /> {{ label_show_update }}</label>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="auto_refresh_servers">{{ label_auto_refresh }}</label>
<div class="controls">
<input type="text" class="input-mini" id="auto_refresh_servers" name="auto_refresh_servers" value="{{ auto_refresh_servers }}" maxlength="10" data-toggle="tooltip" title="{{ label_auto_refresh_servers }}" />&nbsp;{{ label_seconds }}
<div class="control-group">
<label class="control-label" for="auto_refresh_servers">{{ label_auto_refresh }}</label>
<div class="controls">
<input type="text" class="input-mini" id="auto_refresh_servers" name="auto_refresh_servers" value="{{ auto_refresh_servers }}"
maxlength="10" data-toggle="tooltip" title="{{ label_auto_refresh_servers }}" />&nbsp;{{
label_seconds }}
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password_encrypt_key">
{{ label_password_encrypt_key }}
</label>
<div class="controls">
<input type="text" class="input-xxlarge" id="password_encrypt_key" name="password_encrypt_key"
value="{{ password_encrypt_key }}" maxlength="40" data-toggle="tooltip"
title="{{ label_password_encrypt_key_note }}"/>
</div>
</div>
</fieldset>
<fieldset>
<legend>{{ label_settings_notification }}</legend>
<div class="control-group">
<label class="control-label" for="alert_type">{{ label_alert_type }}</label>
<div class="controls">
<select id="alert_type" name="alert_type">
<option value="status" {{ alert_type_selected_status|raw }}>{{ label_alert_type_status }}</option>
<option value="offline" {{ alert_type_selected_offline|raw }}>{{ label_alert_type_offline }}</option>
<option value="always" {{ alert_type_selected_always|raw }}>{{ label_alert_type_always }}</option>
</select>
<p class="help-block">{{ label_alert_type_description|raw }}</p>
<div class="control-group">
<label class="control-label" for="password_encrypt_key">
{{ label_password_encrypt_key }}
</label>
<div class="controls">
<input type="text" class="input-xxlarge" id="password_encrypt_key" name="password_encrypt_key" value="{{ password_encrypt_key }}"
maxlength="40" data-toggle="tooltip" title="{{ label_password_encrypt_key_note }}" />
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>{{ label_settings_log }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_status" name="log_status[]" {{ log_status_checked|raw }} data-toggle="tooltip" title="{{ label_log_status_description }}" /> {{ label_log_status }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="log_retention_period">{{ label_log_retention_period }}</label>
<div class="controls">
<input type="text" class="input-mini" id="log_retention_period" name="log_retention_period" value="{{ log_retention_period }}" data-toggle="tooltip" title="{{ label_log_retention_period_description }}" />&nbsp;{{ label_log_retention_days }}
</fieldset>
<fieldset>
<legend>{{ label_settings_notification }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="combine_notifications" name="combine_notifications[]" {{ combine_notifications_checked|raw }} data-toggle="tooltip" /> {{ label_combine_notifications }}</label>
<p class="help-block">{{ label_combine_notifications_description }}</p>
</div>
</div>
</div>
<legend>{{ label_settings_proxy }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="proxy"><input type="checkbox" id="proxy" name="proxy[]" {{ proxy_checked|raw }} />{{ label_proxy }}</label>
<p class="help-block">{{ label_alert_proxy|raw }}</p>
<div class="control-group">
<label class="control-label" for="alert_type">{{ label_alert_type }}</label>
<div class="controls">
<select id="alert_type" name="alert_type">
<option value="status" {{ alert_type_selected_status|raw }}>{{ label_alert_type_status }}</option>
<option value="offline" {{ alert_type_selected_offline|raw }}>{{ label_alert_type_offline }}</option>
<option value="always" {{ alert_type_selected_always|raw }}>{{ label_alert_type_always }}</option>
</select>
<p class="help-block">{{ label_alert_type_description|raw }}</p>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="proxy_url">{{ label_proxy_url }}</label>
<div class="controls">
<input type="text" id="proxy_url" name="proxy_url" value="{{ proxy_url }}" maxlength="100" placeholder="{{ label_proxy_url }}" />
<p class="help-block">{{ label_alert_proxy_url|raw }}</p>
</fieldset>
<fieldset>
<legend>{{ label_settings_log }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_status" name="log_status[]" {{ log_status_checked|raw
}} data-toggle="tooltip" title="{{ label_log_status_description }}" /> {{ label_log_status }}</label>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="proxy_user">{{ label_proxy_user }}</label>
<div class="controls">
<input type="text" id="proxy_user" name="proxy_user" value="{{ proxy_user }}" maxlength="100" placeholder="{{ label_proxy_user }}" />
<div class="control-group">
<label class="control-label" for="log_retention_period">{{ label_log_retention_period }}</label>
<div class="controls">
<input type="text" class="input-mini" id="log_retention_period" name="log_retention_period" value="{{ log_retention_period }}"
data-toggle="tooltip" title="{{ label_log_retention_period_description }}" />&nbsp;{{
label_log_retention_days }}
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="proxy_password">{{ label_proxy_password }}</label>
<div class="controls">
<input type="password" id="proxy_password" name="proxy_password" value="{{ proxy_password }}" maxlength="100" placeholder="{{ label_proxy_password }}" />
<legend>{{ label_settings_proxy }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="proxy"><input type="checkbox" id="proxy" name="proxy[]" {{ proxy_checked|raw
}} />{{ label_proxy }}</label>
<p class="help-block">{{ label_alert_proxy|raw }}</p>
</div>
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="general_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div id="config-email" class="tab-pane {{ email_active }}">
<fieldset>
<legend>{{ label_settings_email }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="email_status"><input type="checkbox" id="email_status" name="email_status[]" {{ email_status_checked|raw }} /> {{ label_email_status }}</label>
<div class="control-group">
<label class="control-label" for="proxy_url">{{ label_proxy_url }}</label>
<div class="controls">
<input type="text" id="proxy_url" name="proxy_url" value="{{ proxy_url }}" maxlength="100" placeholder="{{ label_proxy_url }}"
/>
<p class="help-block">{{ label_alert_proxy_url|raw }}</p>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_email" name="log_email[]" {{ log_email_checked|raw }} /> {{ label_log_email }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_from_name">{{ label_email_from_name }}</label>
<div class="controls">
<input type="text" id="email_from_name" name="email_from_name" value="{{ email_from_name }}" maxlength="255" />
<div class="control-group">
<label class="control-label" for="proxy_user">{{ label_proxy_user }}</label>
<div class="controls">
<input type="text" id="proxy_user" name="proxy_user" value="{{ proxy_user }}" maxlength="100" placeholder="{{ label_proxy_user }}"
/>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_from_email">{{ label_email_from_email }}</label>
<div class="controls">
<input type="text" id="email_from_email" name="email_from_email" value="{{ email_from_email }}" maxlength="255" />
<div class="control-group">
<label class="control-label" for="proxy_password">{{ label_proxy_password }}</label>
<div class="controls">
<input type="password" id="proxy_password" name="proxy_password" value="{{ proxy_password }}" maxlength="100" placeholder="{{ label_proxy_password }}"
/>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="email_smtp"><input type="checkbox" id="email_smtp" name="email_smtp[]" {{ email_smtp_checked|raw }} />{{ label_email_smtp }}</label>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="general_submit">{{ label_save }}</button>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_host">{{ label_email_smtp_host }}</label>
<div class="controls">
<input type="text" id="email_smtp_host" name="email_smtp_host" value="{{ email_smtp_host }}" maxlength="100" placeholder="{{ label_email_smtp_host }}" />
<input type="text" class="input-small" id="email_smtp_port" name="email_smtp_port" value="{{ email_smtp_port }}" maxlength="10" placeholder="{{ label_email_smtp_port }}" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_security">{{ label_email_smtp_security }}</label>
<div class="controls">
<select id="email_smtp_security" name="email_smtp_security">
<option value="" {{ email_smtp_security_selected_|raw }}>{{ label_email_smtp_security_none }}</option>
<option value="ssl" {{ email_smtp_security_selected_ssl|raw }}>SSL</option>
<option value="tls" {{ email_smtp_security_selected_tls|raw }}>TLS</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_username">{{ label_email_smtp_username }}</label>
<div class="controls">
<input type="text" id="email_smtp_username" name="email_smtp_username" value="{{ email_smtp_username }}" maxlength="100" placeholder="{{ label_email_smtp_noauth }}" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_password">{{ label_email_smtp_password }}</label>
<div class="controls">
<input type="password" id="email_smtp_password" name="email_smtp_password" value="{{ email_smtp_password }}" maxlength="100" placeholder="{{ label_email_smtp_noauth }}" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testEmail">{{ label_test }}</button>
<input type="hidden" name="test_email" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="email_submit" >{{ label_save }}</button>
</div>
</fieldset>
</div>
<div id="config-sms" class="tab-pane {{ sms_active }}">
<fieldset>
<legend>{{ label_settings_sms }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="sms_status"><input type="checkbox" id="sms_status" name="sms_status[]" {{ sms_status_checked|raw }} /> {{ label_sms_status }}</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_sms" name="log_sms[]" {{ log_sms_checked|raw }} /> {{ label_log_sms }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway">{{ label_sms_gateway }}</label>
<div class="controls">
<select id="sms_gateway" name="sms_gateway">
{% for sms_gateway in sms_gateways %}
<option value="{{ sms_gateway.value }}" {% if sms_gateway.value == sms_gateway_current %} selected="selected" {% endif %}>{{ sms_gateway.label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway_username">{{ label_sms_gateway_username }}</label>
<div class="controls">
<input type="text" id="sms_gateway_username" name="sms_gateway_username" value="{{ sms_gateway_username }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway_password">{{ label_sms_gateway_password }}</label>
<div class="controls">
<input type="password" id="sms_gateway_password" name="sms_gateway_password" value="{{ sms_gateway_password }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_from">{{ label_sms_from }}</label>
<div class="controls">
<input type="text" id="sms_from" name="sms_from" value="{{ sms_from }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testSms">{{ label_test }}</button>
<input type="hidden" name="test_sms" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="sms_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div id="config-pushover" class="tab-pane {{ pushover_active }}">
<fieldset>
<legend>{{ label_settings_pushover }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="pushover_status"><input type="checkbox" id="pushover_status" name="pushover_status[]" {{ pushover_status_checked|raw }} /> {{ label_pushover_status }}</label>
<p class="help-block">{{ label_pushover_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_pushover" name="log_pushover[]" {{ log_pushover_checked|raw }} /> {{ label_log_pushover }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="pushover_api_token">{{ label_pushover_api_token }}</label>
<div class="controls">
<p><button class="btn btn-primary" onclick="window.open('{{ pushover_clone_url }}');return false;">{{ label_pushover_clone_app }}</button></p>
<input type="text" id="pushover_api_token" name="pushover_api_token" value="{{ pushover_api_token }}" maxlength="255" />
<p class="help-block">{{ label_pushover_api_token_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testPushover">{{ label_test }}</button>
<input type="hidden" name="test_pushover" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="pushover_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div id="config-telegram" class="tab-pane {{ telegram_active }}">
<fieldset>
<legend>{{ label_settings_telegram }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="telegram_status"><input type="checkbox" id="telegram_status" name="telegram_status[]" {{ telegram_status_checked|raw }} /> {{ label_telegram_status }}</label>
<p class="help-block">{{ label_telegram_description|raw }}</p>
</div>
</fieldset>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_telegram" name="log_telegram[]" {{ log_telegram_checked|raw }} /> {{ label_log_telegram }}</label>
</div>
<div id="config-email" class="tab-pane {{ email_active }}">
<fieldset>
<legend>{{ label_settings_email }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="email_status"><input type="checkbox" id="email_status" name="email_status[]"
{{ email_status_checked|raw }} /> {{ label_email_status }}</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_email" name="log_email[]" {{ log_email_checked|raw
}} /> {{ label_log_email }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_from_name">{{ label_email_from_name }}</label>
<div class="controls">
<input type="text" id="email_from_name" name="email_from_name" value="{{ email_from_name }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_from_email">{{ label_email_from_email }}</label>
<div class="controls">
<input type="text" id="email_from_email" name="email_from_email" value="{{ email_from_email }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="email_smtp"><input type="checkbox" id="email_smtp" name="email_smtp[]"
{{ email_smtp_checked|raw }} />{{ label_email_smtp }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_host">{{ label_email_smtp_host }}</label>
<div class="controls">
<input type="text" id="email_smtp_host" name="email_smtp_host" value="{{ email_smtp_host }}" maxlength="100" placeholder="{{ label_email_smtp_host }}"
/>
<input type="text" class="input-small" id="email_smtp_port" name="email_smtp_port" value="{{ email_smtp_port }}" maxlength="10"
placeholder="{{ label_email_smtp_port }}" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_security">{{ label_email_smtp_security }}</label>
<div class="controls">
<select id="email_smtp_security" name="email_smtp_security">
<option value="" {{ email_smtp_security_selected_|raw }}>{{ label_email_smtp_security_none }}</option>
<option value="ssl" {{ email_smtp_security_selected_ssl|raw }}>SSL</option>
<option value="tls" {{ email_smtp_security_selected_tls|raw }}>TLS</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_username">{{ label_email_smtp_username }}</label>
<div class="controls">
<input type="text" id="email_smtp_username" name="email_smtp_username" value="{{ email_smtp_username }}" maxlength="100"
placeholder="{{ label_email_smtp_noauth }}" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="email_smtp_password">{{ label_email_smtp_password }}</label>
<div class="controls">
<input type="password" id="email_smtp_password" name="email_smtp_password" value="{{ email_smtp_password }}" maxlength="100"
placeholder="{{ label_email_smtp_noauth }}" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testEmail">{{ label_test }}</button>
<input type="hidden" name="test_email" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="email_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div class="control-group">
<label class="control-label" for="telegram_api_token">{{ label_telegram_api_token }}</label>
<div class="controls">
<input type="text" id="telegram_api_token" name="telegram_api_token" value="{{ telegram_api_token }}" maxlength="255" />
<p class="help-block">{{ label_telegram_api_token_description|raw }}</p>
</div>
<div id="config-sms" class="tab-pane {{ sms_active }}">
<fieldset>
<legend>{{ label_settings_sms }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="sms_status"><input type="checkbox" id="sms_status" name="sms_status[]"
{{ sms_status_checked|raw }} /> {{ label_sms_status }}</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_sms" name="log_sms[]" {{ log_sms_checked|raw
}} /> {{ label_log_sms }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway">{{ label_sms_gateway }}</label>
<div class="controls">
<select id="sms_gateway" name="sms_gateway">
{% for sms_gateway in sms_gateways %}
<option value="{{ sms_gateway.value }}" {% if sms_gateway.value==sms_gateway_current %} selected="selected" {% endif %}>{{
sms_gateway.label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway_username">{{ label_sms_gateway_username }}</label>
<div class="controls">
<input type="text" id="sms_gateway_username" name="sms_gateway_username" value="{{ sms_gateway_username }}" maxlength="255"
/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_gateway_password">{{ label_sms_gateway_password }}</label>
<div class="controls">
<input type="password" id="sms_gateway_password" name="sms_gateway_password" value="{{ sms_gateway_password }}" maxlength="255"
/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="sms_from">{{ label_sms_from }}</label>
<div class="controls">
<input type="text" id="sms_from" name="sms_from" value="{{ sms_from }}" maxlength="255" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testSms">{{ label_test }}</button>
<input type="hidden" name="test_sms" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="sms_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testTelegram">{{ label_test }}</button>
<input type="hidden" name="test_telegram" value="0" />
</div>
<div id="config-pushover" class="tab-pane {{ pushover_active }}">
<fieldset>
<legend>{{ label_settings_pushover }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="pushover_status"><input type="checkbox" id="pushover_status" name="pushover_status[]"
{{ pushover_status_checked|raw }} /> {{ label_pushover_status }}</label>
<p class="help-block">{{ label_pushover_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_pushover" name="log_pushover[]" {{ log_pushover_checked|raw
}} /> {{ label_log_pushover }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="pushover_api_token">{{ label_pushover_api_token }}</label>
<div class="controls">
<p><button class="btn btn-primary" onclick="window.open('{{ pushover_clone_url }}');return false;">{{
label_pushover_clone_app }}</button></p>
<input type="text" id="pushover_api_token" name="pushover_api_token" value="{{ pushover_api_token }}" maxlength="255" />
<p class="help-block">{{ label_pushover_api_token_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testPushover">{{ label_test }}</button>
<input type="hidden" name="test_pushover" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="pushover_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="telegram_submit">{{ label_save }}</button>
<div id="config-telegram" class="tab-pane {{ telegram_active }}">
<fieldset>
<legend>{{ label_settings_telegram }}</legend>
<div class="control-group">
<div class="controls">
<label class="checkbox" for="telegram_status"><input type="checkbox" id="telegram_status" name="telegram_status[]"
{{ telegram_status_checked|raw }} /> {{ label_telegram_status }}</label>
<p class="help-block">{{ label_telegram_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox"><input type="checkbox" id="log_telegram" name="log_telegram[]" {{ log_telegram_checked|raw
}} /> {{ label_log_telegram }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="telegram_api_token">{{ label_telegram_api_token }}</label>
<div class="controls">
<input type="text" id="telegram_api_token" name="telegram_api_token" value="{{ telegram_api_token }}" maxlength="255" />
<p class="help-block">{{ label_telegram_api_token_description|raw }}</p>
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary show-modal" data-modal-id="testTelegram">{{ label_test }}</button>
<input type="hidden" name="test_telegram" value="0" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit" name="telegram_submit">{{ label_save }}</button>
</div>
</fieldset>
</div>
</fieldset>
</div>
</div>
{{ macro.csrf_input() }}
</form>
{{ macro.csrf_input() }}
</form>