gmao/tests/integration/test_auth_setup.py
root b051930431
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Gère les présences pendant les vacances scolaires
2026-08-14 18:43:10 +00:00

186 lines
7.6 KiB
Python

from pathlib import Path
def test_login_page_does_not_disclose_demo_passwords(client):
response = client.get('/auth/login')
assert response.status_code == 200
assert b'admin</code>' not in response.data
assert b'admin</code></td><td><code>admin' not in response.data
def test_login_rejects_external_next_url(client, admin_user):
response = client.post(
'/auth/login?next=//example.net',
data={'username': admin_user['username'], 'password': admin_user['password']},
)
assert response.status_code == 302
assert 'example.net' not in response.headers['Location']
def test_setup_requires_token(client, monkeypatch, tmp_path):
from app_new.core.routes import setup_wizard
monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
assert client.get('/setup-wizard/').status_code == 403
assert client.get('/setup-wizard/?token=invalid').status_code == 403
def test_setup_token_is_removed_from_url(client, monkeypatch, tmp_path):
from app_new.core.routes import setup_wizard
monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
token = 'test-setup-token-with-at-least-32-characters'
response = client.get(f'/setup-wizard/?token={token}')
assert response.status_code == 302
assert 'token=' not in response.headers['Location']
assert client.get('/setup-wizard/').status_code == 200
def test_completed_setup_rejects_mutation(client, monkeypatch, tmp_path):
from app_new.core.routes import setup_wizard
monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
Path(tmp_path, '.setup_complete').write_text('complete', encoding='utf-8')
response = client.post('/setup-wizard/api/step/1', json={
'username': 'new-admin',
'password': 'a-strong-password',
})
assert response.status_code == 403
def _authorize_setup(client, monkeypatch, tmp_path):
from app_new.core.routes import setup_wizard
monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
token = 'test-setup-token-with-at-least-32-characters'
response = client.get(f'/setup-wizard/?token={token}')
assert response.status_code == 302
def test_setup_updates_buildings_without_deleting_existing(client, app, monkeypatch, tmp_path):
from app_new import db
from app_new.core.models.college import Building
_authorize_setup(client, monkeypatch, tmp_path)
with app.app_context():
existing = Building(name='Bâtiment conservé', description='Ancienne description')
untouched = Building(name='Bâtiment hors formulaire')
db.session.add_all([existing, untouched])
db.session.commit()
existing_id, untouched_id = existing.id, untouched.id
response = client.post('/setup-wizard/api/step/3', json={'buildings': [
{'id': existing_id, 'name': 'Bâtiment conservé', 'description': 'Mise à jour'},
{'name': 'Nouveau bâtiment', 'description': ''},
]})
assert response.status_code == 200
with app.app_context():
assert db.session.get(Building, existing_id).description == 'Mise à jour'
assert db.session.get(Building, untouched_id) is not None
assert Building.query.filter_by(name='Nouveau bâtiment').count() == 1
def test_setup_creates_zones_and_rooms_with_valid_links(client, app, monkeypatch, tmp_path):
from app_new import db
from app_new.core.models.college import Building, Room, Zone
_authorize_setup(client, monkeypatch, tmp_path)
with app.app_context():
building = Building(name='Bâtiment relations wizard')
db.session.add(building)
db.session.commit()
building_id = building.id
zone_response = client.post('/setup-wizard/api/step/4', json={'zones': [
{'name': 'Zone wizard', 'building_id': building_id},
]})
assert zone_response.status_code == 200
zone_id = zone_response.get_json()['zones'][0]['id']
room_response = client.post('/setup-wizard/api/step/5', json={'rooms': [
{'name': 'Salle wizard', 'code': 'W01', 'building_id': building_id, 'zone_id': zone_id, 'floor': 1},
]})
assert room_response.status_code == 200
with app.app_context():
zone = db.session.get(Zone, zone_id)
room = Room.query.filter_by(name='Salle wizard').one()
assert zone.building_id == building_id
assert room.building_id == building_id
assert room.zone_id == zone_id
assert room.floor == 1
def test_setup_imports_embedded_lot_catalog_idempotently(client, app, monkeypatch, tmp_path):
from app_new.core.models.equipment import EquipmentCategory
from app_new.core.models.maintenance import Lot
from app_new.core.setup_catalog import EQUIPMENT_CATEGORIES, LOTS
_authorize_setup(client, monkeypatch, tmp_path)
first = client.post('/setup-wizard/api/step/6', json={})
second = client.post('/setup-wizard/api/step/6', json={})
assert first.status_code == second.status_code == 200
assert first.get_json()['categories_count'] == len(EQUIPMENT_CATEGORIES)
assert first.get_json()['lots_count'] == len(LOTS)
with app.app_context():
for name in EQUIPMENT_CATEGORIES:
assert EquipmentCategory.query.filter_by(name=name).count() == 1
for name, category_name in LOTS:
lot = Lot.query.filter_by(name=name).one()
assert lot.category.name == category_name
def test_setup_saves_exact_work_days_inside_school_holidays(client, app, monkeypatch, tmp_path):
from datetime import date, time
from app_new.core.models.planning import CollegeClosure, ClosureWorkDay
from app_new.core.services.planning_service import PlanningService
_authorize_setup(client, monkeypatch, tmp_path)
response = client.post('/setup-wizard/api/step/7', json={
'zone': 'C',
'annee': 2026,
'import_vacances': True,
'import_feries': True,
'vacation_periods': [{
'name': 'Petites vacances test wizard',
'start_date': '2026-10-19',
'end_date': '2026-10-30',
'work_days': [
{
'work_date': '2026-10-19', 'start_time': '08:00', 'end_time': '16:00',
'lunch_start': '12:00', 'lunch_end': '12:45', 'notes': 'Début des vacances',
},
{
'work_date': '2026-10-30', 'start_time': '09:15', 'end_time': '13:30',
'lunch_start': '', 'lunch_end': '', 'notes': 'Fin des vacances',
},
],
}],
})
assert response.status_code == 200
with app.app_context():
closure = CollegeClosure.query.filter_by(name='Petites vacances test wizard').one()
assert closure.work_hours_type == 'none'
assert ClosureWorkDay.query.filter_by(closure_id=closure.id).count() == 2
assert PlanningService.get_working_hours(date(2026, 10, 20)) is None
assert PlanningService.get_working_hours(date(2026, 10, 19)) == (
time(8, 0), time(16, 0), time(12, 0), time(12, 45)
)
assert PlanningService.get_working_hours(date(2026, 10, 30)) == (
time(9, 15), time(13, 30), None, None
)
def test_setup_rejects_work_day_outside_vacation_period(client, monkeypatch, tmp_path):
_authorize_setup(client, monkeypatch, tmp_path)
response = client.post('/setup-wizard/api/step/7', json={
'zone': 'C', 'annee': 2026,
'vacation_periods': [{
'name': 'Vacances invalides', 'start_date': '2026-12-20', 'end_date': '2027-01-03',
'work_days': [{'work_date': '2026-12-10', 'start_time': '08:00', 'end_time': '16:00'}],
}],
})
assert response.status_code == 400
assert 'hors de la période' in response.get_json()['error']