This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user