Skip to content

Commit 6901c24

Browse files
committed
refactors and simplifies password change epic
1 parent 5e254d8 commit 6901c24

File tree

3 files changed

+64
-91
lines changed

3 files changed

+64
-91
lines changed

src/shared/modules/connections/connectionsDuck.test.ts

+17-30
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import {
2828
DONE as DISCOVERY_DONE,
2929
updateDiscoveryConnection
3030
} from 'shared/modules/discovery/discoveryDuck'
31-
import forceResetPasswordQueryHelper from './forceResetPasswordQueryHelper'
32-
import { buildTxFunctionByMode } from 'services/bolt/boltHelpers'
31+
import forceResetPasswordQueryHelper, {
32+
MultiDatabaseNotSupportedError
33+
} from './forceResetPasswordQueryHelper'
3334

3435
jest.mock('services/bolt/bolt', () => {
3536
return {
@@ -39,14 +40,6 @@ jest.mock('services/bolt/bolt', () => {
3940
}
4041
})
4142

42-
jest.mock('services/bolt/boltHelpers', () => {
43-
const orig = jest.requireActual('services/bolt/boltHelpers')
44-
return {
45-
...orig,
46-
buildTxFunctionByMode: jest.fn()
47-
}
48-
})
49-
5043
describe('connections reducer', () => {
5144
test('handles connections.SET_ACTIVE', () => {
5245
const initialState: any = {
@@ -505,10 +498,12 @@ describe('handleForcePasswordChangeEpic', () => {
505498
)
506499

507500
const mockSessionClose = jest.fn()
501+
const mockSessionExecuteWrite = jest.fn()
508502

509503
const mockDriver = {
510504
session: jest.fn().mockReturnValue({
511-
close: mockSessionClose
505+
close: mockSessionClose,
506+
executeWrite: mockSessionExecuteWrite
512507
}),
513508
close: jest.fn().mockReturnValue(true)
514509
}
@@ -576,9 +571,7 @@ describe('handleForcePasswordChangeEpic', () => {
576571

577572
test('handleForcePasswordChangeEpic resolves when successfully executing cypher query', () => {
578573
// Given
579-
;(buildTxFunctionByMode as jest.Mock).mockReturnValue(() =>
580-
Promise.resolve()
581-
)
574+
mockSessionExecuteWrite.mockResolvedValue(true)
582575

583576
const p = new Promise<void>((resolve, reject) => {
584577
bus.take($$responseChannel, currentAction => {
@@ -632,11 +625,11 @@ describe('handleForcePasswordChangeEpic', () => {
632625

633626
test('handleForcePasswordChangeEpic resolves with an error if cypher query fails', () => {
634627
// Given
635-
;(buildTxFunctionByMode as jest.Mock)
636-
.mockReturnValueOnce(() =>
637-
Promise.reject(new Error('A password must be at least 8 characters.'))
628+
mockSessionExecuteWrite
629+
.mockRejectedValueOnce(
630+
new Error('A password must be at least 8 characters.')
638631
)
639-
.mockReturnValue(() => Promise.resolve())
632+
.mockResolvedValue(true)
640633

641634
const p = new Promise<void>((resolve, reject) => {
642635
bus.take($$responseChannel, currentAction => {
@@ -682,11 +675,9 @@ describe('handleForcePasswordChangeEpic', () => {
682675

683676
test('handleForcePasswordChangeEpic resolves when successfully falling back to dbms function call', () => {
684677
// Given
685-
;(buildTxFunctionByMode as jest.Mock)
686-
.mockReturnValueOnce(() =>
687-
Promise.reject(new Error("Invalid input 'A': expected <init>"))
688-
)
689-
.mockReturnValue(() => Promise.resolve())
678+
mockSessionExecuteWrite
679+
.mockRejectedValueOnce(new MultiDatabaseNotSupportedError())
680+
.mockResolvedValue(true)
690681

691682
const p = new Promise<void>((resolve, reject) => {
692683
bus.take($$responseChannel, currentAction => {
@@ -740,13 +731,9 @@ describe('handleForcePasswordChangeEpic', () => {
740731

741732
test('handleForcePasswordChangeEpic resolves with an error if dbms function call fails', () => {
742733
// Given
743-
;(buildTxFunctionByMode as jest.Mock)
744-
.mockReturnValueOnce(() =>
745-
Promise.reject(new Error("Invalid input 'A': expected <init>"))
746-
)
747-
.mockReturnValue(() =>
748-
Promise.reject(new Error('A password must be at least 8 characters.'))
749-
)
734+
mockSessionExecuteWrite
735+
.mockRejectedValueOnce(new MultiDatabaseNotSupportedError())
736+
.mockRejectedValue(new Error('A password must be at least 8 characters.'))
750737

751738
const p = new Promise<void>((resolve, reject) => {
752739
bus.take($$responseChannel, currentAction => {

src/shared/modules/connections/connectionsDuck.ts

+30-48
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ import { NEO4J_CLOUD_DOMAINS } from 'shared/modules/settings/settingsDuck'
4040
import { isCloudHost } from 'shared/services/utils'
4141
import { fetchMetaData } from '../dbMeta/dbMetaDuck'
4242
import { isError } from 'shared/utils/typeguards'
43-
import forceResetPasswordQueryHelper from './forceResetPasswordQueryHelper'
43+
import forceResetPasswordQueryHelper, {
44+
MultiDatabaseNotSupportedError
45+
} from './forceResetPasswordQueryHelper'
4446

4547
export const NAME = 'connections'
4648
export const SET_ACTIVE = 'connections/SET_ACTIVE'
@@ -949,6 +951,22 @@ export const handleForcePasswordChangeEpic = (some$: any) =>
949951
if (!action.$$responseChannel) return Rx.Observable.of(null)
950952

951953
return new Promise(resolve => {
954+
const resolveResponse = (error?: Error) => {
955+
resolve({
956+
type: action.$$responseChannel,
957+
success: error === undefined,
958+
...(error === undefined
959+
? {
960+
result: {
961+
meta: action.host
962+
}
963+
}
964+
: {
965+
error
966+
})
967+
})
968+
}
969+
952970
bolt
953971
.directConnect(
954972
action,
@@ -958,64 +976,28 @@ export const handleForcePasswordChangeEpic = (some$: any) =>
958976
)
959977
.then(async driver => {
960978
try {
961-
const res = await forceResetPasswordQueryHelper
979+
const result = await forceResetPasswordQueryHelper
962980
.executeAlterCurrentUserQuery(driver, action)
963-
.then((res: any) => {
964-
resolve({
965-
type: action.$$responseChannel,
966-
success: true,
967-
result: {
968-
...res,
969-
meta: action.host
970-
}
971-
})
972-
})
973-
.catch(e => {
974-
return e
975-
})
981+
.then(() => resolveResponse())
982+
.catch(error => error)
976983

977-
if (isError(res)) {
978-
if (
979-
/(Invalid input 'A': expected <init>)/.test(res.message)
980-
) {
984+
if (isError(result)) {
985+
if (result instanceof MultiDatabaseNotSupportedError) {
986+
// If we get a multi database not supported error, fall back to the legacy function
981987
await forceResetPasswordQueryHelper
982988
.executeCallChangePasswordQuery(driver, action)
983-
.then((res: any) => {
984-
resolve({
985-
type: action.$$responseChannel,
986-
success: true,
987-
result: {
988-
...res,
989-
meta: action.host
990-
}
991-
})
992-
})
993-
.catch(e =>
994-
resolve({
995-
type: action.$$responseChannel,
996-
success: false,
997-
error: e
998-
})
999-
)
989+
.then(() => resolveResponse())
990+
.catch(resolveResponse)
1000991
} else {
1001-
resolve({
1002-
type: action.$$responseChannel,
1003-
success: false,
1004-
error: res
1005-
})
992+
// Otherwise, return the error for the UI to handle e.g. invalid password
993+
resolveResponse(result)
1006994
}
1007995
}
1008996
} finally {
1009997
driver.close()
1010998
}
1011999
})
1012-
.catch(e =>
1013-
resolve({
1014-
type: action.$$responseChannel,
1015-
success: false,
1016-
error: e
1017-
})
1018-
)
1000+
.catch(resolveResponse)
10191001
})
10201002
}
10211003
)

src/shared/modules/connections/forceResetPasswordQueryHelper.ts

+17-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { Driver } from 'neo4j-driver'
33
import { userActionTxMetadata } from 'services/bolt/txMetadata'
44
import { Connection } from './connectionsDuck'
55
import { SYSTEM_DB } from '../dbMeta/dbMetaDuck'
6-
import { buildTxFunctionByMode } from 'services/bolt/boltHelpers'
6+
import { isError } from 'shared/utils/typeguards'
7+
8+
const MULTIDATABASE_NOT_SUPPORTED_ERROR_MESSAGE =
9+
'Driver is connected to the database that does not support multiple databases.'
10+
11+
export class MultiDatabaseNotSupportedError extends Error {}
712

813
export default {
914
executePasswordResetQuery: async (
@@ -20,22 +25,21 @@ export default {
2025
...useDb
2126
})
2227

23-
const txFn = buildTxFunctionByMode(session)
24-
25-
txFn &&
26-
(await txFn(
27-
async (tx: { run: (input: string, parameters: unknown) => unknown }) =>
28-
await tx.run(action.query, action.parameters),
28+
try {
29+
await session.executeWrite(
30+
tx => tx.run(action.query, action.parameters),
2931
{
3032
metadata
3133
}
3234
)
33-
.catch(e => {
34-
throw e
35-
})
36-
.finally(() => {
37-
session.close()
38-
}))
35+
} catch (e) {
36+
throw isError(e) &&
37+
e.message.startsWith(MULTIDATABASE_NOT_SUPPORTED_ERROR_MESSAGE)
38+
? new MultiDatabaseNotSupportedError(e.message)
39+
: e
40+
} finally {
41+
session.close()
42+
}
3943
},
4044
/**
4145
* Executes a query to change the user's password using Cypher available

0 commit comments

Comments
 (0)