From ffc73c76574cb76d60fc7f4acd245380d531989f Mon Sep 17 00:00:00 2001 From: Vladislav Date: Sat, 29 Mar 2025 23:37:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D1=83=D0=B1=D0=BB=D1=8C=20=D0=B4=D0=B2?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B0=D1=89=D0=B8=D0=BC=20=D0=B2=D1=81=D0=B5=20?= =?UTF-8?q?=D0=B2=20=D0=BC=D0=B0=D1=81=D1=82=D0=B5=D1=80,=20=D1=80=D0=B5?= =?UTF-8?q?=D1=88=D0=B0=D1=82=D1=8C=20=D0=BD=D0=B0=D0=B4=D0=BE=20=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=BD=D0=B5=D1=82=20=D0=BF=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=B1=D1=83=D0=B4=D0=B5=D0=BC=20=D0=B0=20=D0=B5=D1=81?= =?UTF-8?q?=D0=BB=D0=B8=20=D1=81=D0=B5=D1=80=D1=8C=D0=B5=D0=B7=D0=BD=D0=BE?= =?UTF-8?q?,=20=D1=82=D0=BE=20=D0=B2=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F:=20=D0=BF=D0=BE=D1=87=D1=82=D0=B8=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80?= =?UTF-8?q?=D1=83=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0,=20=D1=87?= =?UTF-8?q?=D1=83=D0=B2=D1=81=D1=82=D0=B2=D0=B8=D1=82=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BD=D0=B0=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D1=8F=D1=82=D1=81=D1=8F=20=D0=B2=20=D1=84=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D0=B5=20.env,=20=D0=BD=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20doc?= =?UTF-8?q?ker-compose.yml=20=D0=B2=20=D1=81=D1=82=D0=BE=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D1=83=20best=20practice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 10 +++ README.md | 2 +- backend/requirements.txt | 3 +- backend/server.py | 87 +++++++++++++++------------ conf/domain.crt | 1 - conf/domain.key | 1 - {docker => db}/init.sql | 8 +-- docker-compose.yaml | 51 ++++++++++++++++ docker/docker-compose.yml | 51 ---------------- docker/dockfile/Dockerfile | 3 - frontend/index.html | 36 +++++++++++ frontend/static/css/styles.css | 68 +++++++++++++++++++++ {docker/dockfile => nginx}/nginx.conf | 62 +++++++++---------- {conf => nginx/ssl}/domain.conf | 84 ++++++++++++-------------- nginx/ssl/domain.crt | 1 + nginx/ssl/domain.key | 1 + post-receive => scripts/post-receive | 42 ++++++------- scripts/pythonprojects.code-workspace | 11 ++++ 18 files changed, 326 insertions(+), 196 deletions(-) create mode 100644 .env delete mode 100644 conf/domain.crt delete mode 100644 conf/domain.key rename {docker => db}/init.sql (96%) create mode 100644 docker-compose.yaml delete mode 100644 docker/docker-compose.yml delete mode 100644 docker/dockfile/Dockerfile create mode 100644 frontend/index.html create mode 100644 frontend/static/css/styles.css rename {docker/dockfile => nginx}/nginx.conf (95%) rename {conf => nginx/ssl}/domain.conf (59%) create mode 100644 nginx/ssl/domain.crt create mode 100644 nginx/ssl/domain.key rename post-receive => scripts/post-receive (59%) create mode 100644 scripts/pythonprojects.code-workspace diff --git a/.env b/.env new file mode 100644 index 0000000..f35b68a --- /dev/null +++ b/.env @@ -0,0 +1,10 @@ +#Пример .env файла. Используем его чтобы не указывать чувствительные данные (пароли, ключи, API и т.д.) напрямую в коде +# PostgreSQL +POSTGRES_USER=user +POSTGRES_PASSWORD=password +POSTGRES_DB=website +DB_HOST=database + +# Nginx bublick & private key +SSL_CERT_FILE=./nginx/ssl/domain.crt +SSL_KEY_FILE=./nginx/ssl/domain.key \ No newline at end of file diff --git a/README.md b/README.md index 0186ba6..60806e8 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Первый пуш, не гарантирую работоспособность этого кода \ No newline at end of file +Все в дом все в дом diff --git a/backend/requirements.txt b/backend/requirements.txt index 88c17be..6a1a434 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,2 +1,3 @@ Flask -psycopg2-binary \ No newline at end of file +psycopg2-binary +python-dotenv \ No newline at end of file diff --git a/backend/server.py b/backend/server.py index e70d1cf..c2e6566 100644 --- a/backend/server.py +++ b/backend/server.py @@ -1,20 +1,26 @@ from flask import Flask, request, render_template import psycopg2 +import os +from dotenv import load_dotenv +load_dotenv() app = Flask(__name__, template_folder='/media/frontend') - DATABASE = { - 'dbname': 'WebSite', - 'user': 'User', - 'password': 'Password', - 'host': 'DataBase', + 'dbname': os.getenv('POSTGRES_DB'), + 'user': os.getenv('POSTGRES_USER'), + 'password': os.getenv('POSTGRES_PASSWORD'), + 'host': os.getenv('DB_HOST') } def get_db_connection(): - conn = psycopg2.connect(**DATABASE) - return conn + try: + conn = psycopg2.connect(**DATABASE) + return conn + except psycopg2.Error as e: + print(f"Ошибка подключения к базе данных: {e}") + raise @app.route('/', methods=['GET']) def index(): @@ -23,45 +29,50 @@ def index(): @app.route('/submit', methods=['POST']) def submit(): action = request.form.get('action') + message = "" - if action == 'Login': - username = request.form.get('username') - password = request.form.get('password') - + try: conn = get_db_connection() cur = conn.cursor() - cur.execute('SELECT * FROM users WHERE username = %s AND password = %s', (username, password)) - user = cur.fetchone() + if action == 'Login': + username = request.form.get('username') + password = request.form.get('password') - cur.close() - conn.close() + cur.execute( + 'SELECT * FROM users WHERE username = %s AND password = %s', + (username, password) + ) + user = cur.fetchone() + + message = "Успешный вход!" if user else "Неправильные имя пользователя или пароль!" + + elif action == 'Register': + new_username = request.form.get('new_username') + new_password = request.form.get('new_password') + + cur.execute('SELECT * FROM users WHERE username = %s', (new_username,)) + if cur.fetchone(): + message = "Пользователь уже существует!" + else: + cur.execute( + 'INSERT INTO users (username, password) VALUES (%s, %s)', + (new_username, new_password) + ) + conn.commit() + message = "Успешная регистрация!" - if user: - message = "Login successful!" else: - message = "Invalid username or password." + message = "Неизвестное действие" - elif action == 'Register': - new_username = request.form.get('new_username') - new_password = request.form.get('new_password') - - conn = get_db_connection() - cur = conn.cursor() - - cur.execute('SELECT * FROM users WHERE username = %s', (new_username,)) - if cur.fetchone(): - message = "User already exists!" - else: - cur.execute('INSERT INTO users (username, password) VALUES (%s, %s)', (new_username, new_password)) - conn.commit() - message = "Registration successful!" - - cur.close() - conn.close() - - else: - message = "Invalid action." + except psycopg2.Error as e: + conn.rollback() + message = f"Ошибка базы данных: {e}" + finally: + if 'cur' in locals(): + cur.close() + if 'conn' in locals(): + conn.close() return render_template('index.html', message=message) diff --git a/conf/domain.crt b/conf/domain.crt deleted file mode 100644 index 4318e83..0000000 --- a/conf/domain.crt +++ /dev/null @@ -1 +0,0 @@ -Наш сертификат \ No newline at end of file diff --git a/conf/domain.key b/conf/domain.key deleted file mode 100644 index e04f70f..0000000 --- a/conf/domain.key +++ /dev/null @@ -1 +0,0 @@ -Приватный ключ \ No newline at end of file diff --git a/docker/init.sql b/db/init.sql similarity index 96% rename from docker/init.sql rename to db/init.sql index 1826275..6ca779b 100644 --- a/docker/init.sql +++ b/db/init.sql @@ -1,5 +1,5 @@ -CREATE TABLE users ( - id SERIAL PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - password VARCHAR(50) NOT NULL +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(50) NOT NULL ); \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..ce6f781 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,51 @@ +services: + database: + image: postgres:17.4-alpine3.21 + container_name: database + ports: + - "5432:5432" + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + +#Монтируем директорию на хосте, чтобы при повторных "docker-compose up" таблицы с нашими данными сохранялись + volumes: + - /database:/var/lib/postgresql/data + cpus: '0.15' + mem_limit: 256M + + healthcheck: + test: ["CMD-SHELL", "pg_isready -U admin -WebSite"] + interval: 5s + timeout: 5s + retries: 5 + + webserver: + image: nginx:1.27.4-alpine + container_name: webserver + ports: + - "80:80" + - "443:443" + volumes: + - /WebApp/frontend:/usr/share/nginx/html + - /WebApp/nginx/ssl:/etc/nginx/sites-available + - /WebApp/nginx/nginx.conf:/etc/nginx/nginx.conf + + depends_on: + - database + - backend + cpus: '0.15' + mem_limit: 256M + backend: + image: python:3.9 + container_name: backend_part + ports: + - "5000:5000" + volumes: + - /WebApp/backend:/media/backend + working_dir: /media/backend + command: > + sh -c "pip install -r requirements.txt && python server.py" + cpus: '0.35' + mem_limit: 256M diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index 4764d74..0000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,51 +0,0 @@ -services: - - DataBase: - image: postgres:latest - container_name: DataBase - ports: - - "5432:5432" -#Так никто не делает в реальных кейсах, я просто даун, не умею работать с секретами (опция secrets) - environment: - POSTGRES_USER: user - POSTGRES_PASSWORD: password - POSTGRES_DB: WebSite - volumes: - - /home/git/myprojects/database:/var/lib/postgresql/data - cpus: '0.15' - mem_limit: 256M - - healthcheck: - test: ["CMD-SHELL", "pg_isready -U admin -WebSite"] - interval: 5s - timeout: 5s - retries: 5 - - webserver: - image: nginx:latest - container_name: WebServer - ports: - - "80:80" - - "443:443" - volumes: - - /home/git/myprojects/WorkServer/frontend:/usr/share/nginx/html - - /home/git/myprojects/WorkServer/conf:/etc/nginx/sites-available - - depends_on: - - DataBase - - backend - cpus: '0.15' - mem_limit: 256M - backend: - image: python:3.9 - container_name: backend_part - ports: - - "5000:5000" - volumes: - - /home/git/myprojects/WorkServer/backend:/media/backend - - /home/git/myprojects/WorkServer/frontend:/media/frontend - working_dir: /media/backend - command: > - sh -c "pip install -r requirements.txt && python server.py" - cpus: '0.35' - mem_limit: 256M diff --git a/docker/dockfile/Dockerfile b/docker/dockfile/Dockerfile deleted file mode 100644 index b3f3e81..0000000 --- a/docker/dockfile/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM nginx:v1 - -COPY nginx.conf /etc/nginx/nginx.conf diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..37a49d8 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,36 @@ + + + + + + Login and Register Form + + + +
+

Login Form

+
+
+

+ +
+

+ + +
+
+ +
+

Register Form

+
+
+

+ +
+

+ + +
+
+ + \ No newline at end of file diff --git a/frontend/static/css/styles.css b/frontend/static/css/styles.css new file mode 100644 index 0000000..cb4948e --- /dev/null +++ b/frontend/static/css/styles.css @@ -0,0 +1,68 @@ +/* Общие стили */ +body { + font-family: Arial, sans-serif; + background-color: #f4f4f4; + margin: 0; + padding: 20px; + display: flex; + flex-direction: column; /* Располагаем контейнеры вертикально */ + justify-content: center; + align-items: center; + min-height: 100vh; +} + + +/* Контейнер для форм */ +.form-container { /* Изменили селектор на класс .form-container */ + width: 100%; + max-width: 400px; + padding: 20px; + background-color: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + margin-bottom: 20px; +} + + +/* Заголовки */ +h1 { + text-align: center; + color: #333; + margin-bottom: 20px; +} + +/* Метки (labels) */ +label { + display: block; + margin-bottom: 5px; + font-weight: bold; + color: #555; +} + +/* Поля ввода (input) */ +input[type="text"], +input[type="password"] { + width: 100%; + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; +} + +/* Кнопки */ +button { + background-color: #4CAF50; + color: white; + padding: 12px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + width: 100%; + font-size: 16px; + transition: background-color 0.3s ease; +} + +button:hover { + background-color: #45a049; +} diff --git a/docker/dockfile/nginx.conf b/nginx/nginx.conf similarity index 95% rename from docker/dockfile/nginx.conf rename to nginx/nginx.conf index 7d234da..c1e413b 100644 --- a/docker/dockfile/nginx.conf +++ b/nginx/nginx.conf @@ -1,32 +1,32 @@ - -user nginx; -worker_processes auto; - -error_log /var/log/nginx/error.log notice; -pid /var/run/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - - include /etc/nginx/sites-available/domain.conf; + +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/sites-available/domain.conf; } \ No newline at end of file diff --git a/conf/domain.conf b/nginx/ssl/domain.conf similarity index 59% rename from conf/domain.conf rename to nginx/ssl/domain.conf index ee27ffb..3fb7793 100644 --- a/conf/domain.conf +++ b/nginx/ssl/domain.conf @@ -1,44 +1,40 @@ -server { - listen 80; - server_name your_domain.com; - return 301 https://your_domain.com$request_uri; -} - - -server { - listen 443 ssl; - server_name your_domain.com; - - - ssl_certificate /etc/nginx/sites-available/domain.crt; - ssl_certificate_key /etc/nginx/sites-available/domain.key; - - - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers on; - - - root /usr/share/nginx/html; - - - location / { - try_files $uri $uri/ /index.html; - } - - - location /submit { - proxy_pass http://backend_part:5000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; -} - location /api { - proxy_pass http://backend_part:5000/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } -} - +server { + listen 80; + server_name your_doman.com www.your_doman.com; + return 301 https://your_doman.com$request_uri; +} + + +server { + listen 443 ssl; + server_name your_doman.com www.your_doman.com; + + + ssl_certificate /etc/nginx/sites-available/domain.crt; + ssl_certificate_key /etc/nginx/sites-available/domain.key; + + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + + root /usr/share/nginx/html; + + + location / { + try_files $uri $uri/ /index.html; + } + + + location /submit { + proxy_pass http://backend_part:5000; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} + +} + diff --git a/nginx/ssl/domain.crt b/nginx/ssl/domain.crt new file mode 100644 index 0000000..6acf75e --- /dev/null +++ b/nginx/ssl/domain.crt @@ -0,0 +1 @@ +Наш публичный ключ \ No newline at end of file diff --git a/nginx/ssl/domain.key b/nginx/ssl/domain.key new file mode 100644 index 0000000..58c85d4 --- /dev/null +++ b/nginx/ssl/domain.key @@ -0,0 +1 @@ +Наш приватный ключ \ No newline at end of file diff --git a/post-receive b/scripts/post-receive similarity index 59% rename from post-receive rename to scripts/post-receive index 0c79293..010ea92 100644 --- a/post-receive +++ b/scripts/post-receive @@ -1,21 +1,21 @@ -#!/bin/bash - -TARGET="/home/git/myprojects/WorkServer" -GIT_DIR="/home/git/myprojects/web" -BRANCH="master" - -git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f "$BRANCH" - -cd /home/git/myprojects/WorkServer/docker - -#docker-compose block: - -# 1 -docker-compose build - -# 2 -docker-compose down - -# 3 -docker-compose up -d - +#!/bin/bash + +TARGET="path to work repo" +GIT_DIR="Path to .git repo" +BRANCH="master" + +git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f "$BRANCH" + +cd $TARGET + +#docker-compose block: + +# 1 +docker-compose build + +# 2 +docker-compose down + +# 3 +docker-compose up -d + diff --git a/scripts/pythonprojects.code-workspace b/scripts/pythonprojects.code-workspace new file mode 100644 index 0000000..4ae01c0 --- /dev/null +++ b/scripts/pythonprojects.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": "../../../../../PythonProjects/pythonprojects" + }, + { + "path": ".." + } + ], + "settings": {} +} \ No newline at end of file