CI / Generate TypeScript types (push) Successful in 9s
CI / Server unit tests (push) Successful in 21s
CI / Build server (push) Successful in 25s
CI / Build client (push) Successful in 37s
CI / Playwright E2E tests (push) Successful in 1m18s
CI / Build and push Docker image (push) Successful in 39s
CI / Notify (push) Successful in 2s
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import { Store } from "../../types/gen/types.gen";
|
|
import getStorage from "./storage";
|
|
|
|
const storage = getStorage();
|
|
const STORES_KEY = 'stores';
|
|
|
|
/**
|
|
* Vrátí seznam povolených obchodů. Zachovává zpětnou kompatibilitu se starším
|
|
* formátem, kdy byly obchody uloženy jako pole řetězců (převede je na objekty).
|
|
*/
|
|
export async function getStores(): Promise<Store[]> {
|
|
const raw = await storage.getData<(string | Store)[]>(STORES_KEY);
|
|
if (!raw) {
|
|
return [];
|
|
}
|
|
return raw.map(s => (typeof s === 'string' ? { name: s } : s));
|
|
}
|
|
|
|
/**
|
|
* Přidá nový obchod do seznamu povolených.
|
|
*
|
|
* @param name název obchodu
|
|
* @param heslo admin heslo
|
|
* @param url volitelná URL na nabídku podniku
|
|
*/
|
|
export async function addStore(name: string, heslo: string, url?: string): Promise<Store[]> {
|
|
const adminPassword = process.env.ADMIN_PASSWORD;
|
|
if (!adminPassword || heslo !== adminPassword) {
|
|
throw new Error('UNAUTHORIZED');
|
|
}
|
|
const trimmed = name.trim();
|
|
if (!trimmed) {
|
|
throw new Error('Název obchodu nesmí být prázdný');
|
|
}
|
|
const stores = await getStores();
|
|
if (stores.some(s => s.name.toLowerCase() === trimmed.toLowerCase())) {
|
|
throw new Error('Obchod s tímto názvem již existuje');
|
|
}
|
|
const trimmedUrl = url?.trim();
|
|
if (trimmedUrl) {
|
|
// Povolíme pouze http(s), aby URL nemohla být zneužita (např. javascript: → XSS)
|
|
let parsed: URL;
|
|
try {
|
|
parsed = new URL(trimmedUrl);
|
|
} catch {
|
|
throw new Error('Neplatná URL obchodu');
|
|
}
|
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
throw new Error('URL musí začínat http:// nebo https://');
|
|
}
|
|
}
|
|
const store: Store = trimmedUrl ? { name: trimmed, url: trimmedUrl } : { name: trimmed };
|
|
const updated = [...stores, store];
|
|
await storage.setData(STORES_KEY, updated);
|
|
return updated;
|
|
}
|
|
|
|
/**
|
|
* Odebere obchod ze seznamu povolených (dle názvu).
|
|
*
|
|
* @param name název obchodu
|
|
* @param heslo admin heslo
|
|
*/
|
|
export async function removeStore(name: string, heslo: string): Promise<Store[]> {
|
|
const adminPassword = process.env.ADMIN_PASSWORD;
|
|
if (!adminPassword || heslo !== adminPassword) {
|
|
throw new Error('UNAUTHORIZED');
|
|
}
|
|
const stores = await getStores();
|
|
const updated = stores.filter(s => s.name.toLowerCase() !== name.trim().toLowerCase());
|
|
await storage.setData(STORES_KEY, updated);
|
|
return updated;
|
|
}
|