feat: Space Booking System - MVP complet

Sistem web pentru rezervarea de birouri și săli de ședință
cu flux de aprobare administrativă.

Stack: FastAPI + Vue.js 3 + SQLite + TypeScript

Features implementate:
- Autentificare JWT + Self-registration cu email verification
- CRUD Spații, Utilizatori, Settings (Admin)
- Calendar interactiv (FullCalendar) cu drag-and-drop
- Creare rezervări cu validare (durată, program, overlap, max/zi)
- Rezervări recurente (săptămânal)
- Admin: aprobare/respingere/anulare cereri
- Admin: creare directă rezervări (bypass approval)
- Admin: editare orice rezervare
- User: editare/anulare rezervări proprii
- Notificări in-app (bell icon + dropdown)
- Notificări email (async SMTP cu BackgroundTasks)
- Jurnal acțiuni administrative (audit log)
- Rapoarte avansate (utilizare, top users, approval rate)
- Șabloane rezervări (booking templates)
- Atașamente fișiere (upload/download)
- Conflict warnings (verificare disponibilitate real-time)
- Integrare Google Calendar (OAuth2)
- Suport timezone (UTC storage + user preference)
- 225+ teste backend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-09 17:51:29 +00:00
commit df4031d99c
113 changed files with 24491 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
"""Tests for audit service."""
import pytest
from app.models.audit_log import AuditLog
from app.services.audit_service import log_action
def test_log_action_basic(db_session, test_admin):
"""Test basic audit log creation."""
audit = log_action(
db=db_session,
action="booking_approved",
user_id=test_admin.id,
target_type="booking",
target_id=123,
details=None
)
assert audit.id is not None
assert audit.action == "booking_approved"
assert audit.user_id == test_admin.id
assert audit.target_type == "booking"
assert audit.target_id == 123
assert audit.details == {}
assert audit.created_at is not None
def test_log_action_with_details(db_session, test_admin):
"""Test audit log with details."""
details = {
"rejection_reason": "Spațiul este în mentenanță",
"old_value": "pending",
"new_value": "rejected"
}
audit = log_action(
db=db_session,
action="booking_rejected",
user_id=test_admin.id,
target_type="booking",
target_id=456,
details=details
)
assert audit.details == details
assert audit.details["rejection_reason"] == "Spațiul este în mentenanță"
def test_log_action_settings_update(db_session, test_admin):
"""Test audit log for settings update."""
changed_fields = {
"min_duration_minutes": {"old": 30, "new": 60},
"max_duration_minutes": {"old": 480, "new": 720}
}
audit = log_action(
db=db_session,
action="settings_updated",
user_id=test_admin.id,
target_type="settings",
target_id=1,
details={"changed_fields": changed_fields}
)
assert audit.target_type == "settings"
assert "changed_fields" in audit.details
assert audit.details["changed_fields"]["min_duration_minutes"]["new"] == 60
def test_multiple_audit_logs(db_session, test_admin):
"""Test creating multiple audit logs."""
actions = [
("space_created", "space", 1),
("space_updated", "space", 1),
("user_created", "user", 10),
("booking_approved", "booking", 5)
]
for action, target_type, target_id in actions:
log_action(db_session, action, test_admin.id, target_type, target_id)
# Verify all logs were created
logs = db_session.query(AuditLog).filter(AuditLog.user_id == test_admin.id).all()
assert len(logs) == 4
assert logs[0].action == "space_created"
assert logs[3].action == "booking_approved"