mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 19:53:21 +02:00
feat: api serve frontend, build workflow, router readyness
This commit is contained in:
@@ -32,7 +32,9 @@ type LoginCredentials struct {
|
||||
Password string `json:"password" validate:"required,min=8"`
|
||||
}
|
||||
|
||||
var shouldCookieBeSecure = os.Getenv("ENVIRONMENT") == "production"
|
||||
func shouldCookieBeSecure() bool {
|
||||
return os.Getenv("ENVIRONMENT") == "production"
|
||||
}
|
||||
|
||||
func removeJwtCookie(w http.ResponseWriter) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
@@ -40,7 +42,7 @@ func removeJwtCookie(w http.ResponseWriter) {
|
||||
Value: "",
|
||||
Expires: time.Now(),
|
||||
MaxAge: -1,
|
||||
Secure: shouldCookieBeSecure,
|
||||
Secure: shouldCookieBeSecure(),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
})
|
||||
@@ -64,7 +66,7 @@ func (h *Handler) SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
|
||||
Name: "jwt",
|
||||
Value: tokenString,
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
Secure: shouldCookieBeSecure,
|
||||
Secure: shouldCookieBeSecure(),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
})
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/infrastructure/assets"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type spaHandler struct {
|
||||
staticFS fs.FS
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func NewFrontendRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
distFS, _ := fs.Sub(assets.DistEmbed, "dist")
|
||||
handler := &spaHandler{
|
||||
staticFS: distFS,
|
||||
modTime: time.Now(),
|
||||
}
|
||||
|
||||
r.Get("/*", handler.ServeHTTP)
|
||||
return r
|
||||
}
|
||||
|
||||
func (h *spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
path := h.cleanPath(r.URL.Path)
|
||||
if h.fileExists(path) {
|
||||
h.serveAsset(w, r, path)
|
||||
return
|
||||
}
|
||||
h.serveIndex(w, r)
|
||||
}
|
||||
|
||||
func (h *spaHandler) cleanPath(path string) string {
|
||||
return strings.TrimPrefix(filepath.Clean(path), "/")
|
||||
}
|
||||
|
||||
func (h *spaHandler) fileExists(path string) bool {
|
||||
if path == "" || path == "." {
|
||||
return false
|
||||
}
|
||||
f, err := h.staticFS.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *spaHandler) serveAsset(w http.ResponseWriter, r *http.Request, path string) {
|
||||
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||||
http.FileServer(http.FS(h.staticFS)).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (h *spaHandler) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
f, err := h.staticFS.Open("index.html")
|
||||
if err != nil {
|
||||
http.Error(w, "Index not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
content, ok := f.(io.ReadSeeker)
|
||||
if !ok {
|
||||
http.Error(w, "File not seekable", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate")
|
||||
http.ServeContent(w, r, "index.html", h.modTime, content)
|
||||
}
|
||||
Reference in New Issue
Block a user