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
Repository files (latest commit first)
Filename Latest commit message Latest commit date
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ł → Integracje → Webhooki
  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