diff --git a/internal/httpcontroller/auth_routes.go b/internal/httpcontroller/auth_routes.go index 2112f811..35751cfb 100644 --- a/internal/httpcontroller/auth_routes.go +++ b/internal/httpcontroller/auth_routes.go @@ -18,13 +18,13 @@ func (s *Server) initAuthRoutes() { g.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(10))) // OAuth2 routes - g.GET("/oauth2/authorize", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthorize)) - g.POST("/oauth2/token", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthToken)) - g.GET("/callback", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthCallback)) + g.GET("/api/v1/oauth2/authorize", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthorize)) + g.POST("/api/v1/oauth2/token", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthToken)) + g.GET("/api/v1/oauth2/callback", s.Handlers.WithErrorHandling(s.OAuth2Server.HandleBasicAuthCallback)) // Social authentication routes - g.GET("/auth/:provider", s.Handlers.WithErrorHandling(handleGothProvider)) - g.GET("/auth/:provider/callback", s.Handlers.WithErrorHandling(handleGothCallback)) + g.GET("/api/v1/auth/:provider", s.Handlers.WithErrorHandling(handleGothProvider)) + g.GET("/api/v1/auth/:provider/callback", s.Handlers.WithErrorHandling(handleGothCallback)) // Basic authentication routes g.GET("/login", s.Handlers.WithErrorHandling(s.handleLoginPage)) @@ -127,7 +127,7 @@ func (s *Server) handleBasicAuthLogin(c echo.Context) error { if !isValidRedirect(redirect) { redirect = "/" } - redirectURL := fmt.Sprintf("/callback?code=%s&redirect=%s", authCode, redirect) + redirectURL := fmt.Sprintf("/api/v1/oauth2/callback?code=%s&redirect=%s", authCode, redirect) c.Response().Header().Set("HX-Redirect", redirectURL) return c.String(http.StatusOK, "") } diff --git a/internal/httpcontroller/handlers/audio_level_sse.go b/internal/httpcontroller/handlers/audio_level_sse.go index c6b6f37c..f559e736 100644 --- a/internal/httpcontroller/handlers/audio_level_sse.go +++ b/internal/httpcontroller/handlers/audio_level_sse.go @@ -142,7 +142,8 @@ func checkSourceActivity(levels map[string]myaudio.AudioLevelData, lastUpdateTim return updated } -// AudioLevelSSE handles Server-Sent Events for real-time audio level updates +// AudioLevelSSE handles Server-Sent Events for audio level monitoring +// API: GET /api/v1/audio-level func (h *Handlers) AudioLevelSSE(c echo.Context) error { clientIP := c.RealIP() diff --git a/internal/httpcontroller/handlers/detections.go b/internal/httpcontroller/handlers/detections.go index dcbeb3ff..c72d6f2c 100644 --- a/internal/httpcontroller/handlers/detections.go +++ b/internal/httpcontroller/handlers/detections.go @@ -38,6 +38,7 @@ type NoteWithWeather struct { } // ListDetections handles requests for hourly, species-specific, and search detections +// API: GET /api/v1/detections func (h *Handlers) Detections(c echo.Context) error { req := new(DetectionRequest) if err := c.Bind(req); err != nil { @@ -168,7 +169,8 @@ func (h *Handlers) Detections(c echo.Context) error { return nil } -// getNoteHandler retrieves a single note from the database and renders it. +// DetectionDetails retrieves a single detection from the database and renders it. +// API: GET /api/v1/detections/details func (h *Handlers) DetectionDetails(c echo.Context) error { noteID := c.QueryParam("id") if noteID == "" { @@ -210,6 +212,7 @@ func (h *Handlers) DetectionDetails(c echo.Context) error { } // RecentDetections handles requests for the latest detections. +// API: GET /api/v1/detections/recent func (h *Handlers) RecentDetections(c echo.Context) error { h.Debug("RecentDetections: Starting handler") @@ -317,6 +320,7 @@ func (h *Handlers) addWeatherAndTimeOfDay(notes []datastore.Note) ([]NoteWithWea } // DeleteDetection handles the deletion of a detection and its associated files +// API: DELETE /api/v1/detections/delete func (h *Handlers) DeleteDetection(c echo.Context) error { id := c.QueryParam("id") @@ -481,6 +485,7 @@ func (h *Handlers) processComment(noteID uint, comment string, maxRetries int, b } // processReview handles the review status update and related operations +// API: POST /api/v1/detections/review func (h *Handlers) processReview(noteID uint, verified string, lockDetection bool, maxRetries int, baseDelay time.Duration) error { h.Debug("processReview: Starting review process for note ID %d", noteID) h.Debug("processReview: Verified status: %s", verified) @@ -585,6 +590,8 @@ func (h *Handlers) processReview(noteID uint, verified string, lockDetection boo return lastErr } +// ReviewDetection handles the review status update and related operations +// API: POST /api/v1/detections/review func (h *Handlers) ReviewDetection(c echo.Context) error { id := c.FormValue("id") if id == "" { @@ -657,6 +664,7 @@ func (h *Handlers) ReviewDetection(c echo.Context) error { } // LockDetection handles the locking and unlocking of detections +// API: POST /api/v1/detections/lock func (h *Handlers) LockDetection(c echo.Context) error { id := c.QueryParam("id") if id == "" { diff --git a/internal/httpcontroller/handlers/media.go b/internal/httpcontroller/handlers/media.go index e5ec2658..10c9463f 100644 --- a/internal/httpcontroller/handlers/media.go +++ b/internal/httpcontroller/handlers/media.go @@ -220,6 +220,7 @@ func (h *Handlers) ThumbnailAttribution(scientificName string) template.HTML { } // ServeSpectrogram serves or generates a spectrogram for a given clip. +// API: GET /api/v1/media/spectrogram func (h *Handlers) ServeSpectrogram(c echo.Context) error { h.Debug("ServeSpectrogram: Handler called with URL: %s", c.Request().URL.String()) @@ -231,6 +232,7 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { sanitizedClipName, err := h.sanitizeClipName(clipName) if err != nil { h.Debug("ServeSpectrogram: Error sanitizing clip name: %v", err) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } h.Debug("ServeSpectrogram: Sanitized clip name: %s", sanitizedClipName) @@ -243,10 +245,12 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { exists, err := fileExists(fullPath) if err != nil { h.Debug("ServeSpectrogram: Error checking audio file: %v", err) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } if !exists { h.Debug("ServeSpectrogram: Audio file not found: %s", fullPath) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } h.Debug("ServeSpectrogram: Audio file exists at: %s", fullPath) @@ -255,6 +259,7 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { spectrogramPath, err := h.getSpectrogramPath(fullPath, 400) // Assuming 400px width if err != nil { h.Debug("ServeSpectrogram: Error getting spectrogram path: %v", err) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } h.Debug("ServeSpectrogram: Final spectrogram path: %s", spectrogramPath) @@ -263,6 +268,7 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { exists, err = fileExists(spectrogramPath) if err != nil { h.Debug("ServeSpectrogram: Error checking spectrogram file: %v", err) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } if !exists { @@ -270,6 +276,7 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { // Try to create the spectrogram if err := createSpectrogramWithSoX(fullPath, spectrogramPath, 400); err != nil { h.Debug("ServeSpectrogram: Failed to create spectrogram: %v", err) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } h.Debug("ServeSpectrogram: Successfully created spectrogram at: %s", spectrogramPath) @@ -279,10 +286,14 @@ func (h *Handlers) ServeSpectrogram(c echo.Context) error { exists, _ = fileExists(spectrogramPath) if !exists { h.Debug("ServeSpectrogram: Spectrogram still not found after creation attempt: %s", spectrogramPath) + c.Response().Header().Set(echo.HeaderContentType, "image/svg+xml") return c.File("assets/images/spectrogram-placeholder.svg") } h.Debug("ServeSpectrogram: Serving spectrogram file: %s", spectrogramPath) + // Set the correct Content-Type header for PNG images + c.Response().Header().Set(echo.HeaderContentType, "image/png") + c.Response().Header().Set("Cache-Control", "public, max-age=2592000, immutable") // Cache spectrograms for 30 days return c.File(spectrogramPath) } @@ -584,6 +595,7 @@ func sanitizeContentDispositionFilename(filename string) string { } // ServeAudioClip serves an audio clip file +// API: GET /api/v1/media/audio func (h *Handlers) ServeAudioClip(c echo.Context) error { h.Debug("ServeAudioClip: Starting to handle request for path: %s", c.Request().URL.String()) diff --git a/internal/httpcontroller/handlers/mqtt.go b/internal/httpcontroller/handlers/mqtt.go index f337b7b6..0cf39563 100644 --- a/internal/httpcontroller/handlers/mqtt.go +++ b/internal/httpcontroller/handlers/mqtt.go @@ -33,6 +33,7 @@ const ( ) // TestMQTT handles requests to test MQTT connectivity and functionality +// API: GET/POST /api/v1/mqtt/test func (h *Handlers) TestMQTT(c echo.Context) error { // Define a struct for the test configuration type TestConfig struct { diff --git a/internal/httpcontroller/handlers/settings.go b/internal/httpcontroller/handlers/settings.go index 65d007ea..99d35097 100644 --- a/internal/httpcontroller/handlers/settings.go +++ b/internal/httpcontroller/handlers/settings.go @@ -31,6 +31,7 @@ var fieldsToSkip = map[string]bool{ } // GetAudioDevices handles the request to list available audio devices +// API: GET /api/v1/settings/audio/get func (h *Handlers) GetAudioDevices(c echo.Context) error { devices, err := myaudio.ListAudioSources() @@ -45,6 +46,7 @@ func (h *Handlers) GetAudioDevices(c echo.Context) error { } // SaveSettings handles the request to save settings +// API: POST /api/v1/settings/save func (h *Handlers) SaveSettings(c echo.Context) error { settings := conf.Setting() if settings == nil { diff --git a/internal/httpcontroller/handlers/sse.go b/internal/httpcontroller/handlers/sse.go index 41321eb7..bbfd1723 100644 --- a/internal/httpcontroller/handlers/sse.go +++ b/internal/httpcontroller/handlers/sse.go @@ -33,6 +33,8 @@ func NewSSEHandler() *SSEHandler { } } +// ServeSSE handles Server-Sent Events connections +// API: GET /api/v1/sse func (h *SSEHandler) ServeSSE(c echo.Context) error { h.Debug("SSE: New connection request from %s", c.Request().RemoteAddr) diff --git a/internal/httpcontroller/routes.go b/internal/httpcontroller/htmx_routes.go similarity index 73% rename from internal/httpcontroller/routes.go rename to internal/httpcontroller/htmx_routes.go index 3a2ab0d5..ccbee5d3 100644 --- a/internal/httpcontroller/routes.go +++ b/internal/httpcontroller/htmx_routes.go @@ -88,14 +88,14 @@ func (s *Server) initRoutes() { // Partial routes (HTMX responses) s.partialRoutes = map[string]PartialRouteConfig{ - "/detections": {Path: "/detections", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.Detections)}, - "/detections/recent": {Path: "/detections/recent", TemplateName: "recentDetections", Title: "Recent Detections", Handler: h.WithErrorHandling(h.RecentDetections)}, - "/detections/details": {Path: "/detections/details", TemplateName: "detectionDetails", Title: "Detection Details", Handler: h.WithErrorHandling(h.DetectionDetails)}, - "/top-birds": {Path: "/top-birds", TemplateName: "birdsTableHTML", Title: "Top Birds", Handler: h.WithErrorHandling(h.TopBirds)}, - "/notes": {Path: "/notes", TemplateName: "notes", Title: "All Notes", Handler: h.WithErrorHandling(h.GetAllNotes)}, - "/media/spectrogram": {Path: "/media/spectrogram", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.ServeSpectrogram)}, - "/media/audio": {Path: "/media/audio", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.ServeAudioClip)}, - "/login": {Path: "/login", TemplateName: "login", Title: "Login", Handler: h.WithErrorHandling(s.handleLoginPage)}, + "/api/v1/detections": {Path: "/api/v1/detections", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.Detections)}, + "/api/v1/detections/recent": {Path: "/api/v1/detections/recent", TemplateName: "recentDetections", Title: "Recent Detections", Handler: h.WithErrorHandling(h.RecentDetections)}, + "/api/v1/detections/details": {Path: "/api/v1/detections/details", TemplateName: "detectionDetails", Title: "Detection Details", Handler: h.WithErrorHandling(h.DetectionDetails)}, + "/api/v1/top-birds": {Path: "/api/v1/top-birds", TemplateName: "birdsTableHTML", Title: "Top Birds", Handler: h.WithErrorHandling(h.TopBirds)}, + "/api/v1/notes": {Path: "/api/v1/notes", TemplateName: "notes", Title: "All Notes", Handler: h.WithErrorHandling(h.GetAllNotes)}, + "/api/v1/media/spectrogram": {Path: "/api/v1/media/spectrogram", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.ServeSpectrogram)}, + "/api/v1/media/audio": {Path: "/api/v1/media/audio", TemplateName: "", Title: "", Handler: h.WithErrorHandling(h.ServeAudioClip)}, + "/login": {Path: "/login", TemplateName: "login", Title: "Login", Handler: h.WithErrorHandling(s.handleLoginPage)}, } // Set up partial routes @@ -103,7 +103,7 @@ func (s *Server) initRoutes() { s.Echo.GET(route.Path, func(c echo.Context) error { // If the request is a hx-request or media request, call the partial route handler if c.Request().Header.Get("HX-Request") != "" || - strings.HasPrefix(c.Request().URL.Path, "/media/") { + strings.HasPrefix(c.Request().URL.Path, "/api/v1/media/") { return route.Handler(c) } else { // Call the full page route handler @@ -112,30 +112,27 @@ func (s *Server) initRoutes() { }) } - // s.Echo.POST("/login", s.handleBasicAuthLogin) - // s.Echo.GET("/logout", s.handleLogout) - // Special routes - s.Echo.GET("/sse", s.Handlers.SSE.ServeSSE) - s.Echo.GET("/audio-level", s.Handlers.WithErrorHandling(s.Handlers.AudioLevelSSE)) - s.Echo.POST("/settings/save", h.WithErrorHandling(h.SaveSettings), s.AuthMiddleware) - s.Echo.GET("/settings/audio/get", h.WithErrorHandling(h.GetAudioDevices), s.AuthMiddleware) + s.Echo.GET("/api/v1/sse", s.Handlers.SSE.ServeSSE) + s.Echo.GET("/api/v1/audio-level", s.Handlers.WithErrorHandling(s.Handlers.AudioLevelSSE)) + s.Echo.POST("/api/v1/settings/save", h.WithErrorHandling(h.SaveSettings), s.AuthMiddleware) + s.Echo.GET("/api/v1/settings/audio/get", h.WithErrorHandling(h.GetAudioDevices), s.AuthMiddleware) // Add DELETE method for detection deletion - s.Echo.DELETE("/detections/delete", h.WithErrorHandling(h.DeleteDetection), s.AuthMiddleware) + s.Echo.DELETE("/api/v1/detections/delete", h.WithErrorHandling(h.DeleteDetection), s.AuthMiddleware) // Add POST method for ignoring species - s.Echo.POST("/detections/ignore", h.WithErrorHandling(h.IgnoreSpecies), s.AuthMiddleware) + s.Echo.POST("/api/v1/detections/ignore", h.WithErrorHandling(h.IgnoreSpecies), s.AuthMiddleware) // Add POST method for reviewing detections - s.Echo.POST("/detections/review", h.WithErrorHandling(h.ReviewDetection), s.AuthMiddleware) + s.Echo.POST("/api/v1/detections/review", h.WithErrorHandling(h.ReviewDetection), s.AuthMiddleware) // Add POST method for locking/unlocking detections - s.Echo.POST("/detections/lock", h.WithErrorHandling(h.LockDetection), s.AuthMiddleware) + s.Echo.POST("/api/v1/detections/lock", h.WithErrorHandling(h.LockDetection), s.AuthMiddleware) // Add GET method for testing MQTT connection - s.Echo.GET("/mqtt/test", h.WithErrorHandling(h.TestMQTT), s.AuthMiddleware) - s.Echo.POST("/mqtt/test", h.WithErrorHandling(h.TestMQTT), s.AuthMiddleware) + s.Echo.GET("/api/v1/mqtt/test", h.WithErrorHandling(h.TestMQTT), s.AuthMiddleware) + s.Echo.POST("/api/v1/mqtt/test", h.WithErrorHandling(h.TestMQTT), s.AuthMiddleware) // Setup Error handler s.Echo.HTTPErrorHandler = func(err error, c echo.Context) { diff --git a/internal/httpcontroller/middleware.go b/internal/httpcontroller/middleware.go index 5a192e98..fdf5dcd6 100644 --- a/internal/httpcontroller/middleware.go +++ b/internal/httpcontroller/middleware.go @@ -39,44 +39,30 @@ func (s *Server) CSRFMiddleware() echo.MiddlewareFunc { ContextKey: CSRFContextKey, Skipper: func(c echo.Context) bool { path := c.Path() + // Skip CSRF for static assets and auth endpoints only return strings.HasPrefix(path, "/assets/") || - strings.HasPrefix(path, "/media/") || - strings.HasPrefix(path, "/auth/") || - strings.HasPrefix(path, "/oauth2/token") || - path == "/callback" + strings.HasPrefix(path, "/api/v1/media/") || + strings.HasPrefix(path, "/api/v1/sse") || + strings.HasPrefix(path, "/api/v1/audio-level") || + strings.HasPrefix(path, "/api/v1/auth/") || + strings.HasPrefix(path, "/api/v1/oauth2/token") || + path == "/api/v1/oauth2/callback" }, ErrorHandler: func(err error, c echo.Context) error { s.Debug("🚨 CSRF ERROR: Rejected request") - - // Log request method and path s.Debug("🔍 Request Method: %s, Path: %s", c.Request().Method, c.Request().URL.Path) - - // Log CSRF token lookup sources s.Debug("📌 CSRF Token in Header: %s", c.Request().Header.Get("X-CSRF-Token")) s.Debug("📌 CSRF Token in Form: %s", c.FormValue("_csrf")) - - // Log CSRF cookie details - csrfCookie, cookieErr := c.Cookie("csrf") - if cookieErr == nil { - s.Debug("🍪 CSRF Cookie: %s", csrfCookie.Value) - } else { - s.Debug("⚠️ No CSRF Cookie found") - } - - // Log full request cookies for debugging s.Debug("📝 All Cookies: %s", c.Request().Header.Get("Cookie")) s.Debug("💡 Error Details: %v", err) - return echo.NewHTTPError(http.StatusForbidden, "Invalid CSRF token") }, } - // Wrap the middleware to access context return func(next echo.HandlerFunc) echo.HandlerFunc { csrfMiddleware := middleware.CSRFWithConfig(config) return func(c echo.Context) error { clientIP := net.ParseIP(s.RealIP(c)) - // Set the cookie secure option based on the client IP config.CookieSecure = !security.IsInLocalSubnet(clientIP) return csrfMiddleware(next)(c) } @@ -101,35 +87,29 @@ func (s *Server) CacheControlMiddleware() echo.MiddlewareFunc { } path := c.Request().URL.Path - //s.Debug("CacheControlMiddleware: Processing request for path: %s", path) + s.Debug("CacheControlMiddleware: Processing request for path: %s", path) switch { case strings.HasSuffix(path, ".css"), strings.HasSuffix(path, ".js"), strings.HasSuffix(path, ".html"): - // CSS and JS files - shorter cache with validation c.Response().Header().Set("Cache-Control", "public, max-age=3600, must-revalidate") c.Response().Header().Set("ETag", generateETag(path)) - //s.Debug("CacheControlMiddleware: Set cache headers for static file: %s", path) case strings.HasSuffix(path, ".png"), strings.HasSuffix(path, ".jpg"), strings.HasSuffix(path, ".ico"), strings.HasSuffix(path, ".svg"): - // Images can be cached longer c.Response().Header().Set("Cache-Control", "public, max-age=604800, immutable") - //s.Debug("CacheControlMiddleware: Set cache headers for image: %s", path) - case strings.HasPrefix(path, "/media/audio"): - // Audio files - set proper headers for downloads - c.Response().Header().Set("Cache-Control", "private, no-store") + case strings.HasPrefix(path, "/api/v1/media/audio"): + c.Response().Header().Set("Cache-Control", "no-store") c.Response().Header().Set("X-Content-Type-Options", "nosniff") - //s.Debug("CacheControlMiddleware: Set headers for audio file: %s", path) - //s.Debug("CacheControlMiddleware: Headers after setting - Cache-Control: %s, X-Content-Type-Options: %s", - // c.Response().Header().Get("Cache-Control"), - // c.Response().Header().Get("X-Content-Type-Options")) - case strings.HasPrefix(path, "/media/spectrogram"): - // Spectrograms can be cached - c.Response().Header().Set("Cache-Control", "public, max-age=2592000, immutable") - //s.Debug("CacheControlMiddleware: Set cache headers for spectrogram: %s", path) + c.Response().Header().Set("Accept-Ranges", "bytes") + s.Debug("CacheControlMiddleware: Set headers for audio file: %s", path) + case strings.HasPrefix(path, "/api/v1/media/spectrogram"): + c.Response().Header().Set("Cache-Control", "public, max-age=2592000, immutable") // Cache spectrograms for 30 days + s.Debug("CacheControlMiddleware: Set headers for spectrogram: %s", path) + case strings.HasPrefix(path, "/api/v1/"): + c.Response().Header().Set("Cache-Control", "no-store") + c.Response().Header().Set("Pragma", "no-cache") + c.Response().Header().Set("Expires", "0") default: - // Dynamic content - c.Response().Header().Set("Cache-Control", "private, no-cache, must-revalidate") - //s.Debug("CacheControlMiddleware: Set default cache headers for: %s", path) + c.Response().Header().Set("Cache-Control", "no-store") } err := next(c) @@ -191,9 +171,15 @@ func (s *Server) AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc { } // isProtectedRoute checks if the request is protected -// TODO: Add more protected routes func isProtectedRoute(path string) bool { - return strings.HasPrefix(path, "/settings/") + return strings.HasPrefix(path, "/settings/") || + strings.HasPrefix(path, "/api/v1/settings/") || + strings.HasPrefix(path, "/api/v1/detections/delete") || + strings.HasPrefix(path, "/api/v1/detections/ignore") || + strings.HasPrefix(path, "/api/v1/detections/review") || + strings.HasPrefix(path, "/api/v1/detections/lock") || + strings.HasPrefix(path, "/api/v1/mqtt/") || + strings.HasPrefix(path, "/logout") } // generateETag creates a simple hash-based ETag for a given path diff --git a/views/pages/settings/templates/checkbox.html b/views/components/checkbox.html similarity index 100% rename from views/pages/settings/templates/checkbox.html rename to views/components/checkbox.html diff --git a/views/pages/settings/templates/hostField.html b/views/components/hostField.html similarity index 100% rename from views/pages/settings/templates/hostField.html rename to views/components/hostField.html diff --git a/views/pages/settings/templates/passwordField.html b/views/components/passwordField.html similarity index 100% rename from views/pages/settings/templates/passwordField.html rename to views/components/passwordField.html diff --git a/views/pages/settings/templates/textField.html b/views/components/textField.html similarity index 100% rename from views/pages/settings/templates/textField.html rename to views/components/textField.html diff --git a/views/elements/audioLevelIndicator.html b/views/elements/audioLevelIndicator.html index c7b0ceef..3528f1ed 100644 --- a/views/elements/audioLevelIndicator.html +++ b/views/elements/audioLevelIndicator.html @@ -53,7 +53,7 @@ this.cleanupEventSource(); - this.eventSource = new EventSource('/audio-level'); + this.eventSource = new EventSource('/api/v1/audio-level'); this.eventSource.onmessage = (event) => { // Skip processing if we're navigating away diff --git a/views/elements/callback.html b/views/elements/callback.html index b6d2645d..a9600622 100644 --- a/views/elements/callback.html +++ b/views/elements/callback.html @@ -21,7 +21,7 @@ const clientSecret = '{{.Secret}}'; const redirectUri = window.location.origin + '{{.RedirectURL}}'; - fetch('/oauth2/token', { + fetch('/api/v1/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', diff --git a/views/elements/dashboard.html b/views/elements/dashboard.html index 4db5f44f..2dbc27bb 100644 --- a/views/elements/dashboard.html +++ b/views/elements/dashboard.html @@ -17,7 +17,7 @@ - @@ -48,7 +48,7 @@ Recent Detections