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
Branches
No related tags found
No related merge requests found
......@@ -25,24 +25,6 @@ const (
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{
Use: "create",
Short: "Create new user",
......@@ -122,6 +104,7 @@ func createUserFunc(cmd *cobra.Command, args []string) error {
// creates and validates user inputs into the User model
func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) {
var u model.User
var opts model.Opts
users, err := getUsers()
if err != nil {
return u, false, err
......@@ -132,7 +115,7 @@ func createNewUserModel(cmd *cobra.Command) (model.User, bool, error) {
return u, false, err
}
opts, err := retrieveOpts(cmd)
err = opts.RetrieveOpts(cmd)
if err != nil {
return u, false, err
}
......@@ -582,7 +565,7 @@ Note: To search for the account use "useradm user show -l %s"`, login)
return nil
}
func validateInputs(opts userOpts) error {
func validateInputs(opts model.Opts) error {
var err error
err = validateGID(opts.GID)
......@@ -606,66 +589,6 @@ func validateInputs(opts userOpts) error {
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 {
if len(arr) != 3 {
return false
......
......@@ -36,15 +36,13 @@ func init() {
}
func deleteUserFunc(cmd *cobra.Command, args []string) error {
var opts model.Opts
success := false
userLogin, err := getFlagString(cmd, "login")
err := opts.RetrieveOpts(cmd)
if err != nil { return err }
confirm, err := cmd.Flags().GetBool("confirm")
if err != nil { return err }
u, err := locateUser(userLogin)
u, err := locateUser(opts.UID)
if err != nil { return err }
defer func() {
......@@ -61,7 +59,7 @@ func deleteUserFunc(cmd *cobra.Command, args []string) error {
fmt.Printf("Found %v\n\n", u.ToString())
confirmationPrompt(confirm, "removal")
confirmationPrompt(opts.Confirm, "removal")
err = removeDirs(u)
if err != nil { return err }
......
......@@ -4,129 +4,113 @@ import (
"os"
"fmt"
"bufio"
"errors"
"strings"
"os/exec"
"crypto/rand"
"gopkg.in/yaml.v3"
"github.com/spf13/cobra"
"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{
Use: "mod",
Use: "mod [username]",
Short: "Modify user information",
Args: cobra.ExactArgs(1),
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 {
confirm, err := cmd.Flags().GetBool("confirm")
var users []model.User
users, err := getUsers()
if err != nil {
return err
}
block, err := cmd.Flags().GetBool("block")
if err != nil {
return err
}
unblock, err := cmd.Flags().GetBool("unblock")
if err != nil {
return err
}
userNameNew, err := cmd.Flags().GetString("name")
if err != nil {
login := args[0]
res := searchUser(users, false, login, "", "", "", "", "")
if len(res) >= 1 {
err = fmt.Errorf("More than one user found")
return err
}
userGIDNew, err := cmd.Flags().GetString("group")
if err != nil {
return err
u := res[0]
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 {
err = fmt.Errorf("Error trying to create temp file:", 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 {
err = fmt.Errorf("Error serializing the yaml:", 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
}
userShellNew, err := cmd.Flags().GetString("shell")
if err != nil {
return err
// Abrir no editor
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
}
userPasswordNew, err := cmd.Flags().GetString("password")
// Ler o conteúdo editado
editedData, err := os.ReadFile(tmpFile.Name())
if err != nil {
err = fmt.Errorf("Error reading the modified file:", 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{
UID: userUID,
GID: userGIDNew,
GRR: userGRRNew,
Name: userNameNew,
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]"
// Desserializar apenas os campos editáveis
var newState cfg
if err := yaml.Unmarshal(editedData, &newState); err != nil {
err = fmt.Errorf("Error de-serializing the yaml:", err)
return err
}
fmt.Println(userMod.ToString())
confirmationPrompt(confirm, "update")
fmt.Println("Done!")
fmt.Println(userPasswordNew)
// Exibir a struct atualizada
fmt.Println("New config:")
fmt.Printf("%+v\n", newState)
return nil
}
......@@ -158,6 +142,3 @@ func confirmationPrompt(confirm bool, operation string) {
}
}
}
......@@ -14,4 +14,5 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // 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