改进修改用户接口
This commit is contained in:
parent
81c8cee2c4
commit
63be2bc13f
@ -117,7 +117,7 @@ export async function ListUser(page: number, token: string, email: string, name:
|
|||||||
|
|
||||||
export async function editUser(u: EditUser, token: string, uid: string) {
|
export async function editUser(u: EditUser, token: string, uid: string) {
|
||||||
const r = await fetch(import.meta.env.VITE_APIADDR + "/api/v1/admin/user/" + uid, {
|
const r = await fetch(import.meta.env.VITE_APIADDR + "/api/v1/admin/user/" + uid, {
|
||||||
method: "POST",
|
method: "PATCH",
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": "Bearer " + token
|
"Authorization": "Bearer " + token
|
||||||
},
|
},
|
||||||
|
@ -58,10 +58,10 @@ export interface UserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface EditUser {
|
export interface EditUser {
|
||||||
email: string
|
email?: string
|
||||||
name: string
|
name?: string
|
||||||
password: string
|
password?: string
|
||||||
is_admin: boolean
|
is_admin?: boolean
|
||||||
is_disable: boolean
|
is_disable?: boolean
|
||||||
del_textures: boolean
|
del_textures?: boolean
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import Paper from '@mui/material/Paper';
|
|||||||
import useTitle from '@/hooks/useTitle';
|
import useTitle from '@/hooks/useTitle';
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { ListUser, editUser } from '@/apis/apis';
|
import { ListUser, editUser } from '@/apis/apis';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { token } from '@/store/store';
|
import { token } from '@/store/store';
|
||||||
import TablePagination from '@mui/material/TablePagination';
|
import TablePagination from '@mui/material/TablePagination';
|
||||||
@ -133,25 +133,50 @@ function MyDialog({ open, row, setOpen, onUpdate }: MyDialogProp) {
|
|||||||
const [load, setLoad] = useState(false)
|
const [load, setLoad] = useState(false)
|
||||||
const nowToken = useAtomValue(token)
|
const nowToken = useAtomValue(token)
|
||||||
const [err, setErr] = useState("")
|
const [err, setErr] = useState("")
|
||||||
|
const editValue = useRef<EditUser>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!row) return
|
||||||
setErow({
|
setErow({
|
||||||
email: row?.email ?? "",
|
email: row.email,
|
||||||
name: row?.name ?? "",
|
name: row.name,
|
||||||
password: "",
|
password: "",
|
||||||
is_admin: row?.is_admin ?? false,
|
is_admin: row.is_admin,
|
||||||
is_disable: row?.is_disable ?? false,
|
is_disable: row.is_disable,
|
||||||
del_textures: false,
|
del_textures: false,
|
||||||
})
|
})
|
||||||
}, [row])
|
editValue.current = {}
|
||||||
|
}, [row, open])
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
if (load) return
|
if (load) return
|
||||||
setLoad(true)
|
setLoad(true)
|
||||||
editUser(erow, nowToken, String(row?.uid)).then(() => [setOpen(false), onUpdate()]).finally(() => setLoad(false)).
|
editUser(editValue.current, nowToken, String(row?.uid)).then(() => [setOpen(false), onUpdate(), editValue.current = {}]).finally(() => setLoad(false)).
|
||||||
catch(e => setErr(String(e)))
|
catch(e => setErr(String(e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StringKeys<T> = {
|
||||||
|
[K in keyof T]: T[K] extends string ? K : never;
|
||||||
|
}[keyof T];
|
||||||
|
|
||||||
|
function handleSetValue(key: StringKeys<Required<EditUser>>, value: string) {
|
||||||
|
setErow(produce(v => {
|
||||||
|
v[key] = value
|
||||||
|
editValue.current[key] = value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
type BoolKeys<T> = {
|
||||||
|
[K in keyof T]: T[K] extends boolean ? K : never;
|
||||||
|
}[keyof T];
|
||||||
|
|
||||||
|
function handleSetChecked(key: BoolKeys<Required<EditUser>>, value: boolean) {
|
||||||
|
setErow(produce(v => {
|
||||||
|
v[key] = value
|
||||||
|
editValue.current[key] = value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<Dialog open={open}>
|
<Dialog open={open}>
|
||||||
@ -171,10 +196,7 @@ function MyDialog({ open, row, setOpen, onUpdate }: MyDialogProp) {
|
|||||||
type="email"
|
type="email"
|
||||||
variant="standard"
|
variant="standard"
|
||||||
value={erow?.email}
|
value={erow?.email}
|
||||||
onChange={e => setErow(produce(v => {
|
onChange={e => handleSetValue('email', e.target.value)}
|
||||||
v.email = e.target.value
|
|
||||||
return
|
|
||||||
}))}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
margin="dense"
|
margin="dense"
|
||||||
@ -182,33 +204,22 @@ function MyDialog({ open, row, setOpen, onUpdate }: MyDialogProp) {
|
|||||||
type="text"
|
type="text"
|
||||||
variant="standard"
|
variant="standard"
|
||||||
value={erow?.name}
|
value={erow?.name}
|
||||||
onChange={e => setErow(produce(v => {
|
onChange={e => handleSetValue('name', e.target.value)}
|
||||||
v.name = e.target.value
|
|
||||||
return
|
|
||||||
}))}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
margin="dense"
|
margin="dense"
|
||||||
label="密码"
|
label="密码"
|
||||||
type="text"
|
type="text"
|
||||||
|
placeholder='(未更改)'
|
||||||
variant="standard"
|
variant="standard"
|
||||||
value={erow?.password}
|
value={erow?.password}
|
||||||
onChange={e => setErow(produce(v => {
|
onChange={e => handleSetValue('password', e.target.value)}
|
||||||
v.password = e.target.value
|
|
||||||
return
|
|
||||||
}))}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<FormGroup row sx={{ gridArea: "b" }}>
|
<FormGroup row sx={{ gridArea: "b" }}>
|
||||||
<FormControlLabel control={<Checkbox checked={erow?.is_admin} onChange={e => setErow(produce(v => {
|
<FormControlLabel control={<Checkbox checked={erow?.is_admin} onChange={e => handleSetChecked('is_admin', e.target.checked)} />} label="管理权限" />
|
||||||
v.is_admin = e.target.checked
|
<FormControlLabel control={<Checkbox checked={erow?.is_disable} onChange={e => handleSetChecked('is_disable', e.target.checked)} />} label="禁用" />
|
||||||
}))} />} label="管理权限" />
|
<FormControlLabel control={<Checkbox checked={erow?.del_textures} onChange={e => handleSetChecked('del_textures', e.target.checked)} />} label="清空材质" />
|
||||||
<FormControlLabel control={<Checkbox checked={erow?.is_disable} onChange={e => setErow(produce(v => {
|
|
||||||
v.is_disable = e.target.checked
|
|
||||||
}))} />} label="禁用" />
|
|
||||||
<FormControlLabel control={<Checkbox checked={erow?.del_textures} onChange={e => setErow(produce(v => {
|
|
||||||
v.del_textures = e.target.checked
|
|
||||||
}))} />} label="清空材质" />
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<Box sx={{ gridArea: "c" }}>
|
<Box sx={{ gridArea: "c" }}>
|
||||||
<SkinViewUUID uuid={row?.uuid ?? ""} width={175} height={175} />
|
<SkinViewUUID uuid={row?.uuid ?? ""} width={175} height={175} />
|
||||||
|
@ -93,7 +93,7 @@ function ChangePasswd() {
|
|||||||
required
|
required
|
||||||
error={oldPassErr}
|
error={oldPassErr}
|
||||||
helperText={oldPassErr ? "旧密码错误" : ""}
|
helperText={oldPassErr ? "旧密码错误" : ""}
|
||||||
onChange={p => setPass(produce(v => { v.old = p.target.value; return v }))}
|
onChange={p => setPass(produce(v => { v.old = p.target.value }))}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@ -102,7 +102,7 @@ function ChangePasswd() {
|
|||||||
label="新密码"
|
label="新密码"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
onChange={p => setPass(produce(v => { v.pass1 = p.target.value; return v }))}
|
onChange={p => setPass(produce(v => { v.pass1 = p.target.value }))}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@ -113,7 +113,7 @@ function ChangePasswd() {
|
|||||||
required
|
required
|
||||||
error={err != ""}
|
error={err != ""}
|
||||||
helperText={err}
|
helperText={err}
|
||||||
onChange={p => setPass(produce(v => { v.pass2 = p.target.value; return v }))}
|
onChange={p => setPass(produce(v => { v.pass2 = p.target.value }))}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
<Button sx={{ marginTop: "1em" }} onClick={handelClick} variant='contained'>提交</Button>
|
<Button sx={{ marginTop: "1em" }} onClick={handelClick} variant='contained'>提交</Button>
|
||||||
|
@ -55,6 +55,12 @@ func (y *Yggdrasil) PutTexture() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
t := ctx.Value(tokenKey).(*model.TokenClaims)
|
t := ctx.Value(tokenKey).(*model.TokenClaims)
|
||||||
|
|
||||||
|
if uuid != t.Subject {
|
||||||
|
y.logger.DebugContext(ctx, "uuid 不相同")
|
||||||
|
w.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
model := r.FormValue("model")
|
model := r.FormValue("model")
|
||||||
|
|
||||||
skin, err := func() ([]byte, error) {
|
skin, err := func() ([]byte, error) {
|
||||||
@ -99,14 +105,8 @@ func (y *Yggdrasil) PutTexture() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = y.yggdrasilService.PutTexture(ctx, t, skin, model, uuid, textureType)
|
err = y.yggdrasilService.PutTexture(ctx, t, skin, model, textureType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, yggdrasilS.ErrUUIDNotEq) {
|
|
||||||
y.logger.DebugContext(ctx, err.Error())
|
|
||||||
w.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
y.handleYgError(ctx, w, err)
|
y.handleYgError(ctx, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,7 +139,14 @@ func (y *Yggdrasil) DelTexture() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := ctx.Value(tokenKey).(*model.TokenClaims)
|
t := ctx.Value(tokenKey).(*model.TokenClaims)
|
||||||
err := y.yggdrasilService.DelTexture(ctx, uuid, t, textureType)
|
|
||||||
|
if uuid != t.Subject {
|
||||||
|
y.logger.DebugContext(ctx, "uuid 不相同")
|
||||||
|
w.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := y.yggdrasilService.DelTexture(ctx, t, textureType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, yggdrasilS.ErrUUIDNotEq) {
|
if errors.Is(err, yggdrasilS.ErrUUIDNotEq) {
|
||||||
y.logger.DebugContext(ctx, err.Error())
|
y.logger.DebugContext(ctx, err.Error())
|
||||||
|
@ -64,11 +64,11 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EditUser struct {
|
type EditUser struct {
|
||||||
Email string `json:"email" validate:"required,email"`
|
Email string `json:"email" validate:"omitempty,email"`
|
||||||
Name string `json:"name" validate:"required,min=3,max=16"`
|
Name string `json:"name" validate:"omitempty,min=3,max=16"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
IsAdmin bool `json:"is_admin"`
|
IsAdmin *bool `json:"is_admin"`
|
||||||
IsDisable bool `json:"is_disable"`
|
IsDisable *bool `json:"is_disable"`
|
||||||
DelTextures bool `json:"del_textures"`
|
DelTextures bool `json:"del_textures"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ func newSkinApi(handel *handle.Handel) http.Handler {
|
|||||||
r.Use(handel.NeedAuth)
|
r.Use(handel.NeedAuth)
|
||||||
r.Use(handel.NeedAdmin)
|
r.Use(handel.NeedAdmin)
|
||||||
r.Get("/admin/users", handel.ListUser())
|
r.Get("/admin/users", handel.ListUser())
|
||||||
r.Post("/admin/user/{uid}", handel.EditUser())
|
r.Patch("/admin/user/{uid}", handel.EditUser())
|
||||||
})
|
})
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/xmdhs/authlib-skin/db/ent/predicate"
|
"github.com/xmdhs/authlib-skin/db/ent/predicate"
|
||||||
"github.com/xmdhs/authlib-skin/db/ent/user"
|
"github.com/xmdhs/authlib-skin/db/ent/user"
|
||||||
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
|
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
|
||||||
"github.com/xmdhs/authlib-skin/db/ent/usertoken"
|
|
||||||
"github.com/xmdhs/authlib-skin/model"
|
"github.com/xmdhs/authlib-skin/model"
|
||||||
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||||
utilsService "github.com/xmdhs/authlib-skin/service/utils"
|
utilsService "github.com/xmdhs/authlib-skin/service/utils"
|
||||||
@ -82,19 +81,32 @@ func (w *WebService) EditUser(ctx context.Context, u model.EditUser, uid int) er
|
|||||||
uuid := ""
|
uuid := ""
|
||||||
changePasswd := false
|
changePasswd := false
|
||||||
err := utils.WithTx(ctx, w.client, func(tx *ent.Tx) error {
|
err := utils.WithTx(ctx, w.client, func(tx *ent.Tx) error {
|
||||||
up := tx.User.UpdateOneID(uid).SetEmail(u.Email)
|
if u.Email != "" {
|
||||||
if u.Password != "" {
|
c, err := tx.User.Query().Where(user.Email(u.Email)).Count(ctx)
|
||||||
p, s := utils.Argon2ID(u.Password)
|
if err != nil {
|
||||||
up = up.SetPassword(p).SetSalt(s)
|
return err
|
||||||
err := tx.UserToken.Update().Where(usertoken.HasUserWith(user.ID(uid))).AddTokenID(1).Exec(ctx)
|
}
|
||||||
|
if c != 0 {
|
||||||
|
return ErrExistUser
|
||||||
|
}
|
||||||
|
err = tx.User.UpdateOneID(uid).SetEmail(u.Email).Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
changePasswd = true
|
|
||||||
}
|
}
|
||||||
err := tx.UserProfile.Update().Where(userprofile.HasUserWith(user.ID(uid))).SetName(u.Name).Exec(ctx)
|
|
||||||
if err != nil {
|
if u.Name != "" {
|
||||||
return err
|
c, err := tx.UserProfile.Query().Where(userprofile.Name(u.Name)).Count(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c != 0 {
|
||||||
|
return ErrExitsName
|
||||||
|
}
|
||||||
|
err = tx.UserProfile.Update().Where(userprofile.HasUserWith(user.ID(uid))).SetName(u.Name).Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.DelTextures {
|
if u.DelTextures {
|
||||||
@ -111,21 +123,25 @@ func (w *WebService) EditUser(ctx context.Context, u model.EditUser, uid int) er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state := 0
|
|
||||||
if u.IsAdmin {
|
|
||||||
state = utilsService.SetAdmin(state)
|
|
||||||
}
|
|
||||||
if u.IsDisable {
|
|
||||||
state = utilsService.SetDisable(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
up = up.SetState(state)
|
aUser, err := tx.User.Get(ctx, uid)
|
||||||
|
|
||||||
err = up.Exec(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state := aUser.State
|
||||||
|
if u.IsAdmin != nil {
|
||||||
|
state = utilsService.SetAdmin(state, *u.IsAdmin)
|
||||||
|
}
|
||||||
|
if u.IsDisable != nil {
|
||||||
|
state = utilsService.SetDisable(state, *u.IsDisable)
|
||||||
|
}
|
||||||
|
if state != aUser.State {
|
||||||
|
err := tx.User.UpdateOneID(uid).SetState(state).Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -147,10 +147,16 @@ func IsDisable(state int) bool {
|
|||||||
return state&2 == 2
|
return state&2 == 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetAdmin(state int) int {
|
func SetAdmin(state int, is bool) int {
|
||||||
return state | 1
|
if is {
|
||||||
|
return state | 1
|
||||||
|
}
|
||||||
|
return state & (state ^ 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetDisable(state int) int {
|
func SetDisable(state int, is bool) int {
|
||||||
return state | 2
|
if is {
|
||||||
|
return state | 2
|
||||||
|
}
|
||||||
|
return state & (state ^ 2)
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,7 @@ func (y *Yggdrasil) delTexture(ctx context.Context, userProfileID int, textureTy
|
|||||||
return utilsService.DelTexture(ctx, userProfileID, textureType, y.client, y.config)
|
return utilsService.DelTexture(ctx, userProfileID, textureType, y.client, y.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yggdrasil) DelTexture(ctx context.Context, uuid string, t *model.TokenClaims, textureType string) error {
|
func (y *Yggdrasil) DelTexture(ctx context.Context, t *model.TokenClaims, textureType string) error {
|
||||||
if uuid != t.Subject {
|
|
||||||
return fmt.Errorf("PutTexture: %w", ErrUUIDNotEq)
|
|
||||||
}
|
|
||||||
up, err := y.client.UserProfile.Query().Where(userprofile.HasUserWith(user.ID(t.UID))).First(ctx)
|
up, err := y.client.UserProfile.Query().Where(userprofile.HasUserWith(user.ID(t.UID))).First(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("DelTexture: %w", err)
|
return fmt.Errorf("DelTexture: %w", err)
|
||||||
@ -38,18 +35,14 @@ func (y *Yggdrasil) DelTexture(ctx context.Context, uuid string, t *model.TokenC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("DelTexture: %w", err)
|
return fmt.Errorf("DelTexture: %w", err)
|
||||||
}
|
}
|
||||||
err = y.cache.Del([]byte("Profile" + uuid))
|
err = y.cache.Del([]byte("Profile" + t.Subject))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("DelTexture: %w", err)
|
return fmt.Errorf("DelTexture: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yggdrasil) PutTexture(ctx context.Context, t *model.TokenClaims, texturebyte []byte, model string, uuid string, textureType string) error {
|
func (y *Yggdrasil) PutTexture(ctx context.Context, t *model.TokenClaims, texturebyte []byte, model string, textureType string) error {
|
||||||
if uuid != t.Subject {
|
|
||||||
return fmt.Errorf("PutTexture: %w", ErrUUIDNotEq)
|
|
||||||
}
|
|
||||||
|
|
||||||
up, err := y.client.UserProfile.Query().Where(userprofile.HasUserWith(user.ID(t.UID))).First(ctx)
|
up, err := y.client.UserProfile.Query().Where(userprofile.HasUserWith(user.ID(t.UID))).First(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("PutTexture: %w", err)
|
return fmt.Errorf("PutTexture: %w", err)
|
||||||
@ -96,7 +89,7 @@ func (y *Yggdrasil) PutTexture(ctx context.Context, t *model.TokenClaims, textur
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("PutTexture: %w", err)
|
return fmt.Errorf("PutTexture: %w", err)
|
||||||
}
|
}
|
||||||
err = y.cache.Del([]byte("Profile" + uuid))
|
err = y.cache.Del([]byte("Profile" + t.Subject))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("PutTexture: %w", err)
|
return fmt.Errorf("PutTexture: %w", err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user