From 8ee4b844fdc238e8c140904e0faf9d06340c76d4 Mon Sep 17 00:00:00 2001 From: Nelson Chan Date: Tue, 28 Mar 2023 11:40:19 +0800 Subject: [PATCH 01/26] Fix: Pass rejectUnauthorized to Socks Proxy --- server/proxy.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/proxy.js b/server/proxy.js index 2f2b57694..660b9b411 100644 --- a/server/proxy.js +++ b/server/proxy.js @@ -132,6 +132,9 @@ class Proxy { ...httpAgentOptions, ...httpsAgentOptions, ...proxyOptions, + tls: { + rejectUnauthorized: httpsAgentOptions.rejectUnauthorized, + }, }); httpAgent = agent; From e575d41f7dae35e079ef98bfde9377f756038336 Mon Sep 17 00:00:00 2001 From: AmadeusGraves Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 02/26] Translated using Weblate (Spanish) Currently translated at 99.2% (703 of 708 strings) Co-authored-by: AmadeusGraves Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/es-ES.json | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/lang/es-ES.json b/src/lang/es-ES.json index 6065bdb3b..3d051bae7 100644 --- a/src/lang/es-ES.json +++ b/src/lang/es-ES.json @@ -696,5 +696,47 @@ "Bark Endpoint": "Endpoint Bark", "WebHookUrl": "WebHookUrl", "High": "Alto", - "alertaApiEndpoint": "Endpoint API" + "alertaApiEndpoint": "Endpoint API", + "Body Encoding": "Codificación del cuerpo", + "Expiry date": "Fecha de expiración", + "Expiry": "Expiración", + "API Keys": "Claves API", + "Key Added": "Clave añadida", + "Add Another": "Añadir otro", + "Continue": "Continuar", + "Don't expire": "No caduca", + "apiKey-inactive": "Inactivo", + "apiKey-expired": "Expirado", + "apiKey-active": "Activo", + "No API Keys": "No hay claves API", + "Add API Key": "Añadir clave API", + "apiKeyAddedMsg": "Su clave API ha sido añadida. Anótala, ya que no se volverá a mostrar.", + "Clone": "Clonar", + "cloneOf": "Clon de {0}", + "pagertreeDoNothing": "No hacer nada", + "pagertreeResolve": "Resolución automática", + "pagertreeCritical": "Crítico", + "pagertreeHigh": "Alto", + "pagertreeMedium": "Medio", + "pagertreeLow": "Bajo", + "pagertreeSilent": "Silencio", + "pagertreeUrgency": "Urgencia", + "pagertreeIntegrationUrl": "URL de integración", + "lunaseaTarget": "Objetivo", + "wayToGetPagerTreeIntegrationURL": "Después de crear la integración Uptime Kuma en PagerTree, copie el Endpoint. Ver todos los detalles {0}", + "Generate": "Generar", + "deleteAPIKeyMsg": "¿Está seguro de que desea eliminar esta clave API?", + "telegramMessageThreadID": "(Opcional) ID del hilo de mensajes", + "telegramMessageThreadIDDescription": "Opcional Identificador único para el hilo de mensajes de destino (asunto) del foro; solo para supergrupos de foros", + "telegramProtectContent": "Proteger Forwarding/Saving", + "telegramProtectContentDescription": "Si se activa, los mensajes del bot en Telegram estarán protegidos contra el reenvío y el guardado.", + "notificationRegional": "Regional", + "Clone Monitor": "Clonar Monitor", + "telegramSendSilently": "Enviar en silencio", + "telegramSendSilentlyDescription": "Envía el mensaje en silencio. Los usuarios recibirán una notificación sin sonido.", + "Add New Tag": "Añadir nueva etiqueta", + "lunaseaUserID": "ID Usuario", + "lunaseaDeviceID": "ID Dispositivo", + "disableAPIKeyMsg": "¿Está seguro de que desea desactivar esta clave API?", + "Expires": "Expira" } From 738a494dcb21abae731e057e7f6725a5af7ad216 Mon Sep 17 00:00:00 2001 From: DoyunShin Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 03/26] Translated using Weblate (Korean) Currently translated at 97.7% (692 of 708 strings) Co-authored-by: DoyunShin Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/ko-KR.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lang/ko-KR.json b/src/lang/ko-KR.json index 801ea1a5d..2a8696e00 100644 --- a/src/lang/ko-KR.json +++ b/src/lang/ko-KR.json @@ -719,5 +719,10 @@ "notificationRegional": "지역별", "Google Analytics ID": "Google Analytics ID", "Add API Key": "API 키 추가", - "apiKeyAddedMsg": "API 키가 추가되었습니다. 다시 표시되지 않을 것이므로 메모해 두세요." + "apiKeyAddedMsg": "API 키가 추가되었습니다. 다시 표시되지 않을 것이므로 메모해 두세요.", + "pagertreeCritical": "치명적인", + "apiKey-active": "사용 가능", + "lunaseaUserID": "사용자 ID", + "apiKey-expired": "만료됨", + "Expires": "만료일" } From 2ac1abd424e41a6d97e15f9e39d9f9e5a68d4148 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 04/26] Translated using Weblate (Russian) Currently translated at 100.0% (708 of 708 strings) Co-authored-by: Alex Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/ru-RU.json | 156 ++++++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 55 deletions(-) diff --git a/src/lang/ru-RU.json b/src/lang/ru-RU.json index 3299d5ae9..1bd3f26ad 100644 --- a/src/lang/ru-RU.json +++ b/src/lang/ru-RU.json @@ -8,7 +8,7 @@ "acceptedStatusCodesDescription": "Выберите коды статусов для определения доступности сервиса.", "passwordNotMatchMsg": "Повтор пароля не совпадает.", "notificationDescription": "Привяжите уведомления к мониторам.", - "keywordDescription": "Поиск слова в чистом HTML или в JSON-ответе (чувствительно к регистру)", + "keywordDescription": "Поиск слова в чистом HTML или в JSON-ответе (чувствительно к регистру).", "pauseDashboardHome": "Пауза", "deleteMonitorMsg": "Вы действительно хотите удалить данный монитор?", "deleteNotificationMsg": "Вы действительно хотите удалить это уведомление для всех мониторов?", @@ -45,9 +45,9 @@ "Uptime": "Аптайм", "Cert Exp.": "Сертификат истекает.", "day": "день | дней", - "-day": " дней", + "-day": "-дней", "hour": "час", - "-hour": " часа", + "-hour": "-часа", "Response": "Ответ", "Ping": "Пинг", "Monitor Type": "Тип монитора", @@ -124,12 +124,12 @@ "Also apply to existing monitors": "Применить к существующим мониторам", "Export": "Экспорт", "Import": "Импорт", - "backupDescription": "Вы можете сохранить резервную копию всех мониторов и уведомлений в виде JSON-файла", - "backupDescription2": "P.S. История и события сохранены не будут", - "backupDescription3": "Важные данные, такие как токены уведомлений, добавляются при экспорте, поэтому храните файлы в безопасном месте", + "backupDescription": "Вы можете сохранить резервную копию всех мониторов и уведомлений в виде JSON-файла.", + "backupDescription2": "Важно: история и события сохранены не будут.", + "backupDescription3": "Важные данные, такие как токены уведомлений, добавляются при экспорте, поэтому храните файлы в безопасном месте.", "alertNoFile": "Выберите файл для импорта.", "alertWrongFileType": "Выберите JSON-файл.", - "twoFAVerifyLabel": "Пожалуйста, введите свой токен, чтобы проверить работу 2FA", + "twoFAVerifyLabel": "Пожалуйста, введите свой токен, чтобы проверить работу 2FA:", "tokenValidSettingsMsg": "Токен действителен! Теперь вы можете сохранить настройки 2FA.", "confirmEnableTwoFAMsg": "Вы действительно хотите включить 2FA?", "confirmDisableTwoFAMsg": "Вы действительно хотите выключить 2FA?", @@ -444,11 +444,11 @@ "The slug is already taken. Please choose another slug.": "The slug is already taken. Please choose another slug.", "Page Not Found": "Страница не найдена", "wayToGetCloudflaredURL": "(Скачать cloudflared с {0})", - "cloudflareWebsite": "Cloudflare Website", + "cloudflareWebsite": "Веб-сайт Cloudflare", "Message:": "Сообщение:", - "Don't know how to get the token? Please read the guide:": "Don't know how to get the token? Please read the guide:", - "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.", - "HTTP Headers": "HTTP заголовки", + "Don't know how to get the token? Please read the guide:": "Не знаете, как получить токен? Пожалуйста, прочтите руководство:", + "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Текущее соединение может быть потеряно, если вы в данный момент подключаетесь через туннель Cloudflare. Вы уверены, что хотите это остановить? Введите свой текущий пароль, чтобы подтвердить это.", + "HTTP Headers": "заголовки HTTP", "Trust Proxy": "Доверять прокси", "Other Software": "Другое программное обеспечение", "For example: nginx, Apache and Traefik.": "К примеру: nginx, Apache и Traefik.", @@ -463,13 +463,13 @@ "Proxy": "Прокси", "Date Created": "Дата создания", "HomeAssistant": "Home Assistant", - "onebotHttpAddress": "OneBot HTTP Address", - "onebotMessageType": "OneBot Message Type", + "onebotHttpAddress": "HTTP-адрес OneBot", + "onebotMessageType": "Тип сообщения OneBot", "onebotGroupMessage": "Группа", "onebotPrivateMessage": "Private", "onebotUserOrGroupId": "ID группы или пользователя", "onebotSafetyTips": "В целях безопасности необходимо установить токен доступа", - "PushDeer Key": "PushDeer Key", + "PushDeer Key": "ключ PushDeer", "Footer Text": "Текст нижнего колонтитула", "Show Powered By": "Показывать на чем создано", "Domain Names": "Доменные имена", @@ -488,40 +488,40 @@ "From Name/Number": "Имя/номер отправителя", "Leave blank to use a shared sender number.": "Оставьте пустым, чтобы использовать общий номер отправителя.", "Octopush API Version": "Версия API Octopush", - "Legacy Octopush-DM": "Legacy Octopush-DM", - "endpoint": "endpoint", + "Legacy Octopush-DM": "устаревший Octopush-DM", + "endpoint": "конечная точка", "octopushAPIKey": "\"API key\" из учетных данных HTTP API в панели управления", "octopushLogin": "\"Login\" из учетных данных HTTP API в панели управления", "promosmsLogin": "Логин API", "promosmsPassword": "Пароль API", - "pushoversounds pushover": "Pushover (default)", - "pushoversounds bike": "Bike", - "pushoversounds bugle": "Bugle", - "pushoversounds cashregister": "Cash Register", + "pushoversounds pushover": "Pushover (по умолчанию)", + "pushoversounds bike": "Велосипед", + "pushoversounds bugle": "Горн", + "pushoversounds cashregister": "Кассовый аппарат", "pushoversounds classical": "Classical", - "pushoversounds cosmic": "Cosmic", - "pushoversounds falling": "Falling", - "pushoversounds gamelan": "Gamelan", - "pushoversounds incoming": "Incoming", - "pushoversounds intermission": "Intermission", - "pushoversounds magic": "Magic", - "pushoversounds mechanical": "Mechanical", - "pushoversounds pianobar": "Piano Bar", - "pushoversounds siren": "Siren", - "pushoversounds spacealarm": "Space Alarm", - "pushoversounds tugboat": "Tug Boat", - "pushoversounds alien": "Alien Alarm (long)", - "pushoversounds climb": "Climb (long)", - "pushoversounds persistent": "Persistent (long)", - "pushoversounds echo": "Pushover Echo (long)", - "pushoversounds updown": "Up Down (long)", - "pushoversounds vibrate": "Vibrate Only", - "pushoversounds none": "None (silent)", - "pushyAPIKey": "Secret API Key", + "pushoversounds cosmic": "Космический", + "pushoversounds falling": "Падающий", + "pushoversounds gamelan": "Гамелан", + "pushoversounds incoming": "Входящий", + "pushoversounds intermission": "Антракт", + "pushoversounds magic": "Магия", + "pushoversounds mechanical": "Механический", + "pushoversounds pianobar": "Пиано-бар", + "pushoversounds siren": "Сирена", + "pushoversounds spacealarm": "Космическая сигнализация", + "pushoversounds tugboat": "Буксирное судно", + "pushoversounds alien": "Инопланетная тревога (долгое)", + "pushoversounds climb": "Подъем (долгое)", + "pushoversounds persistent": "Стойкий (долгое)", + "pushoversounds echo": "Pushover Эхо (долгое)", + "pushoversounds updown": "Вверх вниз (долгое)", + "pushoversounds vibrate": "Только вибрация", + "pushoversounds none": "Нет (тихо)", + "pushyAPIKey": "Секретный ключ API", "pushyToken": "Токен устройства", "Using a Reverse Proxy?": "Используете обратный прокси?", "Check how to config it for WebSocket": "Проверьте, как настроить его для WebSocket", - "Steam Game Server": "Steam Game Server", + "Steam Game Server": "Игровой сервер Steam", "Most likely causes:": "Наиболее вероятные причины:", "The resource is no longer available.": "Ресурс больше не доступен.", "There might be a typing error in the address.": "В адресе может быть опечатка.", @@ -536,24 +536,24 @@ "certificationExpiryDescription": "HTTPS Мониторы инициируют уведомление, когда срок действия сертификата TLS истечет:", "Setup Docker Host": "Настроить Docker Host", "Connection Type": "Тип соединения", - "Docker Daemon": "Docker Daemon", - "deleteDockerHostMsg": "Are you sure want to delete this docker host for all monitors?", - "socket": "Socket", + "Docker Daemon": "Демон Docker", + "deleteDockerHostMsg": "Вы уверены, что хотите удалить этот узел docker для всех мониторов?", + "socket": "Сокет", "tcp": "TCP / HTTP", "Docker Container": "Docker контейнер", "Container Name / ID": "Название контейнера / ID", - "Docker Host": "Docker Host", - "Docker Hosts": "Docker Hosts", - "ntfy Topic": "ntfy Topic", + "Docker Host": "Хост Docker", + "Docker Hosts": "Хосты Docker", + "ntfy Topic": "тема ntfy", "Domain": "Домен", - "Workstation": "Workstation", + "Workstation": "Рабочая станция", "disableCloudflaredNoAuthMsg": "Вы находитесь в режиме без авторизации, пароль не требуется.", "trustProxyDescription": "Доверять заголовкам 'X-Forwarded-*'. Если вы хотите получить правильный IP-адрес клиента, а ваш Uptime Kuma находится под Nginx или Apache, вам следует включить этот параметр.", "wayToGetLineNotifyToken": "Вы можете получить токен доступа в {0}", "Examples": "Примеры", - "Home Assistant URL": "Home Assistant URL", + "Home Assistant URL": "URL-адрес Home Assistant", "Long-Lived Access Token": "Токен доступа с длительным сроком службы", - "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ", + "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Токен доступа с длительным сроком действия можно создать, нажав на имя вашего профиля (внизу слева) и прокрутив его вниз, затем нажмите Создать токен. ", "Notification Service": "Служба уведомлений", "default: notify all devices": "по стандарту: уведомлять все устройства", "A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Список служб уведомлений можно найти в Home Assistant в разделе \"Инструменты разработчика > Службы\", выполнив поиск по слову \"уведомление\", чтобы найти название вашего устройства/телефона.", @@ -618,7 +618,7 @@ "Custom CSS": "Пользовательские CSS", "weekdayShortTue": "Вт", "dayOfWeek": "День недели", - "confirmDeleteTagMsg": "Вы уверены, что хотите удалить этот тег? Мониторы, связанные с этим тегом не будут удалены.", + "confirmDeleteTagMsg": "Вы уверены, что хотите удалить этот тег? Мониторы, связанные с этим тегом не будут удалены.", "loadingError": "Невозможно получить данные, пожалуйста попробуйте позже.", "Packet Size": "Размер пакета", "warningTimezone": "Используется часовой пояс сервера", @@ -676,10 +676,10 @@ "Integration URL": "URL интеграции", "do nothing": "ничего не делать", "smseagleTo": "Номер(а) телефона", - "smseagleGroup": "Имена групп в телефонной книжке", + "smseagleGroup": "Название(я) групп телефонной книги", "smseagleContact": "Имена контактов из телефонной книжки", "smseagleRecipientType": "Тип получателя", - "smseagleRecipient": "Получатель (через запятую, если несколько)", + "smseagleRecipient": "Получатель(я) (через запятую, если необходимо указать несколько)", "smseagleToken": "Токен доступа API", "smseagleUrl": "URL вашего SMSEagle устройства", "smseagleEncoding": "Отправить в юникоде", @@ -687,9 +687,9 @@ "Server Address": "Адрес сервера", "Learn More": "Узнать больше", "topicExplanation": "MQTT топик для мониторинга", - "Guild ID": "Guild ID", + "Guild ID": "Идентификатор гильдии", "Kook": "Kook", - "wayToGetKookBotToken": "Создайте приложение и получите токен вашего бота тут {0}.", + "wayToGetKookBotToken": "Создайте приложение и получите токен бота по адресу {0}", "Resend Notification if Down X times consecutively": "Повторная отправка уведомления при падении несколько раз", "telegramProtectContent": "Запретить пересылку/сохранение", "telegramProtectContentDescription": "Если включено, сообщения бота в Telegram будут запрещены для пересылки и сохранения.", @@ -700,5 +700,51 @@ "Clone": "Копия", "cloneOf": "Копия {0}", "notificationRegional": "Региональный", - "Add New Tag": "Добавить тег" + "Add New Tag": "Добавить тег", + "Body Encoding": "Тип содержимого запроса.(JSON or XML)", + "Strategy": "Стратегия", + "Free Mobile User Identifier": "Бесплатный идентификатор мобильного пользователя", + "Auto resolve or acknowledged": "Автоматическое разрешение или подтверждение", + "auto acknowledged": "автоматическое подтверждение", + "auto resolve": "автоматическое разрешение", + "API Keys": "Ключи API", + "Expiry": "Истекает", + "Expiry date": "Дата окончания действия", + "Don't expire": "Не истекает", + "Continue": "Продолжать", + "Add Another": "Добавьте еще один", + "Key Added": "Ключ добавлен", + "Add API Key": "Добавить ключ API", + "No API Keys": "Нет API ключей", + "apiKey-active": "Активный", + "apiKey-expired": "Истёк", + "apiKey-inactive": "Неактивный", + "Expires": "Истекает", + "disableAPIKeyMsg": "Вы уверены, что хотите отключить этот ключ?", + "Generate": "Создать", + "pagertreeResolve": "Автоматическое разрешение", + "pagertreeDoNothing": "ничего не делать", + "lunaseaTarget": "Цель", + "lunaseaDeviceID": "Идентификатор устройства", + "lunaseaUserID": "Идентификатор пользователя", + "Lowcost": "Низкая стоимость", + "pagertreeIntegrationUrl": "URL-адрес интеграции", + "pagertreeUrgency": "Срочность", + "pagertreeSilent": "Тихий", + "pagertreeLow": "Низкий", + "pagertreeMedium": "Средний", + "pagertreeHigh": "Высокий", + "pagertreeCritical": "Критический", + "high": "высокий", + "promosmsAllowLongSMS": "Разрешить длинные SMS-сообщения", + "Economy": "Экономия", + "wayToGetPagerDutyKey": "Вы можете получить это, перейдя в службу -> Каталог служб -> (Выберите службу) -> Интеграции -> Добавить интеграцию. Здесь вы можете выполнить поиск по \"Events API V2\". Дополнительная информация {0}", + "apiKeyAddedMsg": "Ваш API ключ был добавлен. Пожалуйста, запишите это, так как оно больше не будет показан.", + "deleteAPIKeyMsg": "Вы уверены, что хотите удалить этот ключ?", + "wayToGetPagerTreeIntegrationURL": "После создания интеграции Uptime Kuma в PagerTree, скопируйте конечную точку. Смотрите полную информацию {0}", + "telegramMessageThreadIDDescription": "Необязательный уникальный идентификатор для цепочки сообщений (темы) форума; только для форумов-супергрупп", + "grpcMethodDescription": "Название метода - преобразовать в формат cammelCase, такой как sayHello, check и т.д.", + "Proto Service Name": "название службы Proto", + "Proto Method": "Метод Proto", + "Proto Content": "Содержание Proto" } From 29be8d3ddb1649e7a98f6eda1f95998c9b8cc5a6 Mon Sep 17 00:00:00 2001 From: ilya12077 Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 05/26] Translated using Weblate (Russian) Currently translated at 100.0% (708 of 708 strings) Co-authored-by: ilya12077 Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/ru-RU.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lang/ru-RU.json b/src/lang/ru-RU.json index 1bd3f26ad..7ba26cce0 100644 --- a/src/lang/ru-RU.json +++ b/src/lang/ru-RU.json @@ -746,5 +746,6 @@ "grpcMethodDescription": "Название метода - преобразовать в формат cammelCase, такой как sayHello, check и т.д.", "Proto Service Name": "название службы Proto", "Proto Method": "Метод Proto", - "Proto Content": "Содержание Proto" + "Proto Content": "Содержание Proto", + "telegramMessageThreadID": "(Необязательно) ID цепочки сообщений" } From edd1c6b6628d242830a543a757a09f69038a9110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Petr=C3=ADk?= Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 06/26] Translated using Weblate (Slovak) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 27.2% (193 of 708 strings) Co-authored-by: Peter Petrík Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/sk.json | 114 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/src/lang/sk.json b/src/lang/sk.json index 3d4b886a4..3751cce18 100644 --- a/src/lang/sk.json +++ b/src/lang/sk.json @@ -64,7 +64,7 @@ "Up": "Dostupné", "Down": "Nedostupné", "Unknown": "Neznáme", - "markdownSupported": "Podpora Markdown syntaxe", + "markdownSupported": "Podpora Markdown syntaxu", "Name": "Názov", "DateTime": "Dátum a čas", "Resume": "Pokračovať", @@ -81,5 +81,115 @@ "maxRedirectDescription": "Maximálny počet presmerovaní. Hodnota 0 vypne presmerovania.", "needPushEvery": "Tuto adresu by ste mali volať každých {0} sekúnd.", "pushOptionalParams": "Voliteľné parametre: {0}", - "Theme - Heartbeat Bar": "Téma - Heartbeat riadok" + "Theme - Heartbeat Bar": "Téma - Heartbeat riadok", + "Game": "Hra", + "Search Engine Visibility": "Viditeľnosť vyhľadávačmi", + "Allow indexing": "Povoliť indexovanie", + "Change Password": "Zmeniť heslo", + "Current Password": "Aktuálne heslo", + "New Password": "Nové heslo", + "Repeat New Password": "Zopakovať nové heslo", + "Update Password": "Aktualizovať heslo", + "Disable Auth": "Vypnúť autentifikáciu", + "Enable Auth": "Zapnúť autentifikáciu", + "Please use this option carefully!": "Túto možnosť používajte opatrne!", + "Logout": "Odhlásiť sa", + "Leave": "Odísť", + "I understand, please disable": "Rozumiem, vypnite to", + "Yes": "Áno", + "No": "Nie", + "Username": "Používateľské meno", + "Password": "Heslo", + "Login": "Prihlásiť sa", + "No Monitors, please": "Žiadne sledovanie, prosím", + "add one": "pridať jeden", + "Notification Type": "Typ notifikácie", + "Email": "E-mail", + "Test": "Test", + "Certificate Info": "Informácie o certifikáte", + "Resolver Server": "DNS server", + "Last Result": "Posledný výsledok", + "Repeat Password": "Zopakovať heslo", + "Import Backup": "Importovať zálohu", + "Export Backup": "Exportovať zálohu", + "Export": "Exportovať", + "Import": "Importovať", + "respTime": "Čas odozvy (ms)", + "notAvailableShort": "Nie je číslo", + "Default enabled": "Predvolene povolené", + "Create": "Vytvoriť", + "Clear Data": "Vyčistiť dáta", + "Events": "Udalosti", + "Heartbeats": "Odpovede", + "Auto Get": "Získať automaticky", + "Schedule maintenance": "Naplánovať údržbu", + "Affected Monitors": "Dotknuté sledovania", + "Pick Affected Monitors...": "Vybrať dotknuté sledovania…", + "Start of maintenance": "Začiatok údržby", + "All Status Pages": "Všetky stavové stránky", + "Select status pages...": "Vybrať stránky stavu…", + "alertNoFile": "Vyberte súbor na import.", + "alertWrongFileType": "Vyberte súbor JSON.", + "Clear all statistics": "Vymazať všetky štatistiky", + "Skip existing": "Preskočiť existujúce", + "Overwrite": "Prepísať", + "Options": "Možnosti", + "Keep both": "Ponechať obe", + "Setup 2FA": "Nastavenie 2FA", + "Disable 2FA": "Zakázať 2FA", + "2FA Settings": "Nastavenia 2FA", + "Two Factor Authentication": "Dvojfaktorová autentifikácia", + "Inactive": "Neaktívne", + "Token": "Token", + "Show URI": "Zobraziť URI", + "Tags": "Značky", + "Add New below or Select...": "Pridať novú nižšie alebo vybrať…", + "Tag with this value already exist.": "Značka s touto hodnotou už existuje.", + "color": "Farba", + "value (optional)": "hodnota (voliteľné)", + "Gray": "Šedá", + "Red": "Červená", + "Orange": "Oranžová", + "Green": "Zelená", + "Indigo": "Indigo", + "Purple": "Fialová", + "Pink": "Ružová", + "Custom": "Vlastná", + "Avg. Ping": "Priemerný ping", + "Avg. Response": "Priemerný čas odpovede", + "Entry Page": "Vstupná stránka", + "No Services": "Žiadne služby", + "All Systems Operational": "Všetky systémy funkčné", + "Partially Degraded Service": "Čiastočne zhoršená služba", + "Degraded Service": "Degradovaná služba", + "Add Group": "Pridať skupinu", + "Add a monitor": "Pridať sledovanie", + "Edit Status Page": "Upraviť stavovú stránku", + "Go to Dashboard": "Prejdite na informačný panel", + "Status Page": "Stavová stránka", + "Status Pages": "Stavové stránky", + "defaultNotificationName": "Moje {notification} upozornenie ({number})", + "here": "tu", + "Required": "Povinné", + "Post URL": "Post URL", + "Content Type": "Druh obsahu", + "webhookJsonDesc": "{0} je vhodný pre všetky moderné servery HTTP, ako napríklad Express.js", + "webhookFormDataDesc": "{multipart} je dobré pre PHP. JSON bude potrebné analyzovať pomocou {decodeFunction}", + "Generate": "Generovať", + "Discourage search engines from indexing site": "Odradiť vyhľadávacie nástroje od indexovania stránky", + "disableauth.message1": "Ste si istý, že chcete vypnúť autentifikáciu?", + "disableauth.message2": "Je navrhnutý pre scenáre, kde máte v úmysle implementovať autentifikáciu treťou stranou pred Uptime Kuma, ako je Cloudflare Access, Authelia alebo iné autentifikačné mechanizmy.", + "Confirm": "Potvrdiť", + "Remember me": "Zapamätať si ma", + "Resource Record Type": "Typ záznamu", + "Create your admin account": "Vytvorte si účet administrátora", + "Apply on all existing monitors": "Aplikujte na všetky existujúce sledovania", + "Verify Token": "Overiť token", + "Enable 2FA": "Povoliť 2FA", + "Active": "Aktívne", + "Add New Tag": "Pridať novú značku", + "Tag with this name already exist.": "Značka s týmto názvom už existuje.", + "Blue": "Modrá", + "Search...": "Hľadať…", + "statusPageNothing": "Nič tu nie je, pridajte skupinu alebo sledovanie." } From 17f038767db0961cfa9c1fde8507ff7f2e37510d Mon Sep 17 00:00:00 2001 From: Cyril59310 Date: Tue, 28 Mar 2023 18:55:26 +0000 Subject: [PATCH 07/26] Translated using Weblate (French) Currently translated at 100.0% (713 of 713 strings) Translated using Weblate (French) Currently translated at 100.0% (709 of 709 strings) Co-authored-by: Cyril59310 Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/fr-FR.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lang/fr-FR.json b/src/lang/fr-FR.json index 47f3ee252..9e725ad07 100644 --- a/src/lang/fr-FR.json +++ b/src/lang/fr-FR.json @@ -738,5 +738,10 @@ "lunaseaDeviceID": "Identifiant de l'appareil", "lunaseaUserID": "Identifiant de l'utilisateur", "Add New Tag": "Ajouter une étiquette", - "lunaseaTarget": "Cible" + "lunaseaTarget": "Cible", + "statusPageRefreshIn": "Actualisation dans : {0}", + "twilioFromNumber": "Du Nombre", + "twilioToNumber": "Au Nombre", + "twilioAccountSID": "ID du compte", + "twilioAuthToken": "Jeton d'authentification" } From cbcd2a10274e4926900f6e14d638e84e1b5e346c Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 08/26] Translated using Weblate (Russian) Currently translated at 99.8% (708 of 709 strings) Co-authored-by: Alex Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/ru-RU.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lang/ru-RU.json b/src/lang/ru-RU.json index 7ba26cce0..8e46e20d8 100644 --- a/src/lang/ru-RU.json +++ b/src/lang/ru-RU.json @@ -747,5 +747,6 @@ "Proto Service Name": "название службы Proto", "Proto Method": "Метод Proto", "Proto Content": "Содержание Proto", - "telegramMessageThreadID": "(Необязательно) ID цепочки сообщений" + "telegramMessageThreadID": "(Необязательно) ID цепочки сообщений", + "statusPageRefreshIn": "Обновлять каждые: {0}" } From 1aac15bcccd96b17d0f05832abb0165c11c8d538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taha=20=C4=B0PEK?= Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 09/26] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (709 of 709 strings) Co-authored-by: Taha İPEK Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/tr-TR.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lang/tr-TR.json b/src/lang/tr-TR.json index 78f1e08e1..3a3aeffe6 100644 --- a/src/lang/tr-TR.json +++ b/src/lang/tr-TR.json @@ -738,5 +738,6 @@ "lunaseaTarget": "Hedef", "Add New Tag": "Yeni Etiket Ekle", "lunaseaDeviceID": "Cihaz ID", - "lunaseaUserID": "Kullanıcı ID" + "lunaseaUserID": "Kullanıcı ID", + "statusPageRefreshIn": "{0} içinde yenilenecek" } From 4fb10a4e3fe0facd0c63f8c663fd830e73859626 Mon Sep 17 00:00:00 2001 From: 401Unauthorized Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 10/26] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (709 of 709 strings) Co-authored-by: 401Unauthorized Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/zh-CN.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index feb8af846..1c33ff524 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -740,5 +740,6 @@ "Add New Tag": "添加新标签", "lunaseaDeviceID": "设备ID", "lunaseaTarget": "目标", - "lunaseaUserID": "用户ID" + "lunaseaUserID": "用户ID", + "statusPageRefreshIn": "将于 {0} 后刷新" } From 3ada6fa99bdb333cd86ea95dda12c0254bff9134 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 11/26] Translated using Weblate (Chinese (Traditional, Hong Kong)) Currently translated at 96.0% (681 of 709 strings) Co-authored-by: Louis Lam Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/zh-HK.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lang/zh-HK.json b/src/lang/zh-HK.json index e3a8d5bad..b567b72f0 100644 --- a/src/lang/zh-HK.json +++ b/src/lang/zh-HK.json @@ -228,7 +228,7 @@ "smtpCC": "CC", "smtpBCC": "BCC", "Discord Webhook URL": "Discord Webhook 網址", - "wayToGetDiscordURL": "您可以前往伺服器設定 -> 整合 -> Webhook -> 新 Webhook 以取得", + "wayToGetDiscordURL": "您可以前往 伺服器設定 -> 整合 -> Webhook -> 新 Webhook 以取得", "Bot Display Name": "機器人顯示名稱", "Prefix Custom Message": "前綴自訂訊息", "Webhook URL": "Webhook 網址", @@ -706,5 +706,8 @@ "Add New Tag": "加新標籤", "Economy": "經濟", "Lowcost": "平價", - "high": "高價" + "high": "高價", + "statusPageRefreshIn": "將於 {0} 後重新整理", + "SendKey": "SendKey", + "SMSManager API Docs": "SMSManager API 文件 " } From f0f7645c57e09b57c89afafb618b2e730fff93c1 Mon Sep 17 00:00:00 2001 From: Mirinek Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 12/26] Translated using Weblate (Czech) Currently translated at 100.0% (709 of 709 strings) Co-authored-by: Mirinek Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/cs-CZ.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lang/cs-CZ.json b/src/lang/cs-CZ.json index 2b9953288..44a6ac8a8 100644 --- a/src/lang/cs-CZ.json +++ b/src/lang/cs-CZ.json @@ -738,5 +738,6 @@ "Add New Tag": "Přidat nový štítek", "lunaseaTarget": "Cíl", "lunaseaDeviceID": "ID zařízení", - "lunaseaUserID": "ID uživatele" + "lunaseaUserID": "ID uživatele", + "statusPageRefreshIn": "Obnovení za: {0}" } From ebd42444d1adede0d11f6a19f5cab9a3b13c1e4d Mon Sep 17 00:00:00 2001 From: Alex Javadi <15309978+aljvdi@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 13/26] Translated using Weblate (Persian) Currently translated at 100.0% (713 of 713 strings) Translated using Weblate (Persian) Currently translated at 100.0% (713 of 713 strings) Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com> Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/fa.json | 577 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 546 insertions(+), 31 deletions(-) diff --git a/src/lang/fa.json b/src/lang/fa.json index b05d99e7b..e96923519 100644 --- a/src/lang/fa.json +++ b/src/lang/fa.json @@ -1,34 +1,34 @@ { - "languageName": "Farsi", - "checkEverySecond": "بررسی هر {0} ثانیه.", - "retryCheckEverySecond": "تکرار مجدد هر {0} ثانیه.", - "retriesDescription": "حداکثر تعداد تکرار پیش از علامت گذاری وب‌سایت بعنوان خارج از دسترس و ارسال اطلاع‌رسانی.", + "languageName": "فارسی", + "checkEverySecond": "بررسی هر {0} ثانیه", + "retryCheckEverySecond": "تکرار مجدد هر {0} ثانیه", + "retriesDescription": "حداکثر تعداد تکرار پیش از علامت گذاری وب‌سایت بعنوان خارج از دسترس و ارسال اطلاع‌رسانی", "ignoreTLSError": "بی‌خیال ارور TLS/SSL برای سایت‌های HTTPS", - "upsideDownModeDescription": "نتیجه وضعیت را برعکس کن، مثلا اگر سرویس در دسترس بود فرض کن که سرویس پایین است!", + "upsideDownModeDescription": "نتیجه وضعیت را برعکس کن، مثلا اگر سرویس در دسترس بود فرض کن که سرویس پایین است.", "maxRedirectDescription": "حداکثر تعداد ریدایرکتی که سرویس پشتیبانی کند. برای اینکه ری‌دایرکت‌ها پشتیبانی نشوند، عدد 0 را وارد کنید.", "acceptedStatusCodesDescription": "لطفا HTTP Status Code هایی که میخواهید به عنوان پاسخ موفقیت آمیز در نظر گرفته شود را انتخاب کنید.", - "passwordNotMatchMsg": "تکرار رمز عبور مطابقت ندارد!", + "passwordNotMatchMsg": "تکرار رمز عبور مطابقت ندارد.", "notificationDescription": "برای اینکه سرویس اطلاع‌رسانی کار کند، آنرا به یکی از مانیتور‌ها متصل کنید.", "keywordDescription": "در نتیجه درخواست (اهمیتی ندارد پاسخ JSON است یا HTML) بدنبال این کلمه بگرد (حساس به کوچک/بزرگ بودن حروف).", "pauseDashboardHome": "متوقف شده", "deleteMonitorMsg": "آیا از حذف این مانیتور مطمئن هستید؟", "deleteNotificationMsg": "آیا مطمئن هستید که میخواهید این سرویس اطلاع‌رسانی را برای تمامی مانیتورها حذف کنید؟", "resolverserverDescription": "سرویس CloudFlare به عنوان سرور پیش‌فرض استفاده می‌شود، شما میتوانید آنرا به هر سرور دیگری بعدا تغییر دهید.", - "rrtypeDescription": "لطفا نوع Resource Record را انتخاب کنید.", + "rrtypeDescription": "لطفا نوع Resource Record را انتخاب کنید", "pauseMonitorMsg": "آیا مطمئن هستید که میخواهید این مانیتور را متوقف کنید ؟", "enableDefaultNotificationDescription": "برای هر مانیتور جدید، این سرویس اطلاع‌رسانی به صورت پیش‌فرض فعال خواهد شد. البته که شما میتوانید به صورت دستی آنرا برای هر مانیتور به صورت جداگانه غیر فعال کنید.", "clearEventsMsg": "آیا از اینکه تمامی تاریخچه رویداد‌های این مانیتور حذف شود مطمئن هستید؟", - "clearHeartbeatsMsg": "آیا از اینکه تاریخچه تمامی Heartbeat های این مانیتور حذف شود مطمئن هستید؟ ", + "clearHeartbeatsMsg": "آیا از اینکه تاریخچه تمامی ضربان قلب های این مانیتور حذف شود مطمئن هستید؟", "confirmClearStatisticsMsg": "آیا از حذف تمامی آمار و ارقام مطمئن هستید؟", - "importHandleDescription": " اگر که میخواهید بیخیال مانیتورها و یا سرویس‌های اطلاع‌رسانی که با نام مشابه از قبل موجود هستند شوید، گزینه 'بی‌خیال موارد ..' را انتخاب کنید. توجه کنید که گزینه 'بازنویسی' تمامی موارد موجود با نام مشابه را از بین خواهد برد.", - "confirmImportMsg": "آیا از بازگردانی بک آپ مطمئن هستید؟ لطفا از اینکه نوع بازگردانی درستی را انتخاب کرده‌اید اطمینان حاصل کنید!", - "twoFAVerifyLabel": "لطفا جهت اطمینان از عملکرد احراز هویت دو مرحله‌ای توکن خود را وارد کنید!", - "tokenValidSettingsMsg": "توکن شما معتبر است، هم اکنون میتوانید احراز هویت دو مرحله‌ای را فعال کنید!", - "confirmEnableTwoFAMsg": " آیا از فعال سازی احراز هویت دو مرحله‌ای مطمئن هستید؟", + "importHandleDescription": "اگر که میخواهید بیخیال مانیتورها و یا سرویس‌های اطلاع‌رسانی که با نام مشابه از قبل موجود هستند شوید، گزینه 'بی‌خیال موارد ..' را انتخاب کنید. توجه کنید که گزینه 'بازنویسی' تمامی موارد موجود با نام مشابه را از بین خواهد برد.", + "confirmImportMsg": "آیا از بازگردانی بک آپ مطمئن هستید؟ لطفا از اینکه نوع بازگردانی درستی را انتخاب کرده‌اید اطمینان حاصل کنید.", + "twoFAVerifyLabel": "لطفا جهت اطمینان از عملکرد احراز هویت دو مرحله‌ای توکن خود را وارد کنید:", + "tokenValidSettingsMsg": "توکن شما معتبر است، هم اکنون میتوانید احراز هویت دو مرحله‌ای را فعال کنید.", + "confirmEnableTwoFAMsg": "آیا از فعال سازی احراز هویت دو مرحله‌ای مطمئن هستید؟", "confirmDisableTwoFAMsg": "آیا از غیرفعال سازی احراز هویت دومرحله‌ای مطمئن هستید؟", "Settings": "تنظیمات", "Dashboard": "پیشخوان", - "New Update": "بروزرسانی جدید!", + "New Update": "بروزرسانی جدید", "Language": "زبان", "Appearance": "ظاهر", "Theme": "پوسته", @@ -48,13 +48,13 @@ "Status": "وضعیت", "DateTime": "تاریخ و زمان", "Message": "پیام", - "No important events": "رخداد جدیدی موجود نیست.", + "No important events": "رخداد جدیدی موجود نیست", "Resume": "ادامه", "Edit": "ویرایش", "Delete": "حذف", "Current": "فعلی", "Uptime": "آپتایم", - "Cert Exp.": "تاریخ انقضای SSL", + "Cert Exp.": "تاریخ انقضای SSL.", "day": "روز", "-day": "-روز", "hour": "ساعت", @@ -76,7 +76,7 @@ "Accepted Status Codes": "وضعیت‌های (Status Code) های قابل قبول", "Save": "ذخیره", "Notifications": "اطلاع‌رسانی‌ها", - "Not available, please setup.": "هیچ موردی موجود نیست، اولین مورد را راه اندازی کنید!", + "Not available, please setup.": "هیچ موردی موجود نیست، اولین مورد را راه اندازی کنید.", "Setup Notification": "راه اندازی اطلاع‌رسانی‌", "Light": "روشن", "Dark": "تاریک", @@ -87,8 +87,8 @@ "None": "هیچ کدام", "Timezone": "موقعیت زمانی", "Search Engine Visibility": "قابلیت دسترسی برای موتورهای جستجو", - "Allow indexing": "اجازه ایندکس شدن را بده.", - "Discourage search engines from indexing site": "به موتورهای جستجو اجازه ایندکس کردن این سامانه را نده.", + "Allow indexing": "اجازه ایندکس شدن در موتور های جستجو را بده", + "Discourage search engines from indexing site": "به موتورهای جستجو اجازه ایندکس کردن این سامانه را نده", "Change Password": "تغییر رمزعبور", "Current Password": "رمزعبور فعلی", "New Password": "رمزعبور جدید", @@ -98,10 +98,10 @@ "Enable Auth": "فعال سازی تایید هویت", "disableauth.message1": "آیا مطمئن هستید که میخواهید احراز هویت را غیر فعال کنید?", "disableauth.message2": "این ویژگی برای کسانی است که لایه امنیتی شخص ثالث دیگر بر روی این آدرس فعال کرده‌اند، مانند Cloudflare Access.", - "Please use this option carefully!": "لطفا از این امکان با دقت استفاده کنید.", + "Please use this option carefully!": "لطفا از این امکان با دقت استفاده کنید!", "Logout": "خروج", "Leave": "منصرف شدم", - "I understand, please disable": "متوجه هستم، لطفا غیرفعال کنید!", + "I understand, please disable": "متوجه هستم، غیرفعال کن", "Confirm": "تایید", "Yes": "بلی", "No": "خیر", @@ -126,12 +126,12 @@ "Import": "ورود اطلاعات", "respTime": "زمان پاسخگویی (میلی‌ثانیه)", "notAvailableShort": "ناموجود", - "Default enabled": "به صورت پیش‌فرض فعال باشد.", - "Apply on all existing monitors": "بر روی تمامی مانیتور‌های فعلی اعمال شود.", + "Default enabled": "به صورت پیش‌فرض فعال باشد", + "Apply on all existing monitors": "بر روی تمامی مانیتور‌های فعلی اعمال شود", "Create": "ایجاد", "Clear Data": "پاکسازی داده‌ها", "Events": "رخداد‌ها", - "Heartbeats": "Heartbeats", + "Heartbeats": "ضربان قلب", "Auto Get": "Auto Get", "backupDescription": "شما میتوانید تمامی مانیتورها و تنظیمات اطلاع‌رسانی‌ها را در قالب یه فایل JSON دریافت کنید.", "backupDescription2": "البته تاریخچه رخدادها دراین فایل قرار نخواهند داشت.", @@ -152,10 +152,10 @@ "Active": "فعال", "Inactive": "غیرفعال", "Token": "توکن", - "Show URI": "نمایش آدرس (URI) ", + "Show URI": "نمایش آدرس (URI)", "Tags": "برچسب‌ها", "Add New below or Select...": "یک مورد جدید اضافه کنید و یا از لیست انتخاب کنید…", - "Tag with this name already exist.": "یک برچسب با این «نام» از قبل وجود دارد", + "Tag with this name already exist.": "یک برچسب با این «نام» از قبل وجود دارد.", "Tag with this value already exist.": "یک برچسب با این «مقدار» از قبل وجود دارد.", "color": "رنگ", "value (optional)": "مقدار (اختیاری)", @@ -167,13 +167,13 @@ "Indigo": "نیلی", "Purple": "بنفش", "Pink": "صورتی", - "Search...": "جستجو...", + "Search...": "جستجو …", "Avg. Ping": "متوسط پینگ", "Avg. Response": "متوسط زمان پاسخ", "Entry Page": "صفحه ورودی", - "statusPageNothing": "چیزی اینجا نیست، لطفا یک گروه و یا یک مانیتور اضافه کنید!", + "statusPageNothing": "چیزی اینجا نیست، لطفا یک گروه و یا یک مانیتور اضافه کنید.", "No Services": "هیچ سرویسی موجود نیست", - "All Systems Operational": "تمامی سیستم‌ها عملیاتی هستند!", + "All Systems Operational": "تمامی سیستم‌ها عملیاتی هستند", "Partially Degraded Service": "افت نسبی کیفیت سرویس", "Degraded Service": "افت کامل کیفیت سرویس", "Add Group": "اضافه کردن گروه", @@ -187,7 +187,7 @@ "One record": "یک مورد", "Info": "اطلاعات", "Powered by": "نیرو گرفته از", - "apprise": "Apprise (Support 50+ Notification services)", + "apprise": "Apprise (پشتیبانی از 50+ خدمات اعلان)", "Monitor": "مانیتور | مانتیور ها", "Help": "کمک", "Game": "بازی", @@ -197,5 +197,520 @@ "statusMaintenance": "در دست تعمیر", "Maintenance": "در حال تعمیر", "General Monitor Type": "حالت مانیتور عمومی", - "markdownSupported": "شیوه نگارشی Markdown پشتیبانی می شود" + "markdownSupported": "شیوه نگارشی Markdown پشتیبانی می شود", + "Body Encoding": "انکودینگ محتوا", + "twilioFromNumber": "از شماره", + "twilioToNumber": "به شماره", + "Resend Notification if Down X times consecutively": "اگر X بار متوالی غیرفعال بود، مجددا اطلاع بده", + "successMessageExplanation": "پیام MQTT موفقیت آمیز به نظر نمیرسد", + "Create Incident": "یک حادثه را اطلاع دهید", + "Switch to Light Theme": "تغییر به حالت روشن", + "No monitors available.": "هیچ مانیتوری در دسترس نیست.", + "deleteProxyMsg": "آیا مطمئن هستید که میخواهید پروکسی را برای همه مانیتور ها غیرفعال کنید؟", + "enableProxyDescription": "این پروکسی تا زمانی که فعال نشود روی درخواست های مانیتور اثری نخواهد داشت. می‌توانید با توجه به وضعیت فعال‌سازی، پروکسی را از همه مانیتورها به طور موقت غیرفعال کنید.", + "supportTelegramChatID": "پشتیبانی از چت مستقیم / گروه / کانال", + "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "توکن دسترسی طولانی مدت (Long-Lived Access Token) را می توان با کلیک بر روی نام پروفایل خود (پایین سمت چپ) و اسکرول کردن به پایین و سپس روی Create Token ایجاد کرد. ", + "A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "فهرستی از سرویس‌های اعلان را می‌توانید در هوم اسیستنت در قسمت «ابزارهای برنامه‌نویس > خدمات» برای «اعلان» جستجو کنید تا نام دستگاه/تلفن خود را پیدا کنید.", + "lastDay4": "چهارمین روز آخر ماه", + "dnsCacheDescription": "ممکن است در برخی از محیط های IPv6 کار نکند، اگر با مشکلی مواجه شدید آن را غیرفعال کنید.", + "Maintenance Time Window of a Day": "صفحه نگه داری در روز", + "Messaging API": "API پیام (Messaging API)", + "wayToGetLineChannelToken": "ابتدا به {0} دسترسی پیدا کنید، یک ارائه دهنده و کانال ایجاد کنید (API پیام)، سپس می توانید رمز توکن کانال و آیدی کاربری را از آیتم های منوی ذکر شده در بالا دریافت کنید.", + "aboutMattermostChannelName": "می‌توانید با وارد کردن نام کانال در قسمت «نام کانال»، کانال پیش‌فرضی را که وب هوک به آن پست می‌کند لغو کنید. این باید در تنظیمات Mattermost Webhook فعال شود. مثال: #other-channel", + "dnsPortDescription": "پورت سرور DNS. پیش فرض ۵۳. می توانید این عدد را در هر زمانی عوض کنید.", + "affectedStatusPages": "نمایش این پیام تعمیر و نگه داری در صفحات استاتوس انتخاب شده", + "octopushSMSSender": "نام فرستنده پیامک: 3-11 الفبای انگلیسی، حروف و فاصله (a-zA-Z0-9)", + "Lowcost": "کم هزینه", + "You can divide numbers with": "می توانید اعداد را با آن تقسیم کنید", + "goAlertInfo": "GoAlert یک برنامه اوپن سورس برای زمان‌بندی تماس، افزایش خودکار و اعلان‌ها (مانند پیامک یا تماس‌های صوتی) است. به طور خودکار شخص مناسب، راه درست و در زمان مناسب را درگیر کنید! {0}", + "API Keys": "کلید های API", + "Expiry": "انقضا", + "Expiry date": "انقضا در تاریخ", + "Don't expire": "بدون انقضا (منقضی نمی شود)", + "For safety, must use secret key": "برای امنیت، میببایستی از SecretKey استفاده کنید", + "promosmsTypeFlash": "SMS FLASH - پیام به طور خودکار در دستگاه گیرنده نشان داده می شود. فقط به گیرندگان لهستانی محدود می شود.", + "promosmsTypeFull": "SMS FULL - پیامک پریموم، می توانید از نام فرستنده خود استفاده کنید (ابتدا باید نام خود را ثبت کنید). قابل اعتماد برای هشدار.", + "matrixHomeserverURL": "URL هوم سرور (با http(s):// و پورت اختیاری)", + "matrixDesc1": "با مراجعه به بخش پیشرفته تنظیمات اتاق در کلاینت Matrix خود می توانید آیدی داخلی اتاق را بیابید. باید شبیه \"!QMdRCpUIfLwsfjxye6:home.server\" باشد.", + "wayToGetPagerDutyKey": "با رفتن به Service -> Service Directory -> (Select a Service) -> Integrations -> Add integration می توانید این مورد را دریافت کنید. در اینجا می توانید \"Events API V2\" را جستجو کنید. اطلاعات بیشتر در {0}", + "smseagleRecipientType": "نوع گیرنده", + "smseagleEncoding": "ارسال به صورت یونیکد", + "Leave blank to use a shared sender number.": "برای استفاده از شماره فرستنده مشترک، آن را خالی بگذارید.", + "onebotSafetyTips": "برای امنیت، میبایستی توکن دسترسی اضافه کنید", + "Custom Monitor Type": "نوع مانیتور سفارشی", + "apiKeyAddedMsg": "کلید API شما اضافه شده است. لطفاً آن را یادداشت کنید زیرا دیگر نمایش داده نخواهد شد.", + "deleteAPIKeyMsg": "آیا مطمئن هستید که می خواهید این کلید API را غیرفعال کنید؟", + "twilioAccountSID": "SID حساب", + "twilioAuthToken": "توکن اعتبارسنجی", + "appriseNotInstalled": "Apprise نصب نشده است. {0}", + "trustProxyDescription": "به هدرهای «X-Forwarded-*» اعتماد کن. اگر می‌خواهید IP مشتری صحیح را دریافت کنید و آپ‌تایم کومای شما پشت پروکسی مانند Nginx یا Apache قرار دارد، باید این گزینه را فعال کنید.", + "matrixDesc2": "اکیداً توصیه می‌شود که یک کاربر جدید ایجاد کنید و از رمز دسترسی کاربر Matrix خود استفاده نکنید زیرا امکان دسترسی کامل به حساب شما و تمام اتاق‌هایی را که به آنها ملحق شده‌اید می‌دهد. در عوض، یک کاربر جدید ایجاد کنید و فقط او را به اتاقی دعوت کنید که می‌خواهید اعلان را دریافت کنید. می‌توانید با اجرای {0} توکن دسترسی را دریافت کنید", + "Certificate Chain": "زنجیره گواهی (Certificate Chain)", + "telegramMessageThreadID": "(اختیاری) آیدی Thread پیام", + "telegramMessageThreadIDDescription": "(اختیاری) شناسه منحصر به فرد برای موضوع پیام هدف در انجمن. فقط برای سوپر گروه های انجمن", + "Channel Name": "نام کانال", + "auto acknowledged": "تصدیق خودکار", + "needPushEvery": "هر {0} ثانیه، URL زیر را صدا بزن.", + "pushOptionalParams": "پارامترهای اختیاری: {0}", + "Affected Monitors": "مانیتورهای تحت تأثیر", + "Pick Affected Monitors...": "انتخاب مانیتورهای تحت تأثیر…", + "Start of maintenance": "زمان شروع نگهداری", + "All Status Pages": "همه صفحات مشاهده وضعیت", + "Select status pages...": "انتخاب صفحه مشاهده وضعیت…", + "here": "اینجا", + "Required": "اجباری", + "Post URL": "URL بعدی", + "defaultNotificationName": "هشدار {notification} در ({number})", + "Add one": "اضافه کردن", + "Page Not Found": "صفحه درخواستی پیدا نشد", + "Reverse Proxy": "ریورس پروکسی", + "Backup": "پشتیبان گیری", + "API Key": "کلید API", + "Show update if available": "نمایش بروز رسانی اگر موجود بود", + "Check how to config it for WebSocket": "بررسی چگونگی پیکربندی برای وب سوکت", + "Steam Game Server": "سرور گیم استیم", + "Most likely causes:": "به احتمال زیاد بخاطر:", + "The resource is no longer available.": "منبع دیگر در دسترس نیست.", + "Docker Container": "کانتینر داکر", + "Container Name / ID": "نام / آیدی کانتینر", + "Docker Host": "هاست داکر", + "Docker Hosts": "هاست های داکر", + "Domain": "دامنه", + "Clone Monitor": "تکثیر", + "Clone": "تکثیر", + "cloneOf": "تکثیر {0}", + "Prefix Custom Message": "پیشوند پیام سفارشی", + "enableGRPCTls": "امکان ارسال درخواست gRPC با اتصال TLS", + "pushoversounds classical": "کلاسیک", + "smtpDkimSettings": "تنظیمات DKIM", + "aboutChannelName": "اگر می‌خواهید کانال وب هوک را دور بزنید، نام کانال را در قسمت {0} نام کانال وارد کنید. مثال: #other-channel", + "aboutKumaURL": "اگر قسمت URL آپ‌تایم کوما را خالی بگذارید، به طور پیش‌فرض به صفحه پروژه گیت هاب تبدیل می‌شود.", + "smtpDkimDesc": "لطفاً برای استفاده به Nodemailer DKIM {0} مراجعه کنید.", + "alertaApiEndpoint": "اند پوینت API", + "serwersmsAPIUser": "نام کاربری API (شامل پیشوند webapi_)", + "serwersmsAPIPassword": "رمز عبور API", + "serwersmsPhoneNumber": "شماره موبایل", + "serwersmsSenderName": "نام فرستنده پیامک (ثبت شده از طریق پورتال مشتری)", + "alertaRecoverState": "حالت ریکاور (Recover State)", + "smseagleToken": "توکن دسترسی API", + "Google Analytics ID": "آیدی گوگل آنالیتیکس", + "pagertreeLow": "کم", + "pagertreeMedium": "متوسط", + "pagertreeHigh": "زیاد", + "pagertreeCritical": "حساس - خیلی مهم", + "pagertreeIntegrationUrl": "URL یکپارچه سازی", + "pagertreeUrgency": "اهمیت", + "pagertreeSilent": "بی صدا", + "pagertreeResolve": "Resolve اتوماتیک", + "pagertreeDoNothing": "هیچ کاری نکن", + "wayToGetPagerTreeIntegrationURL": "پس از ایجاد ادغام آپ‌تایم کوما در PagerTree، اند پوینت را کپی کنید. مشاهده جزئیات کامل در {0}", + "telegramProtectContent": "محافظت از ارسال/ذخیره", + "telegramProtectContentDescription": "در صورت فعال بودن، پیام‌های ربات در تلگرام از ارسال و ذخیره محافظت می‌شوند.", + "wayToGetTelegramChatID": "برای مشاهده chat_id می توانید شناسه چت خود را با ارسال یک پیام به ربات و رفتن به این URL دریافت کنید:", + "YOUR BOT TOKEN HERE": "شناسه ربات خود را اینجا وارد کنید", + "chatIDNotFound": "شناسه چت یافت نشد. لطفا ابتدا به ربات پیام دهید", + "disableCloudflaredNoAuthMsg": "شما در حالت بدون احراز هویت هستید، رمز عبور در این حالت لازم نیست.", + "Trigger type:": "نوع راه اندازی:", + "DateTime Range": "محدوده تاریخ", + "loadingError": "نمی توان داده ها را دریافت کرد، لطفاً بعداً دوباره امتحان کنید.", + "High": "زیاد", + "Retry": "تلاش مجدد", + "Topic": "موضوع", + "Integration Key": "کلید یکپارچه سازی", + "Edit Tag": "ویرایش تگ", + "Server Address": "آدرس سرور", + "Learn More": "بیشتر بدانید", + "Customize": "شخصی سازی", + "Custom Footer": "فوتر اختصاصی", + "No Proxy": "بدون پروکسی", + "Authentication": "احراز هویت", + "steamApiKeyDescription": "برای مانیتورینگ یک سرور استیم،‌ شما نیاز به یک \"Steam Web-API key\" دارید. برای دریافت کلید میتوانید از اینجا اقدام کنید: ", + "No Monitors": "بدون مانیتور", + "Untitled Group": "دسته بنده نشده", + "Services": "سرویس ها", + "Discard": "دست کشیدن", + "Cancel": "انصراف", + "About": "درباره آپ‌تایم کوما", + "wayToGetCloudflaredURL": "(دریافت Cloudflared از {0})", + "cloudflareWebsite": "وب سایت کلادفلر", + "shrinkDatabaseDescription": "تریگر VACUUM برای SQLite. اگر دیتابیس شما بعد از 1.10.0 ایجاد شده باشد، AUTO_VACUUM قبلاً فعال شده است و لازم نیست این عمل انجام شود. (Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.).", + "Message:": "پیام:", + "HTTP Headers": "هدر های HTTP", + "Bot Token": "توکن بات", + "SecretKey": "کلید محرمانه (SecretKey)", + "telegramSendSilently": "ارسال بی صدا", + "telegramSendSilentlyDescription": "پیام را بی صدا ارسال کن. در این حالت کاربران یک اعلان بدون صدا دریافت خواهند کرد.", + "install": "نصب", + "Icon URL": "URL آیکون", + "Steam API Key": "کلید API استیم", + "Security": "امنیت", + "light": "روشن", + "Query": "کوئری", + "Effective Date Range": "محدوده تاریخ مورد تاثیر", + "statusPageRefreshIn": "بارگذاری مجدد در هر:‌ {0}", + "Content Type": "نوع محتوا (Content Type)", + "Server URL": "آدرس سرور", + "Priority": "اهمیت", + "emojiCheatSheet": "چیت شیت ایموجی ها:‌ {0}", + "Read more": "بیشتر بدانید", + "webhookJsonDesc": "{0} برای هر HTTP سرور جدیدی مانند Express.js مناسب است", + "Method": "متد", + "Headers": "هدر ها", + "PushUrl": "URL پوش", + "HeadersInvalidFormat": "هدر ریکوئست یک JSON درست نیست: ", + "BodyInvalidFormat": "هدر ریکوئست یک JSON درست نیست: ", + "Monitor History": "گزارش مانیتورینگ", + "clearDataOlderThan": "گزارشات مانیتورینگ را برای {0} روز نگه دار.", + "PasswordsDoNotMatch": "رمز عبور وارد شده درست نیست.", + "topic": "موضوع", + "topicExplanation": "موضوع MQTT برای مانیتور", + "successMessage": "پیام موفقیت آمیز", + "recent": "اخیر", + "Done": "انجام شده", + "Shrink Database": "فشرده سازی دیتابیس", + "Pick a RR-Type...": "یک تایپ RR انتخاب کنید…", + "Pick Accepted Status Codes...": "یک استاتوس کد قابل قبول انتخاب کنید…", + "Default": "پیش فرض", + "HTTP Options": "آپشن های HTTP", + "Title": "عنوان", + "Content": "محتوا", + "primary": "اولیه", + "dark": "تیره", + "Post": "اطلاع بده", + "Please input title and content": "لطفا یک عنوان و محتوا وارد کنید", + "Created": "ساخته شده در", + "Last Updated": "ویرایش شده در", + "Unpin": "برداشتن", + "Switch to Dark Theme": "تغییر به حالت تیره", + "Show Tags": "نمایش تگ ها", + "Hide Tags": "مخفی سازی تگ ها", + "Description": "توضحیات", + "Custom CSS": "CSS اختصاصی", + "deleteStatusPageMsg": "آیا بابت حذف این استاتوس پیچ مطمئن هستید؟", + "Proxies": "پروکسی ها", + "appriseInstalled": "Apprise نصب شده است.", + "Body": "متن", + "Start": "شروع", + "Stop": "توقف", + "Add New Status Page": "افزودن صفحه استاتوس جدید", + "Slug": "لینک", + "Accept characters:": "کاراکتر های مورد تایید:", + "startOrEndWithOnly": "شروع یا پایان فقط با {0}", + "No consecutive dashes": "بدون خط تیره متوالی", + "Next": "بعدی", + "The slug is already taken. Please choose another slug.": "این لینک قبلا گرفته شده است. لطفا لینک دیگری را انتخاب کنید.", + "New Status Page": "صفحه استاتوس جدید", + "Don't know how to get the token? Please read the guide:": "نمی دانید توکن خود را چگونه دریافت کنید؟ لطفا این راهنما را بخوانید:", + "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "اگر در حال حاضر از طریق تونل به کلادفلر متصل می شوید، ممکن است اتصال فعلی قطع شود. آیا مطمئن هستید که می خواهید کلادفلر را متوقف کنید؟ رمز عبور خود را برای تایید این دستور تایپ کنید.", + "Trust Proxy": "پروکسی مورد اعتماد", + "Other Software": "برنامه های دیگر", + "For example: nginx, Apache and Traefik.": "برای مثال: Nginx ،Apache و Traefik.", + "signedInDispDisabled": "اعتبارسنجی غیرفعال شده است.", + "RadiusCallingStationIdDescription": "شناسه دستگاه تماس گیرنده", + "Certificate Expiry Notification": "اطلاعیه انقضای گواهی", + "RadiusSecret": "کلید Radius", + "API Username": "نام کاربری API", + "Also check beta release": "همچنین برای نسخه های بتا نیز جستجو کن", + "Using a Reverse Proxy?": "استفاده از ریورس پروکسی؟", + "There might be a typing error in the address.": "ممکن است یک خطای تایپ در آدرس وجود داشته باشد.", + "What you can try:": "آنچه می توانید امتحان کنید:", + "Go back to the previous page.": "بازگشت به صفحه قبلی.", + "Coming Soon": "به زودی", + "Connection String": "رشته اتصال‌ (Connection String)", + "settingsCertificateExpiry": "انقضای گواهی TLS", + "certificationExpiryDescription": "مانیتور های HTTPS راه اندازی میشود زمانی که گواهی TLS منقضی شود در:", + "Retype the address.": "آدرس را دوباره تایپ کنید.", + "Setup Docker Host": "راه اندازی هاست داکر", + "Connection Type": "نوع اتصال", + "Docker Daemon": "Daemon داکر", + "deleteDockerHostMsg": "آیا مطمئن هستید که می خواهید این هاست داکر را برای همه مانیتورها حذف کنید؟", + "Workstation": "محل کار (Workstation)", + "Packet Size": "سایز پکت", + "wayToGetTelegramToken": "شما میتوانید توکن خود را از {0} دریافت کنید.", + "Chat ID": "آیدی چت", + "wayToGetLineNotifyToken": "می‌توانید یک توکن جهت دسترسی از {0} دریافت کنید", + "Examples": "مثال ها", + "Home Assistant URL": "URL هوم اسیستنت شما", + "Long-Lived Access Token": "توکن دسترسی طولانی مدت", + "Notification Service": "سرویس اطلاع رسانی", + "default: notify all devices": "پیش فرض: اطلاع به همه دستگاه ها", + "Automations can optionally be triggered in Home Assistant:": "اتوماسیون ها می توانند به صورت اختیاری در هوم اسیستنت فعال شوند:", + "Event type:": "نوع ایونت:", + "Event data:": "نوع دیتا:", + "Then choose an action, for example switch the scene to where an RGB light is red.": "سپس یک عمل را انتخاب کنید، برای مثال صحنه را به جایی که نور RGB قرمز است تغییر دهید.", + "Optional": "اختیاری", + "recurringInterval": "وقفه", + "Recurring": "مکرر", + "strategyManual": "فعال/غیرفعال سازی به صورت دستی", + "warningTimezone": "این از منطقه زمانی سرور استفاده می کند", + "weekdayShortMon": "دوشنبه", + "weekdayShortTue": "سه شنبه", + "weekdayShortWed": "چهارشنبه", + "weekdayShortThu": "پنجشنبه", + "weekdayShortFri": "جمعه", + "weekdayShortSat": "شنبه", + "weekdayShortSun": "یکشنبه", + "dayOfWeek": "روز های هفته", + "dayOfMonth": "روز های ماه", + "lastDay": "روز آخر", + "lastDay1": "روز آخر ماه", + "lastDay2": "دومین روز آخر ماه", + "lastDay3": "سومین روز آخر ماه", + "Enable": "فعال سازی", + "Single Maintenance Window": "تعمیر و نگه داری تک صفحه", + "Schedule Maintenance": "زمانبندی تعمیر و نگهداری", + "Date and Time": "زمان و تاریخ", + "plugin": "پلاگین | پلاگین ها", + "installing": "در حال نصب", + "uninstall": "حذف از نصب", + "uninstalling": "درحال حذف", + "confirmUninstallPlugin": "آیا مطمئن هستید که می خواهید این پلاگین را حذف از نصب کنید؟", + "notificationRegional": "منطقه ای", + "secureOptionNone": "None / STARTTLS (25, 587)", + "secureOptionTLS": "TLS (465)", + "Ignore TLS Error": "خطای TLS را نادیده بگیر", + "From Email": "از ایمیل", + "emailCustomSubject": "موضوع سفارشی", + "To Email": "به ایمیل", + "smtpBCC": "BCC", + "Discord Webhook URL": "URL وب هوک دیسکورد", + "Bot Display Name": "نام نمایشی ربات", + "Hello @everyone is...": "سلام {'@'} همه…", + "wayToGetTeamsURL": "می‌توانید نحوه ایجاد وب هوک را در {0} بیاموزید.", + "wayToGetZohoCliqURL": "می‌توانید نحوه ایجاد وب هوک را در {0} بیاموزید.", + "needSignalAPI": "شما باید یک Signal Client با REST API داشته باشید.", + "wayToCheckSignalURL": "برای مشاهده نحوه تنظیم آن می توانید این URL را بررسی کنید:", + "Number": "عدد", + "Recipients": "گیرندگان", + "Channel access token": "توکن دسترسی به کانال", + "Line Developers Console": "کنسول توسعه دهندگان لاین (Line Developers Console)", + "lineDevConsoleTo": "کنسول توسعه دهندگان لاین (Line Developers Console) - {0}", + "Basic Settings": "تنظیمات پایه", + "User ID": "آیدی کاربر", + "aboutIconURL": "می‌توانید پیوندی به یک عکس در \"URL آیکون \" ارائه دهید تا عکس نمایه پیش‌فرض را لغو کنید. اگر نماد Emoji تنظیم شده باشد، این مورد استفاده نخواهد شد.", + "dataRetentionTimeError": "دوره نگهداری باید 0 یا بیشتر باشد", + "wayToGetDiscordURL": "شما می توانید این را با رفتن به تنظیمات سرور -> ادغام -> مشاهده وب هوک -> وب هوک جدید (Settings -> Integrations -> View Webhooks -> New Webhook) دریافت کنید", + "infiniteRetention": "برای دوره بی نهایت 0 را وارد تنظیم کنید.", + "confirmDeleteTagMsg": "آیا مطمئن هستید که می خواهید این تگ را حذف کنید؟ مانیتورهای مرتبط با این تگ حذف نخواهند شد.", + "grpcMethodDescription": "نام روش تبدیل به فرمت cammelCase مانند sayHello، check و غیره.", + "deleteMaintenanceMsg": "آیا مطمئن هستید که می خواهید این تعمیر و نگهداری را حذف کنید؟", + "recurringIntervalMessage": "یکبار اجرا برای هر روز | یکبار اجرا در هر {0} روز", + "affectedMonitorsDescription": "مانیتورهایی را انتخاب کنید که تحت تأثیر تعمیر و نگهداری فعلی هستند", + "atLeastOneMonitor": "حداقل یک مانیتور مورد تاثیر را انتخاب کنید", + "octopushAPIKey": "\"کلید API\" از اعتبارنامه های HTTP API در کنترل پنل", + "octopushLogin": "\"ورود\" از اعتبار HTTP API در کنترل پنل", + "promosmsLogin": "نام ورود API", + "pushoversounds cashregister": "صندوق فروش", + "pushoversounds falling": "رها کردن", + "pushoversounds incoming": "ورودی", + "pushoversounds intermission": "وقفه", + "pushoversounds magic": "سحر آمیز", + "pushoversounds mechanical": "مکانیکی", + "pushoversounds pianobar": "پیانو بار", + "pushoversounds siren": "آژیر", + "pushoversounds spacealarm": "هشدار فضایی", + "pushoversounds gamelan": "گیم لن (Gamelan)", + "Current User": "کاربر فعلی", + "pushoversounds none": "بی صدا", + "pushoversounds tugboat": "قایق یدک کش", + "pushoversounds alien": "هشدار بیگانه (طولانی)", + "pushoversounds climb": "صعود (طولانی)", + "pushoversounds persistent": "پایدار (طولانی)", + "pushoversounds echo": "اکو (طولانی)", + "pushoversounds updown": "بالا پایین (طولانی)", + "pushoversounds vibrate": "فقط ویبره", + "pushyToken": "توکن دستگاه", + "GoogleChat": "Google Chat (فقط Google Workspace)", + "wayToGetKookBotToken": "یک برنامه ایجاد کنید و توکن ربات خود را از {0} دریافت کنید", + "User Key": "کلید کاربر", + "Message Title": "عنوان پیام", + "Notification Sound": "صدای اعلان", + "More info on:": "اطلاعات بیشتر در مورد: {0}", + "pushoverDesc1": "اولویت اضطراری (2) دارای وقفه پیش‌فرض 30 ثانیه بین تلاش‌های مجدد است و پس از 1 ساعت منقضی می‌شود.", + "pushoverDesc2": "اگر می‌خواهید اعلان‌ها را به دستگاه‌های مختلف ارسال کنید، قسمت دستگاه را پر کنید.", + "pushyAPIKey": "کلید Secret API", + "wayToGetKookGuildID": "«حالت توسعه‌دهنده» را در تنظیمات کوک روشن کنید و روی انجمن کلیک راست کنید تا شناسه آن را دریافت کنید", + "Guild ID": "گیلد آیدی (Guild ID)", + "SMS Type": "نوع پیامک", + "octopushTypePremium": "پرمیوم (سریع - پیشنهاد شده برای هشدار ها)", + "octopushTypeLowCost": "کم هزینه (آهسته - گاهی اوقات توسط اپراتور مسدود می شود)", + "checkPrice": "بررسی قیمت‌های {0} :", + "apiCredentials": "اطلاعات API", + "octopushLegacyHint": "آیا از نسخه قدیمی Octopush (1387-1400) استفاده می کنید یا از نسخه جدید؟", + "octopushPhoneNumber": "شماره تلفن (حالت بین المللی مانند 989121234567+) ", + "LunaSea Device ID": "شناسه دستگاه LunaSea", + "Apprise URL": "آدرس Apprise", + "Example:": "مثال: {0}", + "Read more:": "بیشتر بخوانید: {0}", + "Free Mobile User Identifier": "شناسه کاربری Free Mobile", + "Free Mobile API Key": "کلید API در Free Mobile", + "Enable TLS": "فعال کردن TLS", + "Proto Service Name": "نام Proto Service", + "Proto Method": "متد Proto", + "Proto Content": "محتوای Proto", + "Economy": "اقتصاد", + "high": "زیاد", + "SMSManager API Docs": "مستندات SMSManager API ", + "Gateway Type": "نوع Gateway", + "Base URL": "URL پایه", + "goAlertIntegrationKeyInfo": "کلید ادغام API عمومی را برای سرویس در این قالب دریافت کنید \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee\" معمولاً مقدار پارامتر توکن URL کپی شده است.", + "AccessKeyId": "آیدی AccessKey", + "PhoneNumbers": "شماره های موبایل", + "TemplateCode": "کد تمپلیت", + "Sms template must contain parameters: ": "قالب پیامک باید دارای پارامترهای زیر باشد: ", + "Bark Endpoint": "اند پوینت Bark", + "Bark Group": "گروه Bark", + "Bark Sound": "صدای Bark", + "WebHookUrl": "آدرس وب هوک", + "Device Token": "توکن دستگاه", + "Platform": "پلتفرم", + "Check octopush prices": "بررسی قیمت های octopush {0}.", + "SendKey": "کلید ارسال (SendKey)", + "SecretAccessKey": "کلید دسترسی مخفی (AccessKey Secret)", + "SignName": "نام امضا (SignName)", + "Android": "اندروید", + "Huawei": "هواوی", + "WeCom Bot Key": "کلید ربات WeCom", + "Setup Proxy": "تنظیم پروکسی", + "Proxy Protocol": "پروتکل پروکسی", + "Proxy Server": "پروتکل سرور", + "promosmsTypeEco": "SMS ECO - ارزان اما کند و اغلب بارگذاری شده است. فقط به گیرندگان لهستانی محدود می شود.", + "promosmsTypeSpeed": "SPEED SMS - بالاترین اولویت در سیستم. بسیار سریع و قابل اعتماد اما پرهزینه (حدود دو برابر قیمت SMS FULL).", + "promosmsPhoneNumber": "شماره تلفن (برای گیرنده لهستانی می توانید کدهای منطقه را نادیده بگیرید)", + "promosmsSMSSender": "نام فرستنده پیامک: نام از پیش ثبت شده یا یکی از پیش فرض ها: InfoSMS، SMS Info، MaxSMS، INFO، SMS", + "promosmsAllowLongSMS": "اجازه برای پیامک طولانی", + "Feishu WebHookUrl": "آدرس وب هوک Feishu", + "Internal Room Id": "آیدی اتاق داخلی", + "Uptime Kuma URL": "URL آپ‌تایم کوما", + "signalImportant": "مهم: شما نمی توانید گروه ها و اعداد را در گیرندگان ترکیب کنید!", + "aboutWebhooks": "اطلاعات بیشتر درباره وب هوک در: {0}", + "documentation": "مستندات", + "smtpDkimDomain": "نام دامنه", + "smtpDkimHashAlgo": "الگوریتم رمزگذاری (اختیاری)", + "smtpDkimheaderFieldNames": "کلیدهای هدر برای امضا (اختیاری)", + "smtpDkimskipFields": "کلیدهای هدر برای عدم امضا (اختیاری)", + "Integration URL": "URL یکپارچه سازی", + "smtpDkimKeySelector": "انتخابگر کلید (SecretKey)", + "smtpDkimPrivateKey": "کلید محرمانه (Private Key)", + "socket": "سوکت", + "do nothing": "هیچ کاری نکن", + "auto resolve": "حل خودکار", + "alertaEnvironment": "محیط", + "alertaApiKey": "کلید API", + "alertaAlertState": "وضعیت هشدار", + "smseagleTo": "شماره تلفن(ها)", + "smseagleGroup": "نام(های) گروه دفترچه تلفن", + "smseagleContact": "نام(های) تماس دفترچه تلفن", + "smseagleRecipient": "گیرنده(های) (چند مورد باید با کاما از هم جدا شوند)", + "smseagleUrl": "URL دستگاه SMSEagle شما", + "smseaglePriority": "اولویت پیام (0-9، پیش فرض = 0)", + "Recipient Number": "شماره گیرنده", + "From Name/Number": "از نام/شماره", + "Octopush API Version": "نسخه Octopush API", + "ntfy Topic": "موضوع ntfy", + "onebotHttpAddress": "آدرس HTTP OneBot", + "onebotMessageType": "نوع پیام OneBot", + "onebotGroupMessage": "گروه", + "onebotPrivateMessage": "خصوصی", + "onebotUserOrGroupId": "آیدی گروه/کاربر", + "PushDeer Key": "کلید PushDeer", + "wayToGetClickSendSMSToken": "می‌توانید نام کاربری و کلید API را از {0} دریافت کنید.", + "Continue": "ادامه", + "Add Another": "افزودن یکی دیگر", + "Key Added": "کلید API اضافه شد", + "Add API Key": "افزودن کلید API", + "No API Keys": "بدون کلید API", + "apiKey-active": "فعال", + "apiKey-expired": "منقضی شده", + "apiKey-inactive": "غیرفعال", + "Expires": "انقضا", + "disableAPIKeyMsg": "آیا مطمئن هستید که می خواهید این کلید API را غیرفعال کنید؟", + "Generate": "ایجاد یک کلید API جدید", + "lunaseaTarget": "هدف", + "lunaseaDeviceID": "آيدی دستگاه", + "lunaseaUserID": "آیدی کاربر", + "Auto resolve or acknowledged": "حل خودکار یا اعلام اطلاع یافته (Auto resolve or acknowledged)", + "Legacy Octopush-DM": "(Legacy Octopush-DM)", + "smtpCC": "ارسال نسخه به", + "promosmsPassword": "رمز عبور API", + "pushoversounds pushover": "Pushover (پیش‌فرض)", + "pushoversounds bike": "دوچرخه", + "pushoversounds bugle": "بوق", + "pushoversounds cosmic": "کیهانی", + "resendEveryXTimes": "پیام را هر {0} بار دوباره ارسال کن", + "resendDisabled": "ارسال مجدد غیرفعال است", + "Push URL": "URL پوش", + "Schedule maintenance": "زمانبندی نگهداری (غیرفعال سازی دستی)", + "webhookFormDataDesc": "{multipart} برای PHP مناسب است. آرایه JSON نیاز است تا به این شکل باز شود {decodeFunction}", + "webhookAdditionalHeadersTitle": "هدر اضافی", + "webhookAdditionalHeadersDesc": "تنظیم هدر های اضافی که نیاز است با وب هوک ارسال شود.", + "Webhook URL": "آدرس وب هوک", + "Application Token": "توکن اپلیکیشن", + "Style": "حالت ها", + "info": "اطلاعات", + "warning": "هشدار", + "danger": "خطر", + "error": "خطا", + "critical": "اهمیت ویژه", + "HTTP Basic Auth": "حالت پایه احراز هویت (HTTP Basic Auth)", + "RadiusSecretDescription": "اشتراک گذاری Secret بین کاربر و سرور", + "RadiusCalledStationId": "نام Station Id", + "RadiusCalledStationIdDescription": "شناسه دستگاه فراخوانی شده", + "RadiusCallingStationId": "آیدی ایستگاه تماس (Calling Station Id)", + "tcp": "TCP / HTTP", + "Frontend Version": "نسخه فرانت اند", + "Frontend Version do not match backend version!": "نسخه فرانت اند با نسخه بک اند مطابقت ندارد!", + "backupOutdatedWarning": "منسوخ شده: از آنجایی که بسیاری از ویژگی ها اضافه شده اند و این ویژگی پشتیبان گیری کمی حفظ نشده است، نمی تواند یک نسخه پشتیبان کامل ایجاد یا بازیابی شود.", + "backupRecommend": "لطفاً مستقیماً از Volume یا پوشه داده (./data/) نسخه پشتیبان تهیه کنید.", + "No Maintenance": "بدون تعمیر و نگهداری", + "pauseMaintenanceMsg": "آیا مطمئن هستید که می خواهید توقف کنید؟", + "maintenanceStatus-under-maintenance": "تحت تعمیر و نگهداری", + "maintenanceStatus-inactive": "غیرفعال", + "maintenanceStatus-scheduled": "برنامه ریزی شده", + "maintenanceStatus-ended": "پایان یافته", + "maintenanceStatus-unknown": "ناشناخته", + "Display Timezone": "منطقه زمانی برای نمایش", + "Server Timezone": "منطقه زمانی در سرور", + "statusPageMaintenanceEndDate": "پایان", + "IconUrl": "URL آیکون", + "Enable DNS Cache": "فعال سازی کش DNS", + "Access Token": "توکن دسترسی", + "smtp": "ایمیل (SMTP)", + "Device": "دستگاه", + "Proxy server has authentication": "پروکسی سرور دارای احراز هویت", + "Add New Tag": "اضافه کردن تگ جدید", + "Custom": "غیره", + "default": "پیش فرض", + "enabled": "فعال", + "setAsDefault": "ذخیره به عنوان پیش فرض", + "proxyDescription": "پروکسی برای راه اندازی این مانیتور اجباری است.", + "setAsDefaultProxyDescription": "این پروکسی به طور پیش فرض برای مانیتورهای جدید فعال می شود. همچنان می توانید پروکسی را به طور جداگانه برای هر مانیتور غیرفعال کنید.", + "Valid": "درست", + "Invalid": "نادرست", + "User": "کاربر", + "Installed": "نصب شده", + "Not installed": "نصب نشده", + "Running": "در حال اجرا", + "Not running": "اجرا نشده", + "Remove Token": "حذف توکن", + "Please read": "لطفا بخوانید", + "Subject:": "موضوع:", + "Valid To:": "معتبر تا:", + "Days Remaining:": "روز های باقی مانده:", + "Fingerprint:": "اثرانگشت (Fingerprint):", + "No status pages": "بدون صفحات استاتوس", + "Domain Name Expiry Notification": "اعلان انقضای نام دامنه", + "Issuer:": "صادرکننده:", + "Date Created": "ایجاد شده در", + "Footer Text": "متن فوتر", + "Show Powered By": "نمایش قدرت گرفته از آپ‌تایم کوما", + "Domain Names": "نام دامنه ها", + "Proxy": "پروکسی", + "signedInDisp": "وارد شده به عنوان {0}", + "or": "یا", + "Disable": "غیرفعال سازی", + "endpoint": "نقطه پایانی", + "Status:": "وضعیت: {0}", + "Strategy": "استراتژی", + "Icon Emoji": "ایموجی آیکون" } From a7f21bffec35aced6b9d5f7c87b93a954b91cf88 Mon Sep 17 00:00:00 2001 From: Adam Stachowicz Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 14/26] Translated using Weblate (Polish) Currently translated at 100.0% (713 of 713 strings) Co-authored-by: Adam Stachowicz Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/pl.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/lang/pl.json b/src/lang/pl.json index 1b61bc6bc..02926a342 100644 --- a/src/lang/pl.json +++ b/src/lang/pl.json @@ -727,5 +727,21 @@ "Key Added": "Klucz dodany", "pagertreeDoNothing": "Nie rób nic", "wayToGetPagerTreeIntegrationURL": "Po utworzeniu integracji Uptime Kuma w PagerTree, należy skopiować Endpoint. Zobacz pełne szczegóły {0}", - "notificationRegional": "Regionalne" + "notificationRegional": "Regionalne", + "twilioFromNumber": "Z numeru", + "twilioToNumber": "Do numeru", + "lunaseaTarget": "Cel", + "twilioAccountSID": "SID konta", + "twilioAuthToken": "Token autoryzacyjny", + "apiKeyAddedMsg": "Twój klucz API został dodany. Prosimy o zanotowanie go, ponieważ nie będzie on już więcej pokazywany.", + "telegramMessageThreadID": "(Opcjonalne) ID wątku wiadomości", + "telegramMessageThreadIDDescription": "Opcjonalny Unikalny identyfikator dla docelowego wątku wiadomości (tematu) forum; tylko dla supergrup forum", + "telegramProtectContent": "Ochrona przekazywania/zapisywania", + "telegramProtectContentDescription": "Jeśli włączona, wiadomości bota w Telegramie będą chronione przed przekazywaniem i zapisywaniem.", + "telegramSendSilently": "Wyślij po cichu", + "telegramSendSilentlyDescription": "Wysyła wiadomość po cichu. Użytkownicy otrzymają powiadomienie bez dźwięku.", + "statusPageRefreshIn": "Odświeżenie w ciągu: {0}", + "lunaseaDeviceID": "ID urządzenia", + "lunaseaUserID": "ID użytkownika", + "Add New Tag": "Dodaj nowy tag" } From f608590526719edcfb3248ab77affe751846cc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Gen=C3=A7?= Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 15/26] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (713 of 713 strings) Co-authored-by: Ömer Faruk Genç Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/tr-TR.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lang/tr-TR.json b/src/lang/tr-TR.json index 3a3aeffe6..fdced11fe 100644 --- a/src/lang/tr-TR.json +++ b/src/lang/tr-TR.json @@ -739,5 +739,9 @@ "Add New Tag": "Yeni Etiket Ekle", "lunaseaDeviceID": "Cihaz ID", "lunaseaUserID": "Kullanıcı ID", - "statusPageRefreshIn": "{0} içinde yenilenecek" + "statusPageRefreshIn": "{0} içinde yenilenecek", + "twilioAuthToken": "Kimlik Doğrulama Jetonu", + "twilioFromNumber": "Gönderen Numara", + "twilioToNumber": "Alıcı Numara", + "twilioAccountSID": "Hesap ID" } From d2b09ef042f11d220c0c603cfa07735c298913c8 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 28 Mar 2023 18:55:27 +0000 Subject: [PATCH 16/26] Translated using Weblate (German) Currently translated at 100.0% (713 of 713 strings) Translated using Weblate (German (Switzerland)) Currently translated at 100.0% (713 of 713 strings) Co-authored-by: Marco Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/ Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/ Translation: Uptime Kuma/Uptime Kuma --- src/lang/de-CH.json | 47 +++++++++++++++++++++++++-------------------- src/lang/de-DE.json | 29 ++++++++++++++++------------ 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/lang/de-CH.json b/src/lang/de-CH.json index db2217459..a47d74fc6 100644 --- a/src/lang/de-CH.json +++ b/src/lang/de-CH.json @@ -102,7 +102,7 @@ "deleteNotificationMsg": "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?", "resolverserverDescription": "Cloudflare ist als der Standardserver festgelegt. Dieser kann jederzeit geändert werden.", "Resolver Server": "Auflösungsserver", - "rrtypeDescription": "Wähle den RR-Typ aus, welchen du überwachen möchtest.", + "rrtypeDescription": "Wähle den RR Typ aus, welchen du überwachen möchtest", "Last Result": "Letztes Ergebnis", "pauseMonitorMsg": "Bist du sicher, dass du den Monitor pausieren möchtest?", "clearEventsMsg": "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?", @@ -206,7 +206,7 @@ "mattermost": "Mattermost", "Primary Base URL": "Primär URL", "Push URL": "Push URL", - "needPushEvery": "Du solltest diese URL alle {0} Sekunden aufrufen", + "needPushEvery": "Du solltest diese URL alle {0} Sekunden aufrufen.", "pushOptionalParams": "Optionale Parameter: {0}", "defaultNotificationName": "Mein {notification} Alarm ({number})", "here": "hier", @@ -276,10 +276,10 @@ "appriseInstalled": "Apprise ist installiert.", "appriseNotInstalled": "Apprise ist nicht installiert. {0}", "Access Token": "Access Token", - "Channel access token": "Channel access token", + "Channel access token": "Channel Access Token", "Line Developers Console": "Line Developers Console", "lineDevConsoleTo": "Line Developers Console - {0}", - "Basic Settings": "Basic Settings", + "Basic Settings": "Grundeinstellungen", "User ID": "User ID", "Messaging API": "Messaging API", "wayToGetLineChannelToken": "Rufe zuerst {0} auf, erstelle dann einen Provider und Channel (Messaging API). Als nächstes kannst du den Channel access token und die User ID aus den oben genannten Menüpunkten abrufen.", @@ -298,7 +298,7 @@ "Internal Room Id": "Interne Raum-ID", "matrixDesc1": "Die interne Raum-ID findest du im erweiterten Bereich der Raumeinstellungen im Matrix-Client. Es sollte aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.", "matrixDesc2": "Es wird dringend empfohlen einen neuen Benutzer anzulegen und nicht den Zugriffstoken deines eigenen Matrix-Benutzers zu verwenden. Anderenfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du Folgendes ausführst {0}", - "Method": "Method", + "Method": "Methode", "Body": "Body", "Headers": "Headers", "PushUrl": "Push URL", @@ -348,7 +348,7 @@ "Services": "Dienste", "Discard": "Verwerfen", "Cancel": "Abbrechen", - "Powered by": "Powered by", + "Powered by": "Erstellt mit", "shrinkDatabaseDescription": "Löse VACUUM für die SQLite Datenbank aus. Wenn die Datenbank nach 1.10.0 erstellt wurde, ist AUTO_VACUUM bereits aktiviert und diese Aktion ist nicht erforderlich.", "serwersms": "SerwerSMS.pl", "serwersmsAPIUser": "API Benutzername (inkl. webapi_ prefix)", @@ -533,7 +533,7 @@ "Also check beta release": "Auch nach beta Versionen schauen", "Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?", "Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird", - "Steam Game Server": "Steam Game Server", + "Steam Game Server": "Steam Spielserver", "Most likely causes:": "Wahrscheinliche Ursachen:", "The resource is no longer available.": "Die Quelle ist nicht mehr verfügbar.", "There might be a typing error in the address.": "Es gibt einen Tippfehler in der Adresse.", @@ -590,7 +590,7 @@ "atLeastOneMonitor": "Wähle mindestens einen Monitor", "deleteMaintenanceMsg": "Möchtest du diese Wartung löschen?", "Base URL": "Basis URL", - "goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}", + "goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Engagiere automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt! {0}", "goAlertIntegrationKeyInfo": "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.", "goAlert": "GoAlert", "backupOutdatedWarning": "Veraltet: Da viele Funktionen hinzugefügt wurden und die Backupfunktion nicht mehr gepflegt wird, kann keine vollständige Sicherung erstellt oder wiederhergestellt werden.", @@ -599,13 +599,13 @@ "squadcast": "Squadcast", "SendKey": "SendKey", "SMSManager API Docs": "SMSManager API Dokumente ", - "Gateway Type": "Gateway Type", + "Gateway Type": "Gateway Typ", "SMSManager": "SMSManager", "You can divide numbers with": "Du kannst Zahlen teilen mit", "or": "oder", "recurringInterval": "Intervall", "Recurring": "Wiederkehrend", - "strategyManual": "Active/Inactive Manually", + "strategyManual": "Aktiv/Inaktiv Manuell", "warningTimezone": "Es wird die Zeitzone des Servers genutzt", "weekdayShortMon": "Mo", "weekdayShortTue": "Di", @@ -640,10 +640,10 @@ "installing": "Installiere", "uninstall": "Deinstallieren", "uninstalling": "Deinstalliere", - "confirmUninstallPlugin": "Möchten Sie dieses Plugin wirklich deinstallieren?", + "confirmUninstallPlugin": "Möchtest du dieses Plugin wirklich deinstallieren?", "notificationRegional": "Regional", "Single Maintenance Window": "Einmaliges Wartungsfenster", - "dnsCacheDescription": "In einigen IPv6-Umgebungen funktioniert es möglicherweise nicht. Deaktivieren Sie es, wenn Sie auf Probleme stossen.", + "dnsCacheDescription": "In einigen IPv6-Umgebungen funktioniert es möglicherweise nicht. Deaktiviere es, wenn Probleme auftreten.", "Maintenance Time Window of a Day": "Wartungszeitfenster eines Tages", "Effective Date Range": "Gültigkeitsbereich", "Schedule Maintenance": "Wartung planen", @@ -674,15 +674,15 @@ "Don't expire": "Nicht ablaufen", "Add Another": "Hinzufügen", "Key Added": "Schlüssel hinzugefügt", - "apiKeyAddedMsg": "Ihr API Schlüssel wurde hinzugefügt. Bitte notieren Sie Ihn, da er nicht erneut angezeigt wird.", + "apiKeyAddedMsg": "API Schlüssel wurde hinzugefügt. Bitte notiere den Schlüssel, da er nicht erneut angezeigt wird.", "Add API Key": "API Schlüssel hinzufügen", "No API Keys": "Kein API Schlüssel", "apiKey-active": "Aktiv", "apiKey-expired": "Abgelaufen", "apiKey-inactive": "Inaktiv", "Expires": "Läuft ab", - "disableAPIKeyMsg": "Sind Sie sicher, dass Sie diesen API Schlüssel deaktivieren möchten?", - "deleteAPIKeyMsg": "Sind Sie sicher, dass Sie diesen API Schlüssel löschen möchten?", + "disableAPIKeyMsg": "Bist du sicher, dass du diesen API Schlüssel deaktivieren willst?", + "deleteAPIKeyMsg": "Bist du sicher, dass du diesen API Schlüssel löschen willst?", "Generate": "Generieren", "infiniteRetention": "Für unendliche Speicherung auf 0 setzen.", "dataRetentionTimeError": "Aufbewahrungsfrist muss grösser oder gleich 0 sein", @@ -691,8 +691,8 @@ "cloneOf": "Klon von {0}", "wayToGetZohoCliqURL": "Wie eine Webhook URL erstellt werden kann, erfährst du {0}.", "enableGRPCTls": "Senden von gRPC Anforderungen mit TLS Verbindung zulassen", - "grpcMethodDescription": "Der Name der Methode wird in das \"cammelCase \"-Format konvertiert (z.B. sayHello, check, etc.)", - "wayToGetKookGuildID": "Schalten Sie den „Entwicklermodus“ in den Kook-Einstellungen ein und klicken Sie mit der rechten Maustaste auf die Gilde, um ihre ID zu erhalten", + "grpcMethodDescription": "Der Name der Methode wird in das \"cammelCase\" Format konvertiert (z.B. sayHello, check, etc.)", + "wayToGetKookGuildID": "Schalte den „Entwicklermodus“ in den Kook-Einstellungen ein und klicke mit der rechten Maustaste auf die Gilde, um die ID zu erhalten", "Guild ID": "Gilde ID", "Lowcost": "Kostengünstig", "high": "hoch", @@ -712,7 +712,7 @@ "pagertreeCritical": "Kritisch", "pagertreeResolve": "Automatisch auflösen", "pagertreeDoNothing": "Nichts tun", - "wayToGetPagerTreeIntegrationURL": "Nachdem Sie die Uptime Kuma Integration in PagerTree erstellt haben, kopieren Sie den Endpunkt. Siehe vollständige Details {0}", + "wayToGetPagerTreeIntegrationURL": "Nachdem du die Uptime Kuma Integration in PagerTree erstellt hast, kopiere den Endpunkt. Siehe details {0}", "Server Address": "Serveradresse", "Learn More": "Erfahre mehr", "Edit Tag": "Tag editieren", @@ -724,8 +724,8 @@ "smseagleEncoding": "Als Unicode senden", "smseaglePriority": "Nachrichtenpriorität (0-9, Standard = 0)", "smseagleContact": "Telefonbuch Kontaktname(n)", - "confirmDeleteTagMsg": "Sind Sie sicher, dass Sie diesen Tag löschen möchten? Monitore, die mit diesem Tag verknüpft sind, werden nicht gelöscht.", - "wayToGetKookBotToken": "Erstellen Sie eine Anwendung und erhalten Sie Ihren Bot-Token unter {0}", + "confirmDeleteTagMsg": "Möchtest du dieses Tag wirklich löschen? Monitore, die mit diesem Tag verknüpft sind, werden nicht gelöscht.", + "wayToGetKookBotToken": "Erstelle eine Anwendung und erhalte den Bot-Token unter {0}", "Strategy": "Strategie", "Free Mobile User Identifier": "Kostenlose mobile Benutzerkennung", "smseagleGroup": "Telefonbuch Gruppenname(n)", @@ -735,5 +735,10 @@ "Add New Tag": "Neuen Tag hinzufügen", "lunaseaTarget": "Ziel", "lunaseaDeviceID": "Geräte-ID", - "lunaseaUserID": "Benutzer-ID" + "lunaseaUserID": "Benutzer-ID", + "twilioAccountSID": "Account SID", + "twilioFromNumber": "Absender", + "twilioToNumber": "Empfänger", + "twilioAuthToken": "Auth Token", + "statusPageRefreshIn": "Aktualisierung in: {0}" } diff --git a/src/lang/de-DE.json b/src/lang/de-DE.json index 8b3376071..11e00bd2e 100644 --- a/src/lang/de-DE.json +++ b/src/lang/de-DE.json @@ -590,7 +590,7 @@ "atLeastOneMonitor": "Wähle mindestens einen Monitor", "deleteMaintenanceMsg": "Möchtest du diese Wartung löschen?", "Base URL": "Basis URL", - "goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}", + "goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Engagiere automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt! {0}", "goAlertIntegrationKeyInfo": "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.", "goAlert": "GoAlert", "backupOutdatedWarning": "Veraltet: Da viele Funktionen hinzugefügt wurden und diese Sicherungsfunktion nicht mehr gepflegt wird, kann keine vollständige Sicherung erstellen oder wiederherstellen werden.", @@ -605,7 +605,7 @@ "or": "oder", "recurringInterval": "Intervall", "Recurring": "Wiederkehrend", - "Single Maintenance Window": "Einzigartiges Wartungsfenster", + "Single Maintenance Window": "Einmaliges Wartungsfenster", "Maintenance Time Window of a Day": "Zeitfenster für die Wartung", "Effective Date Range": "Bereich der Wirksamkeitsdaten", "strategyManual": "Aktiv/Inaktiv Manuell", @@ -646,19 +646,19 @@ "Disable": "Deaktivieren", "Custom Monitor Type": "Benutzerdefinierter Monitortyp", "webhookAdditionalHeadersDesc": "Legt zusätzliche Header fest, die mit der Webhook gesendet wurden.", - "dnsCacheDescription": "In einigen IPv6-Umgebungen funktioniert es möglicherweise nicht. Deaktivieren Sie es, wenn Sie auf Probleme stoßen.", + "dnsCacheDescription": "In einigen IPv6-Umgebungen funktioniert es möglicherweise nicht. Deaktiviere es, wenn Probleme auftreten.", "loadingError": "Die Daten konnten nicht abgerufen werden, bitte später noch einmal versuchen.", - "confirmUninstallPlugin": "Möchten Sie dieses Plugin wirklich deinstallieren?", - "grpcMethodDescription": "Der Name der Methode wird in das \"cammelCase \"-Format konvertiert (z.B. sayHello, check, etc.)", + "confirmUninstallPlugin": "Möchtest du dieses Plugin wirklich deinstallieren?", + "grpcMethodDescription": "Der Name der Methode wird in das \"cammelCase\"-Format konvertiert (z.B. sayHello, check, etc.)", "Passive Monitor Type": "Passiver Monitortyp", "Specific Monitor Type": "Spezifischer Monitortyp", "webhookAdditionalHeadersTitle": "Zusätzliche Header", "Packet Size": "Paketgröße", "IconUrl": "Symbol-URL", - "wayToGetZohoCliqURL": "Erfahren Sie, wie Sie eine Webhook-URL {0} erstellen.", + "wayToGetZohoCliqURL": "Wie eine Webhook URL erstellt werden kann, erfährst du {0}.", "dataRetentionTimeError": "Aufbewahrungszeit muss 0 oder größer sein", "infiniteRetention": "Für unendliche Aufbewahrung auf 0 setzen.", - "confirmDeleteTagMsg": "Möchten Sie dieses Tag wirklich löschen? Mit diesem Tag verknüpfte Monitore werden nicht gelöscht.", + "confirmDeleteTagMsg": "Möchtest du dieses Tag wirklich löschen? Monitore, die mit diesem Tag verknüpft sind, werden nicht gelöscht.", "enableGRPCTls": "Senden von gRPC-Anforderungen mit TLS-Verbindung zulassen", "ZohoCliq": "ZohoCliq", "Monitor": "Überwachung | Monitore", @@ -668,8 +668,8 @@ "uninstall": "Deinstallieren", "uninstalling": "Deinstallation", "markdownSupported": "Markdown-Syntax unterstützt", - "wayToGetKookBotToken": "Erstellen Sie eine Anwendung und erhalten Sie Ihren Bot-Token unter {0}", - "wayToGetKookGuildID": "Schalten Sie den „Entwicklermodus“ in den Kook-Einstellungen ein und klicken Sie mit der rechten Maustaste auf die Gilde, um ihre ID zu erhalten", + "wayToGetKookBotToken": "Erstelle eine Anwendung und erhalte den Bot-Token unter {0}", + "wayToGetKookGuildID": "Schalte den „Entwicklermodus“ in den Kook-Einstellungen ein und klicke mit der rechten Maustaste auf die Gilde, um die ID zu erhalten", "Guild ID": "Guild-ID", "Free Mobile User Identifier": "Kostenlose mobile Benutzerkennung", "Free Mobile API Key": "Kostenloser Mobile API-Schlüssel", @@ -687,7 +687,7 @@ "smseagleGroup": "Telefonbuch Gruppenname(n)", "smseagleContact": "Telefonbuch Kontaktname(n)", "smseagleRecipientType": "Empfängertyp", - "smseagleRecipient": "Empfänger (mehrere müssen mit Komma getrennt werden)", + "smseagleRecipient": "Empfänger (mehrere müssen durch Komma getrennt werden)", "smseagleToken": "API-Zugriffstoken", "smseagleUrl": "Ihre SMSEagle-Geräte-URL", "Kook": "Kook", @@ -730,7 +730,7 @@ "telegramProtectContentDescription": "Die Bot-Nachrichten in Telegram sind gegen Weiterleitung und Speichern geschützt.", "notificationRegional": "Regional", "Key Added": "Schlüssel hinzugefügt", - "apiKeyAddedMsg": "Ihr API Schlüssel wurde hinzugefügt. Bitte notieren Sie Ihn, da er nicht erneut angezeigt wird.", + "apiKeyAddedMsg": "API Schlüssel wurde hinzugefügt. Bitte notiere den Schlüssel, da er nicht erneut angezeigt wird.", "telegramMessageThreadID": "(Optional) Nachrichten Thread ID", "telegramMessageThreadIDDescription": "Optionale eindeutige Kennung für den Ziel-Thread (Thema) des Forums; nur für Forum-Supergroups", "telegramSendSilently": "Stumm Senden", @@ -738,5 +738,10 @@ "Add New Tag": "Neuen Tag hinzufügen", "lunaseaDeviceID": "Geräte-ID", "lunaseaTarget": "Ziel", - "lunaseaUserID": "Benutzer-ID" + "lunaseaUserID": "Benutzer-ID", + "twilioAccountSID": "Account SID", + "twilioFromNumber": "Absender", + "twilioToNumber": "Empfänger", + "twilioAuthToken": "Auth Token", + "statusPageRefreshIn": "Aktualisierung in: {0}" } From 02291730fed212eb08d539d130b1e829e30e48e8 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Fri, 31 Mar 2023 04:04:17 +0800 Subject: [PATCH 17/26] WIP --- db/patch-maintenance-cron.sql | 9 + package-lock.json | 9 + package.json | 1 + server/database.js | 1 + server/model/maintenance.js | 232 ++++++++++-------- server/model/maintenance_timeslot.js | 67 ----- server/model/monitor.js | 26 +- .../maintenance-socket-handler.js | 41 ++-- server/uptime-kuma-server.js | 54 ++-- src/components/MaintenanceTime.vue | 6 +- src/lang/en.json | 4 + src/pages/EditMaintenance.vue | 76 ++++-- 12 files changed, 266 insertions(+), 260 deletions(-) create mode 100644 db/patch-maintenance-cron.sql diff --git a/db/patch-maintenance-cron.sql b/db/patch-maintenance-cron.sql new file mode 100644 index 000000000..55e45ddf5 --- /dev/null +++ b/db/patch-maintenance-cron.sql @@ -0,0 +1,9 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +-- 999 characters. https://stackoverflow.com/questions/46134830/maximum-length-for-cron-job +ALTER TABLE maintenance ADD cron TEXT; +ALTER TABLE maintenance ADD timezone VARCHAR(255); +ALTER TABLE maintenance ADD duration INTEGER; + +COMMIT; diff --git a/package-lock.json b/package-lock.json index d198105ec..27205042e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "compression": "~1.7.4", + "croner": "^6.0.3", "dayjs": "~1.11.5", "dotenv": "~16.0.3", "express": "~4.17.3", @@ -7243,6 +7244,14 @@ "yup": "0.32.9" } }, + "node_modules/croner": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/croner/-/croner-6.0.3.tgz", + "integrity": "sha512-Go+s9AaI+MeZUDJ6Kp7OYXCbM3svJ0qZ3IpkGoPetZLnP5wpX8MBTEiJOTYDFokP0Ph85GFZEUTBL9fo1e4DtQ==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", diff --git a/package.json b/package.json index a447b6a59..e92129258 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "compression": "~1.7.4", + "croner": "^6.0.3", "dayjs": "~1.11.5", "dotenv": "~16.0.3", "express": "~4.17.3", diff --git a/server/database.js b/server/database.js index e52ae8bfc..b678714e2 100644 --- a/server/database.js +++ b/server/database.js @@ -74,6 +74,7 @@ class Database { "patch-add-description-monitor.sql": true, "patch-api-key-table.sql": true, "patch-monitor-tls.sql": true, + "patch-maintenance-cron.sql": true, }; /** diff --git a/server/model/maintenance.js b/server/model/maintenance.js index 45db63d13..8f3f322c2 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -3,9 +3,15 @@ const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC, log } const { timeObjectToUTC, timeObjectToLocal } = require("../util-server"); const { R } = require("redbean-node"); const dayjs = require("dayjs"); +const Cron = require("croner"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const apicache = require("../modules/apicache"); class Maintenance extends BeanModel { + static statusList = {}; + static jobList = {}; + /** * Return an object that ready to parse to JSON for public * Only show necessary data to public @@ -15,16 +21,16 @@ class Maintenance extends BeanModel { let dateRange = []; if (this.start_date) { - dateRange.push(utcToLocal(this.start_date)); + dateRange.push(this.start_date); if (this.end_date) { - dateRange.push(utcToLocal(this.end_date)); + dateRange.push(this.end_date); } } let timeRange = []; - let startTime = timeObjectToLocal(parseTimeObject(this.start_time)); + let startTime = parseTimeObject(this.start_time); timeRange.push(startTime); - let endTime = timeObjectToLocal(parseTimeObject(this.end_time)); + let endTime = parseTimeObject(this.end_time); timeRange.push(endTime); let obj = { @@ -39,12 +45,18 @@ class Maintenance extends BeanModel { weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [], daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [], timeslotList: [], + cron: this.cron, + duration: this.duration, + timezone: await this.getTimezone(), + timezoneOffset: await this.getTimezoneOffset(), + status: await this.getStatus(), }; - const timeslotList = await this.getTimeslotList(); - - for (let timeslot of timeslotList) { - obj.timeslotList.push(await timeslot.toPublicJSON()); + if (this.strategy === "single") { + obj.timeslotList.push({ + startDate: this.start_date, + endDate: this.end_date, + }); } if (!Array.isArray(obj.weekdays)) { @@ -55,54 +67,9 @@ class Maintenance extends BeanModel { obj.daysOfMonth = []; } - // Maintenance Status - if (!obj.active) { - obj.status = "inactive"; - } else if (obj.strategy === "manual") { - obj.status = "under-maintenance"; - } else if (obj.timeslotList.length > 0) { - let currentTimestamp = dayjs().unix(); - - for (let timeslot of obj.timeslotList) { - if (dayjs.utc(timeslot.startDate).unix() <= currentTimestamp && dayjs.utc(timeslot.endDate).unix() >= currentTimestamp) { - log.debug("timeslot", "Timeslot ID: " + timeslot.id); - log.debug("timeslot", "currentTimestamp:" + currentTimestamp); - log.debug("timeslot", "timeslot.start_date:" + dayjs.utc(timeslot.startDate).unix()); - log.debug("timeslot", "timeslot.end_date:" + dayjs.utc(timeslot.endDate).unix()); - - obj.status = "under-maintenance"; - break; - } - } - - if (!obj.status) { - obj.status = "scheduled"; - } - } else if (obj.timeslotList.length === 0) { - obj.status = "ended"; - } else { - obj.status = "unknown"; - } - return obj; } - /** - * Only get future or current timeslots only - * @returns {Promise<[]>} - */ - async getTimeslotList() { - return R.convertToBeans("maintenance_timeslot", await R.getAll(` - SELECT maintenance_timeslot.* - FROM maintenance_timeslot, maintenance - WHERE maintenance_timeslot.maintenance_id = maintenance.id - AND maintenance.id = ? - AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()} - `, [ - this.id - ])); - } - /** * Return an object that ready to parse to JSON * @param {string} timezone If not specified, the timeRange will be in UTC @@ -135,26 +102,10 @@ class Maintenance extends BeanModel { } /** - * Get the start date and time for maintenance - * @returns {dayjs.Dayjs} Start date and time - */ - getStartDateTime() { - let startOfTheDay = dayjs.utc(this.start_date).format("HH:mm"); - log.debug("timeslot", "startOfTheDay: " + startOfTheDay); - - // Start Time - let startTimeSecond = dayjs.utc(this.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second"); - log.debug("timeslot", "startTime: " + startTimeSecond); - - // Bake StartDate + StartTime = Start DateTime - return dayjs.utc(this.start_date).add(startTimeSecond, "second"); - } - - /** - * Get the duraction of maintenance in seconds + * Get the duration of maintenance in seconds * @returns {number} Duration of maintenance */ - getDuration() { + calcDuration() { let duration = dayjs.utc(this.end_time, "HH:mm").diff(dayjs.utc(this.start_time, "HH:mm"), "second"); // Add 24hours if it is across day if (duration < 0) { @@ -169,30 +120,24 @@ class Maintenance extends BeanModel { * @param {Object} obj Data to fill bean with * @returns {Bean} Filled bean */ - static jsonToBean(bean, obj) { + static async jsonToBean(bean, obj) { if (obj.id) { bean.id = obj.id; } - // Apply timezone offset to timeRange, as it cannot apply automatically. - if (obj.timeRange[0]) { - timeObjectToUTC(obj.timeRange[0]); - if (obj.timeRange[1]) { - timeObjectToUTC(obj.timeRange[1]); - } - } - bean.title = obj.title; bean.description = obj.description; bean.strategy = obj.strategy; bean.interval_day = obj.intervalDay; + bean.timezone = obj.timezone; + bean.duration = obj.duration; bean.active = obj.active; if (obj.dateRange[0]) { - bean.start_date = localToUTC(obj.dateRange[0]); + bean.start_date = obj.dateRange[0]; if (obj.dateRange[1]) { - bean.end_date = localToUTC(obj.dateRange[1]); + bean.end_date = obj.dateRange[1]; } } @@ -202,38 +147,111 @@ class Maintenance extends BeanModel { bean.weekdays = JSON.stringify(obj.weekdays); bean.days_of_month = JSON.stringify(obj.daysOfMonth); + await bean.generateCron(); + return bean; } /** - * SQL conditions for active maintenance - * @returns {string} + * Run the cron */ - static getActiveMaintenanceSQLCondition() { - return ` - ( - (maintenance_timeslot.start_date <= DATETIME('now') - AND maintenance_timeslot.end_date >= DATETIME('now') - AND maintenance.active = 1) - OR - (maintenance.strategy = 'manual' AND active = 1) - ) - `; + async run() { + if (Maintenance.jobList[this.id]) { + log.debug("maintenance", "Maintenance is already running, stop it first. id: " + this.id); + this.stop(); + } + + log.debug("maintenance", "Run maintenance id: " + this.id); + + // 1.21.2 migration + if (!this.cron) { + //this.generateCron(); + //this.timezone = "UTC"; + // this.duration = + if (this.cron) { + //await R.store(this); + } + } + + if (this.strategy === "single") { + Maintenance.jobList[this.id] = new Cron(this.start_date, { timezone: await this.getTimezone() }, () => { + log.info("maintenance", "Maintenance id: " + this.id + " is under maintenance now"); + UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id); + apicache.clear(); + }); + } + } - /** - * SQL conditions for active and future maintenance - * @returns {string} - */ - static getActiveAndFutureMaintenanceSQLCondition() { - return ` - ( - ((maintenance_timeslot.end_date >= DATETIME('now') - AND maintenance.active = 1) - OR - (maintenance.strategy = 'manual' AND active = 1)) - ) - `; + stop() { + if (Maintenance.jobList[this.id]) { + Maintenance.jobList[this.id].stop(); + delete Maintenance.jobList[this.id]; + } + } + + async isUnderMaintenance() { + return (await this.getStatus()) === "under-maintenance"; + } + + async getTimezone() { + if (!this.timezone) { + return await UptimeKumaServer.getInstance().getTimezone(); + } + return this.timezone; + } + + async getTimezoneOffset() { + return dayjs.tz(dayjs(), await this.getTimezone()).format("Z"); + } + + async getStatus() { + if (!this.active) { + return "inactive"; + } + + if (this.strategy === "manual") { + return "under-maintenance"; + } + + // Check if the maintenance is started + if (this.start_date && dayjs().isBefore(dayjs.tz(this.start_date, await this.getTimezone()))) { + return "scheduled"; + } + + // Check if the maintenance is ended + if (this.end_date && dayjs().isAfter(dayjs.tz(this.end_date, await this.getTimezone()))) { + return "ended"; + } + + if (this.strategy === "single") { + return "under-maintenance"; + } + + if (!Maintenance.statusList[this.id]) { + Maintenance.statusList[this.id] = "unknown"; + } + + return Maintenance.statusList[this.id]; + } + + setStatus(status) { + Maintenance.statusList[this.id] = status; + } + + async generateCron() { + log.info("maintenance", "Generate cron for maintenance id: " + this.id); + + if (this.strategy === "recurring-interval") { + let array = this.start_time.split(":"); + let hour = parseInt(array[0]); + let minute = parseInt(array[1]); + this.cron = minute + " " + hour + " */" + this.interval_day + " * *"; + this.duration = this.calcDuration(); + log.debug("maintenance", "Cron: " + this.cron); + log.debug("maintenance", "Duration: " + this.duration); + } + } } diff --git a/server/model/maintenance_timeslot.js b/server/model/maintenance_timeslot.js index dad719c74..b86c4c1be 100644 --- a/server/model/maintenance_timeslot.js +++ b/server/model/maintenance_timeslot.js @@ -151,73 +151,6 @@ class MaintenanceTimeslot extends BeanModel { } } - static async isDuplicateTimeslot(timeslot) { - let bean = await R.findOne("maintenance_timeslot", "maintenance_id = ? AND start_date = ? AND end_date = ?", [ - timeslot.maintenance_id, - timeslot.start_date, - timeslot.end_date - ]); - return bean !== null; - } - - /** - * Generate a next timeslot for all recurring types - * @param maintenance - * @param minDate - * @param {function} nextDayCallback The logic how to get the next possible day - * @param {function} isValidCallback Check the day whether is matched the current strategy - * @returns {Promise} - */ - static async handleRecurringType(maintenance, minDate, nextDayCallback, isValidCallback) { - let bean = R.dispense("maintenance_timeslot"); - - let duration = maintenance.getDuration(); - let startDateTime = maintenance.getStartDateTime(); - let endDateTime; - - // Keep generating from the first possible date, until it is ok - while (true) { - //log.debug("timeslot", "startDateTime: " + startDateTime.format()); - - // Handling out of effective date range - if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { - log.debug("timeslot", "Out of effective date range"); - return null; - } - - endDateTime = startDateTime.add(duration, "second"); - - // If endDateTime is out of effective date range, use the end datetime from effective date range - if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { - endDateTime = dayjs.utc(maintenance.end_date); - } - - // If minDate is set, the endDateTime must be bigger than it. - // And the endDateTime must be bigger current time - // Is valid under current recurring strategy - if ( - (!minDate || endDateTime.diff(minDate) > 0) && - endDateTime.diff(dayjs()) > 0 && - isValidCallback(startDateTime) - ) { - break; - } - startDateTime = nextDayCallback(startDateTime); - } - - bean.maintenance_id = maintenance.id; - bean.start_date = localToUTC(startDateTime); - bean.end_date = localToUTC(endDateTime); - bean.generated_next = false; - - if (!await this.isDuplicateTimeslot(bean)) { - await R.store(bean); - return bean; - } else { - log.debug("maintenance", "Duplicate timeslot, skip"); - return null; - } - } } module.exports = MaintenanceTimeslot; diff --git a/server/model/monitor.js b/server/model/monitor.js index 44460819e..b4a0ba2a3 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -16,7 +16,6 @@ const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent"); const { DockerHost } = require("../docker"); -const Maintenance = require("./maintenance"); const { UptimeCacheList } = require("../uptime-cache-list"); const Gamedig = require("gamedig"); @@ -1303,18 +1302,19 @@ class Monitor extends BeanModel { * @returns {Promise} */ static async isUnderMaintenance(monitorID) { - let activeCondition = Maintenance.getActiveMaintenanceSQLCondition(); - const maintenance = await R.getRow(` - SELECT COUNT(*) AS count - FROM monitor_maintenance mm - JOIN maintenance - ON mm.maintenance_id = maintenance.id - AND mm.monitor_id = ? - LEFT JOIN maintenance_timeslot - ON maintenance_timeslot.maintenance_id = maintenance.id - WHERE ${activeCondition} - LIMIT 1`, [ monitorID ]); - return maintenance.count !== 0; + const maintenanceIDList = await R.getCol(` + SELECT maintenance_id FROM monitor_maintenance + WHERE monitor_id = ? + `, [ monitorID ]); + + for (const maintenanceID of maintenanceIDList) { + const maintenance = await UptimeKumaServer.getInstance().getMaintenance(maintenanceID); + if (maintenance && await maintenance.isUnderMaintenance()) { + return true; + } + } + + return false; } /** Make sure monitor interval is between bounds */ diff --git a/server/socket-handlers/maintenance-socket-handler.js b/server/socket-handlers/maintenance-socket-handler.js index 929150cdd..2b377f2ff 100644 --- a/server/socket-handlers/maintenance-socket-handler.js +++ b/server/socket-handlers/maintenance-socket-handler.js @@ -5,7 +5,6 @@ const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const Maintenance = require("../model/maintenance"); const server = UptimeKumaServer.getInstance(); -const MaintenanceTimeslot = require("../model/maintenance_timeslot"); /** * Handlers for Maintenance @@ -19,10 +18,12 @@ module.exports.maintenanceSocketHandler = (socket) => { log.debug("maintenance", maintenance); - let bean = Maintenance.jsonToBean(R.dispense("maintenance"), maintenance); + let bean = await Maintenance.jsonToBean(R.dispense("maintenance"), maintenance); bean.user_id = socket.userID; let maintenanceID = await R.store(bean); - await MaintenanceTimeslot.generateTimeslot(bean); + + server.maintenanceList[maintenanceID] = bean; + bean.run(); await server.sendMaintenanceList(socket); @@ -45,17 +46,15 @@ module.exports.maintenanceSocketHandler = (socket) => { try { checkLogin(socket); - let bean = await R.findOne("maintenance", " id = ? ", [ maintenance.id ]); + let bean = server.getMaintenance(maintenance.id); if (bean.user_id !== socket.userID) { throw new Error("Permission denied."); } - Maintenance.jsonToBean(bean, maintenance); - + await Maintenance.jsonToBean(bean, maintenance); await R.store(bean); - await MaintenanceTimeslot.generateTimeslot(bean, null, true); - + await bean.run(); await server.sendMaintenanceList(socket); callback({ @@ -236,6 +235,7 @@ module.exports.maintenanceSocketHandler = (socket) => { log.debug("maintenance", `Delete Maintenance: ${maintenanceID} User ID: ${socket.userID}`); if (maintenanceID in server.maintenanceList) { + server.maintenanceList[maintenanceID].stop(); delete server.maintenanceList[maintenanceID]; } @@ -267,9 +267,16 @@ module.exports.maintenanceSocketHandler = (socket) => { log.debug("maintenance", `Pause Maintenance: ${maintenanceID} User ID: ${socket.userID}`); - await R.exec("UPDATE maintenance SET active = 0 WHERE id = ? ", [ - maintenanceID, - ]); + let maintenance = server.getMaintenance(maintenanceID); + + if (!maintenance) { + throw new Error("Maintenance not found"); + } + + maintenance.active = false; + maintenance.setStatus("inactive"); + await R.store(maintenance); + maintenance.stop(); apicache.clear(); @@ -294,9 +301,15 @@ module.exports.maintenanceSocketHandler = (socket) => { log.debug("maintenance", `Resume Maintenance: ${maintenanceID} User ID: ${socket.userID}`); - await R.exec("UPDATE maintenance SET active = 1 WHERE id = ? ", [ - maintenanceID, - ]); + let maintenance = server.getMaintenance(maintenanceID); + + if (!maintenance) { + throw new Error("Maintenance not found"); + } + + maintenance.active = true; + await R.store(maintenance); + await maintenance.run(); apicache.clear(); diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index d28f00a92..914e12e48 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -47,8 +47,6 @@ class UptimeKumaServer { */ indexHTML = ""; - generateMaintenanceTimeslotsInterval = undefined; - /** * Plugins Manager * @type {PluginsManager} @@ -112,8 +110,7 @@ class UptimeKumaServer { log.debug("DEBUG", "Timezone: " + process.env.TZ); log.debug("DEBUG", "Current Time: " + dayjs.tz().format()); - await this.generateMaintenanceTimeslots(); - this.generateMaintenanceTimeslotsInterval = setInterval(this.generateMaintenanceTimeslots, 60 * 1000); + await this.loadMaintenanceList(); } /** @@ -175,16 +172,33 @@ class UptimeKumaServer { */ async getMaintenanceJSONList(userID) { let result = {}; + for (let maintenanceID in this.maintenanceList) { + result[maintenanceID] = await this.maintenanceList[maintenanceID].toJSON(); + } + return result; + } + + /** + * Load maintenance list and run + * @param userID + * @returns {Promise} + */ + async loadMaintenanceList(userID) { + let maintenanceList = await R.findAll("maintenance", " ORDER BY end_date DESC, title", [ - let maintenanceList = await R.find("maintenance", " user_id = ? ORDER BY end_date DESC, title", [ - userID, ]); for (let maintenance of maintenanceList) { - result[maintenance.id] = await maintenance.toJSON(); + this.maintenanceList[maintenance.id] = maintenance; + maintenance.run(this); } + } - return result; + getMaintenance(maintenanceID) { + if (this.maintenanceList[maintenanceID]) { + return this.maintenanceList[maintenanceID]; + } + return null; } /** @@ -240,7 +254,7 @@ class UptimeKumaServer { * Attempt to get the current server timezone * If this fails, fall back to environment variables and then make a * guess. - * @returns {string} + * @returns {Promise} */ async getTimezone() { let timezone = await Settings.get("serverTimezone"); @@ -271,28 +285,9 @@ class UptimeKumaServer { dayjs.tz.setDefault(timezone); } - /** Load the timeslots for maintenance */ - async generateMaintenanceTimeslots() { - log.debug("maintenance", "Routine: Generating Maintenance Timeslots"); - - // Prevent #2776 - // Remove duplicate maintenance_timeslot with same start_date, end_date and maintenance_id - await R.exec("DELETE FROM maintenance_timeslot WHERE id NOT IN (SELECT MIN(id) FROM maintenance_timeslot GROUP BY start_date, end_date, maintenance_id)"); - - let list = await R.find("maintenance_timeslot", " generated_next = 0 AND start_date <= DATETIME('now') "); - - for (let maintenanceTimeslot of list) { - let maintenance = await maintenanceTimeslot.maintenance; - await MaintenanceTimeslot.generateTimeslot(maintenance, maintenanceTimeslot.end_date, false); - maintenanceTimeslot.generated_next = true; - await R.store(maintenanceTimeslot); - } - - } - /** Stop the server */ async stop() { - clearTimeout(this.generateMaintenanceTimeslotsInterval); + } loadPlugins() { @@ -341,5 +336,4 @@ module.exports = { }; // Must be at the end -const MaintenanceTimeslot = require("./model/maintenance_timeslot"); const { MonitorType } = require("./monitor-types/monitor-type"); diff --git a/src/components/MaintenanceTime.vue b/src/components/MaintenanceTime.vue index 07d657400..6da21fe01 100644 --- a/src/components/MaintenanceTime.vue +++ b/src/components/MaintenanceTime.vue @@ -4,10 +4,10 @@ {{ $t("Manual") }}
- {{ maintenance.timeslotList[0].startDateServerTimezone }} + {{ maintenance.timeslotList[0].startDate }} - - {{ maintenance.timeslotList[0].endDateServerTimezone }} - (UTC{{ maintenance.timeslotList[0].serverTimezoneOffset }}) + {{ maintenance.timeslotList[0].endDate }} + (UTC{{ maintenance.timezoneOffset }})
diff --git a/src/lang/en.json b/src/lang/en.json index e7656c474..cf7185a89 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -394,6 +394,10 @@ "backupRecommend": "Please backup the volume or the data folder (./data/) directly instead.", "Optional": "Optional", "or": "or", + "sameAsServerTimezone": "Same as Server Timezone", + "startDateTime": "Start Date/Time", + "endDateTime": "End Date/Time", + "cronExpression": "Cron Expression", "recurringInterval": "Interval", "Recurring": "Recurring", "strategyManual": "Active/Inactive Manually", diff --git a/src/pages/EditMaintenance.vue b/src/pages/EditMaintenance.vue index 00e649381..be2abe8cb 100644 --- a/src/pages/EditMaintenance.vue +++ b/src/pages/EditMaintenance.vue @@ -85,14 +85,13 @@

{{ $t("Date and Time") }}

-
⚠️ {{ $t("warningTimezone") }}: {{ $root.info.serverTimezone }} ({{ $root.info.serverTimezoneOffset }})
-
@@ -103,6 +102,25 @@ + + From 524cf7c6077cf5a499709b789d95ea075add3b1e Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Fri, 31 Mar 2023 21:34:05 +0800 Subject: [PATCH 20/26] WIP --- server/model/maintenance.js | 3 +-- server/model/status_page.js | 25 ++++++++++--------------- src/pages/StatusPage.vue | 6 +++++- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/server/model/maintenance.js b/server/model/maintenance.js index c92f8189d..189a513aa 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -1,6 +1,5 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); -const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC, log } = require("../../src/util"); -const { timeObjectToUTC, timeObjectToLocal } = require("../util-server"); +const { parseTimeObject, parseTimeFromTimeObject, log } = require("../../src/util"); const { R } = require("redbean-node"); const dayjs = require("dayjs"); const Cron = require("croner"); diff --git a/server/model/status_page.js b/server/model/status_page.js index 84af99e88..65b77367e 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -3,7 +3,6 @@ const { R } = require("redbean-node"); const cheerio = require("cheerio"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const jsesc = require("jsesc"); -const Maintenance = require("./maintenance"); const googleAnalytics = require("../google-analytics"); class StatusPage extends BeanModel { @@ -290,21 +289,17 @@ class StatusPage extends BeanModel { try { const publicMaintenanceList = []; - let activeCondition = Maintenance.getActiveMaintenanceSQLCondition(); - let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(` - SELECT DISTINCT maintenance.* - FROM maintenance - JOIN maintenance_status_page - ON maintenance_status_page.maintenance_id = maintenance.id - AND maintenance_status_page.status_page_id = ? - LEFT JOIN maintenance_timeslot - ON maintenance_timeslot.maintenance_id = maintenance.id - WHERE ${activeCondition} - ORDER BY maintenance.end_date - `, [ statusPageId ])); + let maintenanceIDList = await R.getCol(` + SELECT DISTINCT maintenance_id + FROM maintenance_status_page + WHERE status_page_id = ? + `, [ statusPageId ]); - for (const bean of maintenanceBeanList) { - publicMaintenanceList.push(await bean.toPublicJSON()); + for (const maintenanceID of maintenanceIDList) { + let maintenance = UptimeKumaServer.getInstance().getMaintenance(maintenanceID); + if (maintenance && await maintenance.isUnderMaintenance()) { + publicMaintenanceList.push(await maintenance.toPublicJSON()); + } } return publicMaintenanceList; diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index b202be305..defa458e6 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -923,7 +923,11 @@ export default { * @returns {string} Sanitized HTML */ maintenanceHTML(description) { - return DOMPurify.sanitize(marked(description)); + if (description) { + return DOMPurify.sanitize(marked(description)); + } else { + return ""; + } }, } From 17ae47d091e60268fe4814c87153e9e03f077ec4 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Fri, 31 Mar 2023 23:52:24 +0800 Subject: [PATCH 21/26] Drop database backup logic, because duplicating a relative large database likely causes a disk space issue, users should take backup manually instead. --- server/database.js | 107 +-------------------------------------------- 1 file changed, 1 insertion(+), 106 deletions(-) diff --git a/server/database.js b/server/database.js index b678714e2..25e507503 100644 --- a/server/database.js +++ b/server/database.js @@ -199,15 +199,7 @@ class Database { } else { log.info("db", "Database patch is needed"); - try { - this.backup(version); - } catch (e) { - log.error("db", e); - log.error("db", "Unable to create a backup before patching the database. Please make sure you have enough space and permission."); - process.exit(1); - } - - // Try catch anything here, if gone wrong, restore the backup + // Try catch anything here try { for (let i = version + 1; i <= this.latestVersion; i++) { const sqlFile = `./db/patch${i}.sql`; @@ -223,7 +215,6 @@ class Database { log.error("db", "Start Uptime-Kuma failed due to issue patching the database"); log.error("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); - this.restore(); process.exit(1); } } @@ -265,8 +256,6 @@ class Database { log.error("db", "Start Uptime-Kuma failed due to issue patching the database"); log.error("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); - this.restore(); - process.exit(1); } @@ -451,100 +440,6 @@ class Database { process.removeListener("unhandledRejection", listener); } - /** - * One backup one time in this process. - * Reset this.backupPath if you want to backup again - * @param {string} version Version code of backup - */ - static backup(version) { - if (! this.backupPath) { - log.info("db", "Backing up the database"); - this.backupPath = this.dataDir + "kuma.db.bak" + version; - fs.copyFileSync(Database.path, this.backupPath); - - const shmPath = Database.path + "-shm"; - if (fs.existsSync(shmPath)) { - this.backupShmPath = shmPath + ".bak" + version; - fs.copyFileSync(shmPath, this.backupShmPath); - } - - const walPath = Database.path + "-wal"; - if (fs.existsSync(walPath)) { - this.backupWalPath = walPath + ".bak" + version; - fs.copyFileSync(walPath, this.backupWalPath); - } - - // Double confirm if all files actually backup - if (!fs.existsSync(this.backupPath)) { - throw new Error("Backup failed! " + this.backupPath); - } - - if (fs.existsSync(shmPath)) { - if (!fs.existsSync(this.backupShmPath)) { - throw new Error("Backup failed! " + this.backupShmPath); - } - } - - if (fs.existsSync(walPath)) { - if (!fs.existsSync(this.backupWalPath)) { - throw new Error("Backup failed! " + this.backupWalPath); - } - } - } - } - - /** Restore from most recent backup */ - static restore() { - if (this.backupPath) { - log.error("db", "Patching the database failed!!! Restoring the backup"); - - const shmPath = Database.path + "-shm"; - const walPath = Database.path + "-wal"; - - // Make sure we have a backup to restore before deleting old db - if ( - !fs.existsSync(this.backupPath) - && !fs.existsSync(shmPath) - && !fs.existsSync(walPath) - ) { - log.error("db", "Backup file not found! Leaving database in failed state."); - process.exit(1); - } - - // Delete patch failed db - try { - if (fs.existsSync(Database.path)) { - fs.unlinkSync(Database.path); - } - - if (fs.existsSync(shmPath)) { - fs.unlinkSync(shmPath); - } - - if (fs.existsSync(walPath)) { - fs.unlinkSync(walPath); - } - } catch (e) { - log.error("db", "Restore failed; you may need to restore the backup manually"); - process.exit(1); - } - - // Restore backup - fs.copyFileSync(this.backupPath, Database.path); - - if (this.backupShmPath) { - fs.copyFileSync(this.backupShmPath, shmPath); - } - - if (this.backupWalPath) { - fs.copyFileSync(this.backupWalPath, walPath); - } - - } else { - log.info("db", "Nothing to restore"); - } - } - /** Get the size of the database */ static getSize() { log.debug("db", "Database.getSize()"); From c01055efb36cfe42987c959e15cbefd23eb1e200 Mon Sep 17 00:00:00 2001 From: DevMirza Date: Wed, 29 Mar 2023 16:29:13 +0000 Subject: [PATCH 22/26] Translated using Weblate (Urdu) Currently translated at 62.4% (445 of 713 strings) Translation: Uptime Kuma/Uptime Kuma Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/ --- src/lang/ur.json | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lang/ur.json b/src/lang/ur.json index 7d591a596..0e364e3e0 100644 --- a/src/lang/ur.json +++ b/src/lang/ur.json @@ -270,7 +270,7 @@ "No Monitors": "کوئی مانیٹر نہیں", "Cancel": "منسوخ کریں", "Powered by": "کی طرف سے طاقت", - "Custom CSS": "حسب ضرورت سی ایس ایس", + "Custom CSS": "اپنی مرضی کے مطابق سی ایس ایس", "deleteProxyMsg": "کیا آپ واقعی اس پراکسی کو تمام مانیٹر کے لیے حذف کرنا چاہتے ہیں؟", "enableProxyDescription": "یہ پراکسی مانیٹر کی درخواستوں پر اس وقت تک اثر نہیں کرے گی جب تک کہ اسے فعال نہ کیا جائے۔ آپ ایکٹیویشن اسٹیٹس کے ذریعے تمام مانیٹرس سے پراکسی کو عارضی طور پر غیر فعال کر سکتے ہیں۔", "setAsDefaultProxyDescription": "یہ پراکسی نئے مانیٹرز کے لیے بطور ڈیفالٹ فعال ہو جائے گی۔ آپ اب بھی ہر مانیٹر کے لیے الگ الگ پراکسی کو غیر فعال کر سکتے ہیں۔", @@ -409,7 +409,7 @@ "maintenanceStatus-scheduled": "طے شدہ", "maintenanceStatus-ended": "ختم ہوا", "recurringInterval": "وقفہ", - "Recurring": "بار بار چلنے والا", + "Recurring": "بار چلنے والا", "strategyManual": "دستی طور پر فعال/غیر فعال", "warningTimezone": "یہ سرور کا ٹائم زون استعمال کر رہا ہے", "weekdayShortMon": "پیر", @@ -427,5 +427,25 @@ "lastDay4": "مہینے کا چوتھا آخری دن", "pauseMaintenanceMsg": "کیا آپ واقعی روکنا چاہتے ہیں؟", "No Maintenance": "کوئی دیکھ بھال نہیں", - "weekdayShortTue": "منگل" + "weekdayShortTue": "منگل", + "Add New Tag": "نیا ٹیگ شامل کریں", + "Enable DNS Cache": "ڈی این ایس کیشے کو فعال کریں", + "Effective Date Range": "مؤثر تاریخ کی حد", + "Schedule Maintenance": "شیڈول کی بحالی", + "Date and Time": "تاریخ اور وقت", + "DateTime Range": "تاریخ کے وقت کی حد", + "loadingError": "ڈیٹا حاصل نہیں کیا جا سکتا، براہ کرم بعد میں دوبارہ کوشش کریں۔", + "Enable": "فعال", + "Disable": "غیر فعال کریں", + "dnsCacheDescription": "ہو سکتا ہے یہ کچھ IPv6 ماحول میں کام نہ کر رہا ہو، اگر آپ کو کوئی مسئلہ درپیش ہو تو اسے غیر فعال کر دیں۔", + "Single Maintenance Window": "سنگل مینٹیننس ونڈو", + "Maintenance Time Window of a Day": "ایک دن کی مینٹیننس ٹائم ونڈو", + "plugin": "پلگ ان | پلگ انز", + "install": "انسٹال کریں", + "statusPageRefreshIn": "اس میں ریفریش کریں: {0}", + "maintenanceStatus-unknown": "نامعلوم", + "Display Timezone": "ٹائم زون ڈسپلے کریں", + "Server Timezone": "سرور ٹائم زون", + "statusPageMaintenanceEndDate": "ختم", + "IconUrl": "آئیکن یو آر ایل" } From e8d48561fc1c69b91419a3daeae48c74be7f7022 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Sat, 1 Apr 2023 01:45:16 +0800 Subject: [PATCH 23/26] Change `Retries` from `0` to `1` --- src/pages/EditMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index addcc7c94..0b8e55073 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -907,7 +907,7 @@ message HealthCheckResponse { interval: 60, retryInterval: this.interval, resendInterval: 0, - maxretries: 0, + maxretries: 1, notificationIDList: {}, ignoreTls: false, upsideDown: false, From 511038b45a4d57f605c3cfb792732fef89e14cff Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Sat, 1 Apr 2023 04:22:10 +0800 Subject: [PATCH 24/26] Remove unused code --- server/database.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/server/database.js b/server/database.js index 25e507503..8576bdedc 100644 --- a/server/database.js +++ b/server/database.js @@ -30,11 +30,6 @@ class Database { */ static patched = false; - /** - * For Backup only - */ - static backupPath = null; - /** * Add patch filename in key * Values: @@ -357,8 +352,6 @@ class Database { } } - this.backup(dayjs().format("YYYYMMDDHHmmss")); - log.info("db", sqlFilename + " is patching"); this.patched = true; await this.importSQLFile("./db/" + sqlFilename); From dbfaddafca84ec910b0eee57172ba7b05deac1dc Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Sat, 1 Apr 2023 16:30:55 +0800 Subject: [PATCH 25/26] Validate cron before submit --- server/model/maintenance.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/model/maintenance.js b/server/model/maintenance.js index 189a513aa..e3ce5d321 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -164,6 +164,7 @@ class Maintenance extends BeanModel { if (bean.strategy === "cron") { bean.duration = obj.durationMinutes * 60; bean.cron = obj.cron; + this.validateCron(bean.cron); } if (bean.strategy.startsWith("recurring-")) { @@ -172,11 +173,21 @@ class Maintenance extends BeanModel { bean.weekdays = JSON.stringify(obj.weekdays); bean.days_of_month = JSON.stringify(obj.daysOfMonth); await bean.generateCron(); + this.validateCron(bean.cron); } - return bean; } + /** + * Throw error if cron is invalid + * @param cron + * @returns {Promise} + */ + static async validateCron(cron) { + let job = new Cron(cron, () => {}); + job.stop(); + } + /** * Run the cron */ From 8f449ab738c19631e70e4c71709c4064ef088e3e Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Sat, 1 Apr 2023 16:36:51 +0800 Subject: [PATCH 26/26] Update to 1.21.2-beta.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b8bcbf69..39a7641c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "1.21.1", + "version": "1.21.2-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.21.1", + "version": "1.21.2-beta.0", "license": "MIT", "dependencies": { "@grpc/grpc-js": "~1.7.3", diff --git a/package.json b/package.json index 90e506436..55479549e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.21.1", + "version": "1.21.2-beta.0", "license": "MIT", "repository": { "type": "git",