This commit is contained in:
@@ -22,6 +22,6 @@ RUN apk add --no-cache ca-certificates tzdata curl
|
||||
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
|
||||
ENV GIN_MODE=release
|
||||
# Set the entrypoint command
|
||||
ENTRYPOINT ["/app/kontor-gin"]
|
||||
|
||||
@@ -4,5 +4,5 @@ import (
|
||||
"embed"
|
||||
)
|
||||
|
||||
//go:embed style/*
|
||||
//go:embed style/* icons/*
|
||||
var StaticFiles embed.FS
|
||||
|
||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 634 B After Width: | Height: | Size: 634 B |
@@ -1,172 +0,0 @@
|
||||
* {
|
||||
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%;
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,23 @@ import (
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
gin_slog "github.com/gin-contrib/slog"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func main() {
|
||||
slog.Info("Kontor started")
|
||||
|
||||
viper.SetDefault("db.host", "localhost")
|
||||
viper.SetDefault("db.port", 5432)
|
||||
viper.SetDefault("db.name", "kontor")
|
||||
viper.SetDefault("db.user", "kontor")
|
||||
viper.SetDefault("db.password", "kontor")
|
||||
viper.SetDefault("port", 8550)
|
||||
|
||||
if err := globals.InitConfig(); err != nil {
|
||||
slog.Info("Failed to initialize config", "error", err)
|
||||
}
|
||||
|
||||
// Set Gin mode based on environment
|
||||
// Production mode disables debug output
|
||||
if os.Getenv("GIN_MODE") == "release" {
|
||||
@@ -57,21 +69,11 @@ func main() {
|
||||
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)
|
||||
// Setup Webapp routes
|
||||
routes.AuthRoutes(router)
|
||||
routes.ComicRoutes(router)
|
||||
|
||||
media := router.Group("/media")
|
||||
media.Use(middleware.AuthRequired)
|
||||
routes.MediaRoutes(router)
|
||||
routes.PublicRoutes(router)
|
||||
|
||||
// Start server
|
||||
port := os.Getenv("PORT")
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
// "kontor-api-gin/pkg/handler"
|
||||
"fmt"
|
||||
|
||||
"html/template"
|
||||
"kontor-api-gin/assets"
|
||||
"kontor-api-gin/pkg/globals"
|
||||
@@ -13,8 +13,6 @@ import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
@@ -24,29 +22,6 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func initConfig() error {
|
||||
viper.SetConfigName("kontor-gin")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("$HOME/.config")
|
||||
viper.AddConfigPath("/etc/kontor")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// Read the config file
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
// Handle the case where config file is not found
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
slog.Info("No config file found, using defaults")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error reading config file: %w", err)
|
||||
}
|
||||
|
||||
slog.Info("initConfig", "Using config file: ", viper.ConfigFileUsed())
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
slog.Info("Kontor started")
|
||||
|
||||
@@ -56,14 +31,15 @@ func main() {
|
||||
viper.SetDefault("db.user", "kontor")
|
||||
viper.SetDefault("db.password", "kontor")
|
||||
viper.SetDefault("port", 8550)
|
||||
viper.SetDefault("gin.mode", "release")
|
||||
|
||||
if err := initConfig(); err != nil {
|
||||
log.Fatalf("Failed to initialize config: %v", err)
|
||||
}
|
||||
if err := globals.InitConfig(); err != nil {
|
||||
log.Fatalf("Failed to initialize config: %v", err)
|
||||
}
|
||||
|
||||
// Set Gin mode based on environment
|
||||
// Production mode disables debug output
|
||||
if os.Getenv("GIN_MODE") == "release" {
|
||||
if viper.GetString("gin.mode") == "release" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
@@ -100,21 +76,11 @@ func main() {
|
||||
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)
|
||||
// Setup Webapp routes
|
||||
routes.AuthRoutes(router)
|
||||
routes.ComicRoutes(router)
|
||||
|
||||
media := router.Group("/media")
|
||||
media.Use(middleware.AuthRequired)
|
||||
routes.MediaRoutes(router)
|
||||
routes.PublicRoutes(router)
|
||||
|
||||
// Start server
|
||||
port := viper.GetInt("port")
|
||||
|
||||
@@ -17,20 +17,20 @@ func LoginGetHandler(c *gin.Context) {
|
||||
logger := slog.Get(c)
|
||||
logger.Info("LoginGetHandler", globals.UserKey, user)
|
||||
if user != nil {
|
||||
c.HTML(http.StatusBadRequest, "login.html", gin.H{
|
||||
c.HTML(http.StatusBadRequest, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "Please logout first",
|
||||
"message": "Please logout first",
|
||||
"user": user,
|
||||
})
|
||||
return
|
||||
}
|
||||
c.HTML(http.StatusOK, "login.html", gin.H{
|
||||
c.HTML(http.StatusOK, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "",
|
||||
"message": "",
|
||||
"user": user,
|
||||
})
|
||||
}
|
||||
@@ -41,11 +41,11 @@ func LoginPostHandler(c *gin.Context) {
|
||||
logger := slog.Get(c)
|
||||
logger.Info("LoginPostHandler", "user", user)
|
||||
if user != nil {
|
||||
c.HTML(http.StatusBadRequest, "login.html", gin.H{
|
||||
c.HTML(http.StatusBadRequest, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "Please logout first",
|
||||
"message": "Please logout first",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -54,30 +54,30 @@ func LoginPostHandler(c *gin.Context) {
|
||||
password := c.PostForm("password")
|
||||
|
||||
if helpers.EmptyUserPass(username, password) {
|
||||
c.HTML(http.StatusBadRequest, "login.html", gin.H{
|
||||
c.HTML(http.StatusBadRequest, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "Parameters can't be empty",
|
||||
"message": "Parameters can't be empty",
|
||||
})
|
||||
}
|
||||
|
||||
if !helpers.CheckUserPass(username, password) {
|
||||
c.HTML(http.StatusUnauthorized, "login.html", gin.H{
|
||||
c.HTML(http.StatusUnauthorized, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "Incorrect username or password",
|
||||
"message": "Incorrect username or password",
|
||||
})
|
||||
}
|
||||
|
||||
session.Set(globals.UserKey, username)
|
||||
if err := session.Save(); err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "login.html", gin.H{
|
||||
c.HTML(http.StatusInternalServerError, "login", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"login": globals.LoginUrl,
|
||||
"content": "Failed to save session",
|
||||
"message": "Failed to save session",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ func ListComicsGetHandler(c *gin.Context) {
|
||||
var comics []schema.Comic
|
||||
|
||||
result := schema.DB.Find(&comics)
|
||||
logger.Info("found Comics", "count", result.RowsAffected)
|
||||
c.HTML(http.StatusOK, "comics.html", gin.H{
|
||||
logger.Info("ListComicsGetHandler", "count", result.RowsAffected)
|
||||
c.HTML(http.StatusOK, "comics", gin.H{
|
||||
"title": "Kontor Comics",
|
||||
"version": "0.4.0",
|
||||
"content": "Media Files...",
|
||||
"message": "Comics...",
|
||||
"comics": comics,
|
||||
"user": user,
|
||||
})
|
||||
|
||||
@@ -69,7 +69,7 @@ func ListComicStoryArcs(c *gin.Context) {
|
||||
|
||||
logger := slog.Get(c)
|
||||
result := schema.DB.Find(&items)
|
||||
logger.Info("found Comic StoryArcs", "count", result.RowsAffected)
|
||||
logger.Info("ListComicStoryArcs", "count", result.RowsAffected)
|
||||
c.JSON(http.StatusOK, items)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ func IndexGetHandler(c *gin.Context) {
|
||||
user := session.Get(globals.UserKey)
|
||||
logger := slog.Get(c)
|
||||
logger.Info("IndexGetHandler", globals.UserKey, user)
|
||||
c.HTML(http.StatusOK, "home.html", gin.H{
|
||||
c.HTML(http.StatusOK, "home", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"content": "This is an index page...",
|
||||
"message": "This is an index page...",
|
||||
"login": globals.LoginUrl,
|
||||
"logout": globals.LogoutUrl,
|
||||
"user": user,
|
||||
|
||||
@@ -3,7 +3,6 @@ package controllers
|
||||
import (
|
||||
"kontor-api-gin/pkg/globals"
|
||||
"kontor-api-gin/pkg/schema"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
@@ -13,11 +12,12 @@ import (
|
||||
|
||||
func ListMediaFiles(c *gin.Context) {
|
||||
var files []schema.MediaFile
|
||||
logger := slog.Get(c)
|
||||
|
||||
// query := schema.DB.Model(&schema.MediaFile{})
|
||||
// result := query.Find(&files)
|
||||
result := schema.DB.Find(&files)
|
||||
log.Printf("found %d MediaFiles", result.RowsAffected)
|
||||
logger.Info("ListMediaFiles", "count", result.RowsAffected)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "All MediaFiles",
|
||||
"files": files,
|
||||
@@ -26,9 +26,10 @@ func ListMediaFiles(c *gin.Context) {
|
||||
|
||||
func ListMediaLoFis(c *gin.Context) {
|
||||
var lofis []schema.MediaLoFi
|
||||
logger := slog.Get(c)
|
||||
|
||||
result := schema.DB.Find(&lofis)
|
||||
log.Printf("found %d MediaLoFis", result.RowsAffected)
|
||||
logger.Info("ListMediaLoFis", "count", result.RowsAffected)
|
||||
c.JSON(http.StatusOK, lofis)
|
||||
}
|
||||
|
||||
@@ -41,10 +42,10 @@ func ListMediaActorsGetHandler(c *gin.Context) {
|
||||
|
||||
result := schema.DB.Find(&actors)
|
||||
logger.Info("ListMediaActorsGetHandler", "count", result.RowsAffected)
|
||||
c.HTML(http.StatusOK, "mediaactors.html", gin.H{
|
||||
c.HTML(http.StatusOK, "mediaactors", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"content": "Media Actors...",
|
||||
"message": "Media Actors...",
|
||||
"actors": actors,
|
||||
"login": globals.LoginUrl,
|
||||
"logout": globals.LogoutUrl,
|
||||
@@ -61,10 +62,10 @@ func ListMediaFilesGetHandler(c *gin.Context) {
|
||||
|
||||
result := schema.DB.Find(&files)
|
||||
logger.Info("ListMediaFilesGetHandler", "count", result.RowsAffected)
|
||||
c.HTML(http.StatusOK, "mediafiles.html", gin.H{
|
||||
c.HTML(http.StatusOK, "mediafiles", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"content": "Media Files...",
|
||||
"message": "Media Files...",
|
||||
"files": files,
|
||||
"login": globals.LoginUrl,
|
||||
"logout": globals.LogoutUrl,
|
||||
@@ -82,10 +83,11 @@ func ListMediaLoFisGetHandler(c *gin.Context) {
|
||||
|
||||
result := schema.DB.Find(&lofis)
|
||||
logger.Info("ListMediaLoFisGetHandler", "count", result.RowsAffected)
|
||||
c.HTML(http.StatusOK, "media_lofi.html", gin.H{
|
||||
logger.Info("ListMediaLoFisGetHandler", "medialofi", lofis[0])
|
||||
c.HTML(http.StatusOK, "lofi", gin.H{
|
||||
"title": "Kontor Gin",
|
||||
"version": "0.4.0",
|
||||
"content": "Media LoFis...",
|
||||
"message": "Media LoFis...",
|
||||
"lofis": lofis,
|
||||
"login": globals.LoginUrl,
|
||||
"logout": globals.LogoutUrl,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func InitConfig() error {
|
||||
viper.SetConfigName("kontor-gin")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("$HOME/.config")
|
||||
viper.AddConfigPath("/etc/kontor")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// Read the config file
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
// Handle the case where config file is not found
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
slog.Info("No config file found, using defaults")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error reading config file: %w", err)
|
||||
}
|
||||
|
||||
slog.Info("initConfig", "Using config file: ", viper.ConfigFileUsed())
|
||||
return nil
|
||||
}
|
||||
@@ -6,6 +6,6 @@ const UserKey = "user"
|
||||
|
||||
const Version = "0.4.0"
|
||||
|
||||
const LoginUrl = "/auth/login"
|
||||
const LoginUrl = "/login"
|
||||
|
||||
const LogoutUrl = "/auth/logout"
|
||||
|
||||
@@ -27,7 +27,7 @@ func MediaRoutes(g *gin.Engine) {
|
||||
media.GET("/lofis", controllers.ListMediaLoFisGetHandler)
|
||||
}
|
||||
|
||||
func ProtectedRoutes(g *gin.Engine) {
|
||||
func AuthRoutes(g *gin.Engine) {
|
||||
auth := g.Group("/auth")
|
||||
auth.Use(middleware.AuthRequired)
|
||||
auth.GET("/logout", controllers.LogoutGetHandler)
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package schema
|
||||
|
||||
type MediaLoFi struct {
|
||||
Base
|
||||
import "time"
|
||||
|
||||
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"`
|
||||
type MediaLoFi struct {
|
||||
ID string `gorm:"type:string;primary_key;"`
|
||||
Created_Date time.Time `json:"created_date"`
|
||||
Last_Modified_date time.Time `json:"last_modified_date"`
|
||||
Deleted_Date *time.Time `json:"deleted_date"`
|
||||
Version int `gorm:"default:0" json:"version"`
|
||||
Url 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 {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ define "footer" }}
|
||||
<div class="footer">{{ .version }}</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{ define "head" }}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
|
||||
<link rel="stylesheet" href="/public/style/main.css" />
|
||||
<title>{{ .title }}</title>
|
||||
</head>
|
||||
{{ end }}
|
||||
@@ -1,13 +1,40 @@
|
||||
{{ define "navbar" }}
|
||||
<div class="topnav">
|
||||
<a href="/">Kontor</a>
|
||||
<a href="/comic/comics">Comics</a>
|
||||
<a href="/media/files">Media</a>
|
||||
<a href="/media/lofis">Lofi</a>
|
||||
{{ if .user }}
|
||||
<a style="float:right" href="{{ .logout }}">Logout</a></li>
|
||||
{{ else }}
|
||||
<a style="float:right" href="{{ .login }}">Login</a></li>
|
||||
{{ end }}
|
||||
<div class="container">
|
||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark" style="background-color: darkgrey;">
|
||||
<a class="navbar-brand" href="/">Kontor</a>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-item nav-link" href="/comic/comics">Comics</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Media</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
||||
<a class="dropdown-item" href="/media/files">Media Files</a>
|
||||
<a class="dropdown-item" href="/media/actors">Media Actors</a>
|
||||
<a class="dropdown-item" href="/media/lofis">Lofi</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/media/files">Media</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/media/lofis">Lofis</a>
|
||||
</li>
|
||||
{{ if .user }}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ .logout }}">Logout</a>
|
||||
</li>
|
||||
{{ else }}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ .login }}">Login</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
<form class="form-inline">
|
||||
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,52 +1,59 @@
|
||||
{{ define "comics.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "comics" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<div class="row">
|
||||
<form class="form-inline" action="/comic/comics">
|
||||
<input type="text" placeholder="Search" name="query">
|
||||
<label>
|
||||
<input type="checkbox" name="completed" {{ if .completed }}checked{{ end }}>Completed
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" name="order" {{ if .order }}checked{{ end }}>Order
|
||||
</label>
|
||||
<button type="submit">Search</button>
|
||||
<div class="pill-nav"><a href="/comic/comic/add">Add Comic</a></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="maincolumn">
|
||||
<table class="table table-hover">
|
||||
<thead><tr>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Publisher</th>
|
||||
<th scope="col">Completed</th>
|
||||
<th colspan="2">Actions</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{{ range .comics }}
|
||||
<tr>
|
||||
<th scope="row"><a href="/comic/comics/{{.ID}}">{{.Title}}</a></th>
|
||||
{{ if .Publisher }}
|
||||
<td><a href="/comic/publishers/{{.Publisher.ID}}">{{.Publisher.Name}}</a></td>
|
||||
{{ else }}
|
||||
<td>Publisher not set</td>
|
||||
{{ end }}
|
||||
<td>
|
||||
{{ if .Completed }}
|
||||
<img src="/tick.png" alt="true" width="24" height="24">
|
||||
{{ else }}
|
||||
<img src="/cross.png" alt="true" width="24" height="24">
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<div class="row">
|
||||
<form class="form-inline" action="/comic/comics">
|
||||
<input type="text" placeholder="Search" name="query">
|
||||
<label>
|
||||
<input type="checkbox" name="completed" {{ if .Completed }}checked{{ end }}>Completed
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" name="order" {{ if .CurrentOrder }}checked{{ end }}>Order
|
||||
</label>
|
||||
<button type="submit">Search</button>
|
||||
<div class="pill-nav"><a href="/comic/comic/add">Add Comic</a></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="maincolumn">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Publisher</th>
|
||||
<th scope="col">Completed</th>
|
||||
<th colspan="2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .comics }}
|
||||
<tr>
|
||||
<th scope="row"><a href="/comic/comics/{{.ID}}">{{.Title}}</a></th>
|
||||
{{ if .Publisher }}
|
||||
<td><a href="/comic/publishers/{{.Publisher.ID}}">{{.Publisher.Name}}</a></td>
|
||||
{{ else }}
|
||||
<td>Publisher not set</td>
|
||||
{{ end }}
|
||||
<td>
|
||||
{{ if .Completed }}
|
||||
<img src="/public/icons/tick.png" alt="true" width="24" height="24">
|
||||
{{ else }}
|
||||
<img src="/public/icons/cross.png" alt="true" width="24" height="24">
|
||||
{{ end }}
|
||||
</td>
|
||||
<td><a href="/comic/comics/edit/{{.ID}}" class="btn btn-outline-primary btn-sm active" role="button" aria-pressed="true">Edit</a></td>
|
||||
<td><a href="/comic/comics/delete/{{.ID}}" class="btn btn-outline-danger btn-sm active" role="button" aria-pressed="true">Delete</a></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td><a href="/comic/comics/edit/{{.ID}}" class="btn btn-outline-primary btn-sm active" role="button" aria-pressed="true">Edit</a></td>
|
||||
<td><a href="/comic/comics/delete/{{.ID}}" class="btn btn-outline-danger btn-sm active" role="button" aria-pressed="true">Delete</a></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{{ define "home.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "home" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<h1>{{ .content }}</h1>
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<h1>{{ .message }}</h1>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,52 +1,62 @@
|
||||
{{ define "media_lofi.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "lofi" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<div class="row">
|
||||
<form class="form-inline" action="/media/lofi">
|
||||
<input type="text" placeholder="Search" name="query">
|
||||
<label>
|
||||
<input type="checkbox" name="review" {{ if .Review }}checked{{ end }}>Completed
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" name="should_download" {{ if .ShouldDownload }}checked{{ end }}>Order
|
||||
</label>
|
||||
<button type="submit">Search</button>
|
||||
<div class="pill-nav"><a href="/media/lofi/add">Add Lofi</a></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="maincolumn">
|
||||
<table class="table table-hover">
|
||||
<thead><tr>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Publisher</th>
|
||||
<th scope="col">Completed</th>
|
||||
<th colspan="2">Actions</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{{ range .comics }}
|
||||
<tr>
|
||||
<th scope="row"><a href="/media/lofi/{{.ID}}">{{.Title}}</a></th>
|
||||
{{ if .WebLink }}
|
||||
<td><a href="{{.WebLink}}">{{.Title}}</a></td>
|
||||
{{ else }}
|
||||
<td>WebLink not set</td>
|
||||
{{ end }}
|
||||
<td>
|
||||
{{ if .Review }}
|
||||
<img src="/tick.png" alt="true" width="24" height="24">
|
||||
{{ else }}
|
||||
<img src="/cross.png" alt="true" width="24" height="24">
|
||||
{{ end }}
|
||||
</td>
|
||||
<td><a href="/media/lofi/edit/{{.ID}}" class="btn btn-outline-primary btn-sm active" role="button" aria-pressed="true">Edit</a></td>
|
||||
<td><a href="/media/lofi/delete/{{.ID}}" class="btn btn-outline-danger btn-sm active" role="button" aria-pressed="true">Delete</a></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<div class="row">
|
||||
<h1>Media Lofi</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<form class="form-inline" action="/media/lofis">
|
||||
<input type="text" placeholder="Search" name="query">
|
||||
<input>
|
||||
<input type="checkbox" name="review" {{ if .Review }}checked{{ end }}>Review
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" name="should_download" {{ if .ShouldDownload }}checked{{ end }}>Download
|
||||
</label>
|
||||
<button type="submit">Search</button>
|
||||
<div class="pill-nav"><a href="/media/lofis/add">Add Lofi</a></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="maincolumn">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Weblink</th>
|
||||
<th scope="col">Review</th>
|
||||
<th colspan="2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .lofis }}
|
||||
<tr>
|
||||
<th scope="row"><a href="/media/lofis/{{.ID}}">{{.Title}}</a></th>
|
||||
{{ if .Url }}
|
||||
<td><a href="{{.Url}}">{{.Url}}</a></td>
|
||||
{{ else }}
|
||||
<td>WebLink not set</td>
|
||||
{{ end }}
|
||||
<td>
|
||||
{{ if .Review }}
|
||||
<img src="/public/icons/tick.png" alt="true" width="24" height="24">
|
||||
{{ else }}
|
||||
<img src="/public/icons/cross.png" alt="true" width="24" height="24">
|
||||
{{ end }}
|
||||
</td>
|
||||
<td><a href="/media/lofis/edit/{{.ID}}" class="btn btn-outline-primary btn-sm active" role="button" aria-pressed="true">Edit</a></td>
|
||||
<td><a href="/media/lofis/delete/{{.ID}}" class="btn btn-outline-danger btn-sm active" role="button" aria-pressed="true">Delete</a></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
{{ define "login.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "login" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<div class="content">
|
||||
<form action={{ .login }} method="post">
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<div class="content">
|
||||
<form action="{{ .login }}" method="post">
|
||||
<div class="container" style="border: 1px solid lightgray; border-radius: 3px; padding: 15px;">
|
||||
{{ if .content }}
|
||||
<div class="notification is-danger">{{ .message }}</div>
|
||||
{{ end}}
|
||||
|
||||
<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 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>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
{{ define "home.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "mediaactors" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<h1>{{ .content }}</h1>
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<div>
|
||||
<h1>{{ .message }}</h1>
|
||||
</div>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{{ define "mediafiles.html" }}
|
||||
{{ template "main" . }}
|
||||
{{ end }}
|
||||
{{ define "mediafiles" }}
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
{{ template "head" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<h1>{{ .content }}</h1>
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<h1>{{ .message }}</h1>
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user