diff --git a/pages/settings/org/members/[org_id].tsx b/pages/settings/org/members/[org_id].tsx
index 3fbc23f3..06086a91 100644
--- a/pages/settings/org/members/[org_id].tsx
+++ b/pages/settings/org/members/[org_id].tsx
@@ -48,11 +48,23 @@ const UserProfilePage = () => {
setSecret(res.data)
}
+ const onDelete = async (member) => {
+ await requestApi.delete(`/org/member/${org.id}/${member.id}`)
+ toast({
+ description: "删除用户成功",
+ status: "success",
+ duration: 2000,
+ isClosable: true,
+ })
+ getMembers()
+ }
+
const onEdit = (member) => {
setCurrentMember(member)
onOpen()
}
+
const onChangeRole = e => {
const member = cloneDeep(currentMember)
member.role = e.currentTarget.value;
@@ -91,7 +103,7 @@ const UserProfilePage = () => {
{users &&
{
- users.map(u => )
+ users.map(u => )
}
}
diff --git a/pages/settings/orgs.tsx b/pages/settings/orgs.tsx
index 0d815928..daad3901 100644
--- a/pages/settings/orgs.tsx
+++ b/pages/settings/orgs.tsx
@@ -14,15 +14,16 @@ import userCustomTheme from "theme/user-custom"
import { useRouter } from "next/router"
import Link from "next/link"
import { ReserveUrls } from "src/data/reserve-urls"
+import { Role } from "src/types/role"
const UserOrgsPage = () => {
- const [orgs, setOrgs]:[Org[],any] = useState([])
+ const [orgs, setOrgs]: [Org[], any] = useState([])
const { isOpen, onOpen, onClose } = useDisclosure()
- const { isOpen:isOpen1, onOpen:onOpen1, onClose:onClose1 } = useDisclosure()
+ const { isOpen: isOpen1, onOpen: onOpen1, onClose: onClose1 } = useDisclosure()
const router = useRouter()
const stackBorderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
- const [secret,setSecret] = useState('')
+ const [secret, setSecret] = useState('')
useEffect(() => {
getOrgs()
@@ -34,7 +35,7 @@ const UserOrgsPage = () => {
}
- const createOrg = async (values:Org) => {
+ const createOrg = async (values: Org) => {
await requestApi.post(`/org/create`, values)
onClose()
router.push(`/${values.username}`)
@@ -44,15 +45,21 @@ const UserOrgsPage = () => {
onOpen()
}
- const onJoinOrg = () => {
- onOpen1()
- }
+ const onJoinOrg = () => {
+ onOpen1()
+ }
+
+ const joinOrg = async () => {
+ await requestApi.post(`/org/join`, { secret: secret })
+ onClose1()
+ getOrgs()
+ }
+
+ const leaveOrg = async orgID => {
+ await requestApi.post(`/org/leave/${orgID}`)
+ getOrgs()
+ }
- const joinOrg = async () => {
- await requestApi.post(`/org/join`,{secret: secret})
- onClose1()
- getOrgs()
- }
return (
<>
@@ -62,25 +69,28 @@ const UserOrgsPage = () => {
组织列表
-
+
} alignItems="left">
- {
- orgs.map(o =>
-
-
-
- {o.nickname}
- {isAdmin(o.role) ? 'admin' : 'member'}
+ {
+ orgs.map(o =>
+
+
+
+ {o.nickname}
+ {isAdmin(o.role) ? 'admin' : 'member'}
+
+
+
+
+ {isAdmin(o.role) && }
+ {o.role !== Role.SUPER_ADMIN && }
-
-
- {isAdmin(o.role) && }
- )
- }
+ )
+ }
@@ -92,8 +102,8 @@ const UserOrgsPage = () => {
{
新建组织
-
{(props) => (
@@ -140,10 +150,10 @@ const UserOrgsPage = () => {
{
- Secret code
- Provided to you by an org admin
- setSecret(e.currentTarget.value)}/>
-
+ Secret code
+ Provided to you by an org admin
+ setSecret(e.currentTarget.value)} />
+
}
diff --git a/server/internal/api/org.go b/server/internal/api/org.go
index 0eb7a4e7..23c5a12f 100644
--- a/server/internal/api/org.go
+++ b/server/internal/api/org.go
@@ -246,3 +246,80 @@ func TransferOrg(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(nil))
}
+
+func DeleteOrgMember(c *gin.Context) {
+ orgID := c.Param("orgID")
+ memberID := c.Param("memberID")
+
+ // 获取待删除用户的组织角色
+ targetRole, err := org.GetMemberRole(orgID, memberID)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, common.RespError(e.BadRequest))
+ return
+ }
+
+ // 获取当前用户的组织角色
+ u := user.CurrentUser(c)
+ currentRole, err := org.GetMemberRole(orgID, u.ID)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, common.RespError(e.BadRequest))
+ return
+ }
+
+ // 超级管理员不能被删除
+ if targetRole == models.ROLE_SUPER_ADMIN {
+ c.JSON(http.StatusForbidden, common.RespError("无法删除超级管理员"))
+ return
+ }
+ // 不能删除自己
+ if u.ID == memberID {
+ c.JSON(http.StatusForbidden, common.RespError("无法删除自己"))
+ return
+ }
+
+ // 若目标用户角色是管理员,则当前用户角色需要是超级管理员
+ if targetRole == models.ROLE_ADMIN {
+ if currentRole != models.ROLE_SUPER_ADMIN {
+ c.JSON(http.StatusForbidden, common.RespError("只有超级管理员才能删除管理员"))
+ return
+ }
+ } else {
+ if !currentRole.IsAdmin() {
+ c.JSON(http.StatusForbidden, common.RespError("只有管理员才能删除组织成员"))
+ return
+ }
+ }
+
+ err0 := org.Delete(orgID, memberID)
+ if err0 != nil {
+ c.JSON(err0.Status, common.RespError(err0.Message))
+ return
+ }
+
+ c.JSON(http.StatusOK, common.RespSuccess(nil))
+}
+
+func LeaveOrg(c *gin.Context) {
+ orgID := c.Param("orgID")
+
+ // 获取当前用户的组织角色
+ u := user.CurrentUser(c)
+ currentRole, err := org.GetMemberRole(orgID, u.ID)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, common.RespError(e.BadRequest))
+ return
+ }
+
+ if currentRole == models.ROLE_SUPER_ADMIN {
+ c.JSON(http.StatusForbidden, common.RespError("超级管理员必须先转移组织,才能离开"))
+ return
+ }
+
+ err0 := org.Delete(orgID, u.ID)
+ if err0 != nil {
+ c.JSON(err0.Status, common.RespError(err0.Message))
+ return
+ }
+
+ c.JSON(http.StatusOK, common.RespSuccess(nil))
+}
diff --git a/server/internal/cache/cache.go b/server/internal/cache/cache.go
index 63e5b7f6..55e67ff2 100644
--- a/server/internal/cache/cache.go
+++ b/server/internal/cache/cache.go
@@ -13,7 +13,7 @@ import (
var logger = log.RootLogger.New("logger", "cache")
func Init() {
- time.Sleep(2 * time.Second)
+ time.Sleep(1 * time.Second)
for {
// load users
rows, err := db.Conn.Query(`SELECT id,type,username,role,nickname,avatar,last_seen_at,created FROM user`)
diff --git a/server/internal/org/org.go b/server/internal/org/org.go
index 71561ceb..6e4e5935 100644
--- a/server/internal/org/org.go
+++ b/server/internal/org/org.go
@@ -196,3 +196,13 @@ func Transfer(orgID, currentOwner, newOwner string) *e.Error {
return nil
}
+
+func Delete(orgID, memberID string) *e.Error {
+ _, err := db.Conn.Exec("DELETE FROM org_member WHERE org_id=? and user_id=?", orgID, memberID)
+ if err != nil {
+ logger.Warn("delete org member error", "error", err)
+ return e.New(http.StatusInternalServerError, e.Internal)
+ }
+
+ return nil
+}
diff --git a/server/internal/server.go b/server/internal/server.go
index a0e589ab..a3eeee41 100644
--- a/server/internal/server.go
+++ b/server/internal/server.go
@@ -112,7 +112,9 @@ func (s *Server) Start() error {
r.GET("/org/secret/:id", IsLogin(), api.GetOrgSecret)
r.POST("/org/join", IsLogin(), api.JoinOrg)
r.POST("/org/member/role", IsLogin(), api.UpdateOrgMember)
- r.POST("/org/transfer", api.TransferOrg)
+ r.POST("/org/transfer", IsLogin(), api.TransferOrg)
+ r.DELETE("/org/member/:orgID/:memberID", IsLogin(), api.DeleteOrgMember)
+ r.POST("/org/leave/:orgID", IsLogin(), api.LeaveOrg)
// admin apis
r.POST("/admin/user", IsLogin(), api.AdminSubmitUser)
r.GET("/admin/user/all", IsLogin(), api.AdminGetUsers)
diff --git a/src/components/users/org-member.tsx b/src/components/users/org-member.tsx
index b6872c25..c104fbb1 100644
--- a/src/components/users/org-member.tsx
+++ b/src/components/users/org-member.tsx
@@ -13,9 +13,10 @@ type Props = PropsOf & {
user : User
highlight?: string
onEdit: any
+ onDelete: any
}
-export const OrgMember= ({user,highlight,onEdit}:Props) =>{
+export const OrgMember= ({user,highlight,onEdit,onDelete}:Props) =>{
const router = useRouter()
return (
@@ -43,7 +44,8 @@ export const OrgMember= ({user,highlight,onEdit}:Props) =>{
followers
-
+
+