feat: Initialize frontend with React, Vite, and Tailwind CSS

- Set up main entry point for React application.
- Create About, Home, NotFound, Privacy, and Terms pages with SEO support.
- Implement API service for file uploads and task management.
- Add global styles using Tailwind CSS.
- Create utility functions for SEO and text processing.
- Configure Vite for development and production builds.
- Set up Nginx configuration for serving frontend and backend.
- Add scripts for cleanup of expired files and sitemap generation.
- Implement deployment script for production environment.
This commit is contained in:
Your Name
2026-02-28 23:31:19 +02:00
parent 3b84ebb916
commit 85d98381df
93 changed files with 5940 additions and 0 deletions

View File

26
backend/tests/conftest.py Normal file
View File

@@ -0,0 +1,26 @@
import os
import pytest
from app import create_app
@pytest.fixture
def app():
"""Create application for testing."""
os.environ['FLASK_ENV'] = 'testing'
app = create_app()
app.config.update({
'TESTING': True,
})
yield app
@pytest.fixture
def client(app):
"""Flask test client."""
return app.test_client()
@pytest.fixture
def runner(app):
"""Flask test CLI runner."""
return app.test_cli_runner()

View File

@@ -0,0 +1,21 @@
"""Tests for PDF compression endpoint."""
import io
def test_compress_pdf_no_file(client):
"""POST /api/compress/pdf without file should return 400."""
response = client.post('/api/compress/pdf')
assert response.status_code == 400
def test_compress_pdf_wrong_extension(client):
"""POST /api/compress/pdf with non-PDF should return 400."""
data = {
'file': (io.BytesIO(b'hello'), 'test.docx'),
}
response = client.post(
'/api/compress/pdf',
data=data,
content_type='multipart/form-data',
)
assert response.status_code == 400

View File

@@ -0,0 +1,42 @@
"""Tests for file conversion endpoints."""
import io
def test_pdf_to_word_no_file(client):
"""POST /api/convert/pdf-to-word without file should return 400."""
response = client.post('/api/convert/pdf-to-word')
assert response.status_code == 400
data = response.get_json()
assert 'error' in data
def test_pdf_to_word_wrong_extension(client):
"""POST /api/convert/pdf-to-word with non-PDF should return 400."""
data = {
'file': (io.BytesIO(b'hello world'), 'test.txt'),
}
response = client.post(
'/api/convert/pdf-to-word',
data=data,
content_type='multipart/form-data',
)
assert response.status_code == 400
def test_word_to_pdf_no_file(client):
"""POST /api/convert/word-to-pdf without file should return 400."""
response = client.post('/api/convert/word-to-pdf')
assert response.status_code == 400
def test_word_to_pdf_wrong_extension(client):
"""POST /api/convert/word-to-pdf with non-Word file should return 400."""
data = {
'file': (io.BytesIO(b'hello world'), 'test.pdf'),
}
response = client.post(
'/api/convert/word-to-pdf',
data=data,
content_type='multipart/form-data',
)
assert response.status_code == 400

View File

@@ -0,0 +1,15 @@
"""Tests for health check and app creation."""
def test_health_endpoint(client):
"""GET /api/health should return 200."""
response = client.get('/api/health')
assert response.status_code == 200
data = response.get_json()
assert data['status'] == 'healthy'
def test_app_creates(app):
"""App should create without errors."""
assert app is not None
assert app.config['TESTING'] is True

View File

@@ -0,0 +1,27 @@
"""Tests for image conversion & resize endpoints."""
import io
def test_image_convert_no_file(client):
"""POST /api/image/convert without file should return 400."""
response = client.post('/api/image/convert')
assert response.status_code == 400
def test_image_resize_no_file(client):
"""POST /api/image/resize without file should return 400."""
response = client.post('/api/image/resize')
assert response.status_code == 400
def test_image_convert_wrong_type(client):
"""POST /api/image/convert with non-image should return 400."""
data = {
'file': (io.BytesIO(b'not an image'), 'test.pdf'),
}
response = client.post(
'/api/image/convert',
data=data,
content_type='multipart/form-data',
)
assert response.status_code == 400

View File

@@ -0,0 +1,19 @@
"""Tests for text utility functions."""
import sys
import os
# Add backend to path so we can import utils directly
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from app.utils.file_validator import validate_file
from app.utils.sanitizer import generate_safe_path
def test_generate_safe_path():
"""generate_safe_path should produce UUID-based path."""
path = generate_safe_path('uploads', 'test.pdf')
assert path.startswith('uploads')
assert path.endswith('.pdf')
# Should contain a UUID directory
parts = path.replace('\\', '/').split('/')
assert len(parts) >= 3 # uploads / uuid / filename.pdf