Update ServersImporter so that it takes into consideration forwardCredentials

This commit is contained in:
Alejandro Celaya 2025-04-20 13:06:09 +02:00
parent 4895cbb9dc
commit d65eafd37f
3 changed files with 56 additions and 28 deletions

View File

@ -54,3 +54,22 @@ export const serializeServer = ({ name, url, apiKey, forwardCredentials }: Serve
apiKey, apiKey,
forwardCredentials: forwardCredentials ? 'true' : 'false', forwardCredentials: forwardCredentials ? 'true' : 'false',
}); });
const validateServerData = (server: any): server is ServerData =>
typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string';
/**
* Provided a record, it picks the right properties to build a ServerData object.
* @throws Error If any of the required ServerData properties is missing.
*/
export const deserializeServer = (potentialServer: Record<string, unknown>): ServerData => {
const { forwardCredentials, ...serverData } = potentialServer;
if (!validateServerData(serverData)) {
throw new Error('Server is missing required "url", "apiKey" and/or "name" properties');
}
return {
...serverData,
forwardCredentials: forwardCredentials === 'true',
};
};

View File

@ -1,14 +1,20 @@
import type { CsvToJson } from '../../utils/helpers/csvjson'; import type { CsvToJson } from '../../utils/helpers/csvjson';
import type { ServerData } from '../data'; import type { ServerData } from '../data';
import { deserializeServer } from '../data';
const validateServer = (server: any): server is ServerData => const validateAndDeserializeServers = (servers: unknown): ServerData[] => {
typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string'; if (!Array.isArray(servers)) {
throw new Error('Provided file does not have the right format.');
const validateServers = (servers: any): servers is ServerData[] => }
Array.isArray(servers) && servers.every(validateServer); return servers.map(deserializeServer);
};
export class ServersImporter { export class ServersImporter {
public constructor(private readonly csvToJson: CsvToJson) {} readonly #csvToJson: CsvToJson;
public constructor(csvToJson: CsvToJson) {
this.#csvToJson = csvToJson;
}
public async importServersFromFile(file: File | null | undefined): Promise<ServerData[]> { public async importServersFromFile(file: File | null | undefined): Promise<ServerData[]> {
if (!file) { if (!file) {
@ -16,12 +22,8 @@ export class ServersImporter {
} }
const content = await file.text(); const content = await file.text();
const servers = await this.csvToJson(content); const servers = await this.#csvToJson(content);
if (!validateServers(servers)) { return validateAndDeserializeServers(servers);
throw new Error('Provided file does not have the right format.');
}
return servers;
} }
} }

View File

@ -1,5 +1,5 @@
import { fromPartial } from '@total-typescript/shoehorn'; import { fromPartial } from '@total-typescript/shoehorn';
import type { RegularServer } from '../../../src/servers/data'; import type { RegularServer, ServerData } from '../../../src/servers/data';
import { ServersImporter } from '../../../src/servers/services/ServersImporter'; import { ServersImporter } from '../../../src/servers/services/ServersImporter';
describe('ServersImporter', () => { describe('ServersImporter', () => {
@ -25,20 +25,24 @@ describe('ServersImporter', () => {
}); });
it.each([ it.each([
[{}], { parsedObject: {}, expectedError: 'Provided file does not have the right format.' },
[undefined], { parsedObject: undefined, expectedError: 'Provided file does not have the right format.' },
[[{ foo: 'bar' }]], {
[ parsedObject: [{ foo: 'bar' }],
[ expectedError: 'Server is missing required "url", "apiKey" and/or "name" properties',
},
{
parsedObject: [
{ {
url: 1, url: 1,
apiKey: 1, apiKey: 1,
name: 1, name: 1,
}, },
], ],
], expectedError: 'Server is missing required "url", "apiKey" and/or "name" properties',
[ },
[ {
parsedObject: [
{ {
url: 'foo', url: 'foo',
apiKey: 'foo', apiKey: 'foo',
@ -46,26 +50,29 @@ describe('ServersImporter', () => {
}, },
{ bar: 'foo' }, { bar: 'foo' },
], ],
], expectedError: 'Server is missing required "url", "apiKey" and/or "name" properties',
])('rejects with error if provided file does not parse to valid list of servers', async (parsedObject) => { },
])('rejects with error if provided file does not parse to valid list of servers', async ({
parsedObject,
expectedError,
}) => {
csvjsonMock.mockResolvedValue(parsedObject); csvjsonMock.mockResolvedValue(parsedObject);
await expect(importer.importServersFromFile(fileMock())).rejects.toEqual(new Error(expectedError));
await expect(importer.importServersFromFile(fileMock())).rejects.toEqual(
new Error('Provided file does not have the right format.'),
);
}); });
it('reads file when a CSV containing valid servers is provided', async () => { it('reads file when a CSV containing valid servers is provided', async () => {
const expectedServers = [ const expectedServers: Required<ServerData>[] = [
{ {
url: 'foo', url: 'foo',
apiKey: 'foo', apiKey: 'foo',
name: 'foo', name: 'foo',
forwardCredentials: false,
}, },
{ {
url: 'bar', url: 'bar',
apiKey: 'bar', apiKey: 'bar',
name: 'bar', name: 'bar',
forwardCredentials: false,
}, },
]; ];