Refaktor, rozdělení api, zpřehlednění kódu
This commit is contained in:
parent
829197e17a
commit
74893c38eb
@ -1,121 +0,0 @@
|
|||||||
import { toast } from "react-toastify";
|
|
||||||
import { FeatureRequest, PizzaOrder } from "./types";
|
|
||||||
import { getBaseUrl, getToken } from "./Utils";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper pro volání API, u kterých chceme automaticky zobrazit toaster s chybou ze serveru.
|
|
||||||
*
|
|
||||||
* @param apiFunction volaná API funkce
|
|
||||||
*/
|
|
||||||
export function errorHandler<T>(apiFunction: () => Promise<T>): Promise<T> {
|
|
||||||
return new Promise<T>((resolve, reject) => {
|
|
||||||
apiFunction().then((result) => {
|
|
||||||
resolve(result);
|
|
||||||
}).catch(e => {
|
|
||||||
toast.error(e.message, { theme: "colored" });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function request<TResponse>(
|
|
||||||
url: string,
|
|
||||||
config: RequestInit = {}
|
|
||||||
): Promise<TResponse> {
|
|
||||||
config.headers = config?.headers ? new Headers(config.headers) : new Headers();
|
|
||||||
config.headers.set("Authorization", `Bearer ${getToken()}`);
|
|
||||||
try {
|
|
||||||
const response = await fetch(getBaseUrl() + url, config);
|
|
||||||
if (!response.ok) {
|
|
||||||
const json = await response.json();
|
|
||||||
// Vyhodíme samotnou hlášku z odpovědi, odchytí si jí errorHandler
|
|
||||||
throw new Error(json.error);
|
|
||||||
}
|
|
||||||
return response.json() as TResponse;
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
get: <TResponse>(url: string) => request<TResponse>(url),
|
|
||||||
post: <TBody extends BodyInit, TResponse>(url: string, body: TBody) => request<TResponse>(url, { method: 'POST', body, headers: { 'Content-Type': 'application/json' } }),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getQrUrl = (login: string) => {
|
|
||||||
return `${getBaseUrl()}/api/qr?login=${login}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getData = async (dayIndex?: number) => {
|
|
||||||
let url = '/api/data';
|
|
||||||
if (dayIndex != null) {
|
|
||||||
url += '?dayIndex=' + dayIndex;
|
|
||||||
}
|
|
||||||
return await api.get<any>(url);
|
|
||||||
}
|
|
||||||
export const createPizzaDay = async () => {
|
|
||||||
return await api.post<any, any>('/api/createPizzaDay', undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deletePizzaDay = async () => {
|
|
||||||
return await api.post<any, any>('/api/deletePizzaDay', undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const lockPizzaDay = async () => {
|
|
||||||
return await api.post<any, any>('/api/lockPizzaDay', undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const unlockPizzaDay = async () => {
|
|
||||||
return await api.post<any, any>('/api/unlockPizzaDay', undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const finishOrder = async () => {
|
|
||||||
return await api.post<any, any>('/api/finishOrder', undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const finishDelivery = async (bankAccount?: string, bankAccountHolder?: string) => {
|
|
||||||
return await api.post<any, any>('/api/finishDelivery', JSON.stringify({ bankAccount, bankAccountHolder }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const addChoice = async (locationIndex: number, foodIndex?: number, dayIndex?: number) => {
|
|
||||||
return await api.post<any, any>('/api/addChoice', JSON.stringify({ locationIndex, foodIndex, dayIndex }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeChoices = async (locationIndex: number, dayIndex?: number) => {
|
|
||||||
return await api.post<any, any>('/api/removeChoices', JSON.stringify({ locationIndex, dayIndex }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeChoice = async (locationIndex: number, foodIndex: number, dayIndex?: number) => {
|
|
||||||
return await api.post<any, any>('/api/removeChoice', JSON.stringify({ locationIndex, foodIndex, dayIndex }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const addPizza = async (pizzaIndex: number, pizzaSizeIndex: number) => {
|
|
||||||
return await api.post<any, any>('/api/addPizza', JSON.stringify({ pizzaIndex, pizzaSizeIndex }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removePizza = async (pizzaOrder: PizzaOrder) => {
|
|
||||||
return await api.post<any, any>('/api/removePizza', JSON.stringify({ pizzaOrder }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const updatePizzaDayNote = async (note?: string) => {
|
|
||||||
return await api.post<any, any>('/api/updatePizzaDayNote', JSON.stringify({ note }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const login = async (login?: string) => {
|
|
||||||
return await api.post<any, any>('/api/login', JSON.stringify({ login }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const changeDepartureTime = async (time: string, dayIndex?: number) => {
|
|
||||||
return await api.post<any, any>('/api/changeDepartureTime', JSON.stringify({ time, dayIndex }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const updatePizzaFee = async (login: string, text?: string, price?: number) => {
|
|
||||||
return await api.post<any, any>('/api/updatePizzaFee', JSON.stringify({ login, text, price }));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getFeatureVotes = async () => {
|
|
||||||
return await api.get<any>('/api/getFeatureVotes');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const updateFeatureVote = async (option: FeatureRequest, active: boolean) => {
|
|
||||||
return await api.post<any, any>('/api/updateFeatureVote', JSON.stringify({ option, active }));
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
import React, { useContext, useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
import { EVENT_DISCONNECT, EVENT_MESSAGE, SocketContext } from './context/socket';
|
import { EVENT_DISCONNECT, EVENT_MESSAGE, SocketContext } from './context/socket';
|
||||||
import { addChoice, addPizza, changeDepartureTime, createPizzaDay, deletePizzaDay, errorHandler, finishDelivery, finishOrder, getData, getQrUrl, lockPizzaDay, removeChoice, removeChoices, removePizza, unlockPizzaDay, updatePizzaDayNote } from './Api';
|
import { addPizza, createPizzaDay, deletePizzaDay, finishDelivery, finishOrder, lockPizzaDay, removePizza, unlockPizzaDay, updatePizzaDayNote } from './api/PizzaDayApi';
|
||||||
import { useAuth } from './context/auth';
|
import { useAuth } from './context/auth';
|
||||||
import Login from './Login';
|
import Login from './Login';
|
||||||
import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap';
|
import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap';
|
||||||
@ -18,6 +18,8 @@ import { ClientData, Restaurants, Food, Order, Locations, PizzaOrder, PizzaDaySt
|
|||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
|
import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
|
||||||
import Loader from './components/Loader';
|
import Loader from './components/Loader';
|
||||||
|
import { getData, errorHandler, getQrUrl } from './api/Api';
|
||||||
|
import { addChoice, removeChoices, removeChoice, changeDepartureTime } from './api/FoodApi';
|
||||||
|
|
||||||
const EVENT_CONNECT = "connect"
|
const EVENT_CONNECT = "connect"
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useCallback, useEffect, useRef } from 'react';
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
import { Button } from 'react-bootstrap';
|
import { Button } from 'react-bootstrap';
|
||||||
import { useAuth } from './context/auth';
|
import { useAuth } from './context/auth';
|
||||||
import { login } from './Api';
|
import { login } from './api/Api';
|
||||||
import './Login.css';
|
import './Login.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
57
client/src/api/Api.ts
Normal file
57
client/src/api/Api.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { toast } from "react-toastify";
|
||||||
|
import { getBaseUrl, getToken } from "../Utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper pro volání API, u kterých chceme automaticky zobrazit toaster s chybou ze serveru.
|
||||||
|
*
|
||||||
|
* @param apiFunction volaná API funkce
|
||||||
|
*/
|
||||||
|
export function errorHandler<T>(apiFunction: () => Promise<T>): Promise<T> {
|
||||||
|
return new Promise<T>((resolve, reject) => {
|
||||||
|
apiFunction().then((result) => {
|
||||||
|
resolve(result);
|
||||||
|
}).catch(e => {
|
||||||
|
toast.error(e.message, { theme: "colored" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function request<TResponse>(
|
||||||
|
url: string,
|
||||||
|
config: RequestInit = {}
|
||||||
|
): Promise<TResponse> {
|
||||||
|
config.headers = config?.headers ? new Headers(config.headers) : new Headers();
|
||||||
|
config.headers.set("Authorization", `Bearer ${getToken()}`);
|
||||||
|
try {
|
||||||
|
const response = await fetch(getBaseUrl() + url, config);
|
||||||
|
if (!response.ok) {
|
||||||
|
const json = await response.json();
|
||||||
|
// Vyhodíme samotnou hlášku z odpovědi, odchytí si jí errorHandler
|
||||||
|
throw new Error(json.error);
|
||||||
|
}
|
||||||
|
return response.json() as TResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const api = {
|
||||||
|
get: <TResponse>(url: string) => request<TResponse>(url),
|
||||||
|
post: <TBody extends BodyInit, TResponse>(url: string, body: TBody) => request<TResponse>(url, { method: 'POST', body, headers: { 'Content-Type': 'application/json' } }),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getQrUrl = (login: string) => {
|
||||||
|
return `${getBaseUrl()}/api/qr?login=${login}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getData = async (dayIndex?: number) => {
|
||||||
|
let url = '/api/data';
|
||||||
|
if (dayIndex != null) {
|
||||||
|
url += '?dayIndex=' + dayIndex;
|
||||||
|
}
|
||||||
|
return await api.get<any>(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const login = async (login?: string) => {
|
||||||
|
return await api.post<any, any>('/api/login', JSON.stringify({ login }));
|
||||||
|
}
|
19
client/src/api/FoodApi.ts
Normal file
19
client/src/api/FoodApi.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { api } from "./Api";
|
||||||
|
|
||||||
|
const FOOD_API_PREFIX = '/api/food';
|
||||||
|
|
||||||
|
export const addChoice = async (locationIndex: number, foodIndex?: number, dayIndex?: number) => {
|
||||||
|
return await api.post<any, any>(`${FOOD_API_PREFIX}/addChoice`, JSON.stringify({ locationIndex, foodIndex, dayIndex }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removeChoices = async (locationIndex: number, dayIndex?: number) => {
|
||||||
|
return await api.post<any, any>(`${FOOD_API_PREFIX}/removeChoices`, JSON.stringify({ locationIndex, dayIndex }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removeChoice = async (locationIndex: number, foodIndex: number, dayIndex?: number) => {
|
||||||
|
return await api.post<any, any>(`${FOOD_API_PREFIX}/removeChoice`, JSON.stringify({ locationIndex, foodIndex, dayIndex }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const changeDepartureTime = async (time: string, dayIndex?: number) => {
|
||||||
|
return await api.post<any, any>(`${FOOD_API_PREFIX}/changeDepartureTime`, JSON.stringify({ time, dayIndex }));
|
||||||
|
}
|
44
client/src/api/PizzaDayApi.ts
Normal file
44
client/src/api/PizzaDayApi.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { PizzaOrder } from "../types";
|
||||||
|
import { api } from "./Api";
|
||||||
|
|
||||||
|
const PIZZADAY_API_PREFIX = '/api/pizzaDay';
|
||||||
|
|
||||||
|
export const createPizzaDay = async () => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/create`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deletePizzaDay = async () => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/delete`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lockPizzaDay = async () => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/lock`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const unlockPizzaDay = async () => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/unlock`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const finishOrder = async () => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/finishOrder`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const finishDelivery = async (bankAccount?: string, bankAccountHolder?: string) => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/finishDelivery`, JSON.stringify({ bankAccount, bankAccountHolder }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addPizza = async (pizzaIndex: number, pizzaSizeIndex: number) => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/add`, JSON.stringify({ pizzaIndex, pizzaSizeIndex }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removePizza = async (pizzaOrder: PizzaOrder) => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/remove`, JSON.stringify({ pizzaOrder }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updatePizzaDayNote = async (note?: string) => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/updatePizzaDayNote`, JSON.stringify({ note }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updatePizzaFee = async (login: string, text?: string, price?: number) => {
|
||||||
|
return await api.post<any, any>(`${PIZZADAY_API_PREFIX}/updatePizzaFee`, JSON.stringify({ login, text, price }));
|
||||||
|
}
|
12
client/src/api/VotingApi.ts
Normal file
12
client/src/api/VotingApi.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { FeatureRequest } from "../types";
|
||||||
|
import { api } from "./Api";
|
||||||
|
|
||||||
|
const VOTING_API_PREFIX = '/api/voting';
|
||||||
|
|
||||||
|
export const getFeatureVotes = async () => {
|
||||||
|
return await api.get<any>(`${VOTING_API_PREFIX}/getVotes`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateFeatureVote = async (option: FeatureRequest, active: boolean) => {
|
||||||
|
return await api.post<any, any>(`${VOTING_API_PREFIX}/updateVote`, JSON.stringify({ option, active }));
|
||||||
|
}
|
@ -5,7 +5,8 @@ import BankAccountModal from "./modals/BankAccountModal";
|
|||||||
import { useBank } from "../context/bank";
|
import { useBank } from "../context/bank";
|
||||||
import FeaturesVotingModal from "./modals/FeaturesVotingModal";
|
import FeaturesVotingModal from "./modals/FeaturesVotingModal";
|
||||||
import { FeatureRequest } from "../types";
|
import { FeatureRequest } from "../types";
|
||||||
import { errorHandler, getFeatureVotes, updateFeatureVote } from "../Api";
|
import { errorHandler } from "../api/Api";
|
||||||
|
import { getFeatureVotes, updateFeatureVote } from "../api/VotingApi";
|
||||||
|
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Table } from "react-bootstrap";
|
import { Table } from "react-bootstrap";
|
||||||
import { useAuth } from "../context/auth";
|
|
||||||
import { Order, PizzaDayState, PizzaOrder } from "../types";
|
import { Order, PizzaDayState, PizzaOrder } from "../types";
|
||||||
import { updatePizzaFee } from "../Api";
|
|
||||||
import PizzaOrderRow from "./PizzaOrderRow";
|
import PizzaOrderRow from "./PizzaOrderRow";
|
||||||
|
import { updatePizzaFee } from "../api/PizzaDayApi";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
state: PizzaDayState,
|
state: PizzaDayState,
|
||||||
@ -12,8 +11,6 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PizzaOrderList({ state, orders, onDelete, creator }: Props) {
|
export default function PizzaOrderList({ state, orders, onDelete, creator }: Props) {
|
||||||
const auth = useAuth();
|
|
||||||
|
|
||||||
const saveFees = async (customer: string, text?: string, price?: number) => {
|
const saveFees = async (customer: string, text?: string, price?: number) => {
|
||||||
await updatePizzaFee(customer, text, price);
|
await updatePizzaFee(customer, text, price);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import { Server } from "socket.io";
|
|
||||||
import bodyParser from "body-parser";
|
import bodyParser from "body-parser";
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { addChoice, getData, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime } from "./service";
|
import { getData, getDateForWeekIndex } from "./service";
|
||||||
import { addPizzaOrder, createPizzaDay, deletePizzaDay, finishPizzaDelivery, finishPizzaOrder, getPizzaList, lockPizzaDay, removePizzaOrder, unlockPizzaDay, updatePizzaDayNote, updatePizzaFee } from "./pizza";
|
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { getQr } from "./qr";
|
import { getQr } from "./qr";
|
||||||
import { generateToken, getLogin, getTrusted, verify } from "./auth";
|
import { generateToken, verify } from "./auth";
|
||||||
import { InsufficientPermissions, getDayOfWeekIndex } from "./utils";
|
import { InsufficientPermissions } from "./utils";
|
||||||
import { getUserVotes, updateFeatureVote } from "./voting";
|
import { initWebsocket } from "./websocket";
|
||||||
|
import pizzaDayRoutes from "./routes/pizzaDayRoutes";
|
||||||
|
import foodRoutes from "./routes/foodRoutes";
|
||||||
|
import votingRoutes from "./routes/votingRoutes";
|
||||||
|
|
||||||
const ENVIRONMENT = process.env.NODE_ENV || 'production';
|
const ENVIRONMENT = process.env.NODE_ENV || 'production';
|
||||||
dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) });
|
dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) });
|
||||||
@ -21,59 +22,15 @@ if (!process.env.JWT_SECRET) {
|
|||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const server = require("http").createServer(app);
|
const server = require("http").createServer(app);
|
||||||
const io = new Server(server, {
|
initWebsocket(server);
|
||||||
cors: {
|
|
||||||
origin: "*",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Body-parser middleware for parsing JSON
|
// Body-parser middleware for parsing JSON
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
// app.use(express.json());
|
|
||||||
|
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: '*'
|
origin: '*'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// app.use((req, res, next) => {
|
|
||||||
// console.log("--- Request ---")
|
|
||||||
// console.log(req.url);
|
|
||||||
// console.log(req.baseUrl);
|
|
||||||
// console.log(req.originalUrl);
|
|
||||||
// console.log(req.path);
|
|
||||||
// next();
|
|
||||||
// });
|
|
||||||
|
|
||||||
app.use(express.static('public'))
|
|
||||||
|
|
||||||
const parseToken = (req: any) => {
|
|
||||||
if (req?.headers?.authorization) {
|
|
||||||
return req.headers.authorization.split(' ')[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ověří a vrátí index dne v týdnu z požadavku, za předpokladu, že byl předán, a je zároveň
|
|
||||||
* roven nebo vyšší indexu dnešního dne.
|
|
||||||
*
|
|
||||||
* @param req request
|
|
||||||
* @returns index dne v týdnu
|
|
||||||
*/
|
|
||||||
const parseValidateFutureDayIndex = (req: any) => {
|
|
||||||
if (req.body.dayIndex == null) {
|
|
||||||
throw Error(`Nebyl předán index dne v týdnu.`);
|
|
||||||
}
|
|
||||||
const todayDayIndex = getDayOfWeekIndex(getToday());
|
|
||||||
const dayIndex = parseInt(req.body.dayIndex);
|
|
||||||
if (isNaN(dayIndex)) {
|
|
||||||
throw Error(`Neplatný index dne v týdnu: ${req.body.dayIndex}`);
|
|
||||||
}
|
|
||||||
if (dayIndex < todayDayIndex) {
|
|
||||||
throw Error(`Předaný index dne v týdnu (${dayIndex}) nesmí být nižší než dnešní den (${todayDayIndex})`);
|
|
||||||
}
|
|
||||||
return dayIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------- Metody nevyžadující token --------------
|
// ----------- Metody nevyžadující token --------------
|
||||||
|
|
||||||
app.get("/api/whoami", (req, res) => {
|
app.get("/api/whoami", (req, res) => {
|
||||||
@ -113,7 +70,7 @@ app.get("/api/qr", (req, res) => {
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
/** Middleware ověřující JWT token */
|
/** Middleware ověřující JWT token */
|
||||||
app.use((req, res, next) => {
|
app.use("/api/", (req, res, next) => {
|
||||||
const userHeader = req.header('remote-user');
|
const userHeader = req.header('remote-user');
|
||||||
const nameHeader = req.header('remote-name');
|
const nameHeader = req.header('remote-name');
|
||||||
const emailHeader = req.header('remote-email');
|
const emailHeader = req.header('remote-email');
|
||||||
@ -143,205 +100,11 @@ app.get("/api/data", async (req, res) => {
|
|||||||
res.status(200).json(await getData(date));
|
res.status(200).json(await getData(date));
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Založí pizza day pro aktuální den, za předpokladu že dosud neexistuje. */
|
// Ostatní routes
|
||||||
app.post("/api/createPizzaDay", async (req, res) => {
|
app.use("/api/pizzaDay", pizzaDayRoutes);
|
||||||
const login = getLogin(parseToken(req));
|
app.use("/api/food", foodRoutes);
|
||||||
const data = await createPizzaDay(login);
|
app.use("/api/voting", votingRoutes);
|
||||||
res.status(200).json(data);
|
app.use(express.static('public'))
|
||||||
io.emit("message", data);
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Smaže pizza day pro aktuální den, za předpokladu že existuje. */
|
|
||||||
app.post("/api/deletePizzaDay", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await deletePizzaDay(login);
|
|
||||||
io.emit("message", data);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/addPizza", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
if (isNaN(req.body?.pizzaIndex)) {
|
|
||||||
throw Error("Nebyl předán index pizzy");
|
|
||||||
}
|
|
||||||
const pizzaIndex = req.body.pizzaIndex;
|
|
||||||
if (isNaN(req.body?.pizzaSizeIndex)) {
|
|
||||||
throw Error("Nebyl předán index velikosti pizzy");
|
|
||||||
}
|
|
||||||
const pizzaSizeIndex = req.body.pizzaSizeIndex;
|
|
||||||
let pizzy = await getPizzaList();
|
|
||||||
if (!pizzy) {
|
|
||||||
throw Error("Selhalo získání seznamu dostupných pizz.");
|
|
||||||
}
|
|
||||||
if (!pizzy[pizzaIndex]) {
|
|
||||||
throw Error("Neplatný index pizzy: " + pizzaIndex);
|
|
||||||
}
|
|
||||||
if (!pizzy[pizzaIndex].sizes[pizzaSizeIndex]) {
|
|
||||||
throw Error("Neplatný index velikosti pizzy: " + pizzaSizeIndex);
|
|
||||||
}
|
|
||||||
const data = await addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/removePizza", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
if (!req.body?.pizzaOrder) {
|
|
||||||
throw Error("Nebyla předána objednávka");
|
|
||||||
}
|
|
||||||
const data = await removePizzaOrder(login, req.body?.pizzaOrder);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/lockPizzaDay", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await lockPizzaDay(login);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/unlockPizzaDay", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await unlockPizzaDay(login);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/finishOrder", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await finishPizzaOrder(login);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/finishDelivery", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await finishPizzaDelivery(login, req.body.bankAccount, req.body.bankAccountHolder);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json({});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/addChoice", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const trusted = getTrusted(parseToken(req));
|
|
||||||
if (req.body.locationIndex > -1) {
|
|
||||||
let date = undefined;
|
|
||||||
if (req.body.dayIndex != null) {
|
|
||||||
let dayIndex;
|
|
||||||
try {
|
|
||||||
dayIndex = parseValidateFutureDayIndex(req);
|
|
||||||
} catch (e: any) {
|
|
||||||
return res.status(400).json({ error: e.message });
|
|
||||||
}
|
|
||||||
date = getDateForWeekIndex(dayIndex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await addChoice(login, trusted, req.body.locationIndex, req.body.foodIndex, date);
|
|
||||||
io.emit("message", data);
|
|
||||||
return res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
}
|
|
||||||
return res.status(400); // TODO přidat popis chyby
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/removeChoices", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const trusted = getTrusted(parseToken(req));
|
|
||||||
let date = undefined;
|
|
||||||
if (req.body.dayIndex != null) {
|
|
||||||
let dayIndex;
|
|
||||||
try {
|
|
||||||
dayIndex = parseValidateFutureDayIndex(req);
|
|
||||||
} catch (e: any) {
|
|
||||||
return res.status(400).json({ error: e.message });
|
|
||||||
}
|
|
||||||
date = getDateForWeekIndex(dayIndex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await removeChoices(login, trusted, req.body.locationIndex, date);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/removeChoice", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const trusted = getTrusted(parseToken(req));
|
|
||||||
let date = undefined;
|
|
||||||
if (req.body.dayIndex != null) {
|
|
||||||
let dayIndex;
|
|
||||||
try {
|
|
||||||
dayIndex = parseValidateFutureDayIndex(req);
|
|
||||||
} catch (e: any) {
|
|
||||||
return res.status(400).json({ error: e.message });
|
|
||||||
}
|
|
||||||
date = getDateForWeekIndex(dayIndex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await removeChoice(login, trusted, req.body.locationIndex, req.body.foodIndex, date);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/updatePizzaDayNote", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
if (req.body.note && req.body.note.length > 100) {
|
|
||||||
throw Error("Poznámka může mít maximálně 100 znaků");
|
|
||||||
}
|
|
||||||
const data = await updatePizzaDayNote(login, req.body.note);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/changeDepartureTime", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
let date = undefined;
|
|
||||||
if (req.body.dayIndex != null) {
|
|
||||||
let dayIndex;
|
|
||||||
try {
|
|
||||||
dayIndex = parseValidateFutureDayIndex(req);
|
|
||||||
} catch (e: any) {
|
|
||||||
return res.status(400).json({ error: e.message });
|
|
||||||
}
|
|
||||||
date = getDateForWeekIndex(dayIndex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await updateDepartureTime(login, req.body?.time, date);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/updatePizzaFee", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
if (!req.body.login) {
|
|
||||||
return res.status(400).json({ error: "Nebyl předán login cílového uživatele" });
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await updatePizzaFee(login, req.body.login, req.body.text, req.body.price);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/api/getFeatureVotes", async (req, res) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
const data = await getUserVotes(login);
|
|
||||||
res.status(200).json(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/api/updateFeatureVote", async (req, res, next) => {
|
|
||||||
const login = getLogin(parseToken(req));
|
|
||||||
if (req.body?.option == null || req.body?.active == null) {
|
|
||||||
res.status(400).json({ error: "Chybné parametry volání" });
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await updateFeatureVote(login, req.body.option, req.body.active);
|
|
||||||
io.emit("message", data);
|
|
||||||
res.status(200).json(data);
|
|
||||||
} catch (e: any) { next(e) }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Middleware pro zpracování chyb
|
// Middleware pro zpracování chyb
|
||||||
app.use((err: any, req: any, res: any, next: any) => {
|
app.use((err: any, req: any, res: any, next: any) => {
|
||||||
@ -353,18 +116,6 @@ app.use((err: any, req: any, res: any, next: any) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
|
||||||
console.log(`New client connected: ${socket.id}`);
|
|
||||||
|
|
||||||
socket.on("message", (message) => {
|
|
||||||
io.emit("message", message);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("disconnect", () => {
|
|
||||||
console.log(`Client disconnected: ${socket.id}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3001;
|
const PORT = process.env.PORT || 3001;
|
||||||
const HOST = process.env.HOST || '0.0.0.0';
|
const HOST = process.env.HOST || '0.0.0.0';
|
||||||
|
|
||||||
|
113
server/src/routes/foodRoutes.ts
Normal file
113
server/src/routes/foodRoutes.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { getLogin, getTrusted } from "../auth";
|
||||||
|
import { getDateForWeekIndex, addChoice, removeChoices, removeChoice, updateDepartureTime, getToday } from "../service";
|
||||||
|
import { getDayOfWeekIndex, parseToken } from "../utils";
|
||||||
|
import { getWebsocket } from "../websocket";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ověří a vrátí index dne v týdnu z požadavku, za předpokladu, že byl předán, a je zároveň
|
||||||
|
* roven nebo vyšší indexu dnešního dne.
|
||||||
|
*
|
||||||
|
* @param req request
|
||||||
|
* @returns index dne v týdnu
|
||||||
|
*/
|
||||||
|
const parseValidateFutureDayIndex = (req: any) => {
|
||||||
|
if (req.body.dayIndex == null) {
|
||||||
|
throw Error(`Nebyl předán index dne v týdnu.`);
|
||||||
|
}
|
||||||
|
const todayDayIndex = getDayOfWeekIndex(getToday());
|
||||||
|
const dayIndex = parseInt(req.body.dayIndex);
|
||||||
|
if (isNaN(dayIndex)) {
|
||||||
|
throw Error(`Neplatný index dne v týdnu: ${req.body.dayIndex}`);
|
||||||
|
}
|
||||||
|
if (dayIndex < todayDayIndex) {
|
||||||
|
throw Error(`Předaný index dne v týdnu (${dayIndex}) nesmí být nižší než dnešní den (${todayDayIndex})`);
|
||||||
|
}
|
||||||
|
return dayIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.post("/addChoice", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const trusted = getTrusted(parseToken(req));
|
||||||
|
if (req.body.locationIndex > -1) {
|
||||||
|
let date = undefined;
|
||||||
|
if (req.body.dayIndex != null) {
|
||||||
|
let dayIndex;
|
||||||
|
try {
|
||||||
|
dayIndex = parseValidateFutureDayIndex(req);
|
||||||
|
} catch (e: any) {
|
||||||
|
return res.status(400).json({ error: e.message });
|
||||||
|
}
|
||||||
|
date = getDateForWeekIndex(dayIndex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await addChoice(login, trusted, req.body.locationIndex, req.body.foodIndex, date);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
return res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
}
|
||||||
|
return res.status(400); // TODO přidat popis chyby
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/removeChoices", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const trusted = getTrusted(parseToken(req));
|
||||||
|
let date = undefined;
|
||||||
|
if (req.body.dayIndex != null) {
|
||||||
|
let dayIndex;
|
||||||
|
try {
|
||||||
|
dayIndex = parseValidateFutureDayIndex(req);
|
||||||
|
} catch (e: any) {
|
||||||
|
return res.status(400).json({ error: e.message });
|
||||||
|
}
|
||||||
|
date = getDateForWeekIndex(dayIndex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await removeChoices(login, trusted, req.body.locationIndex, date);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/removeChoice", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const trusted = getTrusted(parseToken(req));
|
||||||
|
let date = undefined;
|
||||||
|
if (req.body.dayIndex != null) {
|
||||||
|
let dayIndex;
|
||||||
|
try {
|
||||||
|
dayIndex = parseValidateFutureDayIndex(req);
|
||||||
|
} catch (e: any) {
|
||||||
|
return res.status(400).json({ error: e.message });
|
||||||
|
}
|
||||||
|
date = getDateForWeekIndex(dayIndex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await removeChoice(login, trusted, req.body.locationIndex, req.body.foodIndex, date);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/changeDepartureTime", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
let date = undefined;
|
||||||
|
if (req.body.dayIndex != null) {
|
||||||
|
let dayIndex;
|
||||||
|
try {
|
||||||
|
dayIndex = parseValidateFutureDayIndex(req);
|
||||||
|
} catch (e: any) {
|
||||||
|
return res.status(400).json({ error: e.message });
|
||||||
|
}
|
||||||
|
date = getDateForWeekIndex(dayIndex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await updateDepartureTime(login, req.body?.time, date);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
109
server/src/routes/pizzaDayRoutes.ts
Normal file
109
server/src/routes/pizzaDayRoutes.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import express from "express";
|
||||||
|
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";
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
/** Založí pizza day pro aktuální den, za předpokladu že dosud neexistuje. */
|
||||||
|
router.post("/create", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await createPizzaDay(login);
|
||||||
|
res.status(200).json(data);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Smaže pizza day pro aktuální den, za předpokladu že existuje. */
|
||||||
|
router.post("/delete", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await deletePizzaDay(login);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/add", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
if (isNaN(req.body?.pizzaIndex)) {
|
||||||
|
throw Error("Nebyl předán index pizzy");
|
||||||
|
}
|
||||||
|
const pizzaIndex = req.body.pizzaIndex;
|
||||||
|
if (isNaN(req.body?.pizzaSizeIndex)) {
|
||||||
|
throw Error("Nebyl předán index velikosti pizzy");
|
||||||
|
}
|
||||||
|
const pizzaSizeIndex = req.body.pizzaSizeIndex;
|
||||||
|
let pizzy = await getPizzaList();
|
||||||
|
if (!pizzy) {
|
||||||
|
throw Error("Selhalo získání seznamu dostupných pizz.");
|
||||||
|
}
|
||||||
|
if (!pizzy[pizzaIndex]) {
|
||||||
|
throw Error("Neplatný index pizzy: " + pizzaIndex);
|
||||||
|
}
|
||||||
|
if (!pizzy[pizzaIndex].sizes[pizzaSizeIndex]) {
|
||||||
|
throw Error("Neplatný index velikosti pizzy: " + pizzaSizeIndex);
|
||||||
|
}
|
||||||
|
const data = await addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/remove", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
if (!req.body?.pizzaOrder) {
|
||||||
|
throw Error("Nebyla předána objednávka");
|
||||||
|
}
|
||||||
|
const data = await removePizzaOrder(login, req.body?.pizzaOrder);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/lock", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await lockPizzaDay(login);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/unlock", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await unlockPizzaDay(login);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/finishOrder", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await finishPizzaOrder(login);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/finishDelivery", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await finishPizzaDelivery(login, req.body.bankAccount, req.body.bankAccountHolder);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/updatePizzaDayNote", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
if (req.body.note && req.body.note.length > 100) {
|
||||||
|
throw Error("Poznámka může mít maximálně 100 znaků");
|
||||||
|
}
|
||||||
|
const data = await updatePizzaDayNote(login, req.body.note);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/updatePizzaFee", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
if (!req.body.login) {
|
||||||
|
return res.status(400).json({ error: "Nebyl předán login cílového uživatele" });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await updatePizzaFee(login, req.body.login, req.body.text, req.body.price);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
27
server/src/routes/votingRoutes.ts
Normal file
27
server/src/routes/votingRoutes.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { getLogin } from "../auth";
|
||||||
|
import { parseToken } from "../utils";
|
||||||
|
import { getUserVotes, updateFeatureVote } from "../voting";
|
||||||
|
import { getWebsocket } from "../websocket";
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get("/getVotes", async (req, res) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
const data = await getUserVotes(login);
|
||||||
|
res.status(200).json(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/updateVote", async (req, res, next) => {
|
||||||
|
const login = getLogin(parseToken(req));
|
||||||
|
if (req.body?.option == null || req.body?.active == null) {
|
||||||
|
res.status(400).json({ error: "Chybné parametry volání" });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await updateFeatureVote(login, req.body.option, req.body.active);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
} catch (e: any) { next(e) }
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
@ -39,5 +39,48 @@ export function getIsWeekend(date: Date) {
|
|||||||
return index == 5 || index == 6;
|
return index == 5 || index == 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vrátí JWT token z hlaviček, pokud ho obsahují.
|
||||||
|
*
|
||||||
|
* @param req request
|
||||||
|
* @returns token, pokud ho hlavičky requestu obsahují
|
||||||
|
*/
|
||||||
|
export const parseToken = (req: any) => {
|
||||||
|
if (req?.headers?.authorization) {
|
||||||
|
return req.headers.authorization.split(' ')[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ověří přítomnost (not null) předaných parametrů v URL query.
|
||||||
|
* V případě nepřítomnosti kteréhokoli parametru vyhodí chybu.
|
||||||
|
*
|
||||||
|
* @param req request
|
||||||
|
* @param paramNames pole názvů požadovaných parametrů
|
||||||
|
*/
|
||||||
|
export const checkQueryParams = (req: any, paramNames: string[]) => {
|
||||||
|
for (const name of paramNames) {
|
||||||
|
if (req.query[name] == null) {
|
||||||
|
throw Error(`Nebyl předán parametr '${name}' v query požadavku`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ověří přítomnost (not null) předaných parametrů v těle requestu.
|
||||||
|
* V případě nepřítomnosti kteréhokoli parametru vyhodí chybu.
|
||||||
|
*
|
||||||
|
* @param req request
|
||||||
|
* @param paramNames pole názvů požadovaných parametrů
|
||||||
|
*/
|
||||||
|
export const checkBodyParams = (req: any, paramNames: string[]) => {
|
||||||
|
for (const name of paramNames) {
|
||||||
|
if (req.body[name] == null) {
|
||||||
|
throw Error(`Nebyl předán parametr '${name}' v těle požadavku`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO umístit do samostatného souboru
|
// TODO umístit do samostatného souboru
|
||||||
export class InsufficientPermissions extends Error { }
|
export class InsufficientPermissions extends Error { }
|
28
server/src/websocket.ts
Normal file
28
server/src/websocket.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Server } from "socket.io";
|
||||||
|
import { DefaultEventsMap } from "socket.io/dist/typed-events";
|
||||||
|
|
||||||
|
let io: Server<DefaultEventsMap, DefaultEventsMap, DefaultEventsMap, any>;
|
||||||
|
|
||||||
|
export const initWebsocket = (server: any) => {
|
||||||
|
io = new Server(server, {
|
||||||
|
cors: {
|
||||||
|
origin: "*",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
io.on("connection", (socket) => {
|
||||||
|
console.log(`New client connected: ${socket.id}`);
|
||||||
|
|
||||||
|
socket.on("message", (message) => {
|
||||||
|
io.emit("message", message);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disconnect", () => {
|
||||||
|
console.log(`Client disconnected: ${socket.id}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getWebsocket = () => {
|
||||||
|
return io;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user