Skip to content

Commit

Permalink
feat: 增加加入/退出用户组接口,用户管理完成对接用户组操作
Browse files Browse the repository at this point in the history
  • Loading branch information
jorben committed Jul 16, 2024
1 parent 96bf79d commit 647c42a
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 9 deletions.
2 changes: 2 additions & 0 deletions common/errs/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
ErrAuthNoLogin = -10005 // 未登录
ErrAuthUnauthorized = -10006 // 未授权
ErrAuthUnexpired = -10007 // 未过期
ErrAuthGroup = -10008 //权限组操作失败
ErrMenu = -10030 // 获取菜单失败

ErrNoRecord = -10900 // 没有匹配到预期的记录,无数据
Expand All @@ -31,6 +32,7 @@ var errorMsg = map[int]string{
ErrAuthNoLogin: "未登录或登录态已过期",
ErrAuthUnauthorized: "未授权或权限不足",
ErrAuthUnexpired: "刷新登录态失败,当前登录态还有足够长的有效期",
ErrAuthGroup: "用户组操作失败",
ErrMenu: "获取菜单失败,请稍后重试",
ErrNoRecord: "未查询到相关数据",
ErrDbSelect: "查询失败,请稍后重试",
Expand Down
10 changes: 10 additions & 0 deletions dal/casbindal.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,13 @@ func (c *CasbinDal) GetUserGroup(id []string, ptype string) (map[string][]string
}
return group, nil
}

// JoinGroups 为用户加入用户组
func (c *CasbinDal) JoinGroups(id string, groups []string) (bool, error) {
return c.e.AddRolesForUser(id, groups)
}

// ExitGroup 为用户退出用户组
func (c *CasbinDal) ExitGroup(id string, groups string) (bool, error) {
return c.e.DeleteRoleForUser(id, groups)
}
38 changes: 38 additions & 0 deletions router/api/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,44 @@ func UserDelete(ctx *gin.Context) {
c.CJSON(errs.Success)
}

// UserJoinGroup 加入用户组
func UserJoinGroup(ctx *gin.Context) {
c := context.CustomContext{Context: ctx}
param := &struct {
Id uint `json:"id"`
Group string `json:"group"`
}{}
if err := ctx.ShouldBindBodyWithJSON(param); err != nil {
c.CJSON(errs.ErrParam, "用户id或角色值不符合要求")
return
}
userService := service.NewUserService(ctx)
if _, err := userService.JoinGroup(param.Id, param.Group); err != nil {
c.CJSON(errs.ErrAuthGroup, err.Error())
return
}
c.CJSON(errs.Success)
}

// UserExitGroup 退出用户组
func UserExitGroup(ctx *gin.Context) {
c := context.CustomContext{Context: ctx}
param := &struct {
Id uint `json:"id"`
Group string `json:"group"`
}{}
if err := ctx.ShouldBindBodyWithJSON(param); err != nil {
c.CJSON(errs.ErrParam, "用户id或角色值不符合要求")
return
}
userService := service.NewUserService(ctx)
if _, err := userService.ExitGroup(param.Id, param.Group); err != nil {
c.CJSON(errs.ErrAuthGroup, err.Error())
return
}
c.CJSON(errs.Success)
}

// UserList 获取用户列表
func UserList(ctx *gin.Context) {
c := context.CustomContext{Context: ctx}
Expand Down
2 changes: 2 additions & 0 deletions router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func SetupRouter(s *gin.Engine, feEmbed embed.FS) {
backendAdmin.POST("/user/status", api.UserStatus)
backendAdmin.POST("/user/source", api.UserUnbind)
backendAdmin.POST("/user/delete", api.UserDelete)
backendAdmin.POST("/user/join_group", api.UserJoinGroup)
backendAdmin.POST("/user/exit_group", api.UserExitGroup)

s.Use(gzip.Gzip(gzip.DefaultCompression)).StaticFS("/static", getFileSystem(feEmbed, "web/build/static"))
s.NoRoute(func(ctx *gin.Context) {
Expand Down
22 changes: 22 additions & 0 deletions service/userservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ func NewUserService(ctx *gin.Context) *UserService {
}
}

// JoinGroup 加入用户组
func (u *UserService) JoinGroup(id uint, group string) (bool, error) {
strId := strconv.Itoa(int(id))
result, err := u.CasbinDal.JoinGroups(strId, []string{group})
if err != nil {
log.Errorf(u.Ctx, "Casbin join groups failed, id: %d, group: %s, err: %s", id, group, err.Error())
return false, err
}
return result, nil
}

// ExitGroup 退出用户组
func (u *UserService) ExitGroup(id uint, group string) (bool, error) {
strId := strconv.Itoa(int(id))
result, err := u.CasbinDal.ExitGroup(strId, group)
if err != nil {
log.Errorf(u.Ctx, "Casbin exit group failed, id: %d, group: %s, err: %s", id, group, err.Error())
return false, err
}
return result, nil
}

func (u *UserService) DeleteUser(id uint) (bool, error) {
// 解绑所有该用户的登录渠道
if _, err := u.UnbindUserSource(id, ""); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/admin/user/UserDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ const UserDetail = ({ user, setOpenDrawer, setSearchParam, searchParam }) => {
}}
/>
<Divider orientation="left">关联角色</Divider>
<UserDetailGroup group={userDetail?.group} />
<UserDetailGroup userId={userDetail?.ID} group={userDetail?.group} />
<Divider orientation="left">账户状态</Divider>
<Row>
<Col span={12}>
Expand Down
56 changes: 48 additions & 8 deletions web/src/pages/admin/user/UserDetailGroup.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import React, { useEffect, useRef, useState } from "react";
import { PlusOutlined } from "@ant-design/icons";
import { Input, Tag, theme } from "antd";
import { Input, Tag, theme, message } from "antd";
import ApiClient from "../../../services/client";
// import { TweenOneGroup } from "rc-tween-one";
const UserDetailGroup = () => {
const UserDetailGroup = ({ userId, group }) => {
const { token } = theme.useToken();
const [tags, setTags] = useState(["Tag 1", "Tag 2", "Tag 3"]);
const [tags, setTags] = useState([]);
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState("");
const inputRef = useRef(null);
const [messageApi, contextHolder] = message.useMessage();

useEffect(() => {
if (inputVisible) {
inputRef.current?.focus();
}
}, [inputVisible]);

useEffect(() => {
setTags(group ?? []);
}, [group]);
const handleClose = (removedTag) => {
const newTags = tags.filter((tag) => tag !== removedTag);
console.log(newTags);
setTags(newTags);
exitGroup(removedTag);
};
const showInput = () => {
setInputVisible(true);
Expand All @@ -26,7 +31,8 @@ const UserDetailGroup = () => {
};
const handleInputConfirm = () => {
if (inputValue && tags.indexOf(inputValue) === -1) {
setTags([...tags, inputValue]);
// 加入用户组
joinGroup(inputValue);
}
setInputVisible(false);
setInputValue("");
Expand All @@ -50,11 +56,44 @@ const UserDetailGroup = () => {
</Tag>
</span>
);
const tagChild = tags.map(forMap);
const tagChild = tags ? tags.map(forMap) : "";
const tagPlusStyle = {
background: token.colorBgContainer,
borderStyle: "dashed",
};
const joinGroup = async (groupName) => {
const data = { id: userId, group: groupName };
ApiClient.post("/admin/user/join_group", data)
.then((response) => {
if (response.data?.code === 0) {
setTags([...tags, groupName]);
messageApi.success("已加入角色");
} else {
messageApi.error(response.data?.message);
}
})
.catch((error) => {
console.log(error);
messageApi.error("请求失败,请稍后重试!");
});
};
const exitGroup = async (groupName) => {
const data = { id: userId, group: groupName };
ApiClient.post("/admin/user/exit_group", data)
.then((response) => {
if (response.data?.code === 0) {
const newTags = tags.filter((tag) => tag !== groupName);
setTags(newTags);
messageApi.success("已退出角色");
} else {
messageApi.error(response.data?.message);
}
})
.catch((error) => {
console.log(error);
messageApi.error("请求失败,请稍后重试!");
});
};
return (
<>
<div
Expand Down Expand Up @@ -83,6 +122,7 @@ const UserDetailGroup = () => {
<PlusOutlined /> 加入角色
</Tag>
)}
{contextHolder}
</>
);
};
Expand Down

0 comments on commit 647c42a

Please sign in to comment.