diff --git a/go.mod b/go.mod index 1aad9a0..f9a45dd 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mergestat/timediff v0.0.3 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect @@ -31,6 +32,7 @@ require ( require ( github.com/go-chi/chi v1.5.5 github.com/go-chi/chi/v5 v5.0.12 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/gorcon/rcon v1.3.5 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/uptrace/bun v1.2.1 diff --git a/go.sum b/go.sum index ad9da2b..4caf0a5 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorcon/rcon v1.3.5 h1:YE/Vrw6R99uEP08wp0EjdPAP3Jwz/ys3J8qxI1nYoeU= @@ -26,6 +28,8 @@ github.com/mergestat/timediff v0.0.3 h1:ucCNh4/ZrTPjFZ081PccNbhx9spymCJkFxSzgVuP github.com/mergestat/timediff v0.0.3/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 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/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= diff --git a/main.go b/main.go index adb03bb..8612543 100644 --- a/main.go +++ b/main.go @@ -28,23 +28,47 @@ func main() { } cs := services.NewCaptureService(persistence) - server := routes.NewServer(cs) + + cod4StatusProvider := &models.CoD4UdpClient{} + + cachedProvider, err := models.NewCachedProvider(cod4StatusProvider) + if err != nil { + log.Fatal(err) + } + + cod4Service, err := services.NewCoD4Server(cachedProvider) + if err != nil { + log.Fatal(err) + } + + server := routes.NewServer(cs, cod4Service) doneChan := make(chan bool) - scanner, err := services.NewScanner(persistence, time.Second*10, doneChan) + scanner, err := services.NewScanner(persistence, cachedProvider, time.Second*10, doneChan) if err != nil { log.Fatal(err) } go scanner.Scan() - router.Use(routes.PathMiddleware) + router.Use(routes.PathMiddleware, routes.AuthMiddleware) router.Handle("/*", public()) router.Get("/health", routes.Make(server.HandleHealth)) + router.Get("/server/status", routes.Make(server.HandleServerStatus)) router.Get("/captures/{captureID}", routes.Make(server.HandleCapture)) - router.Delete("/captures/{captureID}", routes.Make(server.HandleCaptureDelete)) - router.Get("/new/capture", routes.Make(server.HandleCaptureForm)) - router.Post("/new/capture", routes.Make(server.HandleCaptureCreate)) + router.Get("/captures/{captureID}/table", routes.Make(server.HandleCaptureTable)) + router.Get("/login", routes.Make(server.HandleLogin)) + router.Get("/logout", routes.Make(server.HandleLogout)) + router.Group(func(r chi.Router) { + r.Use(routes.OnlyAuthenticatedMiddleware) + + r.Delete("/captures/{captureID}", routes.Make(server.HandleCaptureDelete)) + r.Get("/captures/{captureID}/start", routes.Make(server.HandleCaptureStart)) + r.Get("/captures/{captureID}/stop", routes.Make(server.HandleCaptureStop)) + r.Post("/new/capture", routes.Make(server.HandleCaptureCreate)) + r.Get("/new/capture", routes.Make(server.HandleCaptureForm)) + }) + router.Post("/signin", routes.Make(server.HandleSignin)) router.Get("/", routes.Make(server.HandleHome)) listenAddr := os.Getenv("LISTEN_ADDR") diff --git a/models/cod4cache.go b/models/cod4cache.go new file mode 100644 index 0000000..fa4e924 --- /dev/null +++ b/models/cod4cache.go @@ -0,0 +1,42 @@ +package models + +import ( + "fmt" + "time" + + "github.com/patrickmn/go-cache" +) + +type CachedProvider struct { + provider StatusProvider + cache *cache.Cache +} + +func NewCachedProvider(provider StatusProvider) (*CachedProvider, error) { + c := cache.New(10*time.Second, 20*time.Second) + + return &CachedProvider{ + provider: provider, + cache: c, + }, nil +} + +func (c *CachedProvider) GetServerStatus(host, port string, timeout time.Duration) (*CoD4ServerStatus, error) { + status, found := c.cache.Get(ID(host, port)) + if found { + return status.(*CoD4ServerStatus), nil + } else { + status, err := c.provider.GetServerStatus(host, port, timeout) + if err != nil { + return nil, err + } + + c.cache.Set(ID(host, port), status, cache.DefaultExpiration) + + return status, nil + } +} + +func ID(host, port string) string { + return fmt.Sprintf("%s:%s", host, port) +} diff --git a/models/cod4server.go b/models/cod4server.go index 1c70052..637f0f5 100644 --- a/models/cod4server.go +++ b/models/cod4server.go @@ -12,38 +12,44 @@ import ( "time" ) -var timeLayout = "Mon Jan 2 15:04:05 2006" +var ( + timeLayout = "Mon Jan 2 15:04:05 2006" +) + +type StatusProvider interface { + GetServerStatus(string, string, time.Duration) (*CoD4ServerStatus, error) +} type CoD4Server struct { - server string - port string - protocol string - timeout time.Duration + server string + port string + timeout time.Duration } type CoD4ServerStatus struct { raw string serverData map[string]string + Name string MapStartTime time.Time MapName string + MaxPlayers int Score []Score meta map[string]interface{} } -func NewCOD4ServerStatus(server, port string, timeout time.Duration) (*CoD4Server, error) { +type CoD4UdpClient struct{} + +func (CoD4UdpClient) GetServerStatus(server, port string, timeout time.Duration) (*CoD4ServerStatus, error) { if server == "" || port == "" { return nil, errors.New("server or port is empty") } - return &CoD4Server{ - server: server, - port: port, - protocol: "udp", - timeout: timeout, - }, nil -} + c := &CoD4Server{ + server: server, + port: port, + timeout: timeout, + } -func (c *CoD4Server) GetServerStatus() (*CoD4ServerStatus, error) { data, err := c.receiveData() if err != nil { return nil, err @@ -54,7 +60,7 @@ func (c *CoD4Server) GetServerStatus() (*CoD4ServerStatus, error) { func (c *CoD4Server) receiveData() (string, error) { address := fmt.Sprintf("%s:%s", c.server, c.port) - conn, err := net.DialTimeout(c.protocol, address, c.timeout) + conn, err := net.DialTimeout("udp", address, c.timeout) if err != nil { return "", fmt.Errorf("could not connect to server: %s", err) } @@ -105,11 +111,16 @@ func parseServerData(data string) (*CoD4ServerStatus, error) { c.serverData[tempData[i]] = tempData[i+1] } + startTime, err := time.ParseInLocation(timeLayout, c.serverData["g_mapStartTime"], time.Local) + if err != nil { + return nil, err + } + c.serverData["sv_hostname"] = colorCode(c.serverData["sv_hostname"]) + c.Name = c.serverData["sv_hostname"] c.serverData["_Maps"] = strings.Join(strings.Split(c.serverData["_Maps"], "-"), ",") c.MapName = c.serverData["mapname"] - - startTime, err := time.ParseInLocation(timeLayout, c.serverData["g_mapStartTime"], time.Local) + c.MaxPlayers, err = strconv.Atoi(c.serverData["sv_maxclients"]) if err != nil { return nil, err } @@ -159,9 +170,19 @@ func colorCode(str string) string { "9": "#6E3C3C", } - re := regexp.MustCompile(`\^(\d)(.*?)\^`) - return re.ReplaceAllStringFunc(str, func(m string) string { - matches := re.FindStringSubmatch(m) - return fmt.Sprintf(`%s^`, colorMap[matches[1]], matches[2]) + re := regexp.MustCompile(`\^(\d)`) + str = re.ReplaceAllStringFunc(str, func(m string) string { + code := string(m[1]) + if color, ok := colorMap[code]; ok { + return fmt.Sprintf(``, color) + } + return m }) + + // Close open span tags + str += "^" + reClose := regexp.MustCompile(`\^(.*?)\^`) + str = reClose.ReplaceAllString(str, "$1") + + return str[:len(str)-1] } diff --git a/models/persistence.go b/models/persistence.go index 08159bc..4acfa46 100644 --- a/models/persistence.go +++ b/models/persistence.go @@ -12,6 +12,7 @@ import ( type Persistence interface { CreateCapture(context.Context, *Capture) error + UpdateCapture(context.Context, *Capture) error GetCaptures(context.Context) ([]Capture, error) GetCapturesByID(context.Context, int64) (*Capture, error) DeleteCapture(context.Context, int64) error @@ -68,6 +69,12 @@ func (s *SQLitePersistence) GetCapturesByID(ctx context.Context, id int64) (*Cap return &capture, err } +func (s *SQLitePersistence) UpdateCapture(ctx context.Context, capture *Capture) error { + _, err := s.db.NewUpdate().Model(capture).WherePK().Exec(ctx) + + return err +} + func (s *SQLitePersistence) DeleteCapture(ctx context.Context, id int64) error { capture := Capture{ ID: id, diff --git a/routes/auth.go b/routes/auth.go new file mode 100644 index 0000000..5f3efa4 --- /dev/null +++ b/routes/auth.go @@ -0,0 +1,52 @@ +package routes + +import ( + "net/http" + "time" + + "gitea.henriburau.de/haw-lan/cod4watcher/services" + "gitea.henriburau.de/haw-lan/cod4watcher/views/auth" +) + +func (s *Server) HandleLogin(w http.ResponseWriter, r *http.Request) error { + return Render(w, r, auth.LoginForm(auth.LoginFormValues{}, map[string]string{})) +} + +func (s *Server) HandleSignin(w http.ResponseWriter, r *http.Request) error { + r.ParseForm() + + creds := services.Credentials{ + Username: r.FormValue("username"), + Password: r.FormValue("password"), + } + + token, expiresIn, err := services.Signin(creds) + if err != nil { + errors := map[string]string{ + "username": "username or password incorrect" + err.Error(), + "password": "username or password incorrect" + err.Error(), + } + return Render(w, r, auth.LoginForm(auth.LoginFormValues{ + Username: creds.Username, + Password: creds.Password, + }, errors)) + } + + http.SetCookie(w, &http.Cookie{ + Name: "session_token", + Value: token, + Expires: expiresIn, + }) + + return hxRedirect(w, r, "/") +} + +func (s *Server) HandleLogout(w http.ResponseWriter, r *http.Request) error { + http.SetCookie(w, &http.Cookie{ + Name: "session_token", + Value: "", + Expires: time.Time{}, + }) + + return hxRedirect(w, r, "/") +} diff --git a/routes/auth_middleware.go b/routes/auth_middleware.go new file mode 100644 index 0000000..3efa66f --- /dev/null +++ b/routes/auth_middleware.go @@ -0,0 +1,62 @@ +package routes + +import ( + "context" + "log/slog" + "net/http" + + "gitea.henriburau.de/haw-lan/cod4watcher/services" + "gitea.henriburau.de/haw-lan/cod4watcher/views" +) + +func OnlyAuthenticatedMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + session, err := getSession(r) + if err != nil { + slog.Error("failed to optain session", "err", err) + } + + if session != nil { + next.ServeHTTP(w, r) + } + + w.WriteHeader(http.StatusUnauthorized) + }) +} + +func AuthMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + session, err := getSession(r) + if err != nil { + slog.Error("error getting token", "err", err) + } + username := "" + if session != nil { + username = session.Username + } + + ctx := context.WithValue(r.Context(), views.AuthContext, username) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +func getSession(r *http.Request) (*services.Session, error) { + c, err := r.Cookie("session_token") + if err != nil { + return nil, err + } + + sessionToken := c.Value + + session, err := services.GetSession(sessionToken) + if err != nil { + return nil, err + } + + if session.IsExpired() { + services.RemoveSession(sessionToken) + return nil, nil + } + + return session, nil +} diff --git a/routes/capture.go b/routes/capture.go index 50cfe2f..8366365 100644 --- a/routes/capture.go +++ b/routes/capture.go @@ -7,6 +7,7 @@ import ( "gitea.henriburau.de/haw-lan/cod4watcher/models" "gitea.henriburau.de/haw-lan/cod4watcher/views/capture" + "gitea.henriburau.de/haw-lan/cod4watcher/views/components" "github.com/go-chi/chi" ) @@ -22,7 +23,52 @@ func (s *Server) HandleCapture(w http.ResponseWriter, r *http.Request) error { return err } - return Render(w, r, capture.Capture(foundCapture)) + return Render(w, r, capture.Capture(foundCapture, *foundCapture.MapScores.BuildTable())) +} + +func (s *Server) HandleCaptureTable(w http.ResponseWriter, r *http.Request) error { + captureString := chi.URLParam(r, "captureID") + captureID, err := strconv.ParseInt(captureString, 10, 64) + if err != nil { + return err + } + + foundCapture, err := s.cs.GetCaptureById(r.Context(), captureID) + if err != nil { + return err + } + + return Render(w, r, components.CaptureTable(*foundCapture.MapScores.BuildTable())) +} + +func (s *Server) HandleCaptureStart(w http.ResponseWriter, r *http.Request) error { + captureString := chi.URLParam(r, "captureID") + captureID, err := strconv.ParseInt(captureString, 10, 64) + if err != nil { + return err + } + + err = s.cs.StartCapture(r.Context(), captureID) + if err != nil { + return err + } + + return hxRedirect(w, r, "/") +} + +func (s *Server) HandleCaptureStop(w http.ResponseWriter, r *http.Request) error { + captureString := chi.URLParam(r, "captureID") + captureID, err := strconv.ParseInt(captureString, 10, 64) + if err != nil { + return err + } + + err = s.cs.StopCapture(r.Context(), captureID) + if err != nil { + return err + } + + return hxRedirect(w, r, "/") } func (s *Server) HandleCaptureDelete(w http.ResponseWriter, r *http.Request) error { @@ -58,7 +104,7 @@ func (s *Server) HandleCaptureCreate(w http.ResponseWriter, r *http.Request) err Start: time.Now(), } - _, err := s.cs.GetServerStatus(r.Context(), newCapture) + _, err := s.c4s.GetServerStatus(newCapture.Host, newCapture.Port) if err != nil { errors["host"] = err.Error() errors["port"] = err.Error() diff --git a/routes/cod4server.go b/routes/cod4server.go new file mode 100644 index 0000000..841c3b1 --- /dev/null +++ b/routes/cod4server.go @@ -0,0 +1,17 @@ +package routes + +import ( + "net/http" + + "gitea.henriburau.de/haw-lan/cod4watcher/views/cod4server" +) + +func (s *Server) HandleServerStatus(w http.ResponseWriter, r *http.Request) error { + status, err := s.c4s.GetServerStatus(r.URL.Query().Get("host"), r.URL.Query().Get("port")) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return err + } + + return Render(w, r, cod4server.ServerStatus(status)) +} diff --git a/routes/home.go b/routes/home.go index b4f62ee..12938d2 100644 --- a/routes/home.go +++ b/routes/home.go @@ -3,17 +3,24 @@ package routes import ( "net/http" + "gitea.henriburau.de/haw-lan/cod4watcher/models" + "gitea.henriburau.de/haw-lan/cod4watcher/views" "gitea.henriburau.de/haw-lan/cod4watcher/views/home" - "github.com/davecgh/go-spew/spew" ) func (s *Server) HandleHome(w http.ResponseWriter, r *http.Request) error { - captureList, err := s.cs.GetActiveCapures(r.Context()) + + var captureList []models.Capture + var err error + if views.Username(r.Context()) != "" { + captureList, err = s.cs.GetCaptures(r.Context()) + } else { + captureList, err = s.cs.GetActiveCapures(r.Context()) + } + if err != nil { return err } - spew.Dump(r.Context()) - return Render(w, r, home.Index(captureList)) } diff --git a/routes/routes.go b/routes/routes.go index 7a38687..412e1f1 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -19,12 +19,13 @@ func Make(h HTTPHandler) http.HandlerFunc { } type Server struct { - cs *services.CaptureService + cs *services.CaptureService + c4s *services.CoD4Service } -func NewServer(cs *services.CaptureService) *Server { +func NewServer(cs *services.CaptureService, c4s *services.CoD4Service) *Server { return &Server{ - cs, + cs, c4s, } } diff --git a/services/authorization.go b/services/authorization.go new file mode 100644 index 0000000..1e4c717 --- /dev/null +++ b/services/authorization.go @@ -0,0 +1,90 @@ +package services + +import ( + "errors" + "time" + + "github.com/golang-jwt/jwt" +) + +var ( + users = map[string]string{ + "henri": "henri123", + } + secret = []byte("mein-secret") +) + +type Session struct { + Username string + Expiry time.Time +} + +type Credentials struct { + Password string + Username string +} + +func (s Session) IsExpired() bool { + return s.Expiry.Before(time.Now()) +} + +func Signin(cred Credentials) (string, time.Time, error) { + expectedPassword, ok := users[cred.Username] + if !ok || expectedPassword != cred.Password { + return "", time.Time{}, errors.New("wrong password") + } + + expiresAt := time.Now().Add(2 * time.Hour) + + sessionToken, err := tokenFromSession(Session{ + Username: cred.Username, + Expiry: expiresAt, + }) + + if err != nil { + return "", time.Time{}, err + } + + return sessionToken, expiresAt, nil +} + +func GetSession(sessionToken string) (*Session, error) { + return sessionFromToken(sessionToken) +} + +func RemoveSession(sessionID string) { +} + +func tokenFromSession(session Session) (string, error) { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, + jwt.MapClaims{ + "username": session.Username, + "exp": session.Expiry.Unix(), + }) + + return token.SignedString(secret) +} + +func sessionFromToken(tokenString string) (*Session, error) { + sessionToken, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return secret, nil + }) + + if err != nil { + return nil, err + } + + if !sessionToken.Valid { + return nil, errors.New("invalid token") + } + + if claims, ok := sessionToken.Claims.(jwt.MapClaims); ok { + expiresAt := time.Unix(int64(claims["exp"].(float64)), 0) + return &Session{ + Username: claims["username"].(string), + Expiry: expiresAt, + }, nil + } else { + return nil, errors.New("cannot read claims") + } +} diff --git a/services/capture.go b/services/capture.go index 6c4e879..9aa1848 100644 --- a/services/capture.go +++ b/services/capture.go @@ -2,7 +2,6 @@ package services import ( "context" - "time" "gitea.henriburau.de/haw-lan/cod4watcher/models" ) @@ -40,14 +39,30 @@ func (cs *CaptureService) GetActiveCapures(ctx context.Context) ([]models.Captur return result, nil } +func (cs *CaptureService) GetCaptures(ctx context.Context) ([]models.Capture, error) { + return cs.p.GetCaptures(ctx) +} -func (cs *CaptureService) GetServerStatus(ctx context.Context, capture *models.Capture) (*models.CoD4ServerStatus, error) { - server, err := models.NewCOD4ServerStatus(capture.Host, capture.Port, time.Second) +func (cs *CaptureService) StartCapture(ctx context.Context, id int64) error { + capture, err := cs.p.GetCapturesByID(ctx, id) if err != nil { - return nil, err + return err } - return server.GetServerStatus() + capture.Active = true + + return cs.p.UpdateCapture(ctx, capture) +} + +func (cs *CaptureService) StopCapture(ctx context.Context, id int64) error { + capture, err := cs.p.GetCapturesByID(ctx, id) + if err != nil { + return err + } + + capture.Active = false + + return cs.p.UpdateCapture(ctx, capture) } func (cs *CaptureService) GetCaptureById(ctx context.Context, id int64) (*models.Capture, error) { diff --git a/services/cod4server.go b/services/cod4server.go new file mode 100644 index 0000000..569c067 --- /dev/null +++ b/services/cod4server.go @@ -0,0 +1,21 @@ +package services + +import ( + "time" + + "gitea.henriburau.de/haw-lan/cod4watcher/models" +) + +type CoD4Service struct { + p models.StatusProvider +} + +func NewCoD4Server(p models.StatusProvider) (*CoD4Service, error) { + return &CoD4Service{ + p, + }, nil +} + +func (s *CoD4Service) GetServerStatus(host, port string) (*models.CoD4ServerStatus, error) { + return s.p.GetServerStatus(host, port, time.Second) +} diff --git a/services/scanner.go b/services/scanner.go index 0a96b47..40736ac 100644 --- a/services/scanner.go +++ b/services/scanner.go @@ -10,13 +10,14 @@ import ( type Scanner struct { p models.Persistence + c4s models.StatusProvider done chan bool interval time.Duration } -func NewScanner(p models.Persistence, interval time.Duration, done chan bool) (*Scanner, error) { +func NewScanner(p models.Persistence, c4s models.StatusProvider, interval time.Duration, done chan bool) (*Scanner, error) { return &Scanner{ - p, done, interval, + p, c4s, done, interval, }, nil } @@ -52,12 +53,7 @@ func (s *Scanner) Scan() { } func (s *Scanner) fetchInformation(ctx context.Context, capture models.Capture) error { - server, err := models.NewCOD4ServerStatus(capture.Host, capture.Port, time.Second) - if err != nil { - return err - } - - status, err := server.GetServerStatus() + status, err := s.c4s.GetServerStatus(capture.Host, capture.Port, time.Second) if err != nil { return err } diff --git a/views/auth/login_form.templ b/views/auth/login_form.templ new file mode 100644 index 0000000..7f18aaf --- /dev/null +++ b/views/auth/login_form.templ @@ -0,0 +1,41 @@ +package auth + +import ( + "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" + "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +) + +type LoginFormValues struct { + Username string + Password string +} + +templ LoginForm(formValues LoginFormValues, errors map[string]string) { + @layouts.Base() { + @components.Form(components.FormProps{ + Title: "Log into your account", + Action: "/signin", + Method: "post", + SubmitText: "Login", + }) { +
+ + @components.Input(components.InputProps{ + Name: "username", + Value: formValues.Username, + Error: errors["username"], + Placeholder: "Your username", + }) +
+
+ + @components.Input(components.InputProps{ + Name: "password", + Value: formValues.Password, + Error: errors["password"], + Placeholder: "Your password", + }) +
+ } + } +} diff --git a/views/auth/login_form_templ.go b/views/auth/login_form_templ.go new file mode 100644 index 0000000..38ce4b2 --- /dev/null +++ b/views/auth/login_form_templ.go @@ -0,0 +1,106 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.707 +package auth + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "gitea.henriburau.de/haw-lan/cod4watcher/views/components" + "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" +) + +type LoginFormValues struct { + Username string + Password string +} + +func LoginForm(formValues LoginFormValues, errors map[string]string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + templ_7745c5c3_Var3 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.Input(components.InputProps{ + Name: "username", + Value: formValues.Username, + Error: errors["username"], + Placeholder: "Your username", + }).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.Input(components.InputProps{ + Name: "password", + Value: formValues.Password, + Error: errors["password"], + Placeholder: "Your password", + }).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = components.Form(components.FormProps{ + Title: "Log into your account", + Action: "/signin", + Method: "post", + SubmitText: "Login", + }).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = layouts.Base().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/capture/capture.templ b/views/capture/capture.templ index 3ed9628..b9a263d 100644 --- a/views/capture/capture.templ +++ b/views/capture/capture.templ @@ -3,17 +3,50 @@ package capture import "gitea.henriburau.de/haw-lan/cod4watcher/models" import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import "fmt" +import "net/url" -templ Capture(capture *models.Capture) { +templ Capture(capture *models.Capture, table models.ResultTable) { @layouts.Base() {
-
- { capture.Name } +
+
+
+ { capture.Name } +
+ @components.ServerAddress(capture.Host, capture.Port) +
+ Loading Server status... +
+
+
+ if len(table.Rows) >= 1 { + @Medal("1. Platz", table.Rows[0].Name, "text-yellow-600") + } + if len(table.Rows) >= 2 { + @Medal("2. Platz", table.Rows[1].Name, "text-gray-500") + } + if len(table.Rows) >= 3 { + @Medal("3. Platz", table.Rows[2].Name, "text-amber-700") + } +
-
- { capture.Host }:{ capture.Port } +
+ @components.CaptureTable(table)
- @components.CaptureTable(*capture.MapScores.BuildTable())
} } + +templ Medal(placement, name, color string) { +
+ + + { placement } { name } + +
+} diff --git a/views/capture/capture_form.templ b/views/capture/capture_form.templ index 207e329..0b84c56 100644 --- a/views/capture/capture_form.templ +++ b/views/capture/capture_form.templ @@ -1,50 +1,53 @@ package capture -import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" -import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import ( + "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" + "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +) type CaptureFormValues struct { Host string Port string Name string + Active bool + ValidateServer bool } templ CaptureForm(formValues CaptureFormValues, errors map[string]string) { @layouts.Base() { -
-
-
Create new capture
-
- - @components.Input(components.InputProps{ - Name: "name", - Value: formValues.Name, - Error: errors["name"], - Placeholder: "Name for the capture", - }) -
-
- - @components.Input(components.InputProps{ - Name: "host", - Value: formValues.Host, - Error: errors["host"], - Placeholder: "Host-Address of the capture", - }) -
-
- - @components.Input(components.InputProps{ - Name: "port", - Value: formValues.Port, - Error: errors["port"], - Placeholder: "Port for the capture", - }) -
- -
-
+ @components.Form(components.FormProps{ + Title: "Create new capture", + Action: "/new/capture", + Method: "post", + SubmitText: "Create capture", + }) { +
+ + @components.Input(components.InputProps{ + Name: "name", + Value: formValues.Name, + Error: errors["name"], + Placeholder: "Name for the capture", + }) +
+
+ + @components.Input(components.InputProps{ + Name: "host", + Value: formValues.Host, + Error: errors["host"], + Placeholder: "Host-Address of the capture", + }) +
+
+ + @components.Input(components.InputProps{ + Name: "port", + Value: formValues.Port, + Error: errors["port"], + Placeholder: "Port for the capture", + }) +
+ } } } diff --git a/views/capture/capture_form_templ.go b/views/capture/capture_form_templ.go index cab5598..cb38435 100644 --- a/views/capture/capture_form_templ.go +++ b/views/capture/capture_form_templ.go @@ -10,13 +10,17 @@ import "context" import "io" import "bytes" -import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" -import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import ( + "gitea.henriburau.de/haw-lan/cod4watcher/views/components" + "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" +) type CaptureFormValues struct { - Host string - Port string - Name string + Host string + Port string + Name string + Active bool + ValidateServer bool } func CaptureForm(formValues CaptureFormValues, errors map[string]string) templ.Component { @@ -38,46 +42,66 @@ func CaptureForm(formValues CaptureFormValues, errors map[string]string) templ.C templ_7745c5c3_Buffer = templ.GetBuffer() defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Create new capture
") - if templ_7745c5c3_Err != nil { + templ_7745c5c3_Var3 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.Input(components.InputProps{ + Name: "name", + Value: formValues.Name, + Error: errors["name"], + Placeholder: "Name for the capture", + }).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.Input(components.InputProps{ + Name: "host", + Value: formValues.Host, + Error: errors["host"], + Placeholder: "Host-Address of the capture", + }).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.Input(components.InputProps{ + Name: "port", + Value: formValues.Port, + Error: errors["port"], + Placeholder: "Port for the capture", + }).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } return templ_7745c5c3_Err - } - templ_7745c5c3_Err = components.Input(components.InputProps{ - Name: "name", - Value: formValues.Name, - Error: errors["name"], - Placeholder: "Name for the capture", - }).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = components.Input(components.InputProps{ - Name: "host", - Value: formValues.Host, - Error: errors["host"], - Placeholder: "Host-Address of the capture", - }).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = components.Input(components.InputProps{ - Name: "port", - Value: formValues.Port, - Error: errors["port"], - Placeholder: "Port for the capture", - }).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + }) + templ_7745c5c3_Err = components.Form(components.FormProps{ + Title: "Create new capture", + Action: "/new/capture", + Method: "post", + SubmitText: "Create capture", + }).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/views/capture/capture_templ.go b/views/capture/capture_templ.go index 812e5ec..5f7e65f 100644 --- a/views/capture/capture_templ.go +++ b/views/capture/capture_templ.go @@ -13,8 +13,10 @@ import "bytes" import "gitea.henriburau.de/haw-lan/cod4watcher/models" import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import "fmt" +import "net/url" -func Capture(capture *models.Capture) templ.Component { +func Capture(capture *models.Capture, table models.ResultTable) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) if !templ_7745c5c3_IsBuffer { @@ -33,54 +35,84 @@ func Capture(capture *models.Capture) templ.Component { templ_7745c5c3_Buffer = templ.GetBuffer() defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(capture.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/capture/capture.templ`, Line: 11, Col: 18} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/capture/capture.templ`, Line: 15, Col: 20} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = components.ServerAddress(capture.Host, capture.Port).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Loading Server status...
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if len(table.Rows) >= 1 { + templ_7745c5c3_Err = Medal("1. Platz", table.Rows[0].Name, "text-yellow-600").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if len(table.Rows) >= 2 { + templ_7745c5c3_Err = Medal("2. Platz", table.Rows[1].Name, "text-gray-500").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if len(table.Rows) >= 3 { + templ_7745c5c3_Err = Medal("3. Platz", table.Rows[2].Name, "text-amber-700").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-trigger=\"every 10s\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = components.CaptureTable(*capture.MapScores.BuildTable()).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = components.CaptureTable(table).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -99,3 +131,75 @@ func Capture(capture *models.Capture) templ.Component { return templ_7745c5c3_Err }) } + +func Medal(placement, name, color string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 = []any{"fa-solid", "fa-medal", "text-3xl", color} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(placement) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/capture/capture.templ`, Line: 49, Col: 14} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/capture/capture.templ`, Line: 49, Col: 23} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/cod4server/server_status.templ b/views/cod4server/server_status.templ new file mode 100644 index 0000000..a4f51b5 --- /dev/null +++ b/views/cod4server/server_status.templ @@ -0,0 +1,16 @@ +package cod4server + +import "gitea.henriburau.de/haw-lan/cod4watcher/models" +import "fmt" + +templ ServerStatus(status *models.CoD4ServerStatus) { +
+ + { status.MapName } + + { fmt.Sprintf("%d/%d",len(status.Score), status.MaxPlayers) } +
+
+ @templ.Raw(status.Name) +
+} diff --git a/views/cod4server/server_status_templ.go b/views/cod4server/server_status_templ.go new file mode 100644 index 0000000..9b9dec5 --- /dev/null +++ b/views/cod4server/server_status_templ.go @@ -0,0 +1,72 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.707 +package cod4server + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import "gitea.henriburau.de/haw-lan/cod4watcher/models" +import "fmt" + +func ServerStatus(status *models.CoD4ServerStatus) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(status.MapName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/cod4server/server_status.templ`, Line: 9, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d/%d", len(status.Score), status.MaxPlayers)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/cod4server/server_status.templ`, Line: 11, Col: 67} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.Raw(status.Name).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/components/button.templ b/views/components/button.templ new file mode 100644 index 0000000..dfbc610 --- /dev/null +++ b/views/components/button.templ @@ -0,0 +1,25 @@ +package components + +templ Button() { + +} + +templ SubmitButton() { + +} + +templ IconButton(icon, url string) { + + + +} + +templ IconButtonRed(icon, url string) { + + + +} diff --git a/views/components/button_templ.go b/views/components/button_templ.go new file mode 100644 index 0000000..6a4c306 --- /dev/null +++ b/views/components/button_templ.go @@ -0,0 +1,189 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.707 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +func Button() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func SubmitButton() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func IconButton(icon, url string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 = []any{icon} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func IconButtonRed(icon, url string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var9 = []any{icon} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/components/capture_card.templ b/views/components/capture_card.templ index 0a3a576..6d9c9b0 100644 --- a/views/components/capture_card.templ +++ b/views/components/capture_card.templ @@ -1,15 +1,31 @@ package components import "gitea.henriburau.de/haw-lan/cod4watcher/models" -import "github.com/mergestat/timediff" +import "gitea.henriburau.de/haw-lan/cod4watcher/views" import "fmt" +import "net/url" templ CaptureCard(capture models.Capture) {
- +
{ capture.Name }
-

{ timediff.TimeDiff(capture.Start) }

- +

{ capture.Host }:{ capture.Port }

+
+ Loading Server status... +
+ if views.Username(ctx) != "" { +
+ @IconButtonRed("fa-solid fa-trash", fmt.Sprintf("/captures/%d", capture.ID)) + if capture.Active { + @IconButton("fa-solid fa-stop", fmt.Sprintf("/captures/%d/stop", capture.ID)) + } else { + @IconButton("fa-solid fa-play", fmt.Sprintf("/captures/%d/start", capture.ID)) + } +
+ }
} diff --git a/views/components/capture_card_templ.go b/views/components/capture_card_templ.go index 04c8d71..e80bfda 100644 --- a/views/components/capture_card_templ.go +++ b/views/components/capture_card_templ.go @@ -11,8 +11,9 @@ import "io" import "bytes" import "gitea.henriburau.de/haw-lan/cod4watcher/models" -import "github.com/mergestat/timediff" +import "gitea.henriburau.de/haw-lan/cod4watcher/views" import "fmt" +import "net/url" func CaptureCard(capture models.Capture) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { @@ -43,7 +44,7 @@ func CaptureCard(capture models.Capture) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(capture.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/capture_card.templ`, Line: 10, Col: 98} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/capture_card.templ`, Line: 11, Col: 98} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -54,28 +55,70 @@ func CaptureCard(capture models.Capture) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(timediff.TimeDiff(capture.Start)) + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(capture.Host) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/capture_card.templ`, Line: 12, Col: 92} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/capture_card.templ`, Line: 13, Col: 72} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Loading Server status...
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if views.Username(ctx) != "" { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = IconButtonRed("fa-solid fa-trash", fmt.Sprintf("/captures/%d", capture.ID)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if capture.Active { + templ_7745c5c3_Err = IconButton("fa-solid fa-stop", fmt.Sprintf("/captures/%d/stop", capture.ID)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = IconButton("fa-solid fa-play", fmt.Sprintf("/captures/%d/start", capture.ID)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/views/components/capture_table.templ b/views/components/capture_table.templ index 7420467..6a5f7b2 100644 --- a/views/components/capture_table.templ +++ b/views/components/capture_table.templ @@ -4,8 +4,8 @@ import "gitea.henriburau.de/haw-lan/cod4watcher/models" import "strconv" templ CaptureTable(table models.ResultTable) { -
- +
+
for _, header := range table.Header { @@ -20,7 +20,7 @@ templ CaptureTable(table models.ResultTable) { } - + for _, row := range table.Rows {
diff --git a/views/components/capture_table_templ.go b/views/components/capture_table_templ.go index 01c525a..9c53193 100644 --- a/views/components/capture_table_templ.go +++ b/views/components/capture_table_templ.go @@ -26,7 +26,7 @@ func CaptureTable(table models.ResultTable) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -62,7 +62,7 @@ func CaptureTable(table models.ResultTable) templ.Component { return templ_7745c5c3_Err } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/views/components/form.templ b/views/components/form.templ new file mode 100644 index 0000000..97b9060 --- /dev/null +++ b/views/components/form.templ @@ -0,0 +1,20 @@ +package components + +type FormProps struct { + Title string + Method string + Action string + SubmitText string +} + +templ Form(props FormProps) { +
+
+
{ props.Title }
+ { children... } + @SubmitButton() { + { props.SubmitText } + } + +
+} \ No newline at end of file diff --git a/views/components/form_templ.go b/views/components/form_templ.go new file mode 100644 index 0000000..43de612 --- /dev/null +++ b/views/components/form_templ.go @@ -0,0 +1,109 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.707 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +type FormProps struct { + Title string + Method string + Action string + SubmitText string +} + +func Form(props FormProps) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/form.templ`, Line: 13, Col: 79} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var5 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.SubmitText) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/form.templ`, Line: 16, Col: 35} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = SubmitButton().Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/components/navbar.templ b/views/components/navbar.templ index fa697f7..2753ba6 100644 --- a/views/components/navbar.templ +++ b/views/components/navbar.templ @@ -1,6 +1,7 @@ package components import "gitea.henriburau.de/haw-lan/cod4watcher/views" +import "strings" templ Nagivation() { diff --git a/views/components/navbar_templ.go b/views/components/navbar_templ.go index cb05ec9..1fcfccc 100644 --- a/views/components/navbar_templ.go +++ b/views/components/navbar_templ.go @@ -11,6 +11,7 @@ import "io" import "bytes" import "gitea.henriburau.de/haw-lan/cod4watcher/views" +import "strings" func Nagivation() templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { @@ -30,17 +31,45 @@ func Nagivation() templ.Component { return templ_7745c5c3_Err } if ctx.Value(views.PathContext) == "" || ctx.Value(views.PathContext) == "/" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("DashboardAbout") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Dashboard") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("DashboardAbout") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Dashboard") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if views.Username(ctx) != "" { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(strings.ToUpper(views.Username(ctx))) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/navbar.templ`, Line: 31, Col: 160} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Login") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/views/components/server_address.templ b/views/components/server_address.templ new file mode 100644 index 0000000..0b750e2 --- /dev/null +++ b/views/components/server_address.templ @@ -0,0 +1,17 @@ +package components + +import "fmt" + +templ ServerAddress(host, port string) { +
+ + { host }:{ port } + + + + + + + +
+} diff --git a/views/components/server_address_templ.go b/views/components/server_address_templ.go new file mode 100644 index 0000000..f20fa34 --- /dev/null +++ b/views/components/server_address_templ.go @@ -0,0 +1,72 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.707 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import "fmt" + +func ServerAddress(host, port string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(host) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/server_address.templ`, Line: 8, Col: 9} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(":") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(port) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/components/server_address.templ`, Line: 8, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/views/context.go b/views/context.go index 1c711b4..806e700 100644 --- a/views/context.go +++ b/views/context.go @@ -1,5 +1,14 @@ package views +import "context" + type contextKey string -var PathContext = contextKey("path") +var ( + PathContext = contextKey("path") + AuthContext = contextKey("auth") +) + +func Username(ctx context.Context) string { + return ctx.Value(AuthContext).(string) +} diff --git a/views/home/index.templ b/views/home/index.templ index 8bf0eb8..4b6c596 100644 --- a/views/home/index.templ +++ b/views/home/index.templ @@ -3,11 +3,22 @@ package home import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" import "gitea.henriburau.de/haw-lan/cod4watcher/models" import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import "gitea.henriburau.de/haw-lan/cod4watcher/views" templ Index(captures []models.Capture) { @layouts.Base() { - for _, capture := range captures { - @components.CaptureCard(capture) + if views.Username(ctx) != "" { + + @components.Button() { + Create new Capture + } + } + +
+ for _, capture := range captures { + @components.CaptureCard(capture) + } +
} } diff --git a/views/home/index_templ.go b/views/home/index_templ.go index 51c7f99..2d036a7 100644 --- a/views/home/index_templ.go +++ b/views/home/index_templ.go @@ -13,6 +13,7 @@ import "bytes" import "gitea.henriburau.de/haw-lan/cod4watcher/views/layouts" import "gitea.henriburau.de/haw-lan/cod4watcher/models" import "gitea.henriburau.de/haw-lan/cod4watcher/views/components" +import "gitea.henriburau.de/haw-lan/cod4watcher/views" func Index(captures []models.Capture) templ.Component { return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { @@ -33,12 +34,49 @@ func Index(captures []models.Capture) templ.Component { templ_7745c5c3_Buffer = templ.GetBuffer() defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) } + if views.Username(ctx) != "" { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var3 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Create new Capture") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = components.Button().Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } for _, capture := range captures { templ_7745c5c3_Err = components.CaptureCard(capture).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } if !templ_7745c5c3_IsBuffer { _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) } diff --git a/views/layouts/base.templ b/views/layouts/base.templ index 80708e1..20cfef3 100644 --- a/views/layouts/base.templ +++ b/views/layouts/base.templ @@ -15,7 +15,7 @@ templ Base() { @components.Nagivation() -
+
{ children... }
diff --git a/views/layouts/base_templ.go b/views/layouts/base_templ.go index 0ba53c9..fa87ba1 100644 --- a/views/layouts/base_templ.go +++ b/views/layouts/base_templ.go @@ -33,7 +33,7 @@ func Base() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }