[feature/backend] implement /users handler + switch to username + add display name + user management cli

This commit is contained in:
CDN 2025-02-21 04:30:07 +08:00
parent 1d712d4e6c
commit 86ab334bc9
Signed by: CDN
GPG key ID: 0C656827F9F80080
38 changed files with 1851 additions and 506 deletions

411
backend/cmd/user.go Normal file
View file

@ -0,0 +1,411 @@
package cmd
import (
"fmt"
"os"
"text/tabwriter"
"tss-rocks-be/ent/user"
"tss-rocks-be/ent/role"
"tss-rocks-be/internal/config"
"tss-rocks-be/internal/server"
"github.com/spf13/cobra"
"golang.org/x/crypto/bcrypt"
)
func GetUserCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "user",
Short: "User management commands",
Long: `Commands for managing users, including create, delete, password, and role management.`,
}
configPath := cmd.PersistentFlags().String("config", "config/config.yaml", "Path to config file")
cmd.AddCommand(getCreateUserCmd(*configPath))
cmd.AddCommand(getPasswordCmd(*configPath))
cmd.AddCommand(getListUsersCmd(*configPath))
cmd.AddCommand(getDeleteUserCmd(*configPath))
cmd.AddCommand(getRoleCmd(*configPath))
return cmd
}
func getCreateUserCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new user",
Long: `Create a new user with specified username, email and password.`,
RunE: func(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
email, _ := cmd.Flags().GetString("email")
password, _ := cmd.Flags().GetString("password")
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 检查用户名是否已存在
exists, err := client.User.Query().Where(user.Username(username)).Exist(cmd.Context())
if err != nil {
return fmt.Errorf("error checking username: %v", err)
}
if exists {
return fmt.Errorf("username '%s' already exists", username)
}
// 检查邮箱是否已存在
exists, err = client.User.Query().Where(user.Email(email)).Exist(cmd.Context())
if err != nil {
return fmt.Errorf("error checking email: %v", err)
}
if exists {
return fmt.Errorf("email '%s' already exists", email)
}
// 生成密码哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("error hashing password: %v", err)
}
// 创建用户
u, err := client.User.Create().
SetUsername(username).
SetEmail(email).
SetPasswordHash(string(hashedPassword)).
SetStatus("active").
Save(cmd.Context())
if err != nil {
return fmt.Errorf("error creating user: %v", err)
}
fmt.Printf("Successfully created user '%s' with email '%s'\n", u.Username, u.Email)
return nil
},
}
// 添加命令行参数
cmd.Flags().String("username", "", "username for the new user")
cmd.Flags().String("email", "", "email for the new user")
cmd.Flags().String("password", "", "password for the new user")
// 设置必需的参数
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("email")
cmd.MarkFlagRequired("password")
return cmd
}
func getPasswordCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "password",
Short: "Change user password",
Long: `Change the password for an existing user.`,
RunE: func(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
password, _ := cmd.Flags().GetString("password")
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 查找用户
u, err := client.User.Query().Where(user.Username(username)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("user with username '%s' not found", username)
}
// 生成新的密码哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("error hashing password: %v", err)
}
// 更新密码
_, err = u.Update().SetPasswordHash(string(hashedPassword)).Save(cmd.Context())
if err != nil {
return fmt.Errorf("error updating password: %v", err)
}
fmt.Printf("Successfully updated password for user '%s'\n", username)
return nil
},
}
// 添加命令行参数
cmd.Flags().String("username", "", "username of the user")
cmd.Flags().String("password", "", "new password")
// 设置必需的参数
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
return cmd
}
func getListUsersCmd(configPath string) *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List all users",
Long: `List all users in the system.`,
RunE: func(cmd *cobra.Command, args []string) error {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 获取所有用户
users, err := client.User.Query().All(cmd.Context())
if err != nil {
return fmt.Errorf("error querying users: %v", err)
}
// 创建表格写入器
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "USERNAME\tEMAIL\tSTATUS\tCREATED AT")
// 输出用户信息
for _, u := range users {
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
u.Username,
u.Email,
u.Status,
u.CreatedAt.Format("2006-01-02 15:04:05"))
}
w.Flush()
return nil
},
}
}
func getDeleteUserCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
Short: "Delete a user",
Long: `Delete an existing user from the system.`,
RunE: func(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
force, _ := cmd.Flags().GetBool("force")
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 查找用户
u, err := client.User.Query().Where(user.Username(username)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("user with username '%s' not found", username)
}
// 检查用户的角色
hasRoles, err := client.User.QueryRoles(u).Exist(cmd.Context())
if err != nil {
return fmt.Errorf("error checking user roles: %v", err)
}
if hasRoles && !force {
return fmt.Errorf("user '%s' has roles assigned. Use --force to override", username)
}
// 删除用户
err = client.User.DeleteOne(u).Exec(cmd.Context())
if err != nil {
return fmt.Errorf("error deleting user: %v", err)
}
fmt.Printf("Successfully deleted user '%s'\n", username)
return nil
},
}
// 添加命令行参数
cmd.Flags().String("username", "", "username of the user to delete")
cmd.Flags().Bool("force", false, "force delete even if user has roles")
// 设置必需的参数
cmd.MarkFlagRequired("username")
return cmd
}
func getRoleCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "role",
Short: "User role management commands",
Long: `Commands for managing user roles, including adding and removing roles.`,
}
cmd.AddCommand(getRoleAddCmd(configPath))
cmd.AddCommand(getRoleRemoveCmd(configPath))
return cmd
}
func getRoleAddCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Add a role to a user",
Long: `Add a role to an existing user.`,
RunE: func(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
roleName, _ := cmd.Flags().GetString("role")
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 查找用户
u, err := client.User.Query().Where(user.Username(username)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("user with username '%s' not found", username)
}
// 检查角色是否已存在
hasRole, err := client.User.QueryRoles(u).Where(role.Name(roleName)).Exist(cmd.Context())
if err != nil {
return fmt.Errorf("error checking user roles: %v", err)
}
if hasRole {
return fmt.Errorf("user '%s' already has role '%s'", username, roleName)
}
// 获取要添加的角色
r, err := client.Role.Query().Where(role.Name(roleName)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("role '%s' not found", roleName)
}
// 添加角色
err = client.User.UpdateOne(u).AddRoles(r).Exec(cmd.Context())
if err != nil {
return fmt.Errorf("error adding role: %v", err)
}
fmt.Printf("Successfully added role '%s' to user '%s'\n", roleName, username)
return nil
},
}
// 添加命令行参数
cmd.Flags().String("username", "", "username of the user")
cmd.Flags().String("role", "", "role to add (admin/editor/contributor)")
// 设置必需的参数
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("role")
return cmd
}
func getRoleRemoveCmd(configPath string) *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "Remove a role from a user",
Long: `Remove a role from an existing user.`,
RunE: func(cmd *cobra.Command, args []string) error {
username, _ := cmd.Flags().GetString("username")
roleName, _ := cmd.Flags().GetString("role")
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
return fmt.Errorf("error loading config: %v", err)
}
// 初始化数据库连接
client := server.NewEntClient(cfg)
if client == nil {
return fmt.Errorf("failed to create database client")
}
defer client.Close()
// 查找用户
u, err := client.User.Query().Where(user.Username(username)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("user with username '%s' not found", username)
}
// 检查角色是否存在
r, err := client.Role.Query().Where(role.Name(roleName)).Only(cmd.Context())
if err != nil {
return fmt.Errorf("role '%s' not found", roleName)
}
// 检查用户是否有该角色
hasRole, err := client.User.QueryRoles(u).Where(role.Name(roleName)).Exist(cmd.Context())
if err != nil {
return fmt.Errorf("error checking user roles: %v", err)
}
if !hasRole {
return fmt.Errorf("user '%s' does not have role '%s'", username, roleName)
}
// 移除角色
err = client.User.UpdateOne(u).RemoveRoles(r).Exec(cmd.Context())
if err != nil {
return fmt.Errorf("error removing role: %v", err)
}
fmt.Printf("Successfully removed role '%s' from user '%s'\n", roleName, username)
return nil
},
}
// 添加命令行参数
cmd.Flags().String("username", "", "username of the user")
cmd.Flags().String("role", "", "role to remove (admin/editor/contributor)")
// 设置必需的参数
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("role")
return cmd
}