Подготовка проекта к публикации: Docker, чистая установка, разделение папок

- Убраны приватные URL и данные из README и docker-compose.yml
- Добавлен .env.example с примером переменных окружения
- Улучшен Dockerfile: добавлен libcairo2-dev для rlPyCairo
- Убраны fallbacks на общие папки: фото, QR, билеты, логотипы строго внутри event_{id}
- Папка скрин/ и *.txt исключены из git
- Пасхалка о создателе mycloud24.ru сохранена
This commit is contained in:
InviteMe Developer
2026-08-31 17:18:43 +03:00
parent 8b5f3f2c0c
commit 6e7b8dfd3a
9 changed files with 46 additions and 18 deletions
-2
View File
@@ -13,5 +13,3 @@ __pycache__/
*.sqlite3 *.sqlite3
app/static/uploads/* app/static/uploads/*
!app/static/uploads/.gitkeep !app/static/uploads/.gitkeep
111.txt
inviteme_logo.png
+31
View File
@@ -0,0 +1,31 @@
# Скопируйте в .env и замените значения перед запуском
# Обязательно: сильный случайный секретный ключ
# Пример генерации: openssl rand -hex 32
SECRET_KEY=change-me-in-production
# Базовый URL приложения (без слэша в конце), используется в QR-кодах
BASE_URL=https://your-domain.example.com
# Часовой пояс для отображения дат
TIMEZONE=Europe/Moscow
# URI базы данных. По умолчанию SQLite в папке instance/
# DATABASE_URL=sqlite:///app/instance/inviteme.db
# Настройки SMTP (заполняются также через веб-интерфейс)
# MAIL_SERVER=smtp.example.com
# MAIL_PORT=465
# MAIL_USE_SSL=true
# MAIL_USERNAME=noreply@example.com
# MAIL_PASSWORD=your-app-password
# MAIL_DEFAULT_SENDER=InviteMe
# Настройки IMAP для сохранения копий отправленных писем
# IMAP_SERVER=imap.example.com
# IMAP_PORT=993
# IMAP_USE_SSL=true
# IMAP_USERNAME=noreply@example.com
# IMAP_PASSWORD=your-app-password
# IMAP_FOLDER=Sent
# IMAP_SAVE_COPY=false
+5
View File
@@ -1,5 +1,6 @@
.env .env
.env.* .env.*
!.env.example
venv/ venv/
__pycache__/ __pycache__/
*.pyc *.pyc
@@ -17,3 +18,7 @@ app/static/uploads/*
*.log *.log
.DS_Store .DS_Store
Thumbs.db Thumbs.db
# Локальные данные и скриншоты
скрин/
*.txt
+1
View File
@@ -12,6 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libffi-dev \ libffi-dev \
libxml2-dev \ libxml2-dev \
libxslt1-dev \ libxslt1-dev \
libcairo2-dev \
fonts-dejavu-core \ fonts-dejavu-core \
fonts-liberation \ fonts-liberation \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
+3 -2
View File
@@ -21,7 +21,7 @@
Требования: установленный Docker и Docker Compose. Требования: установленный Docker и Docker Compose.
```bash ```bash
git clone ssh://git@192.168.1.101:2222/insight/inviteme.git git clone <URL-репозитория>
cd inviteme cd inviteme
# Собрать и запустить # Собрать и запустить
@@ -37,7 +37,7 @@ docker compose up -d --build
Требования: Python 3.12. Требования: Python 3.12.
```bash ```bash
git clone ssh://git@192.168.1.101:2222/insight/inviteme.git git clone <URL-репозитория>
cd inviteme cd inviteme
python -m venv venv python -m venv venv
@@ -72,6 +72,7 @@ venv\Scripts\python run_waitress.py
- Сразу после первого запуска задайте сильный `SECRET_KEY` через переменную окружения. - Сразу после первого запуска задайте сильный `SECRET_KEY` через переменную окружения.
- Не храните реальные пароли в репозитории — используйте `.env` файл или переменные окружения. - Не храните реальные пароли в репозитории — используйте `.env` файл или переменные окружения.
- Папка `instance/` (SQLite) и `app/static/uploads/` не попадают в git. - Папка `instance/` (SQLite) и `app/static/uploads/` не попадают в git.
- Пример переменных окружения — в файле `.env.example`.
## Переменные окружения ## Переменные окружения
+5 -5
View File
@@ -118,16 +118,16 @@ class Guest(db.Model):
return " ".join(parts) if parts else self.full_name return " ".join(parts) if parts else self.full_name
def _photo_paths(self): def _photo_paths(self):
"""Возвращает возможные пути к фото: сначала папка мероприятия, потом корень.""" """Возвращает путь к фото гостя в папке мероприятия."""
if not self.photo_filename: if not self.photo_filename:
return [] return []
from pathlib import Path from pathlib import Path
from flask import current_app from flask import current_app
base = Path(current_app.config["PHOTO_FOLDER"]) from app.utils.paths import event_photo_folder
paths = [base / self.photo_filename]
if self.event_id: if self.event_id:
paths.insert(0, base / f"event_{self.event_id}" / self.photo_filename) return [event_photo_folder(self.event_id) / self.photo_filename]
return paths # fallback только если мероприятие ещё не назначено
return [Path(current_app.config["PHOTO_FOLDER"]) / self.photo_filename]
@property @property
def has_photo_file(self): def has_photo_file(self):
-2
View File
@@ -234,8 +234,6 @@ def send_invitation(guest, event_name=None, additional_text=""):
# QR-код # QR-код
qr_path = event_qr_folder(guest.event_id) / guest.qr_filename qr_path = event_qr_folder(guest.event_id) / guest.qr_filename
if not qr_path.exists():
qr_path = Path(config["QR_FOLDER"]) / guest.qr_filename
if qr_path.exists(): if qr_path.exists():
attachments.append({"path": qr_path, "cid": "qr_code_image", "filename": guest.qr_filename}) attachments.append({"path": qr_path, "cid": "qr_code_image", "filename": guest.qr_filename})
-6
View File
@@ -306,9 +306,6 @@ def generate_ticket_image(guest, event, output_path=None):
if event.ticket_show_qr: if event.ticket_show_qr:
y += 15 y += 15
qr_path = event_qr_folder(guest.event_id) / guest.qr_filename qr_path = event_qr_folder(guest.event_id) / guest.qr_filename
if not qr_path.exists():
# fallback на старую корневую папку
qr_path = Path(current_app.config["QR_FOLDER"]) / guest.qr_filename
if qr_path.exists(): if qr_path.exists():
qr_size = 200 qr_size = 200
qr_img = Image.open(str(qr_path)).convert("RGB") qr_img = Image.open(str(qr_path)).convert("RGB")
@@ -321,9 +318,6 @@ def generate_ticket_image(guest, event, output_path=None):
# Фото гостя # Фото гостя
if event.ticket_show_photo and guest.photo_filename: if event.ticket_show_photo and guest.photo_filename:
photo_path = event_photo_folder(guest.event_id) / guest.photo_filename photo_path = event_photo_folder(guest.event_id) / guest.photo_filename
if not photo_path.exists():
# fallback на старую корневую папку
photo_path = Path(current_app.config["PHOTO_FOLDER"]) / guest.photo_filename
if photo_path.exists(): if photo_path.exists():
photo_img = Image.open(str(photo_path)).convert("RGB") photo_img = Image.open(str(photo_path)).convert("RGB")
photo_img.thumbnail((130, 130)) photo_img.thumbnail((130, 130))
+1 -1
View File
@@ -9,8 +9,8 @@ services:
- "8888:8888" - "8888:8888"
environment: environment:
# Замени на сильный случайный ключ перед запуском в продакшене # Замени на сильный случайный ключ перед запуском в продакшене
# Пример генерации: openssl rand -hex 32
- SECRET_KEY=change-me-in-production - SECRET_KEY=change-me-in-production
- BASE_URL=https://ai.mycloud24.ru
- TIMEZONE=Europe/Moscow - TIMEZONE=Europe/Moscow
volumes: volumes:
# База SQLite и загруженные файлы хранятся вне контейнера # База SQLite и загруженные файлы хранятся вне контейнера