package main import ( "context" "database/sql" "embed" "errors" "github.com/flamego/captcha" "github.com/flamego/cors" "github.com/flamego/flamego" "github.com/flamego/session" sredis "github.com/flamego/session/redis" "github.com/flamego/template" "github.com/go-redis/redis/v8" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/mysql" "github.com/golang-migrate/migrate/v4/source/iofs" "github.com/jmoiron/sqlx" "github.com/joho/godotenv" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "kuvia/pkg/globaleuserdata" "net/http" "os" "strconv" ) //go:embed public var public embed.FS //go:embed templates var templates embed.FS //go:embed database/migrations/*.sql var database embed.FS var sqlConnection *sqlx.DB var s3 *minio.Client func migrateDB() { log.Info().Msg("Run Migration if exists") db, err := sql.Open("mysql", os.Getenv("DB_MIGRATION")) if err != nil { log.Fatal().Err(err).Str("Connection String", os.Getenv("DB_MIGRATION")).Msg("Cant Open SQL Connection") } driver, err := mysql.WithInstance(db, &mysql.Config{}) if err != nil { log.Fatal().Err(err).Str("Connection String", os.Getenv("DB_MIGRATION")).Msg("Cant create drive") } d, err := iofs.New(database, "database/migrations") if err != nil { log.Fatal().Err(err).Msg("Cant creat iofs to get migrations from") } m, err := migrate.NewWithInstance("iofs", d, "mysql", driver) if err != nil { log.Fatal().Err(err).Msg("Cant create migrate instante") } err = m.Up() if err != nil { if err.Error() == "no change" { log.Debug().Msg("No Changes at Migration") } else { panic(err) } } log.Info().Msg("Run Migration done") } func sqlConnect() { log.Info().Msg("Connect to MYSQL Server") db, err := sqlx.Open("mysql", os.Getenv("DB_CONNECTION")) if err != nil { panic(err) } sqlConnection = db log.Debug().Msg("Connection to MYSQL Done") } func s3Connect() { log.Debug().Msg("Connect to s3") minioClient, err := minio.New( os.Getenv("S3_HOST"), &minio.Options{ Creds: credentials.NewStaticV4(os.Getenv("S3_ID"), os.Getenv("S3_SECRET"), os.Getenv("S3_TOKEN")), Secure: false, }) if err != nil { log.Fatal().Err(err).Msg("Cant create s3 client") } ctx := context.Background() bucketexists, err := minioClient.BucketExists(ctx, os.Getenv("S3_BUCKET")) if err != nil { log.Fatal().Err(err).Msg("Cant check S3 Bucket exists") } if bucketexists == false { log.Info().Msg("Create S3 Bucket") err = minioClient.MakeBucket(ctx, os.Getenv("S3_BUCKET"), minio.MakeBucketOptions{}) if err != nil { log.Fatal().Str("Bucket-Name", os.Getenv("S3_BUCKET")).Err(err).Msg("Cant Create S3 Bucklet") } } else { log.Debug().Msg("Bucket already exists") } s3 = minioClient log.Debug().Msg("Finish create s3 client") } func loadEnvConfig() { if _, err := os.Stat(".env"); err == nil { err := godotenv.Load() if err != nil { log.Fatal().Err(err).Msg("Error loading .env file") } } else if errors.Is(err, os.ErrNotExist) { log.Info().Msg("No .env file found") } else { log.Fatal().Err(err).Msg("Error load config from env") } } func main() { log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) loadEnvConfig() migrateDB() sqlConnect() s3Connect() f := flamego.Classic() f.Use(flamego.Static( flamego.StaticOptions{ FileSystem: http.FS(public), }, )) templateFS, err := template.EmbedFS(templates, "templates", []string{".tmpl"}) if err != nil { log.Fatal().Err(err).Msg("Cant creat EmbedFS for templates") } f.Use(template.Templater( template.Options{ FileSystem: templateFS, }, )) redisDB, err := strconv.Atoi(os.Getenv("REDIS_DB")) if err != nil { log.Fatal().Err(err).Str("Redis DB String", os.Getenv("REDIS_DB")).Msg("Cant convertz Redis DB to int") } ro := redis.Options{ Addr: os.Getenv("REDIS_HORST"), DB: redisDB, } f.Use(session.Sessioner(session.Options{ Initer: sredis.Initer(), Config: sredis.Config{ Options: &ro, }, })) f.Use(globaleuserdata.GlobalUserData(sqlConnection)) f.Use(captcha.Captchaer(captcha.Options{ TextLength: 4, })) f.Use(cors.CORS()) f.Any("/", func(s session.Session, t template.Template, data template.Data) { t.HTML(http.StatusOK, "home") }) f.Get("/login", loginForm) f.Post("/login", login) f.Get("/register", registerForm) f.Post("/register", register) f.Get("/logout", logout) f.Get("/gallery/new", galleryNewForm) f.Post("/gallery/new", galleryNew) f.Get("/gallery/edit", galleryEditList) f.Get("/gallery/edit/{id}", galleryEdit) f.Post("/gallery/edit/{id}", galleryEditSave) f.Get("/gallery/edit/{id}/image", galleryEditMainImage) f.Post("/gallery/edit/{id}/image", galleryEditMainImageChange) f.Get("/file/upload", uploadImageForm) f.Post("/file/upload", uploadImage) f.Get("/u/{name}", userProfile) f.Get("/u/{name}/{id}", userGallery) f.Get("/image", getImage) f.Get("/settings/profile", profile) f.Post("/settings/profile", profileUpdate) f.Get("/settings/profile/image", profileImage) f.Post("/settings/profile/image", profileImageChange) f.Run() }