From 9c8838a1b08a0b6927f655f1f8299cfa0b146f86 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Fri, 4 Nov 2022 15:59:21 +0800 Subject: [PATCH] feat: install configuration files and initialize basic information --- internal/base/conf/conf.go | 29 +++++---- internal/base/data/config.go | 12 ++-- internal/base/translator/config.go | 2 +- internal/install/install_controller.go | 40 +++++++++--- internal/migrations/init.go | 65 +++++++++++++++++-- internal/router/config.go | 8 +-- .../service/service_config/service_config.go | 6 +- 7 files changed, 120 insertions(+), 42 deletions(-) diff --git a/internal/base/conf/conf.go b/internal/base/conf/conf.go index 37b091c0..61e4f122 100644 --- a/internal/base/conf/conf.go +++ b/internal/base/conf/conf.go @@ -1,6 +1,7 @@ package conf import ( + "bytes" "path/filepath" "github.com/answerdev/answer/internal/base/data" @@ -11,28 +12,28 @@ import ( "github.com/answerdev/answer/internal/service/service_config" "github.com/answerdev/answer/pkg/writer" "github.com/segmentfault/pacman/contrib/conf/viper" - "sigs.k8s.io/yaml" + "gopkg.in/yaml.v3" ) // AllConfig all config type AllConfig struct { - Debug bool `json:"debug" mapstructure:"debug"` - Data *Data `json:"data" mapstructure:"data"` - Server *Server `json:"server" mapstructure:"server"` - I18n *translator.I18n `json:"i18n" mapstructure:"i18n"` - Swaggerui *router.SwaggerConfig `json:"swaggerui" mapstructure:"swaggerui"` - ServiceConfig *service_config.ServiceConfig `json:"service_config" mapstructure:"service_config"` + Debug bool `json:"debug" mapstructure:"debug" yaml:"debug"` + Server *Server `json:"server" mapstructure:"server" yaml:"server"` + Data *Data `json:"data" mapstructure:"data" yaml:"data"` + I18n *translator.I18n `json:"i18n" mapstructure:"i18n" yaml:"i18n"` + ServiceConfig *service_config.ServiceConfig `json:"service_config" mapstructure:"service_config" yaml:"service_config"` + Swaggerui *router.SwaggerConfig `json:"swaggerui" mapstructure:"swaggerui" yaml:"swaggerui"` } // Server server config type Server struct { - HTTP *server.HTTP `json:"http" mapstructure:"http"` + HTTP *server.HTTP `json:"http" mapstructure:"http" yaml:"http"` } // Data data config type Data struct { - Database *data.Database `json:"database" mapstructure:"database"` - Cache *data.CacheConf `json:"cache" mapstructure:"cache"` + Database *data.Database `json:"database" mapstructure:"database" yaml:"database"` + Cache *data.CacheConf `json:"cache" mapstructure:"cache" yaml:"cache"` } // ReadConfig read config @@ -53,9 +54,11 @@ func ReadConfig(configFilePath string) (c *AllConfig, err error) { // RewriteConfig rewrite config file path func RewriteConfig(configFilePath string, allConfig *AllConfig) error { - content, err := yaml.Marshal(allConfig) - if err != nil { + buf := bytes.Buffer{} + enc := yaml.NewEncoder(&buf) + enc.SetIndent(2) + if err := enc.Encode(allConfig); err != nil { return err } - return writer.ReplaceFile(configFilePath, string(content)) + return writer.ReplaceFile(configFilePath, buf.String()) } diff --git a/internal/base/data/config.go b/internal/base/data/config.go index 6bc4ec74..cd48547c 100644 --- a/internal/base/data/config.go +++ b/internal/base/data/config.go @@ -2,14 +2,14 @@ package data // Database database config type Database struct { - Driver string `json:"driver" mapstructure:"driver"` - Connection string `json:"connection" mapstructure:"connection"` - ConnMaxLifeTime int `json:"conn_max_life_time" mapstructure:"conn_max_life_time"` - MaxOpenConn int `json:"max_open_conn" mapstructure:"max_open_conn"` - MaxIdleConn int `json:"max_idle_conn" mapstructure:"max_idle_conn"` + Driver string `json:"driver" mapstructure:"driver" yaml:"driver"` + Connection string `json:"connection" mapstructure:"connection" yaml:"connection"` + ConnMaxLifeTime int `json:"conn_max_life_time" mapstructure:"conn_max_life_time" yaml:"conn_max_life_time,omitempty"` + MaxOpenConn int `json:"max_open_conn" mapstructure:"max_open_conn" yaml:"max_open_conn,omitempty"` + MaxIdleConn int `json:"max_idle_conn" mapstructure:"max_idle_conn" yaml:"max_idle_conn,omitempty"` } // CacheConf cache type CacheConf struct { - FilePath string `json:"file_path" mapstructure:"file_path"` + FilePath string `json:"file_path" mapstructure:"file_path" yaml:"file_path"` } diff --git a/internal/base/translator/config.go b/internal/base/translator/config.go index a00b5218..55a69203 100644 --- a/internal/base/translator/config.go +++ b/internal/base/translator/config.go @@ -2,5 +2,5 @@ package translator // I18n i18n config type I18n struct { - BundleDir string `json:"bundle_dir" mapstructure:"bundle_dir"` + BundleDir string `json:"bundle_dir" mapstructure:"bundle_dir" yaml:"bundle_dir"` } diff --git a/internal/install/install_controller.go b/internal/install/install_controller.go index 1b98db82..0f5fbaa0 100644 --- a/internal/install/install_controller.go +++ b/internal/install/install_controller.go @@ -1,6 +1,9 @@ package install import ( + "os" + "time" + "github.com/answerdev/answer/configs" "github.com/answerdev/answer/internal/base/conf" "github.com/answerdev/answer/internal/base/data" @@ -15,11 +18,6 @@ import ( "github.com/segmentfault/pacman/log" ) -// 1、校验配置文件 post installation/config-file/check -//2、校验数据库 post installation/db/check -//3、创建配置文件和数据库 post installation/init -//4、配置网站基本信息和超级管理员信息 post installation/base-info - // LangOptions get installation language options // @Summary get installation language options // @Description get installation language options @@ -63,6 +61,7 @@ func CheckConfigFile(ctx *gin.Context) { // @Tags installation // @Accept json // @Produce json +// @Param data body install.CheckDatabaseReq true "CheckDatabaseReq" // @Success 200 {object} handler.RespBody{data=install.CheckConfigFileResp{}} // @Router /installation/db/check [post] func CheckDatabase(ctx *gin.Context) { @@ -76,7 +75,7 @@ func CheckDatabase(ctx *gin.Context) { Driver: req.DbType, Connection: req.GetConnection(), } - resp.ConnectionSuccess = cli.CheckDB(dataConf, true) + resp.ConnectionSuccess = cli.CheckDB(dataConf, false) if !resp.ConnectionSuccess { handler.HandleResponse(ctx, errors.BadRequest(reason.DatabaseConnectionFailed), schema.ErrTypeAlert) return @@ -90,6 +89,7 @@ func CheckDatabase(ctx *gin.Context) { // @Tags installation // @Accept json // @Produce json +// @Param data body install.CheckDatabaseReq true "CheckDatabaseReq" // @Success 200 {object} handler.RespBody{data=install.CheckConfigFileResp{}} // @Router /installation/init [post] func InitEnvironment(ctx *gin.Context) { @@ -137,6 +137,7 @@ func InitEnvironment(ctx *gin.Context) { // @Tags installation // @Accept json // @Produce json +// @Param data body install.InitBaseInfoReq true "InitBaseInfoReq" // @Success 200 {object} handler.RespBody{data=install.CheckConfigFileResp{}} // @Router /installation/base-info [post] func InitBaseInfo(ctx *gin.Context) { @@ -145,8 +146,31 @@ func InitBaseInfo(ctx *gin.Context) { return } - // 修改配置文件 - // 修改管理员和对应信息 + c, err := conf.ReadConfig(confPath) + if err != nil { + log.Errorf("read config failed %s", err) + handler.HandleResponse(ctx, errors.BadRequest(reason.ReadConfigFailed), nil) + return + } + c.ServiceConfig.WebHost = req.SiteURL + if err := conf.RewriteConfig(confPath, c); err != nil { + log.Errorf("rewrite config failed %s", err) + handler.HandleResponse(ctx, errors.BadRequest(reason.ReadConfigFailed), nil) + return + } + + err = migrations.UpdateInstallInfo(c.Data.Database, req.Language, req.SiteName, req.SiteURL, req.ContactEmail, + req.AdminName, req.AdminPassword, req.AdminEmail) + if err != nil { + log.Error(err) + handler.HandleResponse(ctx, errors.BadRequest(reason.InstallConfigFailed), nil) + return + } + handler.HandleResponse(ctx, nil, nil) + go func() { + time.Sleep(1 * time.Second) + os.Exit(0) + }() return } diff --git a/internal/migrations/init.go b/internal/migrations/init.go index e9865b13..3ea6f89b 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -5,6 +5,7 @@ import ( "github.com/answerdev/answer/internal/base/data" "github.com/answerdev/answer/internal/entity" + "golang.org/x/crypto/bcrypt" "xorm.io/xorm" ) @@ -55,11 +56,6 @@ func InitDB(dataConf *data.Database) (err error) { return fmt.Errorf("init admin user failed: %s", err) } - err = initSiteInfo(engine) - if err != nil { - return fmt.Errorf("init site info failed: %s", err) - } - err = initConfigTable(engine) if err != nil { return fmt.Errorf("init config table: %s", err) @@ -82,12 +78,67 @@ func initAdminUser(engine *xorm.Engine) error { return err } -func initSiteInfo(engine *xorm.Engine) error { +func initSiteInfo(engine *xorm.Engine, language, siteName, siteURL, contactEmail string) error { _, err := engine.InsertOne(&entity.SiteInfo{ Type: "interface", - Content: `{"logo":"","theme":"black","language":"en_US"}`, + Content: fmt.Sprintf(`{"logo":"","theme":"black","language":%s}`, language), Status: 1, }) + if err != nil { + return err + } + _, err = engine.InsertOne(&entity.SiteInfo{ + Type: "general", + Content: fmt.Sprintf(`{"name":"%s","site_url":"%s","contact_email":"%s"}`, + siteName, siteURL, contactEmail), + Status: 1, + }) + return err +} + +func updateAdminInfo(engine *xorm.Engine, adminName, adminPassword, adminEmail string) error { + generateFromPassword, err := bcrypt.GenerateFromPassword([]byte(adminPassword), bcrypt.DefaultCost) + if err != nil { + return fmt.Errorf("") + } + adminPassword = string(generateFromPassword) + + // update admin info + _, err = engine.ID("1").Update(&entity.User{ + Username: adminName, + Pass: adminPassword, + EMail: adminEmail, + DisplayName: "admin", + }) + if err != nil { + return fmt.Errorf("update admin user info failed: %s", err) + } + return nil +} + +// UpdateInstallInfo update some init data about the admin interface and admin password +func UpdateInstallInfo(dataConf *data.Database, language string, + siteName string, + siteURL string, + contactEmail string, + adminName string, + adminPassword string, + adminEmail string) error { + + engine, err := data.NewDB(false, dataConf) + if err != nil { + return fmt.Errorf("database connection error: %s", err) + } + + err = updateAdminInfo(engine, adminName, adminPassword, adminEmail) + if err != nil { + return fmt.Errorf("update admin info failed: %s", err) + } + + err = initSiteInfo(engine, language, siteName, siteURL, contactEmail) + if err != nil { + return fmt.Errorf("init site info failed: %s", err) + } return err } diff --git a/internal/router/config.go b/internal/router/config.go index 742c9c8c..2f167185 100644 --- a/internal/router/config.go +++ b/internal/router/config.go @@ -2,8 +2,8 @@ package router // SwaggerConfig struct describes configure for the Swagger API endpoint type SwaggerConfig struct { - Show bool `json:"show"` - Protocol string `json:"protocol"` - Host string `json:"host"` - Address string `json:"address"` + Show bool `json:"show" mapstructure:"show" yaml:"show"` + Protocol string `json:"protocol" mapstructure:"protocol" yaml:"protocol"` + Host string `json:"host" mapstructure:"host" yaml:"host"` + Address string `json:"address" mapstructure:"address" yaml:"address"` } diff --git a/internal/service/service_config/service_config.go b/internal/service/service_config/service_config.go index 33e1f626..92d46393 100644 --- a/internal/service/service_config/service_config.go +++ b/internal/service/service_config/service_config.go @@ -1,7 +1,7 @@ package service_config type ServiceConfig struct { - SecretKey string `json:"secret_key" mapstructure:"secret_key"` - WebHost string `json:"web_host" mapstructure:"web_host"` - UploadPath string `json:"upload_path" mapstructure:"upload_path"` + SecretKey string `json:"secret_key" mapstructure:"secret_key" yaml:"secret_key"` + WebHost string `json:"web_host" mapstructure:"web_host" yaml:"web_host"` + UploadPath string `json:"upload_path" mapstructure:"upload_path" yaml:"upload_path"` }