Skip to content

Commit

Permalink
fix: allow non email logins and user mgmt (#2256)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmorganca committed Jun 9, 2022
1 parent 64ccfa7 commit 5ef42cf
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 97 deletions.
52 changes: 21 additions & 31 deletions ui/components/admin.js
Expand Up @@ -2,8 +2,6 @@ import { useState } from 'react'
import useSWR, { useSWRConfig } from 'swr'
import { PlusIcon } from '@heroicons/react/outline'

import { validateEmail } from '../lib/email'

import InputDropdown from './input'
import DeleteModal from './modals/delete'
import ErrorMessage from './error-message'
Expand Down Expand Up @@ -60,7 +58,7 @@ export default function () {
const { data: auth } = useSWR('/api/users/self')
const { mutate } = useSWRConfig()

const [adminEmail, setAdminEmail] = useState('')
const [name, setName] = useState('')
const [error, setError] = useState('')

const userGrants = grants?.filter(g => g.user)
Expand All @@ -73,43 +71,35 @@ export default function () {
})
.then(() => {
mutate('/api/grants?resource=infra&privilege=admin')
setAdminEmail('')
setName('')
}).catch((e) => setError(e.message || 'something went wrong, please try again later.'))
}

const handleInputChange = (value) => {
setAdminEmail(value)
setName(value)
setError('')
}

const handleKeyDownEvent = (key) => {
if (key === 'Enter' && adminEmail.length > 0) {
if (key === 'Enter' && name.length > 0) {
handleAddAdmin()
}
}

const handleAddAdmin = () => {
if (validateEmail(adminEmail)) {
setError('')

fetch(`/api/users?name=${adminEmail}`)
.then((response) => response.json())
.then(({ items = [] }) => {
if (items.length === 0) {
fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: adminEmail })
})
.then((response) => response.json())
.then((user) => grantAdminAccess(user.id))
.catch((error) => console.error(error))
} else {
grantAdminAccess(items[0].id)
}
})
} else {
setError('Invalid email')
}
setError('')

fetch(`/api/users?name=${name}`)
.then((response) => response.json())
.then(({ items = [] }) => {
if (items.length === 0) {
setError('User does not exist')
} else {
grantAdminAccess(items[0].id)
}
}).catch(e => {
setError(e)
})
}

return (
Expand All @@ -118,9 +108,9 @@ export default function () {
<div className={`flex flex-col sm:flex-row ${error ? 'mt-6 mb-2' : 'mt-6 mb-14'}`}>
<div className='sm:flex-1'>
<InputDropdown
type='email'
value={adminEmail}
placeholder='Email address'
name='name'
value={name}
placeholder='Username or email'
hasDropdownSelection={false}
handleInputChange={e => handleInputChange(e.target.value)}
handleKeyDown={(e) => handleKeyDownEvent(e.key)}
Expand All @@ -129,7 +119,7 @@ export default function () {
</div>
<button
onClick={() => handleAddAdmin()}
disabled={adminEmail.length === 0}
disabled={name.length === 0}
type='button'
className='flex items-center cursor-pointer border border-violet-300 px-5 mt-4 text-2xs sm:ml-4 sm:mt-0 rounded-md disabled:pointer-events-none disabled:opacity-30'
>
Expand Down
52 changes: 23 additions & 29 deletions ui/components/grant.js
Expand Up @@ -2,8 +2,6 @@ import useSWR, { useSWRConfig } from 'swr'
import { useState } from 'react'
import { PlusIcon } from '@heroicons/react/outline'

import { validateEmail } from '../lib/email'

import InputDropdown from '../components/input'
import ErrorMessage from '../components/error-message'

Expand All @@ -25,7 +23,7 @@ export default function ({ id }) {
const { mutate } = useSWRConfig()
const list = items?.filter(item => !!item.user)

const [email, setEmail] = useState('')
const [name, setName] = useState('')
const [error, setError] = useState('')
const [grantError, setGrantError] = useState('')
const [role, setRole] = useState('view')
Expand All @@ -45,45 +43,41 @@ export default function ({ id }) {
await fetch(`/api/grants/${deleteGrantId}`, { method: 'DELETE' })
}

setEmail('')
setName('')
setRole('view')

return { items: [...grants.filter(grant => grant?.user !== user), data] }
})
}

const handleInputChange = value => {
setEmail(value)
setName(value)
setError('')
}

const handleKeyDownEvent = key => {
if (key === 'Enter' && email.length > 0) {
if (key === 'Enter' && name.length > 0) {
handleShareGrant()
}
}

const handleShareGrant = async () => {
if (validateEmail(email)) {
setError('')
try {
const res = await fetch(`/api/users?name=${email}`)
const data = await res.json()

if (!res.ok) {
throw data
}

if (data?.items?.length === 0) {
setError('User does not exist')
} else {
grantPrivilege(data?.items?.[0]?.id)
}
} catch (e) {
setGrantError(e.message || 'something went wrong, please try again later.')
setError('')
try {
const res = await fetch(`/api/users?name=${name}`)
const data = await res.json()

if (!res.ok) {
throw data
}

if (data?.items?.length === 0) {
setError('User does not exist')
} else {
grantPrivilege(data?.items?.[0]?.id)
}
} else {
setError('Invalid email')
} catch (e) {
setGrantError(e.message || 'something went wrong, please try again later.')
}
}

Expand All @@ -103,9 +97,9 @@ export default function ({ id }) {
<div className={`flex gap-1 mt-3 ${error ? 'mb-2' : 'mb-4'}`}>
<div className='flex-1'>
<InputDropdown
type='email'
value={email}
placeholder='Email'
name='name'
value={name}
placeholder='Username or Email'
error={error}
optionType='role'
options={options.filter((item) => item !== 'remove')}
Expand All @@ -117,7 +111,7 @@ export default function ({ id }) {
</div>
<button
onClick={() => handleShareGrant()}
disabled={email.length === 0}
disabled={name.length === 0}
type='button'
className='flex items-center border border-violet-300 disabled:opacity-30 disabled:transform-none disabled:transition-none cursor-pointer disabled:cursor-default mt-4 mr-auto sm:ml-4 sm:mt-0 rounded-md text-2xs px-3 py-3'
>
Expand Down
67 changes: 31 additions & 36 deletions ui/pages/login/index.js
Expand Up @@ -3,7 +3,6 @@ import { useState } from 'react'
import useSWR, { useSWRConfig } from 'swr'

import { kind } from '../../lib/providers'
import { validateEmail } from '../../lib/email'
import LoginLayout from '../../components/layouts/login'

function oidcLogin ({ id, url, clientID }) {
Expand Down Expand Up @@ -54,48 +53,44 @@ export default function Login () {
const { mutate } = useSWRConfig()
const router = useRouter()

const [email, setEmail] = useState('')
const [name, setName] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')

async function onSubmit (e) {
e.preventDefault()

if (validateEmail(email)) {
try {
const res = await fetch('/api/login', {
method: 'post',
body: JSON.stringify({
passwordCredentials: {
name: email,
password
}
})
try {
const res = await fetch('/api/login', {
method: 'post',
body: JSON.stringify({
passwordCredentials: {
name,
password
}
})
})

if (!res.ok) {
throw await res.json()
}

const data = await res.json()
if (!res.ok) {
throw await res.json()
}

if (data.passwordUpdateRequired) {
router.replace({
pathname: '/login/finish',
query: { user: data.userID }
})
const data = await res.json()

return false
}
if (data.passwordUpdateRequired) {
router.replace({
pathname: '/login/finish',
query: { user: data.userID }
})

await mutate('/api/users/self')
router.replace('/')
} catch (e) {
console.error(e)
setError('Invalid credentials')
return false
}
} else {
setError('Invalid email')

await mutate('/api/users/self')
router.replace('/')
} catch (e) {
console.error(e)
setError('Invalid credentials')
}

return false
Expand All @@ -108,14 +103,14 @@ export default function Login () {
{providers?.length > 0 && <Providers providers={providers || []} />}
<form onSubmit={onSubmit} className='flex flex-col w-full max-w-sm relative'>
<div className='w-full my-2'>
<label htmlFor='email' className='text-3xs text-gray-500 uppercase'>Email</label>
<label htmlFor='name' className='text-3xs text-gray-500 uppercase'>Username or Email</label>
<input
required
autoFocus
name='email'
placeholder='enter your email'
name='name'
placeholder='enter your username or email'
onChange={e => {
setEmail(e.target.value)
setName(e.target.value)
setError('')
}}
className={`w-full bg-transparent border-b border-gray-800 text-2xs px-px py-2 focus:outline-none focus:border-b focus:border-gray-200 placeholder:italic ${error ? 'border-pink-500/60' : ''}`}
Expand All @@ -135,7 +130,7 @@ export default function Login () {
className={`w-full bg-transparent border-b border-gray-800 text-2xs px-px py-2 focus:outline-none focus:border-b focus:ring-gray-200 placeholder:italic ${error ? 'border-pink-500/60' : ''}`}
/>
</div>
<button disabled={!email || !password} className='border border-violet-300 hover:border-violet-100 mt-6 mb-2 text-2xs px-4 py-3 rounded-lg disabled:pointer-events-none text-violet-100 disabled:opacity-30'>
<button disabled={!name || !password} className='border border-violet-300 hover:border-violet-100 mt-6 mb-2 text-2xs px-4 py-3 rounded-lg disabled:pointer-events-none text-violet-100 disabled:opacity-30'>
Login
</button>
{error && <p className='absolute -bottom-3.5 w-full mx-auto text-2xs text-pink-400 text-center'>{error}</p>}
Expand Down
2 changes: 1 addition & 1 deletion ui/pages/users/index.js
Expand Up @@ -16,7 +16,7 @@ import DeleteModal from '../../components/modals/delete'
import ResourcesGrant from '../../components/resources-grant'

const columns = [{
Header: 'Email',
Header: 'Name',
accessor: u => u,
Cell: ({ value: user }) => (
<div className='flex items-center py-1.5'>
Expand Down

0 comments on commit 5ef42cf

Please sign in to comment.