diff --git a/.DS_Store b/.DS_Store index 0c4401c..28bdaf6 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 48dbc30..6e141ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .env .docker_build/ +docker-compose.override.yml +tmp/ .theia/ vendor/ config/database.yml diff --git a/Dockerfile b/Dockerfile index 272a536..c281e40 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,20 @@ -FROM golang:1.12 as builder +# Builder Stage +FROM golang:1.23 as builder WORKDIR /usr/app +# Proje dosyalarını kopyala COPY . . +# Uygulamayı derle RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o ibanim . +# Migrations'ı derle RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o migrate ./migrations/ -# Multi stage +# Multi-stage build +# Alpine Stage (minimal imaj) FROM alpine:latest RUN apk --no-cache add ca-certificates @@ -18,10 +23,20 @@ ENV PATH /root WORKDIR /root/ +# Builder aşamasından derlenmiş ikili dosyaları al COPY --from=builder /usr/app/ibanim . - COPY --from=builder /usr/app/migrate . +# Konfigürasyon ve şablon dosyalarını kopyala +COPY --from=builder /usr/app/config /root/config +COPY --from=builder /usr/app/templates /root/templates + +# Örnek konfigürasyon dosyalarını kopyala +COPY --from=builder /usr/app/config/application.yml /root/config/application.yml +COPY --from=builder /usr/app/config/smtp.yml /root/config/smtp.yml +COPY --from=builder /usr/app/config/database.yml /root/config/database.yml + EXPOSE 8080 -CMD ["./ibanim"] +# Başlatma komutunu belirt +CMD ["./ibanim"] diff --git a/config/application.example.yml b/config/application.example.yml deleted file mode 100644 index 1b1e4dd..0000000 --- a/config/application.example.yml +++ /dev/null @@ -1,4 +0,0 @@ -app: - port: 4880 - env: localhost - debug: true \ No newline at end of file diff --git a/config/database.example.yml b/config/database.example.yml deleted file mode 100644 index 075673b..0000000 --- a/config/database.example.yml +++ /dev/null @@ -1,5 +0,0 @@ -db: - adapter: postgres - name: ibanim - user: ibanim - password: ibanim \ No newline at end of file diff --git a/config/db.go b/config/db.go index 3712338..2ef9b50 100644 --- a/config/db.go +++ b/config/db.go @@ -3,63 +3,65 @@ package config import ( "errors" "fmt" + "log" + "os" + "time" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/postgres" - _ "github.com/mattn/go-sqlite3" "github.com/monopayments/iban.im/model" "github.com/qor/validations" - - // _ "github.com/jinzhu/gorm/dialects/sqlite" TODO - disabled for compile time issue - "os" - "time" ) -// global DB variable => TODO repository pattern var DB *gorm.DB -func init() { +func InitDB() { var err error - if Config.App.Env == "gitpod" && Config.Db.Adapter == "postgres" { - if err = os.Unsetenv("PGHOSTADDR"); err != nil { - panic(err) - } + + adapter := os.Getenv("DB_ADAPTER") + if adapter == "" { + adapter = "postgres" } var connStr string - adapter := Config.Db.Adapter if adapter == "mysql" { - connStr = fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?parseTime=True&loc=Local", Config.Db.User, Config.Db.Password, Config.Db.Host, Config.Db.Port, Config.Db.Name) + connStr = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=True&loc=Local", + os.Getenv("DB_USER"), + os.Getenv("DB_PASSWORD"), + os.Getenv("DB_HOST"), + os.Getenv("DB_PORT"), + os.Getenv("DB_NAME"), + ) } else if adapter == "postgres" { - connStr = fmt.Sprintf("postgres://%v:%v@%v/%v?sslmode=disable", Config.Db.User, Config.Db.Password, Config.Db.Host, Config.Db.Name) - } else if adapter == "sqlite3" || adapter == "sqlite" { - connStr = Config.Db.Name + connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", + os.Getenv("DB_USER"), + os.Getenv("DB_PASSWORD"), + os.Getenv("DB_HOST"), + os.Getenv("DB_PORT"), + os.Getenv("DB_NAME"), + ) } else { - panic(errors.New("your database is not supported")) + panic(errors.New("unsupported database adapter")) } DB, err = gorm.Open(adapter, connStr) if err != nil { - panic(err) + log.Fatal("Database connection failed:", err) + } + + // Veritabanı bağlantısını kontrol etme + if err := DB.DB().Ping(); err != nil { + log.Fatalf("Error connecting to DB: %v", err) + } else { + log.Println("Successfully connected to DB") } + validations.RegisterCallbacks(DB) - DB.LogMode(Config.App.Debug) + DB.LogMode(true) DB.DB().SetMaxIdleConns(10) DB.DB().SetMaxOpenConns(30) DB.DB().SetConnMaxLifetime(time.Second * 60) DB.AutoMigrate(&model.User{}, &model.Iban{}, &model.Group{}) - - // TODO ping control for mysql - if adapter == "mysql" { - go checkPing() - } -} - -func checkPing() { - for { - time.Sleep(time.Second * 15) - DB.DB().Ping() - } } diff --git a/config/smtp.example.yml b/config/smtp.example.yml deleted file mode 100644 index 326a99f..0000000 --- a/config/smtp.example.yml +++ /dev/null @@ -1,5 +0,0 @@ -smtp: - host: smtp.iban.im - port: 587 - user: info@iban.im - password: xxxxxx \ No newline at end of file diff --git a/db/db.go b/db/db.go index 1e544ac..ca025ec 100644 --- a/db/db.go +++ b/db/db.go @@ -1,6 +1,7 @@ package db import ( + "fmt" "os" "github.com/jinzhu/gorm" @@ -13,10 +14,10 @@ type DB struct { *gorm.DB } -var connStrMap = map[string]string { - "localhost" : "host=localhost port=5432 user=ibanim dbname=ibanim password=ibanim sslmode=disable", - "docker" : "host=host.docker.internal port=5432 user=ibanim dbname=ibanim password=ibanim sslmode=disable", - "gitpod" : "host=localhost port=5432 user=gitpod dbname=ibanim sslmode=disable", +var connStrMap = map[string]string{ + "localhost": "host=localhost port=5432 user=ibanim dbname=ibanim password=ibanim sslmode=disable", + "docker": "host=host.docker.internal port=5432 user=ibanim dbname=ibanim password=ibanim sslmode=disable", + "gitpod": "host=localhost port=5432 user=gitpod dbname=ibanim sslmode=disable", } // ConnectDB : connecting DB @@ -30,6 +31,13 @@ func ConnectDB(env string) (*DB, error) { if err != nil { panic(err) } + //Check database connection + err = db.DB().Ping() + if err != nil { + panic("Database connection failed!" + err.Error()) + } else { + fmt.Println("database connection successful!") + } return &DB{db}, nil } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..38e4ac5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +services: + db: + image: postgres:15 + restart: always + container_name: postgres_db + environment: + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + POSTGRES_DB: mydb + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + app: + build: . + restart: always + container_name: go_app + environment: + - DB_ADAPTER=postgres + - DB_HOST=db + - DB_PORT=5432 + - DB_USER=myuser + - DB_PASSWORD=mypassword + - DB_NAME=mydb + depends_on: + - db + ports: + - "4880:8080" + volumes: + - ./templates:/usr/app/templates + - ./config:/usr/app/config + +volumes: + postgres_data: diff --git a/go.mod b/go.mod index 070a1ea..b1a79dd 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ require ( github.com/lib/pq v1.10.3 // indirect github.com/mattdamon108/gqlmerge v0.2.3 github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.24 github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/qor/qor v1.2.0 // indirect github.com/qor/validations v0.0.0-20171228122639-f364bca61b46 diff --git a/go.sum b/go.sum index 438d7dd..6ca57fb 100644 --- a/go.sum +++ b/go.sum @@ -100,9 +100,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= diff --git a/main.go b/main.go index ff2803e..1983b34 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,11 @@ const identityKey = "UserID" func main() { - router := gin.New() + router := gin.Default() + router.Use(func(c *gin.Context) { + fmt.Println(">>> New request:", c.Request.Method, c.Request.URL.Path) + c.Next() + }) router.Use(gin.Logger()) router.LoadHTMLGlob("templates/*.tmpl.html") @@ -42,7 +46,11 @@ func main() { log.Fatal("JWT Error:" + err.Error()) } - router.POST("/api/login", authMiddleware.LoginHandler) + router.POST("/api/login", func(c *gin.Context) { + fmt.Println(">>> /api/login endpoint called") // Log ekleyelim + authMiddleware.LoginHandler(c) + }) + auth := router.Group("/auth") auth.GET("/refresh_token", authMiddleware.RefreshHandler) diff --git a/model/iban.go b/model/iban.go index e110134..b1cb73e 100644 --- a/model/iban.go +++ b/model/iban.go @@ -2,26 +2,27 @@ package model import ( "fmt" - "github.com/jinzhu/gorm" - "golang.org/x/crypto/bcrypt" "strings" "time" + + "github.com/jinzhu/gorm" + "golang.org/x/crypto/bcrypt" ) // Iban : Model with injected fields `ID`, `CreatedAt`, `UpdatedAt` type Iban struct { - IbanID uint `gorm:"primary_key"` - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time `sql:"index"` - Text string `gorm:"type:varchar(100);not null"` - Description string - Password string - Handle string `gorm:"type:varchar(20);not null"` - Active bool - IsPrivate bool - OwnerID uint - OwnerType string + IbanID uint `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time `sql:"index"` + Text string `gorm:"type:varchar(100);not null"` + Description string + Password string + Handle string `gorm:"type:varchar(20);not null"` + Active bool + IsPrivate bool + OwnerID uint + OwnerType string } // HashPassword : hashing the password @@ -39,17 +40,13 @@ func (iban *Iban) HashPassword() { func (iban *Iban) ComparePassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(iban.Password), []byte(password)) - if err != nil { - return false - } - - return true + return err == nil } // Check Handle before create or update = must be add as index to db func (iban *Iban) CheckHandle(tx *gorm.DB) (exist bool) { var ibans []Iban - tx.Where("owner_id = ? AND handle = ?",iban.OwnerID,iban.Handle).Find(&ibans) + tx.Where("owner_id = ? AND handle = ?", iban.OwnerID, iban.Handle).Find(&ibans) for _, tmp := range ibans { if iban.Handle == tmp.Handle && iban.IbanID != tmp.IbanID { exist = true @@ -59,19 +56,19 @@ func (iban *Iban) CheckHandle(tx *gorm.DB) (exist bool) { } // BeforeSave Callback -func (iban *Iban) BeforeSave(tx *gorm.DB) (err error) { +func (iban *Iban) BeforeSave(tx *gorm.DB) (err error) { if iban.CheckHandle(tx) { err = fmt.Errorf("handle already exist") } return } -func (iban *Iban) Validate(db *gorm.DB) { +func (iban *Iban) Validate(db *gorm.DB) { if strings.TrimSpace(iban.Text) == "" { db.AddError(fmt.Errorf("you have to provide IBAN")) - }else if strings.TrimSpace(iban.Handle) == "" { + } else if strings.TrimSpace(iban.Handle) == "" { db.AddError(fmt.Errorf("you have to provide handle")) - }else if iban.IsPrivate && strings.TrimSpace(iban.Password) == "" { + } else if iban.IsPrivate && strings.TrimSpace(iban.Password) == "" { db.AddError(fmt.Errorf("you have to provide password")) } -} \ No newline at end of file +} diff --git a/model/user.go b/model/user.go index accc3b8..6b4d8ac 100644 --- a/model/user.go +++ b/model/user.go @@ -15,13 +15,13 @@ type User struct { CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time `sql:"index"` - Email string `gorm:"type:varchar(100);not null"` - Password string `gorm:"not null"` - Handle string `gorm:"not null;unique"` - FirstName string `gorm:"type:varchar(50);not null"` - LastName string `gorm:"type:varchar(50);not null"` - Bio string `gorm:"type:text"` - Visible bool // visible email address + Email string `gorm:"type:varchar(100);not null"` + Password string `gorm:"not null"` + Handle string `gorm:"not null;unique"` + FirstName string `gorm:"type:varchar(50);not null"` + LastName string `gorm:"type:varchar(50);not null"` + Bio string `gorm:"type:text"` + Visible bool // visible email address Avatar string Verified bool Active bool @@ -44,9 +44,6 @@ func (user *User) HashPassword() { func (user *User) ComparePassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) - if err != nil { - return false - } + return err == nil - return true }