Подготовка проекта к публикации: 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:
@@ -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
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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/*
|
||||||
|
|||||||
@@ -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
@@ -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):
|
||||||
|
|||||||
@@ -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})
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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 и загруженные файлы хранятся вне контейнера
|
||||||
|
|||||||
Reference in New Issue
Block a user