Add some user related commands

This commit is contained in:
Miguel de la Cruz 2021-09-13 12:16:25 +02:00
parent d5a297cb86
commit 83a2d2a31f
8 changed files with 223 additions and 11 deletions

View file

@ -1,13 +1,13 @@
package api package api
import ( import (
"git.ctrlz.es/mgdelacroix/craban/services/store" "git.ctrlz.es/mgdelacroix/craban/app"
) )
type API struct { type API struct {
store *store.Store App *app.App
} }
func NewAPI(store *store.Store) (*API, error) { func NewAPI(app *app.App) *API {
return &API{store: store}, nil return &API{App: app}
} }

18
server/app/app.go Normal file
View file

@ -0,0 +1,18 @@
package app
import (
"git.ctrlz.es/mgdelacroix/craban/model"
"git.ctrlz.es/mgdelacroix/craban/services/store"
)
type App struct {
config *model.Config
store *store.Store
}
func NewApp(config *model.Config, store *store.Store) *App {
return &App{
config: config,
store: store,
}
}

36
server/app/user.go Normal file
View file

@ -0,0 +1,36 @@
package app
import (
"fmt"
"git.ctrlz.es/mgdelacroix/craban/model"
"git.ctrlz.es/mgdelacroix/craban/utils"
)
func (a *App) CreateUser(username, password, name, mail string) (*model.User, error) {
hashedPassword, err := utils.Encrypt(password)
if err != nil {
return nil, fmt.Errorf("cannot create user: %w", err)
}
newUser := &model.User{
Username: username,
Password: hashedPassword,
Name: name,
Mail: mail,
}
if err := newUser.IsValid(); err != nil {
return nil, fmt.Errorf("invalid user for creation: %w", err)
}
return a.store.User().Create(newUser)
}
func (a *App) ListUsers() ([]*model.User, error) {
return a.store.User().List()
}
func (a *App) DeleteUserByUsername(username string) error {
return a.store.User().DeleteByUsername(username)
}

View file

@ -16,6 +16,7 @@ func RootCmd() *cobra.Command {
cmd.AddCommand( cmd.AddCommand(
ServeCmd(), ServeCmd(),
UserCmd(),
) )
return cmd return cmd

View file

@ -14,14 +14,15 @@ func ServeCmd() *cobra.Command {
return &cobra.Command{ return &cobra.Command{
Use: "serve", Use: "serve",
Short: "Starts the craban server", Short: "Starts the craban server",
Args: cobra.NoArgs,
Run: serveCmdF, Run: serveCmdF,
} }
} }
func serveCmdF(cmd *cobra.Command, _ []string) { func serveCmdF(cmd *cobra.Command, _ []string) {
configPath, _ := cmd.Flags().GetString("config") config, _ := cmd.Flags().GetString("config")
srv, err := server.NewServerWithConfigPath(configPath) srv, err := server.NewServerWithConfigPath(config)
if err != nil { if err != nil {
log.Error().Err(err).Msg("cannot create server") log.Error().Err(err).Msg("cannot create server")
os.Exit(1) os.Exit(1)

View file

@ -0,0 +1,123 @@
package commands
import (
"os"
"git.ctrlz.es/mgdelacroix/craban/server"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
func UserCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "user",
Short: "User related commands",
}
cmd.AddCommand(
CreateUserCmd(),
ListUserCmd(),
DeleteUserCmd(),
)
return cmd
}
func CreateUserCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new user",
Args: cobra.NoArgs,
Run: createUserCmdF,
}
cmd.Flags().StringP("username", "u", "", "the username of the new user")
cmd.MarkFlagRequired("username")
cmd.Flags().StringP("password", "p", "", "the password of the new user")
cmd.MarkFlagRequired("password")
cmd.Flags().StringP("name", "n", "", "the name of the new user")
cmd.MarkFlagRequired("name")
cmd.Flags().StringP("mail", "m", "", "the mail of the new user")
cmd.MarkFlagRequired("mail")
return cmd
}
func ListUserCmd() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List the users in the system",
Args: cobra.NoArgs,
Run: listUserCmdF,
}
}
func DeleteUserCmd() *cobra.Command {
return &cobra.Command{
Use: "delete <username>",
Short: "Delete a user by username",
Args: cobra.ExactArgs(1),
Run: deleteUserCmdF,
}
}
func createUserCmdF(cmd *cobra.Command, _ []string) {
username, _ := cmd.Flags().GetString("username")
password, _ := cmd.Flags().GetString("password")
name, _ := cmd.Flags().GetString("name")
mail, _ := cmd.Flags().GetString("mail")
config, _ := cmd.Flags().GetString("config")
srv, err := server.NewServerWithConfigPath(config)
if err != nil {
log.Error().Err(err).Msg("cannot create server")
os.Exit(1)
}
defer srv.Store.Close()
user, err := srv.App.CreateUser(username, password, name, mail)
if err != nil {
log.Error().Err(err).Msg("user couldn't be created")
os.Exit(1)
}
log.Info().Str("username", user.Username).Msg("user successfully created")
}
func listUserCmdF(cmd *cobra.Command, _ []string) {
config, _ := cmd.Flags().GetString("config")
srv, err := server.NewServerWithConfigPath(config)
if err != nil {
log.Error().Err(err).Msg("cannot create server")
os.Exit(1)
}
defer srv.Store.Close()
users, err := srv.App.ListUsers()
if err != nil {
log.Error().Err(err).Msg("cannot get user list")
os.Exit(1)
}
for _, user := range users {
log.Info().Str("username", user.Username).Msg("")
}
}
func deleteUserCmdF(cmd *cobra.Command, args []string) {
config, _ := cmd.Flags().GetString("config")
srv, err := server.NewServerWithConfigPath(config)
if err != nil {
log.Error().Err(err).Msg("cannot create server")
os.Exit(1)
}
defer srv.Store.Close()
if err := srv.App.DeleteUserByUsername(args[0]); err != nil {
log.Error().Err(err).Str("username", args[0]).Msg("cannot delete user")
os.Exit(1)
}
log.Info().Str("username", args[0]).Msg("user successfully deleted")
}

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"git.ctrlz.es/mgdelacroix/craban/api" "git.ctrlz.es/mgdelacroix/craban/api"
"git.ctrlz.es/mgdelacroix/craban/app"
"git.ctrlz.es/mgdelacroix/craban/model" "git.ctrlz.es/mgdelacroix/craban/model"
"git.ctrlz.es/mgdelacroix/craban/services/store" "git.ctrlz.es/mgdelacroix/craban/services/store"
"git.ctrlz.es/mgdelacroix/craban/web" "git.ctrlz.es/mgdelacroix/craban/web"
@ -22,6 +23,8 @@ func init() {
type Server struct { type Server struct {
Config *model.Config Config *model.Config
App *app.App
API *api.API
Store *store.Store Store *store.Store
WebServer *web.WebServer WebServer *web.WebServer
} }
@ -43,17 +46,18 @@ func NewServer(config *model.Config) (*Server, error) {
} }
log.Debug().Msg("store created") log.Debug().Msg("store created")
webAPI, err := api.NewAPI(store) app := app.NewApp(config, store)
if err != nil { log.Debug().Msg("app created")
return nil, fmt.Errorf("cannot create API: %w", err) api := api.NewAPI(app)
}
log.Debug().Msg("API created") log.Debug().Msg("API created")
webserver.RegisterRoutes(webAPI) webserver.RegisterRoutes(api)
log.Debug().Msg("webserver routes registered with the API") log.Debug().Msg("webserver routes registered with the API")
return &Server{ return &Server{
Config: config, Config: config,
WebServer: webserver, WebServer: webserver,
App: app,
API: api,
Store: store, Store: store,
}, err }, err
} }

View file

@ -85,3 +85,32 @@ func (us *UserStore) Create(user *model.User) (*model.User, error) {
return us.GetByID(int(id)) return us.GetByID(int(id))
} }
// ToDo: add pagination and filtering
func (us *UserStore) List() ([]*model.User, error) {
rows, err := us.Q().Select(userColumns...).
From("users").
Query()
if err != nil {
return nil, err
}
defer rows.Close()
users, err := us.usersFromRows(rows)
if err != nil {
return nil, err
}
if len(users) == 0 {
return nil, sql.ErrNoRows
}
return users, nil
}
func (us *UserStore) DeleteByUsername(username string) error {
_, err := us.Q().Delete("users").
Where(sq.Eq{"username": username}).
Exec()
return err
}