diff --git a/kontor-gin/Containerfile b/kontor-gin/Containerfile index c90b9fe..e64f5b7 100644 --- a/kontor-gin/Containerfile +++ b/kontor-gin/Containerfile @@ -10,7 +10,7 @@ RUN go mod download # Copy the source code COPY . . # Build the Go application (strip debug info for smaller size) -RUN go build -trimpath -ldflags="-s -w" -o kontor cmd/kontor/main.go +RUN go build -trimpath -ldflags="-s -w" -o kontor-gin cmd/kontor-gin/main.go # ---------- Stage 2: Final ---------- FROM alpine:latest @@ -19,7 +19,9 @@ WORKDIR /app # Install runtime dependencies you actually need RUN apk add --no-cache ca-certificates tzdata curl # Copy the binary and set ownership -COPY --from=builder /app/kontor /app/kontor +COPY --from=builder /app/kontor-gin /app/kontor-gin +COPY --from=builder /app/templates /app/templates +COPY --from=builder /app/assets /app/assets ENV DB_HOST=postgres DB_USER=kontor DB_PASSWORD=kontor DB_NAME=kontor DB_PORT=5432 GIN_MODE=release # Set the entrypoint command -ENTRYPOINT ["/app/kontor"] +ENTRYPOINT ["/app/kontor-gin"] diff --git a/kontor-gin/cmd/kontor-gin/main.go b/kontor-gin/cmd/kontor-gin/main.go new file mode 100644 index 0000000..c2afa42 --- /dev/null +++ b/kontor-gin/cmd/kontor-gin/main.go @@ -0,0 +1,88 @@ +package main + +import ( + // "kontor-api-gin/pkg/handler" + + "kontor-api-gin/pkg/globals" + "kontor-api-gin/pkg/middleware" + "kontor-api-gin/pkg/routes" + "kontor-api-gin/pkg/schema" + "log" + "log/slog" + "os" + + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + gin_slog "github.com/gin-contrib/slog" + "github.com/gin-gonic/gin" +) + +func main() { + slog.Info("Kontor started") + + // Set Gin mode based on environment + // Production mode disables debug output + if os.Getenv("GIN_MODE") == "release" { + gin.SetMode(gin.ReleaseMode) + } + + // Connect to database + schema.Connect() + + // Run migrations + schema.RunMigrations() + + // Create Gin router with default middleware + // Default includes Logger and Recovery middleware + // router := gin.Default() + // Create a new router without default mmiddleware + router := gin.New() + // Add recovery middleware + router.Use(gin.Recovery()) + router.Use(gin_slog.SetLogger( + gin_slog.WithSkipPath([]string{"/health", "/public/style/main.css"}), + gin_slog.WithDefaultLevel(slog.LevelInfo), + gin_slog.WithClientErrorLevel(slog.LevelInfo), + gin_slog.WithServerErrorLevel(slog.LevelInfo), + )) + + router.LoadHTMLGlob("templates/**/*.html") + router.Static("/public", "./assets") + + router.Use(sessions.Sessions("session", cookie.NewStore(globals.Secret))) + + // Setup api routes + api := routes.SetupApiRoutes(router) + api.Use(middleware.CorsMiddleware) + routes.SetupMediaRoutes(api) + routes.SetupComicRoutes(api) + + // Setup public Webapp routes + routes.PublicRoutes(router) + + // Setup protected Webapp routes + protected := router.Group("/auth") + protected.Use(middleware.AuthRequired) + routes.ProtectedRoutes(router) + + comics := router.Group("/comics") + comics.Use(middleware.AuthRequired) + routes.ComicRoutes(router) + + media := router.Group("/media") + media.Use(middleware.AuthRequired) + routes.MediaRoutes(router) + + // Start server + port := os.Getenv("PORT") + if port == "" { + port = "8550" + } + + slog.Info("Server starting", "port", port) + if err := router.Run(":" + port); err != nil { + log.Fatal("Failed to start server:", err) + } + + slog.Info("Kontor finished") +} diff --git a/kontor-gin/cmd/kontor/main.go b/kontor-gin/cmd/kontor/main.go index 4b07ef2..43ba1b4 100644 --- a/kontor-gin/cmd/kontor/main.go +++ b/kontor-gin/cmd/kontor/main.go @@ -49,7 +49,7 @@ func main() { gin_slog.WithServerErrorLevel(slog.LevelInfo), )) - templ := template.Must(template.New("").ParseFS(templates.TemplateFiles, "html/*.tmpl")) + templ := template.Must(template.New("").ParseFS(templates.TemplateFiles, "layouts/*.html", "pages/*.html")) router.SetHTMLTemplate(templ) router.StaticFS("/public", http.FS(assets.StaticFiles)) diff --git a/kontor-gin/pkg/controllers/auth.go b/kontor-gin/pkg/controllers/auth.go index 76e1445..dd70a8e 100644 --- a/kontor-gin/pkg/controllers/auth.go +++ b/kontor-gin/pkg/controllers/auth.go @@ -15,9 +15,9 @@ func LoginGetHandler(c *gin.Context) { session := sessions.Default(c) user := session.Get(globals.UserKey) logger := slog.Get(c) - logger.Info("LoginGetHandler", "user", user) + logger.Info("LoginGetHandler", globals.UserKey, user) if user != nil { - c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + c.HTML(http.StatusBadRequest, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -26,7 +26,7 @@ func LoginGetHandler(c *gin.Context) { }) return } - c.HTML(http.StatusOK, "login.tmpl", gin.H{ + c.HTML(http.StatusOK, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -41,7 +41,7 @@ func LoginPostHandler(c *gin.Context) { logger := slog.Get(c) logger.Info("LoginPostHandler", "user", user) if user != nil { - c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + c.HTML(http.StatusBadRequest, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -54,7 +54,7 @@ func LoginPostHandler(c *gin.Context) { password := c.PostForm("password") if helpers.EmptyUserPass(username, password) { - c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + c.HTML(http.StatusBadRequest, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -63,7 +63,7 @@ func LoginPostHandler(c *gin.Context) { } if !helpers.CheckUserPass(username, password) { - c.HTML(http.StatusUnauthorized, "login.tmpl", gin.H{ + c.HTML(http.StatusUnauthorized, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -73,7 +73,7 @@ func LoginPostHandler(c *gin.Context) { session.Set(globals.UserKey, username) if err := session.Save(); err != nil { - c.HTML(http.StatusInternalServerError, "login.tmpl", gin.H{ + c.HTML(http.StatusInternalServerError, "login.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "login": globals.LoginUrl, @@ -90,7 +90,7 @@ func LogoutGetHandler(c *gin.Context) { session := sessions.Default(c) user := session.Get(globals.UserKey) logger := slog.Get(c) - logger.Info("LogoutGetHandler", "user", user) + logger.Info("LogoutGetHandler", globals.UserKey, user) if user == nil { logger.Info("Invalid session token") return diff --git a/kontor-gin/pkg/controllers/handlers.go b/kontor-gin/pkg/controllers/handlers.go index 7cfddd2..1d1c8b9 100644 --- a/kontor-gin/pkg/controllers/handlers.go +++ b/kontor-gin/pkg/controllers/handlers.go @@ -13,11 +13,12 @@ func IndexGetHandler(c *gin.Context) { session := sessions.Default(c) user := session.Get(globals.UserKey) logger := slog.Get(c) - logger.Info("IndexGetHandler", "user", user) - c.HTML(http.StatusOK, "index.tmpl", gin.H{ + logger.Info("IndexGetHandler", globals.UserKey, user) + c.HTML(http.StatusOK, "home.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "content": "This is an index page...", + "login": globals.LoginUrl, "logout": globals.LogoutUrl, "user": user, }) diff --git a/kontor-gin/pkg/controllers/media.go b/kontor-gin/pkg/controllers/media.go index 24863bc..0806658 100644 --- a/kontor-gin/pkg/controllers/media.go +++ b/kontor-gin/pkg/controllers/media.go @@ -30,25 +30,24 @@ func ListMediaLoFis(c *gin.Context) { result := schema.DB.Find(&lofis) log.Printf("found %d MediaLoFis", result.RowsAffected) c.JSON(http.StatusOK, lofis) - // c.JSON(http.StatusOK, gin.H{ - // "message": "All MediaLoFis", - // "lofis": lofis, - // }) } func ListMediaActorsGetHandler(c *gin.Context) { session := sessions.Default(c) user := session.Get(globals.UserKey) + logger := slog.Get(c) var actors []schema.MediaActor result := schema.DB.Find(&actors) - log.Printf("found %d MediaActors", result.RowsAffected) - c.HTML(http.StatusOK, "media_actor.tmpl", gin.H{ + logger.Info("ListMediaActorsGetHandler", "count", result.RowsAffected) + c.HTML(http.StatusOK, "mediaactors.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "content": "Media Actors...", "actors": actors, + "login": globals.LoginUrl, + "logout": globals.LogoutUrl, "user": user, }) } @@ -61,12 +60,14 @@ func ListMediaFilesGetHandler(c *gin.Context) { var files []schema.MediaFile result := schema.DB.Find(&files) - logger.Info("found MediaFiles", "count", result.RowsAffected) - c.HTML(http.StatusOK, "media_files.tmpl", gin.H{ + logger.Info("ListMediaFilesGetHandler", "count", result.RowsAffected) + c.HTML(http.StatusOK, "mediafiles.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "content": "Media Files...", "files": files, + "login": globals.LoginUrl, + "logout": globals.LogoutUrl, "user": user, }) @@ -80,14 +81,14 @@ func ListMediaLoFisGetHandler(c *gin.Context) { var lofis []schema.MediaLoFi result := schema.DB.Find(&lofis) - logger.Info("found MediaActors", "count", result.RowsAffected) - c.HTML(http.StatusOK, "media_lofi.tmpl", gin.H{ + logger.Info("ListMediaLoFisGetHandler", "count", result.RowsAffected) + c.HTML(http.StatusOK, "media_lofi.html", gin.H{ "title": "Kontor Gin", "version": "0.4.0", "content": "Media LoFis...", "lofis": lofis, + "login": globals.LoginUrl, "logout": globals.LogoutUrl, "user": user, }) - } diff --git a/kontor-gin/pkg/globals/globals.go b/kontor-gin/pkg/globals/globals.go index 3716acb..3fa65fb 100644 --- a/kontor-gin/pkg/globals/globals.go +++ b/kontor-gin/pkg/globals/globals.go @@ -6,6 +6,6 @@ const UserKey = "user" const Version = "0.4.0" -const LoginUrl = "/login" +const LoginUrl = "/auth/login" -const LogoutUrl = "/exit" +const LogoutUrl = "/auth/logout" diff --git a/kontor-gin/pkg/routes/webapp.go b/kontor-gin/pkg/routes/webapp.go index c291058..40127f7 100644 --- a/kontor-gin/pkg/routes/webapp.go +++ b/kontor-gin/pkg/routes/webapp.go @@ -3,21 +3,32 @@ package routes import ( "kontor-api-gin/pkg/controllers" "kontor-api-gin/pkg/globals" + "kontor-api-gin/pkg/middleware" "github.com/gin-gonic/gin" ) -func PublicRoutes(g *gin.RouterGroup) { +func PublicRoutes(g *gin.Engine) { g.GET("/health", controllers.HealthGetHandler) g.GET(globals.LoginUrl, controllers.LoginGetHandler) g.POST(globals.LoginUrl, controllers.LoginPostHandler) - g.GET("/comic/comics", controllers.ListComicsGetHandler) - g.GET("", controllers.IndexGetHandler) + g.GET("/", controllers.IndexGetHandler) } -func ProtectedRoutes(g *gin.RouterGroup) { - g.GET(globals.LogoutUrl, controllers.LogoutGetHandler) - g.GET("/media/actors", controllers.ListMediaActorsGetHandler) - // g.GET("/media/files", controllers.ListMediaFilesGetHandler) - g.GET("/media/lofis", controllers.ListMediaLoFisGetHandler) +func ComicRoutes(g *gin.Engine) { + g.GET("/comic/comics", controllers.ListComicsGetHandler) +} + +func MediaRoutes(g *gin.Engine) { + media := g.Group("/media") + media.Use(middleware.AuthRequired) + media.GET("/actors", controllers.ListMediaActorsGetHandler) + media.GET("/files", controllers.ListMediaFilesGetHandler) + media.GET("/lofis", controllers.ListMediaLoFisGetHandler) +} + +func ProtectedRoutes(g *gin.Engine) { + auth := g.Group("/auth") + auth.Use(middleware.AuthRequired) + auth.GET("/logout", controllers.LogoutGetHandler) } diff --git a/kontor-gin/templates/html/comic_comics.tmpl b/kontor-gin/templates/html/comic_comics.tmpl deleted file mode 100644 index efca0a7..0000000 --- a/kontor-gin/templates/html/comic_comics.tmpl +++ /dev/null @@ -1,58 +0,0 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} -
{{ .content }}
-
-
- - - - - -
-
-
-
- - - - - - - - - {{ range .comics }} - - - {{ if .Publisher }} - - {{ else }} - - {{ end }} - - - - - {{ end }} - -
TitlePublisherCompletedActions
{{.Title}}{{.Publisher.Name}}Publisher not set - {{ if .Completed }} - true - {{ else }} - true - {{ end }} - EditDelete
-
-
- - {{ template "footer.tmpl" . }} - - diff --git a/kontor-gin/templates/html/footer.tmpl b/kontor-gin/templates/html/footer.tmpl deleted file mode 100644 index be72ca1..0000000 --- a/kontor-gin/templates/html/footer.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -{{ define "footer.tmpl" }} - -{{end}} diff --git a/kontor-gin/templates/html/header.tmpl b/kontor-gin/templates/html/header.tmpl deleted file mode 100644 index acbbd6b..0000000 --- a/kontor-gin/templates/html/header.tmpl +++ /dev/null @@ -1,14 +0,0 @@ -{{ define "header.tmpl" }} - - - - - - {{ .title }} - -{{ end }} diff --git a/kontor-gin/templates/html/index.tmpl b/kontor-gin/templates/html/index.tmpl deleted file mode 100644 index a3e7487..0000000 --- a/kontor-gin/templates/html/index.tmpl +++ /dev/null @@ -1,12 +0,0 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} -
{{ .title }}
- - {{ template "footer.tmpl" . }} - - diff --git a/kontor-gin/templates/html/media_actor.tmpl b/kontor-gin/templates/html/media_actor.tmpl deleted file mode 100644 index 6663d53..0000000 --- a/kontor-gin/templates/html/media_actor.tmpl +++ /dev/null @@ -1,12 +0,0 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} -
{{ .content }}
- - {{ template "footer.tmpl" . }} - - diff --git a/kontor-gin/templates/html/media_files.tmpl b/kontor-gin/templates/html/media_files.tmpl deleted file mode 100644 index 6663d53..0000000 --- a/kontor-gin/templates/html/media_files.tmpl +++ /dev/null @@ -1,12 +0,0 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} -
{{ .content }}
- - {{ template "footer.tmpl" . }} - - diff --git a/kontor-gin/templates/html/media_lofi.tmpl b/kontor-gin/templates/html/media_lofi.tmpl deleted file mode 100644 index 6663d53..0000000 --- a/kontor-gin/templates/html/media_lofi.tmpl +++ /dev/null @@ -1,12 +0,0 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} -
{{ .content }}
- - {{ template "footer.tmpl" . }} - - diff --git a/kontor-gin/templates/layouts/main.html b/kontor-gin/templates/layouts/main.html new file mode 100644 index 0000000..2235cf5 --- /dev/null +++ b/kontor-gin/templates/layouts/main.html @@ -0,0 +1,24 @@ +{{ define "main" }} + + + + + + + + {{ .title }} + + + +
+ {{ template "navbar" . }} + {{ template "content" . }} + + + +{{ end }} diff --git a/kontor-gin/templates/html/navbar.tmpl b/kontor-gin/templates/layouts/navbar.html similarity index 60% rename from kontor-gin/templates/html/navbar.tmpl rename to kontor-gin/templates/layouts/navbar.html index e61d977..a6c2c73 100644 --- a/kontor-gin/templates/html/navbar.tmpl +++ b/kontor-gin/templates/layouts/navbar.html @@ -1,13 +1,13 @@ -{{ define "navbar.tmpl" }} +{{ define "navbar" }}
Kontor Comics Media Lofi {{ if .user }} - Logout + Logout {{ else }} - Login + Login {{ end }}
{{ end }} diff --git a/kontor-gin/templates/pages/comics.html b/kontor-gin/templates/pages/comics.html new file mode 100644 index 0000000..28829b8 --- /dev/null +++ b/kontor-gin/templates/pages/comics.html @@ -0,0 +1,52 @@ +{{ define "comics.html" }} +{{ template "main" . }} +{{ end }} + +{{ define "content" }} +
+
+ + + + + +
+
+
+
+ + + + + + + + + {{ range .comics }} + + + {{ if .Publisher }} + + {{ else }} + + {{ end }} + + + + + {{ end }} + +
TitlePublisherCompletedActions
{{.Title}}{{.Publisher.Name}}Publisher not set + {{ if .Completed }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+{{ end }} diff --git a/kontor-gin/templates/pages/home.html b/kontor-gin/templates/pages/home.html new file mode 100644 index 0000000..e27dd85 --- /dev/null +++ b/kontor-gin/templates/pages/home.html @@ -0,0 +1,7 @@ +{{ define "home.html" }} +{{ template "main" . }} +{{ end }} + +{{ define "content" }} +

{{ .content }}

+{{ end }} diff --git a/kontor-gin/templates/pages/lofi.html b/kontor-gin/templates/pages/lofi.html new file mode 100644 index 0000000..b0dc02c --- /dev/null +++ b/kontor-gin/templates/pages/lofi.html @@ -0,0 +1,52 @@ +{{ define "media_lofi.html" }} +{{ template "main" . }} +{{ end }} + +{{ define "content" }} +
+
+ + + + + +
+
+
+
+ + + + + + + + + {{ range .comics }} + + + {{ if .WebLink }} + + {{ else }} + + {{ end }} + + + + + {{ end }} + +
TitlePublisherCompletedActions
{{.Title}}{{.Title}}WebLink not set + {{ if .Review }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+{{ end }} diff --git a/kontor-gin/templates/html/login.tmpl b/kontor-gin/templates/pages/login.html similarity index 84% rename from kontor-gin/templates/html/login.tmpl rename to kontor-gin/templates/pages/login.html index 92f6948..b596105 100644 --- a/kontor-gin/templates/html/login.tmpl +++ b/kontor-gin/templates/pages/login.html @@ -1,11 +1,8 @@ - - -{{ template "header.tmpl" . }} - - -
- {{ template "navbar.tmpl" . }} +{{ define "login.html" }} +{{ template "main" . }} +{{ end }} +{{ define "content" }}
@@ -34,7 +31,4 @@
- - {{ template "footer.tmpl" . }} - - +{{ end }} diff --git a/kontor-gin/templates/pages/mediaactors.html b/kontor-gin/templates/pages/mediaactors.html new file mode 100644 index 0000000..e27dd85 --- /dev/null +++ b/kontor-gin/templates/pages/mediaactors.html @@ -0,0 +1,7 @@ +{{ define "home.html" }} +{{ template "main" . }} +{{ end }} + +{{ define "content" }} +

{{ .content }}

+{{ end }} diff --git a/kontor-gin/templates/pages/mediafiles.html b/kontor-gin/templates/pages/mediafiles.html new file mode 100644 index 0000000..9b6a5e3 --- /dev/null +++ b/kontor-gin/templates/pages/mediafiles.html @@ -0,0 +1,7 @@ +{{ define "mediafiles.html" }} +{{ template "main" . }} +{{ end }} + +{{ define "content" }} +

{{ .content }}

+{{ end }}