Merge pull request #4740 from h3poteto/iss-4653/authorize-error
refs #4653 Add error messages in authorization
This commit is contained in:
commit
acd9538d3c
|
@ -27,7 +27,11 @@
|
|||
"authorize": "Authorize",
|
||||
"authorization_code": "Authorization Code",
|
||||
"authorization_helper": "Please paste the authorization code from your browser",
|
||||
"without_code_authorize": "Please approve Whalebird in your browser, and after you approve it please authorize"
|
||||
"without_code_authorize": "Please approve Whalebird in your browser, and after you approve it please authorize",
|
||||
"detector_error": "Failed to connect to {domain}, make sure the server URL is valid or correct.",
|
||||
"register_error": "Failed to add application.",
|
||||
"token_error": "Failed to authorize.",
|
||||
"credential_error": "Failed to confirm access token."
|
||||
},
|
||||
"remove": "Remove"
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Label, Modal, TextInput, Button } from 'flowbite-react'
|
||||
import { Label, Modal, TextInput, Button, Alert, Spinner } from 'flowbite-react'
|
||||
import generator, { MegalodonInterface, OAuth, detector } from 'megalodon'
|
||||
import { useState } from 'react'
|
||||
import { db } from '@/db'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
|
||||
type NewProps = {
|
||||
opened: boolean
|
||||
|
@ -14,29 +14,53 @@ export default function New(props: NewProps) {
|
|||
const [domain, setDomain] = useState<string>('')
|
||||
const [client, setClient] = useState<MegalodonInterface>()
|
||||
const [appData, setAppData] = useState<OAuth.AppData>()
|
||||
const [error, setError] = useState("")
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const { formatMessage } = useIntl()
|
||||
|
||||
const close = () => {
|
||||
setSNS(null)
|
||||
setDomain('')
|
||||
setClient(undefined)
|
||||
setAppData(undefined)
|
||||
setError("")
|
||||
setLoading(false)
|
||||
props.close()
|
||||
}
|
||||
|
||||
const checkDomain = async () => {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
const input = document.getElementById('domain') as HTMLInputElement
|
||||
setDomain(input.value)
|
||||
const url = `https://${input.value}`
|
||||
const sns = await detector(url)
|
||||
const sns = await detector(url).catch(() => {
|
||||
setError(formatMessage({ id: 'accounts.new.detector_error' }, { domain: input.value}))
|
||||
return undefined
|
||||
})
|
||||
if (!sns) {
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
setSNS(sns)
|
||||
const client = generator(sns, url)
|
||||
setClient(client)
|
||||
const appData = await client.registerApp('Whalebird', {})
|
||||
const appData = await client.registerApp('Whalebird', {}).catch(() => {
|
||||
setError(formatMessage({ id: "accounts.new.register_error" }))
|
||||
return undefined
|
||||
})
|
||||
setLoading(false)
|
||||
if (!appData) {
|
||||
return
|
||||
}
|
||||
setAppData(appData)
|
||||
global.ipc.invoke('open-browser', appData.url)
|
||||
}
|
||||
|
||||
const authorize = async () => {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
if (!client || !appData) return
|
||||
const input = document.getElementById('authorization') as HTMLInputElement
|
||||
let authorizationCode = null
|
||||
|
@ -45,10 +69,27 @@ export default function New(props: NewProps) {
|
|||
} else {
|
||||
authorizationCode = input.value
|
||||
}
|
||||
const tokenData = await client.fetchAccessToken(appData.client_id, appData.client_secret, authorizationCode)
|
||||
if (!sns) return
|
||||
const tokenData = await client.fetchAccessToken(appData.client_id, appData.client_secret, authorizationCode).catch(() => {
|
||||
setError(formatMessage({ id: "accounts.new.token_error" }))
|
||||
return undefined
|
||||
})
|
||||
if (!tokenData) {
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
if (!sns) {
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
const cli = generator(sns, `https://${domain}`, tokenData.access_token, 'Whalebird')
|
||||
const acct = await cli.verifyAccountCredentials()
|
||||
const acct = await cli.verifyAccountCredentials().catch(() => {
|
||||
setError(formatMessage({ id: "accounts.new.credential_error" }))
|
||||
return undefined
|
||||
})
|
||||
setLoading(false)
|
||||
if (!acct) {
|
||||
return
|
||||
}
|
||||
await db.accounts.add({
|
||||
username: acct.data.username,
|
||||
account_id: acct.data.id,
|
||||
|
@ -71,8 +112,13 @@ export default function New(props: NewProps) {
|
|||
<FormattedMessage id="accounts.new.title" />
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{error && (
|
||||
<Alert color="failure">
|
||||
<span>{error}</span>
|
||||
</Alert>
|
||||
)}
|
||||
<form className="flex max-w-md flex-col gap-2">
|
||||
{sns === null && (
|
||||
{sns === null ? (
|
||||
<>
|
||||
<div className="block">
|
||||
<Label htmlFor="domain">
|
||||
|
@ -80,37 +126,45 @@ export default function New(props: NewProps) {
|
|||
</Label>
|
||||
</div>
|
||||
<TextInput id="domain" placeholder="mastodon.social" required type="text" />
|
||||
<Button onClick={checkDomain}>
|
||||
<Button onClick={checkDomain} disabled={loading}>
|
||||
<FormattedMessage id="accounts.new.sign_in" />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{sns && appData && (
|
||||
) : (
|
||||
<>
|
||||
{appData.session_token ? (
|
||||
{appData ? (
|
||||
<>
|
||||
<div className="block text-gray-600">
|
||||
<FormattedMessage id="accounts.new.without_code_authorize" />
|
||||
</div>
|
||||
{appData.session_token ? (
|
||||
<>
|
||||
<div className="block text-gray-600">
|
||||
<FormattedMessage id="accounts.new.without_code_authorize" />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="block">
|
||||
<Label htmlFor="authorization">
|
||||
<FormattedMessage id="accounts.new.authorization_code" />
|
||||
</Label>
|
||||
<p className="text-sm text-gray-600">
|
||||
<FormattedMessage id="accounts.new.authorization_helper" />
|
||||
</p>
|
||||
</div>
|
||||
<TextInput id="authorization" required type="text" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button onClick={authorize} disabled={loading}>
|
||||
<FormattedMessage id="accounts.new.authorize" />
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="block">
|
||||
<Label htmlFor="authorization">
|
||||
<FormattedMessage id="accounts.new.authorization_code" />
|
||||
</Label>
|
||||
<p className="text-sm text-gray-600">
|
||||
<FormattedMessage id="accounts.new.authorization_helper" />
|
||||
</p>
|
||||
</div>
|
||||
<TextInput id="authorization" required type="text" />
|
||||
</>
|
||||
<div className="text-center">
|
||||
<Spinner aria-label="Loading" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button onClick={authorize}>
|
||||
<FormattedMessage id="accounts.new.authorize" />
|
||||
</Button>
|
||||
</>
|
||||
|
||||
)}
|
||||
</form>
|
||||
</Modal.Body>
|
||||
|
|
Loading…
Reference in New Issue