régler problème de dispos des coachs

This commit is contained in:
cedrick2711
2026-08-10 17:20:07 -04:00
parent bb0bc1c192
commit d007900f6c
5 changed files with 27 additions and 17 deletions
+6 -7
View File
@@ -128,14 +128,13 @@ def configure_logging(app):
app.logger.addHandler(app_handler)
# -------------------------------------------------------------------------
# 4. Console Handler (for development)
# 4. Console Handler (always enabled for debugging in both dev and production)
# -------------------------------------------------------------------------
if os.getenv('FLASK_DEBUG', 'false').lower() == 'true':
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(formatter)
console_handler.addFilter(sensitive_filter)
app.logger.addHandler(console_handler)
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
console_handler.addFilter(sensitive_filter)
app.logger.addHandler(console_handler)
# Log startup information
app.logger.info('Logging configured - Level: %s, Log directory: %s', log_level_name, log_dir)
-129
View File
@@ -1,129 +0,0 @@
"""Development HTTPS server for testing production settings locally.
Generates a self-signed certificate (if not present) and runs the
application via Waitress wrapped in a TLS socket. This simulates the
production environment where Nginx handles TLS termination.
Usage:
python run_https.py
The server will listen on https://localhost:8443
Accept the self-signed certificate warning in your browser to proceed.
"""
import os
import socket
import subprocess
import ssl
import sys
from waitress.server import create_server
from app.app import create_app
CERT_FILE = 'certs/localhost.pem'
KEY_FILE = 'certs/localhost-key.pem'
def generate_self_signed_cert():
"""Generate a self-signed certificate for local HTTPS testing.
Uses OpenSSL to create a key and certificate valid for 365 days.
Skips generation if certificate files already exist.
"""
if os.path.exists(CERT_FILE) and os.path.exists(KEY_FILE):
print('[OK] Self-signed certificate already exists.')
return
os.makedirs('certs', exist_ok=True)
print('[INFO] Generating self-signed certificate for localhost...')
try:
subprocess.run([
'openssl', 'req', '-x509', '-newkey', 'rsa:2048',
'-keyout', KEY_FILE,
'-out', CERT_FILE,
'-days', '365',
'-nodes',
'-subj', '/CN=localhost'
], check=True, capture_output=True)
print('[OK] Certificate generated: certs/localhost.pem')
except FileNotFoundError:
print('[ERROR] OpenSSL not found. Install OpenSSL or use:')
print(' winget install OpenSSL.OpenSSL')
print(' OR download from https://slproweb.com/products/Win32OpenSSL.html')
sys.exit(1)
except subprocess.CalledProcessError as e:
print(f'[ERROR] Certificate generation failed: {e}')
sys.exit(1)
def main():
"""Start the HTTPS development server."""
port = int(os.getenv('HTTPS_PORT', 8443))
host = os.getenv('HOST', '127.0.0.1')
# Ensure certificate exists
generate_self_signed_cert()
# Create the Flask application
app = create_app()
# Create SSL context
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(CERT_FILE, KEY_FILE)
# Create a TCP socket, wrap it with TLS, then pass to Waitress
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(5)
# Wrap the socket with TLS
ssl_sock = context.wrap_socket(sock, server_side=True)
# =====================================================================
# WSGI Middleware: Tell Flask the connection is HTTPS
#
# Waitress doesn't know the underlying socket is TLS, so Flask sees
# wsgi.url_scheme = "http". Without this middleware, force_https()
# would cause an infinite redirect loop (ERR_TOO_MANY_REDIRECTS).
# =====================================================================
class ForceHTTPSMiddleware:
"""WSGI middleware that sets url_scheme to 'https'.
Since we're wrapping the TCP socket with SSL before passing it
to Waitress, Flask's request.is_secure returns False because
Waitress reports wsgi.url_scheme='http'. This middleware fixes
that so Flask correctly identifies the connection as HTTPS.
"""
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, environ, start_response):
environ['wsgi.url_scheme'] = 'https'
environ['HTTPS'] = 'on'
return self.wsgi_app(environ, start_response)
# Wrap the Flask app with the HTTPS middleware
app.wsgi_app = ForceHTTPSMiddleware(app.wsgi_app)
print(f'\n╔══════════════════════════════════════════════════════╗')
print(f'║ TEAM TRYOUTS - Development HTTPS Server ║')
print(f'╠══════════════════════════════════════════════════════╣')
print(f'║ URL: https://{host}:{port}')
print(f'║ Cert: self-signed (accept browser warning) ║')
print(f'║ Press Ctrl+C to stop ║')
print(f'╚══════════════════════════════════════════════════════╝\n')
# Create Waitress server with the SSL-wrapped socket
server = create_server(
app,
sockets=[ssl_sock],
threads=4,
channel_timeout=30,
)
server.run()
if __name__ == '__main__':
main()
-6
View File
@@ -85,12 +85,6 @@
</li>
{% endif %}
{% if current_user.role == 'coach' %}
<li>
<a href="{{ url_for('users.manage_coach_availability') }}" class="{% if request.endpoint == 'users.manage_coach_availability' %}active{% endif %}">
<i class="fas fa-clock"></i>
<span>Availability</span>
</a>
</li>
<li>
<a href="{{ url_for('users.notes_dashboard') }}" class="{% if request.endpoint == 'users.notes_dashboard' or request.endpoint == 'users.manage_team_notes' or request.endpoint == 'users.manage_personal_notes' %}active{% endif %}">
<i class="fas fa-sticky-note"></i>
+13 -2
View File
@@ -15,6 +15,9 @@
</div>
<div class="form-actions mt-4">
<button type="button" class="btn btn-primary" onclick="saveAvailability()">
<i class="fas fa-save"></i> Save Availability
</button>
<button type="button" class="btn btn-secondary" onclick="clearAllAvailability()">
<i class="fas fa-trash"></i> Clear All
</button>
@@ -168,13 +171,18 @@ function saveAvailability() {
fetch('{{ url_for("users.manage_coach_availability") }}', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token() }}'
},
body: JSON.stringify({ slots: slots })
})
.then(response => response.json())
.then(data => {
if (data.success) {
flash('Availability saved!', 'success');
} else {
flash(data.error || 'Error saving availability.', 'danger');
}
})
.catch(function(error) {
@@ -188,7 +196,10 @@ function clearAllAvailability() {
return;
}
fetch('{{ url_for("users.clear_coach_availability") }}', { method: 'POST' })
fetch('{{ url_for("users.clear_coach_availability") }}', {
method: 'POST',
headers: { 'X-CSRFToken': '{{ csrf_token() }}' }
})
.then(response => response.json())
.then(data => {
if (data.success) {
+8 -2
View File
@@ -357,7 +357,10 @@ function saveCoachAvailability() {
}
fetch('{{ url_for("users.manage_coach_availability") }}', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token() }}'
},
body: JSON.stringify({ slots: slots })
})
.then(r => r.json())
@@ -376,7 +379,10 @@ function saveCoachAvailability() {
function clearAllAvailability() {
if (!confirm('Are you sure you want to clear all your availability slots?')) return;
fetch('{{ url_for("users.clear_coach_availability") }}', { method: 'POST' })
fetch('{{ url_for("users.clear_coach_availability") }}', {
method: 'POST',
headers: { 'X-CSRFToken': '{{ csrf_token() }}' }
})
.then(r => r.json())
.then(data => {
if (data.success) {