mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-11 10:03:51 +00:00
Ensure forwardCredentials is included when exporting servers as CSV
This commit is contained in:
@@ -45,4 +45,12 @@ export const isNotFoundServer = (server: SelectedServer): server is NotFoundServ
|
|||||||
|
|
||||||
export const getServerId = (server: SelectedServer) => (isServerWithId(server) ? server.id : '');
|
export const getServerId = (server: SelectedServer) => (isServerWithId(server) ? server.id : '');
|
||||||
|
|
||||||
export const serverWithIdToServerData = ({ name, url, apiKey }: ServerWithId): ServerData => ({ name, url, apiKey });
|
/**
|
||||||
|
* Expose values that represent provided server, in a way that can be serialized in JSON or CSV strings.
|
||||||
|
*/
|
||||||
|
export const serializeServer = ({ name, url, apiKey, forwardCredentials }: ServerData): Record<string, string> => ({
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
apiKey,
|
||||||
|
forwardCredentials: forwardCredentials ? 'true' : 'false',
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,24 +2,27 @@ import type { JsonToCsv } from '../../utils/helpers/csvjson';
|
|||||||
import { saveCsv } from '../../utils/helpers/files';
|
import { saveCsv } from '../../utils/helpers/files';
|
||||||
import type { LocalStorage } from '../../utils/services/LocalStorage';
|
import type { LocalStorage } from '../../utils/services/LocalStorage';
|
||||||
import type { ServersMap } from '../data';
|
import type { ServersMap } from '../data';
|
||||||
import { serverWithIdToServerData } from '../data';
|
import { serializeServer } from '../data';
|
||||||
|
|
||||||
const SERVERS_FILENAME = 'shlink-servers.csv';
|
const SERVERS_FILENAME = 'shlink-servers.csv';
|
||||||
|
|
||||||
export class ServersExporter {
|
export class ServersExporter {
|
||||||
public constructor(
|
readonly #storage: LocalStorage;
|
||||||
private readonly storage: LocalStorage,
|
readonly #window: Window;
|
||||||
private readonly window: Window,
|
readonly #jsonToCsv: JsonToCsv;
|
||||||
private readonly jsonToCsv: JsonToCsv,
|
|
||||||
) {}
|
public constructor(storage: LocalStorage, window: Window, jsonToCsv: JsonToCsv) {
|
||||||
|
this.#storage = storage;
|
||||||
|
this.#window = window;
|
||||||
|
this.#jsonToCsv = jsonToCsv;
|
||||||
|
}
|
||||||
|
|
||||||
public readonly exportServers = async () => {
|
public readonly exportServers = async () => {
|
||||||
const servers = Object.values(this.storage.get<ServersMap>('servers') ?? {}).map(serverWithIdToServerData);
|
const servers = Object.values(this.#storage.get<ServersMap>('servers') ?? {}).map(serializeServer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const csv = this.jsonToCsv(servers);
|
const csv = this.#jsonToCsv(servers);
|
||||||
|
saveCsv(this.#window, csv, SERVERS_FILENAME);
|
||||||
saveCsv(this.window, csv, SERVERS_FILENAME);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// FIXME Handle error
|
// FIXME Handle error
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|||||||
@@ -1,27 +1,35 @@
|
|||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
|
import type { ServersMap } from '../../../src/servers/data';
|
||||||
|
import { serializeServer } from '../../../src/servers/data';
|
||||||
import { ServersExporter } from '../../../src/servers/services/ServersExporter';
|
import { ServersExporter } from '../../../src/servers/services/ServersExporter';
|
||||||
import type { LocalStorage } from '../../../src/utils/services/LocalStorage';
|
import type { LocalStorage } from '../../../src/utils/services/LocalStorage';
|
||||||
import { appendChild, removeChild, windowMock } from '../../__mocks__/Window.mock';
|
import { appendChild, removeChild, windowMock } from '../../__mocks__/Window.mock';
|
||||||
|
|
||||||
describe('ServersExporter', () => {
|
describe('ServersExporter', () => {
|
||||||
|
const servers: ServersMap = {
|
||||||
|
abc123: {
|
||||||
|
id: 'abc123',
|
||||||
|
name: 'foo',
|
||||||
|
url: 'https://foo.com',
|
||||||
|
apiKey: 'foo_api_key',
|
||||||
|
autoConnect: true,
|
||||||
|
},
|
||||||
|
def456: {
|
||||||
|
id: 'def456',
|
||||||
|
name: 'bar',
|
||||||
|
url: 'https://bar.com',
|
||||||
|
apiKey: 'bar_api_key',
|
||||||
|
forwardCredentials: true,
|
||||||
|
autoConnect: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
const storageMock = fromPartial<LocalStorage>({
|
const storageMock = fromPartial<LocalStorage>({
|
||||||
get: vi.fn(() => ({
|
get: vi.fn(() => servers as any),
|
||||||
abc123: {
|
|
||||||
id: 'abc123',
|
|
||||||
name: 'foo',
|
|
||||||
autoConnect: true,
|
|
||||||
},
|
|
||||||
def456: {
|
|
||||||
id: 'def456',
|
|
||||||
name: 'bar',
|
|
||||||
autoConnect: false,
|
|
||||||
},
|
|
||||||
} as any)),
|
|
||||||
});
|
});
|
||||||
const erroneousToCsv = vi.fn(() => {
|
const erroneousToCsv = vi.fn(() => {
|
||||||
throw new Error('');
|
throw new Error('');
|
||||||
});
|
});
|
||||||
const createCsvjsonMock = (throwError = false) => (throwError ? erroneousToCsv : vi.fn(() => ''));
|
const createJsonToCsvMock = (throwError = false) => (throwError ? erroneousToCsv : vi.fn(() => ''));
|
||||||
|
|
||||||
describe('exportServers', () => {
|
describe('exportServers', () => {
|
||||||
const error = vi.fn();
|
const error = vi.fn();
|
||||||
@@ -34,8 +42,8 @@ describe('ServersExporter', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('logs an error if something fails', () => {
|
it('logs an error if something fails', () => {
|
||||||
const csvjsonMock = createCsvjsonMock(true);
|
const jsonToCsvMock = createJsonToCsvMock(true);
|
||||||
const exporter = new ServersExporter(storageMock, windowMock, csvjsonMock);
|
const exporter = new ServersExporter(storageMock, windowMock, jsonToCsvMock);
|
||||||
|
|
||||||
exporter.exportServers();
|
exporter.exportServers();
|
||||||
|
|
||||||
@@ -44,7 +52,8 @@ describe('ServersExporter', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('makes use of download link API', () => {
|
it('makes use of download link API', () => {
|
||||||
const exporter = new ServersExporter(storageMock, windowMock, createCsvjsonMock());
|
const jsonToCsvMock = createJsonToCsvMock();
|
||||||
|
const exporter = new ServersExporter(storageMock, windowMock, jsonToCsvMock);
|
||||||
const { document: { createElement } } = windowMock;
|
const { document: { createElement } } = windowMock;
|
||||||
|
|
||||||
exporter.exportServers();
|
exporter.exportServers();
|
||||||
@@ -53,6 +62,7 @@ describe('ServersExporter', () => {
|
|||||||
expect(createElement).toHaveBeenCalledTimes(1);
|
expect(createElement).toHaveBeenCalledTimes(1);
|
||||||
expect(appendChild).toHaveBeenCalledTimes(1);
|
expect(appendChild).toHaveBeenCalledTimes(1);
|
||||||
expect(removeChild).toHaveBeenCalledTimes(1);
|
expect(removeChild).toHaveBeenCalledTimes(1);
|
||||||
|
expect(jsonToCsvMock).toHaveBeenCalledWith(Object.values(servers).map(serializeServer));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user