package main import ( "fmt" "log" "net/http" "os" "path/filepath" "strings" "github.com/gorilla/mux" "github.com/jinzhu/gorm" "github.com/rs/cors" ) var ( db *gorm.DB // Declare db globally config *Config ) func main() { configFile := os.Getenv("BOXES_API_CONFIG") var err error config, err = LoadConfig(configFile) // get the static files directory staticPath := config.StaticFilesDir // Add this before setting up the handler if _, err := os.Stat(staticPath); os.IsNotExist(err) { log.Fatalf("Static directory does not exist: %s", staticPath) } // Get the allowed origins from the ALLOWED_ORIGINS environment variable // If empty, defaults to http://localhost:3000 allowedOrigins := config.AllowedOrigins fmt.Println("Allowed origins: ", allowedOrigins) origins := []string{"http://localhost:3000"} // Default value if allowedOrigins != "" { // Split the comma-separated string into a slice of strings origins = strings.Split(allowedOrigins, ",") fmt.Println("Listening for connections from: ", origins) } // check for errors if err != nil || config == nil { log.Fatalf("Failed to load config: %v", err) } fmt.Println(config.DatabasePath) fmt.Println(config.ImageStorageDir) fmt.Println(config.JWTSecret) fmt.Println(config.LogFile) fmt.Println(config.ListeningPort) // Connect to the database db, err = ConnectDB(config.DatabasePath) if err != nil || db == nil { log.Fatalf("Failed to connect to database: %v", err) } defer db.Close() customHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Don't handle /static/ paths here - let the static file server handle those if strings.HasPrefix(r.URL.Path, "/static/") { http.NotFound(w, r) return } // For all other routes, serve index.html indexPath := filepath.Join(staticPath, "index.html") http.ServeFile(w, r, indexPath) }) // Register the catch-all handler for non-static routes staticRouter.PathPrefix("/").Handler(customHandler) fmt.Println("Default user 'boxuser' created successfully!") // Create the router baseRouter := mux.NewRouter() router := baseRouter.PathPrefix("/api/v1").Subrouter() // Define your routes router.Handle("/login", http.HandlerFunc(LoginHandler)).Methods("POST", "OPTIONS") router.Handle("/boxes", AuthMiddleware(http.HandlerFunc(GetBoxesHandler))).Methods("GET", "OPTIONS") router.Handle("/boxes", AuthMiddleware(http.HandlerFunc(CreateBoxHandler))).Methods("POST", "OPTIONS") router.Handle("/boxes/{id}", AuthMiddleware(http.HandlerFunc(DeleteBoxHandler))).Methods("DELETE", "OPTIONS") router.Handle("/boxes/{id}", AuthMiddleware(http.HandlerFunc(GetBoxHandler))).Methods("GET", "OPTIONS") router.Handle("/items", AuthMiddleware(http.HandlerFunc(GetItemsHandler))).Methods("GET", "OPTIONS") router.Handle("/items", AuthMiddleware(http.HandlerFunc(CreateItemHandler))).Methods("POST", "OPTIONS") router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(GetItemHandler))).Methods("GET", "OPTIONS") router.Handle("/boxes/{id}/items", AuthMiddleware(http.HandlerFunc(GetItemsInBoxHandler))).Methods("GET", "OPTIONS") router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(UpdateItemHandler))).Methods("PUT", "OPTIONS") router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(DeleteItemHandler))).Methods("DELETE", "OPTIONS") router.Handle("/items/{id}/image", AuthMiddleware(http.HandlerFunc(GetItemImageHandler))).Methods("GET", "OPTIONS") fmt.Println("Registering route for search items...") router.Handle("/search/items", AuthMiddleware(http.HandlerFunc(SearchItemsHandler))).Methods("GET", "OPTIONS") // Add a new route for uploading an image with AuthMiddleware router.HandleFunc("/items/{id}/upload", UploadItemImageHandler). Methods("POST"). Handler(AuthMiddleware(http.HandlerFunc(UploadItemImageHandler))) managementRouter := router.PathPrefix("/admin").Subrouter() managementRouter.Use(AuthMiddleware) managementRouter.Handle("/user", http.HandlerFunc(GetUsersHandler)).Methods("GET", "OPTIONS") managementRouter.Handle("/user", http.HandlerFunc(CreateUserHandler)).Methods("POST", "OPTIONS") managementRouter.Handle("/user/{id}", http.HandlerFunc(GetUserHandler)).Methods("GET", "OPTIONS") managementRouter.Handle("/user/{id}", http.HandlerFunc(DeleteUserHandler)).Methods("DELETE", "OPTIONS") managementRouter.Handle("/db", http.HandlerFunc(BackupDatabaseHandler)).Methods("GET", "OPTIONS") managementRouter.Handle("/db", http.HandlerFunc(RestoreDatabaseHandler)).Methods("POST", "OPTIONS") managementRouter.Handle("/imagearchive", http.HandlerFunc(GetImageArchiveHandler)).Methods("GET", "OPTIONS") // Define a route for serving static files fmt.Println("Serving static files from:", staticPath) //staticHandler := http.FileServer(http.Dir(staticPath)) fmt.Println("Registering route for serving static files, no StripPrefix") //staticRouter.HandleFunc("/", customHandler).Methods("GET", "OPTIONS") // perplexity recommends: //staticRouter.PathPrefix("/").Handler(http.StripPrefix("/", customHandler)) // Replace your existing static route with this // Create a dedicated file server for static files fileServer := http.FileServer(http.Dir(staticPath)) // Register the static file handler with explicit path stripping //staticRouter.PathPrefix("/static/").Handler(http.StripPrefix("/static/", staticFS)) baseRouter.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fileServer)) baseRouter.PathPrefix("/").Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Don't handle /static/ paths here if strings.HasPrefix(r.URL.Path, "/static/") { http.NotFound(w, r) return } // For all other routes, serve index.html indexPath := filepath.Join(staticPath, "index.html") http.ServeFile(w, r, indexPath) })) // Apply CORS middleware c := cors.New(cors.Options{ AllowedOrigins: origins, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Authorization", "Content-Type"}, ExposedHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma", "ETag"}, AllowCredentials: true, }) // Start the server with CORS middleware fmt.Printf("Server listening on port %d\n", config.ListeningPort) http.ListenAndServe(fmt.Sprintf(":%d", config.ListeningPort), c.Handler(baseRouter)) }