Add DB management in settings and re-enable TPDB server path

This commit is contained in:
Stu Leak 2025-12-04 12:35:17 -05:00
parent 4ff7708f76
commit 4067f9b793
3 changed files with 96 additions and 2 deletions

View File

@ -480,7 +480,7 @@ var webCmd = &cobra.Command{
}
defer database.Close()
server, err := web.NewServer(database, addr)
server, err := web.NewServer(database, addr, dbPath)
if err != nil {
return fmt.Errorf("failed to create web server: %w", err)
}

View File

@ -9,6 +9,7 @@ import (
"io/fs"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
@ -33,9 +34,10 @@ type Server struct {
db *db.DB
templates *template.Template
addr string
dbPath string
}
func NewServer(database *db.DB, addr string) (*Server, error) {
func NewServer(database *db.DB, addr string, dbPath string) (*Server, error) {
tmpl, err := template.ParseFS(content, "templates/*.html")
if err != nil {
return nil, fmt.Errorf("failed to parse templates: %w", err)
@ -45,6 +47,7 @@ func NewServer(database *db.DB, addr string) (*Server, error) {
db: database,
templates: tmpl,
addr: addr,
dbPath: dbPath,
}, nil
}
@ -91,6 +94,7 @@ func (s *Server) Start() error {
// Settings endpoints
mux.HandleFunc("/api/settings/api-keys", s.handleAPISettingsKeys)
mux.HandleFunc("/api/settings/database", s.handleAPIDatabase)
// API
mux.HandleFunc("/api/import/performer", s.handleAPIImportPerformer)
@ -1369,6 +1373,7 @@ func (s *Server) handleSettingsPage(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{
"PageTitle": "Settings",
"ActivePage": "settings",
"DBPath": s.dbPath,
}
s.render(w, "settings.html", data)
@ -1427,3 +1432,40 @@ func (s *Server) handleAPISettingsKeys(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
// Database management
func (s *Server) handleAPIDatabase(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
info := map[string]interface{}{
"path": s.dbPath,
}
if stat, err := os.Stat(s.dbPath); err == nil {
info["size_bytes"] = stat.Size()
info["size_mb"] = float64(stat.Size()) / (1024 * 1024)
}
json.NewEncoder(w).Encode(APIResponse{
Success: true,
Message: "OK",
Data: info,
})
case http.MethodDelete:
// Close and recreate
if s.db != nil {
_ = s.db.Close()
}
_ = os.Remove(s.dbPath)
newDB, err := db.Open(s.dbPath)
if err != nil {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: fmt.Sprintf("Failed to recreate DB: %v", err)})
return
}
s.db = newDB
json.NewEncoder(w).Encode(APIResponse{
Success: true,
Message: "Database deleted and recreated.",
})
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}

View File

@ -34,6 +34,16 @@
<div id="settings-status" class="status-banner" style="margin-top: 1rem;"></div>
</div>
<div class="gx-card" style="margin-top: 1.5rem; padding: 1.5rem; border: 1px solid #ff8a8a;">
<h4 style="color: #ff8a8a;">Database Maintenance</h4>
<p class="help-text">Current database: <code>{{.DBPath}}</code></p>
<div class="action-buttons" style="margin-top: 0.75rem;">
<button class="btn-secondary" onclick="loadDbInfo()">Refresh Info<div class="hoverEffect"><div></div></div></button>
<button class="btn" style="background: #ff4d4d;" onclick="confirmDeleteDb()">Delete Database<div class="hoverEffect"><div></div></div></button>
</div>
<div id="db-info" class="status-banner" style="margin-top: 0.75rem;"></div>
</div>
</main>
{{template "html-scripts" .}}
@ -90,6 +100,48 @@
el.style.display = msg ? 'block' : 'none';
}
async function loadDbInfo() {
try {
const res = await fetch('/api/settings/database');
const result = await res.json();
if (result.success && result.data) {
const d = result.data;
const el = document.getElementById('db-info');
el.textContent = `Path: ${d.path || ''} | Size: ${ (d.size_mb || 0).toFixed ? (d.size_mb.toFixed(2) + ' MB') : 'n/a'}`;
el.classList.remove('error');
el.style.display = 'block';
}
} catch (err) {
const el = document.getElementById('db-info');
el.textContent = 'Error loading DB info: ' + err.message;
el.classList.add('error');
el.style.display = 'block';
}
}
async function confirmDeleteDb() {
if (!confirm('This will DELETE the database file and recreate an empty one. Continue?')) return;
try {
const res = await fetch('/api/settings/database', { method: 'DELETE' });
const result = await res.json();
const el = document.getElementById('db-info');
if (result.success) {
el.textContent = result.message;
el.classList.remove('error');
el.style.display = 'block';
} else {
el.textContent = result.message || 'Failed to delete DB';
el.classList.add('error');
el.style.display = 'block';
}
} catch (err) {
const el = document.getElementById('db-info');
el.textContent = 'Error deleting DB: ' + err.message;
el.classList.add('error');
el.style.display = 'block';
}
}
document.addEventListener('DOMContentLoaded', loadApiKeys);
</script>
</body>