forked from goffee/goffee
New goffee command, set the password for the user account with the specified name.
user:password [username] [newpassword] [dev|prod] username - the name of the user to update password - the new password to set env - "dev" to use .env-dev, "prod" to use .env
This commit is contained in:
parent
807875da43
commit
06778a5357
6 changed files with 227 additions and 5 deletions
|
|
@ -14,7 +14,7 @@ var cfgFile string
|
|||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "goffee",
|
||||
Version: "v1.7.3",
|
||||
Version: "v1.7.5",
|
||||
Short: "Goffee is the cli tool",
|
||||
Long: `Goffee is the cli tool for creating new projects and performing other tasks`,
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ goffee run:dev
|
|||
w.SetMaxEvents(1)
|
||||
w.IgnoreHiddenFiles(true)
|
||||
w.Ignore(
|
||||
pwd+"/logs/app.log",
|
||||
pwd+"/logs",
|
||||
pwd+"/tmp",
|
||||
pwd+"/.git",
|
||||
pwd+"/storage/sqlite",
|
||||
|
|
|
|||
163
cmd/user-password.go
Normal file
163
cmd/user-password.go
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// Copyright (c) 2026 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var UserPasswordCmd = &cobra.Command{
|
||||
Use: "user:password [username] [newpassword] [dev|prod]",
|
||||
Short: "Change a user password",
|
||||
Long: `Set the password for the user account with the specified name.
|
||||
|
||||
Requires three arguments:
|
||||
username - the name of the user to update
|
||||
password - the new password to set
|
||||
env - "dev" to use .env-dev, "prod" to use .env
|
||||
|
||||
Example:
|
||||
goffee user:password someuser 'strongpassword' dev
|
||||
goffee user:password admin 'newpass123' prod
|
||||
|
||||
`,
|
||||
Args: cobra.ExactArgs(3),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
username := args[0]
|
||||
newPassword := args[1]
|
||||
envMode := args[2]
|
||||
|
||||
// Determine which env file to load
|
||||
var envFile string
|
||||
switch envMode {
|
||||
case "dev":
|
||||
envFile = ".env-dev"
|
||||
case "prod":
|
||||
envFile = ".env"
|
||||
default:
|
||||
fmt.Printf("Error: environment must be 'dev' or 'prod', got '%s'\n", envMode)
|
||||
return
|
||||
}
|
||||
|
||||
// Build full path to env file
|
||||
envPath := filepath.Join(".", envFile)
|
||||
if _, err := os.Stat(envPath); os.IsNotExist(err) {
|
||||
fmt.Printf("Error: environment file '%s' not found in current directory\n", envFile)
|
||||
return
|
||||
}
|
||||
|
||||
// Load env file
|
||||
err := godotenv.Load(envPath)
|
||||
if err != nil {
|
||||
fmt.Printf("Error loading environment file '%s': %v\n", envFile, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
db, err := connectDatabase()
|
||||
if err != nil {
|
||||
fmt.Printf("Error connecting to database: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Find user by name
|
||||
type User struct {
|
||||
ID uint
|
||||
Name string
|
||||
Password string
|
||||
Email string
|
||||
}
|
||||
var user User
|
||||
result := db.Where("name = ?", username).First(&user)
|
||||
if result.Error != nil {
|
||||
if strings.Contains(result.Error.Error(), "record not found") {
|
||||
fmt.Printf("Error: user '%s' not found\n", username)
|
||||
} else {
|
||||
fmt.Printf("Error finding user: %v\n", result.Error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Hash the new password
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
fmt.Printf("Error hashing password: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Update password in database
|
||||
result = db.Model(&user).Update("password", string(hashedPassword))
|
||||
if result.Error != nil {
|
||||
fmt.Printf("Error updating password: %v\n", result.Error)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Password updated successfully for user '%s'\n", username)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(UserPasswordCmd)
|
||||
}
|
||||
|
||||
// connectDatabase establishes a database connection based on the loaded environment variables.
|
||||
func connectDatabase() (*gorm.DB, error) {
|
||||
dbDriver := os.Getenv("DB_DRIVER")
|
||||
|
||||
var dialector gorm.Dialector
|
||||
switch dbDriver {
|
||||
case "sqlite":
|
||||
sqlitePath := os.Getenv("SQLITE_DB_PATH")
|
||||
if sqlitePath == "" {
|
||||
return nil, fmt.Errorf("SQLITE_DB_PATH environment variable not set")
|
||||
}
|
||||
dialector = sqlite.Open(sqlitePath)
|
||||
case "mysql":
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
|
||||
os.Getenv("MYSQL_USERNAME"),
|
||||
os.Getenv("MYSQL_PASSWORD"),
|
||||
os.Getenv("MYSQL_HOST"),
|
||||
os.Getenv("MYSQL_PORT"),
|
||||
os.Getenv("MYSQL_DB_NAME"),
|
||||
os.Getenv("MYSQL_CHARSET"),
|
||||
)
|
||||
dialector = mysql.Open(dsn)
|
||||
case "postgres":
|
||||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s TimeZone=%s",
|
||||
os.Getenv("POSTGRES_HOST"),
|
||||
os.Getenv("POSTGRES_USER"),
|
||||
os.Getenv("POSTGRES_PASSWORD"),
|
||||
os.Getenv("POSTGRES_DB_NAME"),
|
||||
os.Getenv("POSTGRES_PORT"),
|
||||
os.Getenv("POSTGRES_SSL_MODE"),
|
||||
os.Getenv("POSTGRES_TIMEZONE"),
|
||||
)
|
||||
dialector = postgres.Open(dsn)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported database driver: '%s'", dbDriver)
|
||||
}
|
||||
|
||||
db, err := gorm.Open(dialector, &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue