add rest client
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s

This commit is contained in:
2026-09-27 03:09:22 +02:00
parent f0f1819a1f
commit 2d6fa7b7ee
17 changed files with 243 additions and 21 deletions
+21
View File
@@ -0,0 +1,21 @@
package cmd
import (
"log/slog"
"github.com/spf13/cobra"
)
var addLinksCmd = &cobra.Command{
Use: "add-links",
Short: "Add Links",
Long: "Add Links",
// Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
slog.Info("add Links")
},
}
func init() {
rootCmd.AddCommand(addLinksCmd)
}
+60
View File
@@ -0,0 +1,60 @@
package cmd
import (
"log/slog"
"github.com/spf13/cobra"
"resty.dev/v3"
)
type Login struct {
Email string
Password string
}
type LoginResponse struct {
Token string
}
var checkCmd = &cobra.Command{
Use: "check",
Short: "Check Kontor Database",
Long: "Check Kontor Database to given file",
// Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
slog.Info("check kontor")
slog.Info("Verbosity level", "level", verbose)
var login LoginResponse
client := resty.New()
res, err := client.R().
SetBody(Login{
Email: "thomas.peetz@thpeetz.de",
Password: "admin",
}).
SetHeader("Accept", "application/json").
SetResult(&login).
Post("http://127.0.0.1:8550/api/login")
if err != nil {
slog.Info("Health", "error", err.Error())
}
slog.Info("health", "token", login.Token)
res, err = client.R().
SetAuthToken(login.Token).
SetHeader("Accept", "application/json").
Get("http://127.0.0.1:8550/api/v1/comics/comics")
if err != nil {
slog.Info("comics", "error", err.Error())
}
slog.Info("comics", "res", res)
defer client.Close()
slog.Info("kontor.check_kontor.check_duplicate_links")
// check_duplicate_links(first_server, dirs)
slog.Info("kontor.check_kontor.check_media_dirs")
// check_media_dirs(first_server, dirs)
},
}
func init() {
rootCmd.AddCommand(checkCmd)
}
+22
View File
@@ -0,0 +1,22 @@
package cmd
import (
"log/slog"
"github.com/spf13/cobra"
)
var exportCmd = &cobra.Command{
Use: "export",
Short: "Export Kontor Database",
Long: "Export Kontor Database to given file",
// Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
slog.Info("export kontor")
slog.Info("Verbosity level", "level", verbose)
},
}
func init() {
rootCmd.AddCommand(exportCmd)
}
+21
View File
@@ -0,0 +1,21 @@
package cmd
import (
"log/slog"
"github.com/spf13/cobra"
)
var importCmd = &cobra.Command{
Use: "import",
Short: "Import Kontor Database",
Long: "Import Kontor Database from given file",
// Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
slog.Info("import kontor")
},
}
func init() {
rootCmd.AddCommand(importCmd)
}
+42
View File
@@ -0,0 +1,42 @@
package cmd
import (
"fmt"
"log/slog"
"os"
"github.com/spf13/cobra"
)
var cfgFile string
var verbose int
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "kontor-cli",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
slog.Info("Verbosity level", "level", verbose)
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Oops. An error while executing Zero '%s'\n", err)
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.myapp.yaml)")
rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "increase verbosity (-v, -vv, -vvv)")
}
+21
View File
@@ -0,0 +1,21 @@
package cmd
import (
"log/slog"
"github.com/spf13/cobra"
)
var syncCmd = &cobra.Command{
Use: "sync",
Short: "Sync Kontor Database",
Long: "Sync Kontor Database",
// Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
slog.Info("sync kontor")
},
}
func init() {
rootCmd.AddCommand(syncCmd)
}
+8 -1
View File
@@ -1,9 +1,11 @@
package handlers
import (
"kontor-api-gin/internal/helpers"
"kontor-api-gin/internal/service"
"net/http"
"github.com/gin-contrib/slog"
"github.com/gin-gonic/gin"
)
@@ -12,5 +14,10 @@ type AuthHandler struct {
}
func (handler *AuthHandler) Login(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"token": "bla"})
token, err := helpers.GenerateToken("bla")
logger := slog.Get(c)
if err != nil {
logger.Info("Login", "GenerateToken error", err.Error())
}
c.JSON(http.StatusOK, gin.H{"token": token})
}
+1 -1
View File
@@ -20,7 +20,7 @@ func GenerateToken(profile_id string) (string, error) {
"name": "Thomas Peetz",
"admin": true,
"authorized": true,
"profile_id": profile_id,
"sub": profile_id,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// claims["authorized"] = true
+16 -1
View File
@@ -1,6 +1,12 @@
package repository
import "gorm.io/gorm"
import (
"context"
"kontor-api-gin/internal/models/comics"
"log/slog"
"gorm.io/gorm"
)
type ComicRepository struct {
db *gorm.DB
@@ -10,3 +16,12 @@ func NewComicRepository(db *gorm.DB) *ComicRepository {
repo := &ComicRepository{db: db}
return repo
}
func (repository *ComicRepository) List(context context.Context) ([]comics.Comic, error) {
var comics []comics.Comic
result := repository.db.Find(&comics)
slog.Info("ComicRepository#List", "count", result.RowsAffected)
return comics, nil
}
-121
View File
@@ -1,121 +0,0 @@
package schema
import (
"kontor-api-gin/internal/helpers"
"time"
"golang.org/x/crypto/bcrypt"
)
func VerifyPassword(password, hashedPassword string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
func LoginCheck(email string, password string) (string, error) {
var err error
profile := Profile{}
err = DB.Model(Profile{}).Where("email = ?", email).Take(&profile).Error
if err != nil {
return "", err
}
err = VerifyPassword(password, profile.Password)
if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
return "", err
}
token, err := helpers.GenerateToken(profile.ID)
if err != nil {
return "", err
}
return token, nil
}
type Profile struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
First_Name *string `json:"first_name"`
Last_Name *string `json:"last_name"`
User_Name string `json:"user_name"`
Email string `json:"email"`
Password string `json:"password"`
Enabled bool `json:"enabled"`
Assignments []Assignment `gorm:"foreignKey:ProfileID" json:"assignments"`
Tokens []Token `gorm:"foreignKey:ProfileID" json:"tokens"`
}
func (profile *Profile) TableName() string {
return "profile"
}
func (profile *Profile) GetFullName() string {
full_name := ""
if profile.First_Name != nil {
full_name += *profile.First_Name
}
if profile.Last_Name != nil {
full_name += " "
full_name += *profile.Last_Name
}
return full_name
}
type Token struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Token string `gorm:"uniqueIndex" json:"token"`
Name string `json:"name"`
Last_Used_date time.Time `json:"last_used_date"`
Enabled bool `json:"enabled"`
ProfileID *string `json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
}
func (token *Token) TableName() string {
return "token"
}
type Permission struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `json:"name"`
Assignments []Assignment `gorm:"foreignKey:PermissionID" json:"assignments"`
}
func (permission *Permission) TableName() string {
return "permission"
}
type Assignment struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
ProfileID *string `json:"profile_id"`
Profile *Profile `gorm:"foreignKey:ProfileID" json:"profile"`
PermissionID *string `json:"permission_id"`
Permission *Profile `gorm:"foreignKey:PermissionID" json:"permission"`
}
func (assignment *Assignment) TableName() string {
return "assignment"
}
-22
View File
@@ -1,22 +0,0 @@
package schema
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Base struct {
ID string `gorm:"type:string;primary_key;"`
CreatedAt time.Time `json:"created_date"`
UpdatedAt time.Time `json:"last_modified_date"`
DeletedAt *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
}
// BeforeCreate will set a UUID rather than numeric ID.
func (b *Base) BeforeCreate(tx *gorm.DB) (err error) {
b.ID = uuid.New().String()
return
}
-66
View File
@@ -1,66 +0,0 @@
package schema
import (
"fmt"
"log"
"log/slog"
"time"
"github.com/spf13/viper"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
func Connect() {
// Build the connection string from environment variables
// This keeps sensitive credentials out of the codebase
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
viper.GetString("db.host"),
viper.GetString("db.user"),
viper.GetString("db.password"),
viper.GetString("db.name"),
viper.GetInt("db.port"),
)
// Configure GORM with custom settings
// The logger helps with debugging SQL queries during development
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
// Get the underlying SQL database connection for pool configuration
sqlDB, err := db.DB()
if err != nil {
log.Fatal("Failed to get database instance:", err)
}
// Configure connection pool settings
// MaxIdleConns: number of connections kept open when idle
sqlDB.SetMaxIdleConns(10)
// MaxOpenConns: maximum total connections to the database
sqlDB.SetMaxOpenConns(100)
// ConnMaxLifetime: how long a connection can be reused
sqlDB.SetConnMaxLifetime(time.Hour)
DB = db
slog.Info("Database connected successfully")
}
func RunMigrations() {
// AutoMigrate creates tables, missing columns, and missing indexes
// It will NOT delete unused columns to protect your data
err := DB.AutoMigrate()
if err != nil {
log.Fatal("Migration failed:", err)
}
slog.Info("Database migration completed")
}
-107
View File
@@ -1,107 +0,0 @@
package schema
import "time"
type MediaLoFi struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Url string `gorm:"uniqueIndex" json:"url"`
Review bool `json:"review"`
ShouldDownload bool `json:"should_download"`
Title string `gorm:"size:300" json:"title"`
FileName string `json:"file_name"`
}
func (media_lofi *MediaLoFi) TableName() string {
return "media_lofi"
}
type MediaFile struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
CloudLink string `gorm:"column:cloud_link" json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `gorm:"size:300" json:"title"`
WebLink string `gorm:"column:url" json:"url"`
ShouldDownload bool `json:"should_download"`
MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaFileID" json:"media_actor_files"`
}
func (media_file *MediaFile) TableName() string {
return "media_file"
}
type MediaActor struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Name string `json:"name"`
Url string `json:"url"`
MediaActorFiles []MediaActorFile `gorm:"foreignKey:MediaActorID" json:"media_actor_files"`
}
func (media_actor *MediaActor) TableName() string {
return "media_actor"
}
type MediaActorFile struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
MediaActorID *string `json:"media_actor_id"`
MediaActor *MediaActor `gorm:"foreignKey:MediaActorID" json:"media_actor"`
MediaFileID *string `json:"media_file_id"`
MediaFile *MediaFile `gorm:"foreignKey:MediaFileID" json:"media_file"`
}
func (media_file *MediaActorFile) TableName() string {
return "media_actor_file"
}
type MediaArticle struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
Review bool `json:"review"`
Title string `gorm:"size:300" json:"title"`
Url string `gorm:"uniqueIndex" json:"url"`
}
func (media_article *MediaArticle) TableName() string {
return "media_article"
}
type MediaVideo struct {
ID string `gorm:"type:string;primary_key;"`
Created_Date time.Time `json:"created_date"`
Last_Modified_date time.Time `json:"last_modified_date"`
Deleted_Date *time.Time `json:"deleted_date"`
Version int `gorm:"default:0" json:"version"`
CloudLink string `json:"cloud_link"`
FileName string `json:"file_name"`
Path string `json:"path"`
Review bool `json:"review"`
Title string `gorm:"size:300" json:"title"`
Url string `gorm:"uniqueIndex" json:"url"`
ShouldDownload bool `json:"should_download"`
}
func (media_video *MediaVideo) TableName() string {
return "media_video"
}
+3 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"kontor-api-gin/internal/models/comics"
"kontor-api-gin/internal/repository"
"log/slog"
)
type ComicService struct {
@@ -16,5 +17,6 @@ func NewComicService(repo *repository.ComicRepository) *ComicService {
}
func (service *ComicService) List(context context.Context) ([]comics.Comic, error) {
return nil, nil
slog.Info("ComicService#List")
return service.repository.List(context)
}