Migrace na OpenAPI - TypeScript typy
This commit is contained in:
@@ -101,7 +101,7 @@ app.use("/api/", (req, res, next) => {
|
||||
const emailHeader = req.header('remote-email');
|
||||
if (userHeader !== undefined && nameHeader !== undefined) {
|
||||
const remoteName = Buffer.from(nameHeader, 'latin1').toString();
|
||||
if (ENVIRONMENT !== "production"){
|
||||
if (ENVIRONMENT !== "production") {
|
||||
console.log("Tvuj username, name a email: %s, %s, %s.", userHeader, remoteName, emailHeader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WeeklyStats, Locations } from "../../types";
|
||||
import { WeeklyStats, LunchChoice } from "../../types";
|
||||
|
||||
// Mockovací data pro podporované podniky, na jeden týden
|
||||
const MOCK_DATA = {
|
||||
@@ -1386,77 +1386,26 @@ export const getPizzaListMock = () => {
|
||||
}
|
||||
|
||||
export const getStatsMock = (): WeeklyStats => {
|
||||
// TODO stačilo by iterovat ten enum, jako to už děláme jinde
|
||||
return [
|
||||
{
|
||||
date: '24.02.',
|
||||
locations: {
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SLADOVNICKA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.TECHTOWER)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ZASTAVKAUMICHALA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SENKSERIKOVA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SPSE)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.PIZZA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.OBJEDNAVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.NEOBEDVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ROZHODUJI)]]: Math.floor(Math.random() * 10),
|
||||
}
|
||||
locations: { ...Object.keys(LunchChoice).reduce((prev, cur) => ({ ...prev, [cur]: Math.floor(Math.random() * 10) }), {}) }
|
||||
},
|
||||
{
|
||||
date: '25.02.',
|
||||
locations: {
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SLADOVNICKA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.TECHTOWER)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ZASTAVKAUMICHALA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SENKSERIKOVA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SPSE)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.PIZZA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.OBJEDNAVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.NEOBEDVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ROZHODUJI)]]: Math.floor(Math.random() * 10),
|
||||
}
|
||||
locations: { ...Object.keys(LunchChoice).reduce((prev, cur) => ({ ...prev, [cur]: Math.floor(Math.random() * 10) }), {}) }
|
||||
},
|
||||
{
|
||||
date: '26.02.',
|
||||
locations: {
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SLADOVNICKA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.TECHTOWER)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ZASTAVKAUMICHALA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SENKSERIKOVA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SPSE)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.PIZZA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.OBJEDNAVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.NEOBEDVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ROZHODUJI)]]: Math.floor(Math.random() * 10),
|
||||
}
|
||||
locations: { ...Object.keys(LunchChoice).reduce((prev, cur) => ({ ...prev, [cur]: Math.floor(Math.random() * 10) }), {}) }
|
||||
},
|
||||
{
|
||||
date: '27.02.',
|
||||
locations: {
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SLADOVNICKA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.TECHTOWER)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ZASTAVKAUMICHALA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SENKSERIKOVA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SPSE)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.PIZZA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.OBJEDNAVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.NEOBEDVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ROZHODUJI)]]: Math.floor(Math.random() * 10),
|
||||
}
|
||||
locations: { ...Object.keys(LunchChoice).reduce((prev, cur) => ({ ...prev, [cur]: Math.floor(Math.random() * 10) }), {}) }
|
||||
},
|
||||
{
|
||||
date: '28.02.',
|
||||
locations: {
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SLADOVNICKA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.TECHTOWER)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ZASTAVKAUMICHALA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SENKSERIKOVA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.SPSE)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.PIZZA)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.OBJEDNAVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.NEOBEDVAM)]]: Math.floor(Math.random() * 10),
|
||||
[Object.keys(Locations)[Object.values(Locations).indexOf(Locations.ROZHODUJI)]]: Math.floor(Math.random() * 10),
|
||||
}
|
||||
locations: { ...Object.keys(LunchChoice).reduce((prev, cur) => ({ ...prev, [cur]: Math.floor(Math.random() * 10) }), {}) }
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/** Notifikace */
|
||||
import { ClientData, NotififaceInput, NotifikaceData } from '../../types';
|
||||
import axios from 'axios';
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import { getToday } from "./service";
|
||||
import { formatDate, getUsersByLocation, getHumanTime } from "./utils";
|
||||
import { getClientData, getToday } from "./service";
|
||||
import { getUsersByLocation, getHumanTime } from "./utils";
|
||||
import getStorage from "./storage";
|
||||
import { NotifikaceData, NotifikaceInput } from '../../types';
|
||||
|
||||
const storage = getStorage();
|
||||
const ENVIRONMENT = process.env.NODE_ENV || 'production'
|
||||
@@ -54,7 +54,7 @@ dotenv.config({ path: path.resolve(__dirname, `../.env.${ENVIRONMENT}`) });
|
||||
// return promises;
|
||||
// };
|
||||
|
||||
export const ntfyCall = async (data: NotififaceInput) => {
|
||||
export const ntfyCall = async (data: NotifikaceInput) => {
|
||||
const url = process.env.NTFY_HOST
|
||||
const username = process.env.NTFY_USERNAME;
|
||||
const password = process.env.NTFY_PASSWD;
|
||||
@@ -70,8 +70,7 @@ export const ntfyCall = async (data: NotififaceInput) => {
|
||||
console.log("NTFY_PASSWD není definován v env")
|
||||
return
|
||||
}
|
||||
const today = formatDate(getToday());
|
||||
let clientData: ClientData = await storage.getData(today);
|
||||
let clientData = await getClientData(getToday());
|
||||
const userByCLocation = getUsersByLocation(clientData.choices, data.user)
|
||||
|
||||
const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
|
||||
@@ -98,7 +97,7 @@ export const ntfyCall = async (data: NotififaceInput) => {
|
||||
|
||||
}
|
||||
|
||||
export const teamsCall = async (data: NotififaceInput) => {
|
||||
export const teamsCall = async (data: NotifikaceInput) => {
|
||||
const url = process.env.TEAMS_WEBHOOK_URL;
|
||||
const title = data.udalost;
|
||||
let time = new Date();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { formatDate } from "./utils";
|
||||
import { callNotifikace } from "./notifikace";
|
||||
import { generateQr } from "./qr";
|
||||
import { ClientData, PizzaDayState, UdalostEnum, Pizza, PizzaSize, Order, PizzaOrder, DayData } from "../../types";
|
||||
import getStorage from "./storage";
|
||||
import { downloadPizzy } from "./chefie";
|
||||
import { getToday, initIfNeeded } from "./service";
|
||||
import { getClientData, getToday, initIfNeeded } from "./service";
|
||||
import { Pizza, ClientData, PizzaDayState, PizzaSize, PizzaOrder, PizzaVariant, UdalostEnum } from "../../types";
|
||||
|
||||
const storage = getStorage();
|
||||
|
||||
@@ -14,8 +14,7 @@ const storage = getStorage();
|
||||
*/
|
||||
export async function getPizzaList(): Promise<Pizza[] | undefined> {
|
||||
await initIfNeeded();
|
||||
const today = formatDate(getToday());
|
||||
let clientData: DayData = await storage.getData(today);
|
||||
let clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaList) {
|
||||
const mock = process.env.MOCK_DATA === 'true';
|
||||
clientData = await savePizzaList(await downloadPizzy(mock));
|
||||
@@ -31,9 +30,9 @@ export async function getPizzaList(): Promise<Pizza[] | undefined> {
|
||||
export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
||||
await initIfNeeded();
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
clientData.pizzaList = pizzaList;
|
||||
clientData.pizzaListLastUpdate = new Date();
|
||||
clientData.pizzaListLastUpdate = formatDate(new Date());
|
||||
await storage.setData(today, clientData);
|
||||
return clientData;
|
||||
}
|
||||
@@ -43,14 +42,14 @@ export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
||||
*/
|
||||
export async function createPizzaDay(creator: string): Promise<ClientData> {
|
||||
await initIfNeeded();
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den již existuje");
|
||||
}
|
||||
// TODO berka rychlooprava, vyřešit lépe - stahovat jednou, na jediném místě!
|
||||
const pizzaList = await getPizzaList();
|
||||
const data: ClientData = { pizzaDay: { state: PizzaDayState.CREATED, creator, orders: [] }, pizzaList, ...clientData };
|
||||
const today = formatDate(getToday());
|
||||
await storage.setData(today, data);
|
||||
callNotifikace({ input: { udalost: UdalostEnum.ZAHAJENA_PIZZA, user: creator } })
|
||||
return data;
|
||||
@@ -60,8 +59,7 @@ export async function createPizzaDay(creator: string): Promise<ClientData> {
|
||||
* Smaže pizza day pro aktuální den.
|
||||
*/
|
||||
export async function deletePizzaDay(login: string): Promise<ClientData> {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -69,6 +67,7 @@ export async function deletePizzaDay(login: string): Promise<ClientData> {
|
||||
throw Error("Login uživatele se neshoduje se zakladatelem Pizza Day");
|
||||
}
|
||||
delete clientData.pizzaDay;
|
||||
const today = formatDate(getToday());
|
||||
await storage.setData(today, clientData);
|
||||
return clientData;
|
||||
}
|
||||
@@ -82,28 +81,35 @@ export async function deletePizzaDay(login: string): Promise<ClientData> {
|
||||
*/
|
||||
export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
if (clientData.pizzaDay.state !== PizzaDayState.CREATED) {
|
||||
throw Error("Pizza day není ve stavu " + PizzaDayState.CREATED);
|
||||
}
|
||||
let order: Order | undefined = clientData.pizzaDay.orders.find(o => o.customer === login);
|
||||
let order: PizzaOrder | undefined = clientData.pizzaDay?.orders?.find(o => o.customer === login);
|
||||
if (!order) {
|
||||
order = {
|
||||
customer: login,
|
||||
pizzaList: [],
|
||||
totalPrice: 0,
|
||||
hasQr: false,
|
||||
}
|
||||
if (!clientData.pizzaDay.orders) {
|
||||
clientData.pizzaDay.orders = [];
|
||||
}
|
||||
clientData.pizzaDay.orders.push(order);
|
||||
}
|
||||
const pizzaOrder: PizzaOrder = {
|
||||
const pizzaOrder: PizzaVariant = {
|
||||
varId: size.varId,
|
||||
name: pizza.name,
|
||||
size: size.size,
|
||||
price: size.price,
|
||||
}
|
||||
if (!order.pizzaList) {
|
||||
order.pizzaList = [];
|
||||
}
|
||||
order.pizzaList.push(pizzaOrder);
|
||||
order.totalPrice += pizzaOrder.price;
|
||||
await storage.setData(today, clientData);
|
||||
@@ -116,26 +122,26 @@ export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize
|
||||
* @param login login uživatele
|
||||
* @param pizzaOrder objednávka pizzy
|
||||
*/
|
||||
export async function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) {
|
||||
export async function removePizzaOrder(login: string, pizzaOrder: PizzaVariant) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
const orderIndex = clientData.pizzaDay.orders.findIndex(o => o.customer === login);
|
||||
const orderIndex = clientData.pizzaDay!.orders!.findIndex(o => o.customer === login);
|
||||
if (orderIndex < 0) {
|
||||
throw Error("Nebyly nalezeny žádné objednávky pro uživatele " + login);
|
||||
}
|
||||
const order = clientData.pizzaDay.orders[orderIndex];
|
||||
const index = order.pizzaList.findIndex(o => o.name === pizzaOrder.name && o.size === pizzaOrder.size);
|
||||
const order = clientData.pizzaDay!.orders![orderIndex];
|
||||
const index = order.pizzaList!.findIndex(o => o.name === pizzaOrder.name && o.size === pizzaOrder.size);
|
||||
if (index < 0) {
|
||||
throw Error("Objednávka s danými parametry nebyla nalezena");
|
||||
}
|
||||
const price = order.pizzaList[index].price;
|
||||
order.pizzaList.splice(index, 1);
|
||||
const price = order.pizzaList![index].price;
|
||||
order.pizzaList!.splice(index, 1);
|
||||
order.totalPrice -= price;
|
||||
if (order.pizzaList.length == 0) {
|
||||
clientData.pizzaDay.orders.splice(orderIndex, 1);
|
||||
if (order.pizzaList!.length == 0) {
|
||||
clientData.pizzaDay.orders!.splice(orderIndex, 1);
|
||||
}
|
||||
await storage.setData(today, clientData);
|
||||
return clientData;
|
||||
@@ -149,7 +155,7 @@ export async function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) {
|
||||
*/
|
||||
export async function lockPizzaDay(login: string) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -172,7 +178,7 @@ export async function lockPizzaDay(login: string) {
|
||||
*/
|
||||
export async function unlockPizzaDay(login: string) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -195,7 +201,7 @@ export async function unlockPizzaDay(login: string) {
|
||||
*/
|
||||
export async function finishPizzaOrder(login: string) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -220,7 +226,7 @@ export async function finishPizzaOrder(login: string) {
|
||||
*/
|
||||
export async function finishPizzaDelivery(login: string, bankAccount?: string, bankAccountHolder?: string) {
|
||||
const today = formatDate(getToday());
|
||||
const clientData: DayData = await storage.getData(today);
|
||||
const clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -234,9 +240,9 @@ export async function finishPizzaDelivery(login: string, bankAccount?: string, b
|
||||
|
||||
// Vygenerujeme QR kód, pokud k tomu máme data
|
||||
if (bankAccount?.length && bankAccountHolder?.length) {
|
||||
for (const order of clientData.pizzaDay.orders) {
|
||||
for (const order of clientData.pizzaDay.orders!) {
|
||||
if (order.customer !== login) { // zatím platí creator = objednávající, a pro toho nemá QR kód smysl
|
||||
let message = order.pizzaList.map(pizza => `Pizza ${pizza.name} (${pizza.size})`).join(', ');
|
||||
let message = order.pizzaList!.map(pizza => `Pizza ${pizza.name} (${pizza.size})`).join(', ');
|
||||
await generateQr(order.customer, bankAccount, bankAccountHolder, order.totalPrice, message);
|
||||
order.hasQr = true;
|
||||
}
|
||||
@@ -255,15 +261,15 @@ export async function finishPizzaDelivery(login: string, bankAccount?: string, b
|
||||
*/
|
||||
export async function updatePizzaDayNote(login: string, note?: string) {
|
||||
const today = formatDate(getToday());
|
||||
let clientData: DayData = await storage.getData(today);
|
||||
let clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
if (clientData.pizzaDay.state !== PizzaDayState.CREATED) {
|
||||
throw Error("Pizza day není ve stavu " + PizzaDayState.CREATED);
|
||||
}
|
||||
const myOrder = clientData.pizzaDay.orders.find(o => o.customer === login);
|
||||
if (!myOrder || !myOrder.pizzaList.length) {
|
||||
const myOrder = clientData.pizzaDay.orders!.find(o => o.customer === login);
|
||||
if (!myOrder?.pizzaList?.length) {
|
||||
throw Error("Pizza day neobsahuje žádné objednávky uživatele " + login);
|
||||
}
|
||||
myOrder.note = note;
|
||||
@@ -282,7 +288,7 @@ export async function updatePizzaDayNote(login: string, note?: string) {
|
||||
*/
|
||||
export async function updatePizzaFee(login: string, targetLogin: string, text?: string, price?: number) {
|
||||
const today = formatDate(getToday());
|
||||
let clientData: DayData = await storage.getData(today);
|
||||
let clientData = await getClientData(getToday());
|
||||
if (!clientData.pizzaDay) {
|
||||
throw Error("Pizza day pro dnešní den neexistuje");
|
||||
}
|
||||
@@ -292,8 +298,8 @@ export async function updatePizzaFee(login: string, targetLogin: string, text?:
|
||||
if (clientData.pizzaDay.creator !== login) {
|
||||
throw Error("Příplatky může měnit pouze zakladatel Pizza day");
|
||||
}
|
||||
const targetOrder = clientData.pizzaDay.orders.find(o => o.customer === targetLogin);
|
||||
if (!targetOrder || !targetOrder.pizzaList.length) {
|
||||
const targetOrder = clientData.pizzaDay.orders!.find(o => o.customer === targetLogin);
|
||||
if (!targetOrder?.pizzaList?.length) {
|
||||
throw Error(`Pizza day neobsahuje žádné objednávky uživatele ${targetLogin}`);
|
||||
}
|
||||
if (!price) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import axios from "axios";
|
||||
import { load } from 'cheerio';
|
||||
import { getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock, getMenuZastavkaUmichalaMock, getMenuSenkSerikovaMock } from "./mock";
|
||||
import { formatDate } from "./utils";
|
||||
import { Food } from "../../types";
|
||||
import {getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock, getMenuZastavkaUmichalaMock, getMenuSenkSerikovaMock} from "./mock";
|
||||
import {formatDate} from "./utils";
|
||||
|
||||
// Fráze v názvech jídel, které naznačují že se jedná o polévku
|
||||
const SOUP_NAMES = [
|
||||
@@ -407,7 +407,7 @@ export const getMenuSenkSerikova = async (firstDayOfWeek: Date, mock: boolean =
|
||||
const currentDate = new Date(firstDayOfWeek);
|
||||
const result: Food[][] = [];
|
||||
let dayIndex = 0;
|
||||
while(currentDate.getDate() < nowDate) {
|
||||
while (currentDate.getDate() < nowDate) {
|
||||
result[dayIndex] = [{
|
||||
amount: undefined,
|
||||
name: "Pro tento den není uveřejněna nabídka jídel",
|
||||
@@ -417,7 +417,7 @@ export const getMenuSenkSerikova = async (firstDayOfWeek: Date, mock: boolean =
|
||||
dayIndex = dayIndex + 1;
|
||||
currentDate.setDate(firstDayOfWeek.getDate() + dayIndex);
|
||||
}
|
||||
|
||||
|
||||
$('.menicka').each((i, element) => {
|
||||
const currentDayFood: Food[] = [];
|
||||
$(element).find('.popup-gallery li').each((j, element) => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import express, { Request } from "express";
|
||||
import { getLogin, getTrusted } from "../auth";
|
||||
import { addChoice, addVolatileData, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote } from "../service";
|
||||
import { addChoice, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote } from "../service";
|
||||
import { getDayOfWeekIndex, parseToken } from "../utils";
|
||||
import { getWebsocket } from "../websocket";
|
||||
import { callNotifikace } from "../notifikace";
|
||||
import { AddChoiceRequest, ChangeDepartureTimeRequest, IDayIndex, RemoveChoiceRequest, RemoveChoicesRequest, UdalostEnum, UpdateNoteRequest } from "../../../types";
|
||||
import { AddChoiceRequest, ChangeDepartureTimeRequest, IDayIndex, RemoveChoiceRequest, RemoveChoicesRequest, UpdateNoteRequest } from "../../../types";
|
||||
import { UdalostEnum } from "../../../types";
|
||||
|
||||
/**
|
||||
* Ověří a vrátí index dne v týdnu z požadavku, za předpokladu, že byl předán, a je zároveň
|
||||
@@ -45,7 +46,7 @@ router.post("/addChoice", async (req: Request<{}, any, AddChoiceRequest>, res, n
|
||||
}
|
||||
try {
|
||||
const data = await addChoice(login, trusted, req.body.locationKey, req.body.foodIndex, date);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
return res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
@@ -65,7 +66,7 @@ router.post("/removeChoices", async (req: Request<{}, any, RemoveChoicesRequest>
|
||||
}
|
||||
try {
|
||||
const data = await removeChoices(login, trusted, req.body.locationKey, date);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
@@ -85,7 +86,7 @@ router.post("/removeChoice", async (req: Request<{}, any, RemoveChoiceRequest>,
|
||||
}
|
||||
try {
|
||||
const data = await removeChoice(login, trusted, req.body.locationKey, req.body.foodIndex, date);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
@@ -109,7 +110,7 @@ router.post("/updateNote", async (req: Request<{}, any, UpdateNoteRequest>, res,
|
||||
date = getDateForWeekIndex(dayIndex);
|
||||
}
|
||||
const data = await updateNote(login, trusted, note, date);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
@@ -128,7 +129,7 @@ router.post("/changeDepartureTime", async (req: Request<{}, any, ChangeDeparture
|
||||
}
|
||||
try {
|
||||
const data = await updateDepartureTime(login, req.body?.time, date);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ import { getLogin } from "../auth";
|
||||
import { createPizzaDay, deletePizzaDay, getPizzaList, addPizzaOrder, removePizzaOrder, lockPizzaDay, unlockPizzaDay, finishPizzaOrder, finishPizzaDelivery, updatePizzaDayNote, updatePizzaFee } from "../pizza";
|
||||
import { parseToken } from "../utils";
|
||||
import { getWebsocket } from "../websocket";
|
||||
import { addVolatileData } from "../service";
|
||||
import { AddPizzaRequest, FinishDeliveryRequest, RemovePizzaRequest, UpdatePizzaDayNoteRequest, UpdatePizzaFeeRequest } from "../../../types";
|
||||
|
||||
const router = express.Router();
|
||||
@@ -13,14 +12,14 @@ router.post("/create", async (req: Request<{}, any, undefined>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await createPizzaDay(login);
|
||||
res.status(200).json(data);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
});
|
||||
|
||||
/** Smaže pizza day pro aktuální den, za předpokladu že existuje. */
|
||||
router.post("/delete", async (req: Request<{}, any, undefined>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await deletePizzaDay(login);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
});
|
||||
|
||||
router.post("/add", async (req: Request<{}, any, AddPizzaRequest>, res) => {
|
||||
@@ -44,7 +43,7 @@ router.post("/add", async (req: Request<{}, any, AddPizzaRequest>, res) => {
|
||||
throw Error("Neplatný index velikosti pizzy: " + pizzaSizeIndex);
|
||||
}
|
||||
const data = await addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
@@ -54,35 +53,35 @@ router.post("/remove", async (req: Request<{}, any, RemovePizzaRequest>, res) =>
|
||||
throw Error("Nebyla předána objednávka");
|
||||
}
|
||||
const data = await removePizzaOrder(login, req.body?.pizzaOrder);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
router.post("/lock", async (req: Request<{}, any, undefined>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await lockPizzaDay(login);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
router.post("/unlock", async (req: Request<{}, any, undefined>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await unlockPizzaDay(login);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
router.post("/finishOrder", async (req: Request<{}, any, undefined>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await finishPizzaOrder(login);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
router.post("/finishDelivery", async (req: Request<{}, any, FinishDeliveryRequest>, res) => {
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = await finishPizzaDelivery(login, req.body.bankAccount, req.body.bankAccountHolder);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
@@ -93,7 +92,7 @@ router.post("/updatePizzaDayNote", async (req: Request<{}, any, UpdatePizzaDayNo
|
||||
throw Error("Poznámka může mít maximálně 70 znaků");
|
||||
}
|
||||
const data = await updatePizzaDayNote(login, req.body.note);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
@@ -105,7 +104,7 @@ router.post("/updatePizzaFee", async (req: Request<{}, any, UpdatePizzaFeeReques
|
||||
}
|
||||
try {
|
||||
const data = await updatePizzaFee(login, req.body.login, req.body.text, req.body.price);
|
||||
getWebsocket().emit("message", await addVolatileData(data));
|
||||
getWebsocket().emit("message", data);
|
||||
res.status(200).json(data);
|
||||
} catch (e: any) { next(e) }
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import express, { Request, Response } from "express";
|
||||
import { getLogin } from "../auth";
|
||||
import { parseToken } from "../utils";
|
||||
import { WeeklyStats } from "../../../types";
|
||||
import { getStats } from "../stats";
|
||||
import { WeeklyStats } from "../../../types";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import express, { Request, Response } from "express";
|
||||
import { getLogin } from "../auth";
|
||||
import { parseToken } from "../utils";
|
||||
import { getUserVotes, updateFeatureVote } from "../voting";
|
||||
import { FeatureRequest, UpdateFeatureVoteRequest } from "../../../types";
|
||||
import { UpdateFeatureVoteRequest } from "../../../types";
|
||||
import { FeatureRequest } from "../../../types";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getFirstWorkDayOfWeek, getHumanDate, getIsWeekend, getWeekNumber } from "./utils";
|
||||
import { ClientData, Restaurants, DayMenu, DepartureTime, DayData, WeekMenu, LocationKey } from "../../types";
|
||||
import getStorage from "./storage";
|
||||
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku, getMenuZastavkaUmichala, getMenuSenkSerikova } from "./restaurants";
|
||||
import { getTodayMock } from "./mock";
|
||||
import { ClientData, DepartureTime, LunchChoice, Restaurant, RestaurantDayMenu, WeekMenu } from "../../types";
|
||||
|
||||
const storage = getStorage();
|
||||
const MENU_PREFIX = 'menu';
|
||||
@@ -31,45 +31,31 @@ export const getDateForWeekIndex = (index: number) => {
|
||||
function getEmptyData(date?: Date): ClientData {
|
||||
const usedDate = date || getToday();
|
||||
return {
|
||||
todayDayIndex: getDayOfWeekIndex(getToday()),
|
||||
date: getHumanDate(usedDate),
|
||||
isWeekend: getIsWeekend(usedDate),
|
||||
weekIndex: getDayOfWeekIndex(usedDate),
|
||||
dayIndex: getDayOfWeekIndex(usedDate),
|
||||
choices: {},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Přidá k datům "dopočítaná" data, která nejsou přímo uložena v databázi.
|
||||
*
|
||||
* @param data data z databáze
|
||||
* @returns obohacená data
|
||||
*/
|
||||
export async function addVolatileData(data: ClientData): Promise<ClientData> {
|
||||
data.todayWeekIndex = getDayOfWeekIndex(getToday());
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí veškerá klientská data pro předaný den, nebo aktuální den, pokud není předán.
|
||||
*/
|
||||
export async function getData(date?: Date): Promise<ClientData> {
|
||||
const targetDate = date ?? getToday();
|
||||
const dateString = formatDate(targetDate);
|
||||
const data: DayData = await storage.getData(dateString) || getEmptyData(date);
|
||||
let clientData: ClientData = { ...data };
|
||||
const clientData = await getClientData(date);
|
||||
clientData.menus = {
|
||||
[Restaurants.SLADOVNICKA]: await getRestaurantMenu(Restaurants.SLADOVNICKA, date),
|
||||
// [Restaurants.UMOTLIKU]: await getRestaurantMenu(Restaurants.UMOTLIKU, date),
|
||||
[Restaurants.TECHTOWER]: await getRestaurantMenu(Restaurants.TECHTOWER, date),
|
||||
[Restaurants.ZASTAVKAUMICHALA]: await getRestaurantMenu(Restaurants.ZASTAVKAUMICHALA, date),
|
||||
[Restaurants.SENKSERIKOVA]: await getRestaurantMenu(Restaurants.SENKSERIKOVA, date),
|
||||
SLADOVNICKA: await getRestaurantMenu('SLADOVNICKA', date),
|
||||
// UMOTLIKU: await getRestaurantMenu('UMOTLIKU', date),
|
||||
TECHTOWER: await getRestaurantMenu('TECHTOWER', date),
|
||||
ZASTAVKAUMICHALA: await getRestaurantMenu('ZASTAVKAUMICHALA', date),
|
||||
SENKSERIKOVA: await getRestaurantMenu('SENKSERIKOVA', date),
|
||||
}
|
||||
clientData = await addVolatileData(clientData);
|
||||
return clientData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí klíč, pod kterým je uloženo menu pro předané datum.
|
||||
* Vrátí klíč, pod kterým je uloženo menu pro týden příslušící předanému datu.
|
||||
*
|
||||
* @param date datum
|
||||
* @returns databázový klíč
|
||||
@@ -80,13 +66,13 @@ function getMenuKey(date: Date) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí menu restaurací pro předané datum, pokud již existují.
|
||||
* Vrátí menu všech podniků pro celý týden do kterého spadá předané datum, pokud již existují.
|
||||
*
|
||||
* @param date datum
|
||||
* @returns menu restaurací pro předané datum
|
||||
* @returns menu restaurací pro týden příslušící předanému datu
|
||||
*/
|
||||
async function getMenu(date: Date): Promise<WeekMenu | undefined> {
|
||||
return await storage.getData(getMenuKey(date));
|
||||
return await storage.getData<WeekMenu | undefined>(getMenuKey(date));
|
||||
}
|
||||
|
||||
// TODO přesun do restaurants.ts
|
||||
@@ -98,7 +84,7 @@ async function getMenu(date: Date): Promise<WeekMenu | undefined> {
|
||||
* @param date datum, ke kterému získat menu
|
||||
* @param mock příznak, zda chceme pouze mock data
|
||||
*/
|
||||
export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): Promise<DayMenu> {
|
||||
export async function getRestaurantMenu(restaurant: keyof typeof Restaurant, date?: Date): Promise<RestaurantDayMenu> {
|
||||
const usedDate = date ?? getToday();
|
||||
const dayOfWeekIndex = getDayOfWeekIndex(usedDate);
|
||||
const now = new Date().getTime();
|
||||
@@ -110,41 +96,41 @@ export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): P
|
||||
};
|
||||
}
|
||||
|
||||
let menus = await getMenu(usedDate);
|
||||
if (menus == null) {
|
||||
menus = [];
|
||||
let weekMenu = await getMenu(usedDate);
|
||||
if (weekMenu == null) {
|
||||
weekMenu = [{}, {}, {}, {}, {}];
|
||||
}
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (menus[i] == null) {
|
||||
menus[i] = {};
|
||||
if (weekMenu[i] == null) {
|
||||
weekMenu[i] = {};
|
||||
}
|
||||
if (menus[i][restaurant] == null) {
|
||||
menus[i][restaurant] = {
|
||||
if (weekMenu[i][restaurant] == null) {
|
||||
weekMenu[i][restaurant] = {
|
||||
lastUpdate: now,
|
||||
closed: false,
|
||||
food: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!menus[dayOfWeekIndex][restaurant]?.food?.length) {
|
||||
if (!weekMenu[dayOfWeekIndex][restaurant]?.food?.length) {
|
||||
const firstDay = getFirstWorkDayOfWeek(usedDate);
|
||||
const mock = process.env.MOCK_DATA === 'true';
|
||||
switch (restaurant) {
|
||||
case Restaurants.SLADOVNICKA:
|
||||
case 'SLADOVNICKA':
|
||||
try {
|
||||
const sladovnickaFood = await getMenuSladovnicka(firstDay, mock);
|
||||
for (let i = 0; i < sladovnickaFood.length; i++) {
|
||||
menus[i][restaurant]!.food = sladovnickaFood[i];
|
||||
weekMenu[i][restaurant]!.food = sladovnickaFood[i];
|
||||
// Velice chatrný a nespolehlivý způsob detekce uzavření...
|
||||
if (sladovnickaFood[i].length === 1 && sladovnickaFood[i][0].name.toLowerCase() === 'pro daný den nebyla nalezena denní nabídka') {
|
||||
menus[i][restaurant]!.closed = true;
|
||||
weekMenu[i][restaurant]!.closed = true;
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error("Selhalo načtení jídel pro podnik Sladovnická", e);
|
||||
}
|
||||
break;
|
||||
// case Restaurants.UMOTLIKU:
|
||||
// case 'UMOTLIKU':
|
||||
// try {
|
||||
// const uMotlikuFood = await getMenuUMotliku(firstDay, mock);
|
||||
// for (let i = 0; i < uMotlikuFood.length; i++) {
|
||||
@@ -157,39 +143,39 @@ export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): P
|
||||
// console.error("Selhalo načtení jídel pro podnik U Motlíků", e);
|
||||
// }
|
||||
// break;
|
||||
case Restaurants.TECHTOWER:
|
||||
case 'TECHTOWER':
|
||||
try {
|
||||
const techTowerFood = await getMenuTechTower(firstDay, mock);
|
||||
for (let i = 0; i < techTowerFood.length; i++) {
|
||||
menus[i][restaurant]!.food = techTowerFood[i];
|
||||
weekMenu[i][restaurant]!.food = techTowerFood[i];
|
||||
if (techTowerFood[i]?.length === 1 && techTowerFood[i][0].name.toLowerCase() === 'svátek') {
|
||||
menus[i][restaurant]!.closed = true;
|
||||
weekMenu[i][restaurant]!.closed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} catch (e: any) {
|
||||
console.error("Selhalo načtení jídel pro podnik TechTower", e);
|
||||
}
|
||||
case Restaurants.ZASTAVKAUMICHALA:
|
||||
case 'ZASTAVKAUMICHALA':
|
||||
try {
|
||||
const zastavkaUmichalaFood = await getMenuZastavkaUmichala(firstDay, mock);
|
||||
for (let i = 0; i < zastavkaUmichalaFood.length; i++) {
|
||||
menus[i][restaurant]!.food = zastavkaUmichalaFood[i];
|
||||
weekMenu[i][restaurant]!.food = zastavkaUmichalaFood[i];
|
||||
if (zastavkaUmichalaFood[i]?.length === 1 && zastavkaUmichalaFood[i][0].name === 'Pro tento den není uveřejněna nabídka jídel.') {
|
||||
menus[i][restaurant]!.closed = true;
|
||||
weekMenu[i][restaurant]!.closed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} catch (e: any) {
|
||||
console.error("Selhalo načtení jídel pro podnik Zastávka u Michala", e);
|
||||
}
|
||||
case Restaurants.SENKSERIKOVA:
|
||||
case 'SENKSERIKOVA':
|
||||
try {
|
||||
const senkSerikovaFood = await getMenuSenkSerikova(firstDay, mock);
|
||||
for (let i = 0; i < senkSerikovaFood.length; i++) {
|
||||
menus[i][restaurant]!.food = senkSerikovaFood[i];
|
||||
weekMenu[i][restaurant]!.food = senkSerikovaFood[i];
|
||||
if (senkSerikovaFood[i]?.length === 1 && senkSerikovaFood[i][0].name === 'Pro tento den nebylo zadáno menu.') {
|
||||
menus[i][restaurant]!.closed = true;
|
||||
weekMenu[i][restaurant]!.closed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -197,9 +183,9 @@ export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): P
|
||||
console.error("Selhalo načtení jídel pro podnik Pivovarský šenk Šeříková", e);
|
||||
}
|
||||
}
|
||||
await storage.setData(getMenuKey(usedDate), menus);
|
||||
await storage.setData(getMenuKey(usedDate), weekMenu);
|
||||
}
|
||||
return menus[dayOfWeekIndex][restaurant]!;
|
||||
return weekMenu[dayOfWeekIndex][restaurant]!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,9 +210,9 @@ export async function initIfNeeded(date?: Date) {
|
||||
* @param date datum, ke kterému se volba vztahuje
|
||||
* @returns
|
||||
*/
|
||||
export async function removeChoices(login: string, trusted: boolean, locationKey: LocationKey, date?: Date) {
|
||||
export async function removeChoices(login: string, trusted: boolean, locationKey: keyof typeof LunchChoice, date?: Date) {
|
||||
const selectedDay = formatDate(date ?? getToday());
|
||||
let data: DayData = await storage.getData(selectedDay);
|
||||
let data = await getClientData(date);
|
||||
validateTrusted(data, login, trusted);
|
||||
if (locationKey in data.choices) {
|
||||
if (data.choices[locationKey] && login in data.choices[locationKey]) {
|
||||
@@ -251,15 +237,15 @@ export async function removeChoices(login: string, trusted: boolean, locationKey
|
||||
* @param date datum, ke kterému se volba vztahuje
|
||||
* @returns
|
||||
*/
|
||||
export async function removeChoice(login: string, trusted: boolean, locationKey: LocationKey, foodIndex: number, date?: Date) {
|
||||
export async function removeChoice(login: string, trusted: boolean, locationKey: keyof typeof LunchChoice, foodIndex: number, date?: Date) {
|
||||
const selectedDay = formatDate(date ?? getToday());
|
||||
let data: DayData = await storage.getData(selectedDay);
|
||||
let data = await getClientData(date);
|
||||
validateTrusted(data, login, trusted);
|
||||
if (locationKey in data.choices) {
|
||||
if (data.choices[locationKey] && login in data.choices[locationKey]) {
|
||||
const index = data.choices[locationKey][login].options.indexOf(foodIndex);
|
||||
if (index > -1) {
|
||||
data.choices[locationKey][login].options.splice(index, 1)
|
||||
const index = data.choices[locationKey][login].selectedFoods?.indexOf(foodIndex);
|
||||
if (index && index > -1) {
|
||||
data.choices[locationKey][login].selectedFoods?.splice(index, 1);
|
||||
await storage.setData(selectedDay, data);
|
||||
}
|
||||
}
|
||||
@@ -274,10 +260,11 @@ export async function removeChoice(login: string, trusted: boolean, locationKey:
|
||||
* @param date datum, ke kterému se volby vztahují
|
||||
* @param ignoredLocationKey volba, která nebude odstraněna, pokud existuje
|
||||
*/
|
||||
async function removeChoiceIfPresent(login: string, date: string, ignoredLocationKey?: LocationKey) {
|
||||
let data: DayData = await storage.getData(date);
|
||||
async function removeChoiceIfPresent(login: string, date?: Date, ignoredLocationKey?: keyof typeof LunchChoice) {
|
||||
const usedDate = date ?? getToday();
|
||||
let data = await getClientData(usedDate);
|
||||
for (const key of Object.keys(data.choices)) {
|
||||
const locationKey = key as LocationKey;
|
||||
const locationKey = key as keyof typeof LunchChoice;
|
||||
if (ignoredLocationKey != null && ignoredLocationKey == locationKey) {
|
||||
continue;
|
||||
}
|
||||
@@ -286,7 +273,7 @@ async function removeChoiceIfPresent(login: string, date: string, ignoredLocatio
|
||||
if (Object.keys(data.choices[locationKey]).length === 0) {
|
||||
delete data.choices[locationKey];
|
||||
}
|
||||
await storage.setData(date, data);
|
||||
await storage.setData(formatDate(usedDate), data);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
@@ -325,19 +312,18 @@ function validateTrusted(data: ClientData, login: string, trusted: boolean) {
|
||||
* @param date datum, ke kterému se volba vztahuje
|
||||
* @returns aktuální data
|
||||
*/
|
||||
export async function addChoice(login: string, trusted: boolean, locationKey: LocationKey, foodIndex?: number, date?: Date) {
|
||||
export async function addChoice(login: string, trusted: boolean, locationKey: keyof typeof LunchChoice, foodIndex?: number, date?: Date) {
|
||||
const usedDate = date ?? getToday();
|
||||
await initIfNeeded(usedDate);
|
||||
const selectedDate = formatDate(usedDate);
|
||||
let data: DayData = await storage.getData(selectedDate);
|
||||
let data = await getClientData(usedDate);
|
||||
validateTrusted(data, login, trusted);
|
||||
await validateFoodIndex(locationKey, foodIndex, date);
|
||||
// Pokud měníme pouze lokaci, mažeme případné předchozí
|
||||
if (foodIndex == null) {
|
||||
data = await removeChoiceIfPresent(login, selectedDate);
|
||||
data = await removeChoiceIfPresent(login, usedDate);
|
||||
} else {
|
||||
// Mažeme případné ostatní volby (měla by být maximálně jedna)
|
||||
removeChoiceIfPresent(login, selectedDate, locationKey);
|
||||
removeChoiceIfPresent(login, usedDate, locationKey);
|
||||
}
|
||||
// TODO vytáhnout inicializaci "prázdné struktury" do vlastní funkce
|
||||
if (!(data.choices[locationKey])) {
|
||||
@@ -349,12 +335,13 @@ export async function addChoice(login: string, trusted: boolean, locationKey: Lo
|
||||
}
|
||||
data.choices[locationKey][login] = {
|
||||
trusted,
|
||||
options: []
|
||||
selectedFoods: []
|
||||
};
|
||||
}
|
||||
if (foodIndex != null && !data.choices[locationKey][login].options.includes(foodIndex)) {
|
||||
data.choices[locationKey][login].options.push(foodIndex);
|
||||
if (foodIndex != null && !data.choices[locationKey][login].selectedFoods?.includes(foodIndex)) {
|
||||
data.choices[locationKey][login].selectedFoods?.push(foodIndex);
|
||||
}
|
||||
const selectedDate = formatDate(usedDate);
|
||||
await storage.setData(selectedDate, data);
|
||||
return data;
|
||||
}
|
||||
@@ -366,7 +353,7 @@ export async function addChoice(login: string, trusted: boolean, locationKey: Lo
|
||||
* @param foodIndex index jídla pro danou lokalitu
|
||||
* @param date datum, pro které je validace prováděna
|
||||
*/
|
||||
async function validateFoodIndex(locationKey: LocationKey, foodIndex?: number, date?: Date) {
|
||||
async function validateFoodIndex(locationKey: keyof typeof LunchChoice, foodIndex?: number, date?: Date) {
|
||||
if (foodIndex != null) {
|
||||
if (typeof foodIndex !== 'number') {
|
||||
throw Error(`Neplatný index ${foodIndex} typu ${typeof foodIndex}`);
|
||||
@@ -374,13 +361,12 @@ async function validateFoodIndex(locationKey: LocationKey, foodIndex?: number, d
|
||||
if (foodIndex < 0) {
|
||||
throw Error(`Neplatný index ${foodIndex}`);
|
||||
}
|
||||
if (!(locationKey in Restaurants)) {
|
||||
if (!Object.keys(Restaurant).includes(locationKey)) {
|
||||
throw Error(`Neplatný index ${foodIndex} pro lokalitu ${locationKey} nepodporující indexy`);
|
||||
}
|
||||
const usedDate = date ?? getToday();
|
||||
const restaurantKey = Restaurants[locationKey as keyof typeof Restaurants]
|
||||
const menu = await getRestaurantMenu(restaurantKey, usedDate);
|
||||
if (foodIndex > (menu.food.length - 1)) {
|
||||
const menu = await getRestaurantMenu(locationKey as keyof typeof Restaurant, usedDate);
|
||||
if (menu.food?.length && foodIndex > (menu.food.length - 1)) {
|
||||
throw new Error(`Neplatný index ${foodIndex} pro lokalitu ${locationKey}`);
|
||||
}
|
||||
}
|
||||
@@ -397,16 +383,16 @@ async function validateFoodIndex(locationKey: LocationKey, foodIndex?: number, d
|
||||
export async function updateNote(login: string, trusted: boolean, note?: string, date?: Date) {
|
||||
const usedDate = date ?? getToday();
|
||||
await initIfNeeded(usedDate);
|
||||
const selectedDate = formatDate(usedDate);
|
||||
let data: DayData = await storage.getData(selectedDate);
|
||||
let data = await getClientData(usedDate);
|
||||
validateTrusted(data, login, trusted);
|
||||
const userEntry = data.choices != null && Object.entries(data.choices).find(entry => entry[1][login] != null);
|
||||
if (userEntry) {
|
||||
if (!note || !note.length) {
|
||||
if (!note?.length) {
|
||||
delete userEntry[1][login].note;
|
||||
} else {
|
||||
userEntry[1][login].note = note;
|
||||
}
|
||||
const selectedDate = formatDate(usedDate);
|
||||
await storage.setData(selectedDate, data);
|
||||
}
|
||||
return data;
|
||||
@@ -420,8 +406,8 @@ export async function updateNote(login: string, trusted: boolean, note?: string,
|
||||
* @param date datum, ke kterému se čas vztahuje
|
||||
*/
|
||||
export async function updateDepartureTime(login: string, time?: string, date?: Date) {
|
||||
const selectedDate = formatDate(date ?? getToday());
|
||||
let clientData: DayData = await storage.getData(selectedDate);
|
||||
const usedDate = date ?? getToday();
|
||||
let clientData = await getClientData(usedDate);
|
||||
const found = Object.values(clientData.choices).find(location => login in location);
|
||||
// TODO validace, že se jedná o restauraci
|
||||
if (found) {
|
||||
@@ -433,7 +419,23 @@ export async function updateDepartureTime(login: string, time?: string, date?: D
|
||||
}
|
||||
found[login].departureTime = time;
|
||||
}
|
||||
await storage.setData(selectedDate, clientData);
|
||||
await storage.setData(formatDate(usedDate), clientData);
|
||||
}
|
||||
return clientData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí data pro klienta pro předaný nebo aktuální den.
|
||||
*
|
||||
* @param date datum pro který vrátit data, pokud není vyplněno, je použit dnešní den
|
||||
* @returns data pro klienta
|
||||
*/
|
||||
export async function getClientData(date?: Date): Promise<ClientData> {
|
||||
const targetDate = date ?? getToday();
|
||||
const dateString = formatDate(targetDate);
|
||||
const clientData = await storage.getData<ClientData>(dateString) || getEmptyData(date);
|
||||
return {
|
||||
...clientData,
|
||||
todayDayIndex: getDayOfWeekIndex(getToday()),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { WeeklyStats, DayData, Locations, DailyStats, LocationKey } from "../../types";
|
||||
import { DailyStats, LunchChoice, WeeklyStats } from "../../types";
|
||||
import { getStatsMock } from "./mock";
|
||||
import { getClientData } from "./service";
|
||||
import getStorage from "./storage";
|
||||
import { formatDate } from "./utils";
|
||||
|
||||
@@ -32,10 +33,14 @@ export async function getStats(startDate: string, endDate: string): Promise<Week
|
||||
date: `${String(date.getDate()).padStart(2, "0")}.${String(date.getMonth() + 1).padStart(2, "0")}.`,
|
||||
locations: {}
|
||||
}
|
||||
const data: DayData = await storage.getData(formatDate(date));
|
||||
const data = await getClientData(date);
|
||||
if (data?.choices) {
|
||||
Object.keys(data.choices).forEach(locationKey => {
|
||||
locationsStats.locations[locationKey as LocationKey] = Object.keys(data.choices[locationKey as LocationKey]!).length;
|
||||
if (!locationsStats.locations) {
|
||||
locationsStats.locations = {}
|
||||
}
|
||||
// TODO dořešit, tohle je zmatek a té hlášce Sonaru nerozumím
|
||||
locationsStats.locations[locationKey as keyof typeof LunchChoice] = Object.keys(data.choices[locationKey as keyof typeof LunchChoice]!).length;
|
||||
})
|
||||
}
|
||||
result.push(locationsStats);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { ClientData } from "../../../types";
|
||||
|
||||
/**
|
||||
* Interface pro úložiště dat.
|
||||
*
|
||||
@@ -17,7 +15,7 @@ export interface StorageInterface {
|
||||
* Vrátí veškerá data pro předaný klíč.
|
||||
* @param key klíč, pro který vrátit data (typicky datum)
|
||||
*/
|
||||
getData<Type>(key: string): Promise<Type>;
|
||||
getData<Type>(key: string): Promise<Type | undefined>;
|
||||
|
||||
/**
|
||||
* Uloží data pod předaný klíč.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Choices, LocationKey } from "../../types";
|
||||
import { LunchChoice, LunchChoices } from "../../types";
|
||||
|
||||
const DAY_OF_WEEK_FORMAT = new Intl.DateTimeFormat(undefined, {weekday: 'long'});
|
||||
const DAY_OF_WEEK_FORMAT = new Intl.DateTimeFormat(undefined, { weekday: 'long' });
|
||||
|
||||
/** Vrátí datum v ISO formátu. */
|
||||
export function formatDate(date: Date, format?: string) {
|
||||
@@ -114,13 +114,13 @@ export const checkBodyParams = (req: any, paramNames: string[]) => {
|
||||
// TODO umístit do samostatného souboru
|
||||
export class InsufficientPermissions extends Error { }
|
||||
|
||||
export const getUsersByLocation = (choices: Choices, login: string): string[] => {
|
||||
export const getUsersByLocation = (choices: LunchChoices, login?: string): string[] => {
|
||||
const result: string[] = [];
|
||||
|
||||
for (const location of Object.entries(choices)) {
|
||||
const locationKey = location[0] as LocationKey;
|
||||
const locationKey = location[0] as keyof typeof LunchChoice;
|
||||
const locationValue = location[1];
|
||||
if (locationValue[login]) {
|
||||
if (login && locationValue[login]) {
|
||||
for (const username in choices[locationKey]) {
|
||||
if (choices[locationKey].hasOwnProperty(username)) {
|
||||
result.push(username);
|
||||
|
||||
@@ -15,7 +15,7 @@ const STORAGE_KEY = 'voting';
|
||||
* @returns pole voleb
|
||||
*/
|
||||
export async function getUserVotes(login: string) {
|
||||
const data: VotingData = await storage.getData(STORAGE_KEY);
|
||||
const data = await storage.getData<VotingData>(STORAGE_KEY);
|
||||
return data?.[login] || [];
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function getUserVotes(login: string) {
|
||||
* @returns aktuální data
|
||||
*/
|
||||
export async function updateFeatureVote(login: string, option: FeatureRequest, active: boolean): Promise<VotingData> {
|
||||
let data: VotingData = await storage.getData(STORAGE_KEY);
|
||||
let data = await storage.getData<VotingData>(STORAGE_KEY);
|
||||
if (data == null) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user