v0.4.6: MariaDB validation fix + dashboard deployed-only + protected stack restart

- Fix ValidateDump() to scan first 10 lines for header (MariaDB 11.4+ sandbox comment)
- Dashboard shows only deployed/protected stacks, heading "Telepített alkalmazások"
- Protected stacks show restart button when operational (both dashboard + stacks page)
- API blocks all actions except restart on protected stacks
- docker-setup.sh creates .felhom.yml for FileBrowser (subdomain: files)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 08:44:34 +01:00
parent 24a2150520
commit fd627f3d55
6 changed files with 72 additions and 11 deletions
+6
View File
@@ -207,6 +207,12 @@ func (r *Router) deployStack(w http.ResponseWriter, req *http.Request, name stri
func (r *Router) actionStack(w http.ResponseWriter, action, name string) { func (r *Router) actionStack(w http.ResponseWriter, action, name string) {
r.logger.Printf("[API] %s requested for stack: %s", action, name) r.logger.Printf("[API] %s requested for stack: %s", action, name)
// Protected stacks only allow restart — block all other actions
if r.cfg.IsProtectedStack(name) && action != "restart" {
writeJSON(w, http.StatusForbidden, apiResponse{OK: false, Error: fmt.Sprintf("cannot %s protected stack %s", action, name)})
return
}
var err error var err error
switch action { switch action {
case "start": case "start":
+29 -9
View File
@@ -264,18 +264,38 @@ func ValidateDump(filePath string, dbType DBType) DumpValidation {
} }
v.TableCount = tableCount v.TableCount = tableCount
// Basic header check // Header check — scan first 10 lines for expected dump header
switch dbType { // MariaDB 11.4+ prepends a sandbox comment before the header line
case DBTypePostgres: headerFound := false
if !strings.HasPrefix(content, "--") { lines := strings.SplitN(content, "\n", 11) // at most 11 parts = 10 lines
v.Error = "PostgreSQL dump missing comment header" for i, line := range lines {
return v if i >= 10 {
break
} }
case DBTypeMariaDB: switch dbType {
if !strings.HasPrefix(content, "-- ") { case DBTypeMariaDB:
if strings.HasPrefix(line, "-- MariaDB dump") ||
strings.HasPrefix(line, "-- MySQL dump") ||
strings.HasPrefix(line, "-- mysqldump") {
headerFound = true
}
case DBTypePostgres:
if strings.HasPrefix(line, "-- PostgreSQL database dump") {
headerFound = true
}
}
if headerFound {
break
}
}
if !headerFound {
switch dbType {
case DBTypeMariaDB:
v.Error = "MariaDB dump missing comment header" v.Error = "MariaDB dump missing comment header"
return v case DBTypePostgres:
v.Error = "PostgreSQL dump missing comment header"
} }
return v
} }
if tableCount == 0 { if tableCount == 0 {
+9 -1
View File
@@ -36,10 +36,18 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, _ *http.Request) {
} }
} }
// Filter to deployed + protected stacks only for dashboard display
var deployedStacks []stacks.Stack
for _, st := range stackList {
if st.Deployed || st.Protected {
deployedStacks = append(deployedStacks, st)
}
}
sysInfo := system.GetInfo(s.cfg.Paths.HDDPath, s.cpuCollector) sysInfo := system.GetInfo(s.cfg.Paths.HDDPath, s.cpuCollector)
data := s.baseData("dashboard", "Vezérlőpult") data := s.baseData("dashboard", "Vezérlőpult")
data["Stacks"] = stackList data["Stacks"] = deployedStacks
data["RunningCount"] = running data["RunningCount"] = running
data["StoppedCount"] = stopped data["StoppedCount"] = stopped
data["TotalCount"] = len(stackList) data["TotalCount"] = len(stackList)
@@ -120,7 +120,7 @@
</div> </div>
{{end}} {{end}}
<h3>Alkalmazások állapota</h3> <h3>Telepített alkalmazások</h3>
<div class="stack-list"> <div class="stack-list">
{{range .Stacks}} {{range .Stacks}}
@@ -139,6 +139,9 @@
{{if .Protected}} {{if .Protected}}
<span class="badge badge-protected">Védett</span> <span class="badge badge-protected">Védett</span>
{{if isOperational .State}}
<button class="btn btn-sm btn-warning" onclick="stackAction('{{.Name}}', 'restart')"></button>
{{end}}
{{else if not .Deployed}} {{else if not .Deployed}}
<a href="/stacks/{{.Name}}/deploy" class="btn btn-sm btn-primary" onclick="return checkBeforeDeploy(event, '{{.Name}}')">Telepítés</a> <a href="/stacks/{{.Name}}/deploy" class="btn btn-sm btn-primary" onclick="return checkBeforeDeploy(event, '{{.Name}}')">Telepítés</a>
{{else}} {{else}}
@@ -59,6 +59,9 @@
<div class="stack-detail-actions"> <div class="stack-detail-actions">
{{if .Protected}} {{if .Protected}}
<span class="badge badge-protected">Védett rendszerkomponens</span> <span class="badge badge-protected">Védett rendszerkomponens</span>
{{if isOperational .State}}
<button class="btn btn-warning" onclick="stackAction('{{.Name}}', 'restart')">Újraindítás</button>
{{end}}
{{else if not .Deployed}} {{else if not .Deployed}}
<a href="/stacks/{{.Name}}/deploy" class="btn btn-primary" onclick="return checkBeforeDeploy(event, '{{.Name}}')">Telepítés</a> <a href="/stacks/{{.Name}}/deploy" class="btn btn-primary" onclick="return checkBeforeDeploy(event, '{{.Name}}')">Telepítés</a>
<a href="{{appPageURL .Meta.Slug}}" class="btn btn-outline">Részletek</a> <a href="{{appPageURL .Meta.Slug}}" class="btn btn-outline">Részletek</a>
+21
View File
@@ -1323,6 +1323,27 @@ networks:
external: true external: true
EOF EOF
# Create .felhom.yml metadata
cat > "${FILEBROWSER_DIR}/.felhom.yml" << 'METAEOF'
display_name: Filebrowser
slug: filebrowser
description: Fájlkezelő a külső merevlemezhez
subdomain: files
category: storage
app_info:
tagline: Web-alapú fájlkezelő a külső merevlemezhez
use_cases:
- Fájlok böngészése és letöltése a külső HDD-ről
- Médiafájlok megosztása családtagokkal
- Dokumentumok feltöltése és kezelése
first_steps:
- Nyisd meg a files.DOMAIN címet a böngészőben
- Jelentkezz be az admin fiókkal
- Tallózd a /srv mappákat
prerequisites:
- Külső HDD csatlakoztatva és felcsatolva
METAEOF
# Create .env file # Create .env file
cat > "${FILEBROWSER_DIR}/.env" << ENVEOF cat > "${FILEBROWSER_DIR}/.env" << ENVEOF
# FileBrowser environment — generated by docker-setup.sh # FileBrowser environment — generated by docker-setup.sh