CI - Security, Lint & Tests / validate (push) Failing after 1m3s
ajout de compteur d'heure disponible ajout du calendrier de dispo dans les profils publics
136 lines
5.4 KiB
Python
136 lines
5.4 KiB
Python
"""Admin document-upload toggle — enable/disable gate and enforcement
|
|
on contract upload routes.
|
|
|
|
ADMIN-006 style. The document_uploads_enabled setting gates every
|
|
contract upload route for non-admins. Admins always bypass the lock.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from app.extensions import db
|
|
from app.models import AppSettings, Contract, User
|
|
|
|
NON_ADMIN_ROLES = ['manager', 'coach']
|
|
|
|
|
|
def _redirected(response):
|
|
return response.status_code in (301, 302)
|
|
|
|
|
|
class TestDocumentUploadToggle:
|
|
"""Toggle logic — on/off round-trip and audit log."""
|
|
|
|
def test_toggle_from_enabled_to_disabled(self, client, as_role):
|
|
as_role('admin')
|
|
# Default is enabled
|
|
client.post('/admin/toggle-document-uploads', data={}, follow_redirects=False)
|
|
with client.application.app_context():
|
|
assert not AppSettings.get_bool('document_uploads_enabled', default=True)
|
|
|
|
def test_toggle_from_disabled_to_enabled(self, client, as_role):
|
|
as_role('admin')
|
|
client.post('/admin/toggle-document-uploads', data={}, follow_redirects=False)
|
|
client.post('/admin/toggle-document-uploads', data={}, follow_redirects=False)
|
|
with client.application.app_context():
|
|
assert AppSettings.get_bool('document_uploads_enabled', default=True)
|
|
|
|
def test_toggle_creates_audit_log(self, client, as_role):
|
|
from app.models import AuditLog
|
|
|
|
as_role('admin')
|
|
client.post('/admin/toggle-document-uploads', data={}, follow_redirects=False)
|
|
|
|
with client.application.app_context():
|
|
entry = AuditLog.query.filter_by(action='document_uploads_toggled').first()
|
|
assert entry is not None
|
|
|
|
def test_default_is_enabled(self, app):
|
|
with app.app_context():
|
|
assert AppSettings.get_bool('document_uploads_enabled', default=True)
|
|
|
|
|
|
class TestDocumentUploadGateEnforcement:
|
|
"""Non-admin roles are blocked when the toggle is off."""
|
|
|
|
def _contract_for(self, app, player_id):
|
|
"""Create a minimal contract for enforcement tests."""
|
|
from datetime import datetime
|
|
|
|
with app.app_context():
|
|
admin = User.query.filter_by(role='admin').first()
|
|
contract = Contract(
|
|
player_id=player_id,
|
|
uploaded_by_id=admin.id,
|
|
original_filename='test.pdf',
|
|
stored_filename='test.pdf',
|
|
file_path='contrats signes/test.pdf',
|
|
status='pending_player_signing',
|
|
uploaded_at=datetime.utcnow(),
|
|
)
|
|
db.session.add(contract)
|
|
db.session.commit()
|
|
return contract.id
|
|
|
|
@pytest.mark.parametrize('role', NON_ADMIN_ROLES)
|
|
def test_non_admin_cannot_upload_contract_when_disabled(
|
|
self, app, client, as_role, make_user, role
|
|
):
|
|
as_role('admin')
|
|
client.post('/admin/toggle-document-uploads', data={}) # disable
|
|
as_role(role)
|
|
|
|
response = client.post(
|
|
'/users/contracts/upload',
|
|
data={'player_id': '', 'contract_file': ''},
|
|
follow_redirects=True,
|
|
)
|
|
html = response.data.decode()
|
|
# Default locale is French — the flash message says "désactivés"
|
|
assert 'désactivés' in html or 'disabled' in html.lower()
|
|
|
|
@pytest.mark.parametrize('role', NON_ADMIN_ROLES)
|
|
def test_admin_can_always_upload_contract(self, client, as_role, role):
|
|
as_role('admin')
|
|
# Pre-create a player for the contract
|
|
|
|
as_role('player')
|
|
client.post('/admin/toggle-document-uploads', data={}) # disable
|
|
|
|
# Admin should still be able to reach the upload page
|
|
response = client.get('/users/contracts/upload', follow_redirects=False)
|
|
assert _redirected(response) or response.status_code == 200
|
|
|
|
def test_player_cannot_upload_signed_when_disabled(self, app, client, as_role, make_user):
|
|
as_role('admin')
|
|
client.post('/admin/toggle-document-uploads', data={}) # disable while logged in as admin
|
|
player_id = make_user('player')
|
|
contract_id = self._contract_for(app, player_id)
|
|
|
|
# Log in as the player
|
|
with app.app_context():
|
|
username = db.session.get(User, player_id).username
|
|
client.post('/auth/login', data={'username': username, 'password': 'Password123'})
|
|
|
|
response = client.post(
|
|
f'/users/contracts/{contract_id}/upload_signed',
|
|
data={'signed_file': ''},
|
|
follow_redirects=True,
|
|
)
|
|
html = response.data.decode()
|
|
assert 'désactivés' in html or 'disabled' in html.lower()
|
|
|
|
def test_admin_can_always_upload(self, app, client, as_role):
|
|
as_role('admin')
|
|
client.post('/admin/toggle-document-uploads', data={}) # disable
|
|
|
|
# Admin GET the upload page — should be allowed (not redirected away)
|
|
response = client.get('/users/contracts/upload', follow_redirects=False)
|
|
# The admin bypasses the lock so they see the upload form (200)
|
|
# or get redirected (if no players exist, etc). Either way is fine
|
|
# as long as it's not the flash about uploads being disabled.
|
|
body = response.data.decode() if response.status_code == 200 else ''
|
|
# The toggle flash ("désactivés") could still be present, but the
|
|
# upload-disabled message ("désactivés") must not appear in the body.
|
|
# We check for the French lock message specifically.
|
|
assert 'actuellement désactivés' not in body
|