Add DB management in settings and re-enable TPDB server path
This commit is contained in:
parent
4ff7708f76
commit
4067f9b793
|
|
@ -480,7 +480,7 @@ var webCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
defer database.Close()
|
defer database.Close()
|
||||||
|
|
||||||
server, err := web.NewServer(database, addr)
|
server, err := web.NewServer(database, addr, dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create web server: %w", err)
|
return fmt.Errorf("failed to create web server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -33,9 +34,10 @@ type Server struct {
|
||||||
db *db.DB
|
db *db.DB
|
||||||
templates *template.Template
|
templates *template.Template
|
||||||
addr string
|
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")
|
tmpl, err := template.ParseFS(content, "templates/*.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse templates: %w", err)
|
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,
|
db: database,
|
||||||
templates: tmpl,
|
templates: tmpl,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
|
dbPath: dbPath,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,6 +94,7 @@ func (s *Server) Start() error {
|
||||||
|
|
||||||
// Settings endpoints
|
// Settings endpoints
|
||||||
mux.HandleFunc("/api/settings/api-keys", s.handleAPISettingsKeys)
|
mux.HandleFunc("/api/settings/api-keys", s.handleAPISettingsKeys)
|
||||||
|
mux.HandleFunc("/api/settings/database", s.handleAPIDatabase)
|
||||||
|
|
||||||
// API
|
// API
|
||||||
mux.HandleFunc("/api/import/performer", s.handleAPIImportPerformer)
|
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{}{
|
data := map[string]interface{}{
|
||||||
"PageTitle": "Settings",
|
"PageTitle": "Settings",
|
||||||
"ActivePage": "settings",
|
"ActivePage": "settings",
|
||||||
|
"DBPath": s.dbPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.render(w, "settings.html", data)
|
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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,16 @@
|
||||||
|
|
||||||
<div id="settings-status" class="status-banner" style="margin-top: 1rem;"></div>
|
<div id="settings-status" class="status-banner" style="margin-top: 1rem;"></div>
|
||||||
</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>
|
</main>
|
||||||
|
|
||||||
{{template "html-scripts" .}}
|
{{template "html-scripts" .}}
|
||||||
|
|
@ -90,6 +100,48 @@
|
||||||
el.style.display = msg ? 'block' : 'none';
|
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);
|
document.addEventListener('DOMContentLoaded', loadApiKeys);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user