Vorbereitung Release 0.2.0

This commit is contained in:
2026-01-29 23:50:41 +01:00
parent 58f80b3e76
commit b26b5ecc9c
571 changed files with 35728 additions and 5022 deletions
+28
View File
@@ -0,0 +1,28 @@
# ---------- Stage 1: Build ----------
FROM golang:1.25-alpine AS builder
# Set the working directory
WORKDIR /app
# Ensure a portable, static-ish binary
ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64
# Copy and download dependencies
COPY go.mod go.sum ./
RUN go mod download
# Copy the source code
COPY . .
# Build the Go application (strip debug info for smaller size)
RUN go build -trimpath -ldflags="-s -w" -o kontor cmd/kontor/main.go
# ---------- Stage 2: Final ----------
FROM alpine:latest
# Set the working directory
WORKDIR /app
# Install runtime dependencies you actually need
RUN apk add --no-cache ca-certificates tzdata curl
# Create non-root user for security
RUN addgroup -S kontor && adduser -S -G kontor -H -s /sbin/nologin kontor
# Copy the binary and set ownership
COPY --from=builder --chown=kontor:kontor /app/kontor /app/kontor
# Run as non-root user
USER kontor
# Set the entrypoint command
ENTRYPOINT ["/app/kontor"]
+41
View File
@@ -0,0 +1,41 @@
package main
import (
"kontor-api-fiber/pkg/handler"
"kontor-api-fiber/pkg/schema"
"log"
jwtware "github.com/gofiber/contrib/jwt"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
)
func main() {
log.Println("Kontor started")
if err := schema.Connect(); err != nil {
log.Fatal(err)
}
app := fiber.New()
// app.Use(jwtware.New(jwtware.Config{
// SigningKey: jwtware.SigningKey{Key: []byte("secret")},
// }))
//app.Use(logger.New())
app.Get("/health", handler.GetHealth)
app.Post("/login", handler.Login)
api := app.Group("/api", logger.New(), jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Key: []byte("secret")},
}))
api.Use(logger.New())
handler.SetupComicRoutes(api)
handler.SetupMediaRoutes(api)
// Listen on port 8900
app.Listen(":8600")
log.Println("Kontor finished")
}
+42
View File
@@ -0,0 +1,42 @@
module kontor-api-fiber
go 1.24.2
require (
github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/gofiber/contrib/jwt v1.1.2 // indirect
github.com/gofiber/fiber/v2 v2.52.10 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/uptrace/bun v1.2.16 // indirect
github.com/uptrace/bun/dialect/pgdialect v1.2.16 // indirect
github.com/uptrace/bun/driver/pgdriver v1.2.16 // indirect
github.com/uptrace/bun/extra/bundebug v1.2.16 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.68.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/sys v0.39.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
mellium.im/sasl v0.3.2 // indirect
)
+98
View File
@@ -0,0 +1,98 @@
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/gofiber/contrib/jwt v1.1.2 h1:GmWnOqT4A15EkA8IPXwSpvNUXZR4u5SMj+geBmyLAjs=
github.com/gofiber/contrib/jwt v1.1.2/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39EDp2fBVgMFVk=
github.com/gofiber/fiber v1.14.6 h1:QRUPvPmr8ijQuGo1MgupHBn8E+wW0IKqiOvIZPtV70o=
github.com/gofiber/fiber v1.14.6/go.mod h1:Yw2ekF1YDPreO9V6TMYjynu94xRxZBdaa8X5HhHsjCM=
github.com/gofiber/fiber/v2 v2.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
github.com/gofiber/fiber/v2 v2.52.10/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/uptrace/bun v1.2.16 h1:QlObi6ZIK5Ao7kAALnh91HWYNZUBbVwye52fmlQM9kc=
github.com/uptrace/bun v1.2.16/go.mod h1:jMoNg2n56ckaawi/O/J92BHaECmrz6IRjuMWqlMaMTM=
github.com/uptrace/bun/dialect/pgdialect v1.2.16 h1:KFNZ0LxAyczKNfK/IJWMyaleO6eI9/Z5tUv3DE1NVL4=
github.com/uptrace/bun/dialect/pgdialect v1.2.16/go.mod h1:IJdMeV4sLfh0LDUZl7TIxLI0LipF1vwTK3hBC7p5qLo=
github.com/uptrace/bun/driver/pgdriver v1.2.16 h1:b1kpXKUxtTSGYow5Vlsb+dKV3z0R7aSAJNfMfKp61ZU=
github.com/uptrace/bun/driver/pgdriver v1.2.16/go.mod h1:H6lUZ9CBfp1X5Vq62YGSV7q96/v94ja9AYFjKvdoTk0=
github.com/uptrace/bun/extra/bundebug v1.2.16 h1:3OXAfHTU4ydu2+4j05oB1BxPx6+ypdWIVzTugl/7zl0=
github.com/uptrace/bun/extra/bundebug v1.2.16/go.mod h1:vk6R/1i67/S2RvUI5AH/m3P5e67mOkfDCmmCsAPUumo=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
github.com/valyala/fasthttp v1.68.0 h1:v12Nx16iepr8r9ySOwqI+5RBJ/DqTxhOy1HrHoDFnok=
github.com/valyala/fasthttp v1.68.0/go.mod h1:5EXiRfYQAoiO/khu4oU9VISC/eVY6JqmSpPJoHCKsz4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0=
mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY=
+47
View File
@@ -0,0 +1,47 @@
package handler
import (
"context"
"kontor-api-fiber/pkg/schema"
"kontor-api-fiber/pkg/utils"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
"github.com/uptrace/bun"
)
func Login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
var profile schema.Profile
var err error
var db *bun.DB
ctx := context.Background()
db, _ = schema.GetDatabase()
err = db.NewSelect().Model(&profile).Where("email = ?", user).Scan(ctx)
if err != nil {
return c.Status(400).JSON(fiber.Map{
"message": err.Error(),
})
}
if !utils.ComparePassword(profile.Password, pass) {
return c.SendStatus(fiber.StatusUnauthorized)
}
token, err := utils.GenerateToken(profile)
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"token": token})
}
func Restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Welcome " + name)
}
+77
View File
@@ -0,0 +1,77 @@
package handler
import (
"context"
"kontor-api-fiber/pkg/schema"
"log"
"github.com/gofiber/fiber/v2"
"github.com/uptrace/bun"
)
func SetupComicRoutes(api fiber.Router) {
comics := api.Group("/comics")
comics.Get("/comics", GetAllComics)
comics.Get("/publishers", GetAllPublishers)
comics.Get("/comicworks", GetAllComicWorks)
}
func GetAllComics(c *fiber.Ctx) error {
var comics []schema.Comic
var err error
var db *bun.DB
ctx := context.Background()
db, err = schema.GetDatabase()
if err != nil {
log.Fatal(err)
}
err = db.NewSelect().Model(&comics).Relation("Publisher").Scan(ctx)
if err != nil {
log.Fatal(err)
return fiber.NewError(fiber.StatusInternalServerError)
}
return c.JSON(comics)
}
func GetAllPublishers(c *fiber.Ctx) error {
var publishers []schema.Publisher
var err error
var db *bun.DB
ctx := context.Background()
db, err = schema.GetDatabase()
if err != nil {
log.Fatal(err)
}
err = db.NewSelect().Model(&publishers).Relation("ParentPublisher").Scan(ctx)
if err != nil {
log.Fatal(err)
return fiber.NewError(fiber.StatusInternalServerError)
}
return c.JSON(publishers)
}
func GetAllComicWorks(c *fiber.Ctx) error {
var comic_works []schema.ComicWork
var err error
var db *bun.DB
ctx := context.Background()
db, err = schema.GetDatabase()
if err != nil {
log.Fatal(err)
}
err = db.NewSelect().Model(&comic_works).Relation("Comic").Relation("Artist").Relation("WorkType").Scan(ctx)
if err != nil {
log.Fatal(err)
return fiber.NewError(fiber.StatusInternalServerError)
}
return c.JSON(comic_works)
}
+9
View File
@@ -0,0 +1,9 @@
package handler
import "github.com/gofiber/fiber/v2"
func GetHealth(c *fiber.Ctx) error {
return c.Status(200).JSON(&fiber.Map{
"status": "ok",
})
}
+64
View File
@@ -0,0 +1,64 @@
package handler
import (
"context"
"encoding/json"
"fmt"
"kontor-api-fiber/pkg/schema"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
func SetupMediaRoutes(api fiber.Router) {
media := api.Group("/media")
media.Get("/files", GetAllFiles)
media.Post("/files", AddFile)
}
func GetAllFiles(c *fiber.Ctx) error {
var files []schema.MediaFile
var err error
var db *bun.DB
ctx := context.Background()
db, err = schema.GetDatabase()
if err != nil {
log.Fatal(err)
}
err = db.NewSelect().Model(&files).Relation("MediaActorFiles").Scan(ctx)
if err != nil {
log.Fatal(err)
return fiber.NewError(fiber.StatusInternalServerError)
}
return c.JSON(files)
}
func AddFile(c *fiber.Ctx) error {
var err error
var db *bun.DB
ctx := context.Background()
var payload map[string]interface{}
if err = json.Unmarshal(c.Body(), &payload); err != nil {
return err
}
link := payload["url"]
log.Printf("URL %s has been sent", link)
db, err = schema.GetDatabase()
if err != nil {
log.Fatal(err)
}
id := uuid.NewString()
timestamp := time.Now()
mediafile := &schema.MediaFile{ID: id, CreatedAt: timestamp, UpdatedAt: timestamp, WebLink: fmt.Sprintf("%s", link), Version: 1, ShouldDownload: true, Review: true}
_, err = db.NewInsert().Model(mediafile).Exec(ctx)
if err != nil {
return err
}
return c.SendStatus(201)
}
+62
View File
@@ -0,0 +1,62 @@
package schema
import (
"time"
"github.com/uptrace/bun"
)
type Profile struct {
bun.BaseModel `bun:"table:profile"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
FirstName string `bun:"first_name"`
LastName string `bun:"last_name"`
UserName string `bun:"user_name,unique:user_name"`
Email string `bun:"email"`
Password string `bun:"password"`
Enabled bool `bun:"enabled"`
Assignments []Assignment `bun:"rel:has-many,join:id=profile_id"`
Tokens []Token `bun:"rel:has-many,join:id=profile_id"`
}
type Permission struct {
bun.BaseModel `bun:"table:permission"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
Assignments []Assignment `bun:"rel:has-many,join:id=permission_id"`
}
type Token struct {
bun.BaseModel `bun:"table:token"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
LastUsedAt time.Time `bun:"last_used_date,nullzero,notnull,default:current_timestamp"`
Enabled bool `bun:"enabled,default:true"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
}
type Assignment struct {
bun.BaseModel `bun:"table:assignment"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
PermissionID *string `bun:"permission_id"`
Permission *Permission `bun:"rel:belongs-to,join:permission_id=id"`
}
+140
View File
@@ -0,0 +1,140 @@
package schema
import (
"time"
"github.com/uptrace/bun"
)
type Publisher struct {
bun.BaseModel `bun:"table:publisher"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
WebLink string `bun:"weblink"`
ParentPublisherID *string `bun:"parent_publisher_id"`
ParentPublisher *Publisher `bun:"rel:belongs-to,join:parent_publisher_id=id"`
Imprints []Publisher `bun:"rel:has-many,join:id=parent_publisher_id"`
Comics []Comic `bun:"rel:has-many,join:id=publisher_id"`
}
type Comic struct {
bun.BaseModel `bun:"table:comic"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Title string `bun:"title,unique:title,notnull"`
CurrentOrder bool `bun:"current_order"`
Completed bool `bun:"completed"`
WebLink string `bun:"weblink"`
PublisherID *string `bun:"publisher_id"`
Publisher *Publisher `bun:"rel:belongs-to,join:publisher_id=id"`
Issues []Issue `bun:"rel:has-many,join:id=comic_id"`
StoryArcs []StoryArc `bun:"rel:has-many,join:id=comic_id"`
TradePaperbacks []TradePaperback `bun:"rel:has-many,join:id=comic_id"`
Volumes []Volume `bun:"rel:has-many,join:id=comic_id"`
ComicWorks []ComicWork `bun:"rel:has-many,join:id=comic_id"`
}
type Artist struct {
bun.BaseModel `bun:"table:artist"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:title,notnull"`
WebLink string `bun:"weblink"`
}
type Issue struct {
bun.BaseModel `bun:"table:issue"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
InStock bool `bun:"in_stock"`
IsRead bool `bun:"is_read"`
IssueNumber string `bu:"issue_number"`
Title string `bun:"title"`
PublishedOn time.Time `bun:"published_on"`
ComicID *string `bun:"comic_id"`
Comic *Comic `bun:"rel:belongs-to,join:comic_id=id"`
StoryArcID *string `bun:"story_arc_id"`
StoryArc *StoryArc `bun:"rel:belongs-to,join:story_arc_id=id"`
VolumeID *string `bun:"volume_id"`
Volume *Volume `bun:"rel:belongs-to,join:volume_id=id"`
}
type StoryArc struct {
bun.BaseModel `bun:"table:story_arc"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name,notnull"`
ComicID *string `bun:"comic_id"`
Comic *Comic `bun:"rel:belongs-to,join:comic_id=id"`
VolumeID *string `bun:"volume_id"`
Volume *Volume `bun:"rel:belongs-to,join:volume_id=id"`
}
type TradePaperback struct {
bun.BaseModel `bun:"table:trade_paperback"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name,notnull"`
IssueStart int `bun:"issue_start"`
IssueEnd int `bun:"issue_end"`
ComicID *string `bun:"comic_id"`
Comic *Comic `bun:"rel:belongs-to,join:comic_id=id"`
}
type Volume struct {
bun.BaseModel `bun:"table:volume"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name,notnull"`
ComicID *string `bun:"comic_id"`
Comic *Comic `bun:"rel:belongs-to,join:comic_id=id"`
}
type WorkType struct {
bun.BaseModel `bun:"table:worktype"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name,notnull"`
}
type ComicWork struct {
bun.BaseModel `bun:"table:comic_work"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
ArtistID *string `bun:"artist_id"`
Artist *Artist `bun:"rel:belongs-to,join:artist_id=id"`
ComicID *string `bun:"comic_id"`
Comic *Comic `bun:"rel:belongs-to,join:comic_id=id"`
WorkTypeID *string `bun:"work_type_id"`
WorkType *WorkType `bun:"rel:belongs-to,join:work_type_id=id"`
}
+101
View File
@@ -0,0 +1,101 @@
package schema
import (
"context"
"log"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"database/sql"
"github.com/uptrace/bun"
"github.com/uptrace/bun/extra/bundebug"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
func GetTestDatabase() (*bun.DB, error) {
var err error
dsn := "postgres://kontor:kontor@localhost:5432/kontor?sslmode=disable"
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
sqldb.SetMaxOpenConns(4)
sqldb.SetMaxIdleConns(4)
DB := bun.NewDB(sqldb, pgdialect.New())
DB.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
if err = DB.Ping(); err != nil {
return nil, err
}
log.Println("Returned Database Connection")
return DB, nil
}
func TestMain(m *testing.M) {
log.Println("Setup Test")
exitCode := m.Run()
os.Exit(exitCode)
}
func TestSelectComics(t *testing.T) {
var comics []Comic
var err error
var db *bun.DB
ctx := context.Background()
db, err = GetTestDatabase()
require.NoError(t, err)
err = db.NewSelect().Model(&comics).Relation("Publisher").Scan(ctx)
if err != nil {
log.Fatal(err)
}
require.NoError(t, err)
assert.Equal(t, 168, len(comics))
}
func TestSelectPublishers(t *testing.T) {
var publishers []Publisher
var err error
var db *bun.DB
ctx := context.Background()
db, err = GetTestDatabase()
require.NoError(t, err)
err = db.NewSelect().Model(&publishers).Relation("ParentPublisher").Scan(ctx)
if err != nil {
log.Fatal(err)
}
require.NoError(t, err)
assert.Equal(t, 19, len(publishers))
}
func TestSelectWorkTypes(t *testing.T) {
var comic_works []ComicWork
var err error
var db *bun.DB
ctx := context.Background()
db, err = GetTestDatabase()
if err != nil {
log.Fatal(err)
}
err = db.NewSelect().Model(&comic_works).Relation("Comic").Relation("Artist").Relation("WorkType").Scan(ctx)
if err != nil {
log.Fatal(err)
}
require.NoError(t, err)
assert.Equal(t, 59, len(comic_works))
}
+50
View File
@@ -0,0 +1,50 @@
package schema
import (
"database/sql"
"log"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
var DB *bun.DB
func Connect() error {
var err error
dsn := "postgres://kontor:kontor@postgres:5432/kontor?sslmode=disable"
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
sqldb.SetMaxOpenConns(4)
sqldb.SetMaxIdleConns(4)
DB := bun.NewDB(sqldb, pgdialect.New())
if err = DB.Ping(); err != nil {
return err
}
log.Println("Connection Opened to Database")
return nil
}
func GetDatabase() (*bun.DB, error) {
var err error
dsn := "postgres://kontor:kontor@postgres:5432/kontor?sslmode=disable"
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
sqldb.SetMaxOpenConns(4)
sqldb.SetMaxIdleConns(4)
DB := bun.NewDB(sqldb, pgdialect.New())
if err = DB.Ping(); err != nil {
return nil, err
}
log.Println("Returned Database Connection")
return DB, nil
}
+79
View File
@@ -0,0 +1,79 @@
package schema
import (
"time"
"github.com/uptrace/bun"
)
type MediaFile struct {
bun.BaseModel `bun:"table:media_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_file_id"`
}
type MediaActor struct {
bun.BaseModel `bun:"table:media_actor"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
WebLink string `bun:"url,unique:url"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_actor_id"`
}
type MediaActorFile struct {
bun.BaseModel `bun:"table:media_actor_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
MediaActorID *string `bun:"media_actor_id"`
MediaActor *MediaActor `bun:"rel:belongs-to,join:media_actor_id=id"`
MediaFileID *string `bun:"media_file_id"`
MediaFile *MediaFile `bun:"rel:belongs-to,join:media_file_id=id"`
}
type MediaArticle struct {
bun.BaseModel `bun:"table:media_article"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
}
type MediaVideo struct {
bun.BaseModel `bun:"table:media_article"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
}
+8
View File
@@ -0,0 +1,8 @@
package utils
import "golang.org/x/crypto/bcrypt"
func ComparePassword(hashedPassword, password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
return err == nil
}
+38
View File
@@ -0,0 +1,38 @@
package utils
import (
"kontor-api-fiber/pkg/schema"
"time"
"github.com/golang-jwt/jwt/v5"
)
func GenerateToken(user schema.Profile) (string, error) {
// Create the Claims
claims := jwt.MapClaims{
"name": user.FirstName + ", " + user.LastName,
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Create token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Generate encoded token and send it as response.
t, err := token.SignedString([]byte("secret"))
if err != nil {
return "", err
}
return t, nil
}
func VerifyToken(tokenString string) (bool, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte("secret"), nil
})
if err != nil {
return false, err
}
return token.Valid, nil
}