Fix saving profile and add generating new API key
This commit is contained in:
parent
2f375dc24d
commit
004ad46251
|
@ -1,6 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import binascii
|
||||||
|
|
||||||
from sanic.response import json
|
from sanic.response import json
|
||||||
|
from sanic.exceptions import InvalidUsage
|
||||||
|
|
||||||
from obs.api.app import api, require_auth
|
from obs.api.app import api, require_auth
|
||||||
|
|
||||||
|
@ -16,7 +19,7 @@ def user_to_json(user):
|
||||||
"bio": user.bio,
|
"bio": user.bio,
|
||||||
"image": user.image,
|
"image": user.image,
|
||||||
"areTracksVisibleForAll": user.are_tracks_visible_for_all,
|
"areTracksVisibleForAll": user.are_tracks_visible_for_all,
|
||||||
# "apiKey": user.api_key,
|
"apiKey": user.api_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,13 +32,17 @@ async def get_user(req):
|
||||||
@require_auth
|
@require_auth
|
||||||
async def put_user(req):
|
async def put_user(req):
|
||||||
user = req.ctx.user
|
user = req.ctx.user
|
||||||
|
data = req.json
|
||||||
|
|
||||||
for key in ["username", "email", "bio", "image"]:
|
for key in ["email", "bio", "image"]:
|
||||||
if key in req.json and isinstance(req.json[key], (str, type(None))):
|
if key in data and isinstance(data[key], (str, type(None))):
|
||||||
setattr(user, key, req.json[key])
|
setattr(user, key, data[key])
|
||||||
|
|
||||||
if "areTracksVisibleForAll" in req.json:
|
if "areTracksVisibleForAll" in data:
|
||||||
user.are_tracks_visible_for_all = bool(req.json["areTracksVisibleForAll"])
|
user.are_tracks_visible_for_all = bool(data["areTracksVisibleForAll"])
|
||||||
|
|
||||||
|
if data.get("updateApiKey"):
|
||||||
|
user.api_key = binascii.b2a_hex(os.urandom(16)).decode("ascii")
|
||||||
|
|
||||||
await req.ctx.db.commit()
|
await req.ctx.db.commit()
|
||||||
return json(user_to_json(req.ctx.user))
|
return json(user_to_json(req.ctx.user))
|
||||||
|
|
|
@ -19,8 +19,8 @@ const SettingsPage = connect((state) => ({login: state.login}), {setLogin})(func
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setErrors(null)
|
setErrors(null)
|
||||||
try {
|
try {
|
||||||
const response = await api.put('/user', {body: {user: changes}})
|
const response = await api.put('/user', {body: changes})
|
||||||
setLogin(response.user)
|
setLogin(response)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setErrors(err.errors)
|
setErrors(err.errors)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -30,6 +30,19 @@ const SettingsPage = connect((state) => ({login: state.login}), {setLogin})(func
|
||||||
[setLoading, setLogin, setErrors]
|
[setLoading, setLogin, setErrors]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onGenerateNewKey = React.useCallback(async () => {
|
||||||
|
setLoading(true)
|
||||||
|
setErrors(null)
|
||||||
|
try {
|
||||||
|
const response = await api.put('/user', {body: {updateApiKey: true}})
|
||||||
|
setLogin(response)
|
||||||
|
} catch (err) {
|
||||||
|
setErrors(err.errors)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}, [setLoading, setLogin, setErrors])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<Grid centered relaxed divided>
|
<Grid centered relaxed divided>
|
||||||
|
@ -41,7 +54,7 @@ const SettingsPage = connect((state) => ({login: state.login}), {setLogin})(func
|
||||||
|
|
||||||
<Form onSubmit={handleSubmit(onSave)} loading={loading}>
|
<Form onSubmit={handleSubmit(onSave)} loading={loading}>
|
||||||
<Ref innerRef={findInput(register)}>
|
<Ref innerRef={findInput(register)}>
|
||||||
<Form.Input error={errors?.username} label="Username" name="username" defaultValue={login.username} />
|
<Form.Input error={errors?.username} label="Username" name="username" defaultValue={login.username} disabled />
|
||||||
</Ref>
|
</Ref>
|
||||||
<Form.Field error={errors?.bio}>
|
<Form.Field error={errors?.bio}>
|
||||||
<label>Bio</label>
|
<label>Bio</label>
|
||||||
|
@ -62,7 +75,7 @@ const SettingsPage = connect((state) => ({login: state.login}), {setLogin})(func
|
||||||
</Form>
|
</Form>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
<Grid.Column width={6}>
|
<Grid.Column width={6}>
|
||||||
<ApiKeyDialog {...{login}} />
|
<ApiKeyDialog {...{login, onGenerateNewKey}} />
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
@ -101,7 +114,7 @@ function CopyInput({value, ...props}) {
|
||||||
|
|
||||||
const selectField = findInput((ref) => ref?.select())
|
const selectField = findInput((ref) => ref?.select())
|
||||||
|
|
||||||
function ApiKeyDialog({login}) {
|
function ApiKeyDialog({login, onGenerateNewKey}) {
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const [show, setShow] = React.useState(false)
|
const [show, setShow] = React.useState(false)
|
||||||
const onClick = React.useCallback(
|
const onClick = React.useCallback(
|
||||||
|
@ -112,6 +125,14 @@ function ApiKeyDialog({login}) {
|
||||||
[setShow]
|
[setShow]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onGenerateNewKeyInner = React.useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
onGenerateNewKey()
|
||||||
|
},
|
||||||
|
[onGenerateNewKey]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header as="h2">Your API Key</Header>
|
<Header as="h2">Your API Key</Header>
|
||||||
|
@ -120,11 +141,15 @@ function ApiKeyDialog({login}) {
|
||||||
configuration interface to allow direct upload from the device.
|
configuration interface to allow direct upload from the device.
|
||||||
</p>
|
</p>
|
||||||
<p>Please protect your API Key carefully as it allows full control over your account.</p>
|
<p>Please protect your API Key carefully as it allows full control over your account.</p>
|
||||||
<div style={{height: 40, marginBottom: 16}}>
|
<div style={{minHeight: 40, marginBottom: 16}}>
|
||||||
{show ? (
|
{show ? (
|
||||||
<Ref innerRef={selectField}>
|
login.apiKey ? (
|
||||||
<CopyInput label="Personal API key" value={login.apiKey} />
|
<Ref innerRef={selectField}>
|
||||||
</Ref>
|
<CopyInput label="Personal API Key" value={login.apiKey} />
|
||||||
|
</Ref>
|
||||||
|
) : (
|
||||||
|
<Message warning content='You have no API Key, please generate one below.' />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<Button onClick={onClick}>
|
<Button onClick={onClick}>
|
||||||
<Icon name="lock" /> Show API Key
|
<Icon name="lock" /> Show API Key
|
||||||
|
@ -132,7 +157,14 @@ function ApiKeyDialog({login}) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p>The API URL should be set to:</p>
|
<p>The API URL should be set to:</p>
|
||||||
<CopyInput label="API URL" value={config?.apiUrl ?? '...'} />
|
<div style={{marginBottom: 16}}>
|
||||||
|
<CopyInput label="API URL" value={config?.apiUrl ?? '...'} />
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
You can generate a new API Key here, which will invalidate the old one, disconnecting all devices you used it on
|
||||||
|
from your account.
|
||||||
|
</p>
|
||||||
|
<Button onClick={onGenerateNewKeyInner}>Generate new API key</Button>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue