import crypto from "crypto"; import getStorage from "./storage"; import { getClientData, getToday, initIfNeeded } from "./service"; import { getStores } from "./stores"; import { ClientData, GroupState, MealSlot, OrderGroup, OrderGroupMember } from "../../types/gen/types.gen"; import { formatDate } from "./utils"; const storage = getStorage(); async function getExtraData(date?: Date): Promise { await initIfNeeded(date, MealSlot.EXTRA); return getClientData(date, MealSlot.EXTRA); } function getExtraKey(date?: Date): string { return `${formatDate(date ?? getToday())}_extra`; } async function saveExtraData(data: ClientData, date?: Date): Promise { await storage.setData(getExtraKey(date), data); return data; } function findGroup(data: ClientData, id: string): OrderGroup | undefined { return data.groups?.find(g => g.id === id); } export async function createGroup(creatorLogin: string, name: string, date?: Date): Promise { const stores = await getStores(); if (!stores.some(s => s.toLowerCase() === name.trim().toLowerCase())) { throw new Error('Obchod není v seznamu povolených obchodů'); } const data = await getExtraData(date); const group: OrderGroup = { id: crypto.randomUUID(), name: name.trim(), creatorLogin, state: GroupState.OPEN, members: { [creatorLogin]: {} }, }; data.groups = [...(data.groups ?? []), group]; return saveExtraData(data, date); } export async function deleteGroup(login: string, groupId: string, date?: Date): Promise { const data = await getExtraData(date); const group = findGroup(data, groupId); if (!group) throw new Error('Skupina nebyla nalezena'); if (group.creatorLogin !== login) throw new Error('Skupinu může smazat pouze zakladatel'); data.groups = (data.groups ?? []).filter(g => g.id !== groupId); return saveExtraData(data, date); } export async function addGroupMember(login: string, groupId: string, targetLogin: string, date?: Date): Promise { const data = await getExtraData(date); const group = findGroup(data, groupId); if (!group) throw new Error('Skupina nebyla nalezena'); if (group.state === GroupState.ORDERED) throw new Error('Skupinu ve stavu "objednáno" nelze upravovat'); if (login !== group.creatorLogin && login !== targetLogin) { throw new Error('Přidat jiného uživatele může pouze zakladatel'); } if (group.state === GroupState.LOCKED && login !== group.creatorLogin) { throw new Error('Skupinu ve stavu "uzamčeno" může upravovat pouze zakladatel'); } if (group.members[targetLogin]) throw new Error('Uživatel je již ve skupině'); group.members[targetLogin] = {}; return saveExtraData(data, date); } export async function removeGroupMember(login: string, groupId: string, targetLogin: string, date?: Date): Promise { const data = await getExtraData(date); const group = findGroup(data, groupId); if (!group) throw new Error('Skupina nebyla nalezena'); if (group.state === GroupState.ORDERED) throw new Error('Skupinu ve stavu "objednáno" nelze upravovat'); if (login !== group.creatorLogin && login !== targetLogin) { throw new Error('Odebrat jiného uživatele může pouze zakladatel'); } if (group.state === GroupState.LOCKED && login !== group.creatorLogin) { throw new Error('Skupinu ve stavu "uzamčeno" může upravovat pouze zakladatel'); } if (targetLogin === group.creatorLogin) throw new Error('Zakladatel skupiny nemůže být odebrán'); if (!group.members[targetLogin]) throw new Error('Uživatel není ve skupině'); delete group.members[targetLogin]; return saveExtraData(data, date); } export async function updateGroupMember(login: string, groupId: string, targetLogin: string, patch: Partial, date?: Date): Promise { const data = await getExtraData(date); const group = findGroup(data, groupId); if (!group) throw new Error('Skupina nebyla nalezena'); if (group.state === GroupState.ORDERED) throw new Error('Skupinu ve stavu "objednáno" nelze upravovat'); const isSelf = login === targetLogin; const isCreator = login === group.creatorLogin; if (!isSelf && !isCreator) throw new Error('Upravit jiného uživatele může pouze zakladatel'); if (!isCreator && group.state === GroupState.LOCKED) { throw new Error('Skupinu ve stavu "uzamčeno" může upravovat pouze zakladatel'); } if (!group.members[targetLogin]) throw new Error('Uživatel není ve skupině'); group.members[targetLogin] = { ...group.members[targetLogin], ...patch }; return saveExtraData(data, date); } const VALID_TRANSITIONS: Record = { [GroupState.OPEN]: [GroupState.LOCKED], [GroupState.LOCKED]: [GroupState.OPEN, GroupState.ORDERED], [GroupState.ORDERED]: [], }; export async function setGroupState(login: string, groupId: string, newState: GroupState, date?: Date): Promise { const data = await getExtraData(date); const group = findGroup(data, groupId); if (!group) throw new Error('Skupina nebyla nalezena'); if (group.creatorLogin !== login) throw new Error('Stav může měnit pouze zakladatel'); if (!VALID_TRANSITIONS[group.state].includes(newState)) { throw new Error(`Nelze přejít ze stavu "${group.state}" do stavu "${newState}"`); } group.state = newState; return saveExtraData(data, date); }