mirror of
https://github.com/KaySar12/NextZen-UserService.git
synced 2025-06-27 19:35:10 +07:00
310 lines
8.2 KiB
Go
310 lines
8.2 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
|
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/common"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/pkg/config"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/pkg/sqlite"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/file"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/service"
|
|
"github.com/IceWhaleTech/CasaOS-UserService/service/model"
|
|
"gopkg.in/ini.v1"
|
|
)
|
|
|
|
type migrationTool2 struct{}
|
|
|
|
const defaultDBPath = "/var/lib/casaos"
|
|
|
|
func (u *migrationTool2) IsMigrationNeeded() (bool, error) {
|
|
if status, err := version.GetGlobalMigrationStatus(userServiceNameShort); err == nil {
|
|
_status = status
|
|
if status.LastMigratedVersion != "" {
|
|
_logger.Info("Last migrated version: %s", status.LastMigratedVersion)
|
|
if r, err := version.Compare(status.LastMigratedVersion, common.Version); err == nil {
|
|
return r < 0, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
if _, err := os.Stat(version.LegacyCasaOSConfigFilePath); err != nil {
|
|
_logger.Info("`%s` not found, migration is not needed.", version.LegacyCasaOSConfigFilePath)
|
|
return false, nil
|
|
}
|
|
|
|
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
|
|
if err != nil {
|
|
if err == version.ErrLegacyVersionNotFound {
|
|
return false, nil
|
|
}
|
|
|
|
return false, err
|
|
}
|
|
|
|
if majorVersion != 0 {
|
|
return false, nil
|
|
}
|
|
|
|
if minorVersion != 3 {
|
|
return false, nil
|
|
}
|
|
|
|
if patchVersion < 3 || patchVersion > 5 {
|
|
return false, nil
|
|
}
|
|
|
|
// legacy version has to be between 0.3.3 and 0.3.5
|
|
_logger.Info("Migration is needed for a CasaOS version between 0.3.3 and 0.3.5...")
|
|
return true, nil
|
|
}
|
|
|
|
func (u *migrationTool2) PreMigrate() error {
|
|
if _, err := os.Stat(userServiceConfigDirPath); os.IsNotExist(err) {
|
|
_logger.Info("Creating %s since it doesn't exists...", userServiceConfigDirPath)
|
|
if err := os.Mkdir(userServiceConfigDirPath, 0o755); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if _, err := os.Stat(userServiceConfigFilePath); os.IsNotExist(err) {
|
|
_logger.Info("Creating %s since it doesn't exist...", userServiceConfigFilePath)
|
|
|
|
f, err := os.Create(userServiceConfigFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
if _, err := f.WriteString(_userServiceConfigFileSample); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
extension := "." + time.Now().Format("20060102") + ".bak"
|
|
|
|
_logger.Info("Creating a backup %s if it doesn't exist...", version.LegacyCasaOSConfigFilePath+extension)
|
|
if err := file.CopySingleFile(version.LegacyCasaOSConfigFilePath, version.LegacyCasaOSConfigFilePath+extension, "skip"); err != nil {
|
|
return err
|
|
}
|
|
|
|
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
|
|
|
|
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
_logger.Info("Creating a backup %s if it doesn't exist...", dbFile+extension)
|
|
if err := file.CopySingleFile(dbFile, dbFile+extension, "skip"); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *migrationTool2) Migrate() error {
|
|
_logger.Info("Loading legacy %s...", version.LegacyCasaOSConfigFilePath)
|
|
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
migrateConfigurationFile2(legacyConfigFile)
|
|
|
|
return migrateUser2(legacyConfigFile)
|
|
}
|
|
|
|
func (u *migrationTool2) PostMigrate() error {
|
|
defer _status.Done(common.Version)
|
|
|
|
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_logger.Info("Deleting legacy `user` section in %s...", version.LegacyCasaOSConfigFilePath)
|
|
|
|
legacyConfigFile.DeleteSection("user")
|
|
|
|
if err := legacyConfigFile.SaveTo(version.LegacyCasaOSConfigFilePath); err != nil {
|
|
return err
|
|
}
|
|
|
|
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
|
|
|
|
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
legacyDB, err := sql.Open("sqlite3", dbFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer legacyDB.Close()
|
|
|
|
for _, tableName := range []string{"o_users", "o_user"} {
|
|
tableExists, err := isTableExist(legacyDB, tableName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !tableExists {
|
|
continue
|
|
}
|
|
|
|
_logger.Info("Dropping `%s` table in legacy database...", tableName)
|
|
|
|
if _, err = legacyDB.Exec("DROP TABLE " + tableName); err != nil {
|
|
_logger.Error("Failed to drop `%s` table in legacy database: %s", tableName, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewMigrationToolFor033_034_035() interfaces.MigrationTool {
|
|
return &migrationTool2{}
|
|
}
|
|
|
|
func migrateConfigurationFile2(legacyConfigFile *ini.File) {
|
|
_logger.Info("Updating %s with settings from legacy configuration...", config.UserServiceConfigFilePath)
|
|
config.InitSetup(config.UserServiceConfigFilePath)
|
|
|
|
// LogPath
|
|
if logPath, err := legacyConfigFile.Section("app").GetKey("LogPath"); err == nil {
|
|
_logger.Info("[app] LogPath = %s", logPath.Value())
|
|
config.AppInfo.LogPath = logPath.Value()
|
|
}
|
|
|
|
// LogFileExt
|
|
if logFileExt, err := legacyConfigFile.Section("app").GetKey("LogFileExt"); err == nil {
|
|
_logger.Info("[app] LogFileExt = %s", logFileExt.Value())
|
|
config.AppInfo.LogFileExt = logFileExt.Value()
|
|
}
|
|
|
|
// DBPath
|
|
if dbPath, err := legacyConfigFile.Section("app").GetKey("DBPath"); err == nil {
|
|
_logger.Info("[app] DBPath = %s", dbPath.Value())
|
|
config.AppInfo.DBPath = dbPath.Value() + "/db"
|
|
}
|
|
|
|
// UserDataPath
|
|
if userDataPath, err := legacyConfigFile.Section("app").GetKey("UserDataPath"); err == nil {
|
|
_logger.Info("[app] UserDataPath = %s", userDataPath.Value())
|
|
config.AppInfo.UserDataPath = userDataPath.Value()
|
|
}
|
|
|
|
_logger.Info("Saving %s...", config.UserServiceConfigFilePath)
|
|
config.SaveSetup(config.UserServiceConfigFilePath)
|
|
}
|
|
|
|
func migrateUser2(legacyConfigFile *ini.File) error {
|
|
_logger.Info("Migrating user from legacy database to user database...")
|
|
|
|
user := model.UserDBModel{Role: "admin"}
|
|
|
|
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
|
|
|
|
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
|
|
|
|
if _, err := os.Stat(dbFile); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
legacyDB, err := sql.Open("sqlite3", dbFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer legacyDB.Close()
|
|
|
|
newDB := sqlite.GetDb(config.AppInfo.DBPath)
|
|
userService := service.NewUserService(newDB)
|
|
|
|
// create an inline map from string to string
|
|
sqlTableStatementMap := make(map[string]string)
|
|
sqlTableStatementMap["o_users"] = "SELECT id, username, password, role, email, nickname, avatar, description, created_at FROM o_users ORDER BY id ASC"
|
|
sqlTableStatementMap["o_user"] = "SELECT id, user_name, password, role, email, nick_name, avatar, description, created_at FROM o_user ORDER BY id ASC"
|
|
|
|
// historically there were two names for user table: o_users and users
|
|
for tableName, sqlStatement := range sqlTableStatementMap {
|
|
tableExists, err := isTableExist(legacyDB, tableName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !tableExists {
|
|
continue
|
|
}
|
|
rows, err := legacyDB.Query(sqlStatement)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
if err := rows.Scan(
|
|
&user.Id,
|
|
&user.Username,
|
|
&user.Password,
|
|
&user.Role,
|
|
&user.Email,
|
|
&user.Nickname,
|
|
&user.Avatar,
|
|
&user.Description,
|
|
&user.CreatedAt,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
if userService.GetUserAllInfoByName(user.Username).Id > 0 {
|
|
_logger.Info("User %s already exists in user database at %s, skipping...", user.Username, config.AppInfo.DBPath)
|
|
continue
|
|
}
|
|
|
|
_logger.Info("Creating user %s in user database...", user.Username)
|
|
user = userService.CreateUser(user)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func isTableExist(legacyDB *sql.DB, tableName string) (bool, error) {
|
|
rows, err := legacyDB.Query("SELECT name FROM sqlite_master WHERE type='table' AND name= ?", tableName)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
return rows.Next(), nil
|
|
}
|