first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:40:14 +03:00
commit e04ba85564
129 changed files with 17541 additions and 0 deletions

101
configs/db.go Normal file
View File

@@ -0,0 +1,101 @@
package configs
import (
"fmt"
"log"
"os"
"time"
accountModels "ginimageApi/app/accounts/models"
blogModels "ginimageApi/app/blogs/models"
imageModels "ginimageApi/app/images/models"
mcpModels "ginimageApi/app/mcp/models"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// DB global GORM veritabanı bağlantısı
var DB *gorm.DB
// ConnectDB .env dosyasındaki ayarlarla MySQL bağlantısını kurar
func ConnectDB() error {
host := os.Getenv("DB_HOST")
port := os.Getenv("DB_PORT")
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
dbName := os.Getenv("DB_NAME")
// DSN (Data Source Name) oluştur
dsn := fmt.Sprintf(
"%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
user, password, host, port, dbName,
)
// GORM logger ayarları
gormLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
)
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: gormLogger,
})
if err != nil {
return fmt.Errorf("veritabanına bağlanılamadı: %w", err)
}
// Bağlantı havuzu ayarları
sqlDB, err := DB.DB()
if err != nil {
return fmt.Errorf("sql.DB alınamadı: %w", err)
}
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
log.Printf("✅ Veritabanı bağlantısı kuruldu: %s:%s/%s", host, port, dbName)
return nil
}
// RunAutoMigrate tanımlanan modelleri otomatik olarak migrate eder
func RunAutoMigrate() error {
if DB == nil {
return fmt.Errorf("migration icin veritabani baglantisi yok")
}
err := DB.AutoMigrate(
&accountModels.User{},
&accountModels.SocialAccount{},
&accountModels.Profile{},
&accountModels.RefreshToken{},
&blogModels.Category{},
&blogModels.Tag{},
&blogModels.Post{},
&blogModels.CategoryView{},
&blogModels.Comment{},
&imageModels.Image{},
&mcpModels.ToolRun{},
)
if err != nil {
return fmt.Errorf("auto migrate basarisiz: %w", err)
}
log.Println("✅ AutoMigrate tamamlandı")
return nil
}
// SeedSecurityDefaults dinamik guvenlik ayarlari icin baslangic adimini temsil eder.
// Bu projede kalici ayar tablolari henuz olmadigi icin no-op tutulur.
func SeedSecurityDefaults() error {
log.Println("✅ SeedSecurityDefaults tamamlandı")
return nil
}

51
configs/db_test.go Normal file
View File

@@ -0,0 +1,51 @@
package configs
import (
"testing"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestRunAutoMigrateRequiresDB(t *testing.T) {
prev := DB
DB = nil
t.Cleanup(func() { DB = prev })
if err := RunAutoMigrate(); err == nil {
t.Fatalf("expected error when DB is nil")
}
}
func TestRunAutoMigrateSuccess(t *testing.T) {
prev := DB
dsn := "file:" + t.Name() + "?mode=memory&cache=shared"
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatalf("sqlite open failed: %v", err)
}
DB = db
t.Cleanup(func() {
if sqlDB, err := db.DB(); err == nil {
_ = sqlDB.Close()
}
DB = prev
})
if err := RunAutoMigrate(); err != nil {
t.Fatalf("RunAutoMigrate failed: %v", err)
}
if !DB.Migrator().HasTable("users") {
t.Fatalf("expected users table after migration")
}
if !DB.Migrator().HasTable("refresh_tokens") {
t.Fatalf("expected refresh_tokens table after migration")
}
}
func TestSeedSecurityDefaults(t *testing.T) {
if err := SeedSecurityDefaults(); err != nil {
t.Fatalf("SeedSecurityDefaults should not fail: %v", err)
}
}

46
configs/redis.go Normal file
View File

@@ -0,0 +1,46 @@
package configs
import (
"context"
"fmt"
"log"
"os"
"github.com/redis/go-redis/v9"
)
// RDB global Redis istemcisi
var RDB *redis.Client
// ConnectRedis .env'deki REDIS_URL ile Redis bağlantısını kurar
// Format: redis://<user>:<password>@<host>:<port>/<db>
func ConnectRedis() error {
redisURL := os.Getenv("REDIS_URL")
if redisURL == "" {
return fmt.Errorf("REDIS_URL ortam değişkeni tanımlı değil")
}
opts, err := redis.ParseURL(redisURL)
if err != nil {
return fmt.Errorf("REDIS_URL ayrıştırılamadı: %w", err)
}
RDB = redis.NewClient(opts)
// Bağlantıyı test et
ctx := context.Background()
if _, err := RDB.Ping(ctx).Result(); err != nil {
return fmt.Errorf("Redis'e bağlanılamadı: %w", err)
}
log.Printf("✅ Redis bağlantısı kuruldu: %s (db=%d)", opts.Addr, opts.DB)
return nil
}
// CloseRedis Redis bağlantısını güvenli şekilde kapatır
func CloseRedis() error {
if RDB != nil {
return RDB.Close()
}
return nil
}

45
configs/redis_test.go Normal file
View File

@@ -0,0 +1,45 @@
package configs
import (
"context"
"testing"
miniredis "github.com/alicebob/miniredis/v2"
)
func TestConnectRedisMissingURL(t *testing.T) {
t.Setenv("REDIS_URL", "")
if err := ConnectRedis(); err == nil {
t.Fatalf("expected error for missing REDIS_URL")
}
}
func TestConnectRedisInvalidURL(t *testing.T) {
t.Setenv("REDIS_URL", "%%%")
if err := ConnectRedis(); err == nil {
t.Fatalf("expected parse error for invalid REDIS_URL")
}
}
func TestConnectRedisSuccessAndClose(t *testing.T) {
mini, err := miniredis.Run()
if err != nil {
t.Fatalf("miniredis start failed: %v", err)
}
defer mini.Close()
t.Setenv("REDIS_URL", "redis://"+mini.Addr()+"/0")
if err := ConnectRedis(); err != nil {
t.Fatalf("ConnectRedis failed: %v", err)
}
t.Cleanup(func() { _ = CloseRedis() })
if pong, err := RDB.Ping(context.Background()).Result(); err != nil || pong != "PONG" {
t.Fatalf("expected redis ping PONG, got %q err=%v", pong, err)
}
if err := CloseRedis(); err != nil {
t.Fatalf("CloseRedis failed: %v", err)
}
}