1
0
Fork 0

[org] fix: Don't hammer backend when consent is lacking

This commit is contained in:
joostdecock 2025-04-23 20:30:57 +02:00
parent aaed36a46a
commit f9d68bd2e1
3 changed files with 66 additions and 26 deletions

View file

@ -181,6 +181,21 @@ export const Hits = ({ results, Link = false }) => {
export const User = ({ user, Link }) => { export const User = ({ user, Link }) => {
const { setModal } = useContext(ModalContext) const { setModal } = useContext(ModalContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
/*
* We had a bug with the signUp flow where consent was
* not set. Users cannot get out of this, so this allows
* admins to grant consent on their behalf.
*/
const setConsent = async () => {
setLoadingStatus([true, 'Contacting backend'])
const [status, body] = await backend.adminUpdateUser({ id: user.id, data: { consent: 2 } })
if (status === 200 && body.result === 'success') {
setLoadingStatus([true, 'Consent updated', true, true])
} else setLoadingStatus([true, 'An error occured', true, false])
}
return ( return (
<div className="tw:flex tw:flex-row tw:w-full tw:gap-4 tw:my-2"> <div className="tw:flex tw:flex-row tw:w-full tw:gap-4 tw:my-2">
@ -222,6 +237,14 @@ export const User = ({ user, Link }) => {
Details Details
</button> </button>
<ImpersonateButton userId={user.id} /> <ImpersonateButton userId={user.id} />
{user.consent < 1 ? (
<button
className="tw:daisy-btn tw:daisy-btn-warning tw:daisy-btn-sm"
onClick={setConsent}
>
Grant Consent
</button>
) : null}
</div> </div>
</div> </div>
</div> </div>

View file

@ -8,11 +8,9 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
import { Link as DefaultLink } from '@freesewing/react/components/Link' import { Link as DefaultLink } from '@freesewing/react/components/Link'
import { LockIcon, PlusIcon } from '@freesewing/react/components/Icon' import { LockIcon, PlusIcon } from '@freesewing/react/components/Icon'
import { Spinner } from '@freesewing/react/components/Spinner' import { Spinner } from '@freesewing/react/components/Spinner'
import { Popout } from '@freesewing/react/components/Popout'
import { H1, H2, H3 } from '@freesewing/react/components/Heading' import { H1, H2, H3 } from '@freesewing/react/components/Heading'
import { Consent } from '@freesewing/react/components/Account'
//import { ConsentForm, ns as gdprNs } from 'shared/components/gdpr/form.mjs'
const ConsentForm = () => null
const Wrap = ({ children }) => ( const Wrap = ({ children }) => (
<div className="tw:m-auto tw:max-w-xl tw:text-center tw:mt-8 tw:p-8">{children}</div> <div className="tw:m-auto tw:max-w-xl tw:text-center tw:mt-8 tw:p-8">{children}</div>
@ -144,7 +142,20 @@ const ConsentLacking = ({ banner, refresh }) => {
<Wrap> <Wrap>
<div className="tw:text-left"> <div className="tw:text-left">
{banner} {banner}
<ConsentForm submit={updateConsent} /> <Popout warning>
<h2>Your account lacks consent</h2>
<p>
This should have been taken care of when onboarding your account, but due to a earlier
bug in the registration, a small subsection of accounts ended up in this state.
</p>
<p>
Please complete the form to give your consent, that may resolve the matter.
<br />
If it does not, please <a href="/support">contact support</a> so we may help you.
</p>
</Popout>
<h1>Consent & Privacy</h1>
<Consent submit={updateConsent} />
</div> </div>
</Wrap> </Wrap>
) )
@ -167,32 +178,35 @@ export const RoleBlock = ({ children, user = false, Link = false }) => {
* Avoid hydration errors * Avoid hydration errors
*/ */
useEffect(() => { useEffect(() => {
if (admin?.account?.username && account?.username) if (admin?.account?.username && account?.username && !impersonating.admin)
setImpersonating({ setImpersonating({
admin: admin.account.username, admin: admin.account.username,
user: account.username, user: account.username,
}) })
}, [admin])
useEffect(() => {
const verifyUser = async () => { const verifyUser = async () => {
const [status, data] = await backend.ping() if (!error) {
if (status === 200 && data.result === 'success') { const [status, data] = await backend.ping()
// Refresh account in local storage if (status === 200 && data.result === 'success') {
setAccount({ // Refresh account in local storage
...account, setAccount({
...data.account, ...account,
bestBefore: Date.now() + 3600000, ...data.account,
}) bestBefore: Date.now() + 3600000,
} else { })
if (data?.error?.error) setError(data.error.error) } else if (status === 451) setError('consentLacking')
else { else {
signOut() console.log({ status, data })
if (data?.error?.error) setError(data.error.error)
else signOut()
} }
setReady(true)
} }
setReady(true)
}
if (token) {
// Don't hammer the backend. Check once per hour.
if (!account.bestBefore || account.bestBefore < Date.now()) verifyUser()
} }
// Don't hammer the backend. Check once per hour.
if (token && !error && (!account.bestBefore || account.bestBefore < Date.now())) verifyUser()
setReady(true) setReady(true)
}, [admin, refreshCount, signOut]) }, [admin, refreshCount, signOut])
@ -201,7 +215,7 @@ export const RoleBlock = ({ children, user = false, Link = false }) => {
setError(false) setError(false)
} }
if (!ready) return <Spinner /> if (!ready) <Spinner />
const banner = impersonating ? ( const banner = impersonating ? (
<div className="tw:bg-warning tw:rounded-lg tw:shadow tw:py-4 tw:px-6 tw:flex tw:flex-row tw:items-center tw:gap-4 tw:justify-between"> <div className="tw:bg-warning tw:rounded-lg tw:shadow tw:py-4 tw:px-6 tw:flex tw:flex-row tw:items-center tw:gap-4 tw:justify-between">

View file

@ -3,10 +3,13 @@ title: Your Account
sidebar_label: Account sidebar_label: Account
--- ---
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role' import { RoleBlock } from '@freesewing/react/components/Role'
import { Links as AccountLinks } from '@freesewing/react/components/Account' import { Links as AccountLinks } from '@freesewing/react/components/Account'
import Link from '@docusaurus/Link' import Link from '@docusaurus/Link'
<RoleBlock user> <DocusaurusDoc>
<AccountLinks Link={Link} /> <RoleBlock user>
</RoleBlock> <AccountLinks Link={Link} />
</RoleBlock>
</DocusaurusDoc>