feat(cli): add user management commands

This commit is contained in:
Denis Gukov 2021-08-28 16:44:41 +05:00
parent a5a9f0cf0f
commit 22e422e15a
10 changed files with 278 additions and 43 deletions

View File

@ -50,6 +50,19 @@ func Execute() {
}
func runService() {
switch {
case util.Config.MySQL.IsPresent():
fmt.Printf("MySQL %v@%v %v\n", util.Config.MySQL.Username, util.Config.MySQL.Hostname, util.Config.MySQL.DbName)
case util.Config.BoltDb.IsPresent():
fmt.Printf("BoltDB %v\n", util.Config.BoltDb.Hostname)
case util.Config.Postgres.IsPresent():
fmt.Printf("Postgres %v@%v %v\n", util.Config.Postgres.Username, util.Config.Postgres.Hostname, util.Config.Postgres.DbName)
default:
panic(fmt.Errorf("database configuration not found"))
}
fmt.Printf("Tmp Path (projects home) %v\n", util.Config.TmpPath)
store := createStore()
defer store.Close()
@ -86,19 +99,6 @@ func runService() {
func createStore() db.Store {
util.ConfigInit(configPath)
switch {
case util.Config.MySQL.IsPresent():
fmt.Printf("MySQL %v@%v %v\n", util.Config.MySQL.Username, util.Config.MySQL.Hostname, util.Config.MySQL.DbName)
case util.Config.BoltDb.IsPresent():
fmt.Printf("BoltDB %v\n", util.Config.BoltDb.Hostname)
case util.Config.Postgres.IsPresent():
fmt.Printf("Postgres %v@%v %v\n", util.Config.Postgres.Username, util.Config.Postgres.Hostname, util.Config.Postgres.DbName)
default:
panic(fmt.Errorf("database configuration not found"))
}
fmt.Printf("Tmp Path (projects home) %v\n", util.Config.TmpPath)
store := factory.CreateStore()
if err := store.Connect(); err != nil {

View File

@ -10,8 +10,11 @@ type userArgs struct {
name string
email string
password string
admin bool
}
var targetUserArgs userArgs
func init() {
rootCmd.AddCommand(userCmd)
}
@ -20,9 +23,7 @@ var userCmd = &cobra.Command{
Use: "user",
Short: "Manage users",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
_ = cmd.Help()
os.Exit(0)
}
},
}

View File

@ -7,13 +7,12 @@ import (
"os"
)
var newUserArgs userArgs
func init() {
userAddCmd.PersistentFlags().StringVar(&newUserArgs.login, "login", "", "New user login")
userAddCmd.PersistentFlags().StringVar(&newUserArgs.name, "name", "", "New user name")
userAddCmd.PersistentFlags().StringVar(&newUserArgs.email, "email", "", "New user email")
userAddCmd.PersistentFlags().StringVar(&newUserArgs.password, "password", "", "New user password")
userAddCmd.PersistentFlags().StringVar(&targetUserArgs.login, "login", "", "New user login")
userAddCmd.PersistentFlags().StringVar(&targetUserArgs.name, "name", "", "New user name")
userAddCmd.PersistentFlags().StringVar(&targetUserArgs.email, "email", "", "New user email")
userAddCmd.PersistentFlags().StringVar(&targetUserArgs.password, "password", "", "New user password")
userAddCmd.PersistentFlags().BoolVar(&targetUserArgs.admin, "admin", false, "Mark new user as admin")
userCmd.AddCommand(userAddCmd)
}
@ -23,22 +22,22 @@ var userAddCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
ok := true
if newUserArgs.name == "" {
fmt.Println("Argument --name requied")
if targetUserArgs.name == "" {
fmt.Println("Argument --name required")
ok = false
}
if newUserArgs.login == "" {
fmt.Println("Argument --login requied")
if targetUserArgs.login == "" {
fmt.Println("Argument --login required")
ok = false
}
if newUserArgs.email == "" {
fmt.Println("Argument --email requied")
if targetUserArgs.email == "" {
fmt.Println("Argument --email required")
ok = false
}
if newUserArgs.password == "" {
fmt.Println("Argument --password requied")
if targetUserArgs.password == "" {
fmt.Println("Argument --password required")
ok = false
}
@ -51,17 +50,17 @@ var userAddCmd = &cobra.Command{
defer store.Close()
if _, err := store.CreateUser(db.UserWithPwd{
Pwd: newUserArgs.password,
Pwd: targetUserArgs.password,
User: db.User{
Name: newUserArgs.name,
Username: newUserArgs.login,
Email: newUserArgs.email,
Admin: true,
Name: targetUserArgs.name,
Username: targetUserArgs.login,
Email: targetUserArgs.email,
Admin: targetUserArgs.admin,
},
}); err != nil {
panic(err)
}
fmt.Printf("User %s <%s> added!", newUserArgs.login, newUserArgs.email)
fmt.Printf("User %s <%s> added!\n", targetUserArgs.login, targetUserArgs.email)
},
}

109
cli/cmd/user_change.go Normal file
View File

@ -0,0 +1,109 @@
package cmd
import (
"fmt"
"github.com/ansible-semaphore/semaphore/db"
"github.com/spf13/cobra"
"os"
)
func init() {
for _, cmd := range []*cobra.Command{userChangeByLoginCmd, userChangeByEmailCmd} {
cmd.PersistentFlags().StringVar(&targetUserArgs.login, "login", "", "User login")
cmd.PersistentFlags().StringVar(&targetUserArgs.name, "name", "", "User's new name")
cmd.PersistentFlags().StringVar(&targetUserArgs.email, "email", "", "User's new email")
cmd.PersistentFlags().StringVar(&targetUserArgs.password, "password", "", "User's new password")
cmd.PersistentFlags().BoolVar(&targetUserArgs.admin, "admin", false, "Mark user as admin")
userCmd.AddCommand(cmd)
}
}
func applyChangeUserArgsForUser(user db.User, store db.Store) {
if targetUserArgs.name != "" {
user.Name = targetUserArgs.name
}
if targetUserArgs.email != "" {
user.Email = targetUserArgs.email
}
if targetUserArgs.login != "" {
user.Username = targetUserArgs.login
}
if targetUserArgs.name != "" {
user.Name = targetUserArgs.name
}
if targetUserArgs.admin == true {
user.Admin = true
}
if err := store.UpdateUser(db.UserWithPwd{
User: user,
Pwd: targetUserArgs.password,
}); err != nil {
panic(err)
}
fmt.Printf("User %s <%s> changed!\n", user.Username, user.Email)
}
var userChangeByLoginCmd = &cobra.Command{
Use: "change-by-login",
Short: "Change user found by login",
Run: func(cmd *cobra.Command, args []string) {
ok := true
if targetUserArgs.login == "" {
fmt.Println("Argument --login required")
ok = false
}
if !ok {
fmt.Println("Use command `semaphore user change-by-login --help` for details.")
os.Exit(1)
}
store := createStore()
defer store.Close()
user, err := store.GetUserByLoginOrEmail(targetUserArgs.login, "")
if err != nil {
panic(err)
}
applyChangeUserArgsForUser(user, store)
},
}
var userChangeByEmailCmd = &cobra.Command{
Use: "change-by-email",
Short: "Change user found by email",
Run: func(cmd *cobra.Command, args []string) {
ok := true
if targetUserArgs.email == "" {
fmt.Println("Argument --email required")
ok = false
}
if !ok {
fmt.Println("Use command `semaphore user change-by-email --help` for details.")
os.Exit(1)
}
store := createStore()
defer store.Close()
user, err := store.GetUserByLoginOrEmail("", targetUserArgs.email)
if err != nil {
panic(err)
}
applyChangeUserArgsForUser(user, store)
},
}

46
cli/cmd/user_delete.go Normal file
View File

@ -0,0 +1,46 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
)
func init() {
userDeleteCmd.PersistentFlags().StringVar(&targetUserArgs.login, "login", "", "Login of the user you want to delete")
userDeleteCmd.PersistentFlags().StringVar(&targetUserArgs.email, "email", "", "Email of the user you want to delete")
userCmd.AddCommand(userDeleteCmd)
}
var userDeleteCmd = &cobra.Command{
Use: "delete",
Short: "Remove existing user",
Run: func(cmd *cobra.Command, args []string) {
ok := true
if targetUserArgs.login == "" && targetUserArgs.email == "" {
fmt.Println("Argument --email or --login required")
ok = false
}
if !ok {
fmt.Println("Use command `semaphore user delete --help` for details.")
os.Exit(1)
}
store := createStore()
defer store.Close()
user, err := store.GetUserByLoginOrEmail(targetUserArgs.login, targetUserArgs.email)
if err != nil {
panic(err)
}
if err := store.DeleteUser(user.ID); err != nil {
panic(err)
}
fmt.Printf("User %s <%s> deleted!\n", user.Username, user.Email)
},
}

47
cli/cmd/user_get.go Normal file
View File

@ -0,0 +1,47 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
)
func init() {
userGetCmd.PersistentFlags().StringVar(&targetUserArgs.login, "login", "", "Login of the user you want to delete")
userGetCmd.PersistentFlags().StringVar(&targetUserArgs.email, "email", "", "Email of the user you want to delete")
userCmd.AddCommand(userGetCmd)
}
var userGetCmd = &cobra.Command{
Use: "get",
Short: "Show user's data",
Run: func(cmd *cobra.Command, args []string) {
ok := true
if targetUserArgs.login == "" && targetUserArgs.email == "" {
fmt.Println("Argument --email or --login required")
ok = false
}
if !ok {
fmt.Println("Use command `semaphore user get --help` for details.")
os.Exit(1)
}
store := createStore()
defer store.Close()
user, err := store.GetUserByLoginOrEmail(targetUserArgs.login, targetUserArgs.email)
if err != nil {
panic(err)
}
fmt.Printf("ID: %d\n", user.ID)
fmt.Printf("Created: %s\n", user.Created)
fmt.Printf("Login: %s\n", user.Username)
fmt.Printf("Name: %s\n", user.Name)
fmt.Printf("Email: %s\n", user.Email)
fmt.Printf("Admin: %t\n", user.Admin)
},
}

30
cli/cmd/user_list.go Normal file
View File

@ -0,0 +1,30 @@
package cmd
import (
"fmt"
"github.com/ansible-semaphore/semaphore/db"
"github.com/spf13/cobra"
)
func init() {
userCmd.AddCommand(userListCmd)
}
var userListCmd = &cobra.Command{
Use: "list",
Short: "Print all users",
Run: func(cmd *cobra.Command, args []string) {
store := createStore()
defer store.Close()
users, err := store.GetUsers(db.RetrieveQueryParams{})
if err != nil {
panic(err)
}
for _, user := range users {
fmt.Println(user.Username)
}
},
}

View File

@ -87,6 +87,9 @@ type Store interface {
CreateUserWithoutPassword(user User) (User, error)
CreateUser(user UserWithPwd) (User, error)
DeleteUser(userID int) error
// UpdateUser updates all fields of the entity except Pwd.
// Pwd should be present of you want update user password. Empty Pwd ignored.
UpdateUser(user UserWithPwd) error
SetUserPassword(userID int, password string) error
GetUser(userID int) (User, error)

View File

@ -17,7 +17,8 @@ type User struct {
Alert bool `db:"alert" json:"alert"`
}
// UserWithPwd extends User structure with field for unhashed password received from JSON.
type UserWithPwd struct {
Pwd string `db:"-" json:"password"` // raw password from JSON
Pwd string `db:"-" json:"password"` // unhashed password from JSON
User
}

View File

@ -131,7 +131,7 @@ func loadConfig(configPath string) {
}
//If the configPath option has been set try to load and decode it
var usedPath string
//var usedPath string
if configPath == "" {
// if no configPath look in the cwd
@ -141,16 +141,15 @@ func loadConfig(configPath string) {
file, err := os.Open(defaultPath)
exitOnConfigError(err)
decodeConfig(file)
usedPath = defaultPath
//usedPath = defaultPath
} else {
path := configPath
file, err := os.Open(path)
exitOnConfigError(err)
decodeConfig(file)
usedPath = path
//usedPath = path
}
fmt.Println("Using config file: " + usedPath)
//fmt.Println("Using config file: " + usedPath)
}
func validateConfig() {