feat: add interactive exploration of Shannon's capacity formula with Plotly graphs
All checks were successful
Build & Deploy Shannon / 🏗️ Build & Deploy Shannon (push) Successful in 3m1s

- Implemented bandwidth sensitivity and power sensitivity plots.
- Created a contour map for bit rate multiplying factors.
- Added input parameters for C/N and bandwidth with validation.
- Displayed computed results and sensitivity analysis metrics.
- Integrated interactive graphs for user exploration.
- Included background information section for user guidance.
This commit is contained in:
Poidevin, Antoine (ITOP CM) - AF
2026-02-20 10:33:09 +01:00
parent beda405953
commit 6a4ccc3376
38 changed files with 4319 additions and 11161 deletions

107
core/database.py Normal file
View File

@@ -0,0 +1,107 @@
"""
Database module for managing user contributions.
Uses parameterized queries (no SQL injection) and context managers.
"""
import sqlite3
import os
from datetime import datetime
DB_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
def _get_db_path(db_name: str) -> str:
os.makedirs(DB_DIR, exist_ok=True)
return os.path.join(DB_DIR, db_name)
def _init_db(db_path: str):
with sqlite3.connect(db_path) as conn:
conn.execute(
"""CREATE TABLE IF NOT EXISTS contributions (
num INTEGER PRIMARY KEY,
name TEXT NOT NULL,
title TEXT NOT NULL,
keywords TEXT,
text TEXT NOT NULL,
date TEXT NOT NULL,
password TEXT DEFAULT ''
)"""
)
def write_contribution(
db_name: str, name: str, title: str, keywords: str, text: str, password: str = ""
) -> int:
"""Write a new contribution. Returns the new contribution ID."""
db_path = _get_db_path(db_name)
_init_db(db_path)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT COALESCE(MAX(num), 0) FROM contributions")
next_id = cursor.fetchone()[0] + 1
cursor.execute(
"INSERT INTO contributions (num, name, title, keywords, text, date, password) "
"VALUES (?, ?, ?, ?, ?, ?, ?)",
(next_id, name, title, keywords, text, datetime.now().strftime("%Y-%m-%d"), password),
)
return next_id
def search_contributions(
db_name: str,
name_filter: str = "",
title_filter: str = "",
keywords_filter: str = "",
content_filter: str = "",
limit: int = 50,
) -> list[dict]:
"""Search contributions with optional filters. Returns list of dicts."""
db_path = _get_db_path(db_name)
if not os.path.isfile(db_path):
return []
_init_db(db_path)
with sqlite3.connect(db_path) as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute(
"""SELECT num, name, title, keywords, text, date, password
FROM contributions
WHERE name LIKE ? AND title LIKE ? AND keywords LIKE ? AND text LIKE ?
ORDER BY num DESC
LIMIT ?""",
(
f"%{name_filter}%",
f"%{title_filter}%",
f"%{keywords_filter}%",
f"%{content_filter}%",
limit,
),
)
return [dict(row) for row in cursor.fetchall()]
def delete_contribution(db_name: str, num: int, password: str) -> bool:
"""Delete a contribution if the password matches. Returns True on success."""
db_path = _get_db_path(db_name)
if not os.path.isfile(db_path):
return False
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT password FROM contributions WHERE num = ?", (num,)
)
row = cursor.fetchone()
if row is None:
return False
if row[0] != password:
return False
cursor.execute("DELETE FROM contributions WHERE num = ?", (num,))
return True