mirror of
https://github.com/navidrome/navidrome.git
synced 2025-05-30 07:09:29 +03:00
Allow regular users to change their info, including password.
Should fix #199
This commit is contained in:
parent
22582392a0
commit
a35de2bfd1
@ -37,6 +37,7 @@ func CreateToken(u *model.User) (string, error) {
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
claims["iss"] = consts.JWTIssuer
|
||||
claims["sub"] = u.UserName
|
||||
claims["uid"] = u.ID
|
||||
claims["adm"] = u.IsAdmin
|
||||
|
||||
return TouchToken(token)
|
||||
|
@ -144,6 +144,10 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
||||
if !usr.IsAdmin && usr.ID != u.ID {
|
||||
return rest.ErrPermissionDenied
|
||||
}
|
||||
if !usr.IsAdmin {
|
||||
u.IsAdmin = false
|
||||
u.UserName = usr.UserName
|
||||
}
|
||||
err := r.Put(u)
|
||||
if err == model.ErrNotFound {
|
||||
return rest.ErrNotFound
|
||||
@ -153,7 +157,7 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
||||
|
||||
func (r *userRepository) Delete(id string) error {
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin && usr.ID != id {
|
||||
if !usr.IsAdmin {
|
||||
return rest.ErrPermissionDenied
|
||||
}
|
||||
err := r.delete(Eq{"id": id})
|
||||
|
@ -87,6 +87,9 @@
|
||||
"name": "Nome",
|
||||
"password": "Senha",
|
||||
"createdAt": "Data de Criação"
|
||||
},
|
||||
"helperTexts": {
|
||||
"name": "Alterações no seu nome só serão refletidas no próximo login"
|
||||
}
|
||||
},
|
||||
"player": {
|
||||
@ -348,4 +351,4 @@
|
||||
"toggle_love": "Marcar/desmarcar favorita"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ func handleLogin(ds model.DataStore, username string, password string, w http.Re
|
||||
payload := map[string]interface{}{
|
||||
"message": "User '" + username + "' authenticated successfully",
|
||||
"token": tokenString,
|
||||
"id": user.ID,
|
||||
"name": user.Name,
|
||||
"username": username,
|
||||
"isAdmin": user.IsAdmin,
|
||||
|
@ -93,9 +93,7 @@ const Admin = (props) => {
|
||||
{...playlist}
|
||||
options={{ subMenu: 'library' }}
|
||||
/>,
|
||||
permissions === 'admin' ? (
|
||||
<Resource name="user" {...user} options={{ subMenu: 'settings' }} />
|
||||
) : null,
|
||||
<Resource name="user" {...user} options={{ subMenu: 'settings' }} />,
|
||||
<Resource
|
||||
name="player"
|
||||
{...player}
|
||||
|
@ -26,7 +26,9 @@ const authProvider = {
|
||||
.then((response) => {
|
||||
// Validate token
|
||||
jwtDecode(response.token)
|
||||
// TODO Store all items in one object
|
||||
localStorage.setItem('token', response.token)
|
||||
localStorage.setItem('userId', response.id)
|
||||
localStorage.setItem('name', response.name)
|
||||
localStorage.setItem('username', response.username)
|
||||
response.avatar && localStorage.setItem('avatar', response.avatar)
|
||||
@ -94,6 +96,7 @@ const authProvider = {
|
||||
|
||||
const removeItems = () => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('userId')
|
||||
localStorage.removeItem('name')
|
||||
localStorage.removeItem('username')
|
||||
localStorage.removeItem('avatar')
|
||||
|
@ -87,6 +87,9 @@
|
||||
"name": "Name",
|
||||
"password": "Password",
|
||||
"createdAt": "Created at"
|
||||
},
|
||||
"helperTexts": {
|
||||
"name": "Changes to your name will only be reflected on next login"
|
||||
}
|
||||
},
|
||||
"player": {
|
||||
|
@ -58,6 +58,7 @@ const AboutMenuItem = forwardRef(({ onClick, ...rest }, ref) => {
|
||||
})
|
||||
|
||||
const settingsResources = (resource) =>
|
||||
resource.name !== 'user' &&
|
||||
resource.hasList &&
|
||||
resource.options &&
|
||||
resource.options.subMenu === 'settings'
|
||||
@ -68,16 +69,31 @@ const CustomUserMenu = ({ onClick, ...rest }) => {
|
||||
const classes = useStyles(rest)
|
||||
const { permissions } = usePermissions()
|
||||
|
||||
const renderSettingsMenuItemLink = (resource) => {
|
||||
const resourceDefinition = (resourceName) =>
|
||||
resources.find((r) => r?.name === resourceName)
|
||||
|
||||
const renderUserMenuItemLink = () => {
|
||||
const userResource = resourceDefinition('user')
|
||||
if (!userResource) {
|
||||
return null
|
||||
}
|
||||
return renderSettingsMenuItemLink(
|
||||
userResource,
|
||||
permissions !== 'admin' ? localStorage.getItem('userId') : null
|
||||
)
|
||||
}
|
||||
|
||||
const renderSettingsMenuItemLink = (resource, id) => {
|
||||
const label = translate(`resources.${resource.name}.name`, {
|
||||
smart_count: 2,
|
||||
smart_count: id ? 1 : 2,
|
||||
})
|
||||
const link = id ? `/${resource.name}/${id}` : `/${resource.name}`
|
||||
return (
|
||||
<MenuItemLink
|
||||
className={classes.root}
|
||||
activeClassName={classes.active}
|
||||
key={resource.name}
|
||||
to={`/${resource.name}`}
|
||||
to={link}
|
||||
primaryText={label}
|
||||
leftIcon={
|
||||
(resource.icon && createElement(resource.icon)) || <ViewListIcon />
|
||||
@ -94,6 +110,7 @@ const CustomUserMenu = ({ onClick, ...rest }) => {
|
||||
<UserMenu {...rest}>
|
||||
<PersonalMenu sidebarIsOpen={true} onClick={onClick} />
|
||||
<Divider />
|
||||
{renderUserMenuItemLink()}
|
||||
{resources.filter(settingsResources).map(renderSettingsMenuItemLink)}
|
||||
<Divider />
|
||||
<AboutMenuItem />
|
||||
|
@ -31,25 +31,47 @@ const UserTitle = ({ record }) => {
|
||||
|
||||
const UserToolbar = (props) => (
|
||||
<Toolbar {...props} classes={useStyles()}>
|
||||
<SaveButton />
|
||||
<DeleteUserButton />
|
||||
<SaveButton disabled={props.pristine} />
|
||||
{props.permissions === 'admin' && <DeleteUserButton />}
|
||||
</Toolbar>
|
||||
)
|
||||
|
||||
const UserEdit = (props) => (
|
||||
<Edit title={<UserTitle />} {...props}>
|
||||
<SimpleForm variant={'outlined'} toolbar={<UserToolbar />}>
|
||||
<TextInput source="userName" validate={[required()]} />
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<TextInput source="email" validate={[email()]} />
|
||||
<PasswordInput source="password" validate={[required()]} />
|
||||
<BooleanInput source="isAdmin" initialValue={false} />
|
||||
<DateField variant="body1" source="lastLoginAt" showTime />
|
||||
{/*<DateField source="lastAccessAt" showTime />*/}
|
||||
<DateField variant="body1" source="updatedAt" showTime />
|
||||
<DateField variant="body1" source="createdAt" showTime />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
)
|
||||
const UserEdit = (props) => {
|
||||
const { permissions } = props
|
||||
const translate = useTranslate()
|
||||
|
||||
const getNameHelperText = () =>
|
||||
props.id === localStorage.getItem('userId') && {
|
||||
helperText: translate('resources.user.helperTexts.name'),
|
||||
}
|
||||
|
||||
return (
|
||||
<Edit title={<UserTitle />} {...props}>
|
||||
<SimpleForm
|
||||
variant={'outlined'}
|
||||
toolbar={<UserToolbar />}
|
||||
redirect={permissions === 'admin' ? 'list' : false}
|
||||
>
|
||||
{permissions === 'admin' && (
|
||||
<TextInput source="userName" validate={[required()]} />
|
||||
)}
|
||||
<TextInput
|
||||
source="name"
|
||||
validate={[required()]}
|
||||
{...getNameHelperText()}
|
||||
/>
|
||||
<TextInput source="email" validate={[email()]} />
|
||||
<PasswordInput source="password" validate={[required()]} />
|
||||
{permissions === 'admin' && (
|
||||
<BooleanInput source="isAdmin" initialValue={false} />
|
||||
)}
|
||||
<DateField variant="body1" source="lastLoginAt" showTime />
|
||||
{/*<DateField source="lastAccessAt" showTime />*/}
|
||||
<DateField variant="body1" source="updatedAt" showTime />
|
||||
<DateField variant="body1" source="createdAt" showTime />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserEdit
|
||||
|
Loading…
x
Reference in New Issue
Block a user