commit
242e494cb5
@ -0,0 +1,26 @@
|
|||||||
|
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
|
||||||
|
FROM node:14-alpine3.12 AS release
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# split the sqlite install here, so that it can caches the arm prebuilt
|
||||||
|
RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev git && \
|
||||||
|
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||||
|
npm install mapbox/node-sqlite3#593c9d && \
|
||||||
|
apk del .build-deps && \
|
||||||
|
rm -f /usr/bin/python
|
||||||
|
|
||||||
|
# Install apprise
|
||||||
|
RUN apk add --no-cache python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib
|
||||||
|
RUN pip3 --no-cache-dir install apprise && \
|
||||||
|
rm -rf /root/.cache
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm install --legacy-peer-deps && npm run build && npm prune
|
||||||
|
|
||||||
|
EXPOSE 3001
|
||||||
|
VOLUME ["/app/data"]
|
||||||
|
HEALTHCHECK --interval=600s --timeout=130s --start-period=300s CMD node extra/healthcheck.js
|
||||||
|
CMD ["node", "server/server.js"]
|
||||||
|
|
||||||
|
FROM release AS nightly
|
||||||
|
RUN npm run mark-as-nightly
|
@ -1,19 +1,31 @@
|
|||||||
let http = require("http");
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
|
let client;
|
||||||
|
|
||||||
|
if (process.env.SSL_KEY && process.env.SSL_CERT) {
|
||||||
|
client = require("https");
|
||||||
|
} else {
|
||||||
|
client = require("http");
|
||||||
|
}
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
host: "localhost",
|
host: process.env.HOST || "127.0.0.1",
|
||||||
port: "3001",
|
port: parseInt(process.env.PORT) || 3001,
|
||||||
timeout: 2000,
|
timeout: 120 * 1000,
|
||||||
};
|
};
|
||||||
let request = http.request(options, (res) => {
|
|
||||||
console.log(`STATUS: ${res.statusCode}`);
|
let request = client.request(options, (res) => {
|
||||||
if (res.statusCode == 200) {
|
console.log(`Health Check OK [Res Code: ${res.statusCode}]`);
|
||||||
|
if (res.statusCode === 200) {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
request.on("error", function (err) {
|
request.on("error", function (err) {
|
||||||
console.log("ERROR");
|
console.error("Health Check ERROR");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
request.end();
|
request.end();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* For Client Socket
|
||||||
|
*/
|
||||||
|
const { TimeLogger } = require("../src/util");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const { io } = require("./server");
|
||||||
|
|
||||||
|
async function sendNotificationList(socket) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
let list = await R.find("notification", " user_id = ? ", [
|
||||||
|
socket.userID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (let bean of list) {
|
||||||
|
result.push(bean.export())
|
||||||
|
}
|
||||||
|
|
||||||
|
io.to(socket.userID).emit("notificationList", result)
|
||||||
|
|
||||||
|
timeLogger.print("Send Notification List");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Heartbeat History list to socket
|
||||||
|
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
|
* @param overwrite Overwrite client-side's heartbeat list
|
||||||
|
*/
|
||||||
|
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let list = await R.find("heartbeat", `
|
||||||
|
monitor_id = ?
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 100
|
||||||
|
`, [
|
||||||
|
monitorID,
|
||||||
|
])
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
for (let bean of list) {
|
||||||
|
result.unshift(bean.toJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toUser) {
|
||||||
|
io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
|
||||||
|
} else {
|
||||||
|
socket.emit("heartbeatList", monitorID, result, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
timeLogger.print(`[Monitor: ${monitorID}] sendHeartbeatList`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Important Heart beat list (aka event list)
|
||||||
|
* @param socket
|
||||||
|
* @param monitorID
|
||||||
|
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
|
* @param overwrite Overwrite client-side's heartbeat list
|
||||||
|
*/
|
||||||
|
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let list = await R.find("heartbeat", `
|
||||||
|
monitor_id = ?
|
||||||
|
AND important = 1
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 500
|
||||||
|
`, [
|
||||||
|
monitorID,
|
||||||
|
])
|
||||||
|
|
||||||
|
timeLogger.print(`[Monitor: ${monitorID}] sendImportantHeartbeatList`);
|
||||||
|
|
||||||
|
if (toUser) {
|
||||||
|
io.to(socket.userID).emit("importantHeartbeatList", monitorID, list, overwrite);
|
||||||
|
} else {
|
||||||
|
socket.emit("importantHeartbeatList", monitorID, list, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sendNotificationList,
|
||||||
|
sendImportantHeartbeatList,
|
||||||
|
sendHeartbeatList,
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<!--
|
||||||
|
Hack - Disable Chrome save password
|
||||||
|
readonly + onfocus
|
||||||
|
https://stackoverflow.com/questions/41217019/how-to-prevent-a-browser-from-storing-passwords
|
||||||
|
-->
|
||||||
|
<input
|
||||||
|
v-model="model"
|
||||||
|
:type="visibility"
|
||||||
|
class="form-control"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:autocomplete="autocomplete"
|
||||||
|
:required="required"
|
||||||
|
:readonly="isReadOnly"
|
||||||
|
@focus="removeReadOnly"
|
||||||
|
>
|
||||||
|
|
||||||
|
<a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()">
|
||||||
|
<font-awesome-icon icon="eye" />
|
||||||
|
</a>
|
||||||
|
<a v-if="visibility == 'text'" class="btn btn-outline-primary" @click="hideInput()">
|
||||||
|
<font-awesome-icon icon="eye-slash" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: Number,
|
||||||
|
default: 255
|
||||||
|
},
|
||||||
|
autocomplete: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visibility: "password",
|
||||||
|
readOnlyValue: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
model: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$emit("update:modelValue", value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isReadOnly() {
|
||||||
|
// Actually readonly from prop
|
||||||
|
if (this.readonly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hack - Disable Chrome save password
|
||||||
|
return this.readOnlyValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// Hack - Disable Chrome save password
|
||||||
|
if (this.autocomplete) {
|
||||||
|
this.readOnlyValue = "readonly";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showInput() {
|
||||||
|
this.visibility = "text";
|
||||||
|
},
|
||||||
|
hideInput() {
|
||||||
|
this.visibility = "password";
|
||||||
|
},
|
||||||
|
|
||||||
|
// Hack - Disable Chrome save password
|
||||||
|
removeReadOnly() {
|
||||||
|
if (this.autocomplete) {
|
||||||
|
this.readOnlyValue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,10 +1,10 @@
|
|||||||
import { library } from "@fortawesome/fontawesome-svg-core"
|
import { library } from "@fortawesome/fontawesome-svg-core"
|
||||||
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp } from "@fortawesome/free-solid-svg-icons"
|
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"
|
||||||
//import { fa } from '@fortawesome/free-regular-svg-icons'
|
//import { fa } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
|
||||||
|
|
||||||
// Add Free Font Awesome Icons here
|
// Add Free Font Awesome Icons here
|
||||||
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
|
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
|
||||||
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp);
|
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash);
|
||||||
|
|
||||||
export { FontAwesomeIcon }
|
export { FontAwesomeIcon }
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Polski",
|
||||||
|
checkEverySecond: "Sprawdzaj co {0} sekund.",
|
||||||
|
"Avg.": "Średnia ",
|
||||||
|
retriesDescription: "Maksymalna liczba powtórzeń, zanim usługa zostanie oznaczona jako wyłączona i zostanie wysłane powiadomienie",
|
||||||
|
ignoreTLSError: "Ignoruj błąd TLS/SSL dla stron HTTPS",
|
||||||
|
upsideDownModeDescription: "Odwróć status do góry nogami. Jeśli usługa jest osiągalna, to jest oznaczona jako niedostępna.",
|
||||||
|
maxRedirectDescription: "Maksymalna liczba przekierowań do wykonania. Ustaw na 0, aby wyłączyć przekierowania.",
|
||||||
|
acceptedStatusCodesDescription: "Wybierz kody stanu, które są uważane za udaną odpowiedź.",
|
||||||
|
passwordNotMatchMsg: "Powtórzone hasło nie pasuje.",
|
||||||
|
notificationDescription: "Proszę przypisać powiadomienie do monitora(ów), aby zadziałało.",
|
||||||
|
keywordDescription: "Wyszukiwanie słów kluczowych w zwykłym html lub odpowiedzi JSON. Wielkość liter ma znaczenie.",
|
||||||
|
pauseDashboardHome: "Pauza",
|
||||||
|
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
||||||
|
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
||||||
|
resoverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
||||||
|
rrtypeDescription: "Wybierz RR-Type który chcesz monitorować",
|
||||||
|
pauseMonitorMsg: "Czy na pewno chcesz wstrzymać?",
|
||||||
|
Settings: "Ustawienia",
|
||||||
|
Dashboard: "Panel",
|
||||||
|
"New Update": "Nowa aktualizacja",
|
||||||
|
Language: "Język",
|
||||||
|
Appearance: "Wygląd",
|
||||||
|
Theme: "Motyw",
|
||||||
|
General: "Ogólne",
|
||||||
|
Version: "Wersja",
|
||||||
|
"Check Update On GitHub": "Sprawdź aktualizację na GitHub.",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Dodaj",
|
||||||
|
"Add New Monitor": "Dodaj nowy monitor",
|
||||||
|
"Quick Stats": "Szybkie statystyki",
|
||||||
|
Up: "Online",
|
||||||
|
Down: "Offline",
|
||||||
|
Pending: "Oczekujący",
|
||||||
|
Unknown: "Nieznane",
|
||||||
|
Pause: "Pauza",
|
||||||
|
Name: "Nazwa",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Data i godzina",
|
||||||
|
Message: "Wiadomość",
|
||||||
|
"No important events": "Brak ważnych wydarzeń",
|
||||||
|
Resume: "Wznów",
|
||||||
|
Edit: "Edytuj",
|
||||||
|
Delete: "Usuń",
|
||||||
|
Current: "aktualny",
|
||||||
|
Uptime: "Czas pracy",
|
||||||
|
"Cert Exp.": "Wygaśnięcie certyfikatu",
|
||||||
|
days: "dni",
|
||||||
|
day: "dzień",
|
||||||
|
"-day": " dni",
|
||||||
|
hour: "godzina",
|
||||||
|
"-hour": " godziny",
|
||||||
|
Response: "Odpowiedź",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Typ monitora",
|
||||||
|
Keyword: "Słowo kluczowe",
|
||||||
|
"Friendly Name": "Przyjazna nazwa",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Nazwa hosta",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Interwał bicia serca",
|
||||||
|
Retries: "Prób",
|
||||||
|
Advanced: "Zaawansowane",
|
||||||
|
"Upside Down Mode": "Tryb do góry nogami",
|
||||||
|
"Max. Redirects": "Maks. przekierowania",
|
||||||
|
"Accepted Status Codes": "Akceptowane kody statusu",
|
||||||
|
Save: "Zapisz",
|
||||||
|
Notifications: "Powiadomienia",
|
||||||
|
"Not available, please setup.": "Niedostępne, proszę skonfigurować.",
|
||||||
|
"Setup Notification": "Konfiguracja powiadomień",
|
||||||
|
Light: "Jasny",
|
||||||
|
Dark: "Ciemny",
|
||||||
|
Auto: "Automatyczny",
|
||||||
|
"Theme - Heartbeat Bar": "Motyw - pasek bicia serca",
|
||||||
|
Normal: "Normalne",
|
||||||
|
Bottom: "Na dole",
|
||||||
|
None: "Brak",
|
||||||
|
Timezone: "Strefa czasowa",
|
||||||
|
"Search Engine Visibility": "Widoczność w wyszukiwarce",
|
||||||
|
"Allow indexing": "Pozwól na indeksowanie",
|
||||||
|
"Discourage search engines from indexing site": "Zniechęcaj wyszukiwarki do indeksowania strony",
|
||||||
|
"Change Password": "Zmień hasło",
|
||||||
|
"Current Password": "Aktualne hasło",
|
||||||
|
"New Password": "Nowe hasło",
|
||||||
|
"Repeat New Password": "Powtórz nowe hasło",
|
||||||
|
"Update Password": "Zaktualizuj hasło",
|
||||||
|
"Disable Auth": "Wyłącz autoryzację",
|
||||||
|
"Enable Auth": "Włącz autoryzację ",
|
||||||
|
Logout: "Wyloguj się",
|
||||||
|
Leave: "Zostaw",
|
||||||
|
"I understand, please disable": "Rozumiem, proszę wyłączyć",
|
||||||
|
Confirm: "Potwierdź",
|
||||||
|
Yes: "Tak",
|
||||||
|
No: "Nie",
|
||||||
|
Username: "Nazwa użytkownika",
|
||||||
|
Password: "Hasło",
|
||||||
|
"Remember me": "Zapamiętaj mnie",
|
||||||
|
Login: "Zaloguj się",
|
||||||
|
"No Monitors, please": "Brak monitorów, proszę",
|
||||||
|
"add one": "dodaj jeden",
|
||||||
|
"Notification Type": "Typ powiadomienia",
|
||||||
|
Email: "Email",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Informacje o certyfikacie",
|
||||||
|
"Resolver Server": "Server resolver",
|
||||||
|
"Resource Record Type": "Typ rekordu zasobów",
|
||||||
|
"Last Result": "Ostatni wynik",
|
||||||
|
"Create your admin account": "Utwórz swoje konto administratora",
|
||||||
|
"Repeat Password": "Powtórz hasło",
|
||||||
|
respTime: "Czas odp. (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
Create: "Stwórz"
|
||||||
|
}
|
Loading…
Reference in new issue