mirror of
https://github.com/1Panel-dev/KubePi.git
synced 2025-10-06 15:57:03 +08:00
403 lines
12 KiB
Go
403 lines
12 KiB
Go
package user
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/KubeOperator/kubepi/internal/api/v1/commons"
|
|
"github.com/KubeOperator/kubepi/internal/api/v1/session"
|
|
v1 "github.com/KubeOperator/kubepi/internal/model/v1"
|
|
v1Role "github.com/KubeOperator/kubepi/internal/model/v1/role"
|
|
v1User "github.com/KubeOperator/kubepi/internal/model/v1/user"
|
|
"github.com/KubeOperator/kubepi/internal/server"
|
|
"github.com/KubeOperator/kubepi/internal/service/v1/clusterbinding"
|
|
"github.com/KubeOperator/kubepi/internal/service/v1/common"
|
|
"github.com/KubeOperator/kubepi/internal/service/v1/rolebinding"
|
|
"github.com/KubeOperator/kubepi/internal/service/v1/user"
|
|
pkgV1 "github.com/KubeOperator/kubepi/pkg/api/v1"
|
|
"github.com/KubeOperator/kubepi/pkg/collectons"
|
|
"github.com/asdine/storm/v3"
|
|
"github.com/kataras/iris/v12"
|
|
"github.com/kataras/iris/v12/context"
|
|
)
|
|
|
|
type Handler struct {
|
|
userService user.Service
|
|
roleBindingService rolebinding.Service
|
|
clusterBindingService clusterbinding.Service
|
|
}
|
|
|
|
func NewHandler() *Handler {
|
|
return &Handler{
|
|
userService: user.NewService(),
|
|
roleBindingService: rolebinding.NewService(),
|
|
clusterBindingService: clusterbinding.NewService(),
|
|
}
|
|
}
|
|
|
|
// List User
|
|
// @Tags users
|
|
// @Summary Search users
|
|
// @Description Search users by Condition
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} api.Page
|
|
// @Security ApiKeyAuth
|
|
// @Router /users/search [post]
|
|
func (h *Handler) SearchUsers() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
pageNum, _ := ctx.Values().GetInt(pkgV1.PageNum)
|
|
pageSize, _ := ctx.Values().GetInt(pkgV1.PageSize)
|
|
|
|
//pattern := ctx.URLParam("pattern")
|
|
var conditions commons.SearchConditions
|
|
if err := ctx.ReadJSON(&conditions); err != nil {
|
|
ctx.StatusCode(iris.StatusBadRequest)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
users, total, err := h.userService.Search(pageNum, pageSize, conditions.Conditions, common.DBOptions{})
|
|
if err != nil {
|
|
if !errors.Is(err, storm.ErrNotFound) {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
}
|
|
us := make([]User, 0)
|
|
for i := range users {
|
|
bindings, err := h.roleBindingService.GetRoleBindingBySubject(v1Role.Subject{Kind: "User", Name: users[i].Name}, common.DBOptions{})
|
|
if err != nil && !errors.As(err, &storm.ErrNotFound) {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
roles := collectons.NewStringSet()
|
|
for i := range bindings {
|
|
roles.Add(bindings[i].RoleRef)
|
|
}
|
|
us = append(us, User{
|
|
User: users[i],
|
|
Roles: roles.ToSlice(),
|
|
})
|
|
}
|
|
ctx.Values().Set("data", pkgV1.Page{Items: us, Total: total})
|
|
}
|
|
}
|
|
|
|
// Create User
|
|
// @Tags users
|
|
// @Summary Create user
|
|
// @Description Create user
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body docs.UserCreate true "request"
|
|
// @Success 200 {object} v1User.User
|
|
// @Security ApiKeyAuth
|
|
// @Router /users [post]
|
|
func (h *Handler) CreateUser() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
var req User
|
|
if err := ctx.ReadJSON(&req); err != nil {
|
|
ctx.StatusCode(iris.StatusBadRequest)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
u := ctx.Values().Get("profile")
|
|
profile := u.(session.UserProfile)
|
|
//tx
|
|
tx, err := server.DB().Begin(true)
|
|
if err != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
req.CreatedBy = profile.Name
|
|
if req.Language == "" {
|
|
req.Language = profile.Language
|
|
}
|
|
req.Type = v1User.LOCAL
|
|
if err := h.userService.Create(&req.User, common.DBOptions{DB: tx}); err != nil {
|
|
_ = tx.Rollback()
|
|
if errors.Is(err, storm.ErrAlreadyExists) {
|
|
u, _ := h.userService.GetByNameOrEmail(req.User.Name, common.DBOptions{})
|
|
if u != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", "username already exists")
|
|
return
|
|
}
|
|
u, _ = h.userService.GetByNameOrEmail(req.User.Email, common.DBOptions{})
|
|
if u != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", "email already exists")
|
|
return
|
|
}
|
|
}
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
if len(req.Roles) > 0 {
|
|
for i := range req.Roles {
|
|
roleName := req.Roles[i]
|
|
binding := v1Role.Binding{
|
|
BaseModel: v1.BaseModel{
|
|
Kind: "RoleBind",
|
|
ApiVersion: "v1",
|
|
CreatedBy: profile.Name,
|
|
},
|
|
Metadata: v1.Metadata{
|
|
Name: fmt.Sprintf("role-binding-%s-%s", roleName, req.Name),
|
|
},
|
|
Subject: v1Role.Subject{
|
|
Kind: "User",
|
|
Name: req.Name,
|
|
},
|
|
RoleRef: roleName,
|
|
}
|
|
if err := h.roleBindingService.CreateRoleBinding(&binding, common.DBOptions{DB: tx}); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
}
|
|
}
|
|
_ = tx.Commit()
|
|
ctx.Values().Set("data", req)
|
|
}
|
|
}
|
|
|
|
// Delete User
|
|
// @Tags users
|
|
// @Summary Delete user by name
|
|
// @Description Delete user by name
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param name path string true "用户名称"
|
|
// @Success 200 {object} v1User.User
|
|
// @Security ApiKeyAuth
|
|
// @Router /users/{name} [delete]
|
|
func (h *Handler) DeleteUser() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
userName := ctx.Params().GetString("name")
|
|
|
|
u := ctx.Values().Get("profile")
|
|
profile := u.(session.UserProfile)
|
|
|
|
if userName == profile.Name {
|
|
ctx.StatusCode(iris.StatusBadRequest)
|
|
ctx.Values().Set("message", fmt.Errorf("can not delete yourself"))
|
|
return
|
|
}
|
|
tx, _ := server.DB().Begin(true)
|
|
txOptions := common.DBOptions{DB: tx}
|
|
|
|
rbs, err := h.roleBindingService.GetRoleBindingBySubject(v1Role.Subject{
|
|
Kind: "User",
|
|
Name: userName,
|
|
}, txOptions)
|
|
if err != nil && !errors.As(err, &storm.ErrNotFound) {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
for i := range rbs {
|
|
if err := h.roleBindingService.Delete(rbs[i].Name, txOptions); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
}
|
|
cbs, err := h.clusterBindingService.GetBindingsByUserName(userName, txOptions)
|
|
if err != nil && !errors.As(err, &storm.ErrNotFound) {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
|
|
for i := range cbs {
|
|
if err := h.clusterBindingService.Delete(cbs[i].Name, txOptions); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
}
|
|
if err := h.userService.Delete(userName, txOptions); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
_ = tx.Commit()
|
|
}
|
|
}
|
|
|
|
// Get User
|
|
// @Tags users
|
|
// @Summary Get user by name
|
|
// @Description Get user by name
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param name path string true "用户名称"
|
|
// @Success 200 {object} v1User.User
|
|
// @Security ApiKeyAuth
|
|
// @Router /users/{name} [get]
|
|
func (h *Handler) GetUser() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
userName := ctx.Params().GetString("name")
|
|
u, err := h.userService.GetByNameOrEmail(userName, common.DBOptions{})
|
|
if err != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
bindings, err := h.roleBindingService.GetRoleBindingBySubject(v1Role.Subject{Kind: "User", Name: u.Name}, common.DBOptions{})
|
|
if err != nil && !errors.As(err, &storm.ErrNotFound) {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
roles := collectons.NewStringSet()
|
|
for i := range bindings {
|
|
roles.Add(bindings[i].RoleRef)
|
|
}
|
|
ctx.Values().Set("data", &User{User: *u, Roles: roles.ToSlice()})
|
|
}
|
|
}
|
|
|
|
// List User
|
|
// @Tags users
|
|
// @Summary List all users
|
|
// @Description List all users
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} []v1User.User
|
|
// @Security ApiKeyAuth
|
|
// @Router /users [get]
|
|
func (h *Handler) GetUsers() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
us, err := h.userService.List(common.DBOptions{})
|
|
if err != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
ctx.Values().Set("data", us)
|
|
}
|
|
}
|
|
|
|
// Update User
|
|
// @Tags users
|
|
// @Summary Update user by name
|
|
// @Description Update user by name
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param name path string true "用户名称"
|
|
// @Success 200 {object} v1User.User
|
|
// @Security ApiKeyAuth
|
|
// @Router /users/{name} [put]
|
|
func (h *Handler) UpdateUser() iris.Handler {
|
|
return func(ctx *context.Context) {
|
|
userName := ctx.Params().GetString("name")
|
|
var req User
|
|
if err := ctx.ReadJSON(&req); err != nil {
|
|
ctx.StatusCode(iris.StatusBadRequest)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
if req.Password != "" {
|
|
if err := h.userService.ResetPassword(userName, req.Password, common.DBOptions{}); err != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
ctx.Values().Set("data", "ok")
|
|
return
|
|
}
|
|
u := ctx.Values().Get("profile")
|
|
profile := u.(session.UserProfile)
|
|
tx, err := server.DB().Begin(true)
|
|
if err != nil {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
if err := h.userService.Update(userName, &req.User, common.DBOptions{DB: tx}); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
bindings, err := h.roleBindingService.GetRoleBindingBySubject(v1Role.Subject{Kind: "User", Name: userName}, common.DBOptions{})
|
|
if err != nil && !errors.As(err, &storm.ErrNotFound) {
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
currentRoles := collectons.NewStringSet()
|
|
for i := range bindings {
|
|
currentRoles.Add(bindings[i].RoleRef)
|
|
}
|
|
for i := range req.Roles {
|
|
r := req.Roles[i]
|
|
if currentRoles.Exists(r) {
|
|
continue
|
|
}
|
|
binding := v1Role.Binding{
|
|
BaseModel: v1.BaseModel{
|
|
Kind: "RoleBind",
|
|
ApiVersion: "v1",
|
|
CreatedBy: profile.Name,
|
|
},
|
|
Metadata: v1.Metadata{
|
|
Name: fmt.Sprintf("role-binding-%s-%s", r, req.Name),
|
|
},
|
|
Subject: v1Role.Subject{
|
|
Kind: "User",
|
|
Name: req.Name,
|
|
},
|
|
RoleRef: r,
|
|
}
|
|
if err := h.roleBindingService.CreateRoleBinding(&binding, common.DBOptions{DB: tx}); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
currentRoles.Add(binding.RoleRef)
|
|
}
|
|
diffs := currentRoles.Difference(req.Roles)
|
|
|
|
for i := range bindings {
|
|
for j := range diffs {
|
|
if bindings[i].RoleRef == diffs[j] {
|
|
if err := h.roleBindingService.Delete(bindings[i].Name, common.DBOptions{DB: tx}); err != nil {
|
|
_ = tx.Rollback()
|
|
ctx.StatusCode(iris.StatusInternalServerError)
|
|
ctx.Values().Set("message", err.Error())
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_ = tx.Commit()
|
|
ctx.Values().Set("data", &req)
|
|
}
|
|
}
|
|
|
|
func Install(parent iris.Party) {
|
|
handler := NewHandler()
|
|
sp := parent.Party("/users")
|
|
sp.Post("/search", handler.SearchUsers())
|
|
sp.Post("/", handler.CreateUser())
|
|
sp.Delete("/:name", handler.DeleteUser())
|
|
sp.Get("/:name", handler.GetUser())
|
|
sp.Put("/:name", handler.UpdateUser())
|
|
sp.Get("/", handler.GetUsers())
|
|
}
|