diff --git a/apps/client/.babelrc.json b/apps/client/.babelrc.json
deleted file mode 100644
index 86efa43b..00000000
--- a/apps/client/.babelrc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "presets": [
- "@babel/preset-typescript",
- "@babel/preset-env",
- [
- "@nrwl/react/babel",
- {
- "runtime": "automatic",
- "useBuiltIns": "usage"
- }
- ]
- ],
- "plugins": []
-}
diff --git a/apps/client/.storybook/main.js b/apps/client/.storybook/main.js
deleted file mode 100644
index 2484425c..00000000
--- a/apps/client/.storybook/main.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const rootMain = require('../../../.storybook/main')
-
-module.exports = {
- ...rootMain,
- core: { ...rootMain.core, builder: 'webpack5' },
- stories: ['../**/*.stories.@(js|jsx|ts|tsx)'],
- addons: [...rootMain.addons, '@nrwl/react/plugins/storybook'],
- webpackFinal: async (config, { configType }) => {
- // apply any global webpack configs that might have been specified in .storybook/main.js
- if (rootMain.webpackFinal) {
- config = await rootMain.webpackFinal(config, { configType })
- }
-
- // add your own webpack tweaks if needed
-
- return config
- },
-}
diff --git a/apps/client/components/Maintenance.stories.tsx b/apps/client/components/Maintenance.stories.tsx
deleted file mode 100644
index 468d8d2a..00000000
--- a/apps/client/components/Maintenance.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { Story, Meta } from '@storybook/react'
-import Maintenance from './Maintenance.tsx'
-import React from 'react'
-
-export default {
- title: 'components/Maintenance.tsx',
- component: Maintenance,
-} as Meta
-
-const Template: Story = () => {
- return (
- <>
-
- >
- )
-}
-
-export const Base = Template.bind({})
diff --git a/apps/client/pages/api/auth/[...nextauth].ts b/apps/client/pages/api/auth/[...nextauth].ts
index 485d75cb..96fd8d32 100644
--- a/apps/client/pages/api/auth/[...nextauth].ts
+++ b/apps/client/pages/api/auth/[...nextauth].ts
@@ -37,7 +37,7 @@ async function validateCredentials(credentials: any): Promise {
- const { firstName, lastName, email, password, isAdmin } = credentials
+ const { firstName, lastName, email, password, role } = credentials
if (!firstName || !lastName) {
throw new Error('Both first name and last name are required.')
}
const isDevelopment = process.env.NODE_ENV === 'development'
+
+ let userRole: AuthUserRole
+
+ if (role === AuthUserRole.admin && isDevelopment) {
+ userRole = AuthUserRole.admin
+ } else if (role === AuthUserRole.ci) {
+ userRole = AuthUserRole.ci
+ } else {
+ userRole = AuthUserRole.user
+ }
+
const hashedPassword = await bcrypt.hash(password, 10)
return createAuthUser({
firstName,
@@ -69,7 +80,7 @@ async function createNewAuthUser(credentials: {
name: `${firstName} ${lastName}`,
email,
password: hashedPassword,
- role: isAdmin && isDevelopment ? AuthUserRole.admin : AuthUserRole.user,
+ role: userRole,
})
}
@@ -99,14 +110,11 @@ export const authOptions = {
lastName: { label: 'Last name', type: 'text', placeholder: 'Last name' },
email: { label: 'Email', type: 'email', placeholder: 'hello@maybe.co' },
password: { label: 'Password', type: 'password' },
- isAdmin: { label: 'Admin', type: 'checkbox' },
+ role: { label: 'Admin', type: 'text' },
},
async authorize(credentials) {
- const { firstName, lastName, email, password, isAdmin } = await validateCredentials(
- {
- ...credentials,
- isAdmin: Boolean(credentials?.isAdmin),
- }
+ const { firstName, lastName, email, password, role } = await validateCredentials(
+ credentials
)
const existingUser = await getAuthUserByEmail(email)
@@ -123,7 +131,7 @@ export const authOptions = {
throw new Error('Invalid credentials provided.')
}
- return createNewAuthUser({ firstName, lastName, email, password, isAdmin })
+ return createNewAuthUser({ firstName, lastName, email, password, role })
},
}),
],
diff --git a/apps/client/pages/register.tsx b/apps/client/pages/register.tsx
index 6a0a64f5..fed963a0 100644
--- a/apps/client/pages/register.tsx
+++ b/apps/client/pages/register.tsx
@@ -15,7 +15,7 @@ export default function RegisterPage() {
const [isValid, setIsValid] = useState(false)
const [errorMessage, setErrorMessage] = useState(null)
const [isLoading, setIsLoading] = useState(false)
- const [isAdmin, setIsAdmin] = useState(false)
+ const [isAdmin, setIsAdmin] = useState(false)
const { data: session } = useSession()
const router = useRouter()
@@ -39,7 +39,7 @@ export default function RegisterPage() {
password,
firstName,
lastName,
- isAdmin,
+ role: isAdmin ? 'admin' : 'user',
redirect: false,
})
diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json
index b836c388..5f8e9471 100644
--- a/apps/client/tsconfig.json
+++ b/apps/client/tsconfig.json
@@ -27,14 +27,7 @@
"next-env.d.ts",
".next/types/**/*.ts"
],
- "exclude": [
- "node_modules",
- "jest.config.ts",
- "**/*.stories.ts",
- "**/*.stories.js",
- "**/*.stories.jsx",
- "**/*.stories.tsx"
- ],
+ "exclude": ["node_modules", "jest.config.ts"],
"references": [
{
"path": "./.storybook/tsconfig.json"
diff --git a/apps/e2e/src/support/commands.ts b/apps/e2e/src/support/commands.ts
index 676fb30b..be619a25 100644
--- a/apps/e2e/src/support/commands.ts
+++ b/apps/e2e/src/support/commands.ts
@@ -4,6 +4,7 @@ declare namespace Cypress {
interface Chainable {
login(): Chainable
apiRequest(...params: Parameters): Chainable
+ nextApiRequest(...params: Parameters): Chainable
getByTestId(...parameters: Parameters): Chainable
selectDate(date: Date): Chainable
preserveAccessToken(): Chainable
@@ -28,9 +29,22 @@ Cypress.Commands.add('apiRequest', ({ url, headers = {}, ...options }, ...rest)
)
})
+Cypress.Commands.add('nextApiRequest', ({ url, headers = {}, ...options }, ...rest) => {
+ return cy.request(
+ {
+ url: `${Cypress.env('NEXTAUTH_URL')}/${url}`,
+ headers: {
+ ...headers,
+ },
+ ...options,
+ },
+ ...rest
+ )
+})
+
Cypress.Commands.add('login', () => {
cy.visit('/login')
- cy.get('input[name="email"]').type('bond@007.com')
+ cy.get('input[name="email"]').type('test@test.com')
cy.get('input[name="password"]').type('TestPassword123')
cy.get('button[type="submit"]').click()
//eslint-disable-next-line cypress/no-unnecessary-waiting
diff --git a/apps/e2e/src/support/e2e.ts b/apps/e2e/src/support/e2e.ts
index be528804..896a1612 100644
--- a/apps/e2e/src/support/e2e.ts
+++ b/apps/e2e/src/support/e2e.ts
@@ -1,10 +1,36 @@
import './commands'
beforeEach(() => {
- // Login
- cy.login()
+ cy.request({
+ method: 'GET',
+ url: 'api/auth/csrf',
+ }).then((response) => {
+ let csrfCookies = response.headers['set-cookie']
+ if (Array.isArray(csrfCookies) && csrfCookies.length > 1) {
+ csrfCookies = csrfCookies.map((cookie) => cookie.split(';')[0]).join('; ')
+ }
+ const csrfToken = response.body.csrfToken.trim()
- // Delete the current user to wipe all data before test
+ cy.request({
+ method: 'POST',
+ form: true,
+ headers: {
+ Cookie: `${csrfCookies}`,
+ },
+ url: `api/auth/callback/credentials`,
+ body: {
+ email: 'test@test.com',
+ firstName: 'Test',
+ lastName: 'User',
+ password: 'TestPassword123',
+ role: 'ci',
+ csrfToken: csrfToken,
+ json: 'true',
+ },
+ }).then((response) => {
+ expect(response.status).to.equal(200)
+ })
+ })
cy.apiRequest({
method: 'POST',
url: 'e2e/reset',
@@ -12,7 +38,5 @@ beforeEach(() => {
}).then((response) => {
expect(response.status).to.equal(200)
})
-
- // Go back to dashboard
cy.visit('/')
})
diff --git a/apps/server/src/app/routes/e2e.router.ts b/apps/server/src/app/routes/e2e.router.ts
index 5b9edb29..c82bcfcc 100644
--- a/apps/server/src/app/routes/e2e.router.ts
+++ b/apps/server/src/app/routes/e2e.router.ts
@@ -1,4 +1,5 @@
import type { OnboardingState } from '@maybe-finance/server/features'
+import { AuthUserRole } from '@prisma/client'
import { Router } from 'express'
import { DateTime } from 'luxon'
import { z } from 'zod'
@@ -6,13 +7,13 @@ import endpoint from '../lib/endpoint'
const router = Router()
-const testUserId = 'test_ec3ee8a4-fa01-4f11-8ac5-9c49dd7fbae4'
-
router.use((req, res, next) => {
- if (req.user?.sub === testUserId) {
+ const role = req.user?.role
+
+ if (role === AuthUserRole.admin || role === AuthUserRole.ci) {
next()
} else {
- res.status(401).send('Route only available to test users')
+ res.status(401).send('Route only available to CIUser and Admin roles')
}
})
@@ -47,14 +48,15 @@ router.post(
trialLapsed: z.boolean().default(false),
}),
resolve: async ({ ctx, input }) => {
+ const user = ctx.user!
await ctx.prisma.$transaction([
- ctx.prisma.$executeRaw`DELETE FROM "user" WHERE auth_id=${testUserId};`,
+ ctx.prisma.$executeRaw`DELETE FROM "user" WHERE auth_id=${user.authId};`,
ctx.prisma.user.create({
data: {
- authId: testUserId,
- email: 'bond@007.com',
- firstName: 'James',
- lastName: 'Bond',
+ authId: user.authId,
+ email: user.email,
+ firstName: user.firstName,
+ lastName: user.lastName,
dob: new Date('1990-01-01'),
linkAccountDismissedAt: new Date(), // ensures our auto-account link doesn't trigger
diff --git a/libs/server/features/src/account/insight.service.ts b/libs/server/features/src/account/insight.service.ts
index 116e588e..0e6f8d62 100644
--- a/libs/server/features/src/account/insight.service.ts
+++ b/libs/server/features/src/account/insight.service.ts
@@ -687,7 +687,7 @@ export class InsightService implements IInsightService {
INNER JOIN security s ON s.id = h.security_id
LEFT JOIN LATERAL (
SELECT
- asset_class AS "category"
+ s.asset_class AS "category"
) x ON TRUE
WHERE
h.account_id IN ${accountIds}
diff --git a/prisma/seed.ts b/prisma/seed.ts
index a8716316..0886640a 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -35,23 +35,7 @@ async function main() {
},
]
- const hashedPassword = await bcrypt.hash('TestPassword123', 10)
-
await prisma.$transaction([
- // create testing auth user
- prisma.authUser.upsert({
- where: {
- id: 'test_ec3ee8a4-fa01-4f11-8ac5-9c49dd7fbae4',
- },
- create: {
- id: 'test_ec3ee8a4-fa01-4f11-8ac5-9c49dd7fbae4',
- firstName: 'James',
- lastName: 'Bond',
- email: 'bond@007.com',
- password: hashedPassword,
- },
- update: {},
- }),
// create institution linked to provider institutions
...institutions.map(({ id, name, providers }) =>
prisma.institution.upsert({
diff --git a/workspace.json b/workspace.json
index 64b2eb15..ef681dc4 100644
--- a/workspace.json
+++ b/workspace.json
@@ -66,33 +66,6 @@
"options": {
"command": "node tools/scripts/triggerClientDeploy.js"
}
- },
- "storybook": {
- "executor": "@nrwl/storybook:storybook",
- "options": {
- "uiFramework": "@storybook/react",
- "port": 4400,
- "configDir": "apps/client/.storybook"
- },
- "configurations": {
- "ci": {
- "quiet": true
- }
- }
- },
- "build-storybook": {
- "executor": "@nrwl/storybook:build",
- "outputs": ["{options.outputDir}"],
- "options": {
- "uiFramework": "@storybook/react",
- "outputDir": "dist/storybook/client",
- "configDir": "apps/client/.storybook"
- },
- "configurations": {
- "ci": {
- "quiet": true
- }
- }
}
},
"tags": ["scope:app"]