6 Commits

Author SHA1 Message Date
tpeetz 79653d2c43 WIP: add missing handlers, services nd repositories
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Gitea Actions Demo / build-and-test (push) Failing after 12s
2026-11-06 21:20:24 +01:00
Thomas Peetz 50e2da8a66 update kontor-echo
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
Gitea Actions Demo / build-and-test (push) Failing after 14s
2026-11-06 16:48:15 +01:00
Thomas Peetz 9a7219e106 update echo to v5 and prepare kontor-echo to use handlers, repository and service
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
Gitea Actions Demo / build-and-test (push) Failing after 11s
2026-11-06 11:11:04 +01:00
tpeetz 20e141b73e move media models
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
Gitea Actions Demo / build-and-test (push) Failing after 1m3s
2026-11-06 10:29:48 +01:00
tpeetz f75dd3a9fb Fix Media Articlrd
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Gitea Actions Demo / build-and-test (push) Failing after 1m2s
2026-11-01 04:06:17 +01:00
tpeetz f9b7e20841 Fix Listign of MediaArticle 2026-11-01 02:32:18 +01:00
64 changed files with 4167 additions and 190 deletions
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"context"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/handlers"
"kontor-api-echo/internal/router"
"kontor-api-echo/pkg/schema"
"log"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"github.com/labstack/echo/v5"
)
func main() {
slog.Info("Kontor started")
db, _ := schema.GetDatabase()
if err := config.InitConfig(); err != nil {
log.Fatalf("Failed to initialize config: %v", err)
}
e := router.New(handlers.NewAdminHandler(db), handlers.NewMediaHandler(db))
// Cancel the context on SIGINT / SIGTERM
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
sc := echo.StartConfig{
Address: ":1323",
GracefulTimeout: 10 * time.Second,
}
if err := sc.Start(ctx, e); err != nil {
e.Logger.Error("server stopped", "error", err)
}
slog.Info("Kontor finished")
}
+46 -17
View File
@@ -1,39 +1,68 @@
module kontor-api-echo
go 1.24.2
go 1.26.0
require (
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/labstack/echo-jwt/v4 v4.4.0
github.com/labstack/echo-jwt/v5 v5.0.2
github.com/labstack/echo/v4 v4.15.0
github.com/labstack/echo/v5 v5.4.4
github.com/stretchr/testify v1.11.1
github.com/uptrace/bun v1.3.0
github.com/uptrace/bun/dialect/pgdialect v1.2.16
github.com/uptrace/bun/driver/pgdriver v1.2.16
golang.org/x/crypto v0.54.0
)
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/mattn/go-sqlite3 v1.14.34 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
modernc.org/libc v1.68.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.46.1 // indirect
)
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/labstack/echo-jwt/v4 v4.4.0 // indirect
github.com/labstack/echo/v4 v4.15.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.1.0 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // 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/uptrace/bun/dialect/sqlitedialect v1.3.0
github.com/uptrace/bun/driver/sqliteshim v1.3.0
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect
go.yaml.in/yaml/v3 v3.0.6 // indirect
golang.org/x/net v0.57.0 // indirect
golang.org/x/sys v0.49.0 // indirect
golang.org/x/text v0.43.0 // indirect
golang.org/x/time v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
mellium.im/sasl v0.3.2 // indirect
)
+82 -18
View File
@@ -1,43 +1,88 @@
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
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/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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
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/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=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo-jwt/v4 v4.4.0 h1:nrXaEnJupfc2R4XChcLRDyghhMZup77F8nIzHnBK19U=
github.com/labstack/echo-jwt/v4 v4.4.0/go.mod h1:kYXWgWms9iFqI3ldR+HAEj/Zfg5rZtR7ePOgktG4Hjg=
github.com/labstack/echo-jwt/v5 v5.0.2 h1:ECmHEjwbR30fv90LvpQ0XZbEJWhCF/c3Zp8ug/iVrCE=
github.com/labstack/echo-jwt/v5 v5.0.2/go.mod h1:jNxekWlI4+M+UoV8dozKwIHN9MJ2psUR+U1B0nEutIg=
github.com/labstack/echo/v4 v4.15.0 h1:hoRTKWcnR5STXZFe9BmYun9AMTNeSbjHi2vtDuADJ24=
github.com/labstack/echo/v4 v4.15.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
github.com/labstack/echo/v5 v5.4.4 h1:Nag9Mee0M9sOcKjProYuDNiw60QisysgfbIgz5US5Cw=
github.com/labstack/echo/v5 v5.4.4/go.mod h1:4iEGNQiPPZnkfYpNR/L6fINd3NLiGWUD5+eBotFALas=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
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 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.1.0 h1:6W6MbVUrnMb8PEhjkqwsVLY7ryuzRfFHF4mQd7L94ag=
github.com/spf13/pflag v1.1.0/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
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 v1.3.0 h1:hUcbfRpbQk4/upFSI+uZf6jSJw5A0lkIKt0XdpvbUZo=
github.com/uptrace/bun v1.3.0/go.mod h1:wNltaKJk4JtOt4SG5I5zmA7v0/Mzjh1+/S906Rayd3Y=
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/dialect/sqlitedialect v1.3.0 h1:XzxkORYksxkLsIQLJHFYUb3yDvqSQHzTungyKpJhHTw=
github.com/uptrace/bun/dialect/sqlitedialect v1.3.0/go.mod h1:x2D1sY50Itio0I/FVdNe30oMUT2ObiAS+oILcMR+Wys=
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/uptrace/bun/driver/sqliteshim v1.3.0 h1:T3ybxgmP8ejA99YULje9e12h+FqKKAP/4xZo3+X3mXA=
github.com/uptrace/bun/driver/sqliteshim v1.3.0/go.mod h1:MqvqMCAAKNn6M0HF9YK/Z6xrnCP6sih5OZ37AxdAlHw=
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/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
@@ -50,19 +95,38 @@ go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA=
golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s=
golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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=
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
+163
View File
@@ -0,0 +1,163 @@
package config
import (
"errors"
"fmt"
"log/slog"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
CfgFile string
Verbose int
Overwrite bool
ServerName string
Mediatype MediaType
Config CliConfig
ServerConfig ServerConfiguration
DryRun bool
FileName string
)
const (
mediaTypeMedia MediaType = "media"
mediaTypeVideo MediaType = "video"
mediaTypeLofi MediaType = "lofi"
)
type MediaType string
func (e *MediaType) String() string {
return string(*e)
}
func (e *MediaType) Set(v string) error {
switch v {
case "media", "video", "lofi":
*e = MediaType(v)
return nil
default:
return errors.New(`must be one of "media", "video", "lofi"`)
}
}
func (e *MediaType) Type() string {
return "MediaType"
}
func myEnumCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{
"media\thelp text for media",
"video\thelp text for video",
"lofi\thelp text for lofi",
}, cobra.ShellCompDirectiveDefault
}
type Server struct {
Url string `mapstructure:"url"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}
type Database struct {
Type string `mapstructure:"type" validate:"required"`
Path string `mapstructure:"path" validate:"required"`
Host string `mapstructure:"host" validate:"required"`
Name string `mapstructure:"name" validate:"required"`
Port int `mapstructure:"port" validate:"required"`
Password string `mapstructure:"password" validate:"required"`
User string `mapstructure:"user" validate:"required"`
}
type CliConfig struct {
ApiVersion string
Server map[string]Server `mapstructure:"server"`
DB Database `mapstructure:"db"`
}
type ServerConfiguration struct {
Server struct {
Port int `mapstructure:"port" validate:"required"`
Host string `mapstructure:"host"`
} `mapstructure:"server"`
DB Database `mapstructure:"db"`
Gin struct {
Mode string `mapstructure:"mode" validate:"required"`
} `mapstructure:"gin"`
ApiSecret []byte `mapstructure:"api_secret"`
}
func InitCliConfig() {
slog.Info("InitCliConfig")
if CfgFile != "" {
viper.SetConfigFile(CfgFile)
} else {
viper.SetConfigName("kli") // without extension
viper.SetConfigType("yaml")
viper.AddConfigPath(".") // look for config in working directory
viper.AddConfigPath("/home/tpeetz/.config")
}
Mediatype = mediaTypeMedia
// Read the configuration 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")
if err := viper.SafeWriteConfig(); err != nil {
slog.Info("error writing config file", "error", err.Error())
}
} else {
slog.Info("error reading config file", "error", err.Error())
}
} else {
slog.Info("InitCliConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&Config); err != nil {
slog.Info("parsing of config file failed", "error", err.Error())
}
}
}
func InitConfig() error {
viper.SetConfigName("kontor-gin")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("/home/tpeetz/.config")
viper.AddConfigPath("/etc/kontor")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.SetDefault("db.type", "postgres")
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("db.path", "data/kontor.db")
viper.SetDefault("server.port", 8550)
viper.SetDefault("gin.mode", "release")
// 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")
if err := viper.SafeWriteConfig(); err != nil {
slog.Info("error writing config file", "error", err.Error())
return fmt.Errorf("error writing config file: %w", err)
}
} else {
return fmt.Errorf("error reading config file: %w", err)
}
} else {
slog.Info("InitConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&ServerConfig); err != nil {
slog.Info("parsing of config file failed", "error", err.Error())
}
}
return nil
}
+54
View File
@@ -0,0 +1,54 @@
package config
import (
"database/sql"
"fmt"
"log/slog"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/dialect/sqlitedialect"
"github.com/uptrace/bun/driver/pgdriver"
"github.com/uptrace/bun/driver/sqliteshim"
)
func NewDB(db Database) (*bun.DB, error) {
db_type := db.Type
slog.Info("using database", "type", db_type)
switch db_type {
case "postgres":
dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s", db.User, db.Password, db.Host, db.Port, db.Name)
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
db := bun.NewDB(sqldb, pgdialect.New())
return db, nil
case "sqlite":
sqldb, _ := sql.Open(sqliteshim.ShimName, "file::memory:?cache=shared")
db := bun.NewDB(sqldb, sqlitedialect.New())
return db, nil
default:
return nil, fmt.Errorf("unknown db.type=%s", db_type)
}
// Configure GORM with custom settings
// The logger helps with debugging SQL queries during development
// 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)
// slog.Info("Database connected successfully")
}
+39
View File
@@ -0,0 +1,39 @@
package globals
import (
"fmt"
)
var (
Secret = []byte("secret")
Version = "unset"
Commit = "unset"
Date = "unset"
)
const (
UserKey = "user"
MediaFileLink = "/media/files"
MediaLofiLink = "/media/lofis"
MediaMusicLink = "/media/musics"
MediaVideoLink = "/media/videos"
MediaArticleLink = "/media/articles"
MediaActorLink = "/media/actors"
)
func GetDefaultValues(user interface{}, message string) map[string]any {
values := map[string]any{
"title": "Kontor",
"version": fmt.Sprintf("%s %s", Version, Commit),
"message": message,
"user": user,
"media_file_link": MediaFileLink,
"media_lofi_link": MediaLofiLink,
"media_music_link": MediaMusicLink,
"media_video_link": MediaVideoLink,
"media_article_link": MediaArticleLink,
"media_actor_link": MediaActorLink,
}
return values
}
+28
View File
@@ -0,0 +1,28 @@
package handlers
import (
"github.com/uptrace/bun"
)
type AdminHandler struct {
AuthHandler *AuthHandler
ProfileHandler *ProfileHandler
PermissionHandler *PermissionHandler
AssignmentHandler *AssignmentHandler
TokenHandler *TokenHandler
MailAccountHandler *MailAccountHandler
MailHandler *MailHandler
}
func NewAdminHandler(db *bun.DB) *AdminHandler {
adminHandler := &AdminHandler{
AuthHandler: NewAuthHandler(db),
ProfileHandler: NewProfileHandler(db),
PermissionHandler: NewPermissionHandler(db),
AssignmentHandler: NewAssignmentHandler(db),
TokenHandler: NewTokenHandler(db),
MailAccountHandler: NewMailAccountHandler(db),
MailHandler: NewMailHandler(db),
}
return adminHandler
}
@@ -0,0 +1,30 @@
package handlers
import (
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type AssignmentHandler struct {
Service *service.AssignmentService
}
func NewAssignmentHandler(db *bun.DB) *AssignmentHandler {
handler := &AssignmentHandler{Service: service.NewAssignmentService(repository.NewAssignmentRepository(db))}
return handler
}
func (handler *AssignmentHandler) List(c *echo.Context) {
assignments, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertAssignmentsToDtos(assignments)
c.JSON(http.StatusOK, dtos)
}
+26
View File
@@ -0,0 +1,26 @@
package handlers
import "github.com/uptrace/bun"
type MediaHandler struct {
MediaArticleHandler *MediaArticleHandler
MediaActorHandler *MediaActorHandler
MediaFileHandler *MediaFileHandler
MediaLoFiHandler *MediaLoFiHandler
MediaMusicHandler *MediaMusicHandler
MediaVideoHandler *MediaVideoHandler
MediaActorFileHandler *MediaActorFileHandler
}
func NewMediaHandler(db *bun.DB) *MediaHandler {
mediaHandler := &MediaHandler{
MediaArticleHandler: NewMediaArticleHandler(db),
MediaActorHandler: NewMediaActorHandler(db),
MediaFileHandler: NewMediaFileHandler(db),
MediaLoFiHandler: NewMediaLoFiHandler(db),
MediaMusicHandler: NewMediaMusicHandler(db),
MediaVideoHandler: NewMediaVideoHandler(db),
MediaActorFileHandler: NewMediaActorFileHandler(db),
}
return mediaHandler
}
@@ -0,0 +1,137 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaActorHandler struct {
Service *service.MediaActorService
}
func NewMediaActorHandler(db *bun.DB) *MediaActorHandler {
mediaActorHandler := &MediaActorHandler{
Service: service.NewMediaActorService(repository.NewMediaActorRepository(db)),
}
return mediaActorHandler
}
func (handler *MediaActorHandler) List(c *echo.Context) {
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaActorsToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaActorHandler) Get(c *echo.Context) {
id := c.Param("id")
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorHandler) Add(c *echo.Context) {
var input models.MediaActorAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
actor, err := handler.Service.Add(c.Request().Context(), input.WebLink)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaActorHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
actors, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actors"] = actors
c.Render(http.StatusOK, "media_actors", data)
}
func (handler *MediaActorHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
//logger := slog.Get(c)
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
c.Render(http.StatusOK, "actor_detail", data)
}
func (handler *MediaActorHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaActorForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "actor_detail", data)
return
}
logger.Info("MediaActorHandler#UpdatePage", "actor", actor)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
func (handler *MediaActorHandler) DeletePage(c *echo.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
//actor, err := handler.Service.Get(c.Request.Context(), id)
// if err != nil {
// logger.Info("MediaActorHandler#DeletePage", "error", err.Error())
// c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
// return
// }
logger.Info("MediaActorHandler#DeletePage", "actor", id)
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
@@ -0,0 +1,85 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaActorFileHandler struct {
Service *service.MediaActorFileService
}
func NewMediaActorFileHandler(db *bun.DB) *MediaActorFileHandler {
mediaActorFileHandler := &MediaActorFileHandler{
Service: service.NewMediaActorFileService(repository.NewMediaActorFileRepository(db)),
}
return mediaActorFileHandler
}
func (handler *MediaActorFileHandler) List(c *echo.Context) {
media_actor_files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaActorFilesToDtos(media_actor_files)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaActorFileHandler) Get(c *echo.Context) {
id := c.Param("id")
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorFileHandler) Add(c *echo.Context) {
var input models.MediaActorFileAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
actorfile, err := handler.Service.Add(c.Request().Context(), input.MediaActorID, input.MediaFileID)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, actorfile)
}
func (handler *MediaActorFileHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaActorFileHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
media_actor_files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
c.Render(http.StatusOK, "mediaactorfiles", map[string]string{
"title": "Kontor MediaActorFiles",
"version": "0.4.0",
"message": "MediaActorFiles...",
"actors": media_actor_files,
"user": user,
})
}
@@ -0,0 +1,115 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaArticleHandler struct {
Service *service.MediaArticleService
}
func NewMediaArticleHandler(db *bun.DB) *MediaArticleHandler {
mediaFileHandler := &MediaArticleHandler{
Service: service.NewMediaArticleService(repository.NewMediaArticleRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaArticleHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaArticleHandler#List")
articles, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaArticlesToDtos(articles)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaArticleHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaArticleHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaArticles...")
data["title"] = "Kontor MediaArticles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaArticleLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaArticleHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["lofi"] = media_file
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_article, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaArticleForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaArticleHandler#UpdatePage", "media_article", media_article)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
func (handler *MediaArticleHandler) DeletePage(c *echo.Context) {
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
+132
View File
@@ -0,0 +1,132 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaFileHandler struct {
Service *service.MediaFileService
}
func NewMediaFileHandler(db *bun.DB) *MediaFileHandler {
mediaFileHandler := &MediaFileHandler{
Service: service.NewMediaFileService(repository.NewMediaFileRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaFileHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaFileHandler#List")
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaFilesToDtos(files)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaFileHandler) Add(c *echo.Context) {
var input models.MediaFileAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaFileHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaFileHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaFiles...")
data["title"] = "Kontor MediaFiles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaVideoLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaFileHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["lofi"] = media_file
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaFileHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaFileForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaFileHandler#UpdatePage", "media_file", media_file)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaFileLink)
}
func (handler *MediaFileHandler) DeletePage(c *echo.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaFileHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaFileHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaFileLink)
}
+232
View File
@@ -0,0 +1,232 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"time"
"github.com/google/uuid"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaLoFiHandler struct {
Service *service.MediaLoFiService
}
func NewMediaLoFiHandler(db *bun.DB) *MediaLoFiHandler {
mediaLoFiHandler := &MediaLoFiHandler{
Service: service.NewMediaLoFiService(repository.NewMediaLoFiRepository(db)),
}
return mediaLoFiHandler
}
func (handler *MediaLoFiHandler) List(c *echo.Context) {
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaLoFisToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaLoFiHandler) Get(c *echo.Context) {
id := c.Param("id")
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "Lofi not found"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Add(c *echo.Context) {
var input models.MediaLofiAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Update(c *echo.Context) {
var input models.MediaLoFiDTO
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Update(c.Request().Context(), input)
if err != nil {
logger := c.Logger()
logger.Info("MediaLoFiHandler#Update", "error", err.Error())
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not updated"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaLoFiHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
var (
review bool
download bool
)
paramReview, err := echo.QueryParam[string](c, "review")
if err == nil {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, err := echo.QueryParam[string](c, "should_download")
if err == nil {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaLoFiHandler#ListPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
data := globals.GetDefaultValues(user, "MediaFiles...")
data["media_links"] = lofis
data["isReview"] = review
data["isDownload"] = download
data["MediaLinksUrl"] = globals.MediaLofiLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaLoFiHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
var lofi *models.MediaLoFi
if id == "" {
// id is empty, adding is assumed
lofi = &models.MediaLoFi{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Version: 0,
Review: true,
ShouldDownload: true,
}
} else {
// id is set, fetch MediaLofi by ID
lofi, err = handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
}
logger.Info("MediaLoFiHandler#EditPage", "lofi", lofi)
data := globals.GetDefaultValues(user, "MediaLofis...")
data["media"] = lofi
data["MediaLinksUrl"] = globals.MediaLofiLink
c.Render(http.StatusOK, "media_detail", data)
}
func (handler *MediaLoFiHandler) ChangeReviewPage(c *echo.Context) {
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error())
c.Redirect(http.StatusNotFound, globals.MediaLofiLink)
return
}
lofi.Review = !lofi.Review
handler.Service.Update(c.Request().Context(), lofi.ConvertMediaLoFiToDTO())
logger.Info("MediaLoFiHandler#ChangeReviewPage", "lofi", lofi)
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
data := globals.GetDefaultValues(user, "MediaLofis...")
data["lofis"] = lofis
//c.HTML(http.StatusOK, "lofi", data)
c.Redirect(http.StatusCreated, globals.MediaLofiLink)
}
func (handler *MediaLoFiHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaLoFiForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaLoFiHandler#UpdatePage", "error", err.Error())
c.Render(http.StatusBadRequest, "lofi_detail", map[string]any{
"Form": form,
"Errors": err.Error(),
"user": user,
})
return
}
logger.Info("MediaLoFiHandler#UpdatePage", "lofi", lofi)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaLofiLink)
}
func (handler *MediaLoFiHandler) DeletePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#DeletePage", "lofi", id)
c.Render(http.StatusOK, "lofi_delete", map[string]string{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"lofi": lofi,
"user": user,
})
}
@@ -0,0 +1,181 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaMusicHandler struct {
Service *service.MediaMusicService
}
func NewMediaMusicHandler(db *bun.DB) *MediaMusicHandler {
mediaMusicHandler := &MediaMusicHandler{
Service: service.NewMediaMusicService(repository.NewMediaMusicRepository(db)),
}
return mediaMusicHandler
}
func (handler *MediaMusicHandler) List(c *echo.Context) {
musics, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaMusicsToDtos(musics)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaMusicHandler) Get(c *echo.Context) {
id := c.Param("id")
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Add(c *echo.Context) {
var input models.MediaLofiAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
music, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not added"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Update(c *echo.Context) {
var input models.MediaMusicDTO
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
music, err := handler.Service.Update(c.Request().Context(), input)
if err != nil {
logger := c.Logger()
logger.Info("MediaMusicHandler#Update", "error", err.Error())
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not updated"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaMusicHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
var (
review bool
download bool
)
paramReview, err := echo.QueryParam[string](c, "review")
if err == nil {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, err := echo.QueryParam[string](c, "should_download")
if err == nil {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
musics, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaMusicHandler#ListPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#ListPage", "MediaMusic count", len(musics))
data := globals.GetDefaultValues(user, "MediaMusic...")
data["media_links"] = musics
data["MediaLinksUrl"] = globals.MediaMusicLink
data["isReview"] = review
data["isDownload"] = download
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaMusicHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#EditPage", "music", music)
data := globals.GetDefaultValues(user, "MediaMusic...")
data["lofi"] = music
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaMusicForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaMusic...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaMusicHandler#UpdatePage", "music", music)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
func (handler *MediaMusicHandler) DeletePage(c *echo.Context) {
// session := sessions.Default(c)
// user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#DeletePage", "music", id)
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
@@ -0,0 +1,113 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaVideoHandler struct {
Service *service.MediaVideoService
}
func NewMediaVideoHandler(db *bun.DB) *MediaVideoHandler {
handler := &MediaVideoHandler{Service: service.NewMediaVideoService(repository.NewMediaVideoRepository(db))}
return handler
}
func (handler *MediaVideoHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaVideoHandler#List")
videos, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaVideosToDtos(videos)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaVideoHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
videos, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#ListPage", "videos count", len(videos))
data := globals.GetDefaultValues(user, "MediaVideos...")
data["title"] = "Kontor MediaVideos"
data["media_links"] = videos
data["MediaLinksUrl"] = globals.MediaVideoLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaVideoHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
video, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#EditPage", "lofi", video)
data := globals.GetDefaultValues(user, "MediaLofis...")
data["lofi"] = video
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaVideoHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
video, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaVideoForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.Render(http.StatusBadRequest, "lofi_detail", map[string]any{
"Form": form,
"Errors": err.Error(),
"user": user,
})
return
}
logger.Info("MediaVideoHandler#UpdatePage", "lofi", video)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaVideoLink)
}
func (handler *MediaVideoHandler) DeletePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
err = handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#DeletePage", "video", id)
c.Render(http.StatusOK, "lofi_delete", map[string]string{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"user": user,
})
}
@@ -0,0 +1,28 @@
package handlers
import (
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type PermissionHandler struct {
Service *service.PermissionService
}
func NewPermissionHandler(db *bun.DB) *PermissionHandler {
handler := &PermissionHandler{Service: service.NewPermissionService(repository.NewPermissionRepository(db))}
return handler
}
func (handler *PermissionHandler) List(c *echo.Context) {
permissions, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
c.JSON(http.StatusOK, permissions)
}
+30
View File
@@ -0,0 +1,30 @@
package handlers
import (
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type ProfileHandler struct {
Service *service.ProfileService
}
func NewProfileHandler(db *bun.DB) *ProfileHandler {
handler := &ProfileHandler{Service: service.NewProfileService(repository.NewProfileRepository(db))}
return handler
}
func (handler *ProfileHandler) List(c *echo.Context) {
profiles, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertProfilesToDtos(profiles)
c.JSON(http.StatusOK, dtos)
}
+69
View File
@@ -0,0 +1,69 @@
package helpers
import (
"encoding/json"
"fmt"
"time"
)
type DateOnly struct {
time.Time
}
func (d DateOnly) MarshalJSON() ([]byte, error) {
if d.IsZero() {
return []byte("null"), nil
}
return json.Marshal(d.Format("2006-01-02"))
}
func (d *DateOnly) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if s == "" {
return nil
}
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
d.Time = t
return nil
}
type KontorTime struct {
time.Time
}
var layouts = []string{
"2006-01-02 15:04:05.000000",
"2006-01-02T15:04:05.999Z",
"2006-01-02",
}
func (kt KontorTime) MarshalJSON() ([]byte, error) {
if kt.IsZero() {
return []byte("null"), nil
}
return json.Marshal(kt.Format(layouts[0]))
}
func (kt *KontorTime) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if s == "" {
return nil
}
for _, layout := range layouts {
t, err := time.Parse(layout, s)
if err == nil {
kt.Time = t
return nil
}
}
return fmt.Errorf("failed to parse time from %s", s)
}
+63
View File
@@ -0,0 +1,63 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
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"`
}
type AssignmentDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
ProfileID *string `json:"profile_id"`
PermissionID *string `json:"permission_id"`
}
func (dto *AssignmentDTO) ConvertDTOToModel() Assignment {
model := Assignment{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
ProfileID: dto.ProfileID,
PermissionID: dto.PermissionID,
}
return model
}
func ConvertAssignmentsToDtos(assignments []Assignment) []AssignmentDTO {
dtos := make([]AssignmentDTO, len(assignments))
for i, assignment := range assignments {
dtos[i] = AssignmentDTO{
ID: assignment.ID,
CreatedAt: helpers.KontorTime{Time: assignment.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: assignment.UpdatedAt},
DeletedAt: assignment.DeletedAt,
Version: assignment.Version,
ProfileID: assignment.ProfileID,
PermissionID: assignment.PermissionID,
}
}
return dtos
}
type AssignmentDTOList []AssignmentDTO
@@ -0,0 +1,72 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Name string `bun:"name"`
WebLink string `bun:"url,unique:url"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_actor_id"`
}
type MediaActorForm struct {
Name string `form:"name" binding:"required"`
Weblink string `form:"weblink" binding:"required"`
}
type MediaActorDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
Name string `json:"name"`
WebLink string `json:"url"`
}
func (dto MediaActorDTO) ConvertDTOToModel() MediaActor {
model := MediaActor{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Name: dto.Name,
WebLink: dto.WebLink,
}
return model
}
type MediaActorAdd struct {
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: helpers.KontorTime{Time: actor.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: actor.UpdatedAt},
DeletedAt: actor.DeletedAt,
Version: actor.Version,
Name: actor.Name,
WebLink: actor.WebLink,
}
}
return dtos
}
type MediaActorDTOList []MediaActorDTO
@@ -0,0 +1,68 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
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 MediaActorFileAdd struct {
MediaActorID string `json:"media_actor_id"`
MediaFileID string `json:"media_file_id"`
}
type MediaActorFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
MediaActorID *string `json:"media_actor_id"`
MediaFileID *string `json:"media_file_id"`
}
func (dto MediaActorFileDTO) ConvertDTOToModel() MediaActorFile {
model := MediaActorFile{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
MediaActorID: dto.MediaActorID,
MediaFileID: dto.MediaFileID,
}
return model
}
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: helpers.KontorTime{Time: actor_file.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: actor_file.UpdatedAt},
DeletedAt: actor_file.DeletedAt,
Version: actor_file.Version,
MediaActorID: actor_file.MediaActorID,
MediaFileID: actor_file.MediaFileID,
}
}
return dtos
}
type MediaActorFileDTOList []MediaActorFileDTO
@@ -0,0 +1,80 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
}
func (media_article MediaArticle) ConvertMediaArticleToDTO() MediaArticleDTO {
dto := MediaArticleDTO{
ID: media_article.ID,
CreatedAt: helpers.KontorTime{Time: media_article.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_article.UpdatedAt},
DeletedAt: media_article.DeletedAt,
Version: media_article.Version,
Review: media_article.Review,
Title: media_article.Title,
WebLink: media_article.WebLink,
}
return dto
}
type MediaArticleForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaArticleForm) ConvertFormToMediaArticleDTO() MediaArticleDTO {
dto := MediaArticleDTO{}
return dto
}
type MediaArticleDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `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 (dto MediaArticleDTO) ConvertDTOToModel() MediaArticle {
model := MediaArticle{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Review: dto.Review,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func ConvertMediaArticlesToDtos(media_articles []MediaArticle) MediaArticleDTOList {
dtos := make(MediaArticleDTOList, len(media_articles))
for i, media_article := range media_articles {
dtos[i] = media_article.ConvertMediaArticleToDTO()
}
return dtos
}
type MediaArticleDTOList []MediaArticleDTO
+97
View File
@@ -0,0 +1,97 @@
package models
import (
"kontor-api-echo/internal/helpers"
"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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
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 MediaFileAdd struct {
Url string `json:"url"`
}
type MediaFileForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaFileForm) ConvertFormToMediaFileDTO() MediaFileDTO {
media_file := MediaFileDTO{}
return media_file
}
type MediaFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
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 (dto MediaFileDTO) ConvertDTOToModel() MediaFile {
model := MediaFile{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
CloudLink: dto.CloudLink,
FileName: dto.FileName,
Path: dto.Path,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
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: helpers.KontorTime{Time: media_file.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: 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
}
type MediaFileDTOList []MediaFileDTO
+193
View File
@@ -0,0 +1,193 @@
package models
import (
"fmt"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/helpers"
"log/slog"
"time"
"github.com/uptrace/bun"
)
type MediaLoFi struct {
bun.BaseModel `bun:"table:media_lofi"`
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
WebLink string `bun:"url,unique:url"`
Review bool `bun:"review"`
ShouldDownload bool `bun:"should_download"`
Title string `bun:"title"`
FileName string `bun:"file_name"`
}
func (media_lofi *MediaLoFi) Update(update MediaLoFiDTO) {
media_lofi.CreatedAt = update.CreatedAt.Time
media_lofi.UpdatedAt = time.Now()
media_lofi.Version = media_lofi.Version + 1
media_lofi.WebLink = update.WebLink
media_lofi.Review = update.Review
media_lofi.ShouldDownload = update.ShouldDownload
media_lofi.Title = update.Title
media_lofi.FileName = update.FileName
}
func (media_lofi *MediaLoFi) ConvertMediaLoFiToDTO() MediaLoFiDTO {
dto := MediaLoFiDTO{
ID: media_lofi.ID,
CreatedAt: helpers.KontorTime{Time: media_lofi.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: 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 dto
}
type MediaLofiAdd struct {
Url string `json:"url"`
}
type MediaLoFiForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaLoFiForm) ConvertFormToMediaLofiDTO() MediaLoFiDTO {
media_lofi := MediaLoFiDTO{}
return media_lofi
}
type MediaLoFiDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
FileName string `json:"file_name"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func (dto MediaLoFiDTO) ConvertDTOToModel() MediaLoFi {
model := MediaLoFi{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
FileName: dto.FileName,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func (source MediaLoFiDTO) Equals(target MediaLoFiDTO) bool {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals", "id", source.ID)
}
equals := true
if source.Title != target.Title {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Title changed")
}
equals = false
}
if source.WebLink != target.WebLink {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: WebLink changed")
}
equals = false
}
if source.Version != target.Version {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Version changed")
}
equals = false
}
if source.FileName != target.FileName {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: FileName changed")
}
equals = false
}
if source.Review != target.Review {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Review changed")
}
equals = false
}
if source.ShouldDownload != target.ShouldDownload {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: ShouldDownload changed")
}
equals = false
}
return equals
}
type MediaLoFiDTOList []MediaLoFiDTO
func (source MediaLoFiDTOList) GetMediaLofi(lofi_id string) *MediaLoFiDTO {
for _, lofi := range source {
if lofi.ID == lofi_id {
return &lofi
}
}
return nil
}
func (source *MediaLoFiDTOList) CompareIds(target *MediaLoFiDTOList) (missing, obsolete, changed []string) {
sources := make(map[string]MediaLoFiDTO, len(*source))
targets := make(map[string]MediaLoFiDTO, len(*target))
for _, source := range *source {
sources[source.ID] = source
}
for _, target := range *target {
targets[target.ID] = target
}
// iterate source IDs
for id := range sources {
if _, ok := targets[id]; ok {
if config.Verbose > 1 {
slog.Info(fmt.Sprintf("ID %s found in both lists", id))
}
if !sources[id].Equals(targets[id]) {
changed = append(changed, id)
}
} else {
missing = append(missing, id)
}
}
for id := range targets {
if _, ok := sources[id]; ok {
slog.Debug(fmt.Sprintf("ID %s found in both lists", id))
} else {
obsolete = append(obsolete, id)
}
}
slog.Info("CompareIds", "missing", len(missing), "obsolete", len(obsolete), "changed", len(changed))
slog.Debug("CompareIds", "missing", missing, "obsolete", obsolete)
return missing, obsolete, changed
}
func ConvertMediaLoFisToDtos(media_lofis []MediaLoFi) MediaLoFiDTOList {
dtos := make(MediaLoFiDTOList, len(media_lofis))
for i, media_lofi := range media_lofis {
dtos[i] = media_lofi.ConvertMediaLoFiToDTO()
}
return dtos
}
+193
View File
@@ -0,0 +1,193 @@
package models
import (
"fmt"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/helpers"
"log/slog"
"time"
"github.com/uptrace/bun"
)
type MediaMusic struct {
bun.BaseModel `bun:"table:media_music"`
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
WebLink string `bun:"url,unique:url"`
Review bool `bun:"review"`
ShouldDownload bool `bun:"should_download"`
Title string `bun:"title"`
FileName string `bun:"file_name"`
}
func (media_music *MediaMusic) Update(update MediaMusicDTO) {
media_music.CreatedAt = update.CreatedAt.Time
media_music.UpdatedAt = time.Now()
media_music.Version = media_music.Version + 1
media_music.WebLink = update.WebLink
media_music.Review = update.Review
media_music.ShouldDownload = update.ShouldDownload
media_music.Title = update.Title
media_music.FileName = update.FileName
}
func (media_music *MediaMusic) ConvertMediaMusicToDTO() MediaMusicDTO {
dto := MediaMusicDTO{
ID: media_music.ID,
CreatedAt: helpers.KontorTime{Time: media_music.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_music.UpdatedAt},
DeletedAt: media_music.DeletedAt,
Version: media_music.Version,
WebLink: media_music.WebLink,
Review: media_music.Review,
ShouldDownload: media_music.ShouldDownload,
Title: media_music.Title,
FileName: media_music.FileName,
}
return dto
}
type MediaMusicAdd struct {
Url string `json:"url"`
}
type MediaMusicForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaMusicForm) ConvertFormToMediaMusicDTO() MediaMusicDTO {
media_music := MediaMusicDTO{}
return media_music
}
type MediaMusicDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
FileName string `json:"file_name"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func (dto MediaMusicDTO) ConvertDTOToModel() MediaMusic {
model := MediaMusic{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
FileName: dto.FileName,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func (source MediaMusicDTO) Equals(target MediaMusicDTO) bool {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals", "id", source.ID)
}
equals := true
if source.Title != target.Title {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Title changed")
}
equals = false
}
if source.WebLink != target.WebLink {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: WebLink changed")
}
equals = false
}
if source.Version != target.Version {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Version changed")
}
equals = false
}
if source.FileName != target.FileName {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: FileName changed")
}
equals = false
}
if source.Review != target.Review {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Review changed")
}
equals = false
}
if source.ShouldDownload != target.ShouldDownload {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: ShouldDownload changed")
}
equals = false
}
return equals
}
type MediaMusicDTOList []MediaMusicDTO
func (source MediaMusicDTOList) GetMediaMusic(music_id string) *MediaMusicDTO {
for _, music := range source {
if music.ID == music_id {
return &music
}
}
return nil
}
func (source *MediaMusicDTOList) CompareIds(target *MediaMusicDTOList) (missing, obsolete, changed []string) {
sources := make(map[string]MediaMusicDTO, len(*source))
targets := make(map[string]MediaMusicDTO, len(*target))
for _, source := range *source {
sources[source.ID] = source
}
for _, target := range *target {
targets[target.ID] = target
}
// iterate source IDs
for id := range sources {
if _, ok := targets[id]; ok {
if config.Verbose > 1 {
slog.Info(fmt.Sprintf("ID %s found in both lists", id))
}
if !sources[id].Equals(targets[id]) {
changed = append(changed, id)
}
} else {
missing = append(missing, id)
}
}
for id := range targets {
if _, ok := sources[id]; ok {
slog.Debug(fmt.Sprintf("ID %s found in both lists", id))
} else {
obsolete = append(obsolete, id)
}
}
slog.Info("CompareIds", "missing", len(missing), "obsolete", len(obsolete), "changed", len(changed))
slog.Debug("CompareIds", "missing", missing, "obsolete", obsolete)
return missing, obsolete, changed
}
func ConvertMediaMusicsToDtos(media_musics []MediaMusic) MediaMusicDTOList {
dtos := make(MediaMusicDTOList, len(media_musics))
for i, media_music := range media_musics {
dtos[i] = media_music.ConvertMediaMusicToDTO()
}
return dtos
}
@@ -0,0 +1,98 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaVideo struct {
bun.BaseModel `bun:"table:media_video"`
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
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"`
}
func (media_music *MediaVideo) Update(update MediaVideoDTO) {
media_music.CreatedAt = update.CreatedAt.Time
media_music.UpdatedAt = time.Now()
media_music.Version = media_music.Version + 1
media_music.WebLink = update.WebLink
media_music.Review = update.Review
media_music.ShouldDownload = update.ShouldDownload
media_music.Title = update.Title
media_music.FileName = update.FileName
}
type MediaVideoForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaVideoForm) ConvertFormToMediaVideoDTO() MediaVideoDTO {
media_video := MediaVideoDTO{}
return media_video
}
type MediaVideoDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
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 (dto MediaVideoDTO) ConvertDTOToModel() MediaVideo {
model := MediaVideo{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Review: dto.Review,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
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: helpers.KontorTime{Time: media_video.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: 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
}
type MediaVideoDTOList []MediaVideoDTO
+58
View File
@@ -0,0 +1,58 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
Assignments []Assignment `bun:"rel:has-many,join:id=permission_id"`
}
type PermissionDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date" binding:"required"`
UpdatedAt helpers.KontorTime `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"required"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
}
func (permission *PermissionDTO) ConvertDTOToModel() Permission {
model := Permission{
ID: permission.ID,
CreatedAt: permission.CreatedAt.Time,
UpdatedAt: permission.UpdatedAt.Time,
DeletedAt: permission.DeletedAt,
Version: permission.Version,
Name: permission.Name,
}
return model
}
func ConvertPermissionsToDtos(permissions []Permission) []PermissionDTO {
dtos := make([]PermissionDTO, len(permissions))
for i, permission := range permissions {
dtos[i] = PermissionDTO{
ID: permission.ID,
CreatedAt: helpers.KontorTime{Time: permission.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: permission.UpdatedAt},
DeletedAt: permission.DeletedAt,
Version: permission.Version,
Name: permission.Name,
}
}
return dtos
}
type PermissionDTOList []PermissionDTO
+96
View File
@@ -0,0 +1,96 @@
package models
import (
"kontor-api-echo/internal/helpers"
"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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
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"`
}
func (profile *Profile) GetFullName() string {
full_name := ""
if profile.FirstName != "" {
full_name += profile.FirstName
}
if profile.LastName != "" {
full_name += " "
full_name += profile.LastName
}
return full_name
}
type ProfileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date" binding:"required"`
UpdatedAt helpers.KontorTime `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version" binding:"required"`
FirstName string `json:"first_name" binding:"required"`
LastName string `json:"last_name" binding:"required"`
UserName string `json:"user_name" binding:"required"`
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
Enabled bool `json:"enabled" binding:"required"`
}
func (profile *ProfileDTO) ConvertDTOToModel() Profile {
model := Profile{
ID: profile.ID,
CreatedAt: profile.CreatedAt.Time,
UpdatedAt: profile.UpdatedAt.Time,
DeletedAt: profile.DeletedAt,
Version: profile.Version,
FirstName: profile.FirstName,
LastName: profile.LastName,
UserName: profile.UserName,
Email: profile.Email,
Password: profile.Password,
Enabled: profile.Enabled,
}
return model
}
func ConvertProfilesToDtos(profiles []Profile) []ProfileDTO {
dtos := make([]ProfileDTO, len(profiles))
for i, profile := range profiles {
dtos[i] = ProfileDTO{
ID: profile.ID,
CreatedAt: helpers.KontorTime{Time: profile.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: profile.UpdatedAt},
DeletedAt: profile.DeletedAt,
Version: profile.Version,
FirstName: profile.FirstName,
LastName: profile.LastName,
UserName: profile.UserName,
Email: profile.Email,
Password: profile.Password,
Enabled: profile.Enabled,
}
}
return dtos
}
type LoginInput struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
type ProfileDTOList []ProfileDTO
+70
View File
@@ -0,0 +1,70 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
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"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Token string `bun:"token,unique:token"`
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 TokenDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
Token string `json:"token"`
Name string `json:"name"`
LastUsedAt *time.Time `json:"last_used_date"`
Enabled bool `json:"enabled"`
ProfileID *string `json:"profile_id"`
}
func (dto TokenDTO) ConvertDTOToModel() Token {
model := Token{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Token: dto.Token,
Name: dto.Name,
LastUsedAt: *dto.LastUsedAt,
Enabled: dto.Enabled,
ProfileID: dto.ProfileID,
}
return model
}
func ConvertTokensToDtos(tokens []Token) []TokenDTO {
dtos := make([]TokenDTO, len(tokens))
for i, token := range tokens {
dtos[i] = TokenDTO{
ID: token.ID,
CreatedAt: helpers.KontorTime{Time: token.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: token.UpdatedAt},
DeletedAt: token.DeletedAt,
Version: token.Version,
ProfileID: token.ProfileID,
}
}
return dtos
}
type TokenDTOList []TokenDTO
@@ -0,0 +1,60 @@
package repository
import (
"context"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type AssignmentRepository struct {
db *bun.DB
}
func NewAssignmentRepository(db *bun.DB) *AssignmentRepository {
repository := &AssignmentRepository{db: db}
return repository
}
func (repository *AssignmentRepository) FindAll(context context.Context) ([]models.Assignment, error) {
var assignments []models.Assignment
result := repository.db.Find(&assignments)
slog.Info("AssignmentRepository#FindAll", "count", result.RowsAffected)
return assignments, nil
}
func (repository *AssignmentRepository) GetById(context context.Context, id string) (models.Assignment, error) {
var assignment = models.Assignment{ID: id}
slog.Info("AssignmentRepository#GetById", "id", id)
result := repository.db.First(&assignment)
if result.Error != nil {
slog.Info("AssignmentRepository#GetById", "error", result.Error.Error())
}
return assignment, result.Error
}
func (repository *AssignmentRepository) Import(assignments models.AssignmentDTOList) {
slog.Info("AssignmentRepository#Import")
for index, assignment := range assignments {
slog.Info("importing", "index", index, "profile", assignment)
model := assignment.ConvertDTOToModel()
existing_item := models.Assignment{ID: assignment.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
@@ -0,0 +1,75 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaActorRepository struct {
db *bun.DB
}
func (repository *MediaActorRepository) Import(dtos models.MediaActorDTOList) {
slog.Info("MediaActorRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaActor{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaActorRepository(db *bun.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
}
func (repository *MediaActorRepository) GetById(context context.Context, id string) (*models.MediaActor, error) {
var actor = models.MediaActor{ID: id}
slog.Info("MediaActorRepository#GetById", "id", id)
result := repository.db.First(&actor)
if result.Error != nil {
slog.Info("SportRepository#GetById", "error", result.Error.Error())
}
return &actor, result.Error
}
func (repository *MediaActorRepository) Add(context context.Context, url string) (*models.MediaActor, error) {
slog.Info("MediaActorRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaFileRepository#Add")
}
func (repository *MediaActorRepository) Delete(context context.Context, id string) error {
slog.Info("MediaActorRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaActor)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,76 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaActorFileRepository struct {
db *bun.DB
}
func (repository *MediaActorFileRepository) Import(dtos models.MediaActorFileDTOList) {
slog.Info("MediaActorFileRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaActorFile{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaActorFileRepository(db *bun.DB) *MediaActorFileRepository {
repo := &MediaActorFileRepository{db: db}
return repo
}
func (repository *MediaActorFileRepository) FindAll(context context.Context) ([]models.MediaActorFile, error) {
var actor_files []models.MediaActorFile
result := repository.db.Find(&actor_files)
slog.Info("MediaActorFileRepository#FindAll", "count", result.RowsAffected)
return actor_files, nil
}
func (repository *MediaActorFileRepository) GetById(context context.Context, id string) (*models.MediaActorFile, error) {
var actorfile = models.MediaActorFile{ID: id}
slog.Info("MediaActorFileRepository#GetById", "id", id)
result := repository.db.First(&actorfile)
if result.Error != nil {
slog.Info("MediaActorFileRepository#GetById", "error", result.Error.Error())
return nil, result.Error
}
return &actorfile, result.Error
}
func (repository *MediaActorFileRepository) Add(context context.Context, media_actor_id, media_file_id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileRepository#Add", "actor_id", media_actor_id, "file_id", media_file_id)
return nil, fmt.Errorf("unimplemented method MediaActorFileRepository#Add")
}
func (repository *MediaActorFileRepository) Delete(context context.Context, id string) error {
slog.Info("MediaActorFileRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaActorFile)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,85 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/labstack/echo/v4"
"github.com/uptrace/bun"
)
type MediaArticleRepository struct {
db *bun.DB
}
func (repository *MediaArticleRepository) Import(dtos models.MediaArticleDTOList) {
slog.Info("MediaArticleRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "profile", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaArticle{ID: dto.ID}
err := repository.db.NewSelect().Model(&existing_item).Where("id = ?", dto.ID).Scan(context.Background())
if err != nil {
slog.Info("check existing id: not found - inserting")
_, err := repository.db.NewInsert().Model(&model).Exec(context.Background())
if err != nil {
slog.Info("error during import", "error", err.Error())
}
} else {
slog.Info("check existing id: found - updating")
_, err := repository.db.NewUpdate().Model(&model).
Set("updated_at = ? ", time.Now).
Where("id = ?", model.ID).
Exec(context.Background())
if err != nil {
slog.Info("error during updating", "error", err.Error())
}
}
}
}
func NewMediaArticleRepository(db *bun.DB) *MediaArticleRepository {
repo := &MediaArticleRepository{db: db}
return repo
}
func (repository *MediaArticleRepository) FindAll(context context.Context) ([]models.MediaArticle, error) {
var articles []models.MediaArticle
err := repository.db.NewSelect().Model(&articles).Scan(context)
if err != nil {
slog.Info(err.Error())
return nil, echo.ErrInternalServerError
}
slog.Info("MediaArticleRepository#FindAll", "count", len(articles))
return articles, nil
}
func (repository *MediaArticleRepository) GetById(context context.Context, id string) (*models.MediaArticle, error) {
var article = models.MediaArticle{ID: id}
slog.Info("MediaArticleRepository#GetById", "id", id)
err := repository.db.NewSelect().Model(&article).Where("id = ?", id).Scan(context)
if err != nil {
slog.Info("MediaArticleRepository#GetById", "error", err.Error())
return nil, err
}
return &article, err
}
func (repository *MediaArticleRepository) Add(context context.Context, url string) (*models.MediaArticle, error) {
slog.Info("MediaArticleRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaArticleRepository#Add")
}
func (repository *MediaArticleRepository) Delete(context context.Context, id string) error {
slog.Info("MediaArticleRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaArticle)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,76 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaFileRepository struct {
db *bun.DB
}
func (repository *MediaFileRepository) Import(dtos models.MediaFileDTOList) {
slog.Info("MediaFileRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaFile{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaFileRepository(db *bun.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
}
func (repository *MediaFileRepository) GetById(context context.Context, id string) (*models.MediaFile, error) {
var file = models.MediaFile{ID: id}
slog.Info("MediaFileRepository#GetById", "id", id)
result := repository.db.First(&file)
if result.Error != nil {
slog.Info("MediaFileRepository#GetById", "error", result.Error.Error())
return nil, result.Error
}
return &file, result.Error
}
func (repository *MediaFileRepository) Add(context context.Context, url string) (*models.MediaFile, error) {
slog.Info("MediaFileRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaFileRepository#Add")
}
func (repository *MediaFileRepository) Delete(context context.Context, id string) error {
slog.Info("MediaFileRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaFile)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaFileRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,132 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/uptrace/bun"
)
type MediaLoFiRepository struct {
db *bun.DB
}
func (repository *MediaLoFiRepository) Import(dtos models.MediaLoFiDTOList) {
slog.Info("MediaLoFiRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaLoFi{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaLoFiRepository(db *bun.DB) *MediaLoFiRepository {
repo := &MediaLoFiRepository{db: db}
return repo
}
func (repository *MediaLoFiRepository) FindAll(context context.Context) ([]models.MediaLoFi, error) {
var lofis []models.MediaLoFi
err := repository.db.NewSelect().Model(&lofis).Scan(context)
if err != nil {
slog.Info(err.Error())
return nil, echo.ErrInternalServerError
}
slog.Info("MediaLoFiRepository#FindAll", "count", len(lofis))
return lofis, nil
}
func (repository *MediaLoFiRepository) GetById(context context.Context, id string) (*models.MediaLoFi, error) {
var lofi = models.MediaLoFi{ID: id}
slog.Info("MediaLoFiRepository#GetById", "id", id)
err := repository.db.NewSelect().Model(&lofi).Where("id = ?", id).Scan(context)
if err != nil {
slog.Info("MediaLoFiRepository#GetById", "error", err.Error())
return nil, err
}
return &lofi, err
}
func (repository *MediaLoFiRepository) Add(context context.Context, url string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var lofi models.MediaLoFi
search_result := repository.db.Where("url = ?", webLink).First(&lofi)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "lofi", lofi)
return &lofi, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaLoFiRepository#Add URL not found", "url", webLink)
lofi = models.MediaLoFi{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&lofi)
if add_result.Error != nil {
slog.Info("add new MediaLofi", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaLofi", "lofi", lofi)
return &lofi, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaLoFiRepository#Add unknown error")
}
func (repository *MediaLoFiRepository) Update(context context.Context, update models.MediaLoFiDTO) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiRepository#Update", "lofi", update)
var lofi = models.MediaLoFi{ID: update.ID}
slog.Info("MediaLoFiRepository#Update", "id", update.ID)
result := repository.db.First(&lofi)
if result.Error != nil {
slog.Info("MediaLoFiRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
lofi.Update(update)
repository.db.Save(&lofi)
return &lofi, nil
}
func (repository *MediaLoFiRepository) Delete(context context.Context, id string) error {
slog.Info("MediaLoFiRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaLoFi)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaLoFiRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,126 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
type MediaMusicRepository struct {
db *bun.DB
}
func (repository *MediaMusicRepository) Import(dtos models.MediaMusicDTOList) {
slog.Info("MediaMusicRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaMusic{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaMusicRepository(db *bun.DB) *MediaMusicRepository {
repo := &MediaMusicRepository{db: db}
return repo
}
func (repository *MediaMusicRepository) FindAll(context context.Context) ([]models.MediaMusic, error) {
var musics []models.MediaMusic
result := repository.db.Find(&musics)
slog.Info("MediaMusicRepository#FindAll", "count", result.RowsAffected)
return musics, nil
}
func (repository *MediaMusicRepository) GetById(context context.Context, id string) (*models.MediaMusic, error) {
var music = models.MediaMusic{ID: id}
slog.Info("MediaMusicRepository#GetById", "id", id)
result := repository.db.First(&music)
if result.Error != nil {
slog.Info("MediaMusicRepository#GetById", "error", result.Error.Error())
}
return &music, result.Error
}
func (repository *MediaMusicRepository) Add(context context.Context, url string) (*models.MediaMusic, error) {
slog.Info("MediaMusicRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var music models.MediaMusic
search_result := repository.db.Where("url = ?", webLink).First(&music)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "music", music)
return &music, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaMusicRepository#Add URL not found", "url", webLink)
music = models.MediaMusic{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&music)
if add_result.Error != nil {
slog.Info("add new MediaMusic", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaMusic", "music", music)
return &music, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaMusicRepository#Add unknown error")
}
func (repository *MediaMusicRepository) Update(context context.Context, update models.MediaMusicDTO) (*models.MediaMusic, error) {
slog.Info("MediaMusicRepository#Update", "music", update)
var music = models.MediaMusic{ID: update.ID}
slog.Info("MediaMusicRepository#Update", "id", update.ID)
result := repository.db.First(&music)
if result.Error != nil {
slog.Info("MediaMusicRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
music.Update(update)
repository.db.Save(&music)
return &music, nil
}
func (repository *MediaMusicRepository) Delete(context context.Context, id string) error {
slog.Info("MediaMusicRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaMusic)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaMusicRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,127 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
type MediaVideoRepository struct {
db *bun.DB
}
func (repository *MediaVideoRepository) Import(dtos models.MediaVideoDTOList) {
slog.Info("MediaVideoRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaVideo{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaVideoRepository(db *bun.DB) *MediaVideoRepository {
repo := &MediaVideoRepository{db: db}
return repo
}
func (repository *MediaVideoRepository) FindAll(context context.Context) ([]models.MediaVideo, error) {
var videos []models.MediaVideo
result := repository.db.Find(&videos)
slog.Info("MediaVideoRepository#FindAll", "count", result.RowsAffected)
return videos, nil
}
func (repository *MediaVideoRepository) GetById(context context.Context, id string) (*models.MediaVideo, error) {
var video = models.MediaVideo{ID: id}
slog.Info("MediaVideoRepository#GetById", "id", id)
result := repository.db.First(&video)
if result.Error != nil {
slog.Info("MediaVideoRepository#GetById", "error", result.Error.Error())
}
return &video, result.Error
}
func (repository *MediaVideoRepository) Add(context context.Context, url string) (*models.MediaVideo, error) {
slog.Info("MediaVideoRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var video models.MediaVideo
search_result := repository.db.Where("url = ?", webLink).First(&video)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "video", video)
return &video, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaVideoRepository#Add URL not found", "url", webLink)
video = models.MediaVideo{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&video)
if add_result.Error != nil {
slog.Info("add new MediaVideo", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaVideo", "music", video)
return &video, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaVideoRepository#Add unknown error")
}
func (repository *MediaVideoRepository) Update(context context.Context, update models.MediaVideoDTO) (*models.MediaVideo, error) {
slog.Info("MediaVideoRepository#Update", "music", update)
var video = models.MediaVideo{ID: update.ID}
slog.Info("MediaVideoRepository#Update", "id", update.ID)
result := repository.db.First(&video)
if result.Error != nil {
slog.Info("MediaVideoRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
video.Update(update)
repository.db.Save(&video)
return &video, nil
}
func (repository *MediaVideoRepository) Delete(context context.Context, id string) error {
var actor = models.MediaVideo{ID: id}
slog.Info("MediaVideoRepository#Delete", "id", id)
result := repository.db.Delete(&actor)
if result.Error != nil {
slog.Info("MediaVideoRepository#Delete", "error", result.Error.Error())
}
return result.Error
}
@@ -0,0 +1,51 @@
package repository
import (
"context"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type PermissionRepository struct {
db *bun.DB
}
func NewPermissionRepository(db *bun.DB) *PermissionRepository {
repository := &PermissionRepository{db: db}
return repository
}
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 (repository *PermissionRepository) Import(permissions models.PermissionDTOList) {
slog.Info("PermissionRepository#Import")
for index, permission := range permissions {
slog.Info("importing", "index", index, "profile", permission)
model := permission.ConvertDTOToModel()
existing_item := models.Permission{ID: permission.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
@@ -0,0 +1,61 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type ProfileRepository struct {
db *gorm.DB
}
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
}
func (repository *ProfileRepository) Import(profiles models.ProfileDTOList) {
slog.Info("ProfileRepository#Import")
for index, profile := range profiles {
slog.Info("importing", "index", index, "profile", profile)
model := profile.ConvertDTOToModel()
existing_profile := models.Profile{ID: profile.ID}
result_existing := repository.db.First(&existing_profile)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
+34
View File
@@ -0,0 +1,34 @@
package router
import (
"kontor-api-echo/internal/handlers"
"log/slog"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
)
func New(admin *handlers.AdminHandler, media *handlers.MediaHandler) *echo.Echo {
e := echo.New()
skipper := func(c *echo.Context) bool {
// Skip health check endpoint
return c.Request().URL.Path == "/health"
}
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
HandleError: true,
Skipper: skipper,
LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error {
if v.Error == nil {
slog.Info("REQUEST", "uri", v.URI, "status", v.Status)
} else {
slog.Info("REQUEST-ERROR", "uri", v.URI, "status", v.Status, "err", v.Error.Error())
}
return nil
},
}))
return e
}
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type AssignmentService struct {
repository *repository.AssignmentRepository
}
func NewAssignmentService(repo *repository.AssignmentRepository) *AssignmentService {
service := &AssignmentService{repository: repo}
return service
}
func (service *AssignmentService) List(context context.Context) ([]models.Assignment, error) {
slog.Info("AssignmentService#List")
return service.repository.FindAll(context)
}
func (service *AssignmentService) Get(context context.Context, id string) (models.Assignment, error) {
slog.Info("AssignmentService#Get")
return service.repository.GetById(context, id)
}
@@ -0,0 +1,37 @@
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)
}
func (service *MediaActorService) Get(context context.Context, id string) (*models.MediaActor, error) {
slog.Info("MediaActorService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaActorService) Add(context context.Context, url string) (*models.MediaActor, error) {
slog.Info("MediaActorService#Add")
return service.repository.Add(context, url)
}
func (service *MediaActorService) Delete(context context.Context, id string) error {
slog.Info("MediaActorService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaActorFileService struct {
repository *repository.MediaActorFileRepository
}
func NewMediaActorFileService(repo *repository.MediaActorFileRepository) *MediaActorFileService {
service := &MediaActorFileService{repository: repo}
return service
}
func (service *MediaActorFileService) List(context context.Context) ([]models.MediaActorFile, error) {
slog.Info("MediaActorFileService#List")
return service.repository.FindAll(context)
}
func (service *MediaActorFileService) Get(context context.Context, id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaActorFileService) Add(context context.Context, media_actor_id, media_file_id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileService#Add")
return service.repository.Add(context, media_actor_id, media_file_id)
}
func (service *MediaActorFileService) Delete(context context.Context, id string) error {
slog.Info("MediaActorFileService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"log/slog"
)
type MediaArticleService struct {
repository *repository.MediaArticleRepository
}
func NewMediaArticleService(repo *repository.MediaArticleRepository) *MediaArticleService {
service := &MediaArticleService{repository: repo}
return service
}
func (service *MediaArticleService) List(context context.Context) ([]models.MediaArticle, error) {
slog.Info("MediaArticleService#List")
return service.repository.FindAll(context)
}
func (service *MediaArticleService) Get(context context.Context, id string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaArticleService) Add(context context.Context, url string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Add")
return service.repository.Add(context, url)
}
func (service *MediaArticleService) Delete(context context.Context, id string) error {
slog.Info("MediaArticleService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
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)
}
func (service *MediaFileService) Get(context context.Context, id string) (*models.MediaFile, error) {
slog.Info("MediaFileService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaFileService) Add(context context.Context, url string) (*models.MediaFile, error) {
slog.Info("MediaFileService#Add")
return service.repository.Add(context, url)
}
func (service *MediaFileService) Delete(context context.Context, id string) error {
slog.Info("MediaFileService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
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)
}
func (service *MediaLoFiService) Get(context context.Context, id string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaLoFiService) Add(context context.Context, url string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Add")
return service.repository.Add(context, url)
}
func (service *MediaLoFiService) Update(context context.Context, lofi models.MediaLoFiDTO) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Update")
return service.repository.Update(context, lofi)
}
func (service *MediaLoFiService) Delete(context context.Context, id string) error {
slog.Info("MediaLoFiService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaMusicService struct {
repository *repository.MediaMusicRepository
}
func NewMediaMusicService(repo *repository.MediaMusicRepository) *MediaMusicService {
service := &MediaMusicService{repository: repo}
return service
}
func (service *MediaMusicService) List(context context.Context) ([]models.MediaMusic, error) {
slog.Info("MediaMusicService#List")
return service.repository.FindAll(context)
}
func (service *MediaMusicService) Get(context context.Context, id string) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaMusicService) Add(context context.Context, url string) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Add")
return service.repository.Add(context, url)
}
func (service *MediaMusicService) Update(context context.Context, music models.MediaMusicDTO) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Update")
return service.repository.Update(context, music)
}
func (service *MediaMusicService) Delete(context context.Context, id string) error {
slog.Info("MediaMusicService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaVideoService struct {
repository *repository.MediaVideoRepository
}
func NewMediaVideoService(repo *repository.MediaVideoRepository) *MediaVideoService {
service := &MediaVideoService{repository: repo}
return service
}
func (service *MediaVideoService) List(context context.Context) ([]models.MediaVideo, error) {
slog.Info("MediaVideoService#List")
return service.repository.FindAll(context)
}
func (service *MediaVideoService) Get(context context.Context, id string) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaVideoService) Add(context context.Context, url string) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Add")
return service.repository.Add(context, url)
}
func (service *MediaVideoService) Update(context context.Context, music models.MediaVideoDTO) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Update")
return service.repository.Update(context, music)
}
func (service *MediaVideoService) Delete(context context.Context, id string) error {
slog.Info("MediaVideoService#Delete")
return service.repository.Delete(context, id)
}
@@ -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)
}
+22
View File
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type ProfileService struct {
repository *repository.ProfileRepository
}
func NewProfileService(repo *repository.ProfileRepository) *ProfileService {
service := &ProfileService{repository: repo}
return service
}
func (service *ProfileService) List(context context.Context) ([]models.Profile, error) {
slog.Info("ProfileService#List")
return service.repository.FindAll(context)
}
-62
View File
@@ -1,62 +0,0 @@
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"`
}
-79
View File
@@ -1,79 +0,0 @@
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"`
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"`
}
-3
View File
@@ -22,11 +22,8 @@ builds:
goos:
- linux
- windows
- darwin
goarch:
- arm64
- amd64
- "386"
archives:
- formats: [tar.gz]
+1 -2
View File
@@ -15,7 +15,6 @@ import (
"time"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
)
func main() {
@@ -40,7 +39,7 @@ func main() {
}
r := router.New(
handlers.NewAdminHandler(db, []byte(viper.GetString("api_secret"))),
handlers.NewAdminHandler(db, config.ServerConfig.ApiSecret),
handlers.NewBookshelfHandler(db),
handlers.NewComicsHandler(db),
handlers.NewMediaHandler(db),
+3 -1
View File
@@ -11,6 +11,7 @@ import (
)
var (
ApiSecret []byte
CfgFile string
Verbose int
Overwrite bool
@@ -79,7 +80,8 @@ type CliConfig struct {
}
type ServerConfiguration struct {
Server struct {
ApiSecret []byte `mapstructure:"api_secret" validate:"required"`
Server struct {
Port int `mapstructure:"port" validate:"required"`
Host string `mapstructure:"host"`
} `mapstructure:"server"`
+2
View File
@@ -5,6 +5,7 @@ import (
)
type MediaHandler struct {
MediaArticleHandler *MediaArticleHandler
MediaActorHandler *MediaActorHandler
MediaFileHandler *MediaFileHandler
MediaLoFiHandler *MediaLoFiHandler
@@ -15,6 +16,7 @@ type MediaHandler struct {
func NewMediaHandler(db *gorm.DB) *MediaHandler {
mediaHandler := &MediaHandler{
MediaArticleHandler: NewMediaArticleHandler(db),
MediaActorHandler: NewMediaActorHandler(db),
MediaFileHandler: NewMediaFileHandler(db),
MediaLoFiHandler: NewMediaLoFiHandler(db),
+3 -3
View File
@@ -79,7 +79,7 @@ func (handler *MediaActorHandler) ListPage(c *gin.Context) {
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actors"] = actors
c.HTML(http.StatusOK, "mediaactors", data)
c.HTML(http.StatusOK, "media_actors", data)
}
func (handler *MediaActorHandler) EditPage(c *gin.Context) {
@@ -120,7 +120,7 @@ func (handler *MediaActorHandler) UpdatePage(c *gin.Context) {
}
logger.Info("MediaActorHandler#UpdatePage", "actor", actor)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, "web/actors")
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
func (handler *MediaActorHandler) DeletePage(c *gin.Context) {
@@ -135,5 +135,5 @@ func (handler *MediaActorHandler) DeletePage(c *gin.Context) {
// return
// }
logger.Info("MediaActorHandler#DeletePage", "actor", id)
c.Redirect(http.StatusFound, "web/actors")
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
@@ -0,0 +1,134 @@
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 MediaArticleHandler struct {
Service *service.MediaArticleService
}
func NewMediaArticleHandler(db *gorm.DB) *MediaArticleHandler {
mediaFileHandler := &MediaArticleHandler{
Service: service.NewMediaArticleService(repository.NewMediaArticleRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaArticleHandler) List(c *gin.Context) {
logger := slog.Get(c)
logger.Info("MediaArticleHandler#List")
articles, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaArticlesToDtos(articles)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaArticleHandler) Add(c *gin.Context) {
var input models.MediaFileAdd
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request.Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaArticleHandler) Delete(c *gin.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, gin.H{"ok": "true"})
}
func (handler *MediaArticleHandler) 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
}
data := globals.GetDefaultValues(user, "MediaArticles...")
data["title"] = "Kontor MediaArticles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaArticleLink
c.HTML(http.StatusOK, "media_links", data)
}
func (handler *MediaArticleHandler) EditPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_file, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["lofi"] = media_file
c.HTML(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaArticleHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_article, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaArticleForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.HTML(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaArticleHandler#UpdatePage", "media_article", media_article)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
func (handler *MediaArticleHandler) DeletePage(c *gin.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
@@ -34,6 +34,16 @@ func (media_article *MediaArticle) TableName() string {
return "media_article"
}
type MediaArticleForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaArticleForm) ConvertFormToMediaArticleDTO() MediaArticleDTO {
dto := MediaArticleDTO{}
return dto
}
type MediaArticleDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
+4 -1
View File
@@ -21,6 +21,9 @@ import (
func New(admin *handlers.AdminHandler, bookshelf *handlers.BookshelfHandler, comics *handlers.ComicsHandler, media *handlers.MediaHandler, tysc *handlers.TyscHandler) *gin.Engine {
router := gin.New()
router.Use(gin.Recovery())
// router.Use(gin.LoggerWithConfig(gin.LoggerConfig{
// SkipPaths: []string{"/health", "/public/style/main.css"},
// }))
router.Use(gin_slog.SetLogger(
gin_slog.WithSkipPath([]string{"/health", "/public/style/main.css"}),
gin_slog.WithDefaultLevel(slog.LevelInfo),
@@ -60,7 +63,7 @@ func New(admin *handlers.AdminHandler, bookshelf *handlers.BookshelfHandler, com
m.GET("/actors", media.MediaActorHandler.ListPage)
m.GET("/actors/:id", media.MediaActorHandler.EditPage)
m.POST("/actors/:id", media.MediaActorHandler.UpdatePage)
m.GET("/articles", media.MediaFileHandler.ListPage)
m.GET("/articles", media.MediaArticleHandler.ListPage)
m.GET("/files", media.MediaFileHandler.ListPage)
m.GET("/files/edit/:id", media.MediaFileHandler.EditPage)
m.POST("/files/edit/:id", media.MediaFileHandler.UpdatePage)
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaArticleService struct {
repository *repository.MediaArticleRepository
}
func NewMediaArticleService(repo *repository.MediaArticleRepository) *MediaArticleService {
service := &MediaArticleService{repository: repo}
return service
}
func (service *MediaArticleService) List(context context.Context) ([]models.MediaArticle, error) {
slog.Info("MediaArticleService#List")
return service.repository.FindAll(context)
}
func (service *MediaArticleService) Get(context context.Context, id string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaArticleService) Add(context context.Context, url string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Add")
return service.repository.Add(context, url)
}
func (service *MediaArticleService) Delete(context context.Context, id string) error {
slog.Info("MediaArticleService#Delete")
return service.repository.Delete(context, id)
}
@@ -1,4 +1,4 @@
{{ define "mediaactors" }}
{{ define "media_actors" }}
<!doctype html>
<html lang="de">
{{ template "head" . }}
@@ -19,10 +19,10 @@
</div>
</div>
<div class="row">
<form class="form-inline" action="/web/actors">
<form class="form-inline" action="{{ .MediaLinksUrl }}">
<input type="text" placeholder="Search" name="query">
<button type="submit">Search</button>
<div class="pill-nav"><a href="/web/actors/add">Add Lofi</a></div>
<div class="pill-nav"><a href="{{ .MediaLinksUrl }}/edit">Add Lofi</a></div>
</form>
</div>
<div class="row">
@@ -30,7 +30,7 @@
<div class="card shadow p-3 mb-2 bg-body rounded" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">{{.Name}}</h5>
<a href="/web/actors/{{.ID}}" class="btn btn-primary">Read more</a>
<a href="{{ $.media_actor_link }}/{{.ID}}" class="btn btn-primary">Read more</a>
</div>
</div>
{{ end }}