Ponkhy
3 years ago
committed by
GitHub
36 changed files with 1219 additions and 595 deletions
@ -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
@ -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