mirror of
https://github.com/henrygd/beszel.git
synced 2026-03-22 21:46:18 +01:00
Compare commits
3 Commits
be70840609
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c159eaacd1 | ||
|
|
441bdd2ec5 | ||
|
|
ff36138229 |
@@ -28,8 +28,8 @@ func main() {
|
||||
}
|
||||
|
||||
baseApp := getBaseApp()
|
||||
h, _ := hub.NewHub(baseApp)
|
||||
if err := h.StartHub(); err != nil {
|
||||
hub := hub.NewHub(baseApp)
|
||||
if err := hub.StartHub(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,7 @@ func createTestHub(t testing.TB) (*Hub, *pbtests.TestApp, error) {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
h, err := NewHub(testApp)
|
||||
return h, testApp, err
|
||||
return NewHub(testApp), testApp, err
|
||||
}
|
||||
|
||||
// cleanupTestHub stops background system goroutines before tearing down the app.
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// Hub is the application. It embeds the PocketBase app and keeps references to subcomponents.
|
||||
type Hub struct {
|
||||
core.App
|
||||
*alerts.AlertManager
|
||||
@@ -46,7 +47,7 @@ type Hub struct {
|
||||
var containerIDPattern = regexp.MustCompile(`^[a-fA-F0-9]{12,64}$`)
|
||||
|
||||
// NewHub creates a new Hub instance with default configuration
|
||||
func NewHub(app core.App) (*Hub, error) {
|
||||
func NewHub(app core.App) *Hub {
|
||||
hub := &Hub{App: app}
|
||||
hub.AlertManager = alerts.NewAlertManager(hub)
|
||||
hub.um = users.NewUserManager(hub)
|
||||
@@ -56,7 +57,8 @@ func NewHub(app core.App) (*Hub, error) {
|
||||
if hub.hb != nil {
|
||||
hub.hbStop = make(chan struct{})
|
||||
}
|
||||
return hub, initialize(hub)
|
||||
_ = onAfterBootstrapAndMigrations(app, hub.initialize)
|
||||
return hub
|
||||
}
|
||||
|
||||
// GetEnv retrieves an environment variable with a "BESZEL_HUB_" prefix, or falls back to the unprefixed key.
|
||||
@@ -68,6 +70,26 @@ func GetEnv(key string) (value string, exists bool) {
|
||||
return os.LookupEnv(key)
|
||||
}
|
||||
|
||||
// onAfterBootstrapAndMigrations ensures the provided function runs after the database is set up and migrations are applied.
|
||||
// This is a workaround for behavior in PocketBase where onBootstrap runs before migrations, forcing use of onServe for this purpose.
|
||||
// However, PB's tests.TestApp is already bootstrapped, generally doesn't serve, but does handle migrations.
|
||||
// So this ensures that the provided function runs at the right time either way, after DB is ready and migrations are done.
|
||||
func onAfterBootstrapAndMigrations(app core.App, fn func(app core.App) error) error {
|
||||
// pb tests.TestApp is already bootstrapped and doesn't serve
|
||||
if app.IsBootstrapped() {
|
||||
return fn(app)
|
||||
}
|
||||
// Must use OnServe because OnBootstrap appears to run before migrations, even if calling e.Next() before anything else
|
||||
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
if err := fn(e.App); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Next()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartHub sets up event handlers and starts the PocketBase server
|
||||
func (h *Hub) StartHub() error {
|
||||
h.App.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
// sync systems with config
|
||||
@@ -112,24 +134,21 @@ func (h *Hub) StartHub() error {
|
||||
}
|
||||
|
||||
// initialize sets up initial configuration (collections, settings, etc.)
|
||||
func initialize(hub *Hub) error {
|
||||
if !hub.App.IsBootstrapped() {
|
||||
hub.App.Bootstrap()
|
||||
}
|
||||
func (h *Hub) initialize(app core.App) error {
|
||||
// set general settings
|
||||
settings := hub.App.Settings()
|
||||
settings := app.Settings()
|
||||
// batch requests (for alerts)
|
||||
settings.Batch.Enabled = true
|
||||
// set URL if APP_URL env is set
|
||||
if appURL, isSet := GetEnv("APP_URL"); isSet {
|
||||
hub.appURL = appURL
|
||||
settings.Meta.AppURL = hub.appURL
|
||||
h.appURL = appURL
|
||||
settings.Meta.AppURL = appURL
|
||||
}
|
||||
if err := hub.App.Save(settings); err != nil {
|
||||
if err := app.Save(settings); err != nil {
|
||||
return err
|
||||
}
|
||||
// set auth settings
|
||||
return setCollectionAuthSettings(hub.App)
|
||||
return setCollectionAuthSettings(app)
|
||||
}
|
||||
|
||||
// registerCronJobs sets up scheduled tasks
|
||||
@@ -141,7 +160,7 @@ func (h *Hub) registerCronJobs(_ *core.ServeEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// custom middlewares
|
||||
// registerMiddlewares registers custom middlewares
|
||||
func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
|
||||
// authorizes request with user matching the provided email
|
||||
authorizeRequestWithEmail := func(e *core.RequestEvent, email string) (err error) {
|
||||
@@ -172,7 +191,7 @@ func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
// custom api routes
|
||||
// registerApiRoutes registers custom API routes
|
||||
func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
||||
// auth protected routes
|
||||
apiAuth := se.Router.Group("/api/beszel")
|
||||
@@ -221,7 +240,7 @@ func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler for universal token API endpoint (create, read, delete)
|
||||
// GetUniversalToken handles the universal token API endpoint (create, read, delete)
|
||||
func (h *Hub) getUniversalToken(e *core.RequestEvent) error {
|
||||
tokenMap := universalTokenMap.GetMap()
|
||||
userID := e.Auth.Id
|
||||
@@ -430,7 +449,7 @@ func (h *Hub) refreshSmartData(e *core.RequestEvent) error {
|
||||
return e.JSON(http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
// generates key pair if it doesn't exist and returns signer
|
||||
// GetSSHKey generates key pair if it doesn't exist and returns signer
|
||||
func (h *Hub) GetSSHKey(dataDir string) (ssh.Signer, error) {
|
||||
if h.signer != nil {
|
||||
return h.signer, nil
|
||||
|
||||
@@ -7,6 +7,19 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<title>Beszel</title>
|
||||
<style>
|
||||
.dark { background: hsl(220 5.5% 9%); color-scheme: dark; }
|
||||
</style>
|
||||
<script>
|
||||
(function() {
|
||||
try {
|
||||
var theme = localStorage.getItem('ui-theme');
|
||||
var isDark = theme === 'dark' ||
|
||||
(theme !== 'light' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.add(isDark ? 'dark' : 'light');
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
globalThis.BESZEL = {
|
||||
BASE_PATH: "%BASE_URL%",
|
||||
|
||||
@@ -134,10 +134,10 @@ export function QuietHours() {
|
||||
const startMinutes = startDate.getUTCHours() * 60 + startDate.getUTCMinutes()
|
||||
const endMinutes = endDate.getUTCHours() * 60 + endDate.getUTCMinutes()
|
||||
|
||||
// Convert UTC to local time offset
|
||||
const offset = now.getTimezoneOffset()
|
||||
const localStartMinutes = (startMinutes - offset + 1440) % 1440
|
||||
const localEndMinutes = (endMinutes - offset + 1440) % 1440
|
||||
// Convert UTC to local time using the stored date's offset, not the current date's offset
|
||||
// This avoids DST mismatch when records were saved in a different DST period
|
||||
const localStartMinutes = (startMinutes - startDate.getTimezoneOffset() + 1440) % 1440
|
||||
const localEndMinutes = (endMinutes - endDate.getTimezoneOffset() + 1440) % 1440
|
||||
|
||||
// Handle cases where window spans midnight
|
||||
if (localStartMinutes <= localEndMinutes) {
|
||||
@@ -347,12 +347,13 @@ function QuietHoursDialog({
|
||||
|
||||
if (windowType === "daily") {
|
||||
// For daily windows, convert local time to UTC
|
||||
// Create a date with the time in local timezone, then convert to UTC
|
||||
const startDate = new Date(`2000-01-01T${startTime}:00`)
|
||||
// Use today's date so the current DST offset is applied (not a fixed historical date)
|
||||
const today = new Date().toISOString().split("T")[0]
|
||||
const startDate = new Date(`${today}T${startTime}:00`)
|
||||
startValue = startDate.toISOString()
|
||||
|
||||
if (endTime) {
|
||||
const endDate = new Date(`2000-01-01T${endTime}:00`)
|
||||
const endDate = new Date(`${today}T${endTime}:00`)
|
||||
endValue = endDate.toISOString()
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -52,10 +52,7 @@ func NewTestHubWithConfig(config core.BaseAppConfig) (*TestHub, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hub, err := hub.NewHub(testApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hub := hub.NewHub(testApp)
|
||||
|
||||
t := &TestHub{
|
||||
App: testApp,
|
||||
|
||||
Reference in New Issue
Block a user