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

This commit is contained in:
Thomas Peetz
2026-10-29 00:14:54 +01:00
parent ab166fc075
commit 2aeba70906
12 changed files with 143 additions and 134772 deletions
+1
View File
@@ -1,2 +1,3 @@
# Added by goreleaser init: # Added by goreleaser init:
dist/ dist/
data/
+3 -12
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"
@@ -26,16 +25,8 @@ func main() {
log.Fatalf("Failed to initialize config: %v", err) log.Fatalf("Failed to initialize config: %v", err)
} }
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"),
)
db, err := config.NewDB(dsn) db, err := config.NewDB()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -45,7 +36,7 @@ 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)
} }
@@ -58,7 +49,7 @@ func main() {
) )
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,
+2 -2
View File
@@ -50,7 +50,7 @@ type ExportData struct {
MediaFile []models.MediaFileDTO `json:"media_file"` MediaFile []models.MediaFileDTO `json:"media_file"`
MediaActor []models.MediaActorDTO `json:"media_actor"` MediaActor []models.MediaActorDTO `json:"media_actor"`
MediaActorFile []models.MediaActorFileDTO `json:"media_actor_file"` MediaActorFile []models.MediaActorFileDTO `json:"media_actor_file"`
Profile []models.ProfileDTO `json:"profile"` Profile models.ProfileDTOList `json:"profile"`
Permission []models.PermissionDTO `json:"permission"` Permission []models.PermissionDTO `json:"permission"`
Assignment []models.AssignmentDTO `json:"assignment"` Assignment []models.AssignmentDTO `json:"assignment"`
Token []models.TokenDTO `json:"token"` Token []models.TokenDTO `json:"token"`
@@ -103,7 +103,7 @@ var (
Mediafiles []models.MediaFileDTO Mediafiles []models.MediaFileDTO
Medialofis models.MediaLoFiDTOList Medialofis models.MediaLoFiDTOList
MediaMusics models.MediaMusicDTOList MediaMusics models.MediaMusicDTOList
Profiles []models.ProfileDTO Profiles models.ProfileDTOList
Permissions []models.PermissionDTO Permissions []models.PermissionDTO
Assignments []models.AssignmentDTO Assignments []models.AssignmentDTO
Tokens []models.TokenDTO Tokens []models.TokenDTO
+36 -36
View File
@@ -1,36 +1,36 @@
package api package api
import ( import (
"encoding/json" "encoding/json"
"log/slog" "log/slog"
"os" "os"
) )
func WriteJson(data *ExportData, fileName string) error { func WriteJson(data *ExportData, fileName string) error {
jsonData, err := json.MarshalIndent(data, "", " ") jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil { if err != nil {
slog.Info("JSON MarshalIndent failed", "Error:", err) slog.Info("JSON MarshalIndent failed", "Error:", err)
return err return err
} }
// Write bytes to file // Write bytes to file
err = os.WriteFile(fileName, jsonData, 0644) err = os.WriteFile(fileName, jsonData, 0644)
if err != nil { if err != nil {
slog.Info("Error writing file:", "Error", err.Error()) slog.Info("Error writing file:", "Error", err.Error())
return err return err
} }
return nil return nil
} }
func ReadJson(data *ExportData, fileName string) error { func ReadJson(data *ExportData, fileName string) error {
content, err := os.ReadFile(fileName) content, err := os.ReadFile(fileName)
if err != nil { if err != nil {
slog.Info("Error reading file", "Error", err.Error()) slog.Info("Error reading file", "Error", err.Error())
return err return err
} }
if err := json.Unmarshal(content, data); err != nil { if err := json.Unmarshal(content, data); err != nil {
slog.Info("Error unmarshal json", "Error", err.Error()) slog.Info("Error unmarshal json", "Error", err.Error())
return err return err
} }
return nil return nil
} }
+3
View File
@@ -21,6 +21,9 @@ var importCmd = &cobra.Command{
if err != nil { if err != nil {
slog.Info("Error importing data", "Error", err.Error()) slog.Info("Error importing data", "Error", err.Error())
} }
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 MediaFiles", "count", len(data.MediaFile))
slog.Info("importing MediaLofis", "count", len(data.MediaLoFi)) slog.Info("importing MediaLofis", "count", len(data.MediaLoFi))
slog.Info("importing MediaLofi", "media_lofi", data.MediaLoFi[0]) slog.Info("importing MediaLofi", "media_lofi", data.MediaLoFi[0])
+45 -17
View File
@@ -11,14 +11,15 @@ import (
) )
var ( var (
CfgFile string CfgFile string
Verbose int Verbose int
Overwrite bool Overwrite bool
ServerName string ServerName string
Mediatype MediaType Mediatype MediaType
Config CliConfig Config CliConfig
DryRun bool ServerConfig ServerConfiguration
FileName string DryRun bool
FileName string
) )
const ( const (
@@ -61,9 +62,31 @@ type Server struct {
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 {
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() {
@@ -90,7 +113,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())
} }
@@ -98,13 +121,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")
@@ -114,6 +130,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
@@ -127,7 +152,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"
"github.com/spf13/viper"
"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"
"log/slog"
) )
func NewDB(dsn string) (*gorm.DB, error) { func NewDB() (*gorm.DB, error) {
db_type := ServerConfig.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",
viper.GetString("db.host"),
viper.GetString("db.user"),
viper.GetString("db.password"),
viper.GetString("db.name"),
viper.GetInt("db.port"),
)
return gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
case "sqlite":
return gorm.Open(sqlite.Open(viper.GetString("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)
// } // }
+20 -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,24 +20,24 @@ 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 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
@@ -48,6 +48,5 @@ type CreateArticleDTO struct {
} }
type UpdateArticleDTO struct { type UpdateArticleDTO struct {
Title *string `json:"title,omitempty" binding:"omitempty"` Title *string `json:"title,omitempty" binding:"omitempty"`
} }
+2 -2
View File
@@ -22,8 +22,8 @@ func (media_actor *MediaActor) TableName() string {
} }
type MediaActorForm struct { type MediaActorForm struct {
Name string `form:"name" binding:"required"` Name string `form:"name" binding:"required"`
Weblink string `form:"weblink" binding:"required"` Weblink string `form:"weblink" binding:"required"`
} }
type MediaActorDTO struct { type MediaActorDTO struct {
+2
View File
@@ -76,3 +76,5 @@ type LoginInput struct {
Email string `json:"email" binding:"required"` Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"` Password string `json:"password" binding:"required"`
} }
type ProfileDTOList []ProfileDTO
@@ -25,4 +25,3 @@ func (service *MailAccountService) Get(context context.Context, id string) (mode
slog.Info("MailAccountService#Get") slog.Info("MailAccountService#Get")
return service.repository.GetById(context, id) return service.repository.GetById(context, id)
} }
File diff suppressed because it is too large Load Diff