Skip to content
Snippets Groups Projects
Commit e303dcc1 authored by Theo's avatar Theo :troll:
Browse files

Refactor: include model Opts and change how user mod works

parent e49eca75
No related branches found
No related tags found
No related merge requests found
...@@ -25,24 +25,6 @@ const ( ...@@ -25,24 +25,6 @@ const (
MAX_UID = 6000 MAX_UID = 6000
) )
type userOpts struct {
GRR string
GID string
UID string
Resp string
Name string
Nobkp string
Ltype string
Shell string
Passwd string
Webdir string
Status string
Course string
Expiry string
Homedir string
Confirm bool
}
var CreateUserCmd = &cobra.Command{ var CreateUserCmd = &cobra.Command{
Use: "create", Use: "create",
Short: "Create new user", Short: "Create new user",
...@@ -122,6 +104,7 @@ func createUserFunc(cmd *cobra.Command, args []string) error { ...@@ -122,6 +104,7 @@ func createUserFunc(cmd *cobra.Command, args []string) error {
// creates and validates user inputs into the User model // creates and validates user inputs into the User model
func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) { func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) {
var u model.User var u model.User
var opts model.Opts
users, err := getUsers() users, err := getUsers()
if err != nil { if err != nil {
return u, false, err return u, false, err
...@@ -132,7 +115,7 @@ func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) { ...@@ -132,7 +115,7 @@ func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) {
return u, false, err return u, false, err
} }
opts, err := retrieveOpts(cmd) err = opts.RetrieveOpts(cmd)
if err != nil { if err != nil {
return u, false, err return u, false, err
} }
...@@ -582,7 +565,7 @@ Note: To search for the account use "useradm user show -l %s"`, login) ...@@ -582,7 +565,7 @@ Note: To search for the account use "useradm user show -l %s"`, login)
return nil return nil
} }
func validateInputs(opts userOpts) error { func validateInputs(opts model.Opts) error {
var err error var err error
err = validateGID(opts.GID) err = validateGID(opts.GID)
...@@ -606,66 +589,6 @@ func validateInputs(opts userOpts) error { ...@@ -606,66 +589,6 @@ func validateInputs(opts userOpts) error {
return nil return nil
} }
func getFlagString(cmd *cobra.Command, flag string) (string, error) {
flagValue, err := cmd.Flags().GetString(flag)
if err != nil {
return "", fmt.Errorf("Failed to get flag %q: %w", flag, err)
}
return flagValue, nil
}
func retrieveOpts(cmd *cobra.Command) (userOpts, error) {
var opts userOpts
var err error
opts.GRR, err = getFlagString(cmd, "grr")
if err != nil { return opts, err }
opts.Resp, err = getFlagString(cmd, "resp")
if err != nil { return opts, err }
opts.Name, err = getFlagString(cmd, "name")
if err != nil { return opts, err }
opts.GID, err = getFlagString(cmd, "group")
if err != nil { return opts, err }
opts.UID, err = getFlagString(cmd, "login")
if err != nil { return opts, err }
opts.Ltype, err = getFlagString(cmd, "type")
if err != nil { return opts, err }
opts.Shell, err = getFlagString(cmd, "shell")
if err != nil { return opts, err }
opts.Webdir, err = getFlagString(cmd, "path")
if err != nil { return opts, err }
opts.Nobkp, err = getFlagString(cmd, "nobkp")
if err != nil { return opts, err }
opts.Status, err = getFlagString(cmd, "status")
if err != nil { return opts, err }
opts.Course, err = getFlagString(cmd, "course")
if err != nil { return opts, err }
opts.Expiry, err = getFlagString(cmd, "expiry")
if err != nil { return opts, err }
opts.Passwd, err = getFlagString(cmd, "passwd")
if err != nil { return opts, err }
opts.Homedir, err = getFlagString(cmd, "homedir")
if err != nil { return opts, err }
opts.Confirm, err = cmd.Flags().GetBool("confirm")
if err != nil { return opts, err }
return opts, nil
}
func isValidDate(arr []string) bool { func isValidDate(arr []string) bool {
if len(arr) != 3 { if len(arr) != 3 {
return false return false
......
...@@ -36,15 +36,13 @@ func init() { ...@@ -36,15 +36,13 @@ func init() {
} }
func deleteUserFunc(cmd *cobra.Command, args []string) error { func deleteUserFunc(cmd *cobra.Command, args []string) error {
var opts model.Opts
success := false success := false
userLogin, err := getFlagString(cmd, "login") err := opts.RetrieveOpts(cmd)
if err != nil { return err } if err != nil { return err }
confirm, err := cmd.Flags().GetBool("confirm") u, err := locateUser(opts.UID)
if err != nil { return err }
u, err := locateUser(userLogin)
if err != nil { return err } if err != nil { return err }
defer func() { defer func() {
...@@ -61,7 +59,7 @@ func deleteUserFunc(cmd *cobra.Command, args []string) error { ...@@ -61,7 +59,7 @@ func deleteUserFunc(cmd *cobra.Command, args []string) error {
fmt.Printf("Found %v\n\n", u.ToString()) fmt.Printf("Found %v\n\n", u.ToString())
confirmationPrompt(confirm, "removal") confirmationPrompt(opts.Confirm, "removal")
err = removeDirs(u) err = removeDirs(u)
if err != nil { return err } if err != nil { return err }
......
...@@ -4,129 +4,113 @@ import ( ...@@ -4,129 +4,113 @@ import (
"os" "os"
"fmt" "fmt"
"bufio" "bufio"
"errors"
"strings" "strings"
"os/exec"
"crypto/rand" "crypto/rand"
"gopkg.in/yaml.v3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gitlab.c3sl.ufpr.br/tss24/useradm/model" "gitlab.c3sl.ufpr.br/tss24/useradm/model"
) )
type cfg struct {
Name string `yaml:"name"`
GRR string `yaml:"grr"`
Group string `yaml:"group"`
Status string `yaml:"status"`
Shell string `yaml:"shell"`
Course string `yaml:"course"`
Resp string `yaml:"resp"`
Expiry string `yaml:"expiry"`
}
var ModCmd = &cobra.Command{ var ModCmd = &cobra.Command{
Use: "mod", Use: "mod [username]",
Short: "Modify user information", Short: "Modify user information",
Args: cobra.ExactArgs(1),
RunE: modifyUserFunc, RunE: modifyUserFunc,
} }
func init() {
// possible flags
ModCmd.Flags().StringP("grr", "r", "", "New user GRR")
ModCmd.Flags().StringP("shell", "s", "", "New user shell")
ModCmd.Flags().StringP("login", "l", "", "User login name")
ModCmd.Flags().StringP("homedir", "d", "", "New user home")
ModCmd.Flags().BoolP ("unblock", "u", false, "Unblocks the user")
ModCmd.Flags().StringP("group", "g", "", "New user initial group")
ModCmd.Flags().StringP("path", "w", "", "Create Webdir, path/login")
ModCmd.Flags().StringP("name", "n", "", "New user full name (use quotes for spaces)")
ModCmd.Flags().StringP("password", "p", "", "New password in plain text (use \"auto\" to autogenerate)")
ModCmd.Flags().BoolP ("block", "b", false, "Block the user (changes the password and sets their shell to /bin/false)")
// required flags
ModCmd.MarkFlagRequired("login")
ModCmd.Flags().BoolP("confirm", "y", false, "Skip confirmation prompt")
}
func modifyUserFunc(cmd *cobra.Command, args []string) error { func modifyUserFunc(cmd *cobra.Command, args []string) error {
confirm, err := cmd.Flags().GetBool("confirm") var users []model.User
users, err := getUsers()
if err != nil { if err != nil {
return err return err
} }
block, err := cmd.Flags().GetBool("block")
if err != nil { login := args[0]
return err res := searchUser(users, false, login, "", "", "", "", "")
} if len(res) >= 1 {
unblock, err := cmd.Flags().GetBool("unblock") err = fmt.Errorf("More than one user found")
if err != nil {
return err
}
userNameNew, err := cmd.Flags().GetString("name")
if err != nil {
return err return err
} }
userGIDNew, err := cmd.Flags().GetString("group") u := res[0]
if err != nil {
return err state := cfg{
Name: u.Name,
GRR: u.GRR,
Group: u.GID,
Status: u.Status,
Shell: u.Shell,
Course: u.Course,
Resp: u.Resp,
Expiry: u.Expiry,
} }
userGRRNew, err := cmd.Flags().GetString("grr")
// Criar arquivo temporário
tmpFile, err := os.CreateTemp("", "config-*.yaml")
if err != nil { if err != nil {
err = fmt.Errorf("Error trying to create temp file:", err)
return err return err
} }
userWebdirNew, err := cmd.Flags().GetString("path") defer os.Remove(tmpFile.Name())
// Serializar apenas os campos editáveis
data, err := yaml.Marshal(state)
if err != nil { if err != nil {
err = fmt.Errorf("Error serializing the yaml:", err)
return err return err
} }
userUID, err := cmd.Flags().GetString("login")
if err != nil { // Escrever no arquivo temporário
if err := os.WriteFile(tmpFile.Name(), data, 0644); err != nil {
err = fmt.Errorf("Error writing to temp file:", err)
return err return err
} }
userShellNew, err := cmd.Flags().GetString("shell")
if err != nil { // Abrir no editor
return err editor := os.Getenv("EDITOR")
if editor == "" {
editor = "nano"
} }
userHomedirNew, err := cmd.Flags().GetString("homedir")
if err != nil { comd := exec.Command(editor, tmpFile.Name())
comd.Stdin = os.Stdin
comd.Stdout = os.Stdout
comd.Stderr = os.Stderr
if err := comd.Run(); err != nil {
err = fmt.Errorf("Error opening the editor:", err)
return err return err
} }
userPasswordNew, err := cmd.Flags().GetString("password")
// Ler o conteúdo editado
editedData, err := os.ReadFile(tmpFile.Name())
if err != nil { if err != nil {
err = fmt.Errorf("Error reading the modified file:", err)
return err return err
} }
if block && unblock {
return errors.New("Can't block and unblock at the same time!\n")
}
var userStatusNew string
if block {
userShellNew = "/bin/false"
userStatusNew = "Blocked!"
userPasswordNew = "auto"
} else if unblock {
userShellNew = "/bin/bash"
userStatusNew = "Active"
userPasswordNew = "auto"
}
userMod := model.User{ // Desserializar apenas os campos editáveis
UID: userUID, var newState cfg
GID: userGIDNew, if err := yaml.Unmarshal(editedData, &newState); err != nil {
GRR: userGRRNew, err = fmt.Errorf("Error de-serializing the yaml:", err)
Name: userNameNew, return err
Shell: userShellNew,
Webdir: userWebdirNew,
Status: userStatusNew,
Homedir: userHomedirNew,
Password: userPasswordNew,
}
if cmd.Flags().Changed("password") || block || unblock {
if userPasswordNew == "auto" {
userPasswordNew = genPassword()
userMod.Password = "[auto-generated]"
} else {
userMod.Password = "[explicitly set]"
}
} else {
userMod.Password = "[unchanged]"
} }
fmt.Println(userMod.ToString()) // Exibir a struct atualizada
fmt.Println("New config:")
confirmationPrompt(confirm, "update") fmt.Printf("%+v\n", newState)
fmt.Println("Done!")
fmt.Println(userPasswordNew)
return nil return nil
} }
...@@ -158,6 +142,3 @@ func confirmationPrompt(confirm bool, operation string) { ...@@ -158,6 +142,3 @@ func confirmationPrompt(confirm bool, operation string) {
} }
} }
} }
...@@ -14,4 +14,5 @@ require ( ...@@ -14,4 +14,5 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.31.0 // indirect golang.org/x/crypto v0.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
package model
import (
"fmt"
"github.com/spf13/cobra"
)
type Opts struct {
GRR string
GID string
UID string
Resp string
Name string
Nobkp string
Ltype string
Shell string
Passwd string
Webdir string
Status string
Course string
Expiry string
Homedir string
Block bool
Unblock bool
Confirm bool
}
func (o *Opts) ToString() string {
return fmt.Sprintf(`Opts:
GRR %s
GID %s
UID %s
Resp %s
Name %s
Nobkp %s
Ltype %s
Shell %s
Passwd %s
Webdir %s
Status %s
Course %s
Expiry %s
Homedir %s
Block %v
Unblock %v
Confirm %v`,
o.GRR, o.GID, o.UID, o.Resp, o.Name, o.Nobkp, o.Ltype, o.Shell,
o.Passwd, o.Webdir, o.Status, o.Course, o.Expiry, o.Homedir,
o.Block, o.Unblock, o.Confirm)
}
func (o *Opts) RetrieveOpts(cmd *cobra.Command) error {
var err error
o.GRR, err = getFlagString(cmd, "grr")
if err != nil { return err }
o.Resp, err = getFlagString(cmd, "resp")
if err != nil { return err }
o.Name, err = getFlagString(cmd, "name")
if err != nil { return err }
o.GID, err = getFlagString(cmd, "group")
if err != nil { return err }
o.UID, err = getFlagString(cmd, "login")
if err != nil { return err }
o.Ltype, err = getFlagString(cmd, "type")
if err != nil { return err }
o.Shell, err = getFlagString(cmd, "shell")
if err != nil { return err }
o.Webdir, err = getFlagString(cmd, "path")
if err != nil { return err }
o.Nobkp, err = getFlagString(cmd, "nobkp")
if err != nil { return err }
o.Status, err = getFlagString(cmd, "status")
if err != nil { return err }
o.Course, err = getFlagString(cmd, "course")
if err != nil { return err }
o.Expiry, err = getFlagString(cmd, "expiry")
if err != nil { return err }
o.Passwd, err = getFlagString(cmd, "passwd")
if err != nil { return err }
o.Homedir, err = getFlagString(cmd, "homedir")
if err != nil { return err }
o.Confirm, err = getFlagBool(cmd, "confirm")
if err != nil { return err }
o.Unblock, err = getFlagBool(cmd, "unblock")
if err != nil { return err }
o.Block, err = getFlagBool(cmd, "block")
if err != nil { return err }
return nil
}
// since this model is used in most subcommands, some
// flags may exist in one command but not in another,
// so if it doesn't exist just set as empty before
// the error occurs, it won't be used anyway... :D
func getFlagString(cmd *cobra.Command, flag string) (string, error) {
if cmd.Flags().Lookup(flag) == nil {
return "", nil
}
flagValue, err := cmd.Flags().GetString(flag)
if err != nil {
return "", fmt.Errorf("failed to get flag %q: %w", flag, err)
}
return flagValue, nil
}
func getFlagBool(cmd *cobra.Command, flag string) (bool, error) {
if cmd.Flags().Lookup(flag) == nil {
return false, nil
}
flagValue, err := cmd.Flags().GetBool(flag)
if err != nil {
return false, fmt.Errorf("failed to get flag %q: %w", flag, err)
}
return flagValue, nil
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment