Merge pull request #108 from statping-ng/dev

0.90.79 Dev to unstable
pull/1101/head
Adam 2022-01-24 11:32:00 +00:00 committed by GitHub
commit 1f5472d35b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 95 additions and 314 deletions

View File

@ -1,3 +1,11 @@
# 0.90.79 (01-24-2022)
- Updated Russian Language - Thanks meatlayer
- Docker file fix for BASE_PATH and health checks - Thanks michaelkrieger
- Removed statping emailer notifier (not SMTP Mail)
- Fixes for notification failures (Issue statping#911) - Thanks glanchow
- Updated Home page uptime wording (24hr/7days) - Thanks Jonathanrbarney & thatInfrastructureGuy
- [GITHUB] Removed mailer tests
# 0.90.78 (09-15-2021) # 0.90.78 (09-15-2021)
- HTTP Webhooks accept multiple HTTP Headers - HTTP Webhooks accept multiple HTTP Headers
- Modified Telegram notifier to allow chat_ids - Modified Telegram notifier to allow chat_ids

View File

@ -60,9 +60,10 @@ ENV IS_DOCKER=true
ENV SASS=/usr/local/bin/sassc ENV SASS=/usr/local/bin/sassc
ENV STATPING_DIR=/app ENV STATPING_DIR=/app
ENV PORT=8080 ENV PORT=8080
ENV BASE_PATH=""
EXPOSE $PORT EXPOSE $PORT
HEALTHCHECK --interval=60s --timeout=10s --retries=3 CMD curl -s "http://localhost:$PORT/health" | jq -r -e ".online==true" HEALTHCHECK --interval=60s --timeout=10s --retries=3 CMD if [ -z "$BASE_PATH" ]; then HEALTHPATH="/health"; else HEALTHPATH="/$BASE_PATH/health" ; fi && curl -s "http://localhost:80$HEALTHPATH" | jq -r -e ".online==true"
CMD statping --port $PORT CMD statping --port $PORT

52
dev/postman.json vendored

File diff suppressed because one or more lines are too long

View File

@ -6,11 +6,11 @@
</div> </div>
<div class="col-4"> <div class="col-4">
<span class="font-5 d-block font-weight-bold">{{service.online_24_hours}} %</span> <span class="font-5 d-block font-weight-bold">{{service.online_24_hours}} %</span>
<span class="font-1 subtitle">{{$t('last_uptime', [24, $tc('hour', 24)])}}</span> <span class="font-1 subtitle">{{$t('last_uptime')}} 24 {{$tc('hour', 24)}}</span>
</div> </div>
<div class="col-4"> <div class="col-4">
<span class="font-5 d-block font-weight-bold">{{service.online_7_days}} %</span> <span class="font-5 d-block font-weight-bold">{{service.online_7_days}} %</span>
<span class="font-1 subtitle">{{$t('last_uptime', [7, $tc('day', 7)])}}</span> <span class="font-1 subtitle">{{$t('last_uptime')}} 7 {{$tc('day', 7)}}</span>
</div> </div>
</div> </div>
</template> </template>

View File

@ -52,8 +52,8 @@ const chinese = {
days_ago: "天前", days_ago: "天前",
today: "今天", today: "今天",
week: "周", week: "周",
month: "月份", month: "月份 | 月数",
day: "日", day: "日 | 天数",
hour: "小时", hour: "小时",
minute: "分钟", minute: "分钟",
failures_24_hours: "过去 24 小时失败", failures_24_hours: "过去 24 小时失败",

View File

@ -51,11 +51,11 @@ const english = {
service_offline_time: "Service has been offline for", service_offline_time: "Service has been offline for",
days_ago: "Days Ago", days_ago: "Days Ago",
today: "Today", today: "Today",
week: "Week", week: "Week | Weeks",
month: "Month", month: "Month | Months",
day: "Day", day: "Day | Days",
hour: "Hour", hour: "Hour | Hours",
minute: "Minute", minute: "Minute | Minutes",
failures_24_hours: "Failures last 24 hours", failures_24_hours: "Failures last 24 hours",
no_services: "You currently don't have any services!", no_services: "You currently don't have any services!",
theme: "Theme", theme: "Theme",

View File

@ -51,11 +51,11 @@ const french = {
service_offline_time: "Le service a été hors ligne pour", service_offline_time: "Le service a été hors ligne pour",
days_ago: "Il y a jours", days_ago: "Il y a jours",
today: "Aujourd'hui", today: "Aujourd'hui",
week: "Semaine", week: "Semaine | Semaines",
month: "Mois", month: "Mois",
day: "Jour", day: "Jour | Jours",
hour: "Heure", hour: "Heure | Heures",
minute: "Minute", minute: "Minute | Minutes",
failures_24_hours: "Les échecs durent 24 heures", failures_24_hours: "Les échecs durent 24 heures",
no_services: "Vous n'avez actuellement aucun service !", no_services: "Vous n'avez actuellement aucun service !",
theme: "Thème", theme: "Thème",
@ -109,7 +109,7 @@ const french = {
notify_before: "Avertir avant", notify_before: "Avertir avant",
message_create: "Créer une annonce", message_create: "Créer une annonce",
message_edit: "Modifier l'annonce", message_edit: "Modifier l'annonce",
minutes: "Procès-Verbal", minutes: "Minutes",
hours: "Heures", hours: "Heures",
days: "Jours", days: "Jours",
user_create: "Créer un utilisateur", user_create: "Créer un utilisateur",

View File

@ -51,11 +51,11 @@ const german = {
service_offline_time: "Dienst war offline für", service_offline_time: "Dienst war offline für",
days_ago: "Tage vergangen", days_ago: "Tage vergangen",
today: "Heute", today: "Heute",
week: "Woche", week: "Woche | Wochen",
month: "Monat", month: "Monat | Monate",
day: "Tag", day: "Tag | Tage",
hour: "Stunde", hour: "Stunde | Stunden",
minute: "Minute", minute: "Minute | Minuten",
failures_24_hours: "Ausfälle letzte 24 Stunden", failures_24_hours: "Ausfälle letzte 24 Stunden",
no_services: "Sie haben derzeit keine Dienste!", no_services: "Sie haben derzeit keine Dienste!",
theme: "Thema", theme: "Thema",

View File

@ -51,10 +51,10 @@ const italian = {
service_offline_time: "Il servizio è stato offline per", service_offline_time: "Il servizio è stato offline per",
days_ago: "Giorni fa", days_ago: "Giorni fa",
today: "Oggi", today: "Oggi",
week: "Settimana", week: "Settimana | Settimane",
month: "Mese", month: "Mese | Mesi",
day: "Giorno", day: "Giorno | Giorni",
hour: "Ora", hour: "Ora | Ore",
minute: "Minuti", minute: "Minuti",
failures_24_hours: "Errori nelle ultime 24 ore", failures_24_hours: "Errori nelle ultime 24 ore",
no_services: "Al momento non hai alcun servizio!", no_services: "Al momento non hai alcun servizio!",

View File

@ -51,11 +51,11 @@ const japanese = {
service_offline_time: "のサービスがオフラインになりました", service_offline_time: "のサービスがオフラインになりました",
days_ago: "日前", days_ago: "日前",
today: "今日", today: "今日",
week: "週数", week: "週数 | 週",
month: "月", month: "月 | ヶ月",
day: "日", day: "日 | 日数",
hour: "アワー", hour: "アワー | 時間",
minute: "分", minute: "分 | 議事録",
failures_24_hours: "過去 24 時間の障害", failures_24_hours: "過去 24 時間の障害",
no_services: "現在、サービスをお持ちになりません。", no_services: "現在、サービスをお持ちになりません。",
theme: "テーマ", theme: "テーマ",

View File

@ -55,7 +55,7 @@ const korean = {
month: "월", month: "월",
day: "일", day: "일",
hour: "시간", hour: "시간",
minute: "분", minute: "분 | 의사록",
failures_24_hours: "지난 24시간 동안 장애 발생", failures_24_hours: "지난 24시간 동안 장애 발생",
no_services: "현재 서비스가 없습니다!", no_services: "현재 서비스가 없습니다!",
theme: "테마", theme: "테마",

View File

@ -1,12 +1,12 @@
const russian = { const russian = {
settings: "Настройки", settings: "Настройки",
dashboard: "Панель управления", dashboard: "Панель",
services: "служб", services: "Сервисы",
service: "обслуживания", service: "Сервис",
failures: "Сбои", failures: "Сбои",
users: "Пользователи", users: "Пользователи",
login: "Войти", login: "Войти",
logout: "Выход из системы", logout: "Выход",
online: "Онлайн", online: "Онлайн",
offline: "Оффлайн", offline: "Оффлайн",
configs: "Конфигурация", configs: "Конфигурация",
@ -22,42 +22,42 @@ const russian = {
regen_api: "Регенерация ключей API", regen_api: "Регенерация ключей API",
regen_desc: "API Secret используется для чтения создания обновлений и удаления маршрутов. Вы можете регенерировать ключи API, если вам нужно.", regen_desc: "API Secret используется для чтения создания обновлений и удаления маршрутов. Вы можете регенерировать ключи API, если вам нужно.",
visibility: "Видимость", visibility: "Видимость",
group: "Группы", group: "Группа",
group_create: "Создать группу", group_create: "Создать группу",
group_update: "Обновить группу", group_update: "Обновить группу",
group_public_desc: "Показать групповые услуги публике", group_public_desc: "Показавать группу публично всем",
groups: "Группы", groups: "Группы",
no_group: "Нет группы", no_group: "Нет группы",
public: "Общественный", public: "Публичный",
private: "Частные", private: "Приватный",
announcements: "Объявления", announcements: "Объявления",
notifiers: "Уведомлятели", notifiers: "Способы уведомлений",
logs: "Журналы", logs: "Журналы",
help: "Помогите", help: "Помощь",
type: "Тип", type: "Тип",
edit: "Редактировать", edit: "Редактировать",
update: "Обновить", update: "Обновить",
create: "Создайте", create: "Создать",
view: "Посмотреть", view: "Посмотреть",
save: "Сохранить", save: "Сохранить",
title: "Название", title: "Название",
status: "положению", status: "Статус",
begins: "Начинается", begins: "Начало",
total_services: "Всего услуг", total_services: "Всего сервисов",
online_services: "Онлайн-сервисы", online_services: "Онлайн-сервисы",
request_timeout: "Тайм-аут запроса", request_timeout: "Тайм-аут запроса",
service_never_online: "Сервис никогда не был в сети", service_never_online: "Сервис никогда не был в сети",
service_online_check: "Проверено онлайн", service_online_check: "Проверено онлайн",
service_offline_time: "Служба была отключена для", service_offline_time: "Сервис был отключен для",
days_ago: "Дней назад", days_ago: "Дней назад",
today: "Сегодня", today: "Сегодня",
week: "Недели", week: "Недели",
month: "Месяц", month: "Месяц | Месяцы",
day: "День", day: "День | Дней",
hour: "Час", hour: "Час | Часов",
minute: "Минута", minute: "Минута | Минуты",
failures_24_hours: "Сбои за 24 часа", failures_24_hours: "Сбои за 24 часа",
no_services: "В настоящее время у вас нет услуг!", no_services: "В настоящее время у вас нет сервисов!",
theme: "Тема", theme: "Тема",
cache: "Кэш", cache: "Кэш",
authentication: "Проверка подлинности", authentication: "Проверка подлинности",
@ -76,20 +76,20 @@ const russian = {
db_password: "Пароль базы данных", db_password: "Пароль базы данных",
db_database: "Имя базы данных", db_database: "Имя базы данных",
send_reports: "Отправка отчетов об ошибках", send_reports: "Отправка отчетов об ошибках",
send_reports_desc: "Отправить ошибки в Statping для отладки", send_reports_desc: "Отправлять ошибки в Statping для отладки",
project_name: "Имя страницы состояния", project_name: "Имя страницы состояния",
description: "Описание", description: "Описание",
domain: "Домен", domain: "Домен",
enable_cdn: "Включить CDN", enable_cdn: "Включить CDN",
newsletter: "Информационный бюллетень", newsletter: "Рассылка новостей",
newsletter_note: "Мы отправим вам только сообщение по электронной почте для серьезных изменений", newsletter_note: "Мы отправим вам электронное письмо только в случае серьезных изменений",
loading: "Загрузка", loading: "Загрузка",
save_settings: "Сохранить настройки", save_settings: "Сохранить настройки",
average_response: "Средний ответ", average_response: "Средний ответ",
last_uptime: "Время безотказной работы", last_uptime: "Время безотказной работы",
sign_in: "Войти", sign_in: "Войти",
last_login: "Последний вход", last_login: "Последний вход",
admin: "Администратор", admin: "Админ",
user: "Пользователя", user: "Пользователя",
failed: "Не удалось", failed: "Не удалось",
wrong_login: "Неверное имя пользователя или пароль", wrong_login: "Неверное имя пользователя или пароль",
@ -99,7 +99,7 @@ const russian = {
assets_btn: "Включить локальные ресурсы", assets_btn: "Включить локальные ресурсы",
assets_loading: "Создание компонентов", assets_loading: "Создание компонентов",
assets_dir: "Каталог активов", assets_dir: "Каталог активов",
footer: "Подколонтитул", footer: "Нижний колонтитул (footer)",
footer_notes: "Вы можете использовать HTML-теги в нижнем колонтитуле", footer_notes: "Вы можете использовать HTML-теги в нижнем колонтитуле",
global_announcement: "Глобальное объявление", global_announcement: "Глобальное объявление",
announcement_date: "Диапазон дат объявления", announcement_date: "Диапазон дат объявления",
@ -114,29 +114,29 @@ const russian = {
days: "Дни", days: "Дни",
user_create: "Создать пользователя", user_create: "Создать пользователя",
user_update: "Обновить пользователя", user_update: "Обновить пользователя",
administrator: "Администратора", administrator: "Администратор",
checkins: "Чеккинс", checkins: "Проверки",
incidents: "Инциденты", incidents: "Инциденты",
service_info: "Информация о сервисе", service_info: "Информация о сервисе",
service_name: "Имя службы", service_name: "Имя сервиса",
service_type: "Тип услуги", service_type: "Тип сервиса",
permalink: "URL-адрес Постоянной ссылки", permalink: "URL-адрес Постоянной ссылки",
service_public: "Государственная служба", service_public: "Видимость публично",
check_interval: "Интервал проверки", check_interval: "Интервал проверки",
service_endpoint: "Конечная точка службы", service_endpoint: "Адрес проверяемого хоста",
service_check: "Тип проверки службы", service_check: "Тип проверки",
service_timeout: "Тайм-аут запроса", service_timeout: "Тайм-аут запроса",
expected_resp: "Ожидаемый ответ", expected_resp: "Ожидаемый ответ",
expected_code: "Код ожидаемого состояния", expected_code: "Код ожидаемого состояния",
follow_redir: "Следуйте за перенаправленными", follow_redir: "Вкл. следование по редиректам",
verify_ssl: "Проверить SSL", verify_ssl: "Проверять SSL",
tls_cert: "Использовать сертификат TLS", tls_cert: "Использовать сертификат TLS",
notification_opts: "Параметры уведомления", notification_opts: "Параметры уведомления",
notifications_enable: "Включить уведомления", notifications_enable: "Включить уведомления",
notify_after: "Уведомлять после сбоев", notify_after: "Уведомлять после сбоев",
notify_all: "Уведомлять обо всех изменениях", notify_all: "Уведомлять обо всех изменениях",
service_update: "Обновить службу", service_update: "Обновить сервис",
service_create: "Создать службу" service_create: "Создать сервис"
} }
export default russian export default russian

View File

@ -51,11 +51,11 @@ const spanish = {
service_offline_time: "El servicio ha estado desconectado para", service_offline_time: "El servicio ha estado desconectado para",
days_ago: "Hace días", days_ago: "Hace días",
today: "Hoy", today: "Hoy",
week: "Semana", week: "Semana | Semanas",
month: "Mes", month: "Mes | Meses",
day: "Día", day: "Día | Días",
hour: "Hora", hour: "Hora | Horas",
minute: "Minuto", minute: "Minuto | Minutos",
failures_24_hours: "Fallos de las últimas 24 horas", failures_24_hours: "Fallos de las últimas 24 horas",
no_services: "¡Actualmente no tienes ningún servicio!", no_services: "¡Actualmente no tienes ningún servicio!",
theme: "Tema", theme: "Tema",

View File

@ -36,7 +36,6 @@ func InitNotifiers() {
Webhook, Webhook,
Mobile, Mobile,
Pushover, Pushover,
statpingMailer,
Gotify, Gotify,
AmazonSNS, AmazonSNS,
) )

View File

@ -1,106 +0,0 @@
package notifiers
import (
"bytes"
"encoding/json"
"github.com/statping-ng/statping-ng/types/core"
"github.com/statping-ng/statping-ng/types/failures"
"github.com/statping-ng/statping-ng/types/notifications"
"github.com/statping-ng/statping-ng/types/notifier"
"github.com/statping-ng/statping-ng/types/services"
"github.com/statping-ng/statping-ng/utils"
"time"
)
var _ notifier.Notifier = (*statpingEmailer)(nil)
const (
statpingEmailerName = "statping_emailer"
statpingEmailerHost = "https://news.statping.com"
)
type statpingEmailer struct {
*notifications.Notification
}
func (s *statpingEmailer) Select() *notifications.Notification {
return s.Notification
}
func (s *statpingEmailer) Valid(values notifications.Values) error {
return nil
}
var statpingMailer = &statpingEmailer{&notifications.Notification{
Method: statpingEmailerName,
Title: "Email",
Description: "Send an email when a service becomes offline or back online using Statping's email service. You will need to verify your email address.",
Author: "Hunter Long",
AuthorUrl: "https://github.com/hunterlong",
Delay: time.Duration(10 * time.Second),
Icon: "fas envelope-square",
Limits: 60,
Form: []notifications.NotificationForm{{
Type: "email",
Title: "Send to Email Address",
Placeholder: "info@statping.com",
DbField: "Host",
Required: true,
}}},
}
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
func (s *statpingEmailer) sendStatpingEmail(msg statpingMail) (string, error) {
data, _ := json.Marshal(msg)
resp, _, err := utils.HttpRequest(statpingEmailerHost+"/notifier", "POST", "application/json", nil, bytes.NewBuffer(data), time.Duration(10*time.Second), true, nil)
if err != nil {
return "", err
}
return string(resp), nil
}
func (s *statpingEmailer) OnTest() (string, error) {
return "", nil
}
type statpingMail struct {
Email string `json:"email"`
Core core.Core `json:"core,omitempty"`
Service services.Service `json:"service,omitempty"`
Failure failures.Failure `json:"failure,omitempty"`
}
// OnFailure will trigger failing service
func (s *statpingEmailer) OnFailure(srv services.Service, f failures.Failure) (string, error) {
ee := statpingMail{
Email: s.Host.String,
Core: *core.App,
Service: srv,
Failure: f,
}
return s.sendStatpingEmail(ee)
}
// OnSuccess will trigger successful service
func (s *statpingEmailer) OnSuccess(srv services.Service) (string, error) {
ee := statpingMail{
Email: s.Host.String,
Core: *core.App,
Service: srv,
Failure: failures.Failure{},
}
return s.sendStatpingEmail(ee)
}
// OnSave will trigger when this notifier is saved
func (s *statpingEmailer) OnSave() (string, error) {
ee := statpingMail{
Email: s.Host.String,
Core: *core.App,
Service: services.Service{},
Failure: failures.Failure{},
}
out, err := s.sendStatpingEmail(ee)
log.Println("statping emailer response", out)
return out, err
}

View File

@ -1,70 +0,0 @@
package notifiers
import (
"github.com/statping-ng/statping-ng/database"
"github.com/statping-ng/statping-ng/types/core"
"github.com/statping-ng/statping-ng/types/failures"
"github.com/statping-ng/statping-ng/types/notifications"
"github.com/statping-ng/statping-ng/types/null"
"github.com/statping-ng/statping-ng/types/services"
"github.com/statping-ng/statping-ng/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)
var (
testEmail string
)
func TestStatpingEmailerNotifier(t *testing.T) {
err := utils.InitLogs()
require.Nil(t, err)
t.Parallel()
db, err := database.OpenTester()
require.Nil(t, err)
db.AutoMigrate(&notifications.Notification{})
notifications.SetDB(db)
core.Example()
testEmail = utils.Params.GetString("TEST_EMAIL")
statpingMailer.Host = null.NewNullString(testEmail)
statpingMailer.Enabled = null.NewNullBool(true)
if testEmail == "" {
t.Log("statping email notifier testing skipped, missing TEST_EMAIL environment variable")
t.SkipNow()
}
t.Run("Load statping emailer", func(t *testing.T) {
statpingMailer.Host = null.NewNullString(testEmail)
statpingMailer.Delay = time.Duration(100 * time.Millisecond)
statpingMailer.Limits = 3
Add(statpingMailer)
assert.Equal(t, "Hunter Long", statpingMailer.Author)
assert.Equal(t, testEmail, statpingMailer.Host.String)
})
t.Run("statping emailer Within Limits", func(t *testing.T) {
ok := statpingMailer.CanSend()
assert.True(t, ok)
})
t.Run("statping emailer OnSave", func(t *testing.T) {
_, err := statpingMailer.OnSave()
assert.Nil(t, err)
})
t.Run("statping emailer OnFailure", func(t *testing.T) {
_, err := statpingMailer.OnFailure(services.Example(false), failures.Example())
assert.Nil(t, err)
})
t.Run("statping emailer OnSuccess", func(t *testing.T) {
_, err := statpingMailer.OnSuccess(services.Example(true))
assert.Nil(t, err)
})
}

View File

@ -23,9 +23,12 @@ func sendSuccess(s *Service) {
return return
} }
s.notifyAfterCount = 0
if s.prevOnline == s.Online { if s.prevOnline == s.Online {
return return
} }
s.prevOnline = true
for _, n := range allNotifiers { for _, n := range allNotifiers {
notif := n.Select() notif := n.Select()
@ -42,9 +45,6 @@ func sendSuccess(s *Service) {
notif.LastSent = utils.Now() notif.LastSent = utils.Now()
} }
} }
s.prevOnline = true
s.notifyAfterCount++
} }
func sendFailure(s *Service, f *failures.Failure) { func sendFailure(s *Service, f *failures.Failure) {
@ -63,6 +63,8 @@ func sendFailure(s *Service, f *failures.Failure) {
} }
} }
s.prevOnline = false
for _, n := range allNotifiers { for _, n := range allNotifiers {
notif := n.Select() notif := n.Select()
if notif.CanSend() { if notif.CanSend() {
@ -78,9 +80,6 @@ func sendFailure(s *Service, f *failures.Failure) {
notif.LastSent = utils.Now() notif.LastSent = utils.Now()
} }
} }
s.prevOnline = false
s.notifyAfterCount++
} }
func logMessage(method string, msg string, error error, onSuccesss bool, serviceId int64) { func logMessage(method string, msg string, error error, onSuccesss bool, serviceId int64) {

View File

@ -1 +1 @@
0.90.78 0.90.79