mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
feat: first frontend implementation
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package secondary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ProcessTemplate(html []byte, data interface{}) ([]byte, error) {
|
||||
tmpl, err := template.New("template").Parse(string(html))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var processedHTML bytes.Buffer
|
||||
err = tmpl.Execute(&processedHTML, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return processedHTML.Bytes(), nil
|
||||
}
|
||||
|
||||
func GetTemplate(name string) []byte {
|
||||
file, err := os.Open("./web/templates/" + name + ".html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bs := make([]byte, stat.Size())
|
||||
_, err = file.Read(bs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
entity "GohCMS2/adapters/secondary/gateways/models"
|
||||
. "GohCMS2/domain/gateways"
|
||||
domain "GohCMS2/domain/user"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -33,7 +32,6 @@ func (u *UserRepository) Get(id uint32) (domain.User, error) {
|
||||
|
||||
func (u *UserRepository) Create(user domain.User) (domain.User, error) {
|
||||
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), 14)
|
||||
fmt.Println("hashedPassword at register: ", string(hashedPassword))
|
||||
|
||||
creationResult := u.db.Create(&entity.User{
|
||||
Username: user.Username,
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ func SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
Secure: false, // TODO false in dev, true in prod
|
||||
HttpOnly: true,
|
||||
Path: "/v1/",
|
||||
Path: "/",
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func isAllowedToCreateUser() bool {
|
||||
return len(users) == 0
|
||||
}
|
||||
|
||||
func isLoggedIn(r *http.Request) bool {
|
||||
func IsLoggedIn(r *http.Request) bool {
|
||||
token, err := jwtauth.VerifyRequest(
|
||||
TokenAuth,
|
||||
r,
|
||||
@@ -91,7 +91,7 @@ func login(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func register(w http.ResponseWriter, r *http.Request) {
|
||||
if !isLoggedIn(r) && !isAllowedToCreateUser() {
|
||||
if !IsLoggedIn(r) && !isAllowedToCreateUser() {
|
||||
http.Error(w, "You are not allowed to create a user. Log in or reset database.", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"GohCMS2/adapters/secondary"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LoginPage struct {
|
||||
IsError bool `json:"isError"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func getPage(page string, data interface{}) ([]byte, error) {
|
||||
template := secondary.GetTemplate(page)
|
||||
processed, err := secondary.ProcessTemplate(template, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return processed, nil
|
||||
}
|
||||
|
||||
func getLoginPageHandler(errMsg string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
bs, err := getPage("login", &LoginPage{
|
||||
IsError: strings.Compare(errMsg, "") != 0,
|
||||
Error: errMsg,
|
||||
})
|
||||
if err != nil {
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
}
|
||||
_, _ = w.Write(bs)
|
||||
}
|
||||
}
|
||||
|
||||
func postLoginPage(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
credentials, err := json.Marshal(&UserLogin{
|
||||
Username: r.FormValue("username"),
|
||||
Password: r.FormValue("password"),
|
||||
})
|
||||
if err != nil {
|
||||
getLoginPageHandler("Missing username or password.")(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO replace url with som env variable
|
||||
response, err := http.Post("http://localhost:8080/v1/auth/login", "application/json", bytes.NewBuffer(credentials))
|
||||
// TODO handle possible errors in separate file (api package)
|
||||
if err != nil || response.StatusCode != http.StatusOK {
|
||||
getLoginPageHandler("Invalid username or password.")(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Set-Cookie", response.Header.Get("Set-Cookie"))
|
||||
|
||||
http.Redirect(w, r, "/home", http.StatusFound)
|
||||
}
|
||||
|
||||
func getHomePage(w http.ResponseWriter, _ *http.Request) {
|
||||
bs, err := getPage("home", nil)
|
||||
if err != nil {
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
}
|
||||
_, _ = w.Write(bs)
|
||||
}
|
||||
|
||||
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.StatusFound)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func NewPageRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/login", getLoginPageHandler(""))
|
||||
r.Post("/login", postLoginPage)
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(IsLoggedInMiddleware)
|
||||
r.Get("/home", getHomePage)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
+52
-12
@@ -4,8 +4,9 @@ import (
|
||||
"GohCMS2/api"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/MadAppGang/httplog"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/httplog"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
"net/http"
|
||||
)
|
||||
@@ -17,6 +18,13 @@ func jsonContentTypeMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func htmlContentTypeMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func initJwt() {
|
||||
api.TokenAuth = jwtauth.New("HS256", []byte("secret"), nil)
|
||||
}
|
||||
@@ -26,29 +34,61 @@ func getHelloWorld(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write(msg)
|
||||
}
|
||||
|
||||
func main() {
|
||||
api.InitContainer()
|
||||
api.InitValidator()
|
||||
initJwt()
|
||||
|
||||
func initBackendRoutes() *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getHelloWorld)
|
||||
|
||||
r.Use(httplog.LoggerWithName("backend"))
|
||||
r.Use(jsonContentTypeMiddleware)
|
||||
r.Get("/", getHelloWorld)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(jwtauth.Verifier(api.TokenAuth))
|
||||
r.Use(jwtauth.Authenticator)
|
||||
r.Mount("/article", api.NewArticleRouter())
|
||||
})
|
||||
|
||||
r.Mount("/auth", api.NewAuthRouter())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func initFrontendRoutes() *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(httplog.LoggerWithName("frontend"))
|
||||
r.Use(htmlContentTypeMiddleware)
|
||||
r.Mount("/", api.NewPageRouter())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func initRoutes() *chi.Mux {
|
||||
backend := initBackendRoutes()
|
||||
frontend := initFrontendRoutes()
|
||||
|
||||
apiRouter := chi.NewRouter()
|
||||
apiRouter.Use(httplog.RequestLogger(httplog.NewLogger("GohCMS2")))
|
||||
apiRouter.Use(jsonContentTypeMiddleware)
|
||||
apiRouter.Mount("/v1", r)
|
||||
// TODO use env variable for allowed origins
|
||||
apiRouter.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{"https://*", "http://*"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
|
||||
ExposedHeaders: []string{"Link"},
|
||||
AllowCredentials: false,
|
||||
MaxAge: 300,
|
||||
}))
|
||||
apiRouter.Mount("/v1", backend)
|
||||
apiRouter.Mount("/", frontend)
|
||||
|
||||
return apiRouter
|
||||
}
|
||||
|
||||
func main() {
|
||||
api.InitContainer()
|
||||
api.InitValidator()
|
||||
initJwt()
|
||||
|
||||
router := initRoutes()
|
||||
|
||||
fmt.Println("Server starting on port 8080")
|
||||
err := http.ListenAndServe(":8080", apiRouter)
|
||||
err := http.ListenAndServe(":8080", router)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -3,23 +3,25 @@ module GohCMS2
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/MadAppGang/httplog v1.3.0
|
||||
github.com/glebarez/sqlite v1.9.0
|
||||
github.com/go-chi/httplog v0.3.1
|
||||
github.com/go-chi/jwtauth/v5 v5.1.1
|
||||
github.com/go-playground/validator/v10 v10.15.0
|
||||
go.uber.org/dig v1.17.0
|
||||
golang.org/x/crypto v0.10.0
|
||||
gorm.io/gorm v1.25.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
@@ -45,6 +47,5 @@ require (
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/rs/zerolog v1.29.1 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/MadAppGang/httplog v1.3.0 h1:1XU54TO8kiqTeO+7oZLKAM3RP/cJ7SadzslRcKspVHo=
|
||||
github.com/MadAppGang/httplog v1.3.0/go.mod h1:gpYEdkjh/Cda6YxtDy4AB7KY+fR7mb3SqBZw74A5hJ4=
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -9,21 +10,21 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs=
|
||||
github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/httplog v0.3.1 h1:uC3IUWCZagtbCinb3ypFh36SEcgd6StWw2Bu0XSXRtg=
|
||||
github.com/go-chi/httplog v0.3.1/go.mod h1:UoiQQ/MTZH5V6JbNB2FzF0DynTh5okpXxlhsyxoP5m8=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/jwtauth/v5 v5.1.1 h1:Pjixqu5YkjE9sCLpzE01L0Q4sQzJIPdo7uz9r8ftp/c=
|
||||
github.com/go-chi/jwtauth/v5 v5.1.1/go.mod h1:CYP1WSbzD4MPuKCr537EM3kfFhSQgpUEtMJFuYJjqWU=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
@@ -32,10 +33,10 @@ github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjA
|
||||
github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
@@ -55,22 +56,19 @@ github.com/lestrrat-go/jwx/v2 v2.0.11/go.mod h1:ZtPtMFlrfDrH2Y0iwfa3dRFn8VzwBrB+
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -102,10 +100,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login Page</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" defer></script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Home</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GohCMS | Login</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"
|
||||
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">
|
||||
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column gap-5 m-auto form-container">
|
||||
<h1>GohCMS</h1>
|
||||
<form action="login" method="POST" class="">
|
||||
<div class="d-flex flex-column gap-4">
|
||||
<div class="form-floating">
|
||||
<input
|
||||
name="username"
|
||||
type="text"
|
||||
class="form-control {{ if .IsError }} is-invalid {{ end }}"
|
||||
id="username"
|
||||
placeholder="Votre nom d'utilisateur"
|
||||
required>
|
||||
<label for="username">Username</label>
|
||||
</div>
|
||||
<div class="form-floating">
|
||||
<input name="password"
|
||||
type="password"
|
||||
class="form-control {{ if .IsError }} is-invalid {{ end }}"
|
||||
id="password"
|
||||
placeholder="Votre mot de passe"
|
||||
required>
|
||||
<label for="password">Password</label>
|
||||
<div class="invalid-feedback">
|
||||
{{.Error}}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" disabled>Log in</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const button = document.querySelector("button[type=submit]")
|
||||
const inputs = document.querySelectorAll('input')
|
||||
|
||||
function formFieldsEmpty() {
|
||||
return Array.from(inputs).some((input) => input.value === "")
|
||||
}
|
||||
|
||||
function setButtonDisabled() {
|
||||
button.disabled = formFieldsEmpty() ? "disabled" : ""
|
||||
}
|
||||
|
||||
window.addEventListener('input', (event) => {
|
||||
if (event.target.tagName === "INPUT") setButtonDisabled()
|
||||
})
|
||||
|
||||
setButtonDisabled()
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user