From debdf3d0b0c40197d935d50c0c2a6f378f9e3919 Mon Sep 17 00:00:00 2001 From: Thomas Peetz Date: Mon, 9 Nov 2026 17:02:59 +0100 Subject: [PATCH] kontor-echo: setup project to show homepage --- kontor-echo/Containerfile | 8 +- kontor-echo/assets/assets.go | 8 + kontor-echo/assets/icons/cross.png | Bin 0 -> 544 bytes kontor-echo/assets/icons/logo.png | Bin 0 -> 17196 bytes kontor-echo/assets/icons/tick.png | Bin 0 -> 634 bytes kontor-echo/assets/style/main.css | 174 ++++++++++++++++++ kontor-echo/cmd/kontor-echo/main.go | 3 +- kontor-echo/cmd/kontor/main.go | 2 - kontor-echo/go.mod | 11 +- kontor-echo/go.sum | 52 ++++-- kontor-echo/internal/config/config.go | 4 +- kontor-echo/internal/handlers/auth.go | 114 ++++++++++++ kontor-echo/internal/handlers/kontor.go | 33 ++++ kontor-echo/internal/handlers/mail.go | 30 +++ kontor-echo/internal/handlers/mailaccount.go | 30 +++ kontor-echo/internal/handlers/media_actor.go | 28 ++- .../internal/handlers/media_article.go | 45 ++--- kontor-echo/internal/handlers/media_file.go | 52 +++--- kontor-echo/internal/handlers/media_lofi.go | 61 +++--- kontor-echo/internal/handlers/media_music.go | 73 ++++---- kontor-echo/internal/handlers/media_video.go | 38 ++-- kontor-echo/internal/handlers/token.go | 30 +++ kontor-echo/internal/helpers/auth.go | 7 + kontor-echo/internal/helpers/token.go | 88 +++++++++ kontor-echo/internal/helpers/url.go | 69 +++++++ kontor-echo/internal/models/mail.go | 73 ++++++++ kontor-echo/internal/models/mailaccount.go | 77 ++++++++ kontor-echo/internal/repository/assignment.go | 51 ++--- kontor-echo/internal/repository/mail.go | 70 +++++++ .../internal/repository/mailaccount.go | 70 +++++++ .../internal/repository/media_actor.go | 44 +++-- .../internal/repository/media_actor_file.go | 45 +++-- kontor-echo/internal/repository/media_file.go | 45 +++-- kontor-echo/internal/repository/media_lofi.go | 80 ++++---- .../internal/repository/media_music.go | 92 ++++----- .../internal/repository/media_video.go | 71 ++++--- kontor-echo/internal/repository/profile.go | 3 +- kontor-echo/internal/repository/token.go | 70 +++++++ kontor-echo/internal/router/router.go | 140 +++++++++++++- kontor-echo/internal/service/assignment.go | 2 +- kontor-echo/internal/service/auth.go | 47 +++++ kontor-echo/internal/service/mail.go | 27 +++ kontor-echo/internal/service/mailaccount.go | 27 +++ kontor-echo/internal/service/token.go | 27 +++ kontor-echo/pkg/handler/health.go | 17 -- kontor-echo/pkg/handler/media.go | 67 ------- kontor-echo/templates/layouts/footer.html | 9 + kontor-echo/templates/layouts/head.html | 13 ++ kontor-echo/templates/layouts/main.html | 24 +++ kontor-echo/templates/layouts/navbar.html | 88 +++++++++ kontor-echo/templates/pages/comics.html | 59 ++++++ kontor-echo/templates/pages/home.html | 27 +++ kontor-echo/templates/pages/lofi.html | 69 +++++++ kontor-echo/templates/pages/lofi_detail.html | 54 ++++++ kontor-echo/templates/pages/login.html | 36 ++++ kontor-echo/templates/pages/media_actor.html | 54 ++++++ kontor-echo/templates/pages/media_actors.html | 41 +++++ kontor-echo/templates/pages/media_detail.html | 54 ++++++ kontor-echo/templates/pages/media_links.html | 71 +++++++ kontor-echo/templates/pages/mediafiles.html | 71 +++++++ kontor-echo/templates/pages/mediavideos.html | 71 +++++++ kontor-echo/templates/pages/publishers.html | 42 +++++ kontor-echo/templates/templates.go | 8 + 63 files changed, 2411 insertions(+), 485 deletions(-) create mode 100644 kontor-echo/assets/assets.go create mode 100644 kontor-echo/assets/icons/cross.png create mode 100644 kontor-echo/assets/icons/logo.png create mode 100644 kontor-echo/assets/icons/tick.png create mode 100644 kontor-echo/assets/style/main.css create mode 100644 kontor-echo/internal/handlers/auth.go create mode 100644 kontor-echo/internal/handlers/kontor.go create mode 100644 kontor-echo/internal/handlers/mail.go create mode 100644 kontor-echo/internal/handlers/mailaccount.go create mode 100644 kontor-echo/internal/handlers/token.go create mode 100644 kontor-echo/internal/helpers/auth.go create mode 100644 kontor-echo/internal/helpers/token.go create mode 100644 kontor-echo/internal/helpers/url.go create mode 100644 kontor-echo/internal/models/mail.go create mode 100644 kontor-echo/internal/models/mailaccount.go create mode 100644 kontor-echo/internal/repository/mail.go create mode 100644 kontor-echo/internal/repository/mailaccount.go create mode 100644 kontor-echo/internal/repository/token.go create mode 100644 kontor-echo/internal/service/auth.go create mode 100644 kontor-echo/internal/service/mail.go create mode 100644 kontor-echo/internal/service/mailaccount.go create mode 100644 kontor-echo/internal/service/token.go delete mode 100644 kontor-echo/pkg/handler/health.go delete mode 100644 kontor-echo/pkg/handler/media.go create mode 100644 kontor-echo/templates/layouts/footer.html create mode 100644 kontor-echo/templates/layouts/head.html create mode 100644 kontor-echo/templates/layouts/main.html create mode 100644 kontor-echo/templates/layouts/navbar.html create mode 100644 kontor-echo/templates/pages/comics.html create mode 100644 kontor-echo/templates/pages/home.html create mode 100644 kontor-echo/templates/pages/lofi.html create mode 100644 kontor-echo/templates/pages/lofi_detail.html create mode 100644 kontor-echo/templates/pages/login.html create mode 100644 kontor-echo/templates/pages/media_actor.html create mode 100644 kontor-echo/templates/pages/media_actors.html create mode 100644 kontor-echo/templates/pages/media_detail.html create mode 100644 kontor-echo/templates/pages/media_links.html create mode 100644 kontor-echo/templates/pages/mediafiles.html create mode 100644 kontor-echo/templates/pages/mediavideos.html create mode 100644 kontor-echo/templates/pages/publishers.html create mode 100644 kontor-echo/templates/templates.go diff --git a/kontor-echo/Containerfile b/kontor-echo/Containerfile index bbb66d7..3a0ae9a 100644 --- a/kontor-echo/Containerfile +++ b/kontor-echo/Containerfile @@ -1,5 +1,5 @@ # ---------- Stage 1: Build ---------- -FROM docker.io/library/golang:1.25-alpine AS builder +FROM docker.io/library/golang:1.26-alpine AS builder # Set the working directory WORKDIR /app # Ensure a portable, static-ish binary @@ -9,8 +9,12 @@ COPY go.mod go.sum ./ RUN go mod download # Copy the source code COPY . . +ARG VERSION="dev" +ARG COMMIT="unset" +ARG DATE="unset" # Build the Go application (strip debug info for smaller size) -RUN go build -trimpath -ldflags="-s -w" -o kontor cmd/kontor/main.go +RUN go build -trimpath -ldflags="-s -w -X kontor-api-echo/internal/globals.Version=${VERSION} -X kontor-api-echo/internal/globals.Commit=${COMMIT} -X kontor-api-echo/internal/globals.Date=${DATE}" -o kontor cmd/kontor-echo/main.go + # ---------- Stage 2: Final ---------- FROM alpine:latest diff --git a/kontor-echo/assets/assets.go b/kontor-echo/assets/assets.go new file mode 100644 index 0000000..c147543 --- /dev/null +++ b/kontor-echo/assets/assets.go @@ -0,0 +1,8 @@ +package assets + +import ( + "embed" +) + +//go:embed style/* icons/* +var StaticFiles embed.FS diff --git a/kontor-echo/assets/icons/cross.png b/kontor-echo/assets/icons/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9fa6dd36ee8165272a13dd263f573507c78ca6 GIT binary patch literal 544 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 U+D>(nEdT%j07*qoM6N<$g0@&8X#fBK literal 0 HcmV?d00001 diff --git a/kontor-echo/assets/style/main.css b/kontor-echo/assets/style/main.css new file mode 100644 index 0000000..52ae177 --- /dev/null +++ b/kontor-echo/assets/style/main.css @@ -0,0 +1,174 @@ +* { + box-sizing: border-box; +} + +body { + font-family: Arial; + padding: 10px; + background: lightgrey; + padding-top: 56px; + padding-bottom: 56px; +} + +/* Header/Blog Title */ +.header { + padding: 30px; + text-align: center; + background-color: lightblue; +} + +.header h1 { + font-size: 50px; +} + +/* Style the top navigation bar */ +.topnav { + overflow: hidden; + background-color: darkgrey; +} + +/* Style the topnav links */ +.topnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +/* Change color on hover */ +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.subnav { + overflow: hidden; + background-color: grey; +} + +.subnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +.form-inline { + display: flex; + flex-flow: row wrap; + align-items: center; + padding-top: 10px; + padding-left: 20px; +} + +.form-inline label { + margin: 5px 10px 5px 0; +} + +.form-inline input { + padding-right: 50px; + margin-right: 10px; +} + +.form-inline button { + padding: 10px 20px; + background-color: dodgerblue; + border: 1px solid #ddd; + color: white; + border-radius: 10px; +} + +.form-inline button:hover { + background-color: royalblue; +} + +.pill-nav a { + display: inline-block; + color: white; + background-color: dodgerblue; + text-align: center; + padding: 10px; + text-decoration: none; + border-radius: 10px; + margin-left: 20px; +} + +/* Change the color of links on mouse-over */ +.pill-nav a:hover { + background-color: royalblue; + color: white; +} + +/* Add a color to the active/current link */ +.pill-nav a.active { + background-color: royalblue; + color: white; +} + +.maincolumn { + float:left; + width: 100%; +} +/* Create two unequal columns that floats next to each other */ +/* Left column */ +.leftcolumn { + float: left; + width: 75%; +} + +/* Right column */ +.rightcolumn { + float: left; + width: 25%; + background-color: #f1f1f1; + padding-left: 20px; +} + +/* Fake image */ +.fakeimg { + background-color: #aaa; + width: 100%; + padding: 20px; +} + +/* Add a card effect for articles */ +.card { + background-color: white; + padding: 20px; + margin-top: 20px; +} + +/* Clear floats after the columns */ +.row::after { + content: ""; + display: table; + clear: both; +} + +/* Footer */ +.footer { + padding: 20px; + text-align: center; + background: #ddd; + margin-top: 20px; +} + +/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 800px) { + .leftcolumn, .rightcolumn { + width: 100%; + padding: 0; + } +} + +/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */ +@media screen and (max-width: 400px) { + .topnav a { + float: none; + width: 100%; + } +} diff --git a/kontor-echo/cmd/kontor-echo/main.go b/kontor-echo/cmd/kontor-echo/main.go index 58a690e..4bb8372 100644 --- a/kontor-echo/cmd/kontor-echo/main.go +++ b/kontor-echo/cmd/kontor-echo/main.go @@ -31,7 +31,8 @@ func main() { defer stop() sc := echo.StartConfig{ - Address: ":1323", + //Address: fmt.Sprintf(":%d", config.ServerConfig.Server.Port), + Address: ":8400", GracefulTimeout: 10 * time.Second, } if err := sc.Start(ctx, e); err != nil { diff --git a/kontor-echo/cmd/kontor/main.go b/kontor-echo/cmd/kontor/main.go index aef6b85..9eebd62 100644 --- a/kontor-echo/cmd/kontor/main.go +++ b/kontor-echo/cmd/kontor/main.go @@ -20,7 +20,6 @@ func main() { } e := echo.New() - e.GET("/health", handler.GetHealth) e.POST("/login", handler.Login) skipper := func(c echo.Context) bool { @@ -47,7 +46,6 @@ func main() { group := e.Group("/api") group.Use(echojwt.WithConfig(echojwt.Config{SigningKey: []byte("secret")})) handler.SetupComicRoutes(group) - handler.SetupMediaRoutes(group) e.Logger.Fatal(e.Start(":8400")) log.Println("Kontor finished") diff --git a/kontor-echo/go.mod b/kontor-echo/go.mod index c295ed8..ad99b5a 100644 --- a/kontor-echo/go.mod +++ b/kontor-echo/go.mod @@ -6,18 +6,18 @@ 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/dialect/pgdialect v1.3.0 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/labstack/echo-jwt/v5 v5.0.2 // 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 @@ -42,12 +42,11 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/puzpuzpuz/xsync/v3 v3.5.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/cobra v1.10.2 github.com/spf13/pflag v1.1.0 // indirect - github.com/spf13/viper v1.21.0 // indirect + github.com/spf13/viper v1.21.0 github.com/subosito/gotenv v1.6.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/uptrace/bun/dialect/sqlitedialect v1.3.0 @@ -60,7 +59,7 @@ require ( go.opentelemetry.io/otel/trace v1.39.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/sys v0.50.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 diff --git a/kontor-echo/go.sum b/kontor-echo/go.sum index f8ba6c2..c10934c 100644 --- a/kontor-echo/go.sum +++ b/kontor-echo/go.sum @@ -5,6 +5,8 @@ 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/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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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= @@ -13,12 +15,18 @@ github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63Y 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/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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= @@ -49,11 +57,11 @@ github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++ 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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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= @@ -71,12 +79,10 @@ 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/pgdialect v1.3.0 h1:0ZkGqGugxaPCxko4DV2f4d7i+FnM2Qj3rNpChfhiv54= +github.com/uptrace/bun/dialect/pgdialect v1.3.0/go.mod h1:kP5HGEpAX8iJCqj3WHm04XnoeBPacdCN1P2HiwMtHpg= 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= @@ -102,19 +108,21 @@ 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/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= +golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= 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/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= +golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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/sys v0.50.0 h1:dkKZEFTEKaLr1sjhs0WiKqoi8Jj5nHbS3Njmx1UoMJs= +golang.org/x/sys v0.50.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= 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= +golang.org/x/tools v0.51.0 h1:k4Xc/1Om9jwkBJBo4NVLMSARBoWtK10mx+W5BnXCeAI= +golang.org/x/tools v0.51.0/go.mod h1:9eEncMayCV6zRMGhR5eZEC2iBx98qWcF1HZ9Z7wJOoA= 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= @@ -122,11 +130,31 @@ 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/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so= +modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= 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/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/kontor-echo/internal/config/config.go b/kontor-echo/internal/config/config.go index 87b0a91..0f87b7b 100644 --- a/kontor-echo/internal/config/config.go +++ b/kontor-echo/internal/config/config.go @@ -138,8 +138,8 @@ func InitConfig() error { 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") + viper.SetDefault("server.host", "127.0.0.1") + viper.SetDefault("server.port", 8400) // Read the config file if err := viper.ReadInConfig(); err != nil { // Handle the case where config file is not found diff --git a/kontor-echo/internal/handlers/auth.go b/kontor-echo/internal/handlers/auth.go new file mode 100644 index 0000000..7a7c6fa --- /dev/null +++ b/kontor-echo/internal/handlers/auth.go @@ -0,0 +1,114 @@ +package handlers + +import ( + "kontor-api-echo/internal/config" + "kontor-api-echo/internal/globals" + "kontor-api-echo/internal/helpers" + "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 AuthHandler struct { + Service *service.AuthService + Secret []byte +} + +func NewAuthHandler(db *bun.DB) *AuthHandler { + handler := &AuthHandler{Service: service.NewAuthService(repository.NewProfileRepository(db)), Secret: config.ServerConfig.ApiSecret} + return handler +} + +func (handler *AuthHandler) Login(c *echo.Context) error { + var input models.LoginInput + + if err := c.Bind(&input); err != nil { + return c.JSON(http.StatusBadRequest, map[string]any{"error": err.Error()}) + } + + profile_id, err := handler.Service.LoginCheck(input.Email, input.Password) + + if err != nil { + return c.JSON(http.StatusBadRequest, map[string]any{"error": "username or password is incorrect."}) + } + + token, err := helpers.GenerateToken(profile_id) + logger := c.Logger() + if err != nil { + logger.Info("Login", "GenerateToken error", err.Error()) + } + return c.JSON(http.StatusOK, map[string]any{"token": token}) +} + +func (handler *AuthHandler) LoginPage(c *echo.Context) error { + cookie, _ := c.Cookie(globals.UserKey) + user := cookie.Value + logger := c.Logger() + logger.Info("LoginPage", globals.UserKey, user) + data := globals.GetDefaultValues(user, "Please logout first") + if user != "" { + return c.Render(http.StatusBadRequest, "login", data) + } + data["message"] = "" + return c.Render(http.StatusOK, "login", data) +} + +func (handler *AuthHandler) LoginPost(c *echo.Context) error { + cookie, _ := c.Cookie(globals.UserKey) + user := cookie.Value + logger := c.Logger() + logger.Info("LoginPost", "user", user) + data := globals.GetDefaultValues(user, "Please logout first") + if user != "" { + return c.Render(http.StatusBadRequest, "login", data) + } + + username := c.FormValue("username") + password := c.FormValue("password") + + if helpers.EmptyUserPass(username, password) { + data["message"] = "Parameters can't be empty" + c.Render(http.StatusBadRequest, "login", data) + } + + profile_id, err := handler.Service.LoginCheck(username, password) + if err != nil { + data["message"] = "Incorrect username or password" + c.Render(http.StatusUnauthorized, "login", data) + } + c.SetCookie(&http.Cookie{ + Name: globals.UserKey, + Value: profile_id, + MaxAge: 3600, + Path: "/", + Domain: "", + HttpOnly: true, + }) + logger.Info("LoginPost: redirect to index") + return c.Redirect(http.StatusMovedPermanently, "/") +} + +func (handler *AuthHandler) LogoutPage(c *echo.Context) error { + cookie, _ := c.Cookie(globals.UserKey) + user := cookie.Value + logger := c.Logger() + logger.Info("LogoutPage", globals.UserKey, user) + if user == "" { + logger.Info("Invalid session token") + return c.Redirect(http.StatusMovedPermanently, "/") + } + c.SetCookie(&http.Cookie{ + Name: globals.UserKey, + Value: "", + MaxAge: -1, // Deletes the cookie immediately + Path: "/", + Domain: "", + HttpOnly: true, + }) + logger.Info("LogoutPage: redirect to index page") + return c.Redirect(http.StatusMovedPermanently, "/") +} diff --git a/kontor-echo/internal/handlers/kontor.go b/kontor-echo/internal/handlers/kontor.go new file mode 100644 index 0000000..88628eb --- /dev/null +++ b/kontor-echo/internal/handlers/kontor.go @@ -0,0 +1,33 @@ +package handlers + +import ( + "kontor-api-echo/internal/globals" + "net/http" + "time" + + "github.com/labstack/echo/v5" +) + +func Health(c *echo.Context) error { + return c.JSON(200, map[string]string{ + "ok": "true", + "status": "healthy", + "version": globals.Version, + "time": time.Now().UTC().Format(time.RFC3339), + }) +} + +func Index(c *echo.Context) error { + logger := c.Logger() + cookie, err := c.Cookie(globals.UserKey) + user := "" + if err != nil { + logger.Info("error reading cookie", "error", err.Error()) + } else { + user = cookie.Value + } + + logger.Info("IndexGetHandler", globals.UserKey, user) + data := globals.GetDefaultValues(user, "This is an index page...") + return c.Render(http.StatusOK, "home", data) +} diff --git a/kontor-echo/internal/handlers/mail.go b/kontor-echo/internal/handlers/mail.go new file mode 100644 index 0000000..8724258 --- /dev/null +++ b/kontor-echo/internal/handlers/mail.go @@ -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 MailHandler struct { + Service *service.MailService +} + +func NewMailHandler(db *bun.DB) *MailHandler { + handler := &MailHandler{Service: service.NewMailService(repository.NewMailRepository(db))} + return handler +} + +func (handler *MailHandler) List(c *echo.Context) { + mails, err := handler.Service.List(c.Request().Context()) + if err != nil { + c.JSON(http.StatusInternalServerError, map[string]any{"error": err.Error()}) + return + } + dtos := models.ConvertMailsToDtos(mails) + c.JSON(http.StatusOK, dtos) +} diff --git a/kontor-echo/internal/handlers/mailaccount.go b/kontor-echo/internal/handlers/mailaccount.go new file mode 100644 index 0000000..f64421c --- /dev/null +++ b/kontor-echo/internal/handlers/mailaccount.go @@ -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 MailAccountHandler struct { + Service *service.MailAccountService +} + +func NewMailAccountHandler(db *bun.DB) *MailAccountHandler { + handler := &MailAccountHandler{Service: service.NewMailAccountService(repository.NewMailAccountRepository(db))} + return handler +} + +func (handler *MailAccountHandler) List(c *echo.Context) { + mailaccounts, err := handler.Service.List(c.Request().Context()) + if err != nil { + c.JSON(http.StatusInternalServerError, map[string]any{"error": err.Error()}) + return + } + dtos := models.ConvertMailAccountsToDtos(mailaccounts) + c.JSON(http.StatusOK, dtos) +} diff --git a/kontor-echo/internal/handlers/media_actor.go b/kontor-echo/internal/handlers/media_actor.go index e0a5fe8..556a662 100644 --- a/kontor-echo/internal/handlers/media_actor.go +++ b/kontor-echo/internal/handlers/media_actor.go @@ -67,35 +67,35 @@ func (handler *MediaActorHandler) Delete(c *echo.Context) { c.JSON(http.StatusOK, map[string]string{"ok": "true"}) } -func (handler *MediaActorHandler) ListPage(c *echo.Context) { +func (handler *MediaActorHandler) ListPage(c *echo.Context) error { 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 + return err } data := globals.GetDefaultValues(user, "MediaActors...") data["actors"] = actors c.Render(http.StatusOK, "media_actors", data) + return nil } -func (handler *MediaActorHandler) EditPage(c *echo.Context) { +func (handler *MediaActorHandler) EditPage(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } data := globals.GetDefaultValues(user, "MediaActors...") data["actor"] = actor - c.Render(http.StatusOK, "actor_detail", data) + return c.Render(http.StatusOK, "actor_detail", data) } -func (handler *MediaActorHandler) UpdatePage(c *echo.Context) { +func (handler *MediaActorHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -103,8 +103,7 @@ func (handler *MediaActorHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } var form models.MediaActorForm if err := c.Bind(&form); err != nil { @@ -113,15 +112,14 @@ func (handler *MediaActorHandler) UpdatePage(c *echo.Context) { data["actor"] = actor data["Form"] = form data["Errors"] = err.Error() - c.Render(http.StatusBadRequest, "actor_detail", data) - return + return c.Render(http.StatusBadRequest, "actor_detail", data) } logger.Info("MediaActorHandler#UpdatePage", "actor", actor) //handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO()) - c.Redirect(http.StatusFound, globals.MediaActorLink) + return c.Redirect(http.StatusFound, globals.MediaActorLink) } -func (handler *MediaActorHandler) DeletePage(c *echo.Context) { +func (handler *MediaActorHandler) DeletePage(c *echo.Context) error { //session := sessions.Default(c) //user := session.Get(globals.UserKey) id := c.Param("id") @@ -129,9 +127,9 @@ func (handler *MediaActorHandler) DeletePage(c *echo.Context) { //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()}) + // c.JSON(http.StatusInternalServerError, map[string]any{"error": err.Error()}) // return // } logger.Info("MediaActorHandler#DeletePage", "actor", id) - c.Redirect(http.StatusFound, globals.MediaActorLink) + return c.Redirect(http.StatusFound, globals.MediaActorLink) } diff --git a/kontor-echo/internal/handlers/media_article.go b/kontor-echo/internal/handlers/media_article.go index 2c38b1c..b013985 100644 --- a/kontor-echo/internal/handlers/media_article.go +++ b/kontor-echo/internal/handlers/media_article.go @@ -22,44 +22,41 @@ func NewMediaArticleHandler(db *bun.DB) *MediaArticleHandler { return mediaFileHandler } -func (handler *MediaArticleHandler) List(c *echo.Context) { +func (handler *MediaArticleHandler) List(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } dtos := models.ConvertMediaArticlesToDtos(articles) - c.JSON(http.StatusOK, dtos) + return c.JSON(http.StatusOK, dtos) } -func (handler *MediaArticleHandler) Delete(c *echo.Context) { +func (handler *MediaArticleHandler) Delete(c *echo.Context) error { 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"}) } - c.JSON(http.StatusOK, map[string]string{"ok": "true"}) + return c.JSON(http.StatusOK, map[string]string{"ok": "true"}) } -func (handler *MediaArticleHandler) ListPage(c *echo.Context) { +func (handler *MediaArticleHandler) ListPage(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } data := globals.GetDefaultValues(user, "MediaArticles...") data["title"] = "Kontor MediaArticles" data["media_links"] = files data["MediaLinksUrl"] = globals.MediaArticleLink - c.Render(http.StatusOK, "media_links", data) + return c.Render(http.StatusOK, "media_links", data) } -func (handler *MediaArticleHandler) EditPage(c *echo.Context) { +func (handler *MediaArticleHandler) EditPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -67,16 +64,15 @@ func (handler *MediaArticleHandler) EditPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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) + return c.Render(http.StatusOK, "lofi_detail", data) } -func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) { +func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -84,8 +80,7 @@ func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } var form models.MediaArticleForm if err := c.Bind(&form); err != nil { @@ -93,23 +88,21 @@ func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) { data := globals.GetDefaultValues(user, "MediaArticle Details...") data["Form"] = form data["Errors"] = err.Error() - c.Render(http.StatusBadRequest, "lofi_detail", data) - return + return c.Render(http.StatusBadRequest, "lofi_detail", data) } logger.Info("MediaArticleHandler#UpdatePage", "media_article", media_article) //handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO()) - c.Redirect(http.StatusFound, globals.MediaArticleLink) + return c.Redirect(http.StatusFound, globals.MediaArticleLink) } -func (handler *MediaArticleHandler) DeletePage(c *echo.Context) { +func (handler *MediaArticleHandler) DeletePage(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaArticleHandler#DeletePage", "lofi", id) - c.Redirect(http.StatusFound, globals.MediaArticleLink) + return c.Redirect(http.StatusFound, globals.MediaArticleLink) } diff --git a/kontor-echo/internal/handlers/media_file.go b/kontor-echo/internal/handlers/media_file.go index b93c9ea..a2ce9de 100644 --- a/kontor-echo/internal/handlers/media_file.go +++ b/kontor-echo/internal/handlers/media_file.go @@ -22,59 +22,57 @@ func NewMediaFileHandler(db *bun.DB) *MediaFileHandler { return mediaFileHandler } -func (handler *MediaFileHandler) List(c *echo.Context) { +func (handler *MediaFileHandler) List(c *echo.Context) error { 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 + return err } dtos := models.ConvertMediaFilesToDtos(files) - c.JSON(http.StatusOK, dtos) + return c.JSON(http.StatusOK, dtos) } -func (handler *MediaFileHandler) Add(c *echo.Context) { +func (handler *MediaFileHandler) Add(c *echo.Context) error { var input models.MediaFileAdd if err := c.Bind(&input); err != nil { c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) - return + return err } 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 + return err } - c.JSON(http.StatusOK, lofi) + return c.JSON(http.StatusOK, lofi) } -func (handler *MediaFileHandler) Delete(c *echo.Context) { +func (handler *MediaFileHandler) Delete(c *echo.Context) error { 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"}) } - c.JSON(http.StatusOK, map[string]string{"ok": "true"}) + return c.JSON(http.StatusOK, map[string]string{"ok": "true"}) } -func (handler *MediaFileHandler) ListPage(c *echo.Context) { +func (handler *MediaFileHandler) ListPage(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } data := globals.GetDefaultValues(user, "MediaFiles...") data["title"] = "Kontor MediaFiles" data["media_links"] = files data["MediaLinksUrl"] = globals.MediaVideoLink - c.Render(http.StatusOK, "media_links", data) + return c.Render(http.StatusOK, "media_links", data) } -func (handler *MediaFileHandler) EditPage(c *echo.Context) { +func (handler *MediaFileHandler) EditPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -82,16 +80,15 @@ func (handler *MediaFileHandler) EditPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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) + return c.Render(http.StatusOK, "lofi_detail", data) } -func (handler *MediaFileHandler) UpdatePage(c *echo.Context) { +func (handler *MediaFileHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -99,8 +96,7 @@ func (handler *MediaFileHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } var form models.MediaFileForm if err := c.Bind(&form); err != nil { @@ -108,15 +104,14 @@ func (handler *MediaFileHandler) UpdatePage(c *echo.Context) { data := globals.GetDefaultValues(user, "MediaFile Details...") data["Form"] = form data["Errors"] = err.Error() - c.Render(http.StatusBadRequest, "lofi_detail", data) - return + return c.Render(http.StatusBadRequest, "lofi_detail", data) } logger.Info("MediaFileHandler#UpdatePage", "media_file", media_file) //handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO()) - c.Redirect(http.StatusFound, globals.MediaFileLink) + return c.Redirect(http.StatusFound, globals.MediaFileLink) } -func (handler *MediaFileHandler) DeletePage(c *echo.Context) { +func (handler *MediaFileHandler) DeletePage(c *echo.Context) error { //session := sessions.Default(c) //user := session.Get(globals.UserKey) id := c.Param("id") @@ -124,9 +119,8 @@ func (handler *MediaFileHandler) DeletePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaFileHandler#DeletePage", "lofi", id) - c.Redirect(http.StatusFound, globals.MediaFileLink) + return c.Redirect(http.StatusFound, globals.MediaFileLink) } diff --git a/kontor-echo/internal/handlers/media_lofi.go b/kontor-echo/internal/handlers/media_lofi.go index 9916eb8..9e5d68c 100644 --- a/kontor-echo/internal/handlers/media_lofi.go +++ b/kontor-echo/internal/handlers/media_lofi.go @@ -59,33 +59,31 @@ func (handler *MediaLoFiHandler) Add(c *echo.Context) { c.JSON(http.StatusOK, lofi) } -func (handler *MediaLoFiHandler) Update(c *echo.Context) { +func (handler *MediaLoFiHandler) Update(c *echo.Context) error { var input models.MediaLoFiDTO if err := c.Bind(&input); err != nil { - c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) - return + return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) } 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not updated"}) } - c.JSON(http.StatusOK, lofi) + return c.JSON(http.StatusOK, lofi) } -func (handler *MediaLoFiHandler) Delete(c *echo.Context) { + +func (handler *MediaLoFiHandler) Delete(c *echo.Context) error { 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"}) } - c.JSON(http.StatusOK, map[string]string{"ok": "true"}) + return c.JSON(http.StatusOK, map[string]string{"ok": "true"}) } -func (handler *MediaLoFiHandler) ListPage(c *echo.Context) { +func (handler *MediaLoFiHandler) ListPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value logger := c.Logger() @@ -113,8 +111,7 @@ func (handler *MediaLoFiHandler) ListPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis)) data := globals.GetDefaultValues(user, "MediaFiles...") @@ -122,10 +119,10 @@ func (handler *MediaLoFiHandler) ListPage(c *echo.Context) { data["isReview"] = review data["isDownload"] = download data["MediaLinksUrl"] = globals.MediaLofiLink - c.Render(http.StatusOK, "media_links", data) + return c.Render(http.StatusOK, "media_links", data) } -func (handler *MediaLoFiHandler) EditPage(c *echo.Context) { +func (handler *MediaLoFiHandler) EditPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -146,25 +143,23 @@ func (handler *MediaLoFiHandler) EditPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } } 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) + return c.Render(http.StatusOK, "media_detail", data) } -func (handler *MediaLoFiHandler) ChangeReviewPage(c *echo.Context) { +func (handler *MediaLoFiHandler) ChangeReviewPage(c *echo.Context) error { 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 + return c.Redirect(http.StatusNotFound, globals.MediaLofiLink) } lofi.Review = !lofi.Review handler.Service.Update(c.Request().Context(), lofi.ConvertMediaLoFiToDTO()) @@ -174,17 +169,16 @@ func (handler *MediaLoFiHandler) ChangeReviewPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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) + //c.Render(http.StatusOK, "lofi", data) + return c.Redirect(http.StatusCreated, globals.MediaLofiLink) } -func (handler *MediaLoFiHandler) UpdatePage(c *echo.Context) { +func (handler *MediaLoFiHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -192,25 +186,23 @@ func (handler *MediaLoFiHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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{ + return 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) + return c.Redirect(http.StatusFound, globals.MediaLofiLink) } -func (handler *MediaLoFiHandler) DeletePage(c *echo.Context) { +func (handler *MediaLoFiHandler) DeletePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -218,11 +210,10 @@ func (handler *MediaLoFiHandler) DeletePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaLoFiHandler#DeletePage", "lofi", id) - c.Render(http.StatusOK, "lofi_delete", map[string]any{ + return c.Render(http.StatusOK, "lofi_delete", map[string]any{ "title": "Kontor MediaFiles", "version": "0.4.0", "message": "MediaFiles...", diff --git a/kontor-echo/internal/handlers/media_music.go b/kontor-echo/internal/handlers/media_music.go index 47d3a4d..445b872 100644 --- a/kontor-echo/internal/handlers/media_music.go +++ b/kontor-echo/internal/handlers/media_music.go @@ -22,68 +22,62 @@ func NewMediaMusicHandler(db *bun.DB) *MediaMusicHandler { return mediaMusicHandler } -func (handler *MediaMusicHandler) List(c *echo.Context) { +func (handler *MediaMusicHandler) List(c *echo.Context) error { musics, err := handler.Service.List(c.Request().Context()) if err != nil { - c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) - return + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } dtos := models.ConvertMediaMusicsToDtos(musics) - c.JSON(http.StatusOK, dtos) + return c.JSON(http.StatusOK, dtos) } -func (handler *MediaMusicHandler) Get(c *echo.Context) { +func (handler *MediaMusicHandler) Get(c *echo.Context) error { 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"}) } - c.JSON(http.StatusOK, music) + return c.JSON(http.StatusOK, music) } -func (handler *MediaMusicHandler) Add(c *echo.Context) { +func (handler *MediaMusicHandler) Add(c *echo.Context) error { var input models.MediaLofiAdd if err := c.Bind(&input); err != nil { - c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) - return + return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) } 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not added"}) } - c.JSON(http.StatusOK, music) + return c.JSON(http.StatusOK, music) } -func (handler *MediaMusicHandler) Update(c *echo.Context) { +func (handler *MediaMusicHandler) Update(c *echo.Context) error { var input models.MediaMusicDTO if err := c.Bind(&input); err != nil { - c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) - return + return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) } 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not updated"}) } - c.JSON(http.StatusOK, music) + return c.JSON(http.StatusOK, music) } -func (handler *MediaMusicHandler) Delete(c *echo.Context) { + +func (handler *MediaMusicHandler) Delete(c *echo.Context) error { 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 + return c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"}) } - c.JSON(http.StatusOK, map[string]string{"ok": "true"}) + return c.JSON(http.StatusOK, map[string]string{"ok": "true"}) } -func (handler *MediaMusicHandler) ListPage(c *echo.Context) { +func (handler *MediaMusicHandler) ListPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value logger := c.Logger() @@ -111,8 +105,7 @@ func (handler *MediaMusicHandler) ListPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaMusicHandler#ListPage", "MediaMusic count", len(musics)) data := globals.GetDefaultValues(user, "MediaMusic...") @@ -120,10 +113,10 @@ func (handler *MediaMusicHandler) ListPage(c *echo.Context) { data["MediaLinksUrl"] = globals.MediaMusicLink data["isReview"] = review data["isDownload"] = download - c.Render(http.StatusOK, "media_links", data) + return c.Render(http.StatusOK, "media_links", data) } -func (handler *MediaMusicHandler) EditPage(c *echo.Context) { +func (handler *MediaMusicHandler) EditPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -131,16 +124,15 @@ func (handler *MediaMusicHandler) EditPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaMusicHandler#EditPage", "music", music) data := globals.GetDefaultValues(user, "MediaMusic...") data["lofi"] = music - c.Render(http.StatusOK, "lofi_detail", data) + return c.Render(http.StatusOK, "lofi_detail", data) } -func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) { +func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -148,8 +140,7 @@ func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } var form models.MediaMusicForm if err := c.Bind(&form); err != nil { @@ -157,15 +148,14 @@ func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) { data := globals.GetDefaultValues(user, "MediaMusic...") data["Form"] = form data["Errors"] = err.Error() - c.Render(http.StatusBadRequest, "lofi_detail", data) - return + return c.Render(http.StatusBadRequest, "lofi_detail", data) } logger.Info("MediaMusicHandler#UpdatePage", "music", music) //handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO()) - c.Redirect(http.StatusFound, globals.MediaMusicLink) + return c.Redirect(http.StatusFound, globals.MediaMusicLink) } -func (handler *MediaMusicHandler) DeletePage(c *echo.Context) { +func (handler *MediaMusicHandler) DeletePage(c *echo.Context) error { // session := sessions.Default(c) // user := session.Get(globals.UserKey) id := c.Param("id") @@ -173,9 +163,8 @@ func (handler *MediaMusicHandler) DeletePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaMusicHandler#DeletePage", "music", id) - c.Redirect(http.StatusFound, globals.MediaMusicLink) + return c.Redirect(http.StatusFound, globals.MediaMusicLink) } diff --git a/kontor-echo/internal/handlers/media_video.go b/kontor-echo/internal/handlers/media_video.go index 563ecd7..2e1e5d4 100644 --- a/kontor-echo/internal/handlers/media_video.go +++ b/kontor-echo/internal/handlers/media_video.go @@ -20,36 +20,34 @@ func NewMediaVideoHandler(db *bun.DB) *MediaVideoHandler { return handler } -func (handler *MediaVideoHandler) List(c *echo.Context) { +func (handler *MediaVideoHandler) List(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } dtos := models.ConvertMediaVideosToDtos(videos) - c.JSON(http.StatusOK, dtos) + return c.JSON(http.StatusOK, dtos) } -func (handler *MediaVideoHandler) ListPage(c *echo.Context) { +func (handler *MediaVideoHandler) ListPage(c *echo.Context) error { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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) + return c.Render(http.StatusOK, "media_links", data) } -func (handler *MediaVideoHandler) EditPage(c *echo.Context) { +func (handler *MediaVideoHandler) EditPage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -57,16 +55,15 @@ func (handler *MediaVideoHandler) EditPage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaVideoHandler#EditPage", "lofi", video) data := globals.GetDefaultValues(user, "MediaLofis...") data["lofi"] = video - c.Render(http.StatusOK, "lofi_detail", data) + return c.Render(http.StatusOK, "lofi_detail", data) } -func (handler *MediaVideoHandler) UpdatePage(c *echo.Context) { +func (handler *MediaVideoHandler) UpdatePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -74,25 +71,23 @@ func (handler *MediaVideoHandler) UpdatePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } 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{ + return 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) + return c.Redirect(http.StatusFound, globals.MediaVideoLink) } -func (handler *MediaVideoHandler) DeletePage(c *echo.Context) { +func (handler *MediaVideoHandler) DeletePage(c *echo.Context) error { cookie, err := c.Cookie(globals.UserKey) user := cookie.Value id := c.Param("id") @@ -100,11 +95,10 @@ func (handler *MediaVideoHandler) DeletePage(c *echo.Context) { 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 + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } logger.Info("MediaVideoHandler#DeletePage", "video", id) - c.Render(http.StatusOK, "lofi_delete", map[string]string{ + return c.Render(http.StatusOK, "lofi_delete", map[string]string{ "title": "Kontor MediaFiles", "version": "0.4.0", "message": "MediaFiles...", diff --git a/kontor-echo/internal/handlers/token.go b/kontor-echo/internal/handlers/token.go new file mode 100644 index 0000000..32f7b42 --- /dev/null +++ b/kontor-echo/internal/handlers/token.go @@ -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 TokenHandler struct { + Service *service.TokenService +} + +func NewTokenHandler(db *bun.DB) *TokenHandler { + handler := &TokenHandler{Service: service.NewTokenService(repository.NewTokenRepository(db))} + return handler +} + +func (handler *TokenHandler) List(c *echo.Context) { + tokens, err := handler.Service.List(c.Request().Context()) + if err != nil { + c.JSON(http.StatusInternalServerError, map[string]any{"error": err.Error()}) + return + } + dtos := models.ConvertTokensToDtos(tokens) + c.JSON(http.StatusOK, dtos) +} diff --git a/kontor-echo/internal/helpers/auth.go b/kontor-echo/internal/helpers/auth.go new file mode 100644 index 0000000..5a43c71 --- /dev/null +++ b/kontor-echo/internal/helpers/auth.go @@ -0,0 +1,7 @@ +package helpers + +import "strings" + +func EmptyUserPass(username, password string) bool { + return strings.Trim(username, " ") == "" || strings.Trim(password, " ") == "" +} diff --git a/kontor-echo/internal/helpers/token.go b/kontor-echo/internal/helpers/token.go new file mode 100644 index 0000000..7a85e88 --- /dev/null +++ b/kontor-echo/internal/helpers/token.go @@ -0,0 +1,88 @@ +package helpers + +import ( + "fmt" + "strings" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/labstack/echo/v5" + "github.com/spf13/viper" +) + +func GenerateToken(profile_id string) (string, error) { + + // token_lifespan := viper.GetInt("token_hour_lifespan") + + claims := jwt.MapClaims{ + "name": "Thomas Peetz", + "admin": true, + "authorized": true, + "sub": profile_id, + "exp": time.Now().Add(time.Hour * 72).Unix(), + } + // claims["authorized"] = true + // claims["profile_id"] = profile_id + // claims["exp"] = time.Now().Add(time.Hour * time.Duration(token_lifespan)).Unix() + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + return token.SignedString([]byte(viper.GetString("api_secret"))) + +} + +func TokenValid(c *echo.Context) error { + logger := c.Logger() + + tokenString := ExtractToken(c) + _, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + logger.Info("TokenValid", "Unexpected signing method", token.Header["alg"]) + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(viper.GetString("api_secret")), nil + }) + if err != nil { + return err + } + return nil +} + +func ExtractToken(c *echo.Context) string { + logger := c.Logger() + + token := c.QueryParam("token") + if token != "" { + logger.Info("ExtractToken", "token from query", token) + return token + } + bearerToken := c.Request().Header.Get("Authorization") + if len(strings.Split(bearerToken, " ")) == 2 { + logger.Info("ExtractToken", "token from query", token) + + return strings.Split(bearerToken, " ")[1] + } + return "" +} + +func ExtractTokenID(c *echo.Context) (string, error) { + + tokenString := ExtractToken(c) + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(viper.GetString("api_secret")), nil + }) + if err != nil { + return "", err + } + claims, ok := token.Claims.(jwt.MapClaims) + if ok && token.Valid { + uid, ok := claims["profile_id"].(string) + if !ok { + return "", err + } + return uid, nil + } + return "", nil +} diff --git a/kontor-echo/internal/helpers/url.go b/kontor-echo/internal/helpers/url.go new file mode 100644 index 0000000..4e94074 --- /dev/null +++ b/kontor-echo/internal/helpers/url.go @@ -0,0 +1,69 @@ +package helpers + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log/slog" + "net/http" + "net/url" +) + +func StripUrl(webLink string, keepParam string) string { + u, err := url.Parse(webLink) + if err != nil { + slog.Info("StripUrl", "error", err) + return webLink + } + values := u.Query() + for key := range values { + if key != keepParam { + values.Del(key) + } + } + u.RawQuery = values.Encode() + return u.String() +} + +func GetParam(webLink string, param string) string { + u, err := url.Parse(webLink) + if err != nil { + slog.Info("StripUrl", "error", err) + return webLink + } + values := u.Query() + for key := range values { + if key == param { + return values.Get(key) + } + } + return "" +} + +type OEmbedResponse struct { + Title string `json:"title"` +} + +func GetVideoTitle(videoUrl string) (string, error) { + videoID := GetParam(videoUrl, "v") + // Construct the oEmbed URL + url := fmt.Sprintf("https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=%s&format=json", videoID) + + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var data OEmbedResponse + if err := json.Unmarshal(body, &data); err != nil { + return "", err + } + + return data.Title, nil +} diff --git a/kontor-echo/internal/models/mail.go b/kontor-echo/internal/models/mail.go new file mode 100644 index 0000000..c5e630d --- /dev/null +++ b/kontor-echo/internal/models/mail.go @@ -0,0 +1,73 @@ +package models + +import ( + "kontor-api-echo/internal/helpers" + "time" + + "github.com/uptrace/bun" +) + +type Mail struct { + bun.BaseModel `bun:"table:mail"` + + 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"` + Folder string `bun:"folder"` + Subject string `bun:"subject"` + Body string `bun:"body"` + SendAt time.Time `bun:"sent_date"` + ReceivedAt time.Time `bun:"received_date"` +} + +type MailDTO 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"` + Folder string `json:"folder"` + Subject string `json:"subject"` + Body string `json:"body"` + SendAt time.Time `json:"sent_date"` + ReceivedAt time.Time `json:"received_date"` +} + +func (dto MailDTO) ConvertDTOToModel() Mail { + model := Mail{ + ID: dto.ID, + CreatedAt: dto.CreatedAt.Time, + UpdatedAt: dto.UpdatedAt.Time, + DeletedAt: dto.DeletedAt, + Version: dto.Version, + Folder: dto.Folder, + Subject: dto.Subject, + Body: dto.Body, + SendAt: dto.SendAt, + ReceivedAt: dto.ReceivedAt, + } + return model +} + +func ConvertMailsToDtos(mails []Mail) []MailDTO { + dtos := make([]MailDTO, len(mails)) + for i, mail := range mails { + dtos[i] = MailDTO{ + ID: mail.ID, + CreatedAt: helpers.KontorTime{Time: mail.CreatedAt}, + UpdatedAt: helpers.KontorTime{Time: mail.UpdatedAt}, + DeletedAt: mail.DeletedAt, + Version: mail.Version, + Folder: mail.Folder, + Subject: mail.Subject, + Body: mail.Body, + SendAt: mail.SendAt, + ReceivedAt: mail.ReceivedAt, + } + } + return dtos +} + +type MailDTOList []MailDTO diff --git a/kontor-echo/internal/models/mailaccount.go b/kontor-echo/internal/models/mailaccount.go new file mode 100644 index 0000000..68f1075 --- /dev/null +++ b/kontor-echo/internal/models/mailaccount.go @@ -0,0 +1,77 @@ +package models + +import ( + "kontor-api-echo/internal/helpers" + "time" + + "github.com/uptrace/bun" +) + +type MailAccount struct { + bun.BaseModel `bun:"table:mail_account"` + + 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"` + Host string `bun:"host"` + Port int `bun:"port"` + Protocol string `bun:"protocol"` + UserName string `bun:"user_name"` + Password string `bun:"password"` + StartTLS bool `bun:"start_tls"` +} + +type MailAccountDTO 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"` + Host string `json:"host"` + Port int `json:"port"` + Protocol string `json:"protocol"` + UserName string `json:"user_name"` + Password string `json:"password"` + StartTLS bool `json:"start_tls"` +} + +func (dto MailAccountDTO) ConvertDTOToModel() MailAccount { + model := MailAccount{ + ID: dto.ID, + CreatedAt: dto.CreatedAt.Time, + UpdatedAt: dto.UpdatedAt.Time, + DeletedAt: dto.DeletedAt, + Version: dto.Version, + Host: dto.Host, + Port: dto.Port, + Protocol: dto.Protocol, + UserName: dto.UserName, + Password: dto.Password, + StartTLS: dto.StartTLS, + } + return model +} + +func ConvertMailAccountsToDtos(mailaccounts []MailAccount) []MailAccountDTO { + dtos := make([]MailAccountDTO, len(mailaccounts)) + for i, mailaccount := range mailaccounts { + dtos[i] = MailAccountDTO{ + ID: mailaccount.ID, + CreatedAt: helpers.KontorTime{Time: mailaccount.CreatedAt}, + UpdatedAt: helpers.KontorTime{Time: mailaccount.UpdatedAt}, + DeletedAt: mailaccount.DeletedAt, + Version: mailaccount.Version, + Host: mailaccount.Host, + Port: mailaccount.Port, + Protocol: mailaccount.Protocol, + UserName: mailaccount.UserName, + Password: mailaccount.Password, + StartTLS: mailaccount.StartTLS, + } + } + return dtos +} + +type MailAccountDTOList []MailAccountDTO diff --git a/kontor-echo/internal/repository/assignment.go b/kontor-echo/internal/repository/assignment.go index 487d894..74090bf 100644 --- a/kontor-echo/internal/repository/assignment.go +++ b/kontor-echo/internal/repository/assignment.go @@ -4,7 +4,9 @@ import ( "context" "kontor-api-echo/internal/models" "log/slog" + "time" + "github.com/labstack/echo/v5" "github.com/uptrace/bun" ) @@ -19,41 +21,48 @@ func NewAssignmentRepository(db *bun.DB) *AssignmentRepository { 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) + err := repository.db.NewSelect().Model(&assignments).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("AssignmentRepository#FindAll", "count", len(assignments)) return assignments, nil } -func (repository *AssignmentRepository) GetById(context context.Context, id string) (models.Assignment, error) { +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()) + err := repository.db.NewSelect().Model(&assignment).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err } - return assignment, result.Error + return &assignment, err } -func (repository *AssignmentRepository) Import(assignments models.AssignmentDTOList) { +func (repository *AssignmentRepository) Import(dtos 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 { + for index, dto := range dtos { + slog.Info("importing", "index", index, "assignment", dto) + model := dto.ConvertDTOToModel() + existing_item := models.Assignment{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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } diff --git a/kontor-echo/internal/repository/mail.go b/kontor-echo/internal/repository/mail.go new file mode 100644 index 0000000..1419c0c --- /dev/null +++ b/kontor-echo/internal/repository/mail.go @@ -0,0 +1,70 @@ +package repository + +import ( + "context" + "kontor-api-echo/internal/models" + "log/slog" + "time" + + "github.com/labstack/echo/v5" + "github.com/uptrace/bun" +) + +type MailRepository struct { + db *bun.DB +} + +func NewMailRepository(db *bun.DB) *MailRepository { + repository := &MailRepository{db: db} + return repository +} + +func (repository *MailRepository) FindAll(context context.Context) ([]models.Mail, error) { + var models []models.Mail + + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) + + return models, nil +} + +func (repository *MailRepository) GetById(context context.Context, id string) (*models.Mail, error) { + var model = models.Mail{ID: id} + slog.Info("MailRepository#GetById", "id", id) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err + } + return &model, err +} + +func (repository *MailRepository) Import(dtos models.MailDTOList) { + slog.Info("MailRepository#Import") + for index, dto := range dtos { + slog.Info("importing", "index", index, "profile", dto) + model := dto.ConvertDTOToModel() + existing_item := models.Mail{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()) + } + } + } +} diff --git a/kontor-echo/internal/repository/mailaccount.go b/kontor-echo/internal/repository/mailaccount.go new file mode 100644 index 0000000..14d6d00 --- /dev/null +++ b/kontor-echo/internal/repository/mailaccount.go @@ -0,0 +1,70 @@ +package repository + +import ( + "context" + "kontor-api-echo/internal/models" + "log/slog" + "time" + + "github.com/labstack/echo/v5" + "github.com/uptrace/bun" +) + +type MailAccountRepository struct { + db *bun.DB +} + +func (repository *MailAccountRepository) Import(dtos models.MailAccountDTOList) { + slog.Info("MailAccountRepository#Import") + for index, dto := range dtos { + slog.Info("importing", "index", index, "mailaccount", dto) + model := dto.ConvertDTOToModel() + existing_item := models.MailAccount{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 NewMailAccountRepository(db *bun.DB) *MailAccountRepository { + repository := &MailAccountRepository{db: db} + return repository +} + +func (repository *MailAccountRepository) FindAll(context context.Context) ([]models.MailAccount, error) { + var models []models.MailAccount + + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) + + return models, nil +} + +func (repository *MailAccountRepository) GetById(context context.Context, id string) (*models.MailAccount, error) { + var model = models.MailAccount{ID: id} + slog.Info("MailAccountRepository#GetById", "id", id) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err + } + return &model, err +} diff --git a/kontor-echo/internal/repository/media_actor.go b/kontor-echo/internal/repository/media_actor.go index 4284902..6fe4110 100644 --- a/kontor-echo/internal/repository/media_actor.go +++ b/kontor-echo/internal/repository/media_actor.go @@ -5,7 +5,9 @@ import ( "fmt" "kontor-api-echo/internal/models" "log/slog" + "time" + "github.com/labstack/echo/v5" "github.com/uptrace/bun" ) @@ -19,18 +21,21 @@ func (repository *MediaActorRepository) Import(dtos models.MediaActorDTOList) { 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 { + 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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } @@ -42,22 +47,27 @@ func NewMediaActorRepository(db *bun.DB) *MediaActorRepository { } func (repository *MediaActorRepository) FindAll(context context.Context) ([]models.MediaActor, error) { - var actors []models.MediaActor + var models []models.MediaActor - result := repository.db.Find(&actors) - slog.Info("MediaActorRepository#FindAll", "count", result.RowsAffected) + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) - return actors, nil + return models, nil } func (repository *MediaActorRepository) GetById(context context.Context, id string) (*models.MediaActor, error) { - var actor = models.MediaActor{ID: id} + var model = 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()) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err } - return &actor, result.Error + return &model, err } func (repository *MediaActorRepository) Add(context context.Context, url string) (*models.MediaActor, error) { diff --git a/kontor-echo/internal/repository/media_actor_file.go b/kontor-echo/internal/repository/media_actor_file.go index 986d36a..2a582d4 100644 --- a/kontor-echo/internal/repository/media_actor_file.go +++ b/kontor-echo/internal/repository/media_actor_file.go @@ -5,7 +5,9 @@ import ( "fmt" "kontor-api-echo/internal/models" "log/slog" + "time" + "github.com/labstack/echo/v5" "github.com/uptrace/bun" ) @@ -19,18 +21,21 @@ func (repository *MediaActorFileRepository) Import(dtos models.MediaActorFileDTO 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 { + 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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } @@ -42,23 +47,27 @@ func NewMediaActorFileRepository(db *bun.DB) *MediaActorFileRepository { } func (repository *MediaActorFileRepository) FindAll(context context.Context) ([]models.MediaActorFile, error) { - var actor_files []models.MediaActorFile + var models []models.MediaActorFile - result := repository.db.Find(&actor_files) - slog.Info("MediaActorFileRepository#FindAll", "count", result.RowsAffected) + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) - return actor_files, nil + return models, nil } func (repository *MediaActorFileRepository) GetById(context context.Context, id string) (*models.MediaActorFile, error) { - var actorfile = models.MediaActorFile{ID: id} + var model = 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 + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err } - return &actorfile, result.Error + return &model, err } func (repository *MediaActorFileRepository) Add(context context.Context, media_actor_id, media_file_id string) (*models.MediaActorFile, error) { diff --git a/kontor-echo/internal/repository/media_file.go b/kontor-echo/internal/repository/media_file.go index 08c9551..d93668c 100644 --- a/kontor-echo/internal/repository/media_file.go +++ b/kontor-echo/internal/repository/media_file.go @@ -5,7 +5,9 @@ import ( "fmt" "kontor-api-echo/internal/models" "log/slog" + "time" + "github.com/labstack/echo/v5" "github.com/uptrace/bun" ) @@ -19,18 +21,21 @@ func (repository *MediaFileRepository) Import(dtos models.MediaFileDTOList) { 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 { + 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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } @@ -42,23 +47,27 @@ func NewMediaFileRepository(db *bun.DB) *MediaFileRepository { } func (repository *MediaFileRepository) FindAll(context context.Context) ([]models.MediaFile, error) { - var files []models.MediaFile + var models []models.MediaFile - result := repository.db.Find(&files) - slog.Info("MediaFileRepository#FindAll", "count", result.RowsAffected) + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) - return files, nil + return models, nil } func (repository *MediaFileRepository) GetById(context context.Context, id string) (*models.MediaFile, error) { - var file = models.MediaFile{ID: id} + var model = 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 + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err } - return &file, result.Error + return &model, err } func (repository *MediaFileRepository) Add(context context.Context, url string) (*models.MediaFile, error) { diff --git a/kontor-echo/internal/repository/media_lofi.go b/kontor-echo/internal/repository/media_lofi.go index c07584d..20d4ab6 100644 --- a/kontor-echo/internal/repository/media_lofi.go +++ b/kontor-echo/internal/repository/media_lofi.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" "errors" - "fmt" "kontor-api-echo/internal/helpers" "kontor-api-echo/internal/models" "log/slog" @@ -25,18 +24,21 @@ func (repository *MediaLoFiRepository) Import(dtos models.MediaLoFiDTOList) { 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 { + 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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } @@ -48,41 +50,37 @@ func NewMediaLoFiRepository(db *bun.DB) *MediaLoFiRepository { } func (repository *MediaLoFiRepository) FindAll(context context.Context) ([]models.MediaLoFi, error) { - var lofis []models.MediaLoFi + var models []models.MediaLoFi - err := repository.db.NewSelect().Model(&lofis).Scan(context) + err := repository.db.NewSelect().Model(&models).Scan(context) if err != nil { slog.Info(err.Error()) return nil, echo.ErrInternalServerError } - slog.Info("MediaLoFiRepository#FindAll", "count", len(lofis)) + slog.Info("MailRepository#FindAll", "count", len(models)) - return lofis, nil + return models, nil } func (repository *MediaLoFiRepository) GetById(context context.Context, id string) (*models.MediaLoFi, error) { - var lofi = models.MediaLoFi{ID: id} + var model = models.MediaLoFi{ID: id} slog.Info("MediaLoFiRepository#GetById", "id", id) - err := repository.db.NewSelect().Model(&lofi).Where("id = ?", id).Scan(context) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) if err != nil { - slog.Info("MediaLoFiRepository#GetById", "error", err.Error()) + slog.Info("AssignmentRepository#GetById", "error", err.Error()) return nil, err } - return &lofi, err + return &model, 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) { + var model models.MediaLoFi + err := repository.db.NewSelect().Model(&model).Where("url = ?", url).Scan(context) + if errors.Is(err, sql.ErrNoRows) { slog.Info("MediaLoFiRepository#Add URL not found", "url", webLink) - lofi = models.MediaLoFi{ + lofi := models.MediaLoFi{ ID: uuid.NewString(), CreatedAt: time.Now(), UpdatedAt: time.Now(), @@ -94,32 +92,32 @@ func (repository *MediaLoFiRepository) Add(context context.Context, url string) 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 + _, add_error := repository.db.NewInsert().Model(&model).Exec(context) + if add_error != nil { + slog.Info("add new MediaLofi", "error", add_error) + return nil, add_error } slog.Info("add new MediaLofi", "lofi", lofi) return &lofi, nil + } else { + slog.Info("search for existing url", "lofi", model) + return &model, 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} + var model = models.MediaLoFi{ID: update.ID} + model.Update(update) 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 + _, err := repository.db.NewUpdate().Model(&model). + Set("updated_at = ? ", time.Now). + Where("id = ?", update.ID). + Exec(context) + if err != nil { + slog.Info("MediaLoFiRepository#Update", "error", err.Error()) } - lofi.Update(update) - repository.db.Save(&lofi) - return &lofi, nil + return &model, nil } func (repository *MediaLoFiRepository) Delete(context context.Context, id string) error { diff --git a/kontor-echo/internal/repository/media_music.go b/kontor-echo/internal/repository/media_music.go index b082a63..fb04fdd 100644 --- a/kontor-echo/internal/repository/media_music.go +++ b/kontor-echo/internal/repository/media_music.go @@ -4,13 +4,13 @@ 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/v5" "github.com/uptrace/bun" ) @@ -24,18 +24,21 @@ func (repository *MediaMusicRepository) Import(dtos models.MediaMusicDTOList) { 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 { + 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") - result := repository.db.Create(&model) - if result.Error != nil { - slog.Info("error during import", "error", result.Error.Error()) + _, 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") - result := repository.db.Save(&model) - if result.Error != nil { - slog.Info("error during updating", "error", result.Error.Error()) + _, 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()) } } } @@ -47,36 +50,37 @@ func NewMediaMusicRepository(db *bun.DB) *MediaMusicRepository { } func (repository *MediaMusicRepository) FindAll(context context.Context) ([]models.MediaMusic, error) { - var musics []models.MediaMusic + var models []models.MediaMusic - result := repository.db.Find(&musics) - slog.Info("MediaMusicRepository#FindAll", "count", result.RowsAffected) + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) - return musics, nil + return models, nil } func (repository *MediaMusicRepository) GetById(context context.Context, id string) (*models.MediaMusic, error) { - var music = models.MediaMusic{ID: id} + var model = 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()) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err } - return &music, result.Error + return &model, err } 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) { + var model models.MediaMusic + err := repository.db.NewSelect().Model(&model).Where("url = ?", url).Scan(context) + if errors.Is(err, sql.ErrNoRows) { slog.Info("MediaMusicRepository#Add URL not found", "url", webLink) - music = models.MediaMusic{ + music := models.MediaMusic{ ID: uuid.NewString(), CreatedAt: time.Now(), UpdatedAt: time.Now(), @@ -88,32 +92,32 @@ func (repository *MediaMusicRepository) Add(context context.Context, url string) 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 + _, add_error := repository.db.NewInsert().Model(&model).Exec(context) + if add_error != nil { + slog.Info("add new MediaMusic", "error", add_error) + return nil, add_error } - slog.Info("add new MediaMusic", "music", music) + slog.Info("add new MediaMusic", "lofi", music) return &music, nil + } else { + slog.Info("search for existing url", "lofi", model) + return &model, 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 + var model = models.MediaMusic{ID: update.ID} + model.Update(update) + slog.Info("MediaLoFiRepository#Update", "id", update.ID) + _, err := repository.db.NewUpdate().Model(&model). + Set("updated_at = ? ", time.Now). + Where("id = ?", update.ID). + Exec(context) + if err != nil { + slog.Info("MediaLoFiRepository#Update", "error", err.Error()) } - music.Update(update) - repository.db.Save(&music) - return &music, nil + return &model, nil } func (repository *MediaMusicRepository) Delete(context context.Context, id string) error { diff --git a/kontor-echo/internal/repository/media_video.go b/kontor-echo/internal/repository/media_video.go index 74041fa..95df8db 100644 --- a/kontor-echo/internal/repository/media_video.go +++ b/kontor-echo/internal/repository/media_video.go @@ -2,10 +2,14 @@ package repository import ( "context" + "database/sql" + "errors" + "kontor-api-echo/internal/helpers" "kontor-api-echo/internal/models" "log/slog" "time" + "github.com/google/uuid" "github.com/labstack/echo/v5" "github.com/uptrace/bun" ) @@ -68,42 +72,37 @@ func (repository *MediaVideoRepository) GetById(context context.Context, id stri return &video, nil } -// 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) Add(context context.Context, url string) (*models.MediaVideo, error) { + slog.Info("MediaVideoRepository#Add", "url", url) + webLink := helpers.StripUrl(url, "v") + var model models.MediaVideo + err := repository.db.NewSelect().Model(&model).Where("url = ?", url).Scan(context) + if errors.Is(err, sql.ErrNoRows) { + slog.Info("MediaMusicRepository#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_error := repository.db.NewInsert().Model(&model).Exec(context) + if add_error != nil { + slog.Info("add new MediaMusic", "error", add_error) + return nil, add_error + } + slog.Info("add new MediaMusic", "lofi", video) + return &video, nil + } else { + slog.Info("search for existing url", "lofi", model) + return &model, nil + } +} func (repository *MediaVideoRepository) Update(context context.Context, update models.MediaVideoDTO) (*models.MediaVideo, error) { slog.Info("MediaVideoRepository#Update", "video", update) diff --git a/kontor-echo/internal/repository/profile.go b/kontor-echo/internal/repository/profile.go index d3d498a..7d68260 100644 --- a/kontor-echo/internal/repository/profile.go +++ b/kontor-echo/internal/repository/profile.go @@ -31,9 +31,10 @@ func (repository *ProfileRepository) FindAll(context context.Context) ([]models. return profiles, nil } -func (repository *ProfileRepository) FindProfileByEmail(context context.Context, email string) (*models.Profile, error) { +func (repository *ProfileRepository) FindProfileByEmail(email string) (*models.Profile, error) { var profile models.Profile slog.Info("MediaArticleRepository#GetById", "email", email) + context := context.Background() err := repository.db.NewSelect().Model(&profile).Where("email = ?", email).Scan(context) if err != nil { diff --git a/kontor-echo/internal/repository/token.go b/kontor-echo/internal/repository/token.go new file mode 100644 index 0000000..c8b6d93 --- /dev/null +++ b/kontor-echo/internal/repository/token.go @@ -0,0 +1,70 @@ +package repository + +import ( + "context" + "kontor-api-echo/internal/models" + "log/slog" + "time" + + "github.com/labstack/echo/v5" + "github.com/uptrace/bun" +) + +type TokenRepository struct { + db *bun.DB +} + +func (repository *TokenRepository) Import(dtos models.TokenDTOList) { + slog.Info("TokenRepository#Import") + for index, dto := range dtos { + slog.Info("importing", "index", index, "video", dto) + model := dto.ConvertDTOToModel() + existing_item := models.Token{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 NewTokenRepository(db *bun.DB) *TokenRepository { + repository := &TokenRepository{db: db} + return repository +} + +func (repository *TokenRepository) FindAll(context context.Context) ([]models.Token, error) { + var models []models.Token + + err := repository.db.NewSelect().Model(&models).Scan(context) + if err != nil { + slog.Info(err.Error()) + return nil, echo.ErrInternalServerError + } + slog.Info("MailRepository#FindAll", "count", len(models)) + + return models, nil +} + +func (repository *TokenRepository) GetById(context context.Context, id string) (*models.Token, error) { + var model = models.Token{ID: id} + slog.Info("TokenRepository#GetById", "id", id) + err := repository.db.NewSelect().Model(&model).Where("id = ?", id).Scan(context) + if err != nil { + slog.Info("AssignmentRepository#GetById", "error", err.Error()) + return nil, err + } + return &model, err +} diff --git a/kontor-echo/internal/router/router.go b/kontor-echo/internal/router/router.go index 82c4568..7f35ce8 100644 --- a/kontor-echo/internal/router/router.go +++ b/kontor-echo/internal/router/router.go @@ -1,34 +1,154 @@ package router import ( + "html/template" + "io" + "kontor-api-echo/assets" + "kontor-api-echo/internal/config" "kontor-api-echo/internal/handlers" + "kontor-api-echo/templates" "log/slog" + "os" + echojwt "github.com/labstack/echo-jwt/v5" "github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" ) +type Template struct { + templates *template.Template +} + +func (t *Template) Render(c *echo.Context, w io.Writer, name string, data any) error { + return t.templates.ExecuteTemplate(w, name, data) +} + 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" - } + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + + e.Use(middleware.Recover()) e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{ - LogStatus: true, LogURI: true, + LogStatus: true, HandleError: true, - Skipper: skipper, + Skipper: func(c *echo.Context) bool { + // Skip health check endpoint + return c.Path() == "/health" + }, 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()) + if v.Error != nil { + logger.Error("request failed", "uri", v.URI, "status", v.Status, "error", v.Error) + return nil } + logger.Info("request", "uri", v.URI, "status", v.Status) return nil }, })) + + e.StaticFS("/public", echo.MustSubFS(assets.StaticFiles, "assets")) + + templ := template.Must(template.New("").ParseFS(templates.TemplateFiles, "layouts/*.html", "pages/*.html")) + + t := &Template{ + templates: templ, + } + + e.Renderer = t + + e.GET("/health", handlers.Health) + e.GET("/", handlers.Index) + e.GET("/login", admin.AuthHandler.LoginPage) + e.POST("/login", admin.AuthHandler.LoginPost) + e.GET("/logout", admin.AuthHandler.LogoutPage) + + mediaGroup := e.Group("/media") + //mediaGroup.Use(middleware.AuthRequired()) + mediaGroup.GET("/actors", media.MediaActorHandler.ListPage) + mediaGroup.GET("/actors/:id", media.MediaActorHandler.EditPage) + mediaGroup.POST("/actors/:id", media.MediaActorHandler.UpdatePage) + mediaGroup.GET("/articles", media.MediaArticleHandler.ListPage) + mediaGroup.GET("/files", media.MediaFileHandler.ListPage) + mediaGroup.GET("/files/edit/:id", media.MediaFileHandler.EditPage) + mediaGroup.POST("/files/edit/:id", media.MediaFileHandler.UpdatePage) + mediaGroup.GET("/files/delete/:id", media.MediaFileHandler.DeletePage) + mediaGroup.GET("/videos", media.MediaVideoHandler.ListPage) + mediaGroup.GET("/videos/edit/:id", media.MediaVideoHandler.EditPage) + mediaGroup.POST("/videos/edit/:id", media.MediaVideoHandler.UpdatePage) + mediaGroup.GET("/videos/delete/:id", media.MediaVideoHandler.DeletePage) + mediaGroup.GET("/lofis", media.MediaLoFiHandler.ListPage) + mediaGroup.GET("/lofis/edit", media.MediaLoFiHandler.EditPage) + mediaGroup.GET("/lofis/edit/:id", media.MediaLoFiHandler.EditPage) + mediaGroup.POST("/lofis/edit/:id", media.MediaLoFiHandler.UpdatePage) + mediaGroup.GET("/lofis/review/:id", media.MediaLoFiHandler.ChangeReviewPage) + mediaGroup.GET("/lofis/delete/:id", media.MediaLoFiHandler.DeletePage) + mediaGroup.GET("/musics", media.MediaMusicHandler.ListPage) + mediaGroup.GET("/musics/edit/:id", media.MediaMusicHandler.EditPage) + mediaGroup.POST("/musics/edit/:id", media.MediaMusicHandler.UpdatePage) + mediaGroup.GET("/musics/delete/:id", media.MediaMusicHandler.DeletePage) + + api := e.Group("/api") + api.POST("/login", admin.AuthHandler.Login) + + v1 := api.Group("/v1") + { + secured := v1.Group("") + secured.Use(echojwt.WithConfig(echojwt.Config{SigningKey: config.ServerConfig.ApiSecret})) + //secured.Use(middleware.JWT(admin.Secret)) + // secured.GET("admin/mailaccounts", admin.MailAccountHandler.List) + // secured.GET("user/profiles", admin.ProfileHandler.List) + // secured.GET("user/permissions", admin.PermissionHandler.List) + // secured.GET("user/assignments", admin.AssignmentHandler.List) + // secured.GET("user/mails", admin.MailHandler.List) + // secured.GET("user/tokens", admin.TokenHandler.List) + // secured.GET("tysc/sports", tysc.SportHandler.List) + // secured.GET("tysc/sports/:id", tysc.SportHandler.Get) + // secured.GET("tysc/players", tysc.PlayerHandler.List) + // secured.GET("tysc/teams", tysc.TeamHandler.List) + // secured.GET("tysc/positions", tysc.PositionHandler.List) + // secured.GET("tysc/roosters", tysc.RoosterHandler.List) + // secured.GET("tysc/vendors", tysc.VendorHandler.List) + // secured.GET("tysc/cardsets", tysc.CardSetHandler.List) + // secured.GET("tysc/cards", tysc.CardHandler.List) + // secured.GET("bookshelf/articles", bookshelf.ArticleHandler.List) + // secured.GET("bookshelf/publishers", bookshelf.BookshelfPublisherHandler.List) + // secured.GET("bookshelf/books", bookshelf.BookHandler.List) + // secured.GET("bookshelf/authors", bookshelf.AuthorHandler.List) + // secured.GET("bookshelf/articleauthors", bookshelf.ArticleAuthorHandler.List) + // secured.GET("bookshelf/bookauthors", bookshelf.BookAuthorHandler.List) + // secured.GET("comics/comics", comics.ComicHandler.List) + // secured.GET("comics/publishers", comics.PublisherHandler.List) + // secured.GET("comics/artists", comics.ArtistHandler.List) + // secured.GET("comics/issues", comics.IssueHandler.List) + // secured.GET("comics/tradepaperbacks", comics.TradePaperbackHandler.List) + // secured.GET("comics/worktypes", comics.WorkTypeHandler.List) + // secured.GET("comics/volumes", comics.VolumeHandler.List) + // secured.GET("comics/storyarcs", comics.StoryArcHandler.List) + // secured.GET("comics/comicworks", comics.ComicworkHandler.List) + // secured.GET("comics/issueworks", comics.IssueworkHandler.List) + mediaGroup := secured.Group("media") + mediaGroup.GET("/files", media.MediaFileHandler.List) + mediaGroup.POST("/files", media.MediaFileHandler.Add) + // mediaGroup.GET("/videos", media.MediaVideoHandler.List) + // mediaGroup.GET("/lofis", media.MediaLoFiHandler.List) + // mediaGroup.POST("/lofis", media.MediaLoFiHandler.Add) + // mediaGroup.GET("/lofis/:id", media.MediaLoFiHandler.Get) + // mediaGroup.POST("/lofis/:id", media.MediaLoFiHandler.Update) + // mediaGroup.DELETE("/lofis/:id", media.MediaLoFiHandler.Delete) + // mediaGroup.POST("/musics", media.MediaMusicHandler.Add) + // mediaGroup.GET("/musics/:id", media.MediaMusicHandler.Get) + // mediaGroup.POST("/musics/:id", media.MediaMusicHandler.Update) + // mediaGroup.DELETE("/musics/:id", media.MediaMusicHandler.Delete) + // mediaGroup.GET("/actors", media.MediaActorHandler.List) + // mediaGroup.POST("/actors", media.MediaActorHandler.Add) + // mediaGroup.GET("/actors/:id", media.MediaActorHandler.Get) + // mediaGroup.DELETE("/actors/:id", media.MediaActorHandler.Delete) + // mediaGroup.GET("/actorfiles", media.MediaActorFileHandler.List) + // mediaGroup.POST("/actorfiles", media.MediaActorFileHandler.Add) + // mediaGroup.DELETE("/actorfiles", media.MediaActorFileHandler.Delete) + } + return e } diff --git a/kontor-echo/internal/service/assignment.go b/kontor-echo/internal/service/assignment.go index dc7dc92..40d923d 100644 --- a/kontor-echo/internal/service/assignment.go +++ b/kontor-echo/internal/service/assignment.go @@ -21,7 +21,7 @@ func (service *AssignmentService) List(context context.Context) ([]models.Assign return service.repository.FindAll(context) } -func (service *AssignmentService) Get(context context.Context, id string) (models.Assignment, error) { +func (service *AssignmentService) Get(context context.Context, id string) (*models.Assignment, error) { slog.Info("AssignmentService#Get") return service.repository.GetById(context, id) } diff --git a/kontor-echo/internal/service/auth.go b/kontor-echo/internal/service/auth.go new file mode 100644 index 0000000..3ba1038 --- /dev/null +++ b/kontor-echo/internal/service/auth.go @@ -0,0 +1,47 @@ +package service + +import ( + "kontor-api-echo/internal/helpers" + "kontor-api-echo/internal/repository" + + "golang.org/x/crypto/bcrypt" +) + +type AuthService struct { + repository *repository.ProfileRepository +} + +func NewAuthService(repository *repository.ProfileRepository) *AuthService { + service := &AuthService{repository: repository} + return service +} + +func VerifyPassword(password, hashedPassword string) error { + return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) +} + +func (service *AuthService) LoginCheck(email string, password string) (string, error) { + + var err error + + profile, err := service.repository.FindProfileByEmail(email) + + if err != nil { + return "", err + } + + err = VerifyPassword(password, profile.Password) + + if err != nil && err == bcrypt.ErrMismatchedHashAndPassword { + return "", err + } + + token, err := helpers.GenerateToken(profile.ID) + + if err != nil { + return "", err + } + + return token, nil + +} diff --git a/kontor-echo/internal/service/mail.go b/kontor-echo/internal/service/mail.go new file mode 100644 index 0000000..4f64a70 --- /dev/null +++ b/kontor-echo/internal/service/mail.go @@ -0,0 +1,27 @@ +package service + +import ( + "context" + "kontor-api-echo/internal/models" + "kontor-api-echo/internal/repository" + "log/slog" +) + +type MailService struct { + repository *repository.MailRepository +} + +func NewMailService(repo *repository.MailRepository) *MailService { + service := &MailService{repository: repo} + return service +} + +func (service *MailService) List(context context.Context) ([]models.Mail, error) { + slog.Info("MailService#List") + return service.repository.FindAll(context) +} + +func (service *MailService) Get(context context.Context, id string) (*models.Mail, error) { + slog.Info("MailService#Get") + return service.repository.GetById(context, id) +} diff --git a/kontor-echo/internal/service/mailaccount.go b/kontor-echo/internal/service/mailaccount.go new file mode 100644 index 0000000..791200c --- /dev/null +++ b/kontor-echo/internal/service/mailaccount.go @@ -0,0 +1,27 @@ +package service + +import ( + "context" + "kontor-api-echo/internal/models" + "kontor-api-echo/internal/repository" + "log/slog" +) + +type MailAccountService struct { + repository *repository.MailAccountRepository +} + +func NewMailAccountService(repo *repository.MailAccountRepository) *MailAccountService { + service := &MailAccountService{repository: repo} + return service +} + +func (service *MailAccountService) List(context context.Context) ([]models.MailAccount, error) { + slog.Info("MailAccountService#List") + return service.repository.FindAll(context) +} + +func (service *MailAccountService) Get(context context.Context, id string) (*models.MailAccount, error) { + slog.Info("MailAccountService#Get") + return service.repository.GetById(context, id) +} diff --git a/kontor-echo/internal/service/token.go b/kontor-echo/internal/service/token.go new file mode 100644 index 0000000..64123f1 --- /dev/null +++ b/kontor-echo/internal/service/token.go @@ -0,0 +1,27 @@ +package service + +import ( + "context" + "kontor-api-echo/internal/models" + "kontor-api-echo/internal/repository" + "log/slog" +) + +type TokenService struct { + repository *repository.TokenRepository +} + +func NewTokenService(repo *repository.TokenRepository) *TokenService { + service := &TokenService{repository: repo} + return service +} + +func (service *TokenService) List(context context.Context) ([]models.Token, error) { + slog.Info("TokenService#List") + return service.repository.FindAll(context) +} + +func (service *TokenService) Get(context context.Context, id string) (*models.Token, error) { + slog.Info("TokenService#Get") + return service.repository.GetById(context, id) +} diff --git a/kontor-echo/pkg/handler/health.go b/kontor-echo/pkg/handler/health.go deleted file mode 100644 index d97ce24..0000000 --- a/kontor-echo/pkg/handler/health.go +++ /dev/null @@ -1,17 +0,0 @@ -package handler - -import ( - "net/http" - - "github.com/labstack/echo/v4" -) - -type Status struct { - Status string `json:"status"` -} - -func GetHealth(c echo.Context) error { - status := new(Status) - status.Status = "ok" - return c.JSON(http.StatusOK, status) -} diff --git a/kontor-echo/pkg/handler/media.go b/kontor-echo/pkg/handler/media.go deleted file mode 100644 index 46e7eba..0000000 --- a/kontor-echo/pkg/handler/media.go +++ /dev/null @@ -1,67 +0,0 @@ -package handler - -import ( - "context" - "fmt" - "kontor-api-echo/pkg/schema" - "log" - "net/http" - "time" - - "github.com/google/uuid" - "github.com/labstack/echo/v4" - "github.com/uptrace/bun" -) - -func SetupMediaRoutes(api *echo.Group) { - media := api.Group("/media") - media.GET("/files", GetAllFiles) - media.POST("/files", AddFile) -} - -func GetAllFiles(c echo.Context) error { - var files []schema.MediaFile - var err error - var db *bun.DB - ctx := context.Background() - - db, err = schema.GetDatabase() - if err != nil { - log.Fatal(err) - } - err = db.NewSelect().Model(&files).Relation("MediaActorFiles").Scan(ctx) - if err != nil { - log.Fatal(err) - return echo.ErrInternalServerError - } - - return c.JSON(http.StatusOK, files) -} - -type Link struct { - URL string `json:"url"` -} - -func AddFile(c echo.Context) error { - var err error - var db *bun.DB - ctx := context.Background() - link := new(Link) - if err = c.Bind(link); err != nil { - return err - } - log.Printf("URL %s has been sent", link) - - db, err = schema.GetDatabase() - if err != nil { - log.Fatal(err) - } - id := uuid.NewString() - timestamp := time.Now() - mediafile := &schema.MediaFile{ID: id, CreatedAt: timestamp, UpdatedAt: timestamp, WebLink: fmt.Sprintf("%s", link), Version: 1, ShouldDownload: true, Review: true} - _, err = db.NewInsert().Model(mediafile).Exec(ctx) - if err != nil { - return err - } - return c.String(http.StatusCreated, "Link created") -} diff --git a/kontor-echo/templates/layouts/footer.html b/kontor-echo/templates/layouts/footer.html new file mode 100644 index 0000000..8d9d7f2 --- /dev/null +++ b/kontor-echo/templates/layouts/footer.html @@ -0,0 +1,9 @@ +{{ define "footer" }} +
+
+ {{ .version }} +
+
+ + +{{ end }} diff --git a/kontor-echo/templates/layouts/head.html b/kontor-echo/templates/layouts/head.html new file mode 100644 index 0000000..6aacaa5 --- /dev/null +++ b/kontor-echo/templates/layouts/head.html @@ -0,0 +1,13 @@ +{{ define "head" }} + + + + + + + + + + {{ .title }} + +{{ end }} diff --git a/kontor-echo/templates/layouts/main.html b/kontor-echo/templates/layouts/main.html new file mode 100644 index 0000000..2235cf5 --- /dev/null +++ b/kontor-echo/templates/layouts/main.html @@ -0,0 +1,24 @@ +{{ define "main" }} + + + + + + + + {{ .title }} + + + +
+ {{ template "navbar" . }} + {{ template "content" . }} + + + +{{ end }} diff --git a/kontor-echo/templates/layouts/navbar.html b/kontor-echo/templates/layouts/navbar.html new file mode 100644 index 0000000..bc15f62 --- /dev/null +++ b/kontor-echo/templates/layouts/navbar.html @@ -0,0 +1,88 @@ +{{ define "navbar" }} + +
+ +
+ + + + +{{ end }} diff --git a/kontor-echo/templates/pages/comics.html b/kontor-echo/templates/pages/comics.html new file mode 100644 index 0000000..40b5ad4 --- /dev/null +++ b/kontor-echo/templates/pages/comics.html @@ -0,0 +1,59 @@ +{{ define "comics" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+ + + + + +
+
+
+
+ + + + + + + + + + + {{ range .comics }} + + + {{ if .Publisher }} + + {{ else }} + + {{ end }} + + + + + {{ end }} + +
TitlePublisherCompletedActions
{{.Title}}{{.Publisher.Name}}Publisher not set + {{ if .Completed }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/home.html b/kontor-echo/templates/pages/home.html new file mode 100644 index 0000000..efef156 --- /dev/null +++ b/kontor-echo/templates/pages/home.html @@ -0,0 +1,27 @@ +{{ define "home" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+
+

Hauptinhalt

+

{{ .message }}

+
+
+ +
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/lofi.html b/kontor-echo/templates/pages/lofi.html new file mode 100644 index 0000000..30d0d5d --- /dev/null +++ b/kontor-echo/templates/pages/lofi.html @@ -0,0 +1,69 @@ +{{ define "lofi" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

Media Lofi

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+
+ + + + + +
+
+
+ + + + + + + + + {{ range .lofis }} + + + {{ if .WebLink }} + + {{ else }} + + {{ end }} + + + + + {{ end }} + +
TitleWeblinkReviewActions
{{.Title}}{{.WebLink}}WebLink not set + {{ if .Review }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/lofi_detail.html b/kontor-echo/templates/pages/lofi_detail.html new file mode 100644 index 0000000..717509b --- /dev/null +++ b/kontor-echo/templates/pages/lofi_detail.html @@ -0,0 +1,54 @@ +{{ define "lofi_detail" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

Media Lofi

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+ {{ if .Errors }} +
{{ .Errors }}
+ {{ end }} +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/login.html b/kontor-echo/templates/pages/login.html new file mode 100644 index 0000000..b0a9cc2 --- /dev/null +++ b/kontor-echo/templates/pages/login.html @@ -0,0 +1,36 @@ +{{ define "login" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+ {{ if .content }} +
{{ .message }}
+ {{ end}} + +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/media_actor.html b/kontor-echo/templates/pages/media_actor.html new file mode 100644 index 0000000..7f3001a --- /dev/null +++ b/kontor-echo/templates/pages/media_actor.html @@ -0,0 +1,54 @@ +{{ define "actor_detail" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

Media Actor

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+ {{ if .Errors }} +
{{ .Errors }}
+ {{ end }} +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/media_actors.html b/kontor-echo/templates/pages/media_actors.html new file mode 100644 index 0000000..79e992c --- /dev/null +++ b/kontor-echo/templates/pages/media_actors.html @@ -0,0 +1,41 @@ +{{ define "media_actors" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

Media Actors

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+
+ + + +
+
+
+ {{ range .actors }} +
+
+
{{.Name}}
+ Read more +
+
+ {{ end }} +
+
+ + +{{ end }} diff --git a/kontor-echo/templates/pages/media_detail.html b/kontor-echo/templates/pages/media_detail.html new file mode 100644 index 0000000..293e7ff --- /dev/null +++ b/kontor-echo/templates/pages/media_detail.html @@ -0,0 +1,54 @@ +{{ define "media_detail" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

{{.message}}

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+ {{ if .Errors }} +
{{ .Errors }}
+ {{ end }} +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/media_links.html b/kontor-echo/templates/pages/media_links.html new file mode 100644 index 0000000..4dad134 --- /dev/null +++ b/kontor-echo/templates/pages/media_links.html @@ -0,0 +1,71 @@ +{{ define "media_links" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+ + + + + +
+
+
+
+ + + + + + + + + + + + {{ range .media_links }} + + + {{ if .WebLink }} + + {{ else }} + + {{ end }} + + + + + + {{ end }} + +
TitleWeblinkReviewDownloadActions
{{.Title}}{{.WebLink}}no link + {{ if .Review }} + true + {{ else }} + true + {{ end }} + + {{ if .ShouldDownload }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/mediafiles.html b/kontor-echo/templates/pages/mediafiles.html new file mode 100644 index 0000000..59bcbed --- /dev/null +++ b/kontor-echo/templates/pages/mediafiles.html @@ -0,0 +1,71 @@ +{{ define "mediafiles" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+ + + + + +
+
+
+
+ + + + + + + + + + + + {{ range .mediafiles }} + + + {{ if .WebLink }} + + {{ else }} + + {{ end }} + + + + + + {{ end }} + +
TitleWeblinkReviewDownloadActions
{{.Title}}{{.WebLink}}no link + {{ if .Review }} + true + {{ else }} + true + {{ end }} + + {{ if .ShouldDownload }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/mediavideos.html b/kontor-echo/templates/pages/mediavideos.html new file mode 100644 index 0000000..88ce5e8 --- /dev/null +++ b/kontor-echo/templates/pages/mediavideos.html @@ -0,0 +1,71 @@ +{{ define "mediavideos" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+ + + + + +
+
+
+
+ + + + + + + + + + + + {{ range .mediavideos }} + + + {{ if .WebLink }} + + {{ else }} + + {{ end }} + + + + + + {{ end }} + +
TitleWeblinkReviewDownloadActions
{{.Title}}{{.WebLink}}no link + {{ if .Review }} + true + {{ else }} + true + {{ end }} + + {{ if .ShouldDownload }} + true + {{ else }} + true + {{ end }} + EditDelete
+
+
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/pages/publishers.html b/kontor-echo/templates/pages/publishers.html new file mode 100644 index 0000000..cd1e982 --- /dev/null +++ b/kontor-echo/templates/pages/publishers.html @@ -0,0 +1,42 @@ +{{ define "publishers" }} + + + {{ template "head" . }} + + + {{ template "navbar" . }} +
+
+
+

Comic Publishers

+

Hier steht der wesentliche Inhalt der Seite.

+
+
+ +
+
+
+
+ + + +
+
+
+ {{ range .publishers }} +
+
+
{{.Name}}
+ Read more +
+
+ {{ end }} +
+
+ {{ template "footer" . }} + + +{{ end }} diff --git a/kontor-echo/templates/templates.go b/kontor-echo/templates/templates.go new file mode 100644 index 0000000..f3737ba --- /dev/null +++ b/kontor-echo/templates/templates.go @@ -0,0 +1,8 @@ +package templates + +import ( + "embed" +) + +//go:embed layouts/* pages/* +var TemplateFiles embed.FS