add tysc handlers to kontor-gin

This commit is contained in:
2026-09-30 04:12:03 +02:00
parent c848758821
commit f912dcb670
100 changed files with 2420 additions and 1064 deletions
+7 -6
View File
@@ -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-gin cmd/kontor-gin/main.go
RUN go build -trimpath -ldflags="-s -w" -o kontor cmd/kontor/main.go
# ---------- Stage 2: Final ----------
FROM alpine:latest
@@ -19,9 +19,10 @@ 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-gin /app/kontor-gin
COPY --from=builder /app/templates /app/templates
COPY --from=builder /app/assets /app/assets
ENV GIN_MODE=release
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 GIN_MODE=release
# Set the entrypoint command
ENTRYPOINT ["/app/kontor-gin"]
ENTRYPOINT ["/app/kontor"]
-93
View File
@@ -1,93 +0,0 @@
package main
import (
// "kontor-api-gin/pkg/handler"
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/schema"
"kontor-api-gin/pkg/middleware"
"kontor-api-gin/pkg/routes"
"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"
"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)
viper.SetDefault("token_hour_lifespan", 1)
viper.SetDefault("api_secret", "secret")
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" {
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)
api.Use(middleware.JwtRequired)
routes.SetupMediaRoutes(api)
routes.SetupComicRoutes(api)
// Setup Webapp routes
routes.AuthRoutes(router)
routes.ComicRoutes(router)
routes.MediaRoutes(router)
routes.PublicRoutes(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")
}
+6 -13
View File
@@ -4,11 +4,8 @@ import (
"context"
"fmt"
"kontor-api-gin/internal/config"
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/handlers"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/router"
"kontor-api-gin/internal/service"
"log"
"log/slog"
"net/http"
@@ -25,7 +22,7 @@ import (
func main() {
slog.Info("Kontor started")
if err := globals.InitConfig(); err != nil {
if err := config.InitConfig(); err != nil {
log.Fatalf("Failed to initialize config: %v", err)
}
@@ -46,11 +43,6 @@ func main() {
log.Fatal(err)
}
comicRepo := repository.NewComicRepository(db)
profileRepo := repository.NewProfileRepository(db)
comicService := service.NewComicService(comicRepo)
authService := service.NewAuthService(profileRepo, []byte(viper.GetString("api_secret")))
// Set Gin mode based on environment
// Production mode disables debug output
if viper.GetString("gin.mode") == "release" {
@@ -58,11 +50,12 @@ func main() {
}
r := router.New(
&handlers.ComicHandler{Service: comicService},
&handlers.AuthHandler{Service: authService},
[]byte(viper.GetString("api_secret")),
handlers.NewAdminHandler(db, []byte(viper.GetString("api_secret"))),
handlers.NewComicsHandler(db),
handlers.NewMediaHandler(db),
handlers.NewTyscHandler(db),
handlers.NewWebAppHandler(db, []byte(viper.GetString("api_secret"))),
)
// router.Use(sessions.Sessions("session", cookie.NewStore(globals.Secret)))
srv := &http.Server{
Addr: ":" + strconv.Itoa(viper.GetInt("port")),
+7 -3
View File
@@ -4,9 +4,9 @@ go 1.26.8
require (
github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/sessions v1.0.2
github.com/gin-contrib/sessions v1.1.2
github.com/gin-contrib/slog v1.1.0
github.com/gin-gonic/gin v1.10.1
github.com/gin-gonic/gin v1.12.0
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/spf13/cobra v1.10.2
@@ -27,9 +27,10 @@ require (
github.com/gin-contrib/sse v1.1.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.22.0 // indirect
github.com/go-playground/validator/v10 v10.30.3 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // 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
@@ -47,6 +48,8 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.60.0 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
@@ -55,6 +58,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.2 // indirect
go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/arch v0.31.0 // indirect
golang.org/x/net v0.59.0 // indirect
+15
View File
@@ -20,12 +20,16 @@ github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQ
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
github.com/gin-contrib/sessions v1.0.2 h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA=
github.com/gin-contrib/sessions v1.0.2/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs=
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/slog v1.1.0 h1:K9MVNrETT6r/C3u2Aheer/gxwVeVqrGL0hXlsmv3fm4=
github.com/gin-contrib/slog v1.1.0/go.mod h1:PvNXQVXcVOAaaiJR84LV1/xlQHIaXi9ygEXyBkmjdkY=
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.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -34,10 +38,14 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8=
github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -89,6 +97,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -123,6 +135,9 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.2 h1:zkEASHHyEClGeURfgNT9PJZVfAbs9oEX9QXggwWNJbc=
github.com/ugorji/go/codec v1.3.2/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU=
go.mongodb.org/mongo-driver/v2 v2.8.0 h1:CxWDGQYY8QQwNjAl/aq2sfWakdnWZynnqJ9F4DhHbP8=
go.mongodb.org/mongo-driver/v2 v2.8.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+13 -3
View File
@@ -1,6 +1,7 @@
package cmd
import (
"kontor-api-gin/internal/models"
"log/slog"
"github.com/spf13/cobra"
@@ -26,7 +27,7 @@ var checkCmd = &cobra.Command{
slog.Info("Verbosity level", "level", verbose)
var login LoginResponse
client := resty.New()
res, err := client.R().
_, err := client.R().
SetBody(Login{
Email: "thomas.peetz@thpeetz.de",
Password: "admin",
@@ -38,14 +39,23 @@ var checkCmd = &cobra.Command{
slog.Info("Health", "error", err.Error())
}
slog.Info("health", "token", login.Token)
res, err = client.R().
type ExportData struct {
Sport []models.SportDTO `json:"sport"`
Comic []models.ComicDTO `json:"comic"`
}
var comics []models.ComicDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&comics).
Get("http://127.0.0.1:8550/api/v1/comics/comics")
if err != nil {
slog.Info("comics", "error", err.Error())
}
slog.Info("comics", "res", res)
// slog.Info("comics", "res", comics)
defer client.Close()
slog.Info("kontor.check_kontor.check_duplicate_links")
+104
View File
@@ -1,9 +1,13 @@
package cmd
import (
"encoding/json"
"kontor-api-gin/internal/models"
"log/slog"
"os"
"github.com/spf13/cobra"
"resty.dev/v3"
)
var exportCmd = &cobra.Command{
@@ -14,6 +18,106 @@ var exportCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
slog.Info("export kontor")
slog.Info("Verbosity level", "level", verbose)
var login LoginResponse
client := resty.New()
_, err := client.R().
SetBody(Login{
Email: "thomas.peetz@thpeetz.de",
Password: "admin",
}).
SetHeader("Accept", "application/json").
SetResult(&login).
Post("http://127.0.0.1:8550/api/login")
if err != nil {
slog.Info("Health", "error", err.Error())
}
slog.Info("health", "token", login.Token)
type ExportData struct {
Sport []models.SportDTO `json:"sport"`
Player []models.PlayerDTO `json:"player"`
Team []models.TeamDTO `json:"team"`
Position []models.PositionDTO `json:"field_position"`
Rooster []models.RoosterDTO `json:"rooster"`
Vendor []models.VendorDTO `json:"vendor"`
CardSet []models.CardSetDTO `json:"card_set"`
Card []models.CardDTO `json:"card"`
Comic []models.ComicDTO `json:"comic"`
}
var sports []models.SportDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&sports).
Get("http://127.0.0.1:8550/api/v1/tysc/sports")
if err != nil {
slog.Info("sports", "error", err.Error())
}
var players []models.PlayerDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&players).
Get("http://127.0.0.1:8550/api/v1/tysc/players")
if err != nil {
slog.Info("players", "error", err.Error())
}
var teams []models.TeamDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&teams).
Get("http://127.0.0.1:8550/api/v1/tysc/teams")
if err != nil {
slog.Info("teams", "error", err.Error())
}
var positions []models.PositionDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&positions).
Get("http://127.0.0.1:8550/api/v1/tysc/positions")
if err != nil {
slog.Info("teams", "error", err.Error())
}
var comics []models.ComicDTO
_, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
SetResult(&comics).
Get("http://127.0.0.1:8550/api/v1/comics/comics")
if err != nil {
slog.Info("comics", "error", err.Error())
}
// slog.Info("comics", "res", comics)
data := ExportData{
Sport: sports,
Player: players,
Team: teams,
Position: positions,
Rooster: []models.RoosterDTO{},
Vendor: []models.VendorDTO{},
CardSet: []models.CardSetDTO{},
Card: []models.CardDTO{},
Comic: comics,
}
defer client.Close()
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
slog.Info("JSON MarshalIndent failed", "Error:", err)
}
// Write bytes to file
err = os.WriteFile("data.json", jsonData, 0644)
if err != nil {
slog.Info("Error writing file:", "Error", err)
}
slog.Info("export kontor finished")
},
}
+8
View File
@@ -9,6 +9,14 @@ import (
)
func InitConfig() error {
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)
viper.SetDefault("gin.mode", "release")
viper.SetConfigName("kontor-gin")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
-40
View File
@@ -1,40 +0,0 @@
package globals
import (
"fmt"
"log/slog"
"strings"
"github.com/spf13/viper"
)
func InitConfig() error {
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)
viper.SetDefault("gin.mode", "release")
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
}
-4
View File
@@ -5,7 +5,3 @@ var Secret = []byte("secret")
const UserKey = "user"
const Version = "0.4.0"
const LoginUrl = "/login"
const LogoutUrl = "/auth/logout"
+23
View File
@@ -0,0 +1,23 @@
package handlers
import (
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"gorm.io/gorm"
)
type AdminHandler struct {
AuthHandler *AuthHandler
PermissionHandler *PermissionHandler
Secret []byte
}
func NewAdminHandler(db *gorm.DB, secret []byte) *AdminHandler {
adminHandler := &AdminHandler{
AuthHandler: &AuthHandler{Service: service.NewAuthService(repository.NewProfileRepository(db), secret)},
PermissionHandler: &PermissionHandler{Service: service.NewPermissionService(repository.NewPermissionRepository(db))},
Secret: secret,
}
return adminHandler
}
+106 -1
View File
@@ -1,23 +1,128 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/helpers"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
type AuthHandler struct {
Service *service.AuthService
Secret []byte
}
func (handler *AuthHandler) Login(c *gin.Context) {
token, err := helpers.GenerateToken("bla")
var input models.LoginInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
proile_id, err := handler.Service.LoginCheck(input.Email, input.Password)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."})
return
}
token, err := helpers.GenerateToken(proile_id)
logger := slog.Get(c)
if err != nil {
logger.Info("Login", "GenerateToken error", err.Error())
}
c.JSON(http.StatusOK, gin.H{"token": token})
}
func (handler *AuthHandler) LoginPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LoginPage", globals.UserKey, user)
if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Please logout first",
"user": user,
})
return
}
c.HTML(http.StatusOK, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "",
"user": user,
})
}
func (handler *AuthHandler) LoginPost(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LoginPost", "user", user)
if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Please logout first",
})
return
}
username := c.PostForm("username")
password := c.PostForm("password")
if helpers.EmptyUserPass(username, password) {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Parameters can't be empty",
})
}
proile_id, err := handler.Service.LoginCheck(username, password)
if err != nil {
c.HTML(http.StatusUnauthorized, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Incorrect username or password",
})
}
session.Set(globals.UserKey, proile_id)
if err := session.Save(); err != nil {
c.HTML(http.StatusInternalServerError, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Failed to save session",
})
return
}
logger.Info("LoginPost: redirect to index")
c.Redirect(http.StatusMovedPermanently, "/")
}
func (handler *AuthHandler) LogoutPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LogoutPage", globals.UserKey, user)
if user == nil {
logger.Info("Invalid session token")
return
}
session.Delete(globals.UserKey)
if err := session.Save(); err != nil {
logger.Info("Failed to save session", "error", err)
return
}
logger.Info("LogoutPage: redirect to index page")
c.Redirect(http.StatusMovedPermanently, "/")
}
+44 -1
View File
@@ -1,12 +1,37 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type ComicsHandler struct {
ComicHandler *ComicHandler
PublisherHandler *PublisherHandler
// ArtistHandler *ArtistHandler
// IssueHandler *IssueHandler
// WorktypeHandler *WorktypeHandler
// VolumeHandler *VolumeHandler
// StoryarcHandler *StoryarcHandler
// ComicworkHandler *ComicworkHandler
// IssueworkHandler *IssueworkHandler
}
func NewComicsHandler(db *gorm.DB) *ComicsHandler {
comicsHandler := &ComicsHandler{
ComicHandler: &ComicHandler{Service: service.NewComicService(repository.NewComicRepository(db))},
PublisherHandler: &PublisherHandler{Service: service.NewPublisherService(repository.NewPublisherRepository(db))},
}
return comicsHandler
}
type ComicHandler struct {
Service *service.ComicService
}
@@ -17,5 +42,23 @@ func (handler *ComicHandler) List(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, comics)
dtos := models.ConvertComicsToDtos(comics)
c.JSON(http.StatusOK, dtos)
}
func (handler *ComicHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
comics, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.HTML(http.StatusOK, "comics", gin.H{
"title": "Kontor Comics",
"version": "0.4.0",
"message": "Comics...",
"comics": comics,
"user": user,
})
}
@@ -1,15 +1,25 @@
package controllers
package handlers
import (
"kontor-api-gin/pkg/globals"
"kontor-api-gin/internal/globals"
"net/http"
"time"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func IndexGetHandler(c *gin.Context) {
func Health(c *gin.Context) {
c.JSON(200, gin.H{
"ok": true,
"status": "healthy",
"version": globals.Version,
"time": time.Now().UTC().Format(time.RFC3339),
})
}
func Index(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
@@ -18,8 +28,7 @@ func IndexGetHandler(c *gin.Context) {
"title": "Kontor Gin",
"version": "0.4.0",
"message": "This is an index page...",
"login": globals.LoginUrl,
"logout": globals.LogoutUrl,
"user": user,
})
}
+23
View File
@@ -0,0 +1,23 @@
package handlers
import (
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"gorm.io/gorm"
)
type MediaHandler struct {
MediaActorHandler *MediaActorHandler
MediaFileHandler *MediaFileHandler
MediaLoFiHandler *MediaLoFiHandler
}
func NewMediaHandler(db *gorm.DB) *MediaHandler {
mediaHandler := &MediaHandler{
MediaActorHandler: &MediaActorHandler{Service: service.NewMediaActorService(repository.NewMediaActorRepository(db))},
MediaFileHandler: &MediaFileHandler{Service: service.NewMediaFileService(repository.NewMediaFileRepository(db))},
MediaLoFiHandler: &MediaLoFiHandler{Service: service.NewMediaLoFiService(repository.NewMediaLoFiRepository(db))},
}
return mediaHandler
}
@@ -0,0 +1,51 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type MediaActorHandler struct {
Service *service.MediaActorService
}
func NewMediaActorHandler(db *gorm.DB) *MediaActorHandler {
mediaActorHandler := &MediaActorHandler{
Service: service.NewMediaActorService(repository.NewMediaActorRepository(db)),
}
return mediaActorHandler
}
func (handler *MediaActorHandler) List(c *gin.Context) {
lofis, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaActorsToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaActorHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
actors, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.HTML(http.StatusOK, "mediaactors", gin.H{
"title": "Kontor MediaActors",
"version": "0.4.0",
"message": "MediaActors...",
"actors": actors,
"user": user,
})
}
@@ -0,0 +1,54 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type MediaFileHandler struct {
Service *service.MediaFileService
}
func NewMediaFileHandler(db *gorm.DB) *MediaFileHandler {
mediaFileHandler := &MediaFileHandler{
Service: service.NewMediaFileService(repository.NewMediaFileRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaFileHandler) List(c *gin.Context) {
logger := slog.Get(c)
logger.Info("MediaFileHandler#List")
files, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaFilesToDtos(files)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaFileHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
files, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.HTML(http.StatusOK, "mediafiles", gin.H{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"mediafiles": files,
"user": user,
})
}
@@ -0,0 +1,51 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type MediaLoFiHandler struct {
Service *service.MediaLoFiService
}
func NewMediaLoFiHandler(db *gorm.DB) *MediaLoFiHandler {
mediaLoFiHandler := &MediaLoFiHandler{
Service: service.NewMediaLoFiService(repository.NewMediaLoFiRepository(db)),
}
return mediaLoFiHandler
}
func (handler *MediaLoFiHandler) List(c *gin.Context) {
lofis, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaLoFisToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaLoFiHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
lofis, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.HTML(http.StatusOK, "lofi", gin.H{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"lofis": lofis,
"user": user,
})
}
@@ -0,0 +1,21 @@
package handlers
import (
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type PermissionHandler struct {
Service *service.PermissionService
}
func (handler *PermissionHandler) List(c *gin.Context) {
permissions, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, permissions)
}
+33
View File
@@ -0,0 +1,33 @@
package handlers
import (
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type PlayerHandler struct {
Service *service.PlayerService
}
func (handler *PlayerHandler) List(c *gin.Context) {
players, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertPlayersToDtos(players)
c.JSON(http.StatusOK, dtos)
}
func (handler *PlayerHandler) Get(c *gin.Context) {
id := c.Param("id")
player, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "player not found"})
return
}
c.JSON(http.StatusOK, player)
}
+33
View File
@@ -0,0 +1,33 @@
package handlers
import (
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type PositionHandler struct {
Service *service.PositionService
}
func (handler *PositionHandler) List(c *gin.Context) {
positions, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertPositionsToDtos(positions)
c.JSON(http.StatusOK, dtos)
}
func (handler *PositionHandler) Get(c *gin.Context) {
id := c.Param("id")
position, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "position not found"})
return
}
c.JSON(http.StatusOK, position)
}
+23
View File
@@ -0,0 +1,23 @@
package handlers
import (
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type PublisherHandler struct {
Service *service.PublisherService
}
func (handler *PublisherHandler) List(c *gin.Context) {
comics, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertPublishersToDtos(comics)
c.JSON(http.StatusOK, dtos)
}
+33
View File
@@ -0,0 +1,33 @@
package handlers
import (
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type SportHandler struct {
Service *service.SportService
}
func (handler *SportHandler) List(c *gin.Context) {
sports, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertSportsToDtos(sports)
c.JSON(http.StatusOK, dtos)
}
func (handler *SportHandler) Get(c *gin.Context) {
id := c.Param("id")
sport, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, sport)
}
+33
View File
@@ -0,0 +1,33 @@
package handlers
import (
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-gonic/gin"
)
type TeamHandler struct {
Service *service.TeamService
}
func (handler *TeamHandler) List(c *gin.Context) {
teams, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertTeamsToDtos(teams)
c.JSON(http.StatusOK, dtos)
}
func (handler *TeamHandler) Get(c *gin.Context) {
id := c.Param("id")
team, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "team not found"})
return
}
c.JSON(http.StatusOK, team)
}
+29
View File
@@ -0,0 +1,29 @@
package handlers
import (
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"gorm.io/gorm"
)
type TyscHandler struct {
SportHandler *SportHandler
PlayerHandler *PlayerHandler
TeamHandler *TeamHandler
PositionHandler *PositionHandler
// RoosterHandler *RoosterHandler
// VendorHandler *VendorHandler
// CardSetHandler *CardSetHandler
// CardHandler *CardHandler
}
func NewTyscHandler(db *gorm.DB) *TyscHandler {
handlerMap := &TyscHandler{
SportHandler: &SportHandler{Service: service.NewSportService(repository.NewSportRepository(db))},
PlayerHandler: &PlayerHandler{Service: service.NewPlayerService(repository.NewPlayerRepository(db))},
TeamHandler: &TeamHandler{Service: service.NewTeamService(repository.NewTeamRepository(db))},
PositionHandler: &PositionHandler{Service: service.NewPositionService(repository.NewPositionRepository(db))},
}
return handlerMap
}
+21
View File
@@ -0,0 +1,21 @@
package handlers
import (
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"gorm.io/gorm"
)
type WebAppHandler struct {
AuthHandler *AuthHandler
ComicHandler *ComicHandler
}
func NewWebAppHandler(db *gorm.DB, secret []byte) *WebAppHandler {
webapp := &WebAppHandler{
AuthHandler: &AuthHandler{Service: service.NewAuthService(repository.NewProfileRepository(db), secret)},
ComicHandler: &ComicHandler{Service: service.NewComicService(repository.NewComicRepository(db))},
}
return webapp
}
+3 -1
View File
@@ -1,6 +1,8 @@
package helpers
import "strings"
import (
"strings"
)
func CheckUserPass(username, password string) bool {
return true
+26
View File
@@ -0,0 +1,26 @@
package middleware
import (
"kontor-api-gin/internal/globals"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("AuthRequired", globals.UserKey, user)
if user == nil {
logger.Info("User not logged in")
c.Redirect(http.StatusMovedPermanently, "/login")
c.Abort()
return
}
c.Next()
}
}
+8 -1
View File
@@ -1,16 +1,23 @@
package middleware
import (
"slices"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func RequestID() gin.HandlerFunc {
func RequestID(skipPaths []string) gin.HandlerFunc {
return func(c *gin.Context) {
logger := slog.Get(c)
id := c.GetHeader("X-Request-ID")
if id == "" {
id = uuid.NewString()
}
if len(skipPaths) > 0 && !slices.Contains(skipPaths, c.Request.URL.Path) {
logger.Info("RequestID", "id", id)
}
c.Set("request_id", id)
c.Writer.Header().Set("X-Request-ID", id)
c.Next()
@@ -1,9 +1,9 @@
package comics
package models
import "time"
type Artist struct {
ID string `gorm:"type:string;primary_key;"`
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
@@ -17,5 +17,6 @@ func (artist *Artist) TableName() string {
}
type CreateArtistDTO struct {
Name string `json:"name" binding:"required"`
Name string `json:"name" binding:"required"`
WebLink string `json:"weblink" binding:"required"`
}
+29
View File
@@ -0,0 +1,29 @@
package models
import "time"
type Assignment struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
ProfileID *string `gorm:"column:profile_id" json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
PermissionID *string `gorm:"column:permission_id" json:"permission_id"`
Permission *Profile `gorm:"foreignKey:PermissionID" json:"permission"`
}
func (assignment *Assignment) TableName() string {
return "assignment"
}
type AssignmentDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date" binding:"omitempty"`
Version int `json:"version" binding:"required"`
ProfileID *string `json:"profile_id" binding:"required"`
PermissionID *string `json:"permission_id" binding:"required"`
}
+55
View File
@@ -0,0 +1,55 @@
package models
import "time"
type Card struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
CardNumber int `gorm:"column:card_number" json:"card_number"`
Year int `gorm:"column:year" json:"year"`
CardSetID string `gorm:"column:card_set_id" json:"card_set_id"`
CardSet CardSet `gorm:"foreignKey:CardSetID" json:"card_set"`
RoosterID string `gorm:"column_rooster_id" json:"rooster_id"`
Rooster *Rooster `gorm:"foreignKey:RoosterID" json:"rooster"`
VendorID string `gorm:"column_vendor_id" json:"vendor_id"`
Vendor Vendor `gorm:"foreignKey:VendorID" json:"vendor"`
}
func (card *Card) TableName() string {
return "card"
}
type CardDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
CardNumber int `json:"card_number" binding:"required"`
Year int `json:"year" binding:"required"`
CardSetID string `json:"card_set_id" binding:"required"`
RoosterID string `json:"rooster_id" binding:"required"`
VendorID string `json:"vendor_id" binding:"required"`
}
func ConvertCardsToDtos(cards []Card) []CardDTO {
dtos := make([]CardDTO, len(cards))
for i, card := range cards {
dtos[i] = CardDTO{
ID: card.ID,
CreatedAt: card.CreatedAt,
UpdatedAt: card.UpdatedAt,
DeletedAt: card.DeletedAt,
Version: card.Version,
CardNumber: card.CardNumber,
Year: card.Year,
CardSetID: card.CardSetID,
RoosterID: card.RoosterID,
VendorID: card.VendorID,
}
}
return dtos
}
+51
View File
@@ -0,0 +1,51 @@
package models
import "time"
type CardSet struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
ParallelSet bool `gorm:"column:parallel_set" json:"parallel_set"`
InsertSet bool `gorm:"column:insert_set" json:"insert_set"`
VendorID string `gorm:"column_vendor_id" json:"vendor_id"`
Vendor Vendor `gorm:"foreignKey:VendorID" json:"vendor"`
Cards []Card `gorm:"foreignKey:CardSetID" json:"cards"`
}
func (cardset *CardSet) TableName() string {
return "card_set"
}
type CardSetDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
ParallelSet bool `json:"parallel_set" binding:"required"`
InsertSet bool `json:"insert_set" binding:"required"`
VendorID string `json:"vendor_id" binding:"required"`
}
func ConvertCardSetsToDtos(cardsets []CardSet) []CardSetDTO {
dtos := make([]CardSetDTO, len(cardsets))
for i, cardset := range cardsets {
dtos[i] = CardSetDTO{
ID: cardset.ID,
CreatedAt: cardset.CreatedAt,
UpdatedAt: cardset.UpdatedAt,
DeletedAt: cardset.DeletedAt,
Version: cardset.Version,
Name: cardset.Name,
ParallelSet: cardset.ParallelSet,
InsertSet: cardset.InsertSet,
VendorID: cardset.VendorID,
}
}
return dtos
}
@@ -1,11 +1,11 @@
package comics
package models
import (
"time"
)
type Comic struct {
ID string `gorm:"type:string;primary_key;"`
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
@@ -15,6 +15,7 @@ type Comic struct {
Completed bool `gorm:"column:completed" json:"completed"`
WebLink string `gorm:"column:weblink" json:"weblink"`
PublisherID *string `gorm:"column:publisher_id" json:"publisher_id"`
Publisher *Publisher `gorm:"foreignKey:PublisherID"`
Issues []Issue `gorm:"foreignKey:ComicID"`
StoryArcs []StoryArc `gorm:"foreignKey:ComicID"`
TradePaperbacks []TradePaperback `gorm:"foreignKey:ComicID"`
@@ -26,6 +27,38 @@ func (comic *Comic) TableName() string {
return "comic"
}
type ComicDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
Title string `json:"title"`
PublisherID *string `json:"publisher_id"`
CurrentOrder bool `json:"current_order"`
Completed bool `json:"completed"`
WebLink string `json:"weblink"`
}
func ConvertComicsToDtos(comics []Comic) []ComicDTO {
dtos := make([]ComicDTO, len(comics))
for i, comic := range comics {
dtos[i] = ComicDTO{
ID: comic.ID,
CreatedAt: comic.CreatedAt,
UpdatedAt: comic.UpdatedAt,
DeletedAt: comic.DeletedAt,
Version: comic.Version,
Title: comic.Title,
CurrentOrder: comic.CurrentOrder,
Completed: comic.Completed,
WebLink: comic.WebLink,
PublisherID: comic.PublisherID,
}
}
return dtos
}
type CreateComicDTO struct {
Title string `json:"title" binding:"required"`
}
@@ -1,4 +1,4 @@
package comics
package models
import "time"
@@ -1,4 +1,4 @@
package comics
package models
import "time"
@@ -1,4 +1,4 @@
package comics
package models
import "time"
+45
View File
@@ -0,0 +1,45 @@
package models
import "time"
type MediaActor struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
WebLink string `gorm:"column:url" json:"url"`
MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaActorID" json:"media_actor_files"`
}
func (media_actor *MediaActor) TableName() string {
return "media_actor"
}
type MediaActorDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
Name string `json:"name"`
WebLink string `json:"url"`
}
func ConvertMediaActorsToDtos(actors []MediaActor) []MediaActorDTO {
dtos := make([]MediaActorDTO, len(actors))
for i, actor := range actors {
dtos[i] = MediaActorDTO{
ID: actor.ID,
CreatedAt: actor.CreatedAt,
UpdatedAt: actor.UpdatedAt,
DeletedAt: actor.DeletedAt,
Version: actor.Version,
Name: actor.Name,
WebLink: actor.WebLink,
}
}
return dtos
}
@@ -0,0 +1,45 @@
package models
import "time"
type MediaActorFile struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
MediaActorID *string `gorm:"column:media_actor_id" json:"media_actor_id"`
MediaActor *MediaActor `gorm:"foreignKey:MediaActorID" json:"media_actor"`
MediaFileID *string `form:"column:media_file_id" json:"media_file_id"`
MediaFile *MediaFile `gorm:"foreignKey:MediaFileID" json:"media_file"`
}
func (media_file *MediaActorFile) TableName() string {
return "media_actor_file"
}
type MediaActorFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
MediaActorID *string `json:"media_actor_id"`
MediaFileID *string `json:"media_file_id"`
}
func ConvertMediaActorFilesToDtos(actor_files []MediaActorFile) []MediaActorFileDTO {
dtos := make([]MediaActorFileDTO, len(actor_files))
for i, actor_file := range actor_files {
dtos[i] = MediaActorFileDTO{
ID: actor_file.ID,
CreatedAt: actor_file.CreatedAt,
UpdatedAt: actor_file.UpdatedAt,
DeletedAt: actor_file.DeletedAt,
Version: actor_file.Version,
MediaActorID: actor_file.MediaActorID,
MediaFileID: actor_file.MediaFileID,
}
}
return dtos
}
@@ -0,0 +1,46 @@
package models
import "time"
type MediaArticle struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Review bool `gorm:"column:review" json:"review"`
Title string `gorm:"size:300, column:title" json:"title"`
WebLink string `gorm:"column:url" json:"url"`
}
func (media_article *MediaArticle) TableName() string {
return "media_article"
}
type MediaArticleDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func ConvertMediaArticlesToDtos(media_articles []MediaArticle) []MediaArticleDTO {
dtos := make([]MediaArticleDTO, len(media_articles))
for i, media_article := range media_articles {
dtos[i] = MediaArticleDTO{
ID: media_article.ID,
CreatedAt: media_article.CreatedAt,
UpdatedAt: media_article.UpdatedAt,
DeletedAt: media_article.DeletedAt,
Version: media_article.Version,
Review: media_article.Review,
Title: media_article.Title,
WebLink: media_article.WebLink,
}
}
return dtos
}
+60
View File
@@ -0,0 +1,60 @@
package models
import "time"
type MediaFile struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
CloudLink string `gorm:"column:cloud_link" json:"cloud_link"`
FileName string `gorm:"column:file_name" json:"file_name"`
Path string `gorm:"column:path" json:"path"`
Review bool `gorm:"column:review" json:"review"`
Title string `gorm:"size:300, column:title" json:"title"`
WebLink string `gorm:"column:url" json:"url"`
ShouldDownload bool `gorm:"column:should_download" json:"should_download"`
MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaFileID" json:"media_actor_files"`
}
func (media_file *MediaFile) TableName() string {
return "media_file"
}
type MediaFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
CloudLink string `json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
ShouldDownload bool `json:"should_download"`
}
func ConvertMediaFilesToDtos(media_files []MediaFile) []MediaFileDTO {
dtos := make([]MediaFileDTO, len(media_files))
for i, media_file := range media_files {
dtos[i] = MediaFileDTO{
ID: media_file.ID,
CreatedAt: media_file.CreatedAt,
UpdatedAt: media_file.UpdatedAt,
DeletedAt: media_file.DeletedAt,
Version: media_file.Version,
CloudLink: media_file.CloudLink,
FileName: media_file.FileName,
Path: media_file.Path,
Review: media_file.Review,
Title: media_file.Title,
WebLink: media_file.WebLink,
ShouldDownload: media_file.ShouldDownload,
}
}
return dtos
}
+52
View File
@@ -0,0 +1,52 @@
package models
import "time"
type MediaLoFi struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
WebLink string `gorm:"column:url" json:"url"`
Review bool `gorm:"column:review" json:"review"`
ShouldDownload bool `gorm:"column:should_download" json:"should_download"`
Title string `gorm:"size:300, column:title" json:"title"`
FileName string `gorm:"column:file_name" json:"file_name"`
}
func (media_lofi *MediaLoFi) TableName() string {
return "media_lofi"
}
type MediaLoFiDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
WebLink string `json:"url"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `json:"title"`
FileName string `json:"file_name"`
}
func ConvertMediaLoFisToDtos(media_lofis []MediaLoFi) []MediaLoFiDTO {
dtos := make([]MediaLoFiDTO, len(media_lofis))
for i, media_lofi := range media_lofis {
dtos[i] = MediaLoFiDTO{
ID: media_lofi.ID,
CreatedAt: media_lofi.CreatedAt,
UpdatedAt: media_lofi.UpdatedAt,
DeletedAt: media_lofi.DeletedAt,
Version: media_lofi.Version,
WebLink: media_lofi.WebLink,
Review: media_lofi.Review,
ShouldDownload: media_lofi.ShouldDownload,
Title: media_lofi.Title,
FileName: media_lofi.FileName,
}
}
return dtos
}
+58
View File
@@ -0,0 +1,58 @@
package models
import "time"
type MediaVideo struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
CloudLink string `gorm:"column:cloud_link" json:"cloud_link"`
FileName string `gorm:"column:file_name" json:"file_name"`
Path string `gorm:"column:path" json:"path"`
Review bool `gorm:"column:review" json:"review"`
Title string `gorm:"size:300, column:title" json:"title"`
WebLink string `gorm:"uniqueIndex,column:url" json:"url"`
ShouldDownload bool `gorm:"column:should_download" json:"should_download"`
}
func (media_video *MediaVideo) TableName() string {
return "media_video"
}
type MediaVideoDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
CloudLink string `json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
ShouldDownload bool `json:"should_download"`
}
func ConvertMediaVideosToDtos(media_videos []MediaVideo) []MediaVideoDTO {
dtos := make([]MediaVideoDTO, len(media_videos))
for i, media_video := range media_videos {
dtos[i] = MediaVideoDTO{
ID: media_video.ID,
CreatedAt: media_video.CreatedAt,
UpdatedAt: media_video.UpdatedAt,
DeletedAt: media_video.DeletedAt,
Version: media_video.Version,
CloudLink: media_video.CloudLink,
FileName: media_video.FileName,
Path: media_video.Path,
Review: media_video.Review,
Title: media_video.Title,
WebLink: media_video.WebLink,
ShouldDownload: media_video.ShouldDownload,
}
}
return dtos
}
+26
View File
@@ -0,0 +1,26 @@
package models
import "time"
type Permission struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
Assignments []Assignment `gorm:"foreignKey:PermissionID" json:"assignments"`
}
func (permission *Permission) TableName() string {
return "permission"
}
type PermissionDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
}
+44
View File
@@ -0,0 +1,44 @@
package models
import "time"
type Player struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
FirstName string `gorm:"column:first_name" json:"first_name"`
LastName string `gorm:"column:last_name" json:"last_name"`
Roosters []Rooster `gorm:"foreignKey:PlayerID" json:"roosters"`
}
func (player *Player) TableName() string {
return "player"
}
type PlayerDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
FirstName string `json:"first_name" binding:"required"`
LastName string `json:"last_name" binding:"required"`
}
func ConvertPlayersToDtos(players []Player) []PlayerDTO {
dtos := make([]PlayerDTO, len(players))
for i, player := range players {
dtos[i] = PlayerDTO{
ID: player.ID,
CreatedAt: player.CreatedAt,
UpdatedAt: player.UpdatedAt,
DeletedAt: player.DeletedAt,
Version: player.Version,
FirstName: player.FirstName,
LastName: player.LastName,
}
}
return dtos
}
+48
View File
@@ -0,0 +1,48 @@
package models
import "time"
type Position struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
ShortName string `gorm:"column:short_name" json:"short_name"`
SportID string `gorm:"column:sport_id" json:"sport_id"`
Sport Sport `gorm:"foreignKey:SportID" json:"sport"`
Roosters []Rooster `gorm:"foreignKey:TeamID" json:"roosters"`
}
func (position *Position) TableName() string {
return "field_position"
}
type PositionDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
ShortName string `json:"short_name" binding:"required"`
SportID string `json:"sport_id" binding:"required"`
}
func ConvertPositionsToDtos(positions []Position) []PositionDTO {
dtos := make([]PositionDTO, len(positions))
for i, position := range positions {
dtos[i] = PositionDTO{
ID: position.ID,
CreatedAt: position.CreatedAt,
UpdatedAt: position.UpdatedAt,
DeletedAt: position.DeletedAt,
Version: position.Version,
Name: position.Name,
ShortName: position.ShortName,
SportID: position.SportID,
}
}
return dtos
}
+55
View File
@@ -0,0 +1,55 @@
package models
import "time"
type Profile struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
First_Name *string `gorm:"column:first_name" json:"first_name"`
Last_Name *string `gorm:"column:last_name" json:"last_name"`
User_Name string `gorm:"column:user_name" json:"user_name"`
Email string `gorm:"column:email" json:"email"`
Password string `gorm:"column:password" json:"password"`
Enabled bool `gorm:"column:enabled" json:"enabled"`
Assignments []Assignment `gorm:"foreignKey:ProfileID" json:"assignments"`
Tokens []Token `gorm:"foreignKey:ProfileID" json:"tokens"`
}
func (profile *Profile) TableName() string {
return "profile"
}
func (profile *Profile) GetFullName() string {
full_name := ""
if profile.First_Name != nil {
full_name += *profile.First_Name
}
if profile.Last_Name != nil {
full_name += " "
full_name += *profile.Last_Name
}
return full_name
}
type ProfileDTO_ struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date" binding:"omitempty"`
Version int `json:"version" binding:"required"`
First_Name *string `json:"first_name" binding:"required"`
Last_Name *string `json:"last_name" binding:"required"`
User_Name string `json:"user_name" binding:"required"`
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
Enabled bool `json:"enabled" binding:"required"`
}
type LoginInput struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
@@ -1,4 +1,4 @@
package comics
package models
import "time"
@@ -20,6 +20,34 @@ func (publisher *Publisher) TableName() string {
return "publisher"
}
type PublisherDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
Name string `json:"name"`
WebLink string `json:"weblink"`
ParentPublisherID *string `json:"parent_publisher_id"`
}
func ConvertPublishersToDtos(publishers []Publisher) []PublisherDTO {
dtos := make([]PublisherDTO, len(publishers))
for i, comic := range publishers {
dtos[i] = PublisherDTO{
ID: comic.ID,
CreatedAt: comic.CreatedAt,
UpdatedAt: comic.UpdatedAt,
DeletedAt: comic.DeletedAt,
Version: comic.Version,
Name: comic.Name,
WebLink: comic.WebLink,
ParentPublisherID: comic.ParentPublisherID,
}
}
return dtos
}
type CreatePublisherDTO struct {
Name string `json:"name" binding:"required"`
WebLink string `json:"weblink" binding:"required"`
+53
View File
@@ -0,0 +1,53 @@
package models
import "time"
type Rooster struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Year int `gorm:"column:year" json:"year"`
TeamID string `gorm:"column:team_id" json:"team_id"`
Team Team `gorm:"foreignKey:TeamID" json:"team"`
PlayerID string `gorm:"column:player_id" json:"player_id"`
Player Player `gorm:"foreignKey:PlayerID" json:"player"`
PositionID string `gorm:"column:position_id" json:"position_id"`
Position Position `gorm:"foreignKey:PositionID" json:"position"`
Cards []Card `gorm:"foreignKey:RoosterID" json:"cards"`
}
func (rooster *Rooster) TableName() string {
return "rooster"
}
type RoosterDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Year int `json:"year" binding:"required"`
TeamID string `json:"team_id" binding:"required"`
PlayerID string `json:"player_id" binding:"required"`
PositionID string `json:"position_id" binding:"required"`
}
func ConvertRoostersToDtos(roosters []Rooster) []RoosterDTO {
dtos := make([]RoosterDTO, len(roosters))
for i, rooster := range roosters {
dtos[i] = RoosterDTO{
ID: rooster.ID,
CreatedAt: rooster.CreatedAt,
UpdatedAt: rooster.UpdatedAt,
DeletedAt: rooster.DeletedAt,
Version: rooster.Version,
Year: rooster.Year,
TeamID: rooster.TeamID,
PlayerID: rooster.PlayerID,
PositionID: rooster.PositionID,
}
}
return dtos
}
+45
View File
@@ -0,0 +1,45 @@
package models
import "time"
type Sport struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"uniqueIndex" json:"name"`
}
func (sport *Sport) TableName() string {
return "sport"
}
type SportDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
}
func ConvertSportsToDtos(sports []Sport) []SportDTO {
dtos := make([]SportDTO, len(sports))
for i, sport := range sports {
dtos[i] = SportDTO{
ID: sport.ID,
CreatedAt: sport.CreatedAt,
UpdatedAt: sport.UpdatedAt,
DeletedAt: sport.DeletedAt,
Version: sport.Version,
Name: sport.Name,
}
}
return dtos
}
type CreateSportDTO struct {
Name string `json:"name" binding:"required"`
WebLink string `json:"weblink" binding:"required"`
}
@@ -1,4 +1,4 @@
package comics
package models
import "time"
+48
View File
@@ -0,0 +1,48 @@
package models
import "time"
type Team struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
ShortName string `gorm:"column:short_name" json:"short_name"`
SportID string `gorm:"column:sport_id" json:"sport_id"`
Sport Sport `gorm:"foreignKey:SportID" json:"sport"`
Roosters []Rooster `gorm:"foreignKey:TeamID" json:"roosters"`
}
func (team *Team) TableName() string {
return "team"
}
type TeamDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
ShortName string `json:"short_name" binding:"required"`
SportID string `json:"sport_id" binding:"required"`
}
func ConvertTeamsToDtos(teams []Team) []TeamDTO {
dtos := make([]TeamDTO, len(teams))
for i, team := range teams {
dtos[i] = TeamDTO{
ID: team.ID,
CreatedAt: team.CreatedAt,
UpdatedAt: team.UpdatedAt,
DeletedAt: team.DeletedAt,
Version: team.Version,
Name: team.Name,
ShortName: team.ShortName,
SportID: team.SportID,
}
}
return dtos
}
+31
View File
@@ -0,0 +1,31 @@
package models
import "time"
type Token struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Token string `gorm:"uniqueIndex,column:token" json:"token"`
Name string `gorm:"column:name" json:"name"`
LastUsedAt time.Time `gorm:"column:last_used_date" json:"last_used_date"`
Enabled bool `gorm:"column.enabled" json:"enabled"`
ProfileID *string `gorm:"column:profile_id" json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
}
func (token *Token) TableName() string {
return "token"
}
type TokenDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Token string `json:"token" binding:"required"`
ProfileID *string `json:"profile_id" binding:"required"`
}
@@ -1,4 +1,4 @@
package comics
package models
import "time"
+42
View File
@@ -0,0 +1,42 @@
package models
import "time"
type Vendor struct {
ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `gorm:"column:name" json:"name"`
CardSets []CardSet `gorm:"foreignKey:VendorID" json:"card_sets"`
Cards []Card `gorm:"foreignKey:VendorID" json:"cards"`
}
func (vendor *Vendor) TableName() string {
return "vendor"
}
type VendorDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt time.Time `json:"created_date" binding:"required"`
UpdatedAt time.Time `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"omitempty"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
}
func ConvertVendorsToDtos(vendors []Vendor) []VendorDTO {
dtos := make([]VendorDTO, len(vendors))
for i, vendor := range vendors {
dtos[i] = VendorDTO{
ID: vendor.ID,
CreatedAt: vendor.CreatedAt,
UpdatedAt: vendor.UpdatedAt,
DeletedAt: vendor.DeletedAt,
Version: vendor.Version,
Name: vendor.Name,
}
}
return dtos
}
@@ -1,4 +1,4 @@
package comics
package models
import "time"
@@ -1,4 +1,4 @@
package comics
package models
import "time"
+4 -4
View File
@@ -2,7 +2,7 @@ package repository
import (
"context"
"kontor-api-gin/internal/models/comics"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
@@ -17,11 +17,11 @@ func NewComicRepository(db *gorm.DB) *ComicRepository {
return repo
}
func (repository *ComicRepository) List(context context.Context) ([]comics.Comic, error) {
var comics []comics.Comic
func (repository *ComicRepository) FindAll(context context.Context) ([]models.Comic, error) {
var comics []models.Comic
result := repository.db.Find(&comics)
slog.Info("ComicRepository#List", "count", result.RowsAffected)
slog.Info("ComicRepository#FindAll", "count", result.RowsAffected)
return comics, nil
}
@@ -0,0 +1,27 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type MediaActorRepository struct {
db *gorm.DB
}
func NewMediaActorRepository(db *gorm.DB) *MediaActorRepository {
repo := &MediaActorRepository{db: db}
return repo
}
func (repository *MediaActorRepository) FindAll(context context.Context) ([]models.MediaActor, error) {
var actors []models.MediaActor
result := repository.db.Find(&actors)
slog.Info("MediaActorRepository#FindAll", "count", result.RowsAffected)
return actors, nil
}
@@ -0,0 +1,27 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type MediaFileRepository struct {
db *gorm.DB
}
func NewMediaFileRepository(db *gorm.DB) *MediaFileRepository {
repo := &MediaFileRepository{db: db}
return repo
}
func (repository *MediaFileRepository) FindAll(context context.Context) ([]models.MediaFile, error) {
var files []models.MediaFile
result := repository.db.Find(&files)
slog.Info("MediaFileRepository#FindAll", "count", result.RowsAffected)
return files, nil
}
@@ -0,0 +1,27 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type MediaLoFiRepository struct {
db *gorm.DB
}
func NewMediaLoFiRepository(db *gorm.DB) *MediaLoFiRepository {
repo := &MediaLoFiRepository{db: db}
return repo
}
func (repository *MediaLoFiRepository) FindAll(context context.Context) ([]models.MediaLoFi, error) {
var lofis []models.MediaLoFi
result := repository.db.Find(&lofis)
slog.Info("MediaLoFiRepository#FindAll", "count", result.RowsAffected)
return lofis, nil
}
@@ -0,0 +1,28 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type PermissionRepository struct {
db *gorm.DB
}
func (repository *PermissionRepository) FindAll(context context.Context) ([]models.Permission, error) {
var permissions []models.Permission
result := repository.db.Find(&permissions)
slog.Info("ComicRepository#List", "count", result.RowsAffected)
return permissions, nil
}
func NewPermissionRepository(db *gorm.DB) *PermissionRepository {
repository := &PermissionRepository{db: db}
return repository
}
+37
View File
@@ -0,0 +1,37 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type PlayerRepository struct {
db *gorm.DB
}
func NewPlayerRepository(db *gorm.DB) *PlayerRepository {
repo := &PlayerRepository{db: db}
return repo
}
func (repository *PlayerRepository) FindAll(context context.Context) ([]models.Player, error) {
var players []models.Player
result := repository.db.Find(&players)
slog.Info("PlayerRepository#FindAll", "count", result.RowsAffected)
return players, nil
}
func (repository *PlayerRepository) GetById(context context.Context, id string) (models.Player, error) {
var player = models.Player{ID: id}
slog.Info("PlayerRepository#GetById", "id", id)
result := repository.db.First(&player)
if result.Error != nil {
slog.Info("PlayerRepository#GetById", "error", result.Error.Error())
}
return player, result.Error
}
@@ -0,0 +1,37 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type PositionRepository struct {
db *gorm.DB
}
func NewPositionRepository(db *gorm.DB) *PositionRepository {
repo := &PositionRepository{db: db}
return repo
}
func (repository *PositionRepository) FindAll(context context.Context) ([]models.Position, error) {
var positions []models.Position
result := repository.db.Find(&positions)
slog.Info("PositionRepository#FindAll", "count", result.RowsAffected)
return positions, nil
}
func (repository *PositionRepository) GetById(context context.Context, id string) (models.Position, error) {
var position = models.Position{ID: id}
slog.Info("PositionRepository#GetById", "id", id)
result := repository.db.First(&position)
if result.Error != nil {
slog.Info("PositionRepository#GetById", "error", result.Error.Error())
}
return position, result.Error
}
+24
View File
@@ -1,6 +1,10 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
@@ -12,3 +16,23 @@ func NewProfileRepository(db *gorm.DB) *ProfileRepository {
repository := &ProfileRepository{db: db}
return repository
}
func (repository *ProfileRepository) FindAll(context context.Context) ([]models.Profile, error) {
var profiles []models.Profile
result := repository.db.Find(&profiles)
slog.Info("ProfileRepository#FindAll", "count", result.RowsAffected)
return profiles, nil
}
func (repository *ProfileRepository) FindProfileByEmail(email string) (*models.Profile, error) {
var profile models.Profile
err := repository.db.Model(models.Profile{}).Where("email = ?", email).Take(&profile).Error
if err != nil {
return nil, err
}
return &profile, nil
}
@@ -0,0 +1,27 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type PublisherRepository struct {
db *gorm.DB
}
func NewPublisherRepository(db *gorm.DB) *PublisherRepository {
repo := &PublisherRepository{db: db}
return repo
}
func (repository *PublisherRepository) FindAll(context context.Context) ([]models.Publisher, error) {
var publishers []models.Publisher
result := repository.db.Find(&publishers)
slog.Info("PublisherRepository#FindAll", "count", result.RowsAffected)
return publishers, nil
}
+37
View File
@@ -0,0 +1,37 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type SportRepository struct {
db *gorm.DB
}
func NewSportRepository(db *gorm.DB) *SportRepository {
repo := &SportRepository{db: db}
return repo
}
func (repository *SportRepository) FindAll(context context.Context) ([]models.Sport, error) {
var sports []models.Sport
result := repository.db.Find(&sports)
slog.Info("SportRepository#FindAll", "count", result.RowsAffected)
return sports, nil
}
func (repository *SportRepository) GetById(context context.Context, id string) (models.Sport, error) {
var sport = models.Sport{ID: id}
slog.Info("SportRepository#GetById", "id", id)
result := repository.db.First(&sport)
if result.Error != nil {
slog.Info("SportRepository#GetById", "error", result.Error.Error())
}
return sport, result.Error
}
+37
View File
@@ -0,0 +1,37 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type TeamRepository struct {
db *gorm.DB
}
func NewTeamRepository(db *gorm.DB) *TeamRepository {
repo := &TeamRepository{db: db}
return repo
}
func (repository *TeamRepository) FindAll(context context.Context) ([]models.Team, error) {
var teams []models.Team
result := repository.db.Find(&teams)
slog.Info("TeamRepository#FindAll", "count", result.RowsAffected)
return teams, nil
}
func (repository *TeamRepository) GetById(context context.Context, id string) (models.Team, error) {
var team = models.Team{ID: id}
slog.Info("TeamRepository#GetById", "id", id)
result := repository.db.First(&team)
if result.Error != nil {
slog.Info("TeamRepository#GetById", "error", result.Error.Error())
}
return team, result.Error
}
+56 -8
View File
@@ -3,6 +3,7 @@ package router
import (
"html/template"
"kontor-api-gin/assets"
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/handlers"
"kontor-api-gin/internal/middleware"
"kontor-api-gin/templates"
@@ -11,11 +12,13 @@ import (
"log/slog"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
gin_slog "github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func New(comics *handlers.ComicHandler, auth *handlers.AuthHandler, secret []byte) *gin.Engine {
func New(admin *handlers.AdminHandler, comics *handlers.ComicsHandler, media *handlers.MediaHandler, tysc *handlers.TyscHandler, webApp *handlers.WebAppHandler) *gin.Engine {
router := gin.New()
router.Use(gin.Recovery())
router.Use(gin_slog.SetLogger(
@@ -25,25 +28,70 @@ func New(comics *handlers.ComicHandler, auth *handlers.AuthHandler, secret []byt
gin_slog.WithServerErrorLevel(slog.LevelInfo),
))
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://app.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
AllowHeaders: []string{"Authorization", "Content-Type"},
AllowOrigins: []string{"https://app.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
AllowHeaders: []string{"Authorization", "Content-Type"},
AllowCredentials: true,
}))
// router.LoadHTMLGlob("templates/**/*.html")
// router.Static("/public", "./assets")
templ := template.Must(template.New("").ParseFS(templates.TemplateFiles, "layouts/*.html", "pages/*.html"))
router.SetHTMLTemplate(templ)
router.StaticFS("/public", http.FS(assets.StaticFiles))
router.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"ok": true}) })
router.Use(sessions.Sessions("session", cookie.NewStore(globals.Secret)))
router.Use(middleware.RequestID([]string{"/health"}))
router.GET("/health", handlers.Health)
router.GET("/", handlers.Index)
router.GET("/login", admin.AuthHandler.LoginPage)
router.POST("/login", admin.AuthHandler.LoginPost)
router.GET("/logout", admin.AuthHandler.LogoutPage)
comic := router.Group("/comics")
comic.GET("/comics", webApp.ComicHandler.ListPage)
m := router.Group("/web")
m.Use(middleware.AuthRequired())
m.GET("/actors", media.MediaActorHandler.ListPage)
m.GET("/articles", media.MediaFileHandler.ListPage)
m.GET("/media-files", media.MediaFileHandler.ListPage)
m.GET("/files", media.MediaFileHandler.ListPage)
m.GET("/media-lofis", media.MediaLoFiHandler.ListPage)
m.GET("/lofis", media.MediaLoFiHandler.ListPage)
api := router.Group("/api")
api.POST("/login", auth.Login)
api.POST("/login", admin.AuthHandler.Login)
v1 := api.Group("/v1")
{
secured := v1.Group("")
secured.Use(middleware.JWT(secret))
secured.GET("comics/comics", comics.List)
secured.Use(middleware.JWT(admin.Secret))
secured.GET("admin/permissions", admin.PermissionHandler.List)
secured.GET("tysc/sports", tysc.SportHandler.List)
secured.GET("tysc/sports/:id", tysc.SportHandler.Get)
secured.GET("tysc/players", tysc.PlayerHandler.List)
secured.GET("tysc/teams", tysc.TeamHandler.List)
secured.GET("tysc/positions", tysc.PositionHandler.List)
// secured.GET("tysc/roosters", tysc.RoosterHandler.List)
// secured.GET("tysc/vendors", tysc.VendorHandler.List)
// secured.GET("tysc/cardsets", tysc.CardSetHandler.List)
// secured.GET("tysc/cards", tysc.CardHandler.List)
secured.GET("/comics/comics", comics.ComicHandler.List)
secured.GET("/comics/publishers", comics.PublisherHandler.List)
// comic.GET("/artists", comics.ArtistHandler.List)
// comic.GET("/issues", comics.IssueHandler.List)
// comic.GET("/worktypes", comics.WorktypeHandler.List)
// comic.GET("/volumes", comics.VolumeHandler.List)
// comic.GET("/storyarcs", comics.StoryarcHandler.List)
// comic.GET("/comicworks", comics.ComicworkHandler.List)
// comic.GET("/issueworks", comics.IssueworkHandler.List)
secured.GET("/media/files", media.MediaFileHandler.List)
secured.GET("/media/lofis", media.MediaLoFiHandler.List)
secured.GET("/media/actors", media.MediaActorHandler.List)
}
return router
}
+36 -1
View File
@@ -1,6 +1,11 @@
package service
import "kontor-api-gin/internal/repository"
import (
"kontor-api-gin/internal/helpers"
"kontor-api-gin/internal/repository"
"golang.org/x/crypto/bcrypt"
)
type AuthService struct {
repository *repository.ProfileRepository
@@ -10,3 +15,33 @@ func NewAuthService(repository *repository.ProfileRepository, secret []byte) *Au
service := &AuthService{repository: repository}
return service
}
func VerifyPassword(password, hashedPassword string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
func (service *AuthService) LoginCheck(email string, password string) (string, error) {
var err error
profile, err := service.repository.FindProfileByEmail(email)
if err != nil {
return "", err
}
err = VerifyPassword(password, profile.Password)
if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
return "", err
}
token, err := helpers.GenerateToken(profile.ID)
if err != nil {
return "", err
}
return token, nil
}
+3 -3
View File
@@ -2,7 +2,7 @@ package service
import (
"context"
"kontor-api-gin/internal/models/comics"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
@@ -16,7 +16,7 @@ func NewComicService(repo *repository.ComicRepository) *ComicService {
return service
}
func (service *ComicService) List(context context.Context) ([]comics.Comic, error) {
func (service *ComicService) List(context context.Context) ([]models.Comic, error) {
slog.Info("ComicService#List")
return service.repository.List(context)
return service.repository.FindAll(context)
}
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaActorService struct {
repository *repository.MediaActorRepository
}
func NewMediaActorService(repo *repository.MediaActorRepository) *MediaActorService {
service := &MediaActorService{repository: repo}
return service
}
func (service *MediaActorService) List(context context.Context) ([]models.MediaActor, error) {
slog.Info("MediaActorService#List")
return service.repository.FindAll(context)
}
+22
View File
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaFileService struct {
repository *repository.MediaFileRepository
}
func NewMediaFileService(repo *repository.MediaFileRepository) *MediaFileService {
service := &MediaFileService{repository: repo}
return service
}
func (service *MediaFileService) List(context context.Context) ([]models.MediaFile, error) {
slog.Info("MediaFileService#List")
return service.repository.FindAll(context)
}
+22
View File
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaLoFiService struct {
repository *repository.MediaLoFiRepository
}
func NewMediaLoFiService(repo *repository.MediaLoFiRepository) *MediaLoFiService {
service := &MediaLoFiService{repository: repo}
return service
}
func (service *MediaLoFiService) List(context context.Context) ([]models.MediaLoFi, error) {
slog.Info("MediaLoFiService#List")
return service.repository.FindAll(context)
}
+23
View File
@@ -0,0 +1,23 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type PermissionService struct {
repository *repository.PermissionRepository
}
func NewPermissionService(repository *repository.PermissionRepository) *PermissionService {
service := &PermissionService{repository: repository}
return service
}
func (service PermissionService) List(context context.Context) ([]models.Permission, error) {
slog.Info("ComicService#List")
return service.repository.FindAll(context)
}
+27
View File
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type PlayerService struct {
repository *repository.PlayerRepository
}
func NewPlayerService(repo *repository.PlayerRepository) *PlayerService {
service := &PlayerService{repository: repo}
return service
}
func (service *PlayerService) List(context context.Context) ([]models.Player, error) {
slog.Info("PlayerService#List")
return service.repository.FindAll(context)
}
func (service *PlayerService) Get(context context.Context, id string) (models.Player, error) {
slog.Info("PlayerService#Get")
return service.repository.GetById(context, id)
}
+27
View File
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type PositionService struct {
repository *repository.PositionRepository
}
func NewPositionService(repo *repository.PositionRepository) *PositionService {
service := &PositionService{repository: repo}
return service
}
func (service *PositionService) List(context context.Context) ([]models.Position, error) {
slog.Info("PositionService#List")
return service.repository.FindAll(context)
}
func (service *PositionService) Get(context context.Context, id string) (models.Position, error) {
slog.Info("PositionService#Get")
return service.repository.GetById(context, id)
}
+22
View File
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type PublisherService struct {
repository *repository.PublisherRepository
}
func NewPublisherService(repo *repository.PublisherRepository) *PublisherService {
service := &PublisherService{repository: repo}
return service
}
func (service *PublisherService) List(context context.Context) ([]models.Publisher, error) {
slog.Info("PublisherService#List")
return service.repository.FindAll(context)
}
+27
View File
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type SportService struct {
repository *repository.SportRepository
}
func NewSportService(repo *repository.SportRepository) *SportService {
service := &SportService{repository: repo}
return service
}
func (service *SportService) List(context context.Context) ([]models.Sport, error) {
slog.Info("SportService#List")
return service.repository.FindAll(context)
}
func (service *SportService) Get(context context.Context, id string) (models.Sport, error) {
slog.Info("SportService#Get")
return service.repository.GetById(context, id)
}
+27
View File
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type TeamService struct {
repository *repository.TeamRepository
}
func NewTeamService(repo *repository.TeamRepository) *TeamService {
service := &TeamService{repository: repo}
return service
}
func (service *TeamService) List(context context.Context) ([]models.Team, error) {
slog.Info("TeamService#List")
return service.repository.FindAll(context)
}
func (service *TeamService) Get(context context.Context, id string) (models.Team, error) {
slog.Info("TeamService#Get")
return service.repository.GetById(context, id)
}
-134
View File
@@ -1,134 +0,0 @@
package controllers
import (
"kontor-api-gin/pkg/globals"
"kontor-api-gin/pkg/helpers"
"kontor-api-gin/pkg/schema"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
type LoginInput struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
func LoginHandler(c *gin.Context) {
var input LoginInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
profile := schema.Profile{}
profile.Email = input.Email
profile.Password = input.Password
token, err := schema.LoginCheck(profile.Email, profile.Password)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."})
return
}
c.JSON(http.StatusOK, gin.H{"token": token})
}
func LoginGetHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LoginGetHandler", globals.UserKey, user)
if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "Please logout first",
"user": user,
})
return
}
c.HTML(http.StatusOK, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "",
"user": user,
})
}
func LoginPostHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LoginPostHandler", "user", user)
if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "Please logout first",
})
return
}
username := c.PostForm("username")
password := c.PostForm("password")
if helpers.EmptyUserPass(username, password) {
c.HTML(http.StatusBadRequest, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "Parameters can't be empty",
})
}
if !helpers.CheckUserPass(username, password) {
c.HTML(http.StatusUnauthorized, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "Incorrect username or password",
})
}
session.Set(globals.UserKey, username)
if err := session.Save(); err != nil {
c.HTML(http.StatusInternalServerError, "login", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"login": globals.LoginUrl,
"message": "Failed to save session",
})
return
}
logger.Info("LoginGetHandler: redirect to index")
c.Redirect(http.StatusMovedPermanently, "/")
}
func LogoutGetHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("LogoutGetHandler", globals.UserKey, user)
if user == nil {
logger.Info("Invalid session token")
return
}
session.Delete(globals.UserKey)
if err := session.Save(); err != nil {
logger.Info("Failed to save session", "error", err)
return
}
logger.Info("LogoutGetHandler: redirect to index page")
c.Redirect(http.StatusMovedPermanently, "/")
}
-30
View File
@@ -1,30 +0,0 @@
package controllers
import (
"kontor-api-gin/pkg/globals"
"kontor-api-gin/pkg/schema"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func ListComicsGetHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
var comics []schema.Comic
result := schema.DB.Find(&comics)
logger.Info("ListComicsGetHandler", "count", result.RowsAffected)
c.HTML(http.StatusOK, "comics", gin.H{
"title": "Kontor Comics",
"version": "0.4.0",
"message": "Comics...",
"comics": comics,
"user": user,
})
}
-92
View File
@@ -1,92 +0,0 @@
package controllers
import (
"kontor-api-gin/pkg/schema"
"net/http"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func ListComics(c *gin.Context) {
var comics []schema.Comic
logger := slog.Get(c)
// query := schema.DB.Model(&schema.MediaFile{})
// result := query.Find(&files)
result := schema.DB.Find(&comics)
logger.Info("found Comics", "count", result.RowsAffected)
c.JSON(http.StatusOK, comics)
}
func ListComicPublishers(c *gin.Context) {
var publishers []schema.Publisher
logger := slog.Get(c)
result := schema.DB.Find(&publishers)
logger.Info("found Comic Publishers", "count", result.RowsAffected)
c.JSON(http.StatusOK, publishers)
}
func ListComicArtists(c *gin.Context) {
var artists []schema.Artist
logger := slog.Get(c)
result := schema.DB.Find(&artists)
logger.Info("found Comic Artists", "count", result.RowsAffected)
c.JSON(http.StatusOK, artists)
}
func ListComicIssues(c *gin.Context) {
var issues []schema.Issue
logger := slog.Get(c)
result := schema.DB.Find(&issues)
logger.Info("found Comic Issues", "count", result.RowsAffected)
c.JSON(http.StatusOK, issues)
}
func ListComicWorkTypes(c *gin.Context) {
var worktypes []schema.WorkType
logger := slog.Get(c)
result := schema.DB.Find(&worktypes)
logger.Info("found Comic WorkTypes", "count", result.RowsAffected)
c.JSON(http.StatusOK, worktypes)
}
func ListComicVolumes(c *gin.Context) {
var items []schema.Volume
logger := slog.Get(c)
result := schema.DB.Find(&items)
logger.Info("found Comic Volumes", "count", result.RowsAffected)
c.JSON(http.StatusOK, items)
}
func ListComicStoryArcs(c *gin.Context) {
var items []schema.StoryArc
logger := slog.Get(c)
result := schema.DB.Find(&items)
logger.Info("ListComicStoryArcs", "count", result.RowsAffected)
c.JSON(http.StatusOK, items)
}
func ListComicWorks(c *gin.Context) {
var items []schema.ComicWork
logger := slog.Get(c)
result := schema.DB.Find(&items)
logger.Info("found Comic ComicWorks", "count", result.RowsAffected)
c.JSON(http.StatusOK, items)
}
func ListComicIssueWorks(c *gin.Context) {
var items []schema.IssueWork
logger := slog.Get(c)
result := schema.DB.Find(&items)
logger.Info("found Comic IssueWorks", "count", result.RowsAffected)
c.JSON(http.StatusOK, items)
}
-17
View File
@@ -1,17 +0,0 @@
package controllers
import (
"kontor-api-gin/pkg/globals"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func HealthGetHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"version": globals.Version,
"time": time.Now().UTC().Format(time.RFC3339),
})
}
-93
View File
@@ -1,93 +0,0 @@
package controllers
import (
"kontor-api-gin/pkg/globals"
"kontor-api-gin/pkg/schema"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
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)
logger.Info("ListMediaFiles", "count", result.RowsAffected)
c.JSON(http.StatusOK, files)
}
func ListMediaLoFis(c *gin.Context) {
var lofis []schema.MediaLoFi
logger := slog.Get(c)
result := schema.DB.Find(&lofis)
logger.Info("ListMediaLoFis", "count", result.RowsAffected)
c.JSON(http.StatusOK, 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)
logger.Info("ListMediaActorsGetHandler", "count", result.RowsAffected)
c.HTML(http.StatusOK, "mediaactors", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Media Actors...",
"actors": actors,
"login": globals.LoginUrl,
"logout": globals.LogoutUrl,
"user": user,
})
}
func ListMediaFilesGetHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
var files []schema.MediaFile
result := schema.DB.Find(&files)
logger.Info("ListMediaFilesGetHandler", "count", result.RowsAffected)
c.HTML(http.StatusOK, "mediafiles", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Media Files...",
"files": files,
"login": globals.LoginUrl,
"logout": globals.LogoutUrl,
"user": user,
})
}
func ListMediaLoFisGetHandler(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
var lofis []schema.MediaLoFi
result := schema.DB.Find(&lofis)
logger.Info("ListMediaLoFisGetHandler", "count", result.RowsAffected)
logger.Info("ListMediaLoFisGetHandler", "medialofi", lofis[0])
c.HTML(http.StatusOK, "lofi", gin.H{
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Media LoFis...",
"lofis": lofis,
"login": globals.LoginUrl,
"logout": globals.LogoutUrl,
"user": user,
})
}
-23
View File
@@ -1,23 +0,0 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
)
// corsMiddleware adds CORS headers for cross-origin requests
func CorsMiddleware(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
c.Header("Access-Control-Allow-Credentials", "true")
// Handle preflight requests
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
-37
View File
@@ -1,37 +0,0 @@
package middleware
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/helpers"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
func AuthRequired(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
logger.Info("AuthRequired", globals.UserKey, user)
if user == nil {
logger.Info("User not logged in")
c.Redirect(http.StatusMovedPermanently, globals.LoginUrl)
c.Abort()
return
}
c.Next()
}
func JwtRequired(c *gin.Context) {
logger := slog.Get(c)
err := helpers.TokenValid(c)
logger.Info("JwtRequired", "TokenValid", err)
if err != nil {
c.String(http.StatusUnauthorized, "Unauthorized")
c.Abort()
return
}
c.Next()
}
-14
View File
@@ -1,14 +0,0 @@
package routes
import (
"kontor-api-gin/pkg/controllers"
"github.com/gin-gonic/gin"
)
func SetupApiRoutes(router *gin.Engine) *gin.RouterGroup {
api := router.Group("/api")
api.POST("/login", controllers.LoginHandler)
v1 := api.Group("/v1")
return v1
}
-30
View File
@@ -1,30 +0,0 @@
package routes
import (
"kontor-api-gin/pkg/controllers"
"github.com/gin-gonic/gin"
)
func SetupComicRoutes(router *gin.RouterGroup) {
comic := router.Group("/comics")
comics := comic.Group("/comics")
comics.GET("", controllers.ListComics)
publishers := comic.Group("/publishers")
publishers.GET("", controllers.ListComicPublishers)
artists := comic.Group("/artists")
artists.GET("/", controllers.ListComicArtists)
issues := comic.Group("/issues")
issues.GET("", controllers.ListComicIssues)
worktypes := comic.Group("/worktypes")
worktypes.GET("", controllers.ListComicWorkTypes)
volumes := comic.Group("/volumes")
volumes.GET("", controllers.ListComicVolumes)
storyarcs := comic.Group("/storyarcs")
storyarcs.GET("", controllers.ListComicStoryArcs)
comicworks := comic.Group("/comicworks")
comicworks.GET("", controllers.ListComicWorks)
issueworks := comic.Group("/issueworks")
issueworks.GET("", controllers.ListComicIssueWorks)
}
-17
View File
@@ -1,17 +0,0 @@
package routes
import (
"kontor-api-gin/pkg/controllers"
"github.com/gin-gonic/gin"
)
func SetupMediaRoutes(router *gin.RouterGroup) {
media := router.Group("/media")
files := media.Group("/files")
files.GET("", controllers.ListMediaFiles)
lofi := media.Group("/lofi")
lofi.GET("/", controllers.ListMediaLoFis)
}
-34
View File
@@ -1,34 +0,0 @@
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.Engine) {
g.GET("/health", controllers.HealthGetHandler)
g.GET(globals.LoginUrl, controllers.LoginGetHandler)
g.POST(globals.LoginUrl, controllers.LoginPostHandler)
g.GET("/", controllers.IndexGetHandler)
}
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 AuthRoutes(g *gin.Engine) {
auth := g.Group("/auth")
auth.Use(middleware.AuthRequired)
auth.GET("/logout", controllers.LogoutGetHandler)
}
-121
View File
@@ -1,121 +0,0 @@
package schema
import (
"kontor-api-gin/internal/helpers"
"time"
"golang.org/x/crypto/bcrypt"
)
func VerifyPassword(password, hashedPassword string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
func LoginCheck(email string, password string) (string, error) {
var err error
profile := Profile{}
err = DB.Model(Profile{}).Where("email = ?", email).Take(&profile).Error
if err != nil {
return "", err
}
err = VerifyPassword(password, profile.Password)
if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
return "", err
}
token, err := helpers.GenerateToken(profile.ID)
if err != nil {
return "", err
}
return token, nil
}
type Profile 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"`
First_Name *string `json:"first_name"`
Last_Name *string `json:"last_name"`
User_Name string `json:"user_name"`
Email string `json:"email"`
Password string `json:"password"`
Enabled bool `json:"enabled"`
Assignments []Assignment `gorm:"foreignKey:ProfileID" json:"assignments"`
Tokens []Token `gorm:"foreignKey:ProfileID" json:"tokens"`
}
func (profile *Profile) TableName() string {
return "profile"
}
func (profile *Profile) GetFullName() string {
full_name := ""
if profile.First_Name != nil {
full_name += *profile.First_Name
}
if profile.Last_Name != nil {
full_name += " "
full_name += *profile.Last_Name
}
return full_name
}
type Token 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"`
Token string `gorm:"uniqueIndex" json:"token"`
Name string `json:"name"`
Last_Used_date time.Time `json:"last_used_date"`
Enabled bool `json:"enabled"`
ProfileID *string `json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
}
func (token *Token) TableName() string {
return "token"
}
type Permission 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"`
Name string `json:"name"`
Assignments []Assignment `gorm:"foreignKey:PermissionID" json:"assignments"`
}
func (permission *Permission) TableName() string {
return "permission"
}
type Assignment 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"`
ProfileID *string `json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
PermissionID *string `json:"permission_id"`
Permission *Profile `gorm:"foreignKey:PermissionID" json:"permission"`
}
func (assignment *Assignment) TableName() string {
return "assignment"
}
-22
View File
@@ -1,22 +0,0 @@
package schema
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Base struct {
ID string `gorm:"type:string;primary_key;"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
}
// BeforeCreate will set a UUID rather than numeric ID.
func (b *Base) BeforeCreate(tx *gorm.DB) (err error) {
b.ID = uuid.New().String()
return
}
-66
View File
@@ -1,66 +0,0 @@
package schema
import (
"fmt"
"log"
"log/slog"
"time"
"github.com/spf13/viper"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
func Connect() {
// Build the connection string from environment variables
// This keeps sensitive credentials out of the codebase
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
viper.GetString("db.host"),
viper.GetString("db.user"),
viper.GetString("db.password"),
viper.GetString("db.name"),
viper.GetInt("db.port"),
)
// Configure GORM with custom settings
// The logger helps with debugging SQL queries during development
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
// Get the underlying SQL database connection for pool configuration
sqlDB, err := db.DB()
if err != nil {
log.Fatal("Failed to get database instance:", err)
}
// Configure connection pool settings
// MaxIdleConns: number of connections kept open when idle
sqlDB.SetMaxIdleConns(10)
// MaxOpenConns: maximum total connections to the database
sqlDB.SetMaxOpenConns(100)
// ConnMaxLifetime: how long a connection can be reused
sqlDB.SetConnMaxLifetime(time.Hour)
DB = db
slog.Info("Database connected successfully")
}
func RunMigrations() {
// AutoMigrate creates tables, missing columns, and missing indexes
// It will NOT delete unused columns to protect your data
err := DB.AutoMigrate()
if err != nil {
log.Fatal("Migration failed:", err)
}
slog.Info("Database migration completed")
}
-107
View File
@@ -1,107 +0,0 @@
package schema
import "time"
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 {
return "media_lofi"
}
type MediaFile 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"`
CloudLink string `gorm:"column:cloud_link" 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:"column:url" 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"
}
type MediaActor 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"`
Name string `json:"name"`
Url string `json:"url"`
MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaActorID" json:"media_actor_files"`
}
func (media_actor *MediaActor) TableName() string {
return "media_actor"
}
type MediaActorFile 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"`
MediaActorID *string `json:"media_actor_id"`
MediaActor *MediaActor `gorm:"foreignKey:MediaActorID" json:"media_actor"`
MediaFileID *string `json:"media_file_id"`
MediaFile *MediaFile `gorm:"foreignKey:MediaFileID" json:"media_file"`
}
func (media_file *MediaActorFile) TableName() string {
return "media_actor_file"
}
type MediaArticle 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"`
Review bool `json:"review"`
Title string `gorm:"size:300" json:"title"`
Url string `gorm:"uniqueIndex" json:"url"`
}
func (media_article *MediaArticle) TableName() string {
return "media_article"
}
type MediaVideo 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"`
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"`
Url string `gorm:"uniqueIndex" json:"url"`
ShouldDownload bool `json:"should_download"`
}
func (media_video *MediaVideo) TableName() string {
return "media_video"
}
+16 -16
View File
@@ -1,32 +1,34 @@
{{ define "navbar" }}
<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>
<a class="nav-item nav-link" href="/">Kontor</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>
<a class="nav-link dropdown-toggle" href="#" id="navbarComicsMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Comics</a>
<div class="dropdown-menu" aria-labelledby="navbarComicsMenuLink">
<a class="dropdown-item" href="/comics/comics">Comics</a>
<a class="dropdown-item" href="/comics/publishers">Publisher</a>
<a class="dropdown-item" href="/comics/artists">Artist</a>
<a class="dropdown-item" href="/comics/issues">Issue</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 class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarWebMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Media</a>
<div class="dropdown-menu" aria-labelledby="navbarWebMenuLink">
<a class="dropdown-item" href="/web/files">Media Files</a>
<a class="dropdown-item" href="/web/actors">Media Actors</a>
<a class="dropdown-item" href="/web/lofis">Lofi</a>
</div>
</li>
{{ if .user }}
<li class="nav-item">
<a class="nav-link" href="{{ .logout }}">Logout</a>
<a class="nav-link" href="/logout">Logout</a>
</li>
{{ else }}
<li class="nav-item">
<a class="nav-link" href="{{ .login }}">Login</a>
<a class="nav-link" href="/login">Login</a>
</li>
{{ end }}
<form class="form-inline">
@@ -35,6 +37,4 @@
</form>
</ul>
</nav>
</div>
{{ end }}
+6 -6
View File
@@ -39,12 +39,12 @@
<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>
{{ 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>
+2 -2
View File
@@ -36,8 +36,8 @@
{{ range .lofis }}
<tr>
<th scope="row"><a href="/media/lofis/{{.ID}}">{{.Title}}</a></th>
{{ if .Url }}
<td><a href="{{.Url}}">{{.Url}}</a></td>
{{ if .WebLink }}
<td><a href="{{.WebLink}}">{{.WebLink}}</a></td>
{{ else }}
<td>WebLink not set</td>
{{ end }}
+70 -1
View File
@@ -5,7 +5,76 @@
<body>
{{ template "navbar" . }}
<h1>{{ .message }}</h1>
<div class="row">
<form class="form-inline" action="/web/files">
<input type="text" placeholder="Search" name="query">
<label>
<input type="checkbox" name="review" {{ if .Review }}checked{{ end }}>Review
</label>
<label>
<input type="checkbox" name="download" {{ if .ShouldDownload }}checked{{ end }}>Download
</label>
<button type="submit">Search</button>
<div class="pill-nav"><a href="/web/files/add">Add MediaFile</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 scope="col">Download</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tbody>
{{ range .mediafiles }}
<tr>
<th scope="row"><a href="/web/files/{{.ID}}">{{.Title}}</a></th>
{{ if .WebLink }}
<td><a href="{{.WebLink}}">{{.WebLink}}</a></td>
{{ else }}
<td>no link</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>
{{ if .ShouldDownload }}
<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="/web/files/edit/{{.ID}}" class="btn btn-outline-primary btn-sm active" role="button"
aria-pressed="true">Edit</a></td>
<td><a href="/web/files/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" . }}
<div class="container">
{{ template "navbar" . }}
</div>
<div class="container">
<h1>{{ .message }}</h1>
<h1>{{ .message }}</h1>
<h1>{{ .message }}</h1>
<h1>{{ .message }}</h1>
</div>
{{ template "footer" . }}
</body>
</html>
+3 -2
View File
@@ -8,8 +8,8 @@ Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000/containers
Wants=kontor-activemq.service kontor-adminer.service kontor-angular.service kontor-api.service kontor-echo.service kontor-fiber.service kontor-javalin.service kontor-quarkus.service kontor-spring.service kontor-vue.service kontor-postgres.service
Before=kontor-activemq.service kontor-adminer.service kontor-angular.service kontor-api.service kontor-echo.service kontor-fiber.service kontor-javalin.service kontor-quarkus.service kontor-spring.service kontor-vue.service kontor-postgres.service
Wants=kontor-activemq.service kontor-adminer.service kontor-angular.service kontor-api.service kontor-echo.service kontor-fiber.service kontor-gin.service kontor-javalin.service kontor-quarkus.service kontor-spring.service kontor-vue.service kontor-postgres.service
Before=kontor-activemq.service kontor-adminer.service kontor-angular.service kontor-api.service kontor-echo.service kontor-fiber.service kontor-gin.service kontor-javalin.service kontor-quarkus.service kontor-spring.service kontor-vue.service kontor-postgres.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
@@ -27,6 +27,7 @@ ExecStartPre=/usr/bin/podman pod create \
-p 8300:8300 \
-p 8400:8400 \
-p 8500:8500 \
-p 8550:8550 \
-p 8600:8600 \
-p 8700:8700 \
-p 8800:8800 \