26 Commits

Author SHA1 Message Date
tpeetz 79653d2c43 WIP: add missing handlers, services nd repositories
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Gitea Actions Demo / build-and-test (push) Failing after 12s
2026-11-06 21:20:24 +01:00
Thomas Peetz 50e2da8a66 update kontor-echo
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
Gitea Actions Demo / build-and-test (push) Failing after 14s
2026-11-06 16:48:15 +01:00
Thomas Peetz 9a7219e106 update echo to v5 and prepare kontor-echo to use handlers, repository and service
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
Gitea Actions Demo / build-and-test (push) Failing after 11s
2026-11-06 11:11:04 +01:00
tpeetz 20e141b73e move media models
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
Gitea Actions Demo / build-and-test (push) Failing after 1m3s
2026-11-06 10:29:48 +01:00
tpeetz f75dd3a9fb Fix Media Articlrd
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Gitea Actions Demo / build-and-test (push) Failing after 1m2s
2026-11-01 04:06:17 +01:00
tpeetz f9b7e20841 Fix Listign of MediaArticle 2026-11-01 02:32:18 +01:00
Thomas Peetz b0cc5f0cd1 add methods in Repository and Model for importing data
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Gitea Actions Demo / build-and-test (push) Failing after 14m37s
2026-10-30 09:15:19 +01:00
Thomas Peetz 8706b3880f add methods in Repository an dModel for importing data
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
Gitea Actions Demo / build-and-test (push) Failing after 13m11s
2026-10-30 00:19:25 +01:00
Thomas Peetz 0750621b96 add methods in Repository and Model for importing data
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
Gitea Actions Demo / build-and-test (push) Failing after 19m24s
2026-10-29 17:40:54 +01:00
Thomas Peetz 2aeba70906 add Database type to cli and server config
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 12s
Gitea Actions Demo / build-and-test (push) Failing after 19m54s
2026-10-29 00:14:54 +01:00
Thomas Peetz ab166fc075 add templates media_links.html and media_detail.html for kontor-gin
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
Gitea Actions Demo / build-and-test (push) Failing after 12m17s
2026-10-28 18:39:34 +01:00
Thomas Peetz 4c681c33dc add MediaMusic
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Gitea Actions Demo / build-and-test (push) Failing after 20m33s
2026-10-27 16:15:34 +01:00
Thomas Peetz 72c08f9731 add method to handlers
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
Gitea Actions Demo / build-and-test (push) Failing after 29m54s
2026-10-26 22:41:15 +01:00
Thomas Peetz 9ab4f2103f add put method to kontor-api
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
Gitea Actions Demo / build-and-test (push) Failing after 14m45s
2026-10-26 12:31:30 +01:00
Thomas Peetz 2889927416 change templates
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
Gitea Actions Demo / build-and-test (push) Failing after 2m49s
2026-10-25 04:05:11 +01:00
Thomas Peetz 05555a7750 add method to set default values for handler
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 11m53s
Gitea Actions Demo / build-and-test (push) Failing after 16m45s
2026-10-25 01:24:19 +02:00
tpeetz 74cda6c72d change cibuild.local
Gitea Actions Demo / build-and-test (push) Failing after 3m44s
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 14m50s
2026-10-24 18:21:25 +00:00
tpeetz 8ef3e201d6 add version information
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Gitea Actions Demo / build-and-test (push) Failing after 12m31s
2026-10-24 02:08:56 +02:00
Thomas Peetz b3530cec7b fix form add Lofi
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
Gitea Actions Demo / build-and-test (push) Failing after 20m16s
2026-10-22 22:25:57 +02:00
Thomas Peetz 1776d5faa6 build kontor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
Gitea Actions Demo / build-and-test (push) Failing after 3m35s
2026-10-22 21:02:48 +02:00
Thomas Peetz fffcdc4724 test Gitea workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-10-22 20:39:09 +02:00
Thomas Peetz b3b143cd3f parse query parameter
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
2026-10-22 17:24:13 +02:00
Thomas Peetz cdd0276020 add flag for Mediatype: media, video, lofi
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2026-10-22 00:34:19 +02:00
Thomas Peetz a20eb43889 use server infos from config file
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2026-10-20 18:11:33 +02:00
Thomas Peetz 61683f643a add diskcache for kontor-scripts
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2026-10-18 21:07:08 +02:00
tpeetz d5705c3a28 move kontor_model in kontor-api (#98)
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
Co-authored-by: Thomas Peetz <thomas.peetz@cimt-ag.de>
Reviewed-on: #98
2026-10-15 23:14:16 +00:00
191 changed files with 8119 additions and 907 deletions
+19
View File
@@ -0,0 +1,19 @@
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} ist testing out Gitea Actions
on:
push:
branches:
- develop/0.4.0
jobs:
build-and-test:
runs-on: inky
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: List files in the directory
run: |
cd ${{ gitea.workspace }}/kontor-gin
go build -o /home/tpeetz/prod/kontor cmd/kontor/main.go
- name: List files in the directory
run: echo "The job's status is ${{ job.status }}."
+23 -1
View File
@@ -4,7 +4,12 @@ from fastapi import APIRouter, status, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.repository.media.actor import delete_mediaactor, import_mediaactor from src.db.repository.media.actor import delete_mediaactor, import_mediaactor
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.actor import MediaActorModel, MediaActorResponse, actor_to_response from src.schema.media.actor import (
MediaActorModel,
MediaActorResponse,
actor_to_response,
actor_to_model
)
from src.db.models.media import MediaActor from src.db.models.media import MediaActor
router = APIRouter() router = APIRouter()
@@ -26,6 +31,23 @@ def get_actor(actor_id: str, db: SessionDep) -> MediaActorResponse:
response = actor_to_response(media_actor) response = actor_to_response(media_actor)
return response return response
@router.put("/actors/{actor_id}", response_model=MediaActorResponse)
def update_actor(actor_id: str, db:SessionDep, info: MediaActorResponse) -> MediaActorResponse:
"""
Update MediaActor with given id and data.
"""
media_actor = db.get(MediaActor, actor_id)
if not media_actor:
raise HTTPException(status_code=404, detail="MediaActor could not be found")
actor_to_model(info, media_actor)
db.add(media_actor)
db.commit()
mediaactor = db.get(MediaActor, actor_id)
if not mediaactor:
raise HTTPException(status_code=404, detail="MediaActor could not be found")
response = actor_to_response(mediaactor)
return response
@router.delete("/actors/{actor_id}", status_code=status.HTTP_204_NO_CONTENT) @router.delete("/actors/{actor_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_actor(actor_id: str, db: SessionDep): def delete_actor(actor_id: str, db: SessionDep):
media_actor = db.get(MediaActor, actor_id) media_actor = db.get(MediaActor, actor_id)
+24
View File
@@ -32,3 +32,27 @@ class MediaActorModel(BaseModel):
version: int version: int
name: Optional[str] name: Optional[str]
url: Optional[str] url: Optional[str]
def actor_to_model(model: MediaActorResponse, media_actor: MediaActor) -> MediaActor:
"""
Set data of response to model
"""
media_actor.file_name = model.file_name
if model.url is not None:
media_actor.url = model.url
else:
media_actor.url = ""
media_actor.last_modified_date = datetime.now()
return media_actor
def actor_to_response(media_actor: MediaActor) -> MediaActorResponse:
response: MediaActorResponse = MediaActorResponse(
id=media_actor.id,
created_date=media_actor.created_date,
last_modified_date=media_actor.last_modified_date,
version=media_actor.version,
name=str(media_actor.name),
url=str(media_actor.url),
)
return response
@@ -1 +1,8 @@
<h2>Footer</h2> <footer class="mt-auto py-3 bg-light fixed-bottom">
<div class="container text-center">
<span class="text-muted">{{ version }}</span>
</div>
</footer>
<!-- Bootstrap JS einbinden -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ url_for('static', path='js/autocomplete.js') }}"></script>
@@ -1,10 +1,49 @@
<div class="topnav"> <!-- <div class="topnav">
<a href="/">Kontor</a> <a href="/">Kontor</a>
<a href="/comic/comics">Comics</a> <a href="/comic/comics">Comics</a>
<a href="/media/files">Media</a> <a href="/media/files">Media</a>
<a style="float:right" href="/login/">Login</a></li> <a style="float:right" href="/login/">Login</a></li>
</div> -->
</div> <nav class="navbar navbar-expand-lg navbar-dark" style="background-color:darkgrey;">
<div class="container-fluid">
<a class="navbar-brand" href="#">Kontor</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarComicsMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Comics</a>
<div class="dropdown-menu" aria-labelledby="navbarComicsMenuLink">
<a class="dropdown-item" href="/comic/comics">Comics</a>
<a class="dropdown-item" href="/comic/publishers">Publisher</a>
<a class="dropdown-item" href="/comic/artists">Artist</a>
<a class="dropdown-item" href="/comic/issues">Issue</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarWebMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Media</a>
<div class="dropdown-menu" aria-labelledby="navbarWebMenuLink">
<a class="dropdown-item" href="/media/files">Media Files</a>
<a class="dropdown-item" href="/media/actors">Media Actors</a>
<a class="dropdown-item" href="/media/lofis">Lofi</a>
<a class="dropdown-item" href="/media/articles">Artikel</a>
</div>
</li>
{% if user %}
<li class="nav-item">
<a class="nav-link" href="/logout">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="/login">Login</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<!-- <nav class="navbar navbar-expand-lg navbar-light bg-light px-5"> <!-- <nav class="navbar navbar-expand-lg navbar-light bg-light px-5">
<div class="container-fluid"> <div class="container-fluid">
+42 -9
View File
@@ -8,19 +8,52 @@
{% with msg=msg %} {% with msg=msg %}
{% include "components/alerts.html" %} {% include "components/alerts.html" %}
{% endwith %} {% endwith %}
<div class="container"> <div class="row">
<div class="col-md-8">
<h1>Media Lofi</h1>
<p>Hier steht der wesentliche Inhalt der Seite.</p>
</div>
<div class="col-md-4">
<aside class="bg-light p-3">
<h3>Seitenbereich</h3>
<p>Optionale Sidebar oder Zusatzinformationen.</p>
</aside>
</div>
</div>
<div class="row">
<form class="form-inline" action="/media/lofis">
<input type="text" placeholder="Search" name="query">
<label>
<input type="checkbox" name="review" {% if review %}checked{% endif %}>Review
</label>
<label>
<input type="checkbox" name="should_download" {% if download %}checked{% endif %}>Download
</label>
<button type="submit">Search</button>
<div class="pill-nav"><a href="/media/lofis/add">Add Lofi</a></div>
</form>
</div>
<div class="row">
<table class="table table-hover"> <table class="table table-hover">
<thead><tr> <thead>
<th scope="col">Titel</th> <tr>
<th scope="col">Review</th> <th scope="col">Title</th>
<th scope="col">Download</th> <th scope="col">Weblink</th>
</tr></thead> <th scope="col">Review</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tbody> <tbody>
{% for medialofi in medialofis %} {% for medialofi in medialofis %}
<tr> <tr>
<th scope="row"><a href="/media/lofi/{{medialofi.id}}">{{medialofi.title}}</a></th> <th scope="row"><a href="/media/lofi/{{medialofi.id}}">{{medialofi.title}}</a></th>
<td>{% with check=medialofi.review %}{% include "components/check.html" %}{% endwith %}</td> <td><a href="{{medialofi.url}}">{{medialofi.url}}</a></td>
<td>{% with check=medialofi.should_download %}{% include "components/check.html" %}{% endwith %}</td> <td>{% with check=medialofi.review %}{% include "components/check.html" %}{% endwith %}</td>
<td>{% with check=medialofi.should_download %}{% include "components/check.html" %}{% endwith %}</td>
<td><a href="/media/lofi/{{medialofi.id}}/edit" class="btn btn-outline-primary btn-sm active" role="button" aria-pressed="true">Edit</a></td>
<td><a href="/media/lofi/{{medialofi.id}}/delete" class="btn btn-outline-danger btn-sm active" role="button" aria-pressed="true">Delete</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
+20 -19
View File
@@ -1,34 +1,35 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de-DE"> <html lang="de-DE">
<head> <head>
<meta charset="utf-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}"> <link rel="stylesheet" href="{{ url_for('static', path='style.css') }}">
{% block title %} {% block title %}
{% endblock %} {% endblock %}
</head> </head>
<body> <body class="d-flex flex-column h-100">
<div class="header"> <header>
{% block header %} {% block header %}
{% endblock %} {% endblock %}
</div> {% include "components/navbar.html" %}
{% include "components/navbar.html" %} {% block subnav %}
{% block subnav %} {% endblock %}
{% endblock %} </header>
<main class="flex-shrink-0">
<div class="container my-4">
{% block content %}
{% endblock %}
</div>
</main>
{% block content %} {% include "components/footer.html" %}
{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
<script src="{{ url_for('static', path='js/autocomplete.js') }}"></script>
{% block scripts %} {% block scripts %}
{% endblock %} {% endblock %}
<div class="footer">
{% include "components/footer.html" %}
</div>
</body> </body>
</html> </html>
+17 -7
View File
@@ -1,9 +1,10 @@
from typing import Optional from typing import Optional
from fastapi import APIRouter, Request, status, responses from fastapi import APIRouter, Request, status, responses, Query
from fastapi.security.utils import get_authorization_scheme_param from fastapi.security.utils import get_authorization_scheme_param
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from src.core.config import Settings
from src.core.security import get_current_user_from_token from src.core.security import get_current_user_from_token
from src.db.models.media import MediaLofi from src.db.models.media import MediaLofi
from src.db.models.admin import Profile from src.db.models.admin import Profile
@@ -14,28 +15,37 @@ from src.webapps.media.forms import AddLinkForm
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
router = APIRouter(include_in_schema=False, prefix="/media") router = APIRouter(include_in_schema=False, prefix="/media")
@router.get("/lofi") @router.get("/lofis")
def get_medialofis(db: SessionDep, request: Request, msg: Optional[str] = None): def get_medialofis(db: SessionDep, request: Request, msg: Optional[str] = None, review: Optional[bool] = Query(default=False), download: Optional[bool] = Query(default=False)):
medialofis = db.query(MediaLofi).all() medialofis = db.query(MediaLofi).all()
try: try:
token = request.cookies.get("access_token") token = request.cookies.get("access_token")
_, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value _, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value
current_user: Profile = get_current_user_from_token(token=param) current_user: Profile = get_current_user_from_token(token=param)
return templates.TemplateResponse("media/lofi_list.html", {"request": request, "msg": msg, "user": current_user, "medialofis": medialofis}) request.params.get("review")
return templates.TemplateResponse("media/lofi_list.html", {
"request": request,
"msg": msg,
"user": current_user,
"version": Settings.PROJECT_VERSION,
"review": review,
"download": download,
"medialofis": medialofis,
})
except Exception as e: except Exception as e:
print(e) print(e)
return templates.TemplateResponse("media/lofi_list.html", {"request": request, "msg": msg, "user": None, "medialofis": medialofis}) return templates.TemplateResponse("media/lofi_list.html", {"request": request, "msg": msg, "user": None, "medialofis": medialofis})
@router.get("/lofi/{lofi_id}") @router.get("/lofis/{lofi_id}")
def lofi_details(lofi_id: str, request: Request, db: SessionDep): def lofi_details(lofi_id: str, request: Request, db: SessionDep):
medialofi = db.get(MediaLofi, lofi_id) medialofi = db.get(MediaLofi, lofi_id)
return templates.TemplateResponse("media/lofi_detail.html", {"request": request, "medialofi":medialofi}) return templates.TemplateResponse("media/lofi_detail.html", {"request": request, "medialofi":medialofi})
@router.get("/add-lofi") @router.get("/lofis/add")
def add_lofi_link(request: Request, db: SessionDep): def add_lofi_link(request: Request, db: SessionDep):
return templates.TemplateResponse("media/add_lofi_link.html", {"request": request}) return templates.TemplateResponse("media/add_lofi_link.html", {"request": request})
@router.post("/add-lofi") @router.post("/lofis/add")
async def post_lofi_link(request: Request, db: SessionDep): async def post_lofi_link(request: Request, db: SessionDep):
form = AddLinkForm(request) form = AddLinkForm(request)
await form.load_data() await form.load_data()
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"context"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/handlers"
"kontor-api-echo/internal/router"
"kontor-api-echo/pkg/schema"
"log"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"github.com/labstack/echo/v5"
)
func main() {
slog.Info("Kontor started")
db, _ := schema.GetDatabase()
if err := config.InitConfig(); err != nil {
log.Fatalf("Failed to initialize config: %v", err)
}
e := router.New(handlers.NewAdminHandler(db), handlers.NewMediaHandler(db))
// Cancel the context on SIGINT / SIGTERM
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
sc := echo.StartConfig{
Address: ":1323",
GracefulTimeout: 10 * time.Second,
}
if err := sc.Start(ctx, e); err != nil {
e.Logger.Error("server stopped", "error", err)
}
slog.Info("Kontor finished")
}
+46 -17
View File
@@ -1,39 +1,68 @@
module kontor-api-echo module kontor-api-echo
go 1.24.2 go 1.26.0
require (
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/labstack/echo-jwt/v4 v4.4.0
github.com/labstack/echo-jwt/v5 v5.0.2
github.com/labstack/echo/v4 v4.15.0
github.com/labstack/echo/v5 v5.4.4
github.com/stretchr/testify v1.11.1
github.com/uptrace/bun v1.3.0
github.com/uptrace/bun/dialect/pgdialect v1.2.16
github.com/uptrace/bun/driver/pgdriver v1.2.16
golang.org/x/crypto v0.54.0
)
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/mattn/go-sqlite3 v1.14.34 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
modernc.org/libc v1.68.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.46.1 // indirect
)
require ( require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/labstack/echo-jwt/v4 v4.4.0 // indirect
github.com/labstack/echo/v4 v4.15.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/stretchr/testify v1.11.1 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.1.0 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/uptrace/bun v1.2.16 // indirect github.com/uptrace/bun/dialect/sqlitedialect v1.3.0
github.com/uptrace/bun/dialect/pgdialect v1.2.16 // indirect github.com/uptrace/bun/driver/sqliteshim v1.3.0
github.com/uptrace/bun/driver/pgdriver v1.2.16 // indirect
github.com/uptrace/bun/extra/bundebug v1.2.16 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/crypto v0.46.0 // indirect go.yaml.in/yaml/v3 v3.0.6 // indirect
golang.org/x/net v0.48.0 // indirect golang.org/x/net v0.57.0 // indirect
golang.org/x/sys v0.39.0 // indirect golang.org/x/sys v0.49.0 // indirect
golang.org/x/text v0.32.0 // indirect golang.org/x/text v0.43.0 // indirect
golang.org/x/time v0.14.0 // indirect golang.org/x/time v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
mellium.im/sasl v0.3.2 // indirect mellium.im/sasl v0.3.2 // indirect
) )
+82 -18
View File
@@ -1,43 +1,88 @@
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo-jwt/v4 v4.4.0 h1:nrXaEnJupfc2R4XChcLRDyghhMZup77F8nIzHnBK19U= github.com/labstack/echo-jwt/v4 v4.4.0 h1:nrXaEnJupfc2R4XChcLRDyghhMZup77F8nIzHnBK19U=
github.com/labstack/echo-jwt/v4 v4.4.0/go.mod h1:kYXWgWms9iFqI3ldR+HAEj/Zfg5rZtR7ePOgktG4Hjg= github.com/labstack/echo-jwt/v4 v4.4.0/go.mod h1:kYXWgWms9iFqI3ldR+HAEj/Zfg5rZtR7ePOgktG4Hjg=
github.com/labstack/echo-jwt/v5 v5.0.2 h1:ECmHEjwbR30fv90LvpQ0XZbEJWhCF/c3Zp8ug/iVrCE=
github.com/labstack/echo-jwt/v5 v5.0.2/go.mod h1:jNxekWlI4+M+UoV8dozKwIHN9MJ2psUR+U1B0nEutIg=
github.com/labstack/echo/v4 v4.15.0 h1:hoRTKWcnR5STXZFe9BmYun9AMTNeSbjHi2vtDuADJ24= github.com/labstack/echo/v4 v4.15.0 h1:hoRTKWcnR5STXZFe9BmYun9AMTNeSbjHi2vtDuADJ24=
github.com/labstack/echo/v4 v4.15.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c= github.com/labstack/echo/v4 v4.15.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
github.com/labstack/echo/v5 v5.4.4 h1:Nag9Mee0M9sOcKjProYuDNiw60QisysgfbIgz5US5Cw=
github.com/labstack/echo/v5 v5.4.4/go.mod h1:4iEGNQiPPZnkfYpNR/L6fINd3NLiGWUD5+eBotFALas=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.1.0 h1:6W6MbVUrnMb8PEhjkqwsVLY7ryuzRfFHF4mQd7L94ag=
github.com/spf13/pflag v1.1.0/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= 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 h1:QlObi6ZIK5Ao7kAALnh91HWYNZUBbVwye52fmlQM9kc=
github.com/uptrace/bun v1.2.16/go.mod h1:jMoNg2n56ckaawi/O/J92BHaECmrz6IRjuMWqlMaMTM= 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 h1:KFNZ0LxAyczKNfK/IJWMyaleO6eI9/Z5tUv3DE1NVL4=
github.com/uptrace/bun/dialect/pgdialect v1.2.16/go.mod h1:IJdMeV4sLfh0LDUZl7TIxLI0LipF1vwTK3hBC7p5qLo= github.com/uptrace/bun/dialect/pgdialect v1.2.16/go.mod h1:IJdMeV4sLfh0LDUZl7TIxLI0LipF1vwTK3hBC7p5qLo=
github.com/uptrace/bun/dialect/sqlitedialect v1.3.0 h1:XzxkORYksxkLsIQLJHFYUb3yDvqSQHzTungyKpJhHTw=
github.com/uptrace/bun/dialect/sqlitedialect v1.3.0/go.mod h1:x2D1sY50Itio0I/FVdNe30oMUT2ObiAS+oILcMR+Wys=
github.com/uptrace/bun/driver/pgdriver v1.2.16 h1:b1kpXKUxtTSGYow5Vlsb+dKV3z0R7aSAJNfMfKp61ZU= github.com/uptrace/bun/driver/pgdriver v1.2.16 h1:b1kpXKUxtTSGYow5Vlsb+dKV3z0R7aSAJNfMfKp61ZU=
github.com/uptrace/bun/driver/pgdriver v1.2.16/go.mod h1:H6lUZ9CBfp1X5Vq62YGSV7q96/v94ja9AYFjKvdoTk0= github.com/uptrace/bun/driver/pgdriver v1.2.16/go.mod h1:H6lUZ9CBfp1X5Vq62YGSV7q96/v94ja9AYFjKvdoTk0=
github.com/uptrace/bun/extra/bundebug v1.2.16 h1:3OXAfHTU4ydu2+4j05oB1BxPx6+ypdWIVzTugl/7zl0= github.com/uptrace/bun/driver/sqliteshim v1.3.0 h1:T3ybxgmP8ejA99YULje9e12h+FqKKAP/4xZo3+X3mXA=
github.com/uptrace/bun/extra/bundebug v1.2.16/go.mod h1:vk6R/1i67/S2RvUI5AH/m3P5e67mOkfDCmmCsAPUumo= github.com/uptrace/bun/driver/sqliteshim v1.3.0/go.mod h1:MqvqMCAAKNn6M0HF9YK/Z6xrnCP6sih5OZ37AxdAlHw=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
@@ -50,19 +95,38 @@ go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s=
golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0=
mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY= mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY=
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
+163
View File
@@ -0,0 +1,163 @@
package config
import (
"errors"
"fmt"
"log/slog"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
CfgFile string
Verbose int
Overwrite bool
ServerName string
Mediatype MediaType
Config CliConfig
ServerConfig ServerConfiguration
DryRun bool
FileName string
)
const (
mediaTypeMedia MediaType = "media"
mediaTypeVideo MediaType = "video"
mediaTypeLofi MediaType = "lofi"
)
type MediaType string
func (e *MediaType) String() string {
return string(*e)
}
func (e *MediaType) Set(v string) error {
switch v {
case "media", "video", "lofi":
*e = MediaType(v)
return nil
default:
return errors.New(`must be one of "media", "video", "lofi"`)
}
}
func (e *MediaType) Type() string {
return "MediaType"
}
func myEnumCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{
"media\thelp text for media",
"video\thelp text for video",
"lofi\thelp text for lofi",
}, cobra.ShellCompDirectiveDefault
}
type Server struct {
Url string `mapstructure:"url"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}
type Database struct {
Type string `mapstructure:"type" validate:"required"`
Path string `mapstructure:"path" validate:"required"`
Host string `mapstructure:"host" validate:"required"`
Name string `mapstructure:"name" validate:"required"`
Port int `mapstructure:"port" validate:"required"`
Password string `mapstructure:"password" validate:"required"`
User string `mapstructure:"user" validate:"required"`
}
type CliConfig struct {
ApiVersion string
Server map[string]Server `mapstructure:"server"`
DB Database `mapstructure:"db"`
}
type ServerConfiguration struct {
Server struct {
Port int `mapstructure:"port" validate:"required"`
Host string `mapstructure:"host"`
} `mapstructure:"server"`
DB Database `mapstructure:"db"`
Gin struct {
Mode string `mapstructure:"mode" validate:"required"`
} `mapstructure:"gin"`
ApiSecret []byte `mapstructure:"api_secret"`
}
func InitCliConfig() {
slog.Info("InitCliConfig")
if CfgFile != "" {
viper.SetConfigFile(CfgFile)
} else {
viper.SetConfigName("kli") // without extension
viper.SetConfigType("yaml")
viper.AddConfigPath(".") // look for config in working directory
viper.AddConfigPath("/home/tpeetz/.config")
}
Mediatype = mediaTypeMedia
// Read the configuration file
if err := viper.ReadInConfig(); err != nil {
// Handle the case where config file is not found
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
slog.Info("No config file found, using defaults")
if err := viper.SafeWriteConfig(); err != nil {
slog.Info("error writing config file", "error", err.Error())
}
} else {
slog.Info("error reading config file", "error", err.Error())
}
} else {
slog.Info("InitCliConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&Config); err != nil {
slog.Info("parsing of config file failed", "error", err.Error())
}
}
}
func InitConfig() error {
viper.SetConfigName("kontor-gin")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("/home/tpeetz/.config")
viper.AddConfigPath("/etc/kontor")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.SetDefault("db.type", "postgres")
viper.SetDefault("db.host", "localhost")
viper.SetDefault("db.port", 5432)
viper.SetDefault("db.name", "kontor")
viper.SetDefault("db.user", "kontor")
viper.SetDefault("db.password", "kontor")
viper.SetDefault("db.path", "data/kontor.db")
viper.SetDefault("server.port", 8550)
viper.SetDefault("gin.mode", "release")
// Read the config file
if err := viper.ReadInConfig(); err != nil {
// Handle the case where config file is not found
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
slog.Info("No config file found, using defaults")
if err := viper.SafeWriteConfig(); err != nil {
slog.Info("error writing config file", "error", err.Error())
return fmt.Errorf("error writing config file: %w", err)
}
} else {
return fmt.Errorf("error reading config file: %w", err)
}
} else {
slog.Info("InitConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&ServerConfig); err != nil {
slog.Info("parsing of config file failed", "error", err.Error())
}
}
return nil
}
+54
View File
@@ -0,0 +1,54 @@
package config
import (
"database/sql"
"fmt"
"log/slog"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/dialect/sqlitedialect"
"github.com/uptrace/bun/driver/pgdriver"
"github.com/uptrace/bun/driver/sqliteshim"
)
func NewDB(db Database) (*bun.DB, error) {
db_type := db.Type
slog.Info("using database", "type", db_type)
switch db_type {
case "postgres":
dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s", db.User, db.Password, db.Host, db.Port, db.Name)
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
db := bun.NewDB(sqldb, pgdialect.New())
return db, nil
case "sqlite":
sqldb, _ := sql.Open(sqliteshim.ShimName, "file::memory:?cache=shared")
db := bun.NewDB(sqldb, sqlitedialect.New())
return db, nil
default:
return nil, fmt.Errorf("unknown db.type=%s", db_type)
}
// Configure GORM with custom settings
// The logger helps with debugging SQL queries during development
// if err != nil {
// log.Fatal("Failed to connect to database:", err)
// }
// // Get the underlying SQL database connection for pool configuration
// sqlDB, err := db.DB()
// if err != nil {
// log.Fatal("Failed to get database instance:", err)
// }
// // Configure connection pool settings
// // MaxIdleConns: number of connections kept open when idle
// sqlDB.SetMaxIdleConns(10)
// // MaxOpenConns: maximum total connections to the database
// sqlDB.SetMaxOpenConns(100)
// // ConnMaxLifetime: how long a connection can be reused
// sqlDB.SetConnMaxLifetime(time.Hour)
// slog.Info("Database connected successfully")
}
+39
View File
@@ -0,0 +1,39 @@
package globals
import (
"fmt"
)
var (
Secret = []byte("secret")
Version = "unset"
Commit = "unset"
Date = "unset"
)
const (
UserKey = "user"
MediaFileLink = "/media/files"
MediaLofiLink = "/media/lofis"
MediaMusicLink = "/media/musics"
MediaVideoLink = "/media/videos"
MediaArticleLink = "/media/articles"
MediaActorLink = "/media/actors"
)
func GetDefaultValues(user interface{}, message string) map[string]any {
values := map[string]any{
"title": "Kontor",
"version": fmt.Sprintf("%s %s", Version, Commit),
"message": message,
"user": user,
"media_file_link": MediaFileLink,
"media_lofi_link": MediaLofiLink,
"media_music_link": MediaMusicLink,
"media_video_link": MediaVideoLink,
"media_article_link": MediaArticleLink,
"media_actor_link": MediaActorLink,
}
return values
}
+28
View File
@@ -0,0 +1,28 @@
package handlers
import (
"github.com/uptrace/bun"
)
type AdminHandler struct {
AuthHandler *AuthHandler
ProfileHandler *ProfileHandler
PermissionHandler *PermissionHandler
AssignmentHandler *AssignmentHandler
TokenHandler *TokenHandler
MailAccountHandler *MailAccountHandler
MailHandler *MailHandler
}
func NewAdminHandler(db *bun.DB) *AdminHandler {
adminHandler := &AdminHandler{
AuthHandler: NewAuthHandler(db),
ProfileHandler: NewProfileHandler(db),
PermissionHandler: NewPermissionHandler(db),
AssignmentHandler: NewAssignmentHandler(db),
TokenHandler: NewTokenHandler(db),
MailAccountHandler: NewMailAccountHandler(db),
MailHandler: NewMailHandler(db),
}
return adminHandler
}
@@ -0,0 +1,30 @@
package handlers
import (
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type AssignmentHandler struct {
Service *service.AssignmentService
}
func NewAssignmentHandler(db *bun.DB) *AssignmentHandler {
handler := &AssignmentHandler{Service: service.NewAssignmentService(repository.NewAssignmentRepository(db))}
return handler
}
func (handler *AssignmentHandler) List(c *echo.Context) {
assignments, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertAssignmentsToDtos(assignments)
c.JSON(http.StatusOK, dtos)
}
+26
View File
@@ -0,0 +1,26 @@
package handlers
import "github.com/uptrace/bun"
type MediaHandler struct {
MediaArticleHandler *MediaArticleHandler
MediaActorHandler *MediaActorHandler
MediaFileHandler *MediaFileHandler
MediaLoFiHandler *MediaLoFiHandler
MediaMusicHandler *MediaMusicHandler
MediaVideoHandler *MediaVideoHandler
MediaActorFileHandler *MediaActorFileHandler
}
func NewMediaHandler(db *bun.DB) *MediaHandler {
mediaHandler := &MediaHandler{
MediaArticleHandler: NewMediaArticleHandler(db),
MediaActorHandler: NewMediaActorHandler(db),
MediaFileHandler: NewMediaFileHandler(db),
MediaLoFiHandler: NewMediaLoFiHandler(db),
MediaMusicHandler: NewMediaMusicHandler(db),
MediaVideoHandler: NewMediaVideoHandler(db),
MediaActorFileHandler: NewMediaActorFileHandler(db),
}
return mediaHandler
}
@@ -0,0 +1,137 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaActorHandler struct {
Service *service.MediaActorService
}
func NewMediaActorHandler(db *bun.DB) *MediaActorHandler {
mediaActorHandler := &MediaActorHandler{
Service: service.NewMediaActorService(repository.NewMediaActorRepository(db)),
}
return mediaActorHandler
}
func (handler *MediaActorHandler) List(c *echo.Context) {
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaActorsToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaActorHandler) Get(c *echo.Context) {
id := c.Param("id")
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorHandler) Add(c *echo.Context) {
var input models.MediaActorAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
actor, err := handler.Service.Add(c.Request().Context(), input.WebLink)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaActorHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
actors, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actors"] = actors
c.Render(http.StatusOK, "media_actors", data)
}
func (handler *MediaActorHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
//logger := slog.Get(c)
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
c.Render(http.StatusOK, "actor_detail", data)
}
func (handler *MediaActorHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaActorForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "actor_detail", data)
return
}
logger.Info("MediaActorHandler#UpdatePage", "actor", actor)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
func (handler *MediaActorHandler) DeletePage(c *echo.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
//actor, err := handler.Service.Get(c.Request.Context(), id)
// if err != nil {
// logger.Info("MediaActorHandler#DeletePage", "error", err.Error())
// c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
// return
// }
logger.Info("MediaActorHandler#DeletePage", "actor", id)
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
@@ -0,0 +1,85 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaActorFileHandler struct {
Service *service.MediaActorFileService
}
func NewMediaActorFileHandler(db *bun.DB) *MediaActorFileHandler {
mediaActorFileHandler := &MediaActorFileHandler{
Service: service.NewMediaActorFileService(repository.NewMediaActorFileRepository(db)),
}
return mediaActorFileHandler
}
func (handler *MediaActorFileHandler) List(c *echo.Context) {
media_actor_files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaActorFilesToDtos(media_actor_files)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaActorFileHandler) Get(c *echo.Context) {
id := c.Param("id")
actor, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, actor)
}
func (handler *MediaActorFileHandler) Add(c *echo.Context) {
var input models.MediaActorFileAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
actorfile, err := handler.Service.Add(c.Request().Context(), input.MediaActorID, input.MediaFileID)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, actorfile)
}
func (handler *MediaActorFileHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "sport not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaActorFileHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
media_actor_files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
c.Render(http.StatusOK, "mediaactorfiles", map[string]string{
"title": "Kontor MediaActorFiles",
"version": "0.4.0",
"message": "MediaActorFiles...",
"actors": media_actor_files,
"user": user,
})
}
@@ -0,0 +1,115 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaArticleHandler struct {
Service *service.MediaArticleService
}
func NewMediaArticleHandler(db *bun.DB) *MediaArticleHandler {
mediaFileHandler := &MediaArticleHandler{
Service: service.NewMediaArticleService(repository.NewMediaArticleRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaArticleHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaArticleHandler#List")
articles, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaArticlesToDtos(articles)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaArticleHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaArticleHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaArticles...")
data["title"] = "Kontor MediaArticles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaArticleLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaArticleHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["lofi"] = media_file
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaArticleHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_article, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaArticleForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaArticleHandler#UpdatePage", "media_article", media_article)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
func (handler *MediaArticleHandler) DeletePage(c *echo.Context) {
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
+132
View File
@@ -0,0 +1,132 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaFileHandler struct {
Service *service.MediaFileService
}
func NewMediaFileHandler(db *bun.DB) *MediaFileHandler {
mediaFileHandler := &MediaFileHandler{
Service: service.NewMediaFileService(repository.NewMediaFileRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaFileHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaFileHandler#List")
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaFilesToDtos(files)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaFileHandler) Add(c *echo.Context) {
var input models.MediaFileAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaFileHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaFileHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
files, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaFiles...")
data["title"] = "Kontor MediaFiles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaVideoLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaFileHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["lofi"] = media_file
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaFileHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
media_file, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaFileForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaFileHandler#UpdatePage", "media_file", media_file)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaFileLink)
}
func (handler *MediaFileHandler) DeletePage(c *echo.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaFileHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaFileHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaFileLink)
}
+232
View File
@@ -0,0 +1,232 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"time"
"github.com/google/uuid"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaLoFiHandler struct {
Service *service.MediaLoFiService
}
func NewMediaLoFiHandler(db *bun.DB) *MediaLoFiHandler {
mediaLoFiHandler := &MediaLoFiHandler{
Service: service.NewMediaLoFiService(repository.NewMediaLoFiRepository(db)),
}
return mediaLoFiHandler
}
func (handler *MediaLoFiHandler) List(c *echo.Context) {
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaLoFisToDtos(lofis)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaLoFiHandler) Get(c *echo.Context) {
id := c.Param("id")
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "Lofi not found"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Add(c *echo.Context) {
var input models.MediaLofiAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Update(c *echo.Context) {
var input models.MediaLoFiDTO
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
lofi, err := handler.Service.Update(c.Request().Context(), input)
if err != nil {
logger := c.Logger()
logger.Info("MediaLoFiHandler#Update", "error", err.Error())
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not updated"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaLoFiHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaLoFiHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
var (
review bool
download bool
)
paramReview, err := echo.QueryParam[string](c, "review")
if err == nil {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, err := echo.QueryParam[string](c, "should_download")
if err == nil {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaLoFiHandler#ListPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
data := globals.GetDefaultValues(user, "MediaFiles...")
data["media_links"] = lofis
data["isReview"] = review
data["isDownload"] = download
data["MediaLinksUrl"] = globals.MediaLofiLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaLoFiHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
var lofi *models.MediaLoFi
if id == "" {
// id is empty, adding is assumed
lofi = &models.MediaLoFi{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Version: 0,
Review: true,
ShouldDownload: true,
}
} else {
// id is set, fetch MediaLofi by ID
lofi, err = handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
}
logger.Info("MediaLoFiHandler#EditPage", "lofi", lofi)
data := globals.GetDefaultValues(user, "MediaLofis...")
data["media"] = lofi
data["MediaLinksUrl"] = globals.MediaLofiLink
c.Render(http.StatusOK, "media_detail", data)
}
func (handler *MediaLoFiHandler) ChangeReviewPage(c *echo.Context) {
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error())
c.Redirect(http.StatusNotFound, globals.MediaLofiLink)
return
}
lofi.Review = !lofi.Review
handler.Service.Update(c.Request().Context(), lofi.ConvertMediaLoFiToDTO())
logger.Info("MediaLoFiHandler#ChangeReviewPage", "lofi", lofi)
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
lofis, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
data := globals.GetDefaultValues(user, "MediaLofis...")
data["lofis"] = lofis
//c.HTML(http.StatusOK, "lofi", data)
c.Redirect(http.StatusCreated, globals.MediaLofiLink)
}
func (handler *MediaLoFiHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaLoFiForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaLoFiHandler#UpdatePage", "error", err.Error())
c.Render(http.StatusBadRequest, "lofi_detail", map[string]any{
"Form": form,
"Errors": err.Error(),
"user": user,
})
return
}
logger.Info("MediaLoFiHandler#UpdatePage", "lofi", lofi)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaLofiLink)
}
func (handler *MediaLoFiHandler) DeletePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
lofi, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#DeletePage", "lofi", id)
c.Render(http.StatusOK, "lofi_delete", map[string]string{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"lofi": lofi,
"user": user,
})
}
@@ -0,0 +1,181 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaMusicHandler struct {
Service *service.MediaMusicService
}
func NewMediaMusicHandler(db *bun.DB) *MediaMusicHandler {
mediaMusicHandler := &MediaMusicHandler{
Service: service.NewMediaMusicService(repository.NewMediaMusicRepository(db)),
}
return mediaMusicHandler
}
func (handler *MediaMusicHandler) List(c *echo.Context) {
musics, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaMusicsToDtos(musics)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaMusicHandler) Get(c *echo.Context) {
id := c.Param("id")
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Add(c *echo.Context) {
var input models.MediaLofiAdd
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
music, err := handler.Service.Add(c.Request().Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not added"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Update(c *echo.Context) {
var input models.MediaMusicDTO
if err := c.Bind(&input); err != nil {
c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
music, err := handler.Service.Update(c.Request().Context(), input)
if err != nil {
logger := c.Logger()
logger.Info("MediaMusicHandler#Update", "error", err.Error())
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not updated"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Delete(c *echo.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, map[string]string{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, map[string]string{"ok": "true"})
}
func (handler *MediaMusicHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
var (
review bool
download bool
)
paramReview, err := echo.QueryParam[string](c, "review")
if err == nil {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, err := echo.QueryParam[string](c, "should_download")
if err == nil {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
musics, err := handler.Service.List(c.Request().Context())
if err != nil {
logger.Info("MediaMusicHandler#ListPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#ListPage", "MediaMusic count", len(musics))
data := globals.GetDefaultValues(user, "MediaMusic...")
data["media_links"] = musics
data["MediaLinksUrl"] = globals.MediaMusicLink
data["isReview"] = review
data["isDownload"] = download
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaMusicHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#EditPage", "music", music)
data := globals.GetDefaultValues(user, "MediaMusic...")
data["lofi"] = music
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaMusicHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
music, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaMusicForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaMusic...")
data["Form"] = form
data["Errors"] = err.Error()
c.Render(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaMusicHandler#UpdatePage", "music", music)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
func (handler *MediaMusicHandler) DeletePage(c *echo.Context) {
// session := sessions.Default(c)
// user := session.Get(globals.UserKey)
id := c.Param("id")
logger := c.Logger()
err := handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#DeletePage", "music", id)
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
@@ -0,0 +1,113 @@
package handlers
import (
"kontor-api-echo/internal/globals"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type MediaVideoHandler struct {
Service *service.MediaVideoService
}
func NewMediaVideoHandler(db *bun.DB) *MediaVideoHandler {
handler := &MediaVideoHandler{Service: service.NewMediaVideoService(repository.NewMediaVideoRepository(db))}
return handler
}
func (handler *MediaVideoHandler) List(c *echo.Context) {
logger := c.Logger()
logger.Info("MediaVideoHandler#List")
videos, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertMediaVideosToDtos(videos)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaVideoHandler) ListPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
logger := c.Logger()
videos, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#ListPage", "videos count", len(videos))
data := globals.GetDefaultValues(user, "MediaVideos...")
data["title"] = "Kontor MediaVideos"
data["media_links"] = videos
data["MediaLinksUrl"] = globals.MediaVideoLink
c.Render(http.StatusOK, "media_links", data)
}
func (handler *MediaVideoHandler) EditPage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
video, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#EditPage", "lofi", video)
data := globals.GetDefaultValues(user, "MediaLofis...")
data["lofi"] = video
c.Render(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaVideoHandler) UpdatePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
video, err := handler.Service.Get(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
var form models.MediaVideoForm
if err := c.Bind(&form); err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.Render(http.StatusBadRequest, "lofi_detail", map[string]any{
"Form": form,
"Errors": err.Error(),
"user": user,
})
return
}
logger.Info("MediaVideoHandler#UpdatePage", "lofi", video)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaVideoLink)
}
func (handler *MediaVideoHandler) DeletePage(c *echo.Context) {
cookie, err := c.Cookie(globals.UserKey)
user := cookie.Value
id := c.Param("id")
logger := c.Logger()
err = handler.Service.Delete(c.Request().Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#DeletePage", "video", id)
c.Render(http.StatusOK, "lofi_delete", map[string]string{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"user": user,
})
}
@@ -0,0 +1,28 @@
package handlers
import (
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type PermissionHandler struct {
Service *service.PermissionService
}
func NewPermissionHandler(db *bun.DB) *PermissionHandler {
handler := &PermissionHandler{Service: service.NewPermissionService(repository.NewPermissionRepository(db))}
return handler
}
func (handler *PermissionHandler) List(c *echo.Context) {
permissions, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
c.JSON(http.StatusOK, permissions)
}
+30
View File
@@ -0,0 +1,30 @@
package handlers
import (
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"kontor-api-echo/internal/service"
"net/http"
"github.com/labstack/echo/v5"
"github.com/uptrace/bun"
)
type ProfileHandler struct {
Service *service.ProfileService
}
func NewProfileHandler(db *bun.DB) *ProfileHandler {
handler := &ProfileHandler{Service: service.NewProfileService(repository.NewProfileRepository(db))}
return handler
}
func (handler *ProfileHandler) List(c *echo.Context) {
profiles, err := handler.Service.List(c.Request().Context())
if err != nil {
c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
dtos := models.ConvertProfilesToDtos(profiles)
c.JSON(http.StatusOK, dtos)
}
+69
View File
@@ -0,0 +1,69 @@
package helpers
import (
"encoding/json"
"fmt"
"time"
)
type DateOnly struct {
time.Time
}
func (d DateOnly) MarshalJSON() ([]byte, error) {
if d.IsZero() {
return []byte("null"), nil
}
return json.Marshal(d.Format("2006-01-02"))
}
func (d *DateOnly) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if s == "" {
return nil
}
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
d.Time = t
return nil
}
type KontorTime struct {
time.Time
}
var layouts = []string{
"2006-01-02 15:04:05.000000",
"2006-01-02T15:04:05.999Z",
"2006-01-02",
}
func (kt KontorTime) MarshalJSON() ([]byte, error) {
if kt.IsZero() {
return []byte("null"), nil
}
return json.Marshal(kt.Format(layouts[0]))
}
func (kt *KontorTime) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if s == "" {
return nil
}
for _, layout := range layouts {
t, err := time.Parse(layout, s)
if err == nil {
kt.Time = t
return nil
}
}
return fmt.Errorf("failed to parse time from %s", s)
}
+63
View File
@@ -0,0 +1,63 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type Assignment struct {
bun.BaseModel `bun:"table:assignment"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
PermissionID *string `bun:"permission_id"`
Permission *Permission `bun:"rel:belongs-to,join:permission_id=id"`
}
type AssignmentDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
ProfileID *string `json:"profile_id"`
PermissionID *string `json:"permission_id"`
}
func (dto *AssignmentDTO) ConvertDTOToModel() Assignment {
model := Assignment{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
ProfileID: dto.ProfileID,
PermissionID: dto.PermissionID,
}
return model
}
func ConvertAssignmentsToDtos(assignments []Assignment) []AssignmentDTO {
dtos := make([]AssignmentDTO, len(assignments))
for i, assignment := range assignments {
dtos[i] = AssignmentDTO{
ID: assignment.ID,
CreatedAt: helpers.KontorTime{Time: assignment.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: assignment.UpdatedAt},
DeletedAt: assignment.DeletedAt,
Version: assignment.Version,
ProfileID: assignment.ProfileID,
PermissionID: assignment.PermissionID,
}
}
return dtos
}
type AssignmentDTOList []AssignmentDTO
@@ -0,0 +1,72 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaActor struct {
bun.BaseModel `bun:"table:media_actor"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Name string `bun:"name"`
WebLink string `bun:"url,unique:url"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_actor_id"`
}
type MediaActorForm struct {
Name string `form:"name" binding:"required"`
Weblink string `form:"weblink" binding:"required"`
}
type MediaActorDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
Name string `json:"name"`
WebLink string `json:"url"`
}
func (dto MediaActorDTO) ConvertDTOToModel() MediaActor {
model := MediaActor{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Name: dto.Name,
WebLink: dto.WebLink,
}
return model
}
type MediaActorAdd struct {
WebLink string `json:"url"`
}
func ConvertMediaActorsToDtos(actors []MediaActor) []MediaActorDTO {
dtos := make([]MediaActorDTO, len(actors))
for i, actor := range actors {
dtos[i] = MediaActorDTO{
ID: actor.ID,
CreatedAt: helpers.KontorTime{Time: actor.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: actor.UpdatedAt},
DeletedAt: actor.DeletedAt,
Version: actor.Version,
Name: actor.Name,
WebLink: actor.WebLink,
}
}
return dtos
}
type MediaActorDTOList []MediaActorDTO
@@ -0,0 +1,68 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaActorFile struct {
bun.BaseModel `bun:"table:media_actor_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
MediaActorID *string `bun:"media_actor_id"`
MediaActor *MediaActor `bun:"rel:belongs-to,join:media_actor_id=id"`
MediaFileID *string `bun:"media_file_id"`
MediaFile *MediaFile `bun:"rel:belongs-to,join:media_file_id=id"`
}
type MediaActorFileAdd struct {
MediaActorID string `json:"media_actor_id"`
MediaFileID string `json:"media_file_id"`
}
type MediaActorFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
MediaActorID *string `json:"media_actor_id"`
MediaFileID *string `json:"media_file_id"`
}
func (dto MediaActorFileDTO) ConvertDTOToModel() MediaActorFile {
model := MediaActorFile{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
MediaActorID: dto.MediaActorID,
MediaFileID: dto.MediaFileID,
}
return model
}
func ConvertMediaActorFilesToDtos(actor_files []MediaActorFile) []MediaActorFileDTO {
dtos := make([]MediaActorFileDTO, len(actor_files))
for i, actor_file := range actor_files {
dtos[i] = MediaActorFileDTO{
ID: actor_file.ID,
CreatedAt: helpers.KontorTime{Time: actor_file.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: actor_file.UpdatedAt},
DeletedAt: actor_file.DeletedAt,
Version: actor_file.Version,
MediaActorID: actor_file.MediaActorID,
MediaFileID: actor_file.MediaFileID,
}
}
return dtos
}
type MediaActorFileDTOList []MediaActorFileDTO
@@ -0,0 +1,80 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaArticle struct {
bun.BaseModel `bun:"table:media_article"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
}
func (media_article MediaArticle) ConvertMediaArticleToDTO() MediaArticleDTO {
dto := MediaArticleDTO{
ID: media_article.ID,
CreatedAt: helpers.KontorTime{Time: media_article.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_article.UpdatedAt},
DeletedAt: media_article.DeletedAt,
Version: media_article.Version,
Review: media_article.Review,
Title: media_article.Title,
WebLink: media_article.WebLink,
}
return dto
}
type MediaArticleForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaArticleForm) ConvertFormToMediaArticleDTO() MediaArticleDTO {
dto := MediaArticleDTO{}
return dto
}
type MediaArticleDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `json:"version"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func (dto MediaArticleDTO) ConvertDTOToModel() MediaArticle {
model := MediaArticle{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Review: dto.Review,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func ConvertMediaArticlesToDtos(media_articles []MediaArticle) MediaArticleDTOList {
dtos := make(MediaArticleDTOList, len(media_articles))
for i, media_article := range media_articles {
dtos[i] = media_article.ConvertMediaArticleToDTO()
}
return dtos
}
type MediaArticleDTOList []MediaArticleDTO
+97
View File
@@ -0,0 +1,97 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaFile struct {
bun.BaseModel `bun:"table:media_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_file_id"`
}
type MediaFileAdd struct {
Url string `json:"url"`
}
type MediaFileForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaFileForm) ConvertFormToMediaFileDTO() MediaFileDTO {
media_file := MediaFileDTO{}
return media_file
}
type MediaFileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
CloudLink string `json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
ShouldDownload bool `json:"should_download"`
}
func (dto MediaFileDTO) ConvertDTOToModel() MediaFile {
model := MediaFile{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
CloudLink: dto.CloudLink,
FileName: dto.FileName,
Path: dto.Path,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func ConvertMediaFilesToDtos(media_files []MediaFile) []MediaFileDTO {
dtos := make([]MediaFileDTO, len(media_files))
for i, media_file := range media_files {
dtos[i] = MediaFileDTO{
ID: media_file.ID,
CreatedAt: helpers.KontorTime{Time: media_file.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_file.UpdatedAt},
DeletedAt: media_file.DeletedAt,
Version: media_file.Version,
CloudLink: media_file.CloudLink,
FileName: media_file.FileName,
Path: media_file.Path,
Review: media_file.Review,
Title: media_file.Title,
WebLink: media_file.WebLink,
ShouldDownload: media_file.ShouldDownload,
}
}
return dtos
}
type MediaFileDTOList []MediaFileDTO
+193
View File
@@ -0,0 +1,193 @@
package models
import (
"fmt"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/helpers"
"log/slog"
"time"
"github.com/uptrace/bun"
)
type MediaLoFi struct {
bun.BaseModel `bun:"table:media_lofi"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
WebLink string `bun:"url,unique:url"`
Review bool `bun:"review"`
ShouldDownload bool `bun:"should_download"`
Title string `bun:"title"`
FileName string `bun:"file_name"`
}
func (media_lofi *MediaLoFi) Update(update MediaLoFiDTO) {
media_lofi.CreatedAt = update.CreatedAt.Time
media_lofi.UpdatedAt = time.Now()
media_lofi.Version = media_lofi.Version + 1
media_lofi.WebLink = update.WebLink
media_lofi.Review = update.Review
media_lofi.ShouldDownload = update.ShouldDownload
media_lofi.Title = update.Title
media_lofi.FileName = update.FileName
}
func (media_lofi *MediaLoFi) ConvertMediaLoFiToDTO() MediaLoFiDTO {
dto := MediaLoFiDTO{
ID: media_lofi.ID,
CreatedAt: helpers.KontorTime{Time: media_lofi.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_lofi.UpdatedAt},
DeletedAt: media_lofi.DeletedAt,
Version: media_lofi.Version,
WebLink: media_lofi.WebLink,
Review: media_lofi.Review,
ShouldDownload: media_lofi.ShouldDownload,
Title: media_lofi.Title,
FileName: media_lofi.FileName,
}
return dto
}
type MediaLofiAdd struct {
Url string `json:"url"`
}
type MediaLoFiForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaLoFiForm) ConvertFormToMediaLofiDTO() MediaLoFiDTO {
media_lofi := MediaLoFiDTO{}
return media_lofi
}
type MediaLoFiDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
FileName string `json:"file_name"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func (dto MediaLoFiDTO) ConvertDTOToModel() MediaLoFi {
model := MediaLoFi{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
FileName: dto.FileName,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func (source MediaLoFiDTO) Equals(target MediaLoFiDTO) bool {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals", "id", source.ID)
}
equals := true
if source.Title != target.Title {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Title changed")
}
equals = false
}
if source.WebLink != target.WebLink {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: WebLink changed")
}
equals = false
}
if source.Version != target.Version {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Version changed")
}
equals = false
}
if source.FileName != target.FileName {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: FileName changed")
}
equals = false
}
if source.Review != target.Review {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: Review changed")
}
equals = false
}
if source.ShouldDownload != target.ShouldDownload {
if config.Verbose > 1 {
slog.Info("MediaLoFiDTO#Equals: ShouldDownload changed")
}
equals = false
}
return equals
}
type MediaLoFiDTOList []MediaLoFiDTO
func (source MediaLoFiDTOList) GetMediaLofi(lofi_id string) *MediaLoFiDTO {
for _, lofi := range source {
if lofi.ID == lofi_id {
return &lofi
}
}
return nil
}
func (source *MediaLoFiDTOList) CompareIds(target *MediaLoFiDTOList) (missing, obsolete, changed []string) {
sources := make(map[string]MediaLoFiDTO, len(*source))
targets := make(map[string]MediaLoFiDTO, len(*target))
for _, source := range *source {
sources[source.ID] = source
}
for _, target := range *target {
targets[target.ID] = target
}
// iterate source IDs
for id := range sources {
if _, ok := targets[id]; ok {
if config.Verbose > 1 {
slog.Info(fmt.Sprintf("ID %s found in both lists", id))
}
if !sources[id].Equals(targets[id]) {
changed = append(changed, id)
}
} else {
missing = append(missing, id)
}
}
for id := range targets {
if _, ok := sources[id]; ok {
slog.Debug(fmt.Sprintf("ID %s found in both lists", id))
} else {
obsolete = append(obsolete, id)
}
}
slog.Info("CompareIds", "missing", len(missing), "obsolete", len(obsolete), "changed", len(changed))
slog.Debug("CompareIds", "missing", missing, "obsolete", obsolete)
return missing, obsolete, changed
}
func ConvertMediaLoFisToDtos(media_lofis []MediaLoFi) MediaLoFiDTOList {
dtos := make(MediaLoFiDTOList, len(media_lofis))
for i, media_lofi := range media_lofis {
dtos[i] = media_lofi.ConvertMediaLoFiToDTO()
}
return dtos
}
+193
View File
@@ -0,0 +1,193 @@
package models
import (
"fmt"
"kontor-api-echo/internal/config"
"kontor-api-echo/internal/helpers"
"log/slog"
"time"
"github.com/uptrace/bun"
)
type MediaMusic struct {
bun.BaseModel `bun:"table:media_music"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
WebLink string `bun:"url,unique:url"`
Review bool `bun:"review"`
ShouldDownload bool `bun:"should_download"`
Title string `bun:"title"`
FileName string `bun:"file_name"`
}
func (media_music *MediaMusic) Update(update MediaMusicDTO) {
media_music.CreatedAt = update.CreatedAt.Time
media_music.UpdatedAt = time.Now()
media_music.Version = media_music.Version + 1
media_music.WebLink = update.WebLink
media_music.Review = update.Review
media_music.ShouldDownload = update.ShouldDownload
media_music.Title = update.Title
media_music.FileName = update.FileName
}
func (media_music *MediaMusic) ConvertMediaMusicToDTO() MediaMusicDTO {
dto := MediaMusicDTO{
ID: media_music.ID,
CreatedAt: helpers.KontorTime{Time: media_music.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_music.UpdatedAt},
DeletedAt: media_music.DeletedAt,
Version: media_music.Version,
WebLink: media_music.WebLink,
Review: media_music.Review,
ShouldDownload: media_music.ShouldDownload,
Title: media_music.Title,
FileName: media_music.FileName,
}
return dto
}
type MediaMusicAdd struct {
Url string `json:"url"`
}
type MediaMusicForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaMusicForm) ConvertFormToMediaMusicDTO() MediaMusicDTO {
media_music := MediaMusicDTO{}
return media_music
}
type MediaMusicDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
FileName string `json:"file_name"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `json:"title"`
WebLink string `json:"url"`
}
func (dto MediaMusicDTO) ConvertDTOToModel() MediaMusic {
model := MediaMusic{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
FileName: dto.FileName,
Review: dto.Review,
ShouldDownload: dto.ShouldDownload,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func (source MediaMusicDTO) Equals(target MediaMusicDTO) bool {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals", "id", source.ID)
}
equals := true
if source.Title != target.Title {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Title changed")
}
equals = false
}
if source.WebLink != target.WebLink {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: WebLink changed")
}
equals = false
}
if source.Version != target.Version {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Version changed")
}
equals = false
}
if source.FileName != target.FileName {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: FileName changed")
}
equals = false
}
if source.Review != target.Review {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: Review changed")
}
equals = false
}
if source.ShouldDownload != target.ShouldDownload {
if config.Verbose > 1 {
slog.Info("MediaMusicDTO#Equals: ShouldDownload changed")
}
equals = false
}
return equals
}
type MediaMusicDTOList []MediaMusicDTO
func (source MediaMusicDTOList) GetMediaMusic(music_id string) *MediaMusicDTO {
for _, music := range source {
if music.ID == music_id {
return &music
}
}
return nil
}
func (source *MediaMusicDTOList) CompareIds(target *MediaMusicDTOList) (missing, obsolete, changed []string) {
sources := make(map[string]MediaMusicDTO, len(*source))
targets := make(map[string]MediaMusicDTO, len(*target))
for _, source := range *source {
sources[source.ID] = source
}
for _, target := range *target {
targets[target.ID] = target
}
// iterate source IDs
for id := range sources {
if _, ok := targets[id]; ok {
if config.Verbose > 1 {
slog.Info(fmt.Sprintf("ID %s found in both lists", id))
}
if !sources[id].Equals(targets[id]) {
changed = append(changed, id)
}
} else {
missing = append(missing, id)
}
}
for id := range targets {
if _, ok := sources[id]; ok {
slog.Debug(fmt.Sprintf("ID %s found in both lists", id))
} else {
obsolete = append(obsolete, id)
}
}
slog.Info("CompareIds", "missing", len(missing), "obsolete", len(obsolete), "changed", len(changed))
slog.Debug("CompareIds", "missing", missing, "obsolete", obsolete)
return missing, obsolete, changed
}
func ConvertMediaMusicsToDtos(media_musics []MediaMusic) MediaMusicDTOList {
dtos := make(MediaMusicDTOList, len(media_musics))
for i, media_music := range media_musics {
dtos[i] = media_music.ConvertMediaMusicToDTO()
}
return dtos
}
@@ -0,0 +1,98 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type MediaVideo struct {
bun.BaseModel `bun:"table:media_video"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
}
func (media_music *MediaVideo) Update(update MediaVideoDTO) {
media_music.CreatedAt = update.CreatedAt.Time
media_music.UpdatedAt = time.Now()
media_music.Version = media_music.Version + 1
media_music.WebLink = update.WebLink
media_music.Review = update.Review
media_music.ShouldDownload = update.ShouldDownload
media_music.Title = update.Title
media_music.FileName = update.FileName
}
type MediaVideoForm struct {
Title string `form:"title" binding:"required"`
Url string `form:"url" binding:"required"`
}
func (form *MediaVideoForm) ConvertFormToMediaVideoDTO() MediaVideoDTO {
media_video := MediaVideoDTO{}
return media_video
}
type MediaVideoDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
CloudLink string `json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `json:"title"`
WebLink string `json:"url"`
ShouldDownload bool `json:"should_download"`
}
func (dto MediaVideoDTO) ConvertDTOToModel() MediaVideo {
model := MediaVideo{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Review: dto.Review,
Title: dto.Title,
WebLink: dto.WebLink,
}
return model
}
func ConvertMediaVideosToDtos(media_videos []MediaVideo) []MediaVideoDTO {
dtos := make([]MediaVideoDTO, len(media_videos))
for i, media_video := range media_videos {
dtos[i] = MediaVideoDTO{
ID: media_video.ID,
CreatedAt: helpers.KontorTime{Time: media_video.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: media_video.UpdatedAt},
DeletedAt: media_video.DeletedAt,
Version: media_video.Version,
CloudLink: media_video.CloudLink,
FileName: media_video.FileName,
Path: media_video.Path,
Review: media_video.Review,
Title: media_video.Title,
WebLink: media_video.WebLink,
ShouldDownload: media_video.ShouldDownload,
}
}
return dtos
}
type MediaVideoDTOList []MediaVideoDTO
+58
View File
@@ -0,0 +1,58 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type Permission struct {
bun.BaseModel `bun:"table:permission"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
Assignments []Assignment `bun:"rel:has-many,join:id=permission_id"`
}
type PermissionDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date" binding:"required"`
UpdatedAt helpers.KontorTime `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty" binding:"required"`
Version int `json:"version" binding:"required"`
Name string `json:"name" binding:"required"`
}
func (permission *PermissionDTO) ConvertDTOToModel() Permission {
model := Permission{
ID: permission.ID,
CreatedAt: permission.CreatedAt.Time,
UpdatedAt: permission.UpdatedAt.Time,
DeletedAt: permission.DeletedAt,
Version: permission.Version,
Name: permission.Name,
}
return model
}
func ConvertPermissionsToDtos(permissions []Permission) []PermissionDTO {
dtos := make([]PermissionDTO, len(permissions))
for i, permission := range permissions {
dtos[i] = PermissionDTO{
ID: permission.ID,
CreatedAt: helpers.KontorTime{Time: permission.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: permission.UpdatedAt},
DeletedAt: permission.DeletedAt,
Version: permission.Version,
Name: permission.Name,
}
}
return dtos
}
type PermissionDTOList []PermissionDTO
+96
View File
@@ -0,0 +1,96 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type Profile struct {
bun.BaseModel `bun:"table:profile"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
FirstName string `bun:"first_name"`
LastName string `bun:"last_name"`
UserName string `bun:"user_name,unique:user_name"`
Email string `bun:"email"`
Password string `bun:"password"`
Enabled bool `bun:"enabled"`
Assignments []Assignment `bun:"rel:has-many,join:id=profile_id"`
Tokens []Token `bun:"rel:has-many,join:id=profile_id"`
}
func (profile *Profile) GetFullName() string {
full_name := ""
if profile.FirstName != "" {
full_name += profile.FirstName
}
if profile.LastName != "" {
full_name += " "
full_name += profile.LastName
}
return full_name
}
type ProfileDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date" binding:"required"`
UpdatedAt helpers.KontorTime `json:"last_modified_date" binding:"required"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version" binding:"required"`
FirstName string `json:"first_name" binding:"required"`
LastName string `json:"last_name" binding:"required"`
UserName string `json:"user_name" binding:"required"`
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
Enabled bool `json:"enabled" binding:"required"`
}
func (profile *ProfileDTO) ConvertDTOToModel() Profile {
model := Profile{
ID: profile.ID,
CreatedAt: profile.CreatedAt.Time,
UpdatedAt: profile.UpdatedAt.Time,
DeletedAt: profile.DeletedAt,
Version: profile.Version,
FirstName: profile.FirstName,
LastName: profile.LastName,
UserName: profile.UserName,
Email: profile.Email,
Password: profile.Password,
Enabled: profile.Enabled,
}
return model
}
func ConvertProfilesToDtos(profiles []Profile) []ProfileDTO {
dtos := make([]ProfileDTO, len(profiles))
for i, profile := range profiles {
dtos[i] = ProfileDTO{
ID: profile.ID,
CreatedAt: helpers.KontorTime{Time: profile.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: profile.UpdatedAt},
DeletedAt: profile.DeletedAt,
Version: profile.Version,
FirstName: profile.FirstName,
LastName: profile.LastName,
UserName: profile.UserName,
Email: profile.Email,
Password: profile.Password,
Enabled: profile.Enabled,
}
}
return dtos
}
type LoginInput struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
type ProfileDTOList []ProfileDTO
+70
View File
@@ -0,0 +1,70 @@
package models
import (
"kontor-api-echo/internal/helpers"
"time"
"github.com/uptrace/bun"
)
type Token struct {
bun.BaseModel `bun:"table:token"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
DeletedAt *time.Time `bun:"deleted_date,nullzero"`
Version int `bun:"version,default:0"`
Token string `bun:"token,unique:token"`
Name string `bun:"name,unique:name"`
LastUsedAt time.Time `bun:"last_used_date,nullzero,notnull,default:current_timestamp"`
Enabled bool `bun:"enabled,default:true"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
}
type TokenDTO struct {
ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"`
Token string `json:"token"`
Name string `json:"name"`
LastUsedAt *time.Time `json:"last_used_date"`
Enabled bool `json:"enabled"`
ProfileID *string `json:"profile_id"`
}
func (dto TokenDTO) ConvertDTOToModel() Token {
model := Token{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Token: dto.Token,
Name: dto.Name,
LastUsedAt: *dto.LastUsedAt,
Enabled: dto.Enabled,
ProfileID: dto.ProfileID,
}
return model
}
func ConvertTokensToDtos(tokens []Token) []TokenDTO {
dtos := make([]TokenDTO, len(tokens))
for i, token := range tokens {
dtos[i] = TokenDTO{
ID: token.ID,
CreatedAt: helpers.KontorTime{Time: token.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: token.UpdatedAt},
DeletedAt: token.DeletedAt,
Version: token.Version,
ProfileID: token.ProfileID,
}
}
return dtos
}
type TokenDTOList []TokenDTO
@@ -0,0 +1,60 @@
package repository
import (
"context"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type AssignmentRepository struct {
db *bun.DB
}
func NewAssignmentRepository(db *bun.DB) *AssignmentRepository {
repository := &AssignmentRepository{db: db}
return repository
}
func (repository *AssignmentRepository) FindAll(context context.Context) ([]models.Assignment, error) {
var assignments []models.Assignment
result := repository.db.Find(&assignments)
slog.Info("AssignmentRepository#FindAll", "count", result.RowsAffected)
return assignments, nil
}
func (repository *AssignmentRepository) GetById(context context.Context, id string) (models.Assignment, error) {
var assignment = models.Assignment{ID: id}
slog.Info("AssignmentRepository#GetById", "id", id)
result := repository.db.First(&assignment)
if result.Error != nil {
slog.Info("AssignmentRepository#GetById", "error", result.Error.Error())
}
return assignment, result.Error
}
func (repository *AssignmentRepository) Import(assignments models.AssignmentDTOList) {
slog.Info("AssignmentRepository#Import")
for index, assignment := range assignments {
slog.Info("importing", "index", index, "profile", assignment)
model := assignment.ConvertDTOToModel()
existing_item := models.Assignment{ID: assignment.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
@@ -0,0 +1,75 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaActorRepository struct {
db *bun.DB
}
func (repository *MediaActorRepository) Import(dtos models.MediaActorDTOList) {
slog.Info("MediaActorRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaActor{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaActorRepository(db *bun.DB) *MediaActorRepository {
repo := &MediaActorRepository{db: db}
return repo
}
func (repository *MediaActorRepository) FindAll(context context.Context) ([]models.MediaActor, error) {
var actors []models.MediaActor
result := repository.db.Find(&actors)
slog.Info("MediaActorRepository#FindAll", "count", result.RowsAffected)
return actors, nil
}
func (repository *MediaActorRepository) GetById(context context.Context, id string) (*models.MediaActor, error) {
var actor = models.MediaActor{ID: id}
slog.Info("MediaActorRepository#GetById", "id", id)
result := repository.db.First(&actor)
if result.Error != nil {
slog.Info("SportRepository#GetById", "error", result.Error.Error())
}
return &actor, result.Error
}
func (repository *MediaActorRepository) Add(context context.Context, url string) (*models.MediaActor, error) {
slog.Info("MediaActorRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaFileRepository#Add")
}
func (repository *MediaActorRepository) Delete(context context.Context, id string) error {
slog.Info("MediaActorRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaActor)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,76 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaActorFileRepository struct {
db *bun.DB
}
func (repository *MediaActorFileRepository) Import(dtos models.MediaActorFileDTOList) {
slog.Info("MediaActorFileRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaActorFile{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaActorFileRepository(db *bun.DB) *MediaActorFileRepository {
repo := &MediaActorFileRepository{db: db}
return repo
}
func (repository *MediaActorFileRepository) FindAll(context context.Context) ([]models.MediaActorFile, error) {
var actor_files []models.MediaActorFile
result := repository.db.Find(&actor_files)
slog.Info("MediaActorFileRepository#FindAll", "count", result.RowsAffected)
return actor_files, nil
}
func (repository *MediaActorFileRepository) GetById(context context.Context, id string) (*models.MediaActorFile, error) {
var actorfile = models.MediaActorFile{ID: id}
slog.Info("MediaActorFileRepository#GetById", "id", id)
result := repository.db.First(&actorfile)
if result.Error != nil {
slog.Info("MediaActorFileRepository#GetById", "error", result.Error.Error())
return nil, result.Error
}
return &actorfile, result.Error
}
func (repository *MediaActorFileRepository) Add(context context.Context, media_actor_id, media_file_id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileRepository#Add", "actor_id", media_actor_id, "file_id", media_file_id)
return nil, fmt.Errorf("unimplemented method MediaActorFileRepository#Add")
}
func (repository *MediaActorFileRepository) Delete(context context.Context, id string) error {
slog.Info("MediaActorFileRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaActorFile)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,85 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/labstack/echo/v4"
"github.com/uptrace/bun"
)
type MediaArticleRepository struct {
db *bun.DB
}
func (repository *MediaArticleRepository) Import(dtos models.MediaArticleDTOList) {
slog.Info("MediaArticleRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "profile", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaArticle{ID: dto.ID}
err := repository.db.NewSelect().Model(&existing_item).Where("id = ?", dto.ID).Scan(context.Background())
if err != nil {
slog.Info("check existing id: not found - inserting")
_, err := repository.db.NewInsert().Model(&model).Exec(context.Background())
if err != nil {
slog.Info("error during import", "error", err.Error())
}
} else {
slog.Info("check existing id: found - updating")
_, err := repository.db.NewUpdate().Model(&model).
Set("updated_at = ? ", time.Now).
Where("id = ?", model.ID).
Exec(context.Background())
if err != nil {
slog.Info("error during updating", "error", err.Error())
}
}
}
}
func NewMediaArticleRepository(db *bun.DB) *MediaArticleRepository {
repo := &MediaArticleRepository{db: db}
return repo
}
func (repository *MediaArticleRepository) FindAll(context context.Context) ([]models.MediaArticle, error) {
var articles []models.MediaArticle
err := repository.db.NewSelect().Model(&articles).Scan(context)
if err != nil {
slog.Info(err.Error())
return nil, echo.ErrInternalServerError
}
slog.Info("MediaArticleRepository#FindAll", "count", len(articles))
return articles, nil
}
func (repository *MediaArticleRepository) GetById(context context.Context, id string) (*models.MediaArticle, error) {
var article = models.MediaArticle{ID: id}
slog.Info("MediaArticleRepository#GetById", "id", id)
err := repository.db.NewSelect().Model(&article).Where("id = ?", id).Scan(context)
if err != nil {
slog.Info("MediaArticleRepository#GetById", "error", err.Error())
return nil, err
}
return &article, err
}
func (repository *MediaArticleRepository) Add(context context.Context, url string) (*models.MediaArticle, error) {
slog.Info("MediaArticleRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaArticleRepository#Add")
}
func (repository *MediaArticleRepository) Delete(context context.Context, id string) error {
slog.Info("MediaArticleRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaArticle)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaArticleRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,76 @@
package repository
import (
"context"
"fmt"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type MediaFileRepository struct {
db *bun.DB
}
func (repository *MediaFileRepository) Import(dtos models.MediaFileDTOList) {
slog.Info("MediaFileRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaFile{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaFileRepository(db *bun.DB) *MediaFileRepository {
repo := &MediaFileRepository{db: db}
return repo
}
func (repository *MediaFileRepository) FindAll(context context.Context) ([]models.MediaFile, error) {
var files []models.MediaFile
result := repository.db.Find(&files)
slog.Info("MediaFileRepository#FindAll", "count", result.RowsAffected)
return files, nil
}
func (repository *MediaFileRepository) GetById(context context.Context, id string) (*models.MediaFile, error) {
var file = models.MediaFile{ID: id}
slog.Info("MediaFileRepository#GetById", "id", id)
result := repository.db.First(&file)
if result.Error != nil {
slog.Info("MediaFileRepository#GetById", "error", result.Error.Error())
return nil, result.Error
}
return &file, result.Error
}
func (repository *MediaFileRepository) Add(context context.Context, url string) (*models.MediaFile, error) {
slog.Info("MediaFileRepository#Add", "url", url)
return nil, fmt.Errorf("unimplemented method MediaFileRepository#Add")
}
func (repository *MediaFileRepository) Delete(context context.Context, id string) error {
slog.Info("MediaFileRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaFile)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaFileRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,132 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/uptrace/bun"
)
type MediaLoFiRepository struct {
db *bun.DB
}
func (repository *MediaLoFiRepository) Import(dtos models.MediaLoFiDTOList) {
slog.Info("MediaLoFiRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaLoFi{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaLoFiRepository(db *bun.DB) *MediaLoFiRepository {
repo := &MediaLoFiRepository{db: db}
return repo
}
func (repository *MediaLoFiRepository) FindAll(context context.Context) ([]models.MediaLoFi, error) {
var lofis []models.MediaLoFi
err := repository.db.NewSelect().Model(&lofis).Scan(context)
if err != nil {
slog.Info(err.Error())
return nil, echo.ErrInternalServerError
}
slog.Info("MediaLoFiRepository#FindAll", "count", len(lofis))
return lofis, nil
}
func (repository *MediaLoFiRepository) GetById(context context.Context, id string) (*models.MediaLoFi, error) {
var lofi = models.MediaLoFi{ID: id}
slog.Info("MediaLoFiRepository#GetById", "id", id)
err := repository.db.NewSelect().Model(&lofi).Where("id = ?", id).Scan(context)
if err != nil {
slog.Info("MediaLoFiRepository#GetById", "error", err.Error())
return nil, err
}
return &lofi, err
}
func (repository *MediaLoFiRepository) Add(context context.Context, url string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var lofi models.MediaLoFi
search_result := repository.db.Where("url = ?", webLink).First(&lofi)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "lofi", lofi)
return &lofi, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaLoFiRepository#Add URL not found", "url", webLink)
lofi = models.MediaLoFi{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&lofi)
if add_result.Error != nil {
slog.Info("add new MediaLofi", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaLofi", "lofi", lofi)
return &lofi, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaLoFiRepository#Add unknown error")
}
func (repository *MediaLoFiRepository) Update(context context.Context, update models.MediaLoFiDTO) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiRepository#Update", "lofi", update)
var lofi = models.MediaLoFi{ID: update.ID}
slog.Info("MediaLoFiRepository#Update", "id", update.ID)
result := repository.db.First(&lofi)
if result.Error != nil {
slog.Info("MediaLoFiRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
lofi.Update(update)
repository.db.Save(&lofi)
return &lofi, nil
}
func (repository *MediaLoFiRepository) Delete(context context.Context, id string) error {
slog.Info("MediaLoFiRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaLoFi)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaLoFiRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,126 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
type MediaMusicRepository struct {
db *bun.DB
}
func (repository *MediaMusicRepository) Import(dtos models.MediaMusicDTOList) {
slog.Info("MediaMusicRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaMusic{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaMusicRepository(db *bun.DB) *MediaMusicRepository {
repo := &MediaMusicRepository{db: db}
return repo
}
func (repository *MediaMusicRepository) FindAll(context context.Context) ([]models.MediaMusic, error) {
var musics []models.MediaMusic
result := repository.db.Find(&musics)
slog.Info("MediaMusicRepository#FindAll", "count", result.RowsAffected)
return musics, nil
}
func (repository *MediaMusicRepository) GetById(context context.Context, id string) (*models.MediaMusic, error) {
var music = models.MediaMusic{ID: id}
slog.Info("MediaMusicRepository#GetById", "id", id)
result := repository.db.First(&music)
if result.Error != nil {
slog.Info("MediaMusicRepository#GetById", "error", result.Error.Error())
}
return &music, result.Error
}
func (repository *MediaMusicRepository) Add(context context.Context, url string) (*models.MediaMusic, error) {
slog.Info("MediaMusicRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var music models.MediaMusic
search_result := repository.db.Where("url = ?", webLink).First(&music)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "music", music)
return &music, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaMusicRepository#Add URL not found", "url", webLink)
music = models.MediaMusic{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&music)
if add_result.Error != nil {
slog.Info("add new MediaMusic", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaMusic", "music", music)
return &music, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaMusicRepository#Add unknown error")
}
func (repository *MediaMusicRepository) Update(context context.Context, update models.MediaMusicDTO) (*models.MediaMusic, error) {
slog.Info("MediaMusicRepository#Update", "music", update)
var music = models.MediaMusic{ID: update.ID}
slog.Info("MediaMusicRepository#Update", "id", update.ID)
result := repository.db.First(&music)
if result.Error != nil {
slog.Info("MediaMusicRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
music.Update(update)
repository.db.Save(&music)
return &music, nil
}
func (repository *MediaMusicRepository) Delete(context context.Context, id string) error {
slog.Info("MediaMusicRepository#Delete", "id", id)
_, err := repository.db.NewDelete().Model((*models.MediaMusic)(nil)).Where("id = ?", id).Exec(context)
if err != nil {
slog.Info("MediaMusicRepository#Delete", "error", err.Error())
}
return err
}
@@ -0,0 +1,127 @@
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"kontor-api-echo/internal/helpers"
"kontor-api-echo/internal/models"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
)
type MediaVideoRepository struct {
db *bun.DB
}
func (repository *MediaVideoRepository) Import(dtos models.MediaVideoDTOList) {
slog.Info("MediaVideoRepository#Import")
for index, dto := range dtos {
slog.Info("importing", "index", index, "video", dto)
model := dto.ConvertDTOToModel()
existing_item := models.MediaVideo{ID: dto.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
func NewMediaVideoRepository(db *bun.DB) *MediaVideoRepository {
repo := &MediaVideoRepository{db: db}
return repo
}
func (repository *MediaVideoRepository) FindAll(context context.Context) ([]models.MediaVideo, error) {
var videos []models.MediaVideo
result := repository.db.Find(&videos)
slog.Info("MediaVideoRepository#FindAll", "count", result.RowsAffected)
return videos, nil
}
func (repository *MediaVideoRepository) GetById(context context.Context, id string) (*models.MediaVideo, error) {
var video = models.MediaVideo{ID: id}
slog.Info("MediaVideoRepository#GetById", "id", id)
result := repository.db.First(&video)
if result.Error != nil {
slog.Info("MediaVideoRepository#GetById", "error", result.Error.Error())
}
return &video, result.Error
}
func (repository *MediaVideoRepository) Add(context context.Context, url string) (*models.MediaVideo, error) {
slog.Info("MediaVideoRepository#Add", "url", url)
webLink := helpers.StripUrl(url, "v")
var video models.MediaVideo
search_result := repository.db.Where("url = ?", webLink).First(&video)
if search_result.RowsAffected > 0 {
slog.Info("search for existing url", "result", search_result, "video", video)
return &video, nil
}
if errors.Is(search_result.Error, sql.ErrNoRows) {
slog.Info("MediaVideoRepository#Add URL not found", "url", webLink)
video = models.MediaVideo{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DeletedAt: nil,
Version: 0,
WebLink: webLink,
ShouldDownload: false,
Review: true,
Title: "",
FileName: "",
}
add_result := repository.db.Create(&video)
if add_result.Error != nil {
slog.Info("add new MediaVideo", "error", add_result.Error)
return nil, add_result.Error
}
slog.Info("add new MediaVideo", "music", video)
return &video, nil
}
if search_result.Error != nil {
return nil, search_result.Error
}
return nil, fmt.Errorf("MediaVideoRepository#Add unknown error")
}
func (repository *MediaVideoRepository) Update(context context.Context, update models.MediaVideoDTO) (*models.MediaVideo, error) {
slog.Info("MediaVideoRepository#Update", "music", update)
var video = models.MediaVideo{ID: update.ID}
slog.Info("MediaVideoRepository#Update", "id", update.ID)
result := repository.db.First(&video)
if result.Error != nil {
slog.Info("MediaVideoRepository#Update", "error", result.Error.Error())
return nil, result.Error
}
video.Update(update)
repository.db.Save(&video)
return &video, nil
}
func (repository *MediaVideoRepository) Delete(context context.Context, id string) error {
var actor = models.MediaVideo{ID: id}
slog.Info("MediaVideoRepository#Delete", "id", id)
result := repository.db.Delete(&actor)
if result.Error != nil {
slog.Info("MediaVideoRepository#Delete", "error", result.Error.Error())
}
return result.Error
}
@@ -0,0 +1,51 @@
package repository
import (
"context"
"kontor-api-echo/internal/models"
"log/slog"
"github.com/uptrace/bun"
)
type PermissionRepository struct {
db *bun.DB
}
func NewPermissionRepository(db *bun.DB) *PermissionRepository {
repository := &PermissionRepository{db: db}
return repository
}
func (repository *PermissionRepository) FindAll(context context.Context) ([]models.Permission, error) {
var permissions []models.Permission
result := repository.db.Find(&permissions)
slog.Info("ComicRepository#List", "count", result.RowsAffected)
return permissions, nil
}
func (repository *PermissionRepository) Import(permissions models.PermissionDTOList) {
slog.Info("PermissionRepository#Import")
for index, permission := range permissions {
slog.Info("importing", "index", index, "profile", permission)
model := permission.ConvertDTOToModel()
existing_item := models.Permission{ID: permission.ID}
result_existing := repository.db.First(&existing_item)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
@@ -0,0 +1,61 @@
package repository
import (
"context"
"kontor-api-gin/internal/models"
"log/slog"
"gorm.io/gorm"
)
type ProfileRepository struct {
db *gorm.DB
}
func NewProfileRepository(db *gorm.DB) *ProfileRepository {
repository := &ProfileRepository{db: db}
return repository
}
func (repository *ProfileRepository) FindAll(context context.Context) ([]models.Profile, error) {
var profiles []models.Profile
result := repository.db.Find(&profiles)
slog.Info("ProfileRepository#FindAll", "count", result.RowsAffected)
return profiles, nil
}
func (repository *ProfileRepository) FindProfileByEmail(email string) (*models.Profile, error) {
var profile models.Profile
err := repository.db.Model(models.Profile{}).Where("email = ?", email).Take(&profile).Error
if err != nil {
return nil, err
}
return &profile, nil
}
func (repository *ProfileRepository) Import(profiles models.ProfileDTOList) {
slog.Info("ProfileRepository#Import")
for index, profile := range profiles {
slog.Info("importing", "index", index, "profile", profile)
model := profile.ConvertDTOToModel()
existing_profile := models.Profile{ID: profile.ID}
result_existing := repository.db.First(&existing_profile)
if result_existing.Error != nil {
slog.Info("check existing id: not found - inserting")
result := repository.db.Create(&model)
if result.Error != nil {
slog.Info("error during import", "error", result.Error.Error())
}
} else {
slog.Info("check existing id: found - updating")
result := repository.db.Save(&model)
if result.Error != nil {
slog.Info("error during updating", "error", result.Error.Error())
}
}
}
}
+34
View File
@@ -0,0 +1,34 @@
package router
import (
"kontor-api-echo/internal/handlers"
"log/slog"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
)
func New(admin *handlers.AdminHandler, media *handlers.MediaHandler) *echo.Echo {
e := echo.New()
skipper := func(c *echo.Context) bool {
// Skip health check endpoint
return c.Request().URL.Path == "/health"
}
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
HandleError: true,
Skipper: skipper,
LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error {
if v.Error == nil {
slog.Info("REQUEST", "uri", v.URI, "status", v.Status)
} else {
slog.Info("REQUEST-ERROR", "uri", v.URI, "status", v.Status, "err", v.Error.Error())
}
return nil
},
}))
return e
}
@@ -0,0 +1,27 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type AssignmentService struct {
repository *repository.AssignmentRepository
}
func NewAssignmentService(repo *repository.AssignmentRepository) *AssignmentService {
service := &AssignmentService{repository: repo}
return service
}
func (service *AssignmentService) List(context context.Context) ([]models.Assignment, error) {
slog.Info("AssignmentService#List")
return service.repository.FindAll(context)
}
func (service *AssignmentService) Get(context context.Context, id string) (models.Assignment, error) {
slog.Info("AssignmentService#Get")
return service.repository.GetById(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaActorService struct {
repository *repository.MediaActorRepository
}
func NewMediaActorService(repo *repository.MediaActorRepository) *MediaActorService {
service := &MediaActorService{repository: repo}
return service
}
func (service *MediaActorService) List(context context.Context) ([]models.MediaActor, error) {
slog.Info("MediaActorService#List")
return service.repository.FindAll(context)
}
func (service *MediaActorService) Get(context context.Context, id string) (*models.MediaActor, error) {
slog.Info("MediaActorService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaActorService) Add(context context.Context, url string) (*models.MediaActor, error) {
slog.Info("MediaActorService#Add")
return service.repository.Add(context, url)
}
func (service *MediaActorService) Delete(context context.Context, id string) error {
slog.Info("MediaActorService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaActorFileService struct {
repository *repository.MediaActorFileRepository
}
func NewMediaActorFileService(repo *repository.MediaActorFileRepository) *MediaActorFileService {
service := &MediaActorFileService{repository: repo}
return service
}
func (service *MediaActorFileService) List(context context.Context) ([]models.MediaActorFile, error) {
slog.Info("MediaActorFileService#List")
return service.repository.FindAll(context)
}
func (service *MediaActorFileService) Get(context context.Context, id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaActorFileService) Add(context context.Context, media_actor_id, media_file_id string) (*models.MediaActorFile, error) {
slog.Info("MediaActorFileService#Add")
return service.repository.Add(context, media_actor_id, media_file_id)
}
func (service *MediaActorFileService) Delete(context context.Context, id string) error {
slog.Info("MediaActorFileService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-echo/internal/models"
"kontor-api-echo/internal/repository"
"log/slog"
)
type MediaArticleService struct {
repository *repository.MediaArticleRepository
}
func NewMediaArticleService(repo *repository.MediaArticleRepository) *MediaArticleService {
service := &MediaArticleService{repository: repo}
return service
}
func (service *MediaArticleService) List(context context.Context) ([]models.MediaArticle, error) {
slog.Info("MediaArticleService#List")
return service.repository.FindAll(context)
}
func (service *MediaArticleService) Get(context context.Context, id string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaArticleService) Add(context context.Context, url string) (*models.MediaArticle, error) {
slog.Info("MediaArticleService#Add")
return service.repository.Add(context, url)
}
func (service *MediaArticleService) Delete(context context.Context, id string) error {
slog.Info("MediaArticleService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,37 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaFileService struct {
repository *repository.MediaFileRepository
}
func NewMediaFileService(repo *repository.MediaFileRepository) *MediaFileService {
service := &MediaFileService{repository: repo}
return service
}
func (service *MediaFileService) List(context context.Context) ([]models.MediaFile, error) {
slog.Info("MediaFileService#List")
return service.repository.FindAll(context)
}
func (service *MediaFileService) Get(context context.Context, id string) (*models.MediaFile, error) {
slog.Info("MediaFileService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaFileService) Add(context context.Context, url string) (*models.MediaFile, error) {
slog.Info("MediaFileService#Add")
return service.repository.Add(context, url)
}
func (service *MediaFileService) Delete(context context.Context, id string) error {
slog.Info("MediaFileService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaLoFiService struct {
repository *repository.MediaLoFiRepository
}
func NewMediaLoFiService(repo *repository.MediaLoFiRepository) *MediaLoFiService {
service := &MediaLoFiService{repository: repo}
return service
}
func (service *MediaLoFiService) List(context context.Context) ([]models.MediaLoFi, error) {
slog.Info("MediaLoFiService#List")
return service.repository.FindAll(context)
}
func (service *MediaLoFiService) Get(context context.Context, id string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaLoFiService) Add(context context.Context, url string) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Add")
return service.repository.Add(context, url)
}
func (service *MediaLoFiService) Update(context context.Context, lofi models.MediaLoFiDTO) (*models.MediaLoFi, error) {
slog.Info("MediaLoFiService#Update")
return service.repository.Update(context, lofi)
}
func (service *MediaLoFiService) Delete(context context.Context, id string) error {
slog.Info("MediaLoFiService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaMusicService struct {
repository *repository.MediaMusicRepository
}
func NewMediaMusicService(repo *repository.MediaMusicRepository) *MediaMusicService {
service := &MediaMusicService{repository: repo}
return service
}
func (service *MediaMusicService) List(context context.Context) ([]models.MediaMusic, error) {
slog.Info("MediaMusicService#List")
return service.repository.FindAll(context)
}
func (service *MediaMusicService) Get(context context.Context, id string) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaMusicService) Add(context context.Context, url string) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Add")
return service.repository.Add(context, url)
}
func (service *MediaMusicService) Update(context context.Context, music models.MediaMusicDTO) (*models.MediaMusic, error) {
slog.Info("MediaMusicService#Update")
return service.repository.Update(context, music)
}
func (service *MediaMusicService) Delete(context context.Context, id string) error {
slog.Info("MediaMusicService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,42 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type MediaVideoService struct {
repository *repository.MediaVideoRepository
}
func NewMediaVideoService(repo *repository.MediaVideoRepository) *MediaVideoService {
service := &MediaVideoService{repository: repo}
return service
}
func (service *MediaVideoService) List(context context.Context) ([]models.MediaVideo, error) {
slog.Info("MediaVideoService#List")
return service.repository.FindAll(context)
}
func (service *MediaVideoService) Get(context context.Context, id string) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Get")
return service.repository.GetById(context, id)
}
func (service *MediaVideoService) Add(context context.Context, url string) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Add")
return service.repository.Add(context, url)
}
func (service *MediaVideoService) Update(context context.Context, music models.MediaVideoDTO) (*models.MediaVideo, error) {
slog.Info("MediaVideoService#Update")
return service.repository.Update(context, music)
}
func (service *MediaVideoService) Delete(context context.Context, id string) error {
slog.Info("MediaVideoService#Delete")
return service.repository.Delete(context, id)
}
@@ -0,0 +1,23 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type PermissionService struct {
repository *repository.PermissionRepository
}
func NewPermissionService(repository *repository.PermissionRepository) *PermissionService {
service := &PermissionService{repository: repository}
return service
}
func (service PermissionService) List(context context.Context) ([]models.Permission, error) {
slog.Info("ComicService#List")
return service.repository.FindAll(context)
}
+22
View File
@@ -0,0 +1,22 @@
package service
import (
"context"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log/slog"
)
type ProfileService struct {
repository *repository.ProfileRepository
}
func NewProfileService(repo *repository.ProfileRepository) *ProfileService {
service := &ProfileService{repository: repo}
return service
}
func (service *ProfileService) List(context context.Context) ([]models.Profile, error) {
slog.Info("ProfileService#List")
return service.repository.FindAll(context)
}
-62
View File
@@ -1,62 +0,0 @@
package schema
import (
"time"
"github.com/uptrace/bun"
)
type Profile struct {
bun.BaseModel `bun:"table:profile"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
FirstName string `bun:"first_name"`
LastName string `bun:"last_name"`
UserName string `bun:"user_name,unique:user_name"`
Email string `bun:"email"`
Password string `bun:"password"`
Enabled bool `bun:"enabled"`
Assignments []Assignment `bun:"rel:has-many,join:id=profile_id"`
Tokens []Token `bun:"rel:has-many,join:id=profile_id"`
}
type Permission struct {
bun.BaseModel `bun:"table:permission"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
Assignments []Assignment `bun:"rel:has-many,join:id=permission_id"`
}
type Token struct {
bun.BaseModel `bun:"table:token"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name,unique:name"`
LastUsedAt time.Time `bun:"last_used_date,nullzero,notnull,default:current_timestamp"`
Enabled bool `bun:"enabled,default:true"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
}
type Assignment struct {
bun.BaseModel `bun:"table:assignment"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
ProfileID *string `bun:"profile_id"`
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
PermissionID *string `bun:"permission_id"`
Permission *Permission `bun:"rel:belongs-to,join:permission_id=id"`
}
-79
View File
@@ -1,79 +0,0 @@
package schema
import (
"time"
"github.com/uptrace/bun"
)
type MediaFile struct {
bun.BaseModel `bun:"table:media_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_file_id"`
}
type MediaActor struct {
bun.BaseModel `bun:"table:media_actor"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Name string `bun:"name"`
WebLink string `bun:"url,unique:url"`
MediaActorFiles []MediaActorFile `bun:"rel:has-many,join:id=media_actor_id"`
}
type MediaActorFile struct {
bun.BaseModel `bun:"table:media_actor_file"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
MediaActorID *string `bun:"media_actor_id"`
MediaActor *MediaActor `bun:"rel:belongs-to,join:media_actor_id=id"`
MediaFileID *string `bun:"media_file_id"`
MediaFile *MediaFile `bun:"rel:belongs-to,join:media_file_id=id"`
}
type MediaArticle struct {
bun.BaseModel `bun:"table:media_article"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
}
type MediaVideo struct {
bun.BaseModel `bun:"table:media_article"`
ID string `bun:"id,pk"`
CreatedAt time.Time `bun:"created_date,nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:"last_modified_date,nullzero,notnull,default:current_timestamp"`
Version int `bun:"version,default:0"`
CloudLink string `bun:"cloud_link"`
FileName string `bun:"file_name"`
Path string `bun:"path"`
Review bool `bun:"review"`
Title string `bun:"title"`
WebLink string `bun:"url,unique:url"`
ShouldDownload bool `bun:"should_download"`
}
+3
View File
@@ -0,0 +1,3 @@
# Added by goreleaser init:
dist/
data/
+55
View File
@@ -0,0 +1,55 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 2
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
- main: ./...
env:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- amd64
archives:
- formats: [tar.gz]
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
formats: [zip]
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
release:
footer: >-
---
Released by [GoReleaser](https://github.com/goreleaser/goreleaser).
+4 -1
View File
@@ -9,8 +9,11 @@ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
# Copy the source code # Copy the source code
COPY . . COPY . .
ARG VERSION="dev"
ARG COMMIT="unset"
ARG DATE="unset"
# Build the Go application (strip debug info for smaller size) # 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-gin/internal/globals.Version=${VERSION} -X kontor-api-gin/internal/globals.Commit=${COMMIT} -X kontor-api-gin/internal/globals.Date=${DATE}" -o kontor cmd/kontor/main.go
# ---------- Stage 2: Final ---------- # ---------- Stage 2: Final ----------
FROM alpine:latest FROM alpine:latest
+2
View File
@@ -6,6 +6,8 @@ body {
font-family: Arial; font-family: Arial;
padding: 10px; padding: 10px;
background: lightgrey; background: lightgrey;
padding-top: 56px;
padding-bottom: 56px;
} }
/* Header/Blog Title */ /* Header/Blog Title */
+9 -1
View File
@@ -9,5 +9,13 @@ cd "$(dirname "$0")/.."
source version source version
echo " => Baue Image localhost/kontor-gin:$kontorVersion" echo " => Baue Image localhost/kontor-gin:$kontorVersion"
buildah build -t kontor-gin:$kontorVersion kontor-gin buildah build \
-t kontor-gin:$kontorVersion \
--build-arg VERSION=0.4.0-SNAPSHOT \
--build-arg COMMIT=$(git rev-parse HEAD) \
--build-arg DATE=$(date +%Y-%m-%dT%H:%M:%S) \
kontor-gin
cd kontor-gin
go build -ldflags "-X kontor-api-gin/internal/cmd.commit=`git rev-parse HEAD` -X kontor-api-gin/internal/cmd.version=0.4.0-SNAPSHOT -X kontor-api-gin/internal/cmd.date=`date +%Y-%m-%dT%H:%M:%S`" -o ~/.local/bin/kontor-cli cmd/kontor-cli/main.go
go build -ldflags "-X kontor-api-gin/internal/globals.Version=0.4.0-SNAPSHOT -X kontor-api-gin/internal/globals.Commit=`git rev-parse HEAD` -X kontor-api-gin/internal/globals.Date=`date +%Y-%m-%dT%H:%M:%S`" -o ~/.local/bin/kontor cmd/kontor/main.go
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# script/cibuild.local:
set -e
cd "$(dirname "$0")/.."
source version
cd kontor-gin
go build -ldflags "-X kontor-api-gin/internal/cmd.commit=`git rev-parse HEAD` -X kontor-api-gin/internal/cmd.version=0.4.0-SNAPSHOT -X kontor-api-gin/internal/cmd.date=`date +%Y-%m-%dT%H:%M:%S`" -o ~/.local/bin/kontor-cli cmd/kontor-cli/main.go
go build -ldflags "-X kontor-api-gin/internal/globals.Version=0.4.0-SNAPSHOT -X kontor-api-gin/internal/globals.Commit=`git rev-parse HEAD` -X kontor-api-gin/internal/globals.Date=`date +%Y-%m-%dT%H:%M:%S`" -o ~/.local/bin/kontor cmd/kontor/main.go
+4 -16
View File
@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"fmt"
"kontor-api-gin/internal/config" "kontor-api-gin/internal/config"
"kontor-api-gin/internal/handlers" "kontor-api-gin/internal/handlers"
"kontor-api-gin/internal/router" "kontor-api-gin/internal/router"
@@ -16,7 +15,6 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/spf13/viper"
) )
func main() { func main() {
@@ -26,16 +24,7 @@ func main() {
log.Fatalf("Failed to initialize config: %v", err) log.Fatalf("Failed to initialize config: %v", err)
} }
dsn := fmt.Sprintf( db, err := config.NewDB(config.ServerConfig.DB)
"host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
viper.GetString("db.host"),
viper.GetString("db.user"),
viper.GetString("db.password"),
viper.GetString("db.name"),
viper.GetInt("db.port"),
)
db, err := config.NewDB(dsn)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -45,21 +34,20 @@ func main() {
// Set Gin mode based on environment // Set Gin mode based on environment
// Production mode disables debug output // Production mode disables debug output
if viper.GetString("gin.mode") == "release" { if config.ServerConfig.Gin.Mode == "release" {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
} }
r := router.New( r := router.New(
handlers.NewAdminHandler(db, []byte(viper.GetString("api_secret"))), handlers.NewAdminHandler(db, config.ServerConfig.ApiSecret),
handlers.NewBookshelfHandler(db), handlers.NewBookshelfHandler(db),
handlers.NewComicsHandler(db), handlers.NewComicsHandler(db),
handlers.NewMediaHandler(db), handlers.NewMediaHandler(db),
handlers.NewTyscHandler(db), handlers.NewTyscHandler(db),
handlers.NewWebAppHandler(db, []byte(viper.GetString("api_secret"))),
) )
srv := &http.Server{ srv := &http.Server{
Addr: ":" + strconv.Itoa(viper.GetInt("port")), Addr: ":" + strconv.Itoa(config.ServerConfig.Server.Port),
Handler: r, Handler: r,
ReadHeaderTimeout: 5 * time.Second, ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second,
+1 -3
View File
@@ -3,11 +3,11 @@ module kontor-api-gin
go 1.26.8 go 1.26.8
require ( require (
github.com/JanikL/go-artemis v0.0.0-20250315150102-10f50406b94d
github.com/gin-contrib/cors v1.7.2 github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/sessions v1.1.2 github.com/gin-contrib/sessions v1.1.2
github.com/gin-contrib/slog v1.1.0 github.com/gin-contrib/slog v1.1.0
github.com/gin-gonic/gin v1.12.0 github.com/gin-gonic/gin v1.12.0
github.com/go-stomp/stomp/v3 v3.1.5
github.com/golang-jwt/jwt/v5 v5.3.1 github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/spf13/cobra v1.10.2 github.com/spf13/cobra v1.10.2
@@ -32,8 +32,6 @@ require (
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.3 // indirect github.com/go-playground/validator/v10 v10.30.3 // indirect
github.com/go-stomp/stomp v2.1.4+incompatible // indirect
github.com/go-stomp/stomp/v3 v3.1.5 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect github.com/goccy/go-yaml v1.19.2 // indirect
-4
View File
@@ -1,5 +1,3 @@
github.com/JanikL/go-artemis v0.0.0-20250315150102-10f50406b94d h1:kXaXwcE0eB92pqrluNv1/9IlSJyn56g8Kfl9KdFbHUM=
github.com/JanikL/go-artemis v0.0.0-20250315150102-10f50406b94d/go.mod h1:vVJ6kbfbD0LWMirPFhis2ZZCg5kP6IZYAbRJEGBJwE0=
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
github.com/bytedance/sonic v1.15.4 h1:FgtV/4aBHpla9AxuMpuuzVUpa/Cf3izufkxNmnEzdI8= github.com/bytedance/sonic v1.15.4 h1:FgtV/4aBHpla9AxuMpuuzVUpa/Cf3izufkxNmnEzdI8=
@@ -36,8 +34,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8= github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8=
github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc= github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc=
github.com/go-stomp/stomp v2.1.4+incompatible h1:D3SheUVDOz9RsjVWkoh/1iCOwD0qWjyeTZMUZ0EXg2Y=
github.com/go-stomp/stomp v2.1.4+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c=
github.com/go-stomp/stomp/v3 v3.1.5 h1:Pikz1OSusmSKUm5mRKYfXQZaDatfZ+EnBBA1JJ2xENQ= github.com/go-stomp/stomp/v3 v3.1.5 h1:Pikz1OSusmSKUm5mRKYfXQZaDatfZ+EnBBA1JJ2xENQ=
github.com/go-stomp/stomp/v3 v3.1.5/go.mod h1:ztzZej6T2W4Y6FlD+Tb5n7HQP3/O5UNQiuC169pIp10= github.com/go-stomp/stomp/v3 v3.1.5/go.mod h1:ztzZej6T2W4Y6FlD+Tb5n7HQP3/O5UNQiuC169pIp10=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
+87 -86
View File
@@ -1,12 +1,10 @@
package api package api
import ( import (
"encoding/json"
"fmt" "fmt"
"kontor-api-gin/internal/config" "kontor-api-gin/internal/config"
"kontor-api-gin/internal/models" "kontor-api-gin/internal/models"
"log/slog" "log/slog"
"os"
"resty.dev/v3" "resty.dev/v3"
) )
@@ -21,42 +19,43 @@ type LoginResponse struct {
} }
type ExportData struct { type ExportData struct {
Sport models.SportDTOList `json:"sport"` Sport models.SportDTOList `json:"sport"`
Player models.PlayerDTOList `json:"player"` Player models.PlayerDTOList `json:"player"`
Team []models.TeamDTO `json:"team"` Team models.TeamDTOList `json:"team"`
Position []models.PositionDTO `json:"field_position"` Position models.PositionDTOList `json:"field_position"`
Rooster []models.RoosterDTO `json:"rooster"` Rooster models.RoosterDTOList `json:"rooster"`
Vendor []models.VendorDTO `json:"vendor"` Vendor models.VendorDTOList `json:"vendor"`
CardSet []models.CardSetDTO `json:"card_set"` CardSet models.CardSetDTOList `json:"card_set"`
Card []models.CardDTO `json:"card"` Card models.CardDTOList `json:"card"`
Artist []models.ArtistDTO `json:"artist"` Artist models.ArtistDTOList `json:"artist"`
Publisher []models.PublisherDTO `json:"publisher"` Publisher models.PublisherDTOList `json:"publisher"`
Worktype []models.WorkTypeDTO `json:"worktype"` Worktype models.WorkTypeDTOList `json:"worktype"`
Comic []models.ComicDTO `json:"comic"` Comic models.ComicDTOList `json:"comic"`
Volume []models.VolumeDTO `json:"volume"` Volume models.VolumeDTOList `json:"volume"`
StoryArc []models.StoryArcDTO `json:"story_arc"` StoryArc models.StoryArcDTOList `json:"story_arc"`
Issue []models.IssueDTO `json:"issue"` Issue models.IssueDTOList `json:"issue"`
TradePaperback []models.TradePaperbackDTO `json:"trade_paperback"` TradePaperback models.TradePaperbackDTOList `json:"trade_paperback"`
ComicWork []models.ComicworkDTO `json:"comic_work"` ComicWork models.ComicworkDTOList `json:"comic_work"`
IssueWork []models.IssueworkDTO `json:"issue_work"` IssueWork models.IssueworkDTOList `json:"issue_work"`
Article []models.ArticleDTO `json:"article"` Article models.ArticleDTOList `json:"article"`
BookshelfPublisher []models.BookshelfPublisherDTO `json:"bookshelf_publisher"` BookshelfPublisher models.BookshelfPublisherDTOList `json:"bookshelf_publisher"`
Book []models.BookDTO `json:"book"` Book models.BookDTOList `json:"book"`
Author []models.AuthorDTO `json:"author"` Author models.AuthorDTOList `json:"author"`
ArticleAuthor []models.ArticleAuthorDTO `json:"article_author"` ArticleAuthor models.ArticleAuthorDTOList `json:"article_author"`
BookAuthor []models.BookAuthorDTO `json:"book_author"` BookAuthor models.BookAuthorDTOList `json:"book_author"`
MediaArticle []models.MediaArticleDTO `json:"media_article"` MediaArticle models.MediaArticleDTOList `json:"media_article"`
MediaVideo []models.MediaVideoDTO `json:"media_video"` MediaVideo models.MediaVideoDTOList `json:"media_video"`
MediaLoFi models.MediaLoFiDTOList `json:"media_lofi"` MediaLoFi models.MediaLoFiDTOList `json:"media_lofi"`
MediaFile []models.MediaFileDTO `json:"media_file"` MediaMusic models.MediaMusicDTOList `json:"media_music"`
MediaActor []models.MediaActorDTO `json:"media_actor"` MediaFile models.MediaFileDTOList `json:"media_file"`
MediaActorFile []models.MediaActorFileDTO `json:"media_actor_file"` MediaActor models.MediaActorDTOList `json:"media_actor"`
Profile []models.ProfileDTO `json:"profile"` MediaActorFile models.MediaActorFileDTOList `json:"media_actor_file"`
Permission []models.PermissionDTO `json:"permission"` Profile models.ProfileDTOList `json:"profile"`
Assignment []models.AssignmentDTO `json:"assignment"` Permission models.PermissionDTOList `json:"permission"`
Token []models.TokenDTO `json:"token"` Assignment models.AssignmentDTOList `json:"assignment"`
MailAccount []models.MailAccountDTO `json:"mail_account"` Token models.TokenDTOList `json:"token"`
Mail []models.MailDTO `json:"mail"` MailAccount models.MailAccountDTOList `json:"mail_account"`
Mail models.MailDTOList `json:"mail"`
} }
func (e *ExportData) GetMap() map[string]any { func (e *ExportData) GetMap() map[string]any {
@@ -75,40 +74,41 @@ func (e *ExportData) GetMap() map[string]any {
var ( var (
Sports models.SportDTOList Sports models.SportDTOList
Players models.PlayerDTOList Players models.PlayerDTOList
Teams []models.TeamDTO Teams models.TeamDTOList
Positions []models.PositionDTO Positions models.PositionDTOList
Roosters []models.RoosterDTO Roosters models.RoosterDTOList
Vendors []models.VendorDTO Vendors models.VendorDTOList
Cardsets []models.CardSetDTO Cardsets models.CardSetDTOList
Cards []models.CardDTO Cards models.CardDTOList
Artists []models.ArtistDTO Artists models.ArtistDTOList
Publishers []models.PublisherDTO Publishers models.PublisherDTOList
Worktypes []models.WorkTypeDTO Worktypes models.WorkTypeDTOList
Comics []models.ComicDTO Comics models.ComicDTOList
Volumes []models.VolumeDTO Volumes models.VolumeDTOList
Storyarcs []models.StoryArcDTO Storyarcs models.StoryArcDTOList
Issues []models.IssueDTO Issues models.IssueDTOList
Tradepaperbacks []models.TradePaperbackDTO Tradepaperbacks models.TradePaperbackDTOList
Comicworks []models.ComicworkDTO Comicworks models.ComicworkDTOList
Issueworks []models.IssueworkDTO Issueworks models.IssueworkDTOList
Articles []models.ArticleDTO Articles models.ArticleDTOList
Bookshelf_publishers []models.BookshelfPublisherDTO Bookshelf_publishers models.BookshelfPublisherDTOList
Books []models.BookDTO Books models.BookDTOList
Authors []models.AuthorDTO Authors models.AuthorDTOList
Article_authors []models.ArticleAuthorDTO Article_authors models.ArticleAuthorDTOList
Book_authors []models.BookAuthorDTO Book_authors models.BookAuthorDTOList
Mediaarticles []models.MediaArticleDTO Mediaarticles models.MediaArticleDTOList
Mediavideos []models.MediaVideoDTO Mediavideos models.MediaVideoDTOList
Mediaactors []models.MediaActorDTO Mediaactors models.MediaActorDTOList
Mediaactorfiles []models.MediaActorFileDTO Mediaactorfiles models.MediaActorFileDTOList
Mediafiles []models.MediaFileDTO Mediafiles models.MediaFileDTOList
Medialofis models.MediaLoFiDTOList Medialofis models.MediaLoFiDTOList
Profiles []models.ProfileDTO MediaMusics models.MediaMusicDTOList
Permissions []models.PermissionDTO Profiles models.ProfileDTOList
Assignments []models.AssignmentDTO Permissions models.PermissionDTOList
Tokens []models.TokenDTO Assignments models.AssignmentDTOList
Mailaccounts []models.MailAccountDTO Tokens models.TokenDTOList
Mail []models.MailDTO Mailaccounts models.MailAccountDTOList
Mail models.MailDTOList
) )
var Registry map[string]any var Registry map[string]any
@@ -174,6 +174,7 @@ func GetData(server config.Server, apiVersion string) (data *ExportData, err err
MediaActorFile: Mediaactorfiles, MediaActorFile: Mediaactorfiles,
MediaFile: Mediafiles, MediaFile: Mediafiles,
MediaLoFi: Medialofis, MediaLoFi: Medialofis,
MediaMusic: MediaMusics,
Profile: Profiles, Profile: Profiles,
Permission: Permissions, Permission: Permissions,
Assignment: Assignments, Assignment: Assignments,
@@ -186,6 +187,7 @@ func GetData(server config.Server, apiVersion string) (data *ExportData, err err
} }
func DeleteData(target config.Server, path, id string) { func DeleteData(target config.Server, path, id string) {
slog.Info("DeleteData")
url := fmt.Sprintf("%s/%s/%s/%s", target.Url, config.Config.ApiVersion, path, id) url := fmt.Sprintf("%s/%s/%s/%s", target.Url, config.Config.ApiVersion, path, id)
client := resty.New() client := resty.New()
client.SetLoggerWarnLevel(true) client.SetLoggerWarnLevel(true)
@@ -199,6 +201,19 @@ func DeleteData(target config.Server, path, id string) {
} }
} }
func PushData(target config.Server, path string, data any, result any) (response *resty.Response, err error) {
url := fmt.Sprintf("%s/%s/%s", target.Url, config.Config.ApiVersion, path)
client := resty.New()
token := GetToken(client, target)
response, err = client.R().
SetBody(data).
SetAuthToken(token).
SetHeader("Accept", "application/json").
SetResult(result).
Post(url)
return response, err
}
func UpdateData(target config.Server, path string, v any) { func UpdateData(target config.Server, path string, v any) {
client := resty.New() client := resty.New()
client.SetLoggerWarnLevel(true) client.SetLoggerWarnLevel(true)
@@ -207,21 +222,6 @@ func UpdateData(target config.Server, path string, v any) {
PostJSON(client, target, token, config.Config.ApiVersion, path, v, &result) PostJSON(client, target, token, config.Config.ApiVersion, path, v, &result)
} }
func WriteJson(data *ExportData, fileName string) error {
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
slog.Info("JSON MarshalIndent failed", "Error:", err)
return err
}
// Write bytes to file
err = os.WriteFile(fileName, jsonData, 0644)
if err != nil {
slog.Info("Error writing file:", "Error", err)
return err
}
return nil
}
func GetJSON(client *resty.Client, token string, server config.Server, path string, v any) { func GetJSON(client *resty.Client, token string, server config.Server, path string, v any) {
url := fmt.Sprintf("%s/%s/%s", server.Url, config.Config.ApiVersion, path) url := fmt.Sprintf("%s/%s/%s", server.Url, config.Config.ApiVersion, path)
if config.Verbose > 2 { if config.Verbose > 2 {
@@ -299,6 +299,7 @@ func init() {
"media/files": &Mediafiles, "media/files": &Mediafiles,
"media/actorfiles": &Mediaactorfiles, "media/actorfiles": &Mediaactorfiles,
"media/lofis": &Medialofis, "media/lofis": &Medialofis,
"media/musics": &MediaMusics,
"user/profiles": &Profiles, "user/profiles": &Profiles,
"user/permissions": &Permissions, "user/permissions": &Permissions,
"user/assignments": &Assignments, "user/assignments": &Assignments,
+36
View File
@@ -0,0 +1,36 @@
package api
import (
"encoding/json"
"log/slog"
"os"
)
func WriteJson(data *ExportData, fileName string) error {
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
slog.Info("JSON MarshalIndent failed", "Error:", err)
return err
}
// Write bytes to file
err = os.WriteFile(fileName, jsonData, 0644)
if err != nil {
slog.Info("Error writing file:", "Error", err.Error())
return err
}
return nil
}
func ReadJson(data *ExportData, fileName string) error {
content, err := os.ReadFile(fileName)
if err != nil {
slog.Info("Error reading file", "Error", err.Error())
return err
}
if err := json.Unmarshal(content, data); err != nil {
slog.Info("Error unmarshal json", "Error", err.Error())
return err
}
return nil
}
+2 -14
View File
@@ -10,11 +10,6 @@ import (
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"resty.dev/v3"
)
var (
servername string
) )
var addLinksCmd = &cobra.Command{ var addLinksCmd = &cobra.Command{
@@ -31,18 +26,11 @@ var addLinksCmd = &cobra.Command{
slog.Warn("add links failed", "error", err) slog.Warn("add links failed", "error", err)
os.Exit(1) os.Exit(1)
} }
client := resty.New() localServer := config.Config.Server[config.ServerName]
localServer := config.Config.Server[servername]
token := api.GetToken(client, localServer)
for _, line := range lines { for _, line := range lines {
lofiAdd := models.MediaLofiAdd{Url: line} lofiAdd := models.MediaLofiAdd{Url: line}
addResult := &models.MediaLoFi{} addResult := &models.MediaLoFi{}
response, err := client.R(). response, err := api.PushData(localServer, "media/lofis", lofiAdd, addResult)
SetBody(lofiAdd).
SetAuthToken(token).
SetHeader("Accept", "application/json").
SetResult(addResult).
Post("http://localhost:8550/api/v1/media/lofis")
if err != nil { if err != nil {
slog.Info("Add Lofi", "error", err.Error()) slog.Info("Add Lofi", "error", err.Error())
} }
+1 -9
View File
@@ -7,12 +7,9 @@ import (
"log/slog" "log/slog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper"
"resty.dev/v3" "resty.dev/v3"
) )
var filename string
var exportCmd = &cobra.Command{ var exportCmd = &cobra.Command{
Use: "export", Use: "export",
Short: "Export Kontor Database", Short: "Export Kontor Database",
@@ -28,7 +25,7 @@ var exportCmd = &cobra.Command{
localServer := config.Config.Server[config.ServerName] localServer := config.Config.Server[config.ServerName]
export, _ := api.GetData(localServer, config.Config.ApiVersion) export, _ := api.GetData(localServer, config.Config.ApiVersion)
err := api.WriteJson(export, filename) err := api.WriteJson(export, config.FileName)
if err != nil { if err != nil {
slog.Info("WriteJon failed", "Error:", err) slog.Info("WriteJon failed", "Error:", err)
} }
@@ -38,9 +35,4 @@ var exportCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(exportCmd) rootCmd.AddCommand(exportCmd)
exportCmd.PersistentFlags().StringVarP(&filename, "file", "f", "/home/tpeetz/.sync/media/data-gin.json", "Filename to store data")
viper.BindPFlag("file", exportCmd.PersistentFlags().Lookup("file"))
exportCmd.PersistentFlags().StringVarP(&config.Config.ApiVersion, "api", "a", "api/v1", "API Version")
viper.BindPFlag("api", exportCmd.PersistentFlags().Lookup("api"))
} }
+138
View File
@@ -1,6 +1,11 @@
package cmd package cmd
import ( import (
"kontor-api-gin/internal/api"
"kontor-api-gin/internal/config"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"log"
"log/slog" "log/slog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -13,6 +18,139 @@ var importCmd = &cobra.Command{
// Args: cobra.ExactArgs(1), // Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
slog.Info("import kontor") slog.Info("import kontor")
slog.Info("Verbosity level", "level", config.Verbose)
data := api.ExportData{}
err := api.ReadJson(&data, config.FileName)
if err != nil {
slog.Info("Error importing data", "Error", err.Error())
}
db, err := config.NewDB(config.Config.DB)
if err != nil {
log.Fatal(err)
}
if config.Config.DB.Type == "sqlite" {
if err := db.AutoMigrate(
models.Profile{},
models.Permission{},
models.Assignment{},
models.Sport{},
models.Player{},
models.Team{},
models.Position{},
models.Rooster{},
models.Vendor{},
models.CardSet{},
models.Card{},
models.Artist{},
models.Publisher{},
models.WorkType{},
models.Comic{},
models.Volume{},
models.StoryArc{},
models.Issue{},
models.TradePaperback{},
models.ComicWork{},
models.IssueWork{},
models.Article{},
models.BookshelfPublisher{},
models.Book{},
models.Author{},
models.ArticleAuthor{},
models.BookAuthor{},
models.MediaArticle{},
models.MediaVideo{},
models.MediaLoFi{},
models.MediaMusic{},
models.MediaFile{},
models.MediaActor{},
models.MediaActorFile{},
models.Token{},
models.MailAccount{},
models.Mail{},
); err != nil {
log.Fatal(err)
}
}
profileRepository := repository.NewProfileRepository(db)
profileRepository.Import(data.Profile)
permissionRepository := repository.NewPermissionRepository(db)
permissionRepository.Import(data.Permission)
assignmentRepository := repository.NewAssignmentRepository(db)
assignmentRepository.Import(data.Assignment)
sportRepository := repository.NewSportRepository(db)
sportRepository.Import(data.Sport)
playerRepository := repository.NewPlayerRepository(db)
playerRepository.Import(data.Player)
teamRepository := repository.NewTeamRepository(db)
teamRepository.Import(data.Team)
roosterRepository := repository.NewRoosterRepository(db)
roosterRepository.Import(data.Rooster)
vendorRepository := repository.NewVendorRepository(db)
vendorRepository.Import(data.Vendor)
cardSetRepository := repository.NewCardSetRepository(db)
cardSetRepository.Import(data.CardSet)
cardRepository := repository.NewCardRepository(db)
cardRepository.Import(data.Card)
artistRepository := repository.NewArtistRepository(db)
artistRepository.Import(data.Artist)
publisherRepository := repository.NewPublisherRepository(db)
publisherRepository.Import(data.Publisher)
workTypeRepository := repository.NewWorkTypeRepository(db)
workTypeRepository.Import(data.Worktype)
comicRepository := repository.NewComicRepository(db)
comicRepository.Import(data.Comic)
volumeRepository := repository.NewVolumeRepository(db)
volumeRepository.Import(data.Volume)
storyArcRepository := repository.NewStoryArcRepository(db)
storyArcRepository.Import(data.StoryArc)
issueRepository := repository.NewIssueRepository(db)
issueRepository.Import(data.Issue)
tradePaperbackRepository := repository.NewTradePaperbackRepository(db)
tradePaperbackRepository.Import(data.TradePaperback)
comicWorkRepository := repository.NewComicworkRepository(db)
comicWorkRepository.Import(data.ComicWork)
issueWorkRepository := repository.NewIssueworkRepository(db)
issueWorkRepository.Import(data.IssueWork)
articleRepository := repository.NewArticleRepository(db)
articleRepository.Import(data.Article)
bookshelfPublisherRepository := repository.NewBookshelfPublisherRepository(db)
bookshelfPublisherRepository.Import(data.BookshelfPublisher)
bookRepository := repository.NewBookRepository(db)
bookRepository.Import(data.Book)
authorRepository := repository.NewAuthorRepository(db)
authorRepository.Import(data.Author)
articleAuthorRepository := repository.NewArticleAuthorRepository(db)
articleAuthorRepository.Import(data.ArticleAuthor)
bookAuthorRepository := repository.NewBookAuthorRepository(db)
bookAuthorRepository.Import(data.BookAuthor)
mediaArticleRepository := repository.NewMediaArticleRepository(db)
mediaArticleRepository.Import(data.MediaArticle)
mediaVideoRepository := repository.NewMediaVideoRepository(db)
mediaVideoRepository.Import(data.MediaVideo)
mediaLoFiRepository := repository.NewMediaLoFiRepository(db)
mediaLoFiRepository.Import(data.MediaLoFi)
mediaMusicRepository := repository.NewMediaMusicRepository(db)
mediaMusicRepository.Import(data.MediaMusic)
mediaFileRepository := repository.NewMediaFileRepository(db)
mediaFileRepository.Import(data.MediaFile)
mediaActorRepository := repository.NewMediaActorRepository(db)
mediaActorRepository.Import(data.MediaActor)
mediaActorFileRepository := repository.NewMediaActorFileRepository(db)
mediaActorFileRepository.Import(data.MediaActorFile)
tokenRepository := repository.NewTokenRepository(db)
tokenRepository.Import(data.Token)
mailAccountRepository := repository.NewMailAccountRepository(db)
mailAccountRepository.Import(data.MailAccount)
mailRepository := repository.NewMailRepository(db)
mailRepository.Import(data.Mail)
slog.Info("importing Profiles", "count", len(data.Profile))
slog.Info("importing Permissions", "count", len(data.Permission))
slog.Info("importing Assignments", "count", len(data.Assignment))
slog.Info("importing MediaFiles", "count", len(data.MediaFile))
slog.Info("importing MediaLofis", "count", len(data.MediaLoFi))
slog.Info("importing MediaLofi", "media_lofi", data.MediaLoFi[0])
slog.Info("import kontor finished")
}, },
} }
+13
View File
@@ -35,8 +35,21 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&config.CfgFile, "config", "c", "/home/tpeetz/.config/kli.yaml", "config file") rootCmd.PersistentFlags().StringVarP(&config.CfgFile, "config", "c", "/home/tpeetz/.config/kli.yaml", "config file")
rootCmd.PersistentFlags().CountVarP(&config.Verbose, "verbose", "v", "increase verbosity (-v, -vv, -vvv)") rootCmd.PersistentFlags().CountVarP(&config.Verbose, "verbose", "v", "increase verbosity (-v, -vv, -vvv)")
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config")) viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
exportCmd.Flags().StringVarP(&config.ServerName, "servername", "s", "local", "Define server to get Kontor items") exportCmd.Flags().StringVarP(&config.ServerName, "servername", "s", "local", "Define server to get Kontor items")
updateTitleCmd.Flags().StringVarP(&config.ServerName, "servername", "s", "local", "Define server to get Kontor items") updateTitleCmd.Flags().StringVarP(&config.ServerName, "servername", "s", "local", "Define server to get Kontor items")
addLinksCmd.Flags().StringVarP(&config.ServerName, "servername", "s", "local", "Define server to get Kontor items")
addLinksCmd.Flags().Var(&config.Mediatype, "mediatype", "MediaType: allowed values are: media, videos, lofi")
exportCmd.PersistentFlags().StringVarP(&config.FileName, "file", "f", "/home/tpeetz/.sync/media/data-gin.json", "Filename to store data")
importCmd.PersistentFlags().StringVarP(&config.FileName, "file", "f", "/home/tpeetz/.sync/media/data-gin.json", "Filename to import data from")
viper.BindPFlag("file", exportCmd.PersistentFlags().Lookup("file"))
exportCmd.PersistentFlags().StringVarP(&config.Config.ApiVersion, "api", "a", "api/v1", "API Version")
viper.BindPFlag("api", exportCmd.PersistentFlags().Lookup("api"))
viper.BindPFlag("server", exportCmd.PersistentFlags().Lookup("server")) viper.BindPFlag("server", exportCmd.PersistentFlags().Lookup("server"))
cobra.OnInitialize(config.InitCliConfig) cobra.OnInitialize(config.InitCliConfig)
} }
+30
View File
@@ -0,0 +1,30 @@
package cmd
import (
"fmt"
"log/slog"
"github.com/spf13/cobra"
)
var (
version = "unset"
commit = "unset"
date = "unset"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Show Kontor Version",
Long: "Show Kontor Version",
Run: func(cmd *cobra.Command, args []string) {
slog.Info("version kontor")
fmt.Println("Version: ", version)
fmt.Println("Version: ", commit)
fmt.Println("Version: ", date)
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
+84 -15
View File
@@ -1,31 +1,94 @@
package config package config
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
var ( var (
CfgFile string ApiSecret []byte
Verbose int CfgFile string
Overwrite bool Verbose int
ServerName string Overwrite bool
Config CliConfig ServerName string
DryRun bool Mediatype MediaType
Config CliConfig
ServerConfig ServerConfiguration
DryRun bool
FileName string
) )
const (
mediaTypeMedia MediaType = "media"
mediaTypeVideo MediaType = "video"
mediaTypeLofi MediaType = "lofi"
)
type MediaType string
func (e *MediaType) String() string {
return string(*e)
}
func (e *MediaType) Set(v string) error {
switch v {
case "media", "video", "lofi":
*e = MediaType(v)
return nil
default:
return errors.New(`must be one of "media", "video", "lofi"`)
}
}
func (e *MediaType) Type() string {
return "MediaType"
}
func myEnumCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{
"media\thelp text for media",
"video\thelp text for video",
"lofi\thelp text for lofi",
}, cobra.ShellCompDirectiveDefault
}
type Server struct { type Server struct {
Url string `mapstructure:"url"` Url string `mapstructure:"url"`
Username string `mapstructure:"username"` Username string `mapstructure:"username"`
Password string `mapstructure:"password"` Password string `mapstructure:"password"`
} }
type Database struct {
Type string `mapstructure:"type" validate:"required"`
Path string `mapstructure:"path" validate:"required"`
Host string `mapstructure:"host" validate:"required"`
Name string `mapstructure:"name" validate:"required"`
Port int `mapstructure:"port" validate:"required"`
Password string `mapstructure:"password" validate:"required"`
User string `mapstructure:"user" validate:"required"`
}
type CliConfig struct { type CliConfig struct {
ApiVersion string ApiVersion string
Server map[string]Server `mapstructure:"server"` Server map[string]Server `mapstructure:"server"`
DB Database `mapstructure:"db"`
}
type ServerConfiguration struct {
ApiSecret []byte `mapstructure:"api_secret" validate:"required"`
Server struct {
Port int `mapstructure:"port" validate:"required"`
Host string `mapstructure:"host"`
} `mapstructure:"server"`
DB Database `mapstructure:"db"`
Gin struct {
Mode string `mapstructure:"mode" validate:"required"`
} `mapstructure:"gin"`
} }
func InitCliConfig() { func InitCliConfig() {
@@ -38,6 +101,7 @@ func InitCliConfig() {
viper.AddConfigPath(".") // look for config in working directory viper.AddConfigPath(".") // look for config in working directory
viper.AddConfigPath("/home/tpeetz/.config") viper.AddConfigPath("/home/tpeetz/.config")
} }
Mediatype = mediaTypeMedia
// Read the configuration file // Read the configuration file
if err := viper.ReadInConfig(); err != nil { if err := viper.ReadInConfig(); err != nil {
@@ -51,7 +115,7 @@ func InitCliConfig() {
slog.Info("error reading config file", "error", err.Error()) slog.Info("error reading config file", "error", err.Error())
} }
} else { } else {
slog.Info("initConfig", "Using config file: ", viper.ConfigFileUsed()) slog.Info("InitCliConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&Config); err != nil { if err := viper.Unmarshal(&Config); err != nil {
slog.Info("parsing of config file failed", "error", err.Error()) slog.Info("parsing of config file failed", "error", err.Error())
} }
@@ -59,13 +123,6 @@ func InitCliConfig() {
} }
func InitConfig() error { func InitConfig() error {
viper.SetDefault("db.host", "localhost")
viper.SetDefault("db.port", 5432)
viper.SetDefault("db.name", "kontor")
viper.SetDefault("db.user", "kontor")
viper.SetDefault("db.password", "kontor")
viper.SetDefault("port", 8550)
viper.SetDefault("gin.mode", "release")
viper.SetConfigName("kontor-gin") viper.SetConfigName("kontor-gin")
viper.SetConfigType("yaml") viper.SetConfigType("yaml")
@@ -75,6 +132,15 @@ func InitConfig() error {
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv() viper.AutomaticEnv()
viper.SetDefault("db.type", "postgres")
viper.SetDefault("db.host", "localhost")
viper.SetDefault("db.port", 5432)
viper.SetDefault("db.name", "kontor")
viper.SetDefault("db.user", "kontor")
viper.SetDefault("db.password", "kontor")
viper.SetDefault("db.path", "data/kontor.db")
viper.SetDefault("server.port", 8550)
viper.SetDefault("gin.mode", "release")
// Read the config file // Read the config file
if err := viper.ReadInConfig(); err != nil { if err := viper.ReadInConfig(); err != nil {
// Handle the case where config file is not found // Handle the case where config file is not found
@@ -88,7 +154,10 @@ func InitConfig() error {
return fmt.Errorf("error reading config file: %w", err) return fmt.Errorf("error reading config file: %w", err)
} }
} else { } else {
slog.Info("initConfig", "Using config file: ", viper.ConfigFileUsed()) slog.Info("InitConfig", "Using config file: ", viper.ConfigFileUsed())
if err := viper.Unmarshal(&ServerConfig); err != nil {
slog.Info("parsing of config file failed", "error", err.Error())
}
} }
return nil return nil
+29 -4
View File
@@ -1,17 +1,42 @@
package config package config
import ( import (
"fmt"
"log/slog"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
) )
func NewDB(dsn string) (*gorm.DB, error) { func NewDB(db Database) (*gorm.DB, error) {
db_type := db.Type
slog.Info("using database", "type", db_type)
switch db_type {
case "postgres":
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
db.Host,
db.User,
db.Password,
db.Name,
db.Port,
)
return gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
case "sqlite":
return gorm.Open(sqlite.Open(db.Path), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
default:
return nil, fmt.Errorf("unknown db.type=%s", db_type)
}
// Configure GORM with custom settings // Configure GORM with custom settings
// The logger helps with debugging SQL queries during development // The logger helps with debugging SQL queries during development
return gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
// if err != nil { // if err != nil {
// log.Fatal("Failed to connect to database:", err) // log.Fatal("Failed to connect to database:", err)
// } // }
+37 -3
View File
@@ -1,7 +1,41 @@
package globals package globals
var Secret = []byte("secret") import (
"fmt"
const UserKey = "user" "github.com/gin-gonic/gin"
)
const Version = "0.4.0" var (
Secret = []byte("secret")
Version = "unset"
Commit = "unset"
Date = "unset"
)
const (
UserKey = "user"
MediaFileLink = "/media/files"
MediaLofiLink = "/media/lofis"
MediaMusicLink = "/media/musics"
MediaVideoLink = "/media/videos"
MediaArticleLink = "/media/articles"
MediaActorLink = "/media/actors"
)
func GetDefaultValues(user interface{}, message string) gin.H {
values := gin.H{
"title": "Kontor",
"version": fmt.Sprintf("%s %s", Version, Commit),
"message": message,
"user": user,
"media_file_link": MediaFileLink,
"media_lofi_link": MediaLofiLink,
"media_music_link": MediaMusicLink,
"media_video_link": MediaVideoLink,
"media_article_link": MediaArticleLink,
"media_actor_link": MediaActorLink,
}
return values
}
+12 -32
View File
@@ -45,21 +45,13 @@ func (handler *AuthHandler) LoginPage(c *gin.Context) {
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
logger := slog.Get(c) logger := slog.Get(c)
logger.Info("LoginPage", globals.UserKey, user) logger.Info("LoginPage", globals.UserKey, user)
data := globals.GetDefaultValues(user, "Please logout first")
if user != nil { if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{ c.HTML(http.StatusBadRequest, "login", data)
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Please logout first",
"user": user,
})
return return
} }
c.HTML(http.StatusOK, "login", gin.H{ data["message"] = ""
"title": "Kontor Gin", c.HTML(http.StatusOK, "login", data)
"version": "0.4.0",
"message": "",
"user": user,
})
} }
func (handler *AuthHandler) LoginPost(c *gin.Context) { func (handler *AuthHandler) LoginPost(c *gin.Context) {
@@ -67,12 +59,9 @@ func (handler *AuthHandler) LoginPost(c *gin.Context) {
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
logger := slog.Get(c) logger := slog.Get(c)
logger.Info("LoginPost", "user", user) logger.Info("LoginPost", "user", user)
data := globals.GetDefaultValues(user, "Please logout first")
if user != nil { if user != nil {
c.HTML(http.StatusBadRequest, "login", gin.H{ c.HTML(http.StatusBadRequest, "login", data)
"title": "Kontor Gin",
"version": "0.4.0",
"message": "Please logout first",
})
return return
} }
@@ -80,29 +69,20 @@ func (handler *AuthHandler) LoginPost(c *gin.Context) {
password := c.PostForm("password") password := c.PostForm("password")
if helpers.EmptyUserPass(username, password) { if helpers.EmptyUserPass(username, password) {
c.HTML(http.StatusBadRequest, "login", gin.H{ data["message"] = "Parameters can't be empty"
"title": "Kontor Gin", c.HTML(http.StatusBadRequest, "login", data)
"version": "0.4.0",
"message": "Parameters can't be empty",
})
} }
proile_id, err := handler.Service.LoginCheck(username, password) proile_id, err := handler.Service.LoginCheck(username, password)
if err != nil { if err != nil {
c.HTML(http.StatusUnauthorized, "login", gin.H{ data["message"] = "Incorrect username or password"
"title": "Kontor Gin", c.HTML(http.StatusUnauthorized, "login", data)
"version": "0.4.0",
"message": "Incorrect username or password",
})
} }
session.Set(globals.UserKey, proile_id) session.Set(globals.UserKey, proile_id)
if err := session.Save(); err != nil { if err := session.Save(); err != nil {
c.HTML(http.StatusInternalServerError, "login", gin.H{ data["message"] = "Failed to save session"
"title": "Kontor Gin", c.HTML(http.StatusInternalServerError, "login", data)
"version": "0.4.0",
"message": "Failed to save session",
})
return return
} }
logger.Info("LoginPost: redirect to index") logger.Info("LoginPost: redirect to index")
+4 -7
View File
@@ -68,11 +68,8 @@ func (handler *ComicHandler) ListPage(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
c.HTML(http.StatusOK, "comics", gin.H{ data := globals.GetDefaultValues(user, "Comics...")
"title": "Kontor Comics", data["title"] = "Kontor Comics"
"version": "0.4.0", data["comics"] = comics
"message": "Comics...", c.HTML(http.StatusOK, "comics", data)
"comics": comics,
"user": user,
})
} }
+2 -7
View File
@@ -24,11 +24,6 @@ func Index(c *gin.Context) {
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
logger := slog.Get(c) logger := slog.Get(c)
logger.Info("IndexGetHandler", globals.UserKey, user) logger.Info("IndexGetHandler", globals.UserKey, user)
c.HTML(http.StatusOK, "home", gin.H{ data := globals.GetDefaultValues(user, "This is an index page...")
"title": "Kontor Gin", c.HTML(http.StatusOK, "home", data)
"version": "0.4.0",
"message": "This is an index page...",
"user": user,
})
} }
+4
View File
@@ -5,18 +5,22 @@ import (
) )
type MediaHandler struct { type MediaHandler struct {
MediaArticleHandler *MediaArticleHandler
MediaActorHandler *MediaActorHandler MediaActorHandler *MediaActorHandler
MediaFileHandler *MediaFileHandler MediaFileHandler *MediaFileHandler
MediaLoFiHandler *MediaLoFiHandler MediaLoFiHandler *MediaLoFiHandler
MediaMusicHandler *MediaMusicHandler
MediaVideoHandler *MediaVideoHandler MediaVideoHandler *MediaVideoHandler
MediaActorFileHandler *MediaActorFileHandler MediaActorFileHandler *MediaActorFileHandler
} }
func NewMediaHandler(db *gorm.DB) *MediaHandler { func NewMediaHandler(db *gorm.DB) *MediaHandler {
mediaHandler := &MediaHandler{ mediaHandler := &MediaHandler{
MediaArticleHandler: NewMediaArticleHandler(db),
MediaActorHandler: NewMediaActorHandler(db), MediaActorHandler: NewMediaActorHandler(db),
MediaFileHandler: NewMediaFileHandler(db), MediaFileHandler: NewMediaFileHandler(db),
MediaLoFiHandler: NewMediaLoFiHandler(db), MediaLoFiHandler: NewMediaLoFiHandler(db),
MediaMusicHandler: NewMediaMusicHandler(db),
MediaVideoHandler: NewMediaVideoHandler(db), MediaVideoHandler: NewMediaVideoHandler(db),
MediaActorFileHandler: NewMediaActorFileHandler(db), MediaActorFileHandler: NewMediaActorFileHandler(db),
} }
+60 -7
View File
@@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -76,11 +77,63 @@ func (handler *MediaActorHandler) ListPage(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
c.HTML(http.StatusOK, "mediaactors", gin.H{ data := globals.GetDefaultValues(user, "MediaActors...")
"title": "Kontor MediaActors", data["actors"] = actors
"version": "0.4.0", c.HTML(http.StatusOK, "media_actors", data)
"message": "MediaActors...", }
"actors": actors,
"user": user, func (handler *MediaActorHandler) EditPage(c *gin.Context) {
}) session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
//logger := slog.Get(c)
actor, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
c.HTML(http.StatusOK, "actor_detail", data)
}
func (handler *MediaActorHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
actor, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaActorForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaActorHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaActors...")
data["actor"] = actor
data["Form"] = form
data["Errors"] = err.Error()
c.HTML(http.StatusBadRequest, "actor_detail", data)
return
}
logger.Info("MediaActorHandler#UpdatePage", "actor", actor)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaActorLink)
}
func (handler *MediaActorHandler) DeletePage(c *gin.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
//actor, err := handler.Service.Get(c.Request.Context(), id)
// if err != nil {
// logger.Info("MediaActorHandler#DeletePage", "error", err.Error())
// c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
// return
// }
logger.Info("MediaActorHandler#DeletePage", "actor", id)
c.Redirect(http.StatusFound, globals.MediaActorLink)
} }
@@ -0,0 +1,134 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type MediaArticleHandler struct {
Service *service.MediaArticleService
}
func NewMediaArticleHandler(db *gorm.DB) *MediaArticleHandler {
mediaFileHandler := &MediaArticleHandler{
Service: service.NewMediaArticleService(repository.NewMediaArticleRepository(db)),
}
return mediaFileHandler
}
func (handler *MediaArticleHandler) List(c *gin.Context) {
logger := slog.Get(c)
logger.Info("MediaArticleHandler#List")
articles, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaArticlesToDtos(articles)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaArticleHandler) Add(c *gin.Context) {
var input models.MediaFileAdd
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
lofi, err := handler.Service.Add(c.Request.Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "lofi not added"})
return
}
c.JSON(http.StatusOK, lofi)
}
func (handler *MediaArticleHandler) Delete(c *gin.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "lofi not found"})
return
}
c.JSON(http.StatusOK, gin.H{"ok": "true"})
}
func (handler *MediaArticleHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
files, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "MediaArticles...")
data["title"] = "Kontor MediaArticles"
data["media_links"] = files
data["MediaLinksUrl"] = globals.MediaArticleLink
c.HTML(http.StatusOK, "media_links", data)
}
func (handler *MediaArticleHandler) EditPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_file, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["lofi"] = media_file
c.HTML(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaArticleHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_article, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaArticleForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaArticleHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaArticle Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.HTML(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaArticleHandler#UpdatePage", "media_article", media_article)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
func (handler *MediaArticleHandler) DeletePage(c *gin.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
logger.Info("MediaArticleHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaArticleHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaArticleLink)
}
+62 -7
View File
@@ -69,11 +69,66 @@ func (handler *MediaFileHandler) ListPage(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
c.HTML(http.StatusOK, "mediafiles", gin.H{ data := globals.GetDefaultValues(user, "MediaFiles...")
"title": "Kontor MediaFiles", data["title"] = "Kontor MediaFiles"
"version": "0.4.0", data["media_links"] = files
"message": "MediaFiles...", data["MediaLinksUrl"] = globals.MediaVideoLink
"mediafiles": files, c.HTML(http.StatusOK, "media_links", data)
"user": user, }
})
func (handler *MediaFileHandler) EditPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_file, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaLoFiHandler#EditPage", "media_file", media_file)
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["lofi"] = media_file
c.HTML(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaFileHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
media_file, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaFileForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaFileHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaFile Details...")
data["Form"] = form
data["Errors"] = err.Error()
c.HTML(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaFileHandler#UpdatePage", "media_file", media_file)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaFileDTO())
c.Redirect(http.StatusFound, globals.MediaFileLink)
}
func (handler *MediaFileHandler) DeletePage(c *gin.Context) {
//session := sessions.Default(c)
//user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
logger.Info("MediaFileHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaFileHandler#DeletePage", "lofi", id)
c.Redirect(http.StatusFound, globals.MediaFileLink)
} }
+59 -29
View File
@@ -6,10 +6,12 @@ import (
"kontor-api-gin/internal/repository" "kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service" "kontor-api-gin/internal/service"
"net/http" "net/http"
"time"
"github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog" "github.com/gin-contrib/slog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -89,6 +91,27 @@ func (handler *MediaLoFiHandler) ListPage(c *gin.Context) {
session := sessions.Default(c) session := sessions.Default(c)
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
logger := slog.Get(c) logger := slog.Get(c)
var (
review bool
download bool
)
paramReview, existsReview := c.GetQuery("review")
if existsReview {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, existsDownload := c.GetQuery("should_download")
if existsDownload {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
lofis, err := handler.Service.List(c.Request.Context()) lofis, err := handler.Service.List(c.Request.Context())
if err != nil { if err != nil {
logger.Info("MediaLoFiHandler#ListPage", "error", err.Error()) logger.Info("MediaLoFiHandler#ListPage", "error", err.Error())
@@ -96,13 +119,12 @@ func (handler *MediaLoFiHandler) ListPage(c *gin.Context) {
return return
} }
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis)) logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
c.HTML(http.StatusOK, "lofi", gin.H{ data := globals.GetDefaultValues(user, "MediaFiles...")
"title": "Kontor MediaFiles", data["media_links"] = lofis
"version": "0.4.0", data["isReview"] = review
"message": "MediaFiles...", data["isDownload"] = download
"lofis": lofis, data["MediaLinksUrl"] = globals.MediaLofiLink
"user": user, c.HTML(http.StatusOK, "media_links", data)
})
} }
func (handler *MediaLoFiHandler) EditPage(c *gin.Context) { func (handler *MediaLoFiHandler) EditPage(c *gin.Context) {
@@ -110,20 +132,32 @@ func (handler *MediaLoFiHandler) EditPage(c *gin.Context) {
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
id := c.Param("id") id := c.Param("id")
logger := slog.Get(c) logger := slog.Get(c)
lofi, err := handler.Service.Get(c.Request.Context(), id) var lofi *models.MediaLoFi
if err != nil { var err error
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error()) if id == "" {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // id is empty, adding is assumed
return lofi = &models.MediaLoFi{
ID: uuid.NewString(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Version: 0,
Review: true,
ShouldDownload: true,
}
} else {
// id is set, fetch MediaLofi by ID
lofi, err = handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaLoFiHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
} }
logger.Info("MediaLoFiHandler#EditPage", "lofi", lofi) logger.Info("MediaLoFiHandler#EditPage", "lofi", lofi)
c.HTML(http.StatusOK, "lofi_detail", gin.H{ data := globals.GetDefaultValues(user, "MediaLofis...")
"title": "Kontor MediaFLofi", data["media"] = lofi
"version": "0.4.0", data["MediaLinksUrl"] = globals.MediaLofiLink
"message": "MediaFiles...", c.HTML(http.StatusOK, "media_detail", data)
"lofi": lofi,
"user": user,
})
} }
func (handler *MediaLoFiHandler) ChangeReviewPage(c *gin.Context) { func (handler *MediaLoFiHandler) ChangeReviewPage(c *gin.Context) {
@@ -132,7 +166,7 @@ func (handler *MediaLoFiHandler) ChangeReviewPage(c *gin.Context) {
lofi, err := handler.Service.Get(c.Request.Context(), id) lofi, err := handler.Service.Get(c.Request.Context(), id)
if err != nil { if err != nil {
logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error()) logger.Info("MediaLoFiHandler#ChangeReviewPage", "error", err.Error())
c.Redirect(http.StatusNotFound, "/web/media-lofis") c.Redirect(http.StatusNotFound, globals.MediaLofiLink)
return return
} }
lofi.Review = !lofi.Review lofi.Review = !lofi.Review
@@ -147,14 +181,10 @@ func (handler *MediaLoFiHandler) ChangeReviewPage(c *gin.Context) {
return return
} }
logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis)) logger.Info("MediaLoFiHandler#ListPage", "lofis count", len(lofis))
c.HTML(http.StatusOK, "lofi", gin.H{ data := globals.GetDefaultValues(user, "MediaLofis...")
"title": "Kontor MediaFiles", data["lofis"] = lofis
"version": "0.4.0", //c.HTML(http.StatusOK, "lofi", data)
"message": "MediaFiles...", c.Redirect(http.StatusCreated, globals.MediaLofiLink)
"lofis": lofis,
"user": user,
})
c.Redirect(http.StatusCreated, "/web/media-lofis")
} }
func (handler *MediaLoFiHandler) UpdatePage(c *gin.Context) { func (handler *MediaLoFiHandler) UpdatePage(c *gin.Context) {
@@ -180,7 +210,7 @@ func (handler *MediaLoFiHandler) UpdatePage(c *gin.Context) {
} }
logger.Info("MediaLoFiHandler#UpdatePage", "lofi", lofi) logger.Info("MediaLoFiHandler#UpdatePage", "lofi", lofi)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO()) //handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, "web/media-lofis") c.Redirect(http.StatusFound, globals.MediaLofiLink)
} }
func (handler *MediaLoFiHandler) DeletePage(c *gin.Context) { func (handler *MediaLoFiHandler) DeletePage(c *gin.Context) {
+183
View File
@@ -0,0 +1,183 @@
package handlers
import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type MediaMusicHandler struct {
Service *service.MediaMusicService
}
func NewMediaMusicHandler(db *gorm.DB) *MediaMusicHandler {
mediaMusicHandler := &MediaMusicHandler{
Service: service.NewMediaMusicService(repository.NewMediaMusicRepository(db)),
}
return mediaMusicHandler
}
func (handler *MediaMusicHandler) List(c *gin.Context) {
musics, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
dtos := models.ConvertMediaMusicsToDtos(musics)
c.JSON(http.StatusOK, dtos)
}
func (handler *MediaMusicHandler) Get(c *gin.Context) {
id := c.Param("id")
music, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Add(c *gin.Context) {
var input models.MediaLofiAdd
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
music, err := handler.Service.Add(c.Request.Context(), input.Url)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "MediaMusic not added"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Update(c *gin.Context) {
var input models.MediaMusicDTO
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
music, err := handler.Service.Update(c.Request.Context(), input)
if err != nil {
logger := slog.Get(c)
logger.Info("MediaMusicHandler#Update", "error", err.Error())
c.JSON(http.StatusNotFound, gin.H{"error": "MediaMusic not updated"})
return
}
c.JSON(http.StatusOK, music)
}
func (handler *MediaMusicHandler) Delete(c *gin.Context) {
id := c.Param("id")
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "MediaMusic not found"})
return
}
c.JSON(http.StatusOK, gin.H{"ok": "true"})
}
func (handler *MediaMusicHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
logger := slog.Get(c)
var (
review bool
download bool
)
paramReview, existsReview := c.GetQuery("review")
if existsReview {
if paramReview == "on" {
review = true
} else {
review = false
}
}
paramDownload, existsDownload := c.GetQuery("should_download")
if existsDownload {
if paramDownload == "on" {
download = true
} else {
download = false
}
}
musics, err := handler.Service.List(c.Request.Context())
if err != nil {
logger.Info("MediaMusicHandler#ListPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#ListPage", "MediaMusic count", len(musics))
data := globals.GetDefaultValues(user, "MediaMusic...")
data["media_links"] = musics
data["MediaLinksUrl"] = globals.MediaMusicLink
data["isReview"] = review
data["isDownload"] = download
c.HTML(http.StatusOK, "media_links", data)
}
func (handler *MediaMusicHandler) EditPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
music, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#EditPage", "music", music)
data := globals.GetDefaultValues(user, "MediaMusic...")
data["lofi"] = music
c.HTML(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaMusicHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
music, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaMusicForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaMusicHandler#UpdatePage", "error", err.Error())
data := globals.GetDefaultValues(user, "MediaMusic...")
data["Form"] = form
data["Errors"] = err.Error()
c.HTML(http.StatusBadRequest, "lofi_detail", data)
return
}
logger.Info("MediaMusicHandler#UpdatePage", "music", music)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
func (handler *MediaMusicHandler) DeletePage(c *gin.Context) {
// session := sessions.Default(c)
// user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
logger.Info("MediaMusicHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaMusicHandler#DeletePage", "music", id)
c.Redirect(http.StatusFound, globals.MediaMusicLink)
}
+69 -6
View File
@@ -37,16 +37,79 @@ func (handler *MediaVideoHandler) List(c *gin.Context) {
func (handler *MediaVideoHandler) ListPage(c *gin.Context) { func (handler *MediaVideoHandler) ListPage(c *gin.Context) {
session := sessions.Default(c) session := sessions.Default(c)
user := session.Get(globals.UserKey) user := session.Get(globals.UserKey)
logger := slog.Get(c)
videos, err := handler.Service.List(c.Request.Context()) videos, err := handler.Service.List(c.Request.Context())
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
c.HTML(http.StatusOK, "mediavideos", gin.H{ logger.Info("MediaVideoHandler#ListPage", "videos count", len(videos))
"title": "Kontor MediaFiles", data := globals.GetDefaultValues(user, "MediaVideos...")
"version": "0.4.0", data["title"] = "Kontor MediaVideos"
"message": "MediaFiles...", data["media_links"] = videos
"mediavideos": videos, data["MediaLinksUrl"] = globals.MediaVideoLink
"user": user, c.HTML(http.StatusOK, "media_links", data)
}
func (handler *MediaVideoHandler) EditPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
video, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#EditPage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#EditPage", "lofi", video)
data := globals.GetDefaultValues(user, "MediaLofis...")
data["lofi"] = video
c.HTML(http.StatusOK, "lofi_detail", data)
}
func (handler *MediaVideoHandler) UpdatePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
video, err := handler.Service.Get(c.Request.Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
var form models.MediaVideoForm
if err := c.ShouldBind(&form); err != nil {
logger.Info("MediaVideoHandler#UpdatePage", "error", err.Error())
c.HTML(http.StatusBadRequest, "lofi_detail", gin.H{
"Form": form,
"Errors": err.Error(),
"user": user,
})
return
}
logger.Info("MediaVideoHandler#UpdatePage", "lofi", video)
//handler.Service.Update(c.Request.Context(), form.ConvertFormToMediaLofiDTO())
c.Redirect(http.StatusFound, globals.MediaVideoLink)
}
func (handler *MediaVideoHandler) DeletePage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
id := c.Param("id")
logger := slog.Get(c)
err := handler.Service.Delete(c.Request.Context(), id)
if err != nil {
logger.Info("MediaVideoHandler#DeletePage", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
logger.Info("MediaVideoHandler#DeletePage", "video", id)
c.HTML(http.StatusOK, "lofi_delete", gin.H{
"title": "Kontor MediaFiles",
"version": "0.4.0",
"message": "MediaFiles...",
"user": user,
}) })
} }
+16
View File
@@ -1,11 +1,13 @@
package handlers package handlers
import ( import (
"kontor-api-gin/internal/globals"
"kontor-api-gin/internal/models" "kontor-api-gin/internal/models"
"kontor-api-gin/internal/repository" "kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service" "kontor-api-gin/internal/service"
"net/http" "net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -28,3 +30,17 @@ func (handler *PublisherHandler) List(c *gin.Context) {
dtos := models.ConvertPublishersToDtos(comics) dtos := models.ConvertPublishersToDtos(comics)
c.JSON(http.StatusOK, dtos) c.JSON(http.StatusOK, dtos)
} }
func (handler *PublisherHandler) ListPage(c *gin.Context) {
session := sessions.Default(c)
user := session.Get(globals.UserKey)
publishers, err := handler.Service.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
data := globals.GetDefaultValues(user, "Publishers...")
data["title"] = "Kontor Comics"
data["publishers"] = publishers
c.HTML(http.StatusOK, "publishers", data)
}
-21
View File
@@ -1,21 +0,0 @@
package handlers
import (
"kontor-api-gin/internal/repository"
"kontor-api-gin/internal/service"
"gorm.io/gorm"
)
type WebAppHandler struct {
AuthHandler *AuthHandler
ComicHandler *ComicHandler
}
func NewWebAppHandler(db *gorm.DB, secret []byte) *WebAppHandler {
webapp := &WebAppHandler{
AuthHandler: &AuthHandler{Service: service.NewAuthService(repository.NewProfileRepository(db), secret)},
ComicHandler: &ComicHandler{Service: service.NewComicService(repository.NewComicRepository(db))},
}
return webapp
}
+1 -1
View File
@@ -16,7 +16,7 @@ func RequestID(skipPaths []string) gin.HandlerFunc {
id = uuid.NewString() id = uuid.NewString()
} }
if len(skipPaths) > 0 && !slices.Contains(skipPaths, c.Request.URL.Path) { if len(skipPaths) > 0 && !slices.Contains(skipPaths, c.Request.URL.Path) {
logger.Info("RequestID", "id", id) logger.Info("RequestID", "id", id, "path", c.Request.URL.Path)
} }
c.Set("request_id", id) c.Set("request_id", id)
c.Writer.Header().Set("X-Request-ID", id) c.Writer.Header().Set("X-Request-ID", id)
+34 -21
View File
@@ -6,13 +6,13 @@ import (
) )
type Article struct { type Article struct {
ID string `gorm:"type:string;primary_key;" json:"id"` ID string `gorm:"type:string;primary_key;" json:"id"`
CreatedAt time.Time `gorm:"column:created_date" json:"created_date"` CreatedAt time.Time `gorm:"column:created_date" json:"created_date"`
UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"` UpdatedAt time.Time `gorm:"column:last_modified_date" json:"last_modified_date"`
DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"` DeletedAt *time.Time `gorm:"column:deleted_date" json:"deleted_date"`
Version int `gorm:"default:0" json:"version"` Version int `gorm:"default:0" json:"version"`
Title string `gorm:"uniqueIndex" json:"title"` Title string `gorm:"uniqueIndex" json:"title"`
ArticleAuthors []ArticleAuthor `gorm:"foreignKey:ArticleID" json:"article_authors"` ArticleAuthors []ArticleAuthor `gorm:"foreignKey:ArticleID" json:"article_authors"`
} }
func (article *Article) TableName() string { func (article *Article) TableName() string {
@@ -20,34 +20,47 @@ func (article *Article) TableName() string {
} }
type ArticleDTO struct { type ArticleDTO struct {
ID string `json:"id" binding:"required"` ID string `json:"id" binding:"required"`
CreatedAt helpers.KontorTime `json:"created_date"` CreatedAt helpers.KontorTime `json:"created_date"`
UpdatedAt helpers.KontorTime `json:"last_modified_date"` UpdatedAt helpers.KontorTime `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date,omitempty"` DeletedAt *time.Time `json:"deleted_date,omitempty"`
Version int `json:"version"` Version int `json:"version"`
Title string `json:"title"` Title string `json:"title"`
}
func (dto ArticleDTO) ConvertDTOToModel() Article {
model := Article{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Title: dto.Title,
}
return model
} }
func ConvertArticlesToDtos(articles []Article) []ArticleDTO { func ConvertArticlesToDtos(articles []Article) []ArticleDTO {
dtos := make([]ArticleDTO, len(articles)) dtos := make([]ArticleDTO, len(articles))
for i, article := range articles { for i, article := range articles {
dtos[i] = ArticleDTO{ dtos[i] = ArticleDTO{
ID: article.ID, ID: article.ID,
CreatedAt: helpers.KontorTime{Time: article.CreatedAt}, CreatedAt: helpers.KontorTime{Time: article.CreatedAt},
UpdatedAt: helpers.KontorTime{Time: article.UpdatedAt}, UpdatedAt: helpers.KontorTime{Time: article.UpdatedAt},
DeletedAt: article.DeletedAt, DeletedAt: article.DeletedAt,
Version: article.Version, Version: article.Version,
Title: article.Title, Title: article.Title,
} }
} }
return dtos return dtos
} }
type ArticleDTOList []ArticleDTO
type CreateArticleDTO struct { type CreateArticleDTO struct {
Title string `json:"title" binding:"required"` Title string `json:"title" binding:"required"`
} }
type UpdateArticleDTO struct { type UpdateArticleDTO struct {
Title *string `json:"title,omitempty" binding:"omitempty"` Title *string `json:"title,omitempty" binding:"omitempty"`
} }
@@ -31,6 +31,19 @@ type ArticleAuthorDTO struct {
AuthorID *string `json:"author_id"` AuthorID *string `json:"author_id"`
} }
func (dto ArticleAuthorDTO) ConvertDTOToModel() ArticleAuthor {
model := ArticleAuthor{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
ArticleID: dto.ArticleID,
AuthorID: dto.AuthorID,
}
return model
}
func ConvertArticleAuthorsToDtos(article_authors []ArticleAuthor) []ArticleAuthorDTO { func ConvertArticleAuthorsToDtos(article_authors []ArticleAuthor) []ArticleAuthorDTO {
dtos := make([]ArticleAuthorDTO, len(article_authors)) dtos := make([]ArticleAuthorDTO, len(article_authors))
for i, article_author := range article_authors { for i, article_author := range article_authors {
@@ -46,3 +59,5 @@ func ConvertArticleAuthorsToDtos(article_authors []ArticleAuthor) []ArticleAutho
} }
return dtos return dtos
} }
type ArticleAuthorDTOList []ArticleAuthorDTO
+15
View File
@@ -29,6 +29,19 @@ type ArtistDTO struct {
WebLink string `json:"weblink"` WebLink string `json:"weblink"`
} }
func (dto ArtistDTO) ConvertDTOToModel() Artist {
model := Artist{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Name: dto.Name,
WebLink: dto.WebLink,
}
return model
}
func ConvertArtistsToDtos(artists []Artist) []ArtistDTO { func ConvertArtistsToDtos(artists []Artist) []ArtistDTO {
dtos := make([]ArtistDTO, len(artists)) dtos := make([]ArtistDTO, len(artists))
for i, artist := range artists { for i, artist := range artists {
@@ -49,3 +62,5 @@ type CreateArtistDTO struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
WebLink string `json:"weblink" binding:"required"` WebLink string `json:"weblink" binding:"required"`
} }
type ArtistDTOList []ArtistDTO
+15
View File
@@ -31,6 +31,19 @@ type AssignmentDTO struct {
PermissionID *string `json:"permission_id"` PermissionID *string `json:"permission_id"`
} }
func (dto *AssignmentDTO) ConvertDTOToModel() Assignment {
model := Assignment{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
ProfileID: dto.ProfileID,
PermissionID: dto.PermissionID,
}
return model
}
func ConvertAssignmentsToDtos(assignments []Assignment) []AssignmentDTO { func ConvertAssignmentsToDtos(assignments []Assignment) []AssignmentDTO {
dtos := make([]AssignmentDTO, len(assignments)) dtos := make([]AssignmentDTO, len(assignments))
for i, assignment := range assignments { for i, assignment := range assignments {
@@ -46,3 +59,5 @@ func ConvertAssignmentsToDtos(assignments []Assignment) []AssignmentDTO {
} }
return dtos return dtos
} }
type AssignmentDTOList []AssignmentDTO
+15
View File
@@ -31,6 +31,19 @@ type AuthorDTO struct {
LastName string `json:"last_name"` LastName string `json:"last_name"`
} }
func (dto AuthorDTO) ConvertDTOToModel() Author {
model := Author{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
FirstName: dto.FirstName,
LastName: dto.LastName,
}
return model
}
func ConvertAuthorsToDtos(authors []Author) []AuthorDTO { func ConvertAuthorsToDtos(authors []Author) []AuthorDTO {
dtos := make([]AuthorDTO, len(authors)) dtos := make([]AuthorDTO, len(authors))
for i, author := range authors { for i, author := range authors {
@@ -46,3 +59,5 @@ func ConvertAuthorsToDtos(authors []Author) []AuthorDTO {
} }
return dtos return dtos
} }
type AuthorDTOList []AuthorDTO
+14
View File
@@ -32,6 +32,18 @@ type BookDTO struct {
Title string `json:"title"` Title string `json:"title"`
} }
func (dto BookDTO) ConvertDTOToModel() Book {
model := Book{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
Title: dto.Title,
}
return model
}
func ConvertBooksToDtos(books []Book) []BookDTO { func ConvertBooksToDtos(books []Book) []BookDTO {
dtos := make([]BookDTO, len(books)) dtos := make([]BookDTO, len(books))
for i, book := range books { for i, book := range books {
@@ -46,3 +58,5 @@ func ConvertBooksToDtos(books []Book) []BookDTO {
} }
return dtos return dtos
} }
type BookDTOList []BookDTO
+15
View File
@@ -31,6 +31,19 @@ type BookAuthorDTO struct {
AuthorID *string `json:"author_id"` AuthorID *string `json:"author_id"`
} }
func (dto BookAuthorDTO) ConvertDTOToModel() BookAuthor {
model := BookAuthor{
ID: dto.ID,
CreatedAt: dto.CreatedAt.Time,
UpdatedAt: dto.UpdatedAt.Time,
DeletedAt: dto.DeletedAt,
Version: dto.Version,
BookID: dto.BookID,
AuthorID: dto.AuthorID,
}
return model
}
func ConvertBookAuthorsToDtos(book_authors []BookAuthor) []BookAuthorDTO { func ConvertBookAuthorsToDtos(book_authors []BookAuthor) []BookAuthorDTO {
dtos := make([]BookAuthorDTO, len(book_authors)) dtos := make([]BookAuthorDTO, len(book_authors))
for i, book_author := range book_authors { for i, book_author := range book_authors {
@@ -46,3 +59,5 @@ func ConvertBookAuthorsToDtos(book_authors []BookAuthor) []BookAuthorDTO {
} }
return dtos return dtos
} }
type BookAuthorDTOList []BookAuthorDTO

Some files were not shown because too many files have changed in this diff Show More