feat: Add build scripts, refactor for binary embedding

This commit is contained in:
Florian Sylvain
2023-08-12 19:42:27 +02:00
parent 047e14df60
commit 7e8b415cab
12 changed files with 98 additions and 17 deletions
+30 -16
View File
@@ -2,15 +2,23 @@ package api
import (
"bytes"
"embed"
"encoding/json"
"github.com/go-chi/chi/v5"
"html/template"
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
)
//go:embed web/templates/*
var templateFiles embed.FS
//go:embed web/static
var staticFolder embed.FS
var contentTypes = map[string]string{
".css": "text/css",
".js": "application/javascript",
@@ -21,6 +29,8 @@ var contentTypes = map[string]string{
".ico": "image/x-icon",
}
const loginRoute = "/login"
type LoginPage struct {
IsError bool `json:"isError"`
Error string `json:"error"`
@@ -37,7 +47,7 @@ func NewLoginPage(error string, username string) *LoginPage {
func getPage(page string, data interface{}) ([]byte, error) {
var processedHTML bytes.Buffer
tmpl, err := template.ParseFiles("./web/templates/" + page + ".html")
tmpl, err := template.ParseFS(templateFiles, "web/templates/"+page+".html")
if err != nil {
return nil, err
}
@@ -104,48 +114,52 @@ func getHomePage(w http.ResponseWriter, _ *http.Request) {
}
func getLogin(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/login", http.StatusPermanentRedirect)
http.Redirect(w, r, loginRoute, http.StatusPermanentRedirect)
}
func getLogout(w http.ResponseWriter, r *http.Request) {
removeJwtCookie(w)
http.Redirect(w, r, "/login", http.StatusSeeOther)
http.Redirect(w, r, loginRoute, http.StatusSeeOther)
}
func IsLoggedInMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !IsLoggedIn(r) {
http.Redirect(w, r, "/login", http.StatusSeeOther)
http.Redirect(w, r, loginRoute, http.StatusSeeOther)
return
}
next.ServeHTTP(w, r)
})
}
func staticFileServerWithContentType(dir http.Dir) http.Handler {
func staticFileServerWithContentType(fsys http.FileSystem) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestedFilePath := r.URL.Path
fileExtension := filepath.Ext(requestedFilePath)
if contentType, ok := contentTypes[fileExtension]; ok {
w.Header().Set("Content-Type", contentType)
path := r.URL.Path
if ext := filepath.Ext(path); ext != "" {
if ct, ok := contentTypes[ext]; ok {
w.Header().Set("Content-Type", ct)
}
}
http.FileServer(dir).ServeHTTP(w, r)
http.FileServer(fsys).ServeHTTP(w, r)
})
}
func NewPageRouter() http.Handler {
r := chi.NewRouter()
r.Handle("/static/*", http.StripPrefix("/static/", staticFileServerWithContentType("./web/static")))
contentStatic, _ := fs.Sub(fs.FS(staticFolder), "web/static")
r.Handle("/static/*", staticFileServerWithContentType(http.FS(contentStatic)))
r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./web/static/favicon.ico")
_, err := http.FS(staticFolder).Open("favicon.ico")
if err != nil {
return
}
})
r.Get("/", getLogin)
r.Get("/login", getLoginPageHandler(NewLoginPage("", "")))
r.Post("/login", getLoginPageHandler(NewLoginPage("", "")))
r.Get(loginRoute, getLoginPageHandler(NewLoginPage("", "")))
r.Post(loginRoute, getLoginPageHandler(NewLoginPage("", "")))
r.Get("/logout", getLogout)
r.Group(func(r chi.Router) {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+32
View File
@@ -0,0 +1,32 @@
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container">
<div class="d-flex gap-2 justify-content-center align-items-center">
<img src="/static/gohcms-favicon-128.png" alt="Logo" style="width: 2.5rem"/>
<a class="navbar-brand h1 my-auto" href="https://github.com/Floriansylvain/GohCMS" target="_blank">
GohCMS
</a>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="/home">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link 2</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link 3</a>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link disconnect-link" href="/logout">Se déconnecter</a>
</li>
</ul>
</div>
</div>
</nav>
+89
View File
@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>GohCMS | Connexion</title>
<link rel="stylesheet" href="/static/bootstrap.min.css" type="text/css">
<script src="/static/bootstrap.min.js"
type="application/javascript"
defer></script>
<style>
.form-container {
max-width: 24rem;
}
</style>
</head>
<body class="d-flex min-vh-100 vw-100 justify-content-center align-items-center text-dark">
<div class="container">
<div class="d-flex flex-column gap-5 m-auto form-container">
<h1>GohCMS</h1>
<form action="login" class="" method="POST">
<div class="d-flex flex-column gap-4">
<div class="form-floating">
<input class="form-control {{ if .IsError }} is-invalid {{ end }}"
id="username"
name="username"
placeholder="Nom d'utilisateur"
required
type="text"
value="{{.Username}}">
<label for="username">Nom d'utilisateur</label>
</div>
<div class="form-floating">
<input class="form-control {{ if .IsError }} is-invalid {{ end }}"
id="password"
name="password"
placeholder="Mot de passe"
required
type="password">
<label for="password">Mot de passe</label>
<div class="invalid-feedback">{{.Error}}</div>
</div>
<button id="loginFormButton" class="btn btn-primary" disabled type="submit">
<span class="loginFormButtonLoading visually-hidden spinner-border spinner-border-sm"
role="status"></span>
<span class="loginFormButtonDefault">Se connecter</span>
</button>
</div>
</form>
</div>
</div>
<script>
const button = document.querySelector("#loginFormButton")
const inputs = document.querySelectorAll('input')
function formFieldsEmpty() {
return Array.from(inputs).some((input) => input.value === "")
}
function setButtonDisabled() {
button.disabled = formFieldsEmpty() ? "disabled" : ""
}
function setButtonLoading() {
button.classList.add("disabled")
button.querySelector(".loginFormButtonDefault").classList.add("visually-hidden")
button.querySelector(".loginFormButtonLoading").classList.remove("visually-hidden")
}
function onLoginFormSubmit(event) {
event.preventDefault()
setButtonLoading()
event.target.submit()
}
function onInput(event) {
if (event.target.tagName === "INPUT") setButtonDisabled()
}
window.addEventListener('submit', onLoginFormSubmit)
window.addEventListener('input', onInput)
setButtonDisabled()
</script>
</body>
</html>