diff --git a/kontor-fiber/Containerfile b/kontor-fiber/Containerfile index 4e303fb..84a867a 100644 --- a/kontor-fiber/Containerfile +++ b/kontor-fiber/Containerfile @@ -21,5 +21,6 @@ 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/views /app/views +COPY --from=builder /app/static /app/static # Set the entrypoint command ENTRYPOINT ["/app/kontor"] diff --git a/kontor-fiber/cmd/kontor/main.go b/kontor-fiber/cmd/kontor/main.go index ba744c1..62575da 100644 --- a/kontor-fiber/cmd/kontor/main.go +++ b/kontor-fiber/cmd/kontor/main.go @@ -32,7 +32,7 @@ func main() { app.Get("/health", handler.GetHealth) app.Post("/login", handler.Login) - app.Get("/", web.Mainpage) + web.SetupRoutes(app) //api := app.Group("/api/v1") api := app.Group("/api/v1", logger.New(), jwtware.New(jwtware.Config{ @@ -54,7 +54,7 @@ func main() { }, })) // Listen on port 8900 - app.Listen(":8510") + app.Listen(":8500") log.Println("Kontor finished") } diff --git a/kontor-fiber/pkg/web/routes.go b/kontor-fiber/pkg/web/routes.go new file mode 100644 index 0000000..3789ef0 --- /dev/null +++ b/kontor-fiber/pkg/web/routes.go @@ -0,0 +1,12 @@ +package web + +import ( + "github.com/gofiber/fiber/v3" +) + +func SetupRoutes(app *fiber.App) { + app.Get("/", Mainpage) + app.Get("/comic/comics", Mainpage) + app.Get("/media/files", Mainpage) + +} diff --git a/kontor-gin/assets/assets.go b/kontor-gin/assets/assets.go new file mode 100644 index 0000000..5950723 --- /dev/null +++ b/kontor-gin/assets/assets.go @@ -0,0 +1,8 @@ +package assets + +import ( + "embed" +) + +//go:embed style/* +var StaticFiles embed.FS diff --git a/kontor-gin/assets/main.css b/kontor-gin/assets/main.css new file mode 100644 index 0000000..8b5c0c3 --- /dev/null +++ b/kontor-gin/assets/main.css @@ -0,0 +1,172 @@ +* { + box-sizing: border-box; +} + +body { + font-family: Arial; + padding: 10px; + background: lightgrey; +} + +/* Header/Blog Title */ +.header { + padding: 30px; + text-align: center; + background-color: lightblue; +} + +.header h1 { + font-size: 50px; +} + +/* Style the top navigation bar */ +.topnav { + overflow: hidden; + background-color: darkgrey; +} + +/* Style the topnav links */ +.topnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +/* Change color on hover */ +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.subnav { + overflow: hidden; + background-color: grey; +} + +.subnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +.form-inline { + display: flex; + flex-flow: row wrap; + align-items: center; + padding-top: 10px; + padding-left: 20px; +} + +.form-inline label { + margin: 5px 10px 5px 0; +} + +.form-inline input { + padding-right: 50px; + margin-right: 10px; +} + +.form-inline button { + padding: 10px 20px; + background-color: dodgerblue; + border: 1px solid #ddd; + color: white; + border-radius: 10px; +} + +.form-inline button:hover { + background-color: royalblue; +} + +.pill-nav a { + display: inline-block; + color: white; + background-color: dodgerblue; + text-align: center; + padding: 10px; + text-decoration: none; + border-radius: 10px; + margin-left: 20px; +} + +/* Change the color of links on mouse-over */ +.pill-nav a:hover { + background-color: royalblue; + color: white; +} + +/* Add a color to the active/current link */ +.pill-nav a.active { + background-color: royalblue; + color: white; +} + +.maincolumn { + float:left; + width: 100%; +} +/* Create two unequal columns that floats next to each other */ +/* Left column */ +.leftcolumn { + float: left; + width: 75%; +} + +/* Right column */ +.rightcolumn { + float: left; + width: 25%; + background-color: #f1f1f1; + padding-left: 20px; +} + +/* Fake image */ +.fakeimg { + background-color: #aaa; + width: 100%; + padding: 20px; +} + +/* Add a card effect for articles */ +.card { + background-color: white; + padding: 20px; + margin-top: 20px; +} + +/* Clear floats after the columns */ +.row::after { + content: ""; + display: table; + clear: both; +} + +/* Footer */ +.footer { + padding: 20px; + text-align: center; + background: #ddd; + margin-top: 20px; +} + +/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 800px) { + .leftcolumn, .rightcolumn { + width: 100%; + padding: 0; + } +} + +/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */ +@media screen and (max-width: 400px) { + .topnav a { + float: none; + width: 100%; + } +} diff --git a/kontor-gin/assets/style/main.css b/kontor-gin/assets/style/main.css new file mode 100644 index 0000000..8b5c0c3 --- /dev/null +++ b/kontor-gin/assets/style/main.css @@ -0,0 +1,172 @@ +* { + box-sizing: border-box; +} + +body { + font-family: Arial; + padding: 10px; + background: lightgrey; +} + +/* Header/Blog Title */ +.header { + padding: 30px; + text-align: center; + background-color: lightblue; +} + +.header h1 { + font-size: 50px; +} + +/* Style the top navigation bar */ +.topnav { + overflow: hidden; + background-color: darkgrey; +} + +/* Style the topnav links */ +.topnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +/* Change color on hover */ +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.subnav { + overflow: hidden; + background-color: grey; +} + +.subnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +.form-inline { + display: flex; + flex-flow: row wrap; + align-items: center; + padding-top: 10px; + padding-left: 20px; +} + +.form-inline label { + margin: 5px 10px 5px 0; +} + +.form-inline input { + padding-right: 50px; + margin-right: 10px; +} + +.form-inline button { + padding: 10px 20px; + background-color: dodgerblue; + border: 1px solid #ddd; + color: white; + border-radius: 10px; +} + +.form-inline button:hover { + background-color: royalblue; +} + +.pill-nav a { + display: inline-block; + color: white; + background-color: dodgerblue; + text-align: center; + padding: 10px; + text-decoration: none; + border-radius: 10px; + margin-left: 20px; +} + +/* Change the color of links on mouse-over */ +.pill-nav a:hover { + background-color: royalblue; + color: white; +} + +/* Add a color to the active/current link */ +.pill-nav a.active { + background-color: royalblue; + color: white; +} + +.maincolumn { + float:left; + width: 100%; +} +/* Create two unequal columns that floats next to each other */ +/* Left column */ +.leftcolumn { + float: left; + width: 75%; +} + +/* Right column */ +.rightcolumn { + float: left; + width: 25%; + background-color: #f1f1f1; + padding-left: 20px; +} + +/* Fake image */ +.fakeimg { + background-color: #aaa; + width: 100%; + padding: 20px; +} + +/* Add a card effect for articles */ +.card { + background-color: white; + padding: 20px; + margin-top: 20px; +} + +/* Clear floats after the columns */ +.row::after { + content: ""; + display: table; + clear: both; +} + +/* Footer */ +.footer { + padding: 20px; + text-align: center; + background: #ddd; + margin-top: 20px; +} + +/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 800px) { + .leftcolumn, .rightcolumn { + width: 100%; + padding: 0; + } +} + +/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */ +@media screen and (max-width: 400px) { + .topnav a { + float: none; + width: 100%; + } +} diff --git a/kontor-gin/cmd/kontor/main.go b/kontor-gin/cmd/kontor/main.go index b42b24f..095e604 100644 --- a/kontor-gin/cmd/kontor/main.go +++ b/kontor-gin/cmd/kontor/main.go @@ -2,11 +2,19 @@ package main import ( // "kontor-api-gin/pkg/handler" + "html/template" + "kontor-api-gin/assets" + "kontor-api-gin/pkg/globals" + "kontor-api-gin/pkg/middleware" "kontor-api-gin/pkg/routes" "kontor-api-gin/pkg/schema" + "kontor-api-gin/templates" "log" + "net/http" "os" + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" ) @@ -27,18 +35,40 @@ func main() { // Create Gin router with default middleware // Default includes Logger and Recovery middleware - router := gin.Default() + //router := gin.Default() + // Create a new router without default mmiddleware + router := gin.New() + templ := template.Must(template.New("").ParseFS(templates.TemplateFiles, "html/*.tmpl")) + router.SetHTMLTemplate(templ) + + router.StaticFS("/public", http.FS(assets.StaticFiles)) // Add CORS middleware for frontend access - router.Use(corsMiddleware()) + // router.Use(middleware.CorsMiddleware) - // Setup application routes + router.Use(gin.LoggerWithConfig(gin.LoggerConfig{ + SkipPaths: []string{"/health", "/metrics"}, + })) + // Add recovery middleware + router.Use(gin.Recovery()) + + router.Use(sessions.Sessions("session", cookie.NewStore(globals.Secret))) + // Setup api routes api := routes.SetupApiRoutes(router) routes.SetupMediaRoutes(api) + // Setup public Webapp routes + public := router.Group("/") + routes.PublicRoutes(public) + + // Setup protected Webapp routes + protected := router.Group("/") + protected.Use(middleware.AuthRequired) + routes.ProtectedRoutes(protected) + // Health check endpoint router.GET("/health", func(c *gin.Context) { - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "status": "healthy", }) }) @@ -56,19 +86,3 @@ func main() { log.Println("Kontor finished") } - -// corsMiddleware adds CORS headers for cross-origin requests -func corsMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") - - if c.Request.Method == "OPTIONS" { - c.AbortWithStatus(204) - return - } - - c.Next() - } -} diff --git a/kontor-gin/go.mod b/kontor-gin/go.mod index b628a62..75c70ee 100644 --- a/kontor-gin/go.mod +++ b/kontor-gin/go.mod @@ -8,6 +8,7 @@ require ( github.com/bytedance/sonic/loader v0.5.2 // indirect github.com/cloudwego/base64x v0.1.7 // indirect github.com/gabriel-vasile/mimetype v1.4.15 // indirect + github.com/gin-contrib/sessions v1.1.2 // indirect github.com/gin-contrib/sse v1.1.2 // indirect github.com/gin-gonic/gin v1.12.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -16,6 +17,9 @@ require ( github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/context v1.1.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.4.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.11.0 // indirect diff --git a/kontor-gin/go.sum b/kontor-gin/go.sum index 757df08..1908f13 100644 --- a/kontor-gin/go.sum +++ b/kontor-gin/go.sum @@ -10,6 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI= github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ= +github.com/gin-contrib/sessions v1.1.2 h1:utWRqOHT/kbqxxqF/mtutV9wfGLi1+uu5YuvWUhj/Ow= +github.com/gin-contrib/sessions v1.1.2/go.mod h1:qRxYwA/TYJw0wv28oFzs4gY/8G8z69id862SNgX9Gmw= github.com/gin-contrib/sse v1.1.2 h1:MU2fgl1RrdYTMcgJLtz2kJF+vPg3xrqaaKfUUU18tCo= github.com/gin-contrib/sse v1.1.2/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= @@ -27,6 +29,12 @@ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= +github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= +github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= diff --git a/kontor-gin/pkg/controllers/auth.go b/kontor-gin/pkg/controllers/auth.go new file mode 100644 index 0000000..6834f3f --- /dev/null +++ b/kontor-gin/pkg/controllers/auth.go @@ -0,0 +1,93 @@ +package controllers + +import ( + "kontor-api-gin/pkg/globals" + "kontor-api-gin/pkg/helpers" + "log" + "net/http" + + "github.com/gin-contrib/sessions" + + "github.com/gin-gonic/gin" +) + +func LoginGetHandler(c *gin.Context) { + session := sessions.Default(c) + user := session.Get(globals.UserKey) + if user != nil { + c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "Please logout first", + "user": user, + }) + return + } + c.HTML(http.StatusOK, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "", + "user": user, + }) +} + +func LoginPostHandler(c *gin.Context) { + session := sessions.Default(c) + user := session.Get(globals.UserKey) + if user != nil { + c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "Please logout first", + }) + return + } + + username := c.PostForm("username") + password := c.PostForm("password") + + if helpers.EmptyUserPass(username, password) { + c.HTML(http.StatusBadRequest, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "Parameters can't be empty", + }) + } + + if !helpers.CheckUserPass(username, password) { + c.HTML(http.StatusUnauthorized, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "Incorrect username or password", + }) + } + + session.Set(globals.UserKey, username) + if err := session.Save(); err != nil { + c.HTML(http.StatusInternalServerError, "login.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "Failed to save session", + }) + return + } + + c.Redirect(http.StatusMovedPermanently, "/") +} + +func LogoutGetHandler(c *gin.Context) { + session := sessions.Default(c) + user := session.Get(globals.UserKey) + log.Printf("logging out user %v", user) + if user == nil { + log.Println("Invalid session token") + return + } + session.Delete(globals.UserKey) + if err := session.Save(); err != nil { + log.Printf("Failed to save session: %v", err) + return + } + + c.Redirect(http.StatusMovedPermanently, "/") +} diff --git a/kontor-gin/pkg/controllers/handlers.go b/kontor-gin/pkg/controllers/handlers.go new file mode 100644 index 0000000..9b283c6 --- /dev/null +++ b/kontor-gin/pkg/controllers/handlers.go @@ -0,0 +1,20 @@ +package controllers + +import ( + "kontor-api-gin/pkg/globals" + "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +func IndexGetHandler(c *gin.Context) { + session := sessions.Default(c) + user := session.Get(globals.UserKey) + c.HTML(http.StatusOK, "index.tmpl", gin.H{ + "title": "Kontor Gin", + "version": "0.4.0", + "content": "This is an index page...", + "user": user, + }) +} diff --git a/kontor-gin/pkg/handlers/media.go b/kontor-gin/pkg/controllers/media.go similarity index 57% rename from kontor-gin/pkg/handlers/media.go rename to kontor-gin/pkg/controllers/media.go index d41acf3..8053e67 100644 --- a/kontor-gin/pkg/handlers/media.go +++ b/kontor-gin/pkg/controllers/media.go @@ -1,4 +1,4 @@ -package handlers +package controllers import ( "kontor-api-gin/pkg/schema" @@ -20,3 +20,15 @@ func ListMediaFiles(c *gin.Context) { "files": files, }) } + +func ListMediaLoFis(c *gin.Context) { + var lofis []schema.MediaLoFi + + 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, + // }) +} diff --git a/kontor-gin/pkg/globals/globals.go b/kontor-gin/pkg/globals/globals.go new file mode 100644 index 0000000..11bbad1 --- /dev/null +++ b/kontor-gin/pkg/globals/globals.go @@ -0,0 +1,5 @@ +package globals + +var Secret = []byte("secret") + +const UserKey = "user" diff --git a/kontor-gin/pkg/helpers/auth.go b/kontor-gin/pkg/helpers/auth.go new file mode 100644 index 0000000..f2c1a4d --- /dev/null +++ b/kontor-gin/pkg/helpers/auth.go @@ -0,0 +1,11 @@ +package helpers + +import "strings" + +func CheckUserPass(username, password string) bool { + return true +} + +func EmptyUserPass(username, password string) bool { + return strings.Trim(username, " ") == "" || strings.Trim(password, " ") == "" +} diff --git a/kontor-gin/pkg/middleware/authRequired.go b/kontor-gin/pkg/middleware/authRequired.go new file mode 100644 index 0000000..3077951 --- /dev/null +++ b/kontor-gin/pkg/middleware/authRequired.go @@ -0,0 +1,22 @@ +package middleware + +import ( + "log" + "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +func AuthRequired(c *gin.Context) { + session := sessions.Default(c) + user := session.Get("user") + log.Printf("current user %v", user) + if user == nil { + log.Println("User not logged in") + c.Redirect(http.StatusMovedPermanently, "/auth/login") + c.Abort() + return + } + c.Next() +} diff --git a/kontor-gin/pkg/middleware/cors.go b/kontor-gin/pkg/middleware/cors.go new file mode 100644 index 0000000..9194bec --- /dev/null +++ b/kontor-gin/pkg/middleware/cors.go @@ -0,0 +1,21 @@ +package middleware + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// corsMiddleware adds CORS headers for cross-origin requests +func CorsMiddleware(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") + + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(http.StatusNoContent) + return + } + + c.Next() +} diff --git a/kontor-gin/pkg/routes/media.go b/kontor-gin/pkg/routes/media.go index cc89bba..c762351 100644 --- a/kontor-gin/pkg/routes/media.go +++ b/kontor-gin/pkg/routes/media.go @@ -1,7 +1,7 @@ package routes import ( - "kontor-api-gin/pkg/handlers" + "kontor-api-gin/pkg/controllers" "github.com/gin-gonic/gin" ) @@ -11,6 +11,11 @@ func SetupMediaRoutes(router *gin.RouterGroup) { files := media.Group("/files") { - files.GET("", handlers.ListMediaFiles) + files.GET("", controllers.ListMediaFiles) + } + + lofi := media.Group("/lofi") + { + lofi.GET("", controllers.ListMediaLoFis) } } diff --git a/kontor-gin/pkg/routes/webapp.go b/kontor-gin/pkg/routes/webapp.go new file mode 100644 index 0000000..8aa1ca9 --- /dev/null +++ b/kontor-gin/pkg/routes/webapp.go @@ -0,0 +1,21 @@ +package routes + +import ( + "kontor-api-gin/pkg/controllers" + + "github.com/gin-gonic/gin" +) + +func PublicRoutes(g *gin.RouterGroup) { + g.GET("/auth/login", controllers.LoginGetHandler) + g.POST("/auth/login", controllers.LoginPostHandler) + g.GET("/", controllers.IndexGetHandler) +} + +func ProtectedRoutes(g *gin.RouterGroup) { + g.GET("/media/actors", controllers.IndexGetHandler) + g.GET("/comic/comics", controllers.IndexGetHandler) + g.GET("/media/files", controllers.IndexGetHandler) + g.GET("/media/lofis", controllers.IndexGetHandler) + g.GET("/auth/logout", controllers.LogoutGetHandler) +} diff --git a/kontor-gin/pkg/schema/media.go b/kontor-gin/pkg/schema/media.go index 7664a20..b4e2b40 100644 --- a/kontor-gin/pkg/schema/media.go +++ b/kontor-gin/pkg/schema/media.go @@ -1,37 +1,48 @@ package schema -import ( -) +type MediaLoFi struct { + Base + + WebLink string `gorm:"uniqueIndex" json:"url"` + Review bool `json:"review"` + ShouldDownload bool `json:"should_download"` + Title string `gorm:"size:300" json:"title"` + FileName string `json:"file_name"` +} + +func (media_lofi *MediaLoFi) TableName() string { + return "media_lofi" +} type MediaFile struct { Base - CloudLink string `json:"cloud_link"` - FileName string `json:"file_name"` - Path string `json:"path"` - Review bool `json:"review"` - Title string `gorm:"size:300" json:"title"` - WebLink string `gorm:"uniqueIndex" json:"url"` - ShouldDownload bool `json:"should_download"` + CloudLink string `json:"cloud_link"` + FileName string `json:"file_name"` + Path string `json:"path"` + Review bool `json:"review"` + Title string `gorm:"size:300" json:"title"` + WebLink string `gorm:"uniqueIndex" json:"url"` + ShouldDownload bool `json:"should_download"` MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaFileID" json:"media_actor_files"` } func (media_file *MediaFile) TableName() string { - return "media_file" + return "media_file" } type MediaActor struct { Base - Name string `json:"name"` - WebLink string `gorm:"uniqueIndex" json:"url"` + Name string `json:"name"` + WebLink string `gorm:"uniqueIndex" json:"url"` MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaActorID" json:"media_actor_files"` } func (media_actor *MediaActor) TableName() string { - return "media_actor" + return "media_actor" } type MediaActorFile struct { @@ -44,7 +55,7 @@ type MediaActorFile struct { } func (media_file *MediaActorFile) TableName() string { - return "media_actor_file" + return "media_actor_file" } // type MediaArticle struct { diff --git a/kontor-gin/templates/html/footer.tmpl b/kontor-gin/templates/html/footer.tmpl new file mode 100644 index 0000000..be72ca1 --- /dev/null +++ b/kontor-gin/templates/html/footer.tmpl @@ -0,0 +1,3 @@ +{{ define "footer.tmpl" }} + +{{end}} diff --git a/kontor-gin/templates/html/header.tmpl b/kontor-gin/templates/html/header.tmpl new file mode 100644 index 0000000..acbbd6b --- /dev/null +++ b/kontor-gin/templates/html/header.tmpl @@ -0,0 +1,14 @@ +{{ define "header.tmpl" }} + + + + + + {{ .title }} + +{{ end }} diff --git a/kontor-gin/templates/html/index.tmpl b/kontor-gin/templates/html/index.tmpl new file mode 100644 index 0000000..a3e7487 --- /dev/null +++ b/kontor-gin/templates/html/index.tmpl @@ -0,0 +1,12 @@ + + +{{ template "header.tmpl" . }} + + +
+ {{ template "navbar.tmpl" . }} +
{{ .title }}
+ + {{ template "footer.tmpl" . }} + + diff --git a/kontor-gin/templates/html/login.tmpl b/kontor-gin/templates/html/login.tmpl new file mode 100644 index 0000000..5a05568 --- /dev/null +++ b/kontor-gin/templates/html/login.tmpl @@ -0,0 +1,40 @@ + + +{{ template "header.tmpl" . }} + + +
+ {{ template "navbar.tmpl" . }} + +
+
+ +
+ + {{ if .content }} +
{{ .content }}
+ {{ end}} + +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+ + {{ template "footer.tmpl" . }} + + diff --git a/kontor-gin/templates/html/navbar.tmpl b/kontor-gin/templates/html/navbar.tmpl new file mode 100644 index 0000000..41e017f --- /dev/null +++ b/kontor-gin/templates/html/navbar.tmpl @@ -0,0 +1,12 @@ +{{ define "navbar.tmpl" }} +
+ Kontor + Comics + Media + {{ if .user }} + Logout + {{ else }} + Login + {{ end }} +
+{{ end }} diff --git a/kontor-gin/templates/templates.go b/kontor-gin/templates/templates.go new file mode 100644 index 0000000..5404b49 --- /dev/null +++ b/kontor-gin/templates/templates.go @@ -0,0 +1,8 @@ +package templates + +import ( + "embed" +) + +//go:embed html/* +var TemplateFiles embed.FS diff --git a/script/update b/script/update index 3203f0c..13b31da 100755 --- a/script/update +++ b/script/update @@ -11,7 +11,7 @@ source version echo "==> Stopping and removing pod kontor" if podman pod exists kontor; then podman pod stop kontor - pause 3 + #pause 3 podman pod rm kontor fi diff --git a/service/container/kontor-fiber.service b/service/container/kontor-fiber.service index 7fea759..d322f13 100644 --- a/service/container/kontor-fiber.service +++ b/service/container/kontor-fiber.service @@ -26,7 +26,7 @@ ExecStart=/usr/bin/podman run \ --name kontor-fiber \ --label io.containers.autoupdate=local \ --label PODMAN_SYSTEMD_UNIT=kontor-fiber.service \ - --health-cmd="curl -f http://kontor-echo:8500/health || exit 1" \ + --health-cmd="curl -f http://kontor-fiber:8500/health || exit 1" \ --health-interval=1s \ --health-timeout=5s \ --health-retries=10 \ diff --git a/service/container/kontor-gin.service b/service/container/kontor-gin.service new file mode 100644 index 0000000..9be8f59 --- /dev/null +++ b/service/container/kontor-gin.service @@ -0,0 +1,45 @@ +# kontor-gin.service +# autogenerated by Podman 4.9.3 +# Sun Apr 19 16:28:14 CEST 2026 + +[Unit] +Description=Podman kontor-gin.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers +BindsTo=pod-kontor.service +After=pod-kontor.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStart=/usr/bin/podman run \ + --cidfile=%t/%n.ctr-id \ + --cgroups=no-conmon \ + --rm \ + --pod-id-file %t/pod-kontor.pod-id \ + --sdnotify=conmon \ + -d \ + --replace \ + --name kontor-gin \ + --label io.containers.autoupdate=local \ + --label PODMAN_SYSTEMD_UNIT=kontor-gin.service \ + --health-cmd="curl -f http://kontor-gin:8550/health || exit 1" \ + --health-interval=1s \ + --health-timeout=5s \ + --health-retries=10 \ + localhost/kontor-gin:0.4.0 +ExecStop=/usr/bin/podman stop \ + --ignore -t 10 \ + --cidfile=%t/%n.ctr-id +ExecStopPost=/usr/bin/podman rm \ + -f \ + --ignore -t 10 \ + --cidfile=%t/%n.ctr-id +Type=notify +NotifyAccess=all + +[Install] +WantedBy=default.target