2020-08-13 17:34:02 +02:00
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package cmd
import (
2020-10-11 22:10:03 +02:00
"fmt"
"os"
"strconv"
"strings"
"time"
2020-08-13 17:34:02 +02:00
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)
var (
userFlagUsername string
userFlagEmail string
userFlagPassword string
userFlagAvatar = "default"
userFlagResetPasswordDirectly bool
userFlagEnableUser bool
userFlagDisableUser bool
)
func init ( ) {
// User create flags
userCreateCmd . Flags ( ) . StringVarP ( & userFlagUsername , "username" , "u" , "" , "The username of the new user." )
_ = userCreateCmd . MarkFlagRequired ( "username" )
userCreateCmd . Flags ( ) . StringVarP ( & userFlagEmail , "email" , "e" , "" , "The email address of the new user." )
_ = userCreateCmd . MarkFlagRequired ( "email" )
userCreateCmd . Flags ( ) . StringVarP ( & userFlagPassword , "password" , "p" , "" , "The password of the new user. You will be asked to enter it if not provided through the flag." )
userCreateCmd . Flags ( ) . StringVarP ( & userFlagAvatar , "avatar-provider" , "a" , "" , "The avatar provider of the new user. Optional." )
// User update flags
userUpdateCmd . Flags ( ) . StringVarP ( & userFlagUsername , "username" , "u" , "" , "The new username of the user." )
userUpdateCmd . Flags ( ) . StringVarP ( & userFlagEmail , "email" , "e" , "" , "The new email address of the user." )
userUpdateCmd . Flags ( ) . StringVarP ( & userFlagAvatar , "avatar-provider" , "a" , "" , "The new avatar provider of the new user." )
// Reset PW flags
userResetPasswordCmd . Flags ( ) . BoolVarP ( & userFlagResetPasswordDirectly , "direct" , "d" , false , "If provided, reset the password directly instead of sending the user a reset mail." )
userResetPasswordCmd . Flags ( ) . StringVarP ( & userFlagPassword , "password" , "p" , "" , "The new password of the user. Only used in combination with --direct. You will be asked to enter it if not provided through the flag." )
// Change status flags
userChangeEnabledCmd . Flags ( ) . BoolVarP ( & userFlagDisableUser , "disable" , "d" , false , "Disable the user." )
userChangeEnabledCmd . Flags ( ) . BoolVarP ( & userFlagEnableUser , "enable" , "e" , false , "Enable the user." )
userCmd . AddCommand ( userListCmd , userCreateCmd , userUpdateCmd , userResetPasswordCmd , userChangeEnabledCmd )
rootCmd . AddCommand ( userCmd )
}
func getPasswordFromFlagOrInput ( ) ( pw string ) {
pw = userFlagPassword
if userFlagPassword == "" {
fmt . Print ( "Enter Password: " )
2020-08-13 17:59:10 +02:00
bytePW , err := terminal . ReadPassword ( int ( os . Stdin . Fd ( ) ) )
2020-08-13 17:34:02 +02:00
if err != nil {
log . Fatalf ( "Error reading password: %s" , err )
}
fmt . Printf ( "\nConfirm Password: " )
2020-08-13 17:59:10 +02:00
byteConfirmPW , err := terminal . ReadPassword ( int ( os . Stdin . Fd ( ) ) )
2020-08-13 17:34:02 +02:00
if err != nil {
log . Fatalf ( "Error reading password: %s" , err )
}
if string ( bytePW ) != string ( byteConfirmPW ) {
log . Critical ( "Passwords don't match!" )
}
fmt . Printf ( "\n" )
pw = strings . TrimSpace ( string ( bytePW ) )
}
return
}
func getUserFromArg ( arg string ) * user . User {
id , err := strconv . ParseInt ( arg , 10 , 64 )
if err != nil {
log . Fatalf ( "Invalid user id: %s" , err )
}
u , err := user . GetUserByID ( id )
if err != nil {
log . Fatalf ( "Could not get user: %s" , err )
}
return u
}
var userCmd = & cobra . Command {
Use : "user" ,
Short : "Manage users locally through the cli." ,
}
var userListCmd = & cobra . Command {
Use : "list" ,
Short : "Shows a list of all users." ,
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
initialize . FullInit ( )
} ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
users , err := user . ListUsers ( "" )
if err != nil {
log . Fatalf ( "Error getting users: %s" , err )
}
table := tablewriter . NewWriter ( os . Stdout )
table . SetHeader ( [ ] string {
"ID" ,
"Username" ,
"Email" ,
"Active" ,
"Created" ,
"Updated" ,
} )
for _ , u := range users {
table . Append ( [ ] string {
strconv . FormatInt ( u . ID , 10 ) ,
u . Username ,
u . Email ,
strconv . FormatBool ( u . IsActive ) ,
u . Created . Format ( time . RFC3339 ) ,
u . Updated . Format ( time . RFC3339 ) ,
} )
}
table . Render ( )
} ,
}
var userCreateCmd = & cobra . Command {
Use : "create" ,
Short : "Create a new user." ,
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
initialize . FullInit ( )
} ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
u := & user . User {
Username : userFlagUsername ,
Email : userFlagEmail ,
Password : getPasswordFromFlagOrInput ( ) ,
}
_ , err := user . CreateUser ( u )
if err != nil {
log . Fatalf ( "Error creating new user: %s" , err )
}
fmt . Printf ( "\nUser was created successfully.\n" )
} ,
}
var userUpdateCmd = & cobra . Command {
Use : "update [user id]" ,
Short : "Update an existing user." ,
Args : cobra . ExactArgs ( 1 ) ,
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
initialize . FullInit ( )
} ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
u := getUserFromArg ( args [ 0 ] )
if userFlagUsername != "" {
u . Username = userFlagUsername
}
if userFlagEmail != "" {
u . Email = userFlagEmail
}
if userFlagAvatar != "default" {
u . AvatarProvider = userFlagAvatar
}
_ , err := user . UpdateUser ( u )
if err != nil {
log . Fatalf ( "Error updating the user: %s" , err )
}
fmt . Println ( "User updated successfully." )
} ,
}
var userResetPasswordCmd = & cobra . Command {
Use : "reset-password [user id]" ,
Short : "Reset a users password, either through mailing them a reset link or directly." ,
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
initialize . FullInit ( )
} ,
Args : cobra . ExactArgs ( 1 ) ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
u := getUserFromArg ( args [ 0 ] )
// By default we reset as usual, only with specific flag directly.
if userFlagResetPasswordDirectly {
err := user . UpdateUserPassword ( u , getPasswordFromFlagOrInput ( ) )
if err != nil {
log . Fatalf ( "Could not update user password: %s" , err )
}
fmt . Println ( "Password updated successfully." )
} else {
err := user . RequestUserPasswordResetToken ( u )
if err != nil {
log . Fatalf ( "Could not send password reset email: %s" , err )
}
fmt . Println ( "Password reset email sent successfully." )
}
} ,
}
var userChangeEnabledCmd = & cobra . Command {
Use : "change-status [user id]" ,
Short : "Enable or disable a user. Will toggle the current status if no flag (--enable or --disable) is provided." ,
PreRun : func ( cmd * cobra . Command , args [ ] string ) {
initialize . FullInit ( )
} ,
Args : cobra . ExactArgs ( 1 ) ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
u := getUserFromArg ( args [ 0 ] )
if userFlagEnableUser {
u . IsActive = true
} else if userFlagDisableUser {
u . IsActive = false
} else {
u . IsActive = ! u . IsActive
}
_ , err := user . UpdateUser ( u )
if err != nil {
log . Fatalf ( "Could not enable the user" )
}
fmt . Printf ( "User status successfully changed, user is now active: %t.\n" , u . IsActive )
} ,
}