pull/52/head
sunface 4 years ago
parent fc935a6ac7
commit aa205c0086

@ -48,11 +48,23 @@ const UserProfilePage = () => {
setSecret(res.data) 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) => { const onEdit = (member) => {
setCurrentMember(member) setCurrentMember(member)
onOpen() onOpen()
} }
const onChangeRole = e => { const onChangeRole = e => {
const member = cloneDeep(currentMember) const member = cloneDeep(currentMember)
member.role = e.currentTarget.value; member.role = e.currentTarget.value;
@ -91,7 +103,7 @@ const UserProfilePage = () => {
{users && {users &&
<VStack alignItems="left" width="100%"> <VStack alignItems="left" width="100%">
{ {
users.map(u => <OrgMember user={u} key={u.id} onEdit={onEdit}/>) users.map(u => <OrgMember user={u} key={u.id} onEdit={onEdit} onDelete={onDelete}/>)
} }
</VStack>} </VStack>}
</Card> </Card>

@ -14,6 +14,7 @@ import userCustomTheme from "theme/user-custom"
import { useRouter } from "next/router" import { useRouter } from "next/router"
import Link from "next/link" import Link from "next/link"
import { ReserveUrls } from "src/data/reserve-urls" import { ReserveUrls } from "src/data/reserve-urls"
import { Role } from "src/types/role"
const UserOrgsPage = () => { const UserOrgsPage = () => {
@ -53,6 +54,12 @@ const UserOrgsPage = () => {
onClose1() onClose1()
getOrgs() getOrgs()
} }
const leaveOrg = async orgID => {
await requestApi.post(`/org/leave/${orgID}`)
getOrgs()
}
return ( return (
<> <>
<PageContainer> <PageContainer>
@ -78,7 +85,10 @@ const UserOrgsPage = () => {
</HStack> </HStack>
</Link> </Link>
<HStack>
{isAdmin(o.role) && <Button variant="outline" size="md" onClick={() => router.push(`${ReserveUrls.Settings}/org/profile/${o.id}`)}>Manage</Button>} {isAdmin(o.role) && <Button variant="outline" size="md" onClick={() => router.push(`${ReserveUrls.Settings}/org/profile/${o.id}`)}>Manage</Button>}
{o.role !== Role.SUPER_ADMIN && <Button colorScheme="red" variant="outline" size="md" onClick={() => leaveOrg(o.id)}>Leave</Button>}
</HStack>
</Flex>) </Flex>)
} }
</VStack> </VStack>

@ -246,3 +246,80 @@ func TransferOrg(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(nil)) 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))
}

@ -13,7 +13,7 @@ import (
var logger = log.RootLogger.New("logger", "cache") var logger = log.RootLogger.New("logger", "cache")
func Init() { func Init() {
time.Sleep(2 * time.Second) time.Sleep(1 * time.Second)
for { for {
// load users // load users
rows, err := db.Conn.Query(`SELECT id,type,username,role,nickname,avatar,last_seen_at,created FROM user`) rows, err := db.Conn.Query(`SELECT id,type,username,role,nickname,avatar,last_seen_at,created FROM user`)

@ -196,3 +196,13 @@ func Transfer(orgID, currentOwner, newOwner string) *e.Error {
return nil 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
}

@ -112,7 +112,9 @@ func (s *Server) Start() error {
r.GET("/org/secret/:id", IsLogin(), api.GetOrgSecret) r.GET("/org/secret/:id", IsLogin(), api.GetOrgSecret)
r.POST("/org/join", IsLogin(), api.JoinOrg) r.POST("/org/join", IsLogin(), api.JoinOrg)
r.POST("/org/member/role", IsLogin(), api.UpdateOrgMember) 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 // admin apis
r.POST("/admin/user", IsLogin(), api.AdminSubmitUser) r.POST("/admin/user", IsLogin(), api.AdminSubmitUser)
r.GET("/admin/user/all", IsLogin(), api.AdminGetUsers) r.GET("/admin/user/all", IsLogin(), api.AdminGetUsers)

@ -13,9 +13,10 @@ type Props = PropsOf<typeof chakra.div> & {
user : User user : User
highlight?: string highlight?: string
onEdit: any onEdit: any
onDelete: any
} }
export const OrgMember= ({user,highlight,onEdit}:Props) =>{ export const OrgMember= ({user,highlight,onEdit,onDelete}:Props) =>{
const router = useRouter() const router = useRouter()
return ( return (
<Flex alignItems="center" justifyContent="space-between"> <Flex alignItems="center" justifyContent="space-between">
@ -43,7 +44,8 @@ export const OrgMember= ({user,highlight,onEdit}:Props) =>{
</HStack> </HStack>
<HStack> <HStack>
<Text fontWeight="600" fontSize=".95rem"><Count count={user.follows??0}/> followers</Text> <Text fontWeight="600" fontSize=".95rem"><Count count={user.follows??0}/> followers</Text>
<Button variant="outline" size="sm" onClick={() => onEdit(user)} _focus={null}>Edit</Button> <Button variant="ghost" size="sm" onClick={() => onEdit(user)} _focus={null}>Edit</Button>
<Button variant="outline" colorScheme="red" size="sm" onClick={() => onDelete(user)} _focus={null}>Delete</Button>
</HStack> </HStack>
</Flex> </Flex>

Loading…
Cancel
Save