Compare commits
32 Commits
v1.0
..
prod_docker
| Author | SHA1 | Date | |
|---|---|---|---|
| cf2df0aaac | |||
| 1199d6468f | |||
| 7cd958c31e | |||
| f89cf84a38 | |||
| e3fc1d8659 | |||
| 060f8d01c6 | |||
| 667609d70c | |||
| b05f19acd9 | |||
| 2aa9a968f5 | |||
| 2a4825269b | |||
| e42a2f510a | |||
| d2b22fc71f | |||
| 4df6d243f3 | |||
| 471c0c7a49 | |||
| 75ff65e76b | |||
| 7cf1245ef6 | |||
| 2adbfa75a5 | |||
| 216a1cb1d4 | |||
| 7fc98d6c9f | |||
| e346cf9445 | |||
| c030b6dbe6 | |||
| 6f26b9bbc3 | |||
| a34a70572f | |||
| 4b3c8a2424 | |||
| 568b3bf495 | |||
| 5653d32857 | |||
| 7cf5b8df48 | |||
| 65c5fc0f8f | |||
| b626a67907 | |||
| 6643a176a6 | |||
| 89803754a7 | |||
| 5052b3e83a |
@@ -40,7 +40,7 @@ export const confirmUser = async (username) => {
|
|||||||
console.log(tableName);
|
console.log(tableName);
|
||||||
|
|
||||||
const [createTable] = await pool.query(
|
const [createTable] = await pool.query(
|
||||||
`CREATE TABLE IF NOT EXISTS ${tableName} (
|
`CREATE TABLE IF NOT EXISTS ?? (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
Vorname VARCHAR(100) NOT NULL,
|
Vorname VARCHAR(100) NOT NULL,
|
||||||
Nachname Varchar(100) NOT NULL,
|
Nachname Varchar(100) NOT NULL,
|
||||||
@@ -56,14 +56,16 @@ export const confirmUser = async (username) => {
|
|||||||
Plz_Ort Varchar(100),
|
Plz_Ort Varchar(100),
|
||||||
Zahlungsmethode Varchar(100),
|
Zahlungsmethode Varchar(100),
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)`
|
)`,
|
||||||
|
[tableName],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (createTable) {
|
if (createTable) {
|
||||||
let nextID;
|
let nextID;
|
||||||
const getNextID = async () => {
|
const getNextID = async () => {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`SELECT id FROM ${tableName} ORDER BY id DESC LIMIT 1`
|
`SELECT id FROM ?? ORDER BY id DESC LIMIT 1`,
|
||||||
|
[tableName],
|
||||||
);
|
);
|
||||||
nextID = rows.length > 0 ? rows[0].id + 1 : 1;
|
nextID = rows.length > 0 ? rows[0].id + 1 : 1;
|
||||||
};
|
};
|
||||||
@@ -87,8 +89,9 @@ export const newEntry = async (formData, username) => {
|
|||||||
const tableName = confirmation.tableName;
|
const tableName = confirmation.tableName;
|
||||||
|
|
||||||
const [result] = await pool.query(
|
const [result] = await pool.query(
|
||||||
`INSERT INTO ${tableName} (Vorname, Nachname, EMail, Telefonnummer, Lose, Firmenname, Vorname_Geschaeftlich, Nachname_Geschaeftlich, EMail_Geschaeftlich, Telefonnummer_Geschaeftlich, Strasse_Hausnr, Plz_Ort, Zahlungsmethode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
`INSERT INTO ?? (Vorname, Nachname, EMail, Telefonnummer, Lose, Firmenname, Vorname_Geschaeftlich, Nachname_Geschaeftlich, EMail_Geschaeftlich, Telefonnummer_Geschaeftlich, Strasse_Hausnr, Plz_Ort, Zahlungsmethode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
[
|
[
|
||||||
|
tableName,
|
||||||
formData.firstName,
|
formData.firstName,
|
||||||
formData.lastName,
|
formData.lastName,
|
||||||
formData.email,
|
formData.email,
|
||||||
@@ -102,7 +105,7 @@ export const newEntry = async (formData, username) => {
|
|||||||
formData.street,
|
formData.street,
|
||||||
formData.postalCode,
|
formData.postalCode,
|
||||||
formData.paymentMethod,
|
formData.paymentMethod,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { success: true, insertId: result.insertId };
|
return { success: true, insertId: result.insertId };
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ CREATE TABLE users (
|
|||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* This scheme does not have to be implemented manually. It always will be generated by the backend */
|
||||||
CREATE TABLE xx_DD_MM_YYYY (
|
CREATE TABLE xx_DD_MM_YYYY (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
Vorname VARCHAR(100) NOT NULL,
|
Vorname VARCHAR(100) NOT NULL,
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
services:
|
|
||||||
frontend:
|
|
||||||
container_name: ca-lose-frontend
|
|
||||||
hostname: lose-verkaufen
|
|
||||||
build: ./frontend
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
ipv4_address: 172.25.0.2
|
|
||||||
proxynet:
|
|
||||||
ipv4_address: 172.20.0.61
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
backend:
|
|
||||||
container_name: ca-lose-backend
|
|
||||||
hostname: backend
|
|
||||||
build: ./backend
|
|
||||||
environment:
|
|
||||||
NODE_ENV: production
|
|
||||||
DB_HOST: ca-lose-mysql
|
|
||||||
DB_USER: root
|
|
||||||
DB_PASSWORD: ${DB_PASSWORD}
|
|
||||||
DB_NAME: ca_lose
|
|
||||||
depends_on:
|
|
||||||
- database
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
ipv4_address: 172.25.0.3
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
database:
|
|
||||||
container_name: ca-lose-mysql
|
|
||||||
hostname: database
|
|
||||||
image: mysql:8.0
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
|
||||||
MYSQL_DATABASE: ca_lose
|
|
||||||
TZ: Europe/Berlin
|
|
||||||
volumes:
|
|
||||||
- ca-lose_mysql:/var/lib/mysql
|
|
||||||
- ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
ipv4_address: 172.25.0.4
|
|
||||||
proxynet:
|
|
||||||
ipv4_address: 172.20.0.60
|
|
||||||
|
|
||||||
# DNS Server für Hostname-Auflösung innerhalb des VPN
|
|
||||||
dnsmasq:
|
|
||||||
container_name: ca-lose-dns
|
|
||||||
image: andyshinn/dnsmasq:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
command: >
|
|
||||||
--no-daemon
|
|
||||||
--log-queries
|
|
||||||
--address=/lose-verkaufen/172.25.0.2
|
|
||||||
--address=/frontend/172.25.0.2
|
|
||||||
--address=/backend/172.25.0.3
|
|
||||||
--address=/database/172.25.0.4
|
|
||||||
--address=/wg-admin/172.25.0.10
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
ipv4_address: 172.25.0.53
|
|
||||||
|
|
||||||
# WireGuard VPN mit Web-UI (wg-easy)
|
|
||||||
wireguard:
|
|
||||||
image: ghcr.io/wg-easy/wg-easy:latest
|
|
||||||
container_name: ca-lose-wireguard
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_MODULE
|
|
||||||
environment:
|
|
||||||
LANG: de
|
|
||||||
WG_HOST: dus3.the1s.de
|
|
||||||
WG_PORT: "51830"
|
|
||||||
PORT: "51821"
|
|
||||||
WG_DEFAULT_ADDRESS: 10.14.14.x
|
|
||||||
WG_DEFAULT_DNS: "172.25.0.53"
|
|
||||||
WG_ALLOWED_IPS: 172.25.0.0/24
|
|
||||||
WG_PERSISTENT_KEEPALIVE: "25"
|
|
||||||
WG_POST_UP: "iptables -t nat -A POSTROUTING -s 10.14.14.0/24 -o eth0 -j MASQUERADE; iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT; iptables -A FORWARD -i eth0 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -A FORWARD -i wg0 -d 172.25.0.2 -j ACCEPT; iptables -A FORWARD -i wg0 -d 172.25.0.53 -j ACCEPT; iptables -A FORWARD -i wg0 -j DROP"
|
|
||||||
WG_POST_DOWN: "iptables -t nat -D POSTROUTING -s 10.14.14.0/24 -o eth0 -j MASQUERADE; iptables -D FORWARD -i wg0 -o eth0 -j ACCEPT; iptables -D FORWARD -i eth0 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -D FORWARD -i wg0 -d 172.25.0.2 -j ACCEPT; iptables -D FORWARD -i wg0 -d 172.25.0.53 -j ACCEPT; iptables -D FORWARD -i wg0 -j DROP"
|
|
||||||
volumes:
|
|
||||||
- wireguard-data:/etc/wireguard
|
|
||||||
- /lib/modules:/lib/modules:ro
|
|
||||||
ports:
|
|
||||||
- "51830:51830/udp"
|
|
||||||
sysctls:
|
|
||||||
- net.ipv4.ip_forward=1
|
|
||||||
- net.ipv4.conf.all.src_valid_mark=1
|
|
||||||
restart: unless-stopped
|
|
||||||
depends_on:
|
|
||||||
- dnsmasq
|
|
||||||
- frontend
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
ipv4_address: 172.25.0.10
|
|
||||||
proxynet:
|
|
||||||
ipv4_address: 172.20.0.50
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
ca-lose_mysql:
|
|
||||||
wireguard-data:
|
|
||||||
|
|
||||||
networks:
|
|
||||||
ca-lose-internal:
|
|
||||||
driver: bridge
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: 172.25.0.0/24
|
|
||||||
gateway: 172.25.0.1
|
|
||||||
proxynet:
|
|
||||||
external: true
|
|
||||||
+75
-13
@@ -1,16 +1,19 @@
|
|||||||
services:
|
services:
|
||||||
# frontend:
|
frontend:
|
||||||
# container_name: ca-lose-frontend
|
container_name: ca-lose-frontend
|
||||||
# build: ./frontend
|
hostname: lose-verkaufen
|
||||||
# ports:
|
build: ./frontend
|
||||||
# - "8002:80"
|
depends_on:
|
||||||
# restart: unless-stopped
|
- backend
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
ipv4_address: 172.25.0.2
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
container_name: ca-lose-backend
|
container_name: ca-lose-backend
|
||||||
|
hostname: backend
|
||||||
build: ./backend
|
build: ./backend
|
||||||
ports:
|
|
||||||
- "8004:8004"
|
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
DB_HOST: ca-lose-mysql
|
DB_HOST: ca-lose-mysql
|
||||||
@@ -19,21 +22,80 @@ services:
|
|||||||
DB_NAME: ca_lose
|
DB_NAME: ca_lose
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
ipv4_address: 172.25.0.3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: ca-lose-mysql
|
container_name: ca-lose-mysql
|
||||||
|
hostname: database
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
|
||||||
- "3311:3306"
|
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
||||||
MYSQL_DATABASE: ca_lose
|
MYSQL_DATABASE: ca_lose
|
||||||
TZ: Europe/Berlin
|
TZ: Europe/Berlin
|
||||||
volumes:
|
volumes:
|
||||||
- ca-lose_mysql:/var/lib/mysql
|
- ../docker/volumes/ca-lose_mysql:/var/lib/mysql
|
||||||
- ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro
|
- ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
ipv4_address: 172.25.0.4
|
||||||
|
|
||||||
volumes:
|
# DNS Server für Hostname-Auflösung innerhalb des VPN
|
||||||
ca-lose_mysql:
|
dnsmasq:
|
||||||
|
container_name: ca-lose-dns
|
||||||
|
image: andyshinn/dnsmasq:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
command: >
|
||||||
|
--no-daemon
|
||||||
|
--log-queries
|
||||||
|
--address=/lose-verkaufen/172.25.0.2
|
||||||
|
--address=/frontend/172.25.0.2
|
||||||
|
--address=/backend/172.25.0.3
|
||||||
|
--address=/database/172.25.0.4
|
||||||
|
--address=/wireguard/172.25.0.6
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
ipv4_address: 172.25.0.5
|
||||||
|
|
||||||
|
# WireGuard VPN mit Web-UI (wg-easy)
|
||||||
|
wireguard:
|
||||||
|
image: ghcr.io/wg-easy/wg-easy:latest
|
||||||
|
container_name: ca-lose-wireguard
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_MODULE
|
||||||
|
environment:
|
||||||
|
LANG: de
|
||||||
|
WG_HOST: dus3.the1s.de
|
||||||
|
WG_PORT: "51830"
|
||||||
|
WG_DEFAULT_DNS: "172.25.0.5"
|
||||||
|
PORT: "80" # Web-UI Port
|
||||||
|
PASSWORD_HASH: ${WIREGUARD_PASSWORD_HASH}
|
||||||
|
volumes:
|
||||||
|
- ../docker/volumes/ca-lose-wireguard:/etc/wireguard
|
||||||
|
- /lib/modules:/lib/modules:ro
|
||||||
|
ports:
|
||||||
|
- "51830:51830/udp"
|
||||||
|
# - "51831:80/tcp" # only for short configuration access - remove in production - external: 51831 internal: 80
|
||||||
|
sysctls:
|
||||||
|
- net.ipv4.ip_forward=1
|
||||||
|
- net.ipv4.conf.all.src_valid_mark=1
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- dnsmasq
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
ipv4_address: 172.25.0.6
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ca-lose-internal:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 172.25.0.0/24
|
||||||
|
gateway: 172.25.0.1
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const API_BASE =
|
||||||
|
(import.meta as any).env?.VITE_BACKEND_URL ||
|
||||||
|
import.meta.env.VITE_BACKEND_URL ||
|
||||||
|
"http://localhost:8004";
|
||||||
@@ -10,12 +10,15 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
|
IconButton,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { submitFormData } from "../utils/sender";
|
import { submitFormData } from "../utils/sender";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import TranslateIcon from "@mui/icons-material/Translate";
|
||||||
|
import { API_BASE } from "../config/api.config";
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
type: "error" | "info" | "success" | "warning";
|
type: "error" | "info" | "success" | "warning";
|
||||||
@@ -24,7 +27,7 @@ interface Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const MainForm = () => {
|
export const MainForm = () => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [invoice, setInvoice] = useState(false);
|
const [invoice, setInvoice] = useState(false);
|
||||||
const [msg, setMsg] = useState<Message | null>(null);
|
const [msg, setMsg] = useState<Message | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@@ -47,11 +50,27 @@ export const MainForm = () => {
|
|||||||
const [users, setUsers] = useState<string[]>([]);
|
const [users, setUsers] = useState<string[]>([]);
|
||||||
const [selectedUser, setSelectedUser] = useState<string | null>(null);
|
const [selectedUser, setSelectedUser] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const changeTranslation = () => {
|
||||||
|
const clientLng = i18n.language;
|
||||||
|
|
||||||
|
if (clientLng === "en") {
|
||||||
|
i18n.changeLanguage("de");
|
||||||
|
} else if (clientLng === "de") {
|
||||||
|
i18n.changeLanguage("en");
|
||||||
|
} else {
|
||||||
|
setMsg({
|
||||||
|
type: "error",
|
||||||
|
headline: "Error",
|
||||||
|
text: "Cannot change langugage.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Fetch user data or any other data needed for the form
|
// Fetch user data or any other data needed for the form
|
||||||
try {
|
try {
|
||||||
const fetchUsers = async () => {
|
const fetchUsers = async () => {
|
||||||
const response = await fetch("http://localhost:8004/default/users");
|
const response = await fetch(`${API_BASE}/default/users`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setUsers(data.users);
|
setUsers(data.users);
|
||||||
};
|
};
|
||||||
@@ -80,7 +99,7 @@ export const MainForm = () => {
|
|||||||
const confirmUser = async (selectedUser: string) => {
|
const confirmUser = async (selectedUser: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`http://localhost:8004/default/confirm-user?username=${selectedUser}`,
|
`${API_BASE}/default/confirm-user?username=${selectedUser}`,
|
||||||
);
|
);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setNextID(data.nextID);
|
setNextID(data.nextID);
|
||||||
@@ -129,6 +148,7 @@ export const MainForm = () => {
|
|||||||
elevation={6}
|
elevation={6}
|
||||||
className="w-full rounded-2xl"
|
className="w-full rounded-2xl"
|
||||||
sx={{
|
sx={{
|
||||||
|
position: "relative",
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -143,6 +163,14 @@ export const MainForm = () => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box sx={{ position: "absolute", top: 12, right: 12 }}>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => changeTranslation()}
|
||||||
|
aria-label="translate"
|
||||||
|
>
|
||||||
|
<TranslateIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { API_BASE } from "../config/api.config";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
@@ -18,7 +20,7 @@ export const submitFormData = async (data: FormData, username: string) => {
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`http://localhost:8004/default/new-entry?username=${username}`,
|
`${API_BASE}/default/new-entry?username=${username}`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
Reference in New Issue
Block a user