Fix blog API endpoints and path issues

- Fix listLatestBlogs function to use correct blog directory path
- Add /data/blog-list.json endpoint for frontend blog listing
- Update remoteBlogDir references to use blogDir
- Resolve blog listing and admin interface loading issues
This commit is contained in:
Tomas Dvorak
2026-03-14 11:12:40 +01:00
parent 03b9abd32d
commit 3a7c1bbcba
+30 -11
View File
@@ -555,23 +555,23 @@ func extractSlug(path, filename string) string {
} }
func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) { func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) {
// REMOTE SERVER CONFIGURATION - UPDATE THIS PATH // Use the siteRoot path where blogs are actually located
remoteBlogDir := "/var/www/bizoni/blog" // Path to blogs on remote server blogDir := filepath.Join(siteRoot, "blog")
// For local development, you can override with environment variable // For local development, you can override with environment variable
if envPath := os.Getenv("REMOTE_BLOG_DIR"); envPath != "" { if envPath := os.Getenv("REMOTE_BLOG_DIR"); envPath != "" {
remoteBlogDir = envPath blogDir = envPath
} }
// If remote directory doesn't exist locally, try to sync or return error // If blog directory doesn't exist, return error
if _, err := os.Stat(remoteBlogDir); os.IsNotExist(err) { if _, err := os.Stat(blogDir); os.IsNotExist(err) {
return nil, fmt.Errorf("remote blog directory not found: %s. Set REMOTE_BLOG_DIR environment variable or ensure remote directory is mounted", remoteBlogDir) return nil, fmt.Errorf("blog directory not found: %s. Set REMOTE_BLOG_DIR environment variable or ensure blog directory exists", blogDir)
} }
imgDir := filepath.Join(filepath.Dir(remoteBlogDir), "img", "blog") imgDir := filepath.Join(filepath.Dir(blogDir), "img", "blog")
entries, err := os.ReadDir(remoteBlogDir) entries, err := os.ReadDir(blogDir)
if err != nil { if err != nil {
return nil, fmt.Errorf("readdir remote blog: %w", err) return nil, fmt.Errorf("readdir blog: %w", err)
} }
// Match both numeric (0001.html) and slug-based filenames // Match both numeric (0001.html) and slug-based filenames
re := regexp.MustCompile(`^(\d{4}|[a-z0-9-]+)\.html$`) re := regexp.MustCompile(`^(\d{4}|[a-z0-9-]+)\.html$`)
@@ -583,13 +583,13 @@ func listLatestBlogs(siteRoot string, limit int) ([]BlogItem, error) {
} }
id := strings.TrimSuffix(name, ".html") id := strings.TrimSuffix(name, ".html")
// Title and categories extraction from blog HTML // Title and categories extraction from blog HTML
blogPath := filepath.Join(remoteBlogDir, name) blogPath := filepath.Join(blogDir, name)
title := extractTitle(blogPath) title := extractTitle(blogPath)
slug := extractSlug(blogPath, name) slug := extractSlug(blogPath, name)
cats := extractCategories(blogPath) cats := extractCategories(blogPath)
// Determine mod time - prefer image modtime if exists, else html // Determine mod time - prefer image modtime if exists, else html
mtime := time.Time{} mtime := time.Time{}
htmlInfo, err1 := os.Stat(filepath.Join(remoteBlogDir, name)) htmlInfo, err1 := os.Stat(filepath.Join(blogDir, name))
if err1 == nil { if err1 == nil {
mtime = htmlInfo.ModTime() mtime = htmlInfo.ModTime()
} }
@@ -812,6 +812,25 @@ func main() {
w.Write([]byte(";")) w.Write([]byte(";"))
}) })
// Blog list JSON for frontend
mux.HandleFunc("/data/blog-list.json", func(w http.ResponseWriter, r *http.Request) {
okCORS(w)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
limit := 50 // Default limit for blog list
if q := r.URL.Query().Get("limit"); q != "" {
if n, err := strconv.Atoi(q); err == nil && n > 0 {
limit = n
}
}
items, err := listLatestBlogs(staticPath(), limit)
if err != nil {
log.Printf("blog-list.json error: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(items)
})
// Blog API: latest N posts from filesystem // Blog API: latest N posts from filesystem
mux.HandleFunc("/api/blog/latest", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/api/blog/latest", func(w http.ResponseWriter, r *http.Request) {
okCORS(w) okCORS(w)