131 lines
5.3 KiB
Python
131 lines
5.3 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
|