0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-10 22:22:45 -05:00

refactor(core): split updatePasscode into increasePasscodeTryCount and consumePasscode (#1510)

This commit is contained in:
IceHe.xyz 2022-07-11 21:54:26 +08:00 committed by GitHub
parent 988157d586
commit f479a1566f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 48 deletions

View file

@ -5,11 +5,12 @@ import { mockConnector, mockMetadata } from '@/__mocks__';
import { getConnectorInstances } from '@/connectors';
import RequestError from '@/errors/RequestError';
import {
consumePasscode,
deletePasscodesByIds,
findUnconsumedPasscodeByJtiAndType,
findUnconsumedPasscodesByJtiAndType,
increasePasscodeTryCount,
insertPasscode,
updatePasscode,
} from '@/queries/passcode';
import {
@ -39,7 +40,10 @@ const mockedInsertPasscode = insertPasscode as jest.MockedFunction<typeof insert
const mockedGetConnectorInstances = getConnectorInstances as jest.MockedFunction<
typeof getConnectorInstances
>;
const mockedUpdatePasscode = updatePasscode as jest.MockedFunction<typeof updatePasscode>;
const mockedConsumePasscode = consumePasscode as jest.MockedFunction<typeof consumePasscode>;
const mockedIncreasePasscodeTryCount = increasePasscodeTryCount as jest.MockedFunction<
typeof increasePasscodeTryCount
>;
beforeAll(() => {
mockedFindUnconsumedPasscodesByJtiAndType.mockResolvedValue([]);
@ -224,11 +228,7 @@ describe('verifyPasscode', () => {
it('should mark as consumed on successful verification', async () => {
mockedFindUnconsumedPasscodeByJtiAndType.mockResolvedValue(passcode);
await verifyPasscode(passcode.interactionJti, passcode.type, passcode.code, { phone: 'phone' });
expect(mockedUpdatePasscode).toHaveBeenCalledWith(
expect.objectContaining({
set: { consumed: true },
})
);
expect(mockedConsumePasscode).toHaveBeenCalledWith(passcode.id);
});
it('should fail when passcode not found', async () => {
@ -285,10 +285,6 @@ describe('verifyPasscode', () => {
await expect(
verifyPasscode(passcode.interactionJti, passcode.type, 'invalid', { phone: 'phone' })
).rejects.toThrow(new RequestError('passcode.code_mismatch'));
expect(mockedUpdatePasscode).toHaveBeenCalledWith(
expect.objectContaining({
set: { tryCount: passcode.tryCount + 1 },
})
);
expect(mockedIncreasePasscodeTryCount).toHaveBeenCalledWith(passcode.id);
});
});

View file

@ -5,11 +5,12 @@ import { getConnectorInstances } from '@/connectors';
import { ConnectorType, EmailConnectorInstance, SmsConnectorInstance } from '@/connectors/types';
import RequestError from '@/errors/RequestError';
import {
consumePasscode,
deletePasscodesByIds,
findUnconsumedPasscodeByJtiAndType,
findUnconsumedPasscodesByJtiAndType,
increasePasscodeTryCount,
insertPasscode,
updatePasscode,
} from '@/queries/passcode';
import assertThat from '@/utils/assert-that';
@ -106,13 +107,9 @@ export const verifyPasscode = async (
}
if (code !== passcode.code) {
await updatePasscode({
where: { id: passcode.id },
set: { tryCount: passcode.tryCount + 1 },
jsonbMode: 'merge',
});
await increasePasscodeTryCount(passcode.id);
throw new RequestError('passcode.code_mismatch');
}
await updatePasscode({ where: { id: passcode.id }, set: { consumed: true }, jsonbMode: 'merge' });
await consumePasscode(passcode.id);
};

View file

@ -16,7 +16,6 @@ import {
findUnconsumedPasscodeByJtiAndType,
findUnconsumedPasscodesByJtiAndType,
insertPasscode,
updatePasscode,
deletePasscodeById,
deletePasscodesByIds,
} from './passcode';
@ -94,32 +93,6 @@ describe('passcode query', () => {
await expect(insertPasscode(mockPasscode)).resolves.toEqual(mockPasscode);
});
it('updatePasscode', async () => {
const id = 'foo';
const tryCount = 3;
const expectSql = sql`
update ${table}
set ${fields.tryCount}=$1
where ${fields.id}=$2
returning *
`;
mockQuery.mockImplementationOnce(async (sql, values) => {
expectSqlAssert(sql, expectSql.sql);
expect(values).toEqual([tryCount, id]);
return createMockQueryResult([{ ...mockPasscode, tryCount }]);
});
await expect(
updatePasscode({ where: { id }, set: { tryCount }, jsonbMode: 'merge' })
).resolves.toEqual({
...mockPasscode,
tryCount,
});
});
it('deletePasscodeById', async () => {
const id = 'foo';
const expectSql = sql`

View file

@ -2,7 +2,6 @@ import { PasscodeType, Passcode, Passcodes, CreatePasscode } from '@logto/schema
import { sql } from 'slonik';
import { buildInsertInto } from '@/database/insert-into';
import { buildUpdateWhere } from '@/database/update-where';
import { convertToIdentifiers } from '@/database/utils';
import envSet from '@/env-set';
import { DeletionError } from '@/errors/SlonikError';
@ -27,7 +26,21 @@ export const insertPasscode = buildInsertInto<CreatePasscode, Passcode>(Passcode
returning: true,
});
export const updatePasscode = buildUpdateWhere<CreatePasscode, Passcode>(Passcodes, true);
export const consumePasscode = async (id: string) =>
envSet.pool.query<Passcode>(sql`
update ${table}
set ${fields.consumed}=true
where ${fields.id}=${sql`${id}`}
returning ${sql.join(Object.values(fields), sql`, `)}
`);
export const increasePasscodeTryCount = async (id: string) =>
envSet.pool.query<Passcode>(sql`
update ${table}
set ${fields.tryCount}=${fields.tryCount}+1
where ${fields.id}=${sql`${id}`}
returning ${sql.join(Object.values(fields), sql`, `)}
`);
export const deletePasscodeById = async (id: string) => {
const { rowCount } = await envSet.pool.query(sql`