Přidání základních statistik
Some checks failed
ci/woodpecker/push/workflow Pipeline failed

This commit is contained in:
2025-02-27 00:22:34 +01:00
parent 0af78e72d9
commit ca400638d1
15 changed files with 637 additions and 26 deletions

View File

@@ -12,6 +12,7 @@ import pizzaDayRoutes from "./routes/pizzaDayRoutes";
import foodRoutes from "./routes/foodRoutes";
import votingRoutes from "./routes/votingRoutes";
import easterEggRoutes from "./routes/easterEggRoutes";
import statsRoutes from "./routes/statsRoutes";
const ENVIRONMENT = process.env.NODE_ENV || 'production';
dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) });
@@ -132,6 +133,7 @@ app.use("/api/pizzaDay", pizzaDayRoutes);
app.use("/api/food", foodRoutes);
app.use("/api/voting", votingRoutes);
app.use("/api/easterEggs", easterEggRoutes);
app.use("/api/stats", statsRoutes);
app.use(express.static('public'))
// Middleware pro zpracování chyb

View File

@@ -1,4 +1,4 @@
import { getDayOfWeekIndex } from "./utils";
import { WeeklyStats, Locations } from "../../types";
// Mockovací data pro podporované podniky, na jeden týden
const MOCK_DATA = {
@@ -1383,4 +1383,80 @@ export const getMenuSenkSerikovaMock = () => {
export const getPizzaListMock = () => {
return MOCK_PIZZA_LIST;
}
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),
}
},
{
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),
}
},
{
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),
}
},
{
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),
}
},
{
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),
}
}
];
}

View File

@@ -0,0 +1,22 @@
import express, { Request, Response } from "express";
import { getLogin } from "../auth";
import { parseToken } from "../utils";
import { WeeklyStats } from "../../../types";
import { getStats } from "../stats";
const router = express.Router();
router.get("/", async (req: Request<{}, any, undefined>, res: Response<WeeklyStats>) => {
getLogin(parseToken(req));
if (typeof req.query.startDate === 'string' && typeof req.query.endDate === 'string') {
try {
const data = await getStats(req.query.startDate, req.query.endDate);
return res.status(200).json(data);
} catch (e) {
// necháme to zatím spadnout na 400
}
}
res.sendStatus(400);
});
export default router;

44
server/src/stats.ts Normal file
View File

@@ -0,0 +1,44 @@
import { WeeklyStats, DayData, Locations, DailyStats, LocationKey } from "../../types";
import { getStatsMock } from "./mock";
import getStorage from "./storage";
import { formatDate } from "./utils";
const storage = getStorage();
/**
* Vypočte a vrátí statistiky jednotlivých možností pro předaný rozsah dat.
*
* @param startDate počáteční datum
* @param endDate koncové datum
* @returns statistiky pro zadaný rozsah dat
*/
export async function getStats(startDate: string, endDate: string): Promise<WeeklyStats> {
if (process.env.MOCK_DATA === 'true') {
return getStatsMock();
}
const start = new Date(startDate);
const end = new Date(endDate);
// Dočasná validace, aby to někdo ručně neshodil
const daysDiff = ((end as any) - (start as any)) / (1000 * 60 * 60 * 24);
if (daysDiff > 4) {
throw Error('Neplatný rozsah');
}
const result = [];
for (const date = start; date <= end; date.setDate(date.getDate() + 1)) {
const locationsStats: DailyStats = {
// TODO vytáhnout do utils funkce
date: `${String(date.getDate()).padStart(2, "0")}.${String(date.getMonth() + 1).padStart(2, "0")}.`,
locations: {}
}
const data: DayData = await storage.getData(formatDate(date));
if (data?.choices) {
Object.keys(data.choices).forEach(locationKey => {
locationsStats.locations[locationKey as LocationKey] = Object.keys(data.choices[locationKey as LocationKey]!).length;
})
}
result.push(locationsStats);
}
return result as WeeklyStats;
}