add templates for kontor-gin
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s

This commit is contained in:
Thomas Peetz
2026-09-21 19:55:46 +02:00
parent 652aa3005b
commit f2f4a0aaf6
28 changed files with 787 additions and 41 deletions
+1
View File
@@ -21,5 +21,6 @@ RUN apk add --no-cache ca-certificates tzdata curl
# Copy the binary and set ownership # Copy the binary and set ownership
COPY --from=builder /app/kontor /app/kontor COPY --from=builder /app/kontor /app/kontor
COPY --from=builder /app/views /app/views COPY --from=builder /app/views /app/views
COPY --from=builder /app/static /app/static
# Set the entrypoint command # Set the entrypoint command
ENTRYPOINT ["/app/kontor"] ENTRYPOINT ["/app/kontor"]
+2 -2
View File
@@ -32,7 +32,7 @@ func main() {
app.Get("/health", handler.GetHealth) app.Get("/health", handler.GetHealth)
app.Post("/login", handler.Login) app.Post("/login", handler.Login)
app.Get("/", web.Mainpage) web.SetupRoutes(app)
//api := app.Group("/api/v1") //api := app.Group("/api/v1")
api := app.Group("/api/v1", logger.New(), jwtware.New(jwtware.Config{ api := app.Group("/api/v1", logger.New(), jwtware.New(jwtware.Config{
@@ -54,7 +54,7 @@ func main() {
}, },
})) }))
// Listen on port 8900 // Listen on port 8900
app.Listen(":8510") app.Listen(":8500")
log.Println("Kontor finished") log.Println("Kontor finished")
} }
+12
View File
@@ -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)
}
+8
View File
@@ -0,0 +1,8 @@
package assets
import (
"embed"
)
//go:embed style/*
var StaticFiles embed.FS
+172
View File
@@ -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%;
}
}
+172
View File
@@ -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%;
}
}
+34 -20
View File
@@ -2,11 +2,19 @@ package main
import ( import (
// "kontor-api-gin/pkg/handler" // "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/routes"
"kontor-api-gin/pkg/schema" "kontor-api-gin/pkg/schema"
"kontor-api-gin/templates"
"log" "log"
"net/http"
"os" "os"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -27,18 +35,40 @@ func main() {
// Create Gin router with default middleware // Create Gin router with default middleware
// Default includes Logger and Recovery 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 // 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) api := routes.SetupApiRoutes(router)
routes.SetupMediaRoutes(api) 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 // Health check endpoint
router.GET("/health", func(c *gin.Context) { router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "healthy", "status": "healthy",
}) })
}) })
@@ -56,19 +86,3 @@ func main() {
log.Println("Kontor finished") 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()
}
}
+4
View File
@@ -8,6 +8,7 @@ require (
github.com/bytedance/sonic/loader v0.5.2 // indirect github.com/bytedance/sonic/loader v0.5.2 // indirect
github.com/cloudwego/base64x v0.1.7 // indirect github.com/cloudwego/base64x v0.1.7 // indirect
github.com/gabriel-vasile/mimetype v1.4.15 // 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-contrib/sse v1.1.2 // indirect
github.com/gin-gonic/gin v1.12.0 // indirect github.com/gin-gonic/gin v1.12.0 // indirect
github.com/go-playground/locales v0.14.1 // 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-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect github.com/goccy/go-yaml v1.19.2 // indirect
github.com/google/uuid v1.6.0 // 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/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.11.0 // indirect github.com/jackc/pgx/v5 v5.11.0 // indirect
+8
View File
@@ -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/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 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI=
github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ= 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 h1:MU2fgl1RrdYTMcgJLtz2kJF+vPg3xrqaaKfUUU18tCo=
github.com/gin-contrib/sse v1.1.2/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s= 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= 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/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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+93
View File
@@ -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, "/")
}
+20
View File
@@ -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,
})
}
@@ -1,4 +1,4 @@
package handlers package controllers
import ( import (
"kontor-api-gin/pkg/schema" "kontor-api-gin/pkg/schema"
@@ -20,3 +20,15 @@ func ListMediaFiles(c *gin.Context) {
"files": files, "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,
// })
}
+5
View File
@@ -0,0 +1,5 @@
package globals
var Secret = []byte("secret")
const UserKey = "user"
+11
View File
@@ -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, " ") == ""
}
+22
View File
@@ -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()
}
+21
View File
@@ -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()
}
+7 -2
View File
@@ -1,7 +1,7 @@
package routes package routes
import ( import (
"kontor-api-gin/pkg/handlers" "kontor-api-gin/pkg/controllers"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -11,6 +11,11 @@ func SetupMediaRoutes(router *gin.RouterGroup) {
files := media.Group("/files") files := media.Group("/files")
{ {
files.GET("", handlers.ListMediaFiles) files.GET("", controllers.ListMediaFiles)
}
lofi := media.Group("/lofi")
{
lofi.GET("", controllers.ListMediaLoFis)
} }
} }
+21
View File
@@ -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)
}
+13 -2
View File
@@ -1,7 +1,18 @@
package schema 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 { type MediaFile struct {
Base Base
+3
View File
@@ -0,0 +1,3 @@
{{ define "footer.tmpl" }}
<div class="footer">{{ .version }}</div>
{{end}}
+14
View File
@@ -0,0 +1,14 @@
{{ define "header.tmpl" }}
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="/public/style/main.css" />
<title>{{ .title }}</title>
</head>
{{ end }}
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="de-DE">
{{ template "header.tmpl" . }}
<body>
<div class="header"></div>
{{ template "navbar.tmpl" . }}
<div class="content">{{ .title }}</div>
{{ template "footer.tmpl" . }}
</body>
</html>
+40
View File
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="de-DE">
{{ template "header.tmpl" . }}
<body>
<div class="header"></div>
{{ template "navbar.tmpl" . }}
<div class="content">
<form action="/auth/login" method="post">
<div class="container" style="border: 1px solid lightgray; border-radius: 3px; padding: 15px;">
{{ if .content }}
<div class="notification is-danger">{{ .content }}</div>
{{ end}}
<div class="field">
<label class="label">Username</label>
<div class="control">
<input class="input" type="text" placeholder="Enter Username" name="username" required/>
</div>
</div>
<div class="field">
<label class="label">Passwort</label>
<div class="control">
<input class="input" type="password" placeholder="Enter Password" name="password" required/>
</div>
</div>
<div class="field">
<button class="button is-link">Submit</button>
</div>
</div>
</form>
</div>
{{ template "footer.tmpl" . }}
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
{{ define "navbar.tmpl" }}
<div class="topnav">
<a href="/">Kontor</a>
<a href="/comic/comics">Comics</a>
<a href="/media/files">Media</a>
{{ if .user }}
<a style="float:right" href="/auth/logout/">Logout</a></li>
{{ else }}
<a style="float:right" href="/auth/login/">Login</a></li>
{{ end }}
</div>
{{ end }}
+8
View File
@@ -0,0 +1,8 @@
package templates
import (
"embed"
)
//go:embed html/*
var TemplateFiles embed.FS
+1 -1
View File
@@ -11,7 +11,7 @@ source version
echo "==> Stopping and removing pod kontor" echo "==> Stopping and removing pod kontor"
if podman pod exists kontor; then if podman pod exists kontor; then
podman pod stop kontor podman pod stop kontor
pause 3 #pause 3
podman pod rm kontor podman pod rm kontor
fi fi
+1 -1
View File
@@ -26,7 +26,7 @@ ExecStart=/usr/bin/podman run \
--name kontor-fiber \ --name kontor-fiber \
--label io.containers.autoupdate=local \ --label io.containers.autoupdate=local \
--label PODMAN_SYSTEMD_UNIT=kontor-fiber.service \ --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-interval=1s \
--health-timeout=5s \ --health-timeout=5s \
--health-retries=10 \ --health-retries=10 \
+45
View File
@@ -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