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