Strona zawiera tylko i wyłącznie formularz kontaktowy. Oraz niewielki backend w fast apl - zadanie obsługa formularza oraz wysłanie wiadomości na Discord poprzez webhooki
  • Python 41.7%
  • JavaScript 21.7%
  • CSS 21.4%
  • HTML 15.2%
Find a file
2025-11-25 20:19:02 +01:00
.idea Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
static Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
CUSTOMIZATION.md Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
env.example Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
main.py Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
PYCHARM.md Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
QUICKSTART.md Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
README.md Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
requirements.txt Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
STRUCTURE.md Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
test_main.http Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00
test_main.py Przetestowany lokalnie. Do pracy własnej 2025-11-25 20:19:02 +01:00

📝 Formularz z FastAPI i Discord Webhooks

Prosty projekt formularza kontaktowego z backendem FastAPI i integracją Discord webhooks.

📋 Spis treści

Funkcje

  • Prosty formularz HTML z walidacją
  • Backend FastAPI z obsługą CORS
  • Integracja z Discord webhooks
  • Automatyczna walidacja email
  • Responsywny design
  • Obsługa błędów
  • Loading states

📁 Struktura projektu

fastapi-form-project/
├── main.py                 # Backend FastAPI
├── requirements.txt        # Zależności Python
├── .env                    # Konfiguracja (NIE commitować!)
├── .env.example           # Przykładowa konfiguracja
├── .gitignore             # Ignorowane pliki
├── README.md              # Dokumentacja
└── static/                # Pliki frontend
    ├── index.html         # Strona HTML
    ├── style.css          # Style CSS
    └── script.js          # JavaScript

🚀 Instalacja

Wymagania

  • Python 3.8+
  • pip
  • Konto Discord (do webhooków)

Krok 1: Klonowanie/pobranie projektu

cd fastapi-form-project

Krok 2: Utworzenie wirtualnego środowiska

Windows:

python -m venv venv
venv\Scripts\activate

Linux/Mac:

python3 -m venv venv
source venv/bin/activate

Krok 3: Instalacja zależności

pip install -r requirements.txt

🔧 Konfiguracja Discord Webhook

1. Utwórz webhook w Discord

  1. Otwórz Discord i przejdź do swojego serwera
  2. Kliknij prawym przyciskiem na kanał tekstowy
  3. Wybierz Edytuj kanałIntegracjeWebhooki
  4. Kliknij Nowy Webhook
  5. Nadaj mu nazwę (np. "Formularz Kontaktowy")
  6. Skopiuj URL webhooka

2. Skonfiguruj .env

Skopiuj .env.example jako .env:

cp .env.example .env

Edytuj .env i wklej swój URL webhook:

DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1234567890/abcdefghijklmnop

▶️ Uruchomienie

Uruchomienie serwera

python main.py

Lub z uvicorn:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

Dostęp do aplikacji

Otwórz przeglądarkę i przejdź do:

🔍 Jak to działa

Backend (main.py)

  1. FastAPI Application - główna aplikacja
  2. Static Files - serwowanie plików HTML/CSS/JS
  3. Pydantic Models - walidacja danych
  4. Discord Integration - wysyłanie danych do Discord

Frontend (HTML/CSS/JS)

  1. Użytkownik wypełnia formularz
  2. JavaScript przechwytuje submit
  3. Dane są wysyłane do /api/submit-form (POST)
  4. Backend waliduje i wysyła do Discord
  5. Użytkownik otrzymuje potwierdzenie

Przepływ danych

Formularz HTML → JavaScript (walidacja) → FastAPI (/api/submit-form) 
                                           ↓
                                    Walidacja Pydantic
                                           ↓
                                    Discord Webhook
                                           ↓
                                    Powiadomienie na Discord

🛣️ API Endpoints

GET /

Zwraca stronę główną z formularzem.

POST /api/submit-form

Przyjmuje dane z formularza i wysyła do Discord.

Request Body:

{
    "name": "Jan Kowalski",
    "email": "jan@example.com",
    "message": "Witam, mam pytanie..."
}

Response (Success):

{
    "success": true,
    "message": "Formularz został pomyślnie wysłany!"
}

POST /api/discord-webhook

Endpoint do odbierania webhooków z Discord (opcjonalny).

GET /api/health

Sprawdza stan aplikacji.

Response:

{
    "status": "healthy",
    "discord_configured": true
}

🛠️ Rozwijanie projektu

1. Dodanie nowych pól do formularza

a) Dodaj pole w HTML (index.html):

<div class="form-group">
    <label for="phone">
        <span class="icon">📱</span>
        Telefon
    </label>
    <input 
        type="tel" 
        id="phone" 
        name="phone" 
        placeholder="+48 123 456 789"
    >
</div>

b) Zaktualizuj model w main.py:

class FormData(BaseModel):
    name: str
    email: EmailStr
    message: str
    phone: Optional[str] = None  # Nowe pole

c) Dodaj pole do Discord embed:

{
    "name": "📱 Telefon",
    "value": data.phone or "Nie podano",
    "inline": True
}

d) Zaktualizuj JavaScript (script.js):

const formData = {
    name: document.getElementById('name').value.trim(),
    email: document.getElementById('email').value.trim(),
    message: document.getElementById('message').value.trim(),
    phone: document.getElementById('phone').value.trim()  // Nowe pole
};

2. Dodanie bazy danych

Zainstaluj SQLAlchemy:

pip install sqlalchemy

Utwórz database.py:

from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime

SQLALCHEMY_DATABASE_URL = "sqlite:///./submissions.db"

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class Submission(Base):
    __tablename__ = "submissions"
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    email = Column(String)
    message = Column(String)
    created_at = Column(DateTime, default=datetime.utcnow)

Base.metadata.create_all(bind=engine)

W main.py dodaj zapis do bazy:

from database import SessionLocal, Submission

@app.post("/api/submit-form")
async def submit_form(data: FormData):
    # Zapis do bazy
    db = SessionLocal()
    submission = Submission(
        name=data.name,
        email=data.email,
        message=data.message
    )
    db.add(submission)
    db.commit()
    db.close()
    
    # Wysłanie do Discord
    await send_to_discord(data)
    
    return {"success": True, "message": "Zapisano!"}

3. Dodanie CAPTCHA (reCAPTCHA)

a) Zarejestruj się na: https://www.google.com/recaptcha/admin

b) Dodaj w HTML przed przyciskiem submit:

<div class="g-recaptcha" data-sitekey="TWÓJ_SITE_KEY"></div>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

c) W JavaScript, przed wysłaniem:

const recaptchaResponse = grecaptcha.getResponse();
if (!recaptchaResponse) {
    showStatus('Proszę zaznaczyć reCAPTCHA', false);
    return;
}

d) Weryfikacja w backend (main.py):

import httpx

async def verify_recaptcha(response_token: str) -> bool:
    secret_key = os.getenv("RECAPTCHA_SECRET_KEY")
    async with httpx.AsyncClient() as client:
        response = await client.post(
            'https://www.google.com/recaptcha/api/siteverify',
            data={'secret': secret_key, 'response': response_token}
        )
        result = response.json()
        return result.get('success', False)

4. Dodanie wysyłania emaili

Zainstaluj:

pip install fastapi-mail

Przykładowa konfiguracja:

from fastapi_mail import FastMail, MessageSchema, ConnectionConfig

conf = ConnectionConfig(
    MAIL_USERNAME="twoj@email.com",
    MAIL_PASSWORD="twoje-haslo",
    MAIL_FROM="twoj@email.com",
    MAIL_PORT=587,
    MAIL_SERVER="smtp.gmail.com",
    MAIL_STARTTLS=True,
    MAIL_SSL_TLS=False
)

async def send_email_notification(data: FormData):
    message = MessageSchema(
        subject="Nowe zgłoszenie",
        recipients=["admin@example.com"],
        body=f"Od: {data.name}\nEmail: {data.email}\n\n{data.message}",
    )
    
    fm = FastMail(conf)
    await fm.send_message(message)

5. Dodanie rate limiting

Zainstaluj:

pip install slowapi

W main.py:

from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.post("/api/submit-form")
@limiter.limit("5/minute")  # Max 5 zapytań na minutę
async def submit_form(request: Request, data: FormData):
    # ... reszta kodu

6. Dodanie logowania

Dodaj na początku main.py:

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log'),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger(__name__)

# Użycie w funkcjach:
logger.info(f"Otrzymano formularz od: {data.email}")

7. Dodanie testów

Utwórz test_main.py:

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_health_check():
    response = client.get("/api/health")
    assert response.status_code == 200
    assert response.json()["status"] == "healthy"

def test_submit_form():
    response = client.post("/api/submit-form", json={
        "name": "Test User",
        "email": "test@example.com",
        "message": "Test message"
    })
    assert response.status_code == 200

Uruchom testy:

pip install pytest
pytest test_main.py

8. Deploy na produkcję

Opcja A: Heroku

  1. Utwórz Procfile:
web: uvicorn main:app --host 0.0.0.0 --port $PORT
  1. Deploy:
heroku create
git push heroku main

Opcja B: Docker

Utwórz Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Build i uruchom:

docker build -t fastapi-form .
docker run -p 8000:8000 --env-file .env fastapi-form

Opcja C: VPS (Ubuntu)

# Zainstaluj zależności
sudo apt update
sudo apt install python3-pip python3-venv nginx

# Utwórz venv i zainstaluj
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Utwórz systemd service
sudo nano /etc/systemd/system/fastapi-form.service

Zawartość service file:

[Unit]
Description=FastAPI Form Application
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/fastapi-form-project
Environment="PATH=/home/ubuntu/fastapi-form-project/venv/bin"
ExecStart=/home/ubuntu/fastapi-form-project/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000

[Install]
WantedBy=multi-user.target

Uruchom:

sudo systemctl start fastapi-form
sudo systemctl enable fastapi-form

🐛 Troubleshooting

Problem: "Module not found" błąd

Rozwiązanie:

# Upewnij się, że venv jest aktywowane
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows

# Zainstaluj ponownie zależności
pip install -r requirements.txt

Problem: Discord webhook nie działa

Rozwiązanie:

  1. Sprawdź czy URL jest poprawny w .env
  2. Sprawdź czy webhook istnieje na Discord
  3. Sprawdź logi w konsoli: print(webhook_url)

Problem: CORS errors

Rozwiązanie: Dodaj CORS middleware w main.py:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Problem: Port już w użyciu

Rozwiązanie:

# Zmień port w uruchomieniu
uvicorn main:app --port 8001

# Lub zabij proces na porcie 8000 (Linux/Mac)
lsof -ti:8000 | xargs kill -9

# Windows
netstat -ano | findstr :8000
taskkill /PID <PID> /F

📚 Przydatne linki

📄 Licencja

Ten projekt jest wolny do użytku w celach edukacyjnych i komercyjnych.

🤝 Contributing

Pull requesty są mile widziane! Dla większych zmian, najpierw otwórz issue.


Autor: Twoje Imię
Data: 2024
Kontakt: twoj@email.com