mirror of
https://github.com/Dvorinka/PPve.git
synced 2026-06-03 20:12:59 +00:00
fef
This commit is contained in:
+47
-32
@@ -1459,15 +1459,36 @@ function loadHardcodedApps() {
|
||||
|
||||
// Load dynamic apps
|
||||
async function loadDynamicApps() {
|
||||
const dynamicAppsList = document.getElementById('dynamicAppsList');
|
||||
console.log("Loading dynamic apps...");
|
||||
const dynamicAppsContainer = document.getElementById('dynamicApps');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/apps');
|
||||
if (!response.ok) throw new Error('Nepodařilo se načíst seznam aplikací');
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
window.location.href = '/login.html';
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/apps', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
// Token expired or invalid, redirect to login
|
||||
window.location.href = '/login.html';
|
||||
return;
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const apps = await response.json();
|
||||
console.log("Loaded dynamic apps:", apps);
|
||||
|
||||
if (apps.length === 0) {
|
||||
if (!Array.isArray(apps) || apps.length === 0) {
|
||||
dynamicAppsList.innerHTML = `
|
||||
<div class="text-center py-8">
|
||||
<i class="fas fa-inbox text-4xl text-gray-300 mb-2"></i>
|
||||
@@ -1477,7 +1498,8 @@ async function loadDynamicApps() {
|
||||
return;
|
||||
}
|
||||
|
||||
dynamicAppsList.innerHTML = apps
|
||||
// Filter out hardcoded apps and map to HTML
|
||||
const dynamicApps = apps
|
||||
.filter(app => !app.id || !app.id.startsWith('hardcoded-'))
|
||||
.map(app => `
|
||||
<div class="bg-white rounded-lg shadow p-4 flex items-center justify-between" data-app-id="${app.id}">
|
||||
@@ -1489,43 +1511,34 @@ async function loadDynamicApps() {
|
||||
</div>`
|
||||
}
|
||||
<div>
|
||||
<h4 class="font-medium">${app.name}</h4>
|
||||
<p class="text-sm text-gray-500">${app.url}</p>
|
||||
${app.description ? `<p class="text-sm text-gray-400">${app.description}</p>` : ''}
|
||||
<h4 class="font-medium">${app.name || 'Neznámá aplikace'}</h4>
|
||||
<p class="text-sm text-gray-500">${app.url || ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<button class="edit-app-btn p-2 text-blue-500 hover:text-blue-700" data-app-id="${app.id}">
|
||||
<button onclick="editApp('${app.id}')" class="text-blue-500 hover:text-blue-700">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="delete-app-btn p-2 text-red-500 hover:text-red-700" data-app-id="${app.id}">
|
||||
<button onclick="deleteApp('${app.id}')" class="text-red-500 hover:text-red-700">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// Add event listeners to buttons
|
||||
document.querySelectorAll('.edit-app-btn').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const appId = btn.dataset.appId;
|
||||
editApp(appId);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.delete-app-btn').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const appId = btn.dataset.appId;
|
||||
if (confirm('Opravdu chcete tuto aplikaci smazat?')) {
|
||||
deleteApp(appId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
if (dynamicApps.length > 0) {
|
||||
dynamicAppsList.innerHTML = dynamicApps;
|
||||
} else {
|
||||
dynamicAppsList.innerHTML = `
|
||||
<div class="text-center py-8">
|
||||
<i class="fas fa-inbox text-4xl text-gray-300 mb-2"></i>
|
||||
<p class="text-gray-500">Žádné vlastní aplikace nebyly nalezeny</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Chyba při načítání vlastních aplikací:', error);
|
||||
console.error('Error loading dynamic apps:', error);
|
||||
dynamicAppsList.innerHTML = `
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4">
|
||||
<div class="flex">
|
||||
@@ -1533,7 +1546,9 @@ async function loadDynamicApps() {
|
||||
<i class="fas fa-exclamation-circle text-red-400"></i>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm text-red-700">Chyba při načítání vlastních aplikací: ${error.message}</p>
|
||||
<p class="text-sm text-red-700">
|
||||
Chyba při načítání aplikací: ${error.message}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -65,6 +65,60 @@ func main() {
|
||||
kontaktURL, _ := url.Parse("http://webportal:8080")
|
||||
kontaktProxy := httputil.NewSingleHostReverseProxy(kontaktURL)
|
||||
|
||||
// CORS middleware
|
||||
corsMiddleware := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Allow all origins for development
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
origin = "*"
|
||||
}
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
|
||||
// Handle preflight requests
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Auth middleware
|
||||
authMiddleware := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Skip auth for GET requests and OPTIONS
|
||||
if r.Method == "GET" || r.Method == "OPTIONS" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for Authorization header
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
http.Error(w, "Missing authorization token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Verify token (in a real app, you would validate this against your auth system)
|
||||
tokenParts := strings.Split(authHeader, " ")
|
||||
if len(tokenParts) != 2 || tokenParts[0] != "Bearer" {
|
||||
http.Error(w, "Invalid authorization header format", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// In a real app, you would validate the token here
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Apply CORS middleware to all routes
|
||||
r.Use(corsMiddleware)
|
||||
|
||||
// Public routes
|
||||
r.PathPrefix("/kontakt/").Handler(http.StripPrefix("/kontakt", kontaktProxy))
|
||||
r.PathPrefix("/uploads/").Handler(http.StripPrefix("/uploads/", http.FileServer(http.Dir("./uploads"))))
|
||||
@@ -76,9 +130,15 @@ func main() {
|
||||
// Authentication routes
|
||||
r.HandleFunc("/api/login", LoginHandler).Methods("POST", "OPTIONS")
|
||||
|
||||
// Protected API routes
|
||||
// Public endpoints (must be defined before protected ones)
|
||||
r.HandleFunc("/api/banner", GetBannerHandler).Methods("GET", "OPTIONS")
|
||||
r.HandleFunc("/submit", handleSubmit).Methods("POST", "OPTIONS") // Public submit endpoint for evidence-aut.html
|
||||
|
||||
// Protected API routes with auth middleware
|
||||
api := r.PathPrefix("/api").Subrouter()
|
||||
api.Use(AuthMiddleware)
|
||||
api.Use(authMiddleware)
|
||||
|
||||
// Protected API endpoints
|
||||
api.HandleFunc("/submit", handleSubmit).Methods("POST")
|
||||
api.HandleFunc("/banner/update", UpdateBannerHandler).Methods("POST", "OPTIONS")
|
||||
|
||||
@@ -89,27 +149,9 @@ func main() {
|
||||
api.HandleFunc("/apps/{id}", UpdateAppHandler).Methods("PUT")
|
||||
api.HandleFunc("/apps/{id}", DeleteAppHandler).Methods("DELETE")
|
||||
|
||||
// Public endpoints
|
||||
r.HandleFunc("/api/banner", GetBannerHandler).Methods("GET", "OPTIONS")
|
||||
|
||||
// Important: This public submit endpoint must be defined BEFORE the static file server
|
||||
r.HandleFunc("/submit", handleSubmit).Methods("POST", "OPTIONS") // Public submit endpoint for evidence-aut.html
|
||||
|
||||
// Add CORS middleware for API
|
||||
r.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
})
|
||||
// Serve static files (must be the last route)
|
||||
fs := http.FileServer(http.Dir("."))
|
||||
r.PathPrefix("/").Handler(fs)
|
||||
|
||||
// Admin routes
|
||||
r.HandleFunc("/admin", func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -132,31 +174,12 @@ func main() {
|
||||
http.ServeFile(w, r, "evidence-aut.html")
|
||||
}).Methods("GET")
|
||||
|
||||
// Contact page route
|
||||
r.HandleFunc("/kontakt", contactHandler).Methods("GET")
|
||||
|
||||
// Static file server for public files - must be the last route defined
|
||||
fs := http.FileServer(http.Dir("."))
|
||||
r.PathPrefix("/").Handler(fs)
|
||||
|
||||
r.HandleFunc("/kontakt", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Check if kontakt service is already running
|
||||
resp, err := http.Get("http://webportal:8080/health")
|
||||
if err == nil && resp.StatusCode == 200 {
|
||||
http.Redirect(w, r, "http://webportal:8080/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
// Start the service if not running
|
||||
cmd := exec.Command("make", "dev")
|
||||
cmd.Dir = "kontakt"
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to start kontakt service", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Wait briefly for service to start
|
||||
time.Sleep(2 * time.Second)
|
||||
http.Redirect(w, r, "http://webportal:8080/", http.StatusFound)
|
||||
}).Methods("GET")
|
||||
fileServer := http.FileServer(http.Dir("."))
|
||||
r.PathPrefix("/").Handler(fileServer)
|
||||
|
||||
// Apply CORS middleware to all routes
|
||||
handler := enableCORS(r)
|
||||
@@ -173,6 +196,29 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// contactHandler handles the contact page request
|
||||
func contactHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Check if kontakt service is already running
|
||||
resp, err := http.Get("http://webportal:8080/health")
|
||||
if err == nil && resp.StatusCode == 200 {
|
||||
http.Redirect(w, r, "http://webportal:8080/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
// Start the service if not running
|
||||
cmd := exec.Command("make", "dev")
|
||||
cmd.Dir = "kontakt"
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to start kontakt service", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Wait briefly for service to start
|
||||
time.Sleep(2 * time.Second)
|
||||
http.Redirect(w, r, "http://webportal:8080/", http.StatusFound)
|
||||
}
|
||||
|
||||
func enableCORS(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
@@ -238,6 +284,24 @@ func saveApps(apps []App) error {
|
||||
|
||||
// App Handlers
|
||||
func GetAppsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Set CORS headers
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
|
||||
// Handle preflight requests
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// Only allow GET requests
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Load apps from JSON file
|
||||
apps, err := loadApps()
|
||||
if err != nil {
|
||||
log.Printf("Error loading apps: %v", err)
|
||||
@@ -483,8 +547,9 @@ func UpdateAppHandler(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.FormValue("url")
|
||||
description := r.FormValue("description")
|
||||
|
||||
// Handle file upload if a new file is provided
|
||||
var iconPath string
|
||||
|
||||
// Handle file upload
|
||||
file, handler, err := r.FormFile("icon")
|
||||
if err == nil {
|
||||
defer file.Close()
|
||||
|
||||
Reference in New Issue
Block a user