feat: add user management screen
feat: login screen fix: login routing and layout feat: add users migration feat: passport login strategy fix: users migration feat: simple authentication fix: request body feat: JWT authorization feat: 2fa step on login feat: 2fa flow feat: add rememberme to req body fix: hide 2fa secret from jwt fix: block login access to logged in user fix: rerouting to wizard refactor: login screen feat: setup 2fa state on login feat: 2fa secret qr code fix: remove jwt from 2fa secret fix: wizard redirect after login fix: 2fa setup flow fix: user id to uuid feat: user roles feat: user sessions and db persistence feat: session saving on DB and cookie refactor: unused code feat: cookie auto renew on request feat: get user data endpoint fix: repeated requests feat: react routing fix: private routes refactor: auth feat: sessions aware of ua and ip feat: sessions on gql feat: session management screen feat: replace user_tokens usage for users feat: user deletion also deletes active sessions feat: remember me alters session cookie accordingly feat: last session by all users fix: login feedback fix: page loading UX feat: routes based on user role feat: header aware of roles feat: reset password fix: reset password endpoint feat: handle password change feat: reset 2FA feat: user role on management screen feat: change user role fix: user last session query fix: context fix: destroy own session feat: reset password now resets sessions feat: reset 2fa now resets sessions refactor: user data refactor: user management screen feat: user enable feat: schema directives fix: remove schema directive temp feat: create new users feat: register endpoint feat: modals for reset links fix: directive Date errors feat: superuser directive feat: create user url modal fix: user management layout feat: confirmation modals fix: info text feat: 2fa input component feat: code input on 2fa state feat: add button styling feat: confirmation modal on superuser action feat: rework 2fa setup screen feat: rework reset 2fa screen fix: session management screen fix: user management screen fix: blacklist roles chore: migrate old customer values to new columns fix: value migration fix: value migration refactor: remove old code
This commit is contained in:
parent
368781864e
commit
fded22f39a
50 changed files with 9839 additions and 4501 deletions
|
|
@ -13,7 +13,11 @@ import {
|
|||
} from 'react-router-dom'
|
||||
|
||||
import AppContext from 'src/AppContext'
|
||||
import AuthRegister from 'src/pages/AuthRegister'
|
||||
// import AuthRegister from 'src/pages/AuthRegister'
|
||||
import Login from 'src/pages/Authentication/Login'
|
||||
import Register from 'src/pages/Authentication/Register'
|
||||
import Reset2FA from 'src/pages/Authentication/Reset2FA'
|
||||
import ResetPassword from 'src/pages/Authentication/ResetPassword'
|
||||
import Blacklist from 'src/pages/Blacklist'
|
||||
import Cashout from 'src/pages/Cashout'
|
||||
import Commissions from 'src/pages/Commissions'
|
||||
|
|
@ -34,13 +38,18 @@ import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting'
|
|||
import TermsConditions from 'src/pages/OperatorInfo/TermsConditions'
|
||||
import ServerLogs from 'src/pages/ServerLogs'
|
||||
import Services from 'src/pages/Services/Services'
|
||||
// import TokenManagement from 'src/pages/TokenManagement/TokenManagement'
|
||||
import SessionManagement from 'src/pages/SessionManagement/SessionManagement'
|
||||
import Transactions from 'src/pages/Transactions/Transactions'
|
||||
import Triggers from 'src/pages/Triggers'
|
||||
import UserManagement from 'src/pages/UserManagement/UserManagement'
|
||||
import WalletSettings from 'src/pages/Wallet/Wallet'
|
||||
import Wizard from 'src/pages/Wizard'
|
||||
import { namespaces } from 'src/utils/config'
|
||||
|
||||
import PrivateRoute from './PrivateRoute'
|
||||
import PublicRoute from './PublicRoute'
|
||||
import { ROLES } from './utils'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
wrapper: {
|
||||
flex: 1,
|
||||
|
|
@ -55,12 +64,14 @@ const tree = [
|
|||
key: 'transactions',
|
||||
label: 'Transactions',
|
||||
route: '/transactions',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Transactions
|
||||
},
|
||||
{
|
||||
key: 'maintenance',
|
||||
label: 'Maintenance',
|
||||
route: '/maintenance',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
get component() {
|
||||
return () => <Redirect to={this.children[0].route} />
|
||||
},
|
||||
|
|
@ -69,30 +80,35 @@ const tree = [
|
|||
key: 'cash_cassettes',
|
||||
label: 'Cash Cassettes',
|
||||
route: '/maintenance/cash-cassettes',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: CashCassettes
|
||||
},
|
||||
{
|
||||
key: 'funding',
|
||||
label: 'Funding',
|
||||
route: '/maintenance/funding',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Funding
|
||||
},
|
||||
{
|
||||
key: 'logs',
|
||||
label: 'Machine Logs',
|
||||
route: '/maintenance/logs',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: MachineLogs
|
||||
},
|
||||
{
|
||||
key: 'machine-status',
|
||||
label: 'Machine Status',
|
||||
route: '/maintenance/machine-status',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: MachineStatus
|
||||
},
|
||||
{
|
||||
key: 'server-logs',
|
||||
label: 'Server',
|
||||
route: '/maintenance/server-logs',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: ServerLogs
|
||||
}
|
||||
]
|
||||
|
|
@ -101,6 +117,7 @@ const tree = [
|
|||
key: 'settings',
|
||||
label: 'Settings',
|
||||
route: '/settings',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
get component() {
|
||||
return () => <Redirect to={this.children[0].route} />
|
||||
},
|
||||
|
|
@ -109,36 +126,42 @@ const tree = [
|
|||
key: namespaces.COMMISSIONS,
|
||||
label: 'Commissions',
|
||||
route: '/settings/commissions',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Commissions
|
||||
},
|
||||
{
|
||||
key: namespaces.LOCALE,
|
||||
label: 'Locales',
|
||||
route: '/settings/locale',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Locales
|
||||
},
|
||||
{
|
||||
key: namespaces.CASH_OUT,
|
||||
label: 'Cash-out',
|
||||
route: '/settings/cash-out',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Cashout
|
||||
},
|
||||
{
|
||||
key: namespaces.NOTIFICATIONS,
|
||||
label: 'Notifications',
|
||||
route: '/settings/notifications',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Notifications
|
||||
},
|
||||
{
|
||||
key: 'services',
|
||||
label: '3rd party services',
|
||||
route: '/settings/3rd-party-services',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Services
|
||||
},
|
||||
{
|
||||
key: namespaces.WALLETS,
|
||||
label: 'Wallet',
|
||||
route: '/settings/wallet-settings',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: WalletSettings
|
||||
},
|
||||
{
|
||||
|
|
@ -146,6 +169,7 @@ const tree = [
|
|||
label: 'Operator Info',
|
||||
route: '/settings/operator-info',
|
||||
title: 'Operator Information',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
get component() {
|
||||
return () => (
|
||||
<Redirect
|
||||
|
|
@ -161,24 +185,28 @@ const tree = [
|
|||
key: 'contact-info',
|
||||
label: 'Contact information',
|
||||
route: '/settings/operator-info/contact-info',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: ContactInfo
|
||||
},
|
||||
{
|
||||
key: 'receipt-printing',
|
||||
label: 'Receipt',
|
||||
route: '/settings/operator-info/receipt-printing',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: ReceiptPrinting
|
||||
},
|
||||
{
|
||||
key: 'coin-atm-radar',
|
||||
label: 'Coin ATM Radar',
|
||||
route: '/settings/operator-info/coin-atm-radar',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: CoinAtmRadar
|
||||
},
|
||||
{
|
||||
key: 'terms-conditions',
|
||||
label: 'Terms & Conditions',
|
||||
route: '/settings/operator-info/terms-conditions',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: TermsConditions
|
||||
}
|
||||
]
|
||||
|
|
@ -189,6 +217,7 @@ const tree = [
|
|||
key: 'compliance',
|
||||
label: 'Compliance',
|
||||
route: '/compliance',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
get component() {
|
||||
return () => <Redirect to={this.children[0].route} />
|
||||
},
|
||||
|
|
@ -197,18 +226,21 @@ const tree = [
|
|||
key: 'triggers',
|
||||
label: 'Triggers',
|
||||
route: '/compliance/triggers',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Triggers
|
||||
},
|
||||
{
|
||||
key: 'customers',
|
||||
label: 'Customers',
|
||||
route: '/compliance/customers',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Customers
|
||||
},
|
||||
{
|
||||
key: 'blacklist',
|
||||
label: 'Blacklist',
|
||||
route: '/compliance/blacklist',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: Blacklist
|
||||
},
|
||||
{
|
||||
|
|
@ -220,9 +252,35 @@ const tree = [
|
|||
{
|
||||
key: 'customer',
|
||||
route: '/compliance/customer/:id',
|
||||
allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
|
||||
component: CustomerProfile
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'system',
|
||||
label: 'System',
|
||||
route: '/system',
|
||||
allowedRoles: [ROLES.SUPERUSER],
|
||||
get component() {
|
||||
return () => <Redirect to={this.children[0].route} />
|
||||
},
|
||||
children: [
|
||||
{
|
||||
key: 'user-management',
|
||||
label: 'User Management',
|
||||
route: '/system/user-management',
|
||||
allowedRoles: [ROLES.SUPERUSER],
|
||||
component: UserManagement
|
||||
},
|
||||
{
|
||||
key: 'session-management',
|
||||
label: 'Session Management',
|
||||
route: '/system/session-management',
|
||||
allowedRoles: [ROLES.SUPERUSER],
|
||||
component: SessionManagement
|
||||
}
|
||||
]
|
||||
}
|
||||
// {
|
||||
// key: 'system',
|
||||
|
|
@ -276,13 +334,32 @@ const Routes = () => {
|
|||
|
||||
const history = useHistory()
|
||||
const location = useLocation()
|
||||
const { wizardTested, userData } = useContext(AppContext)
|
||||
|
||||
const { wizardTested } = useContext(AppContext)
|
||||
|
||||
const dontTriggerPages = ['/404', '/register', '/wizard']
|
||||
const dontTriggerPages = [
|
||||
'/404',
|
||||
'/register',
|
||||
'/wizard',
|
||||
'/login',
|
||||
'/register',
|
||||
'/resetpassword',
|
||||
'/reset2fa'
|
||||
]
|
||||
|
||||
if (!wizardTested && !R.contains(location.pathname)(dontTriggerPages)) {
|
||||
history.push('/wizard')
|
||||
return null
|
||||
}
|
||||
|
||||
const getFilteredRoutes = () => {
|
||||
if (!userData) return []
|
||||
|
||||
return flattened.filter(value => {
|
||||
const keys = value.allowedRoles.map(v => {
|
||||
return v.key
|
||||
})
|
||||
return R.includes(userData.role, keys)
|
||||
})
|
||||
}
|
||||
|
||||
const Transition = location.state ? Slide : Fade
|
||||
|
|
@ -300,10 +377,10 @@ const Routes = () => {
|
|||
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to={{ pathname: '/dashboard' }} />
|
||||
</Route>
|
||||
<Route path={'/dashboard'}>
|
||||
<PrivateRoute exact path="/">
|
||||
<Redirect to={{ pathname: '/transactions' }} />
|
||||
</PrivateRoute>
|
||||
<PrivateRoute path={'/dashboard'}>
|
||||
<Transition
|
||||
className={classes.wrapper}
|
||||
{...transitionProps}
|
||||
|
|
@ -316,12 +393,15 @@ const Routes = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/machines" component={Machines} />
|
||||
<Route path="/wizard" component={Wizard} />
|
||||
<Route path="/register" component={AuthRegister} />
|
||||
</PrivateRoute>
|
||||
<PrivateRoute path="/machines" component={Machines} />
|
||||
<PrivateRoute path="/wizard" component={Wizard} />
|
||||
<Route path="/register" component={Register} />
|
||||
<PublicRoute path="/login" restricted component={Login} />
|
||||
<Route path="/resetpassword" component={ResetPassword} />
|
||||
<Route path="/reset2fa" component={Reset2FA} />
|
||||
{/* <Route path="/configmigration" component={ConfigMigration} /> */}
|
||||
{flattened.map(({ route, component: Page, key }) => (
|
||||
{getFilteredRoutes().map(({ route, component: Page, key }) => (
|
||||
<Route path={route} key={key}>
|
||||
<Transition
|
||||
className={classes.wrapper}
|
||||
|
|
@ -331,7 +411,9 @@ const Routes = () => {
|
|||
unmountOnExit
|
||||
children={
|
||||
<div className={classes.wrapper}>
|
||||
<Page name={key} />
|
||||
<PrivateRoute path={route} key={key}>
|
||||
<Page name={key} />
|
||||
</PrivateRoute>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue