Initial commit
This commit is contained in:
+185
@@ -0,0 +1,185 @@
|
|||||||
|
# ==============================================================================
|
||||||
|
# Created by https://gitignores.com/
|
||||||
|
# COMPREHENSIVE FRAMEWORK TEMPLATE for Flask
|
||||||
|
# Website: https://flask.palletsprojects.com/
|
||||||
|
# Repository: https://github.com/pallets/flask
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
# TEMPLATE OVERVIEW & USAGE NOTES
|
||||||
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
# • TEMPLATE TYPE: COMPREHENSIVE FRAMEWORK TEMPLATE
|
||||||
|
# • PURPOSE: Complete Flask Python web framework patterns for web applications and development artifacts
|
||||||
|
# • DESIGN PHILOSOPHY: Self-contained with all Flask and Python-specific patterns
|
||||||
|
# • COMBINATION GUIDANCE: Use standalone; optionally add IDE/OS templates
|
||||||
|
# • SECURITY CONSIDERATIONS: Includes security patterns for .env files and credentials
|
||||||
|
# • BEST PRACTICES: Review patterns before use, test with git check-ignore, customize for your project
|
||||||
|
# • OFFICIAL SOURCES: Flask documentation and community best practices
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# SECURITY & SENSITIVE DATA PROTECTION (ALWAYS FIRST!)
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# CRITICAL: Protect sensitive data from accidental commits to version control
|
||||||
|
|
||||||
|
*.crt
|
||||||
|
*.key
|
||||||
|
*.keystore
|
||||||
|
*.pem
|
||||||
|
*.secret
|
||||||
|
*.token
|
||||||
|
*_keys
|
||||||
|
*_secrets
|
||||||
|
*_tokens
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.env.*.local
|
||||||
|
.env.local
|
||||||
|
id_dsa
|
||||||
|
id_rsa
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# BUILD ARTIFACTS & DISTRIBUTION
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
|
||||||
|
*.egg
|
||||||
|
*.egg-info/
|
||||||
|
*.so
|
||||||
|
*.tar.gz
|
||||||
|
*.whl
|
||||||
|
*.zip
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# DEPENDENCY MANAGEMENT & PACKAGE CACHE
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
|
||||||
|
.cache/
|
||||||
|
.eggs/
|
||||||
|
.pybuilder/
|
||||||
|
.python-eggs/
|
||||||
|
.venv
|
||||||
|
__pypackages__/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
docs/_build/
|
||||||
|
eggs/
|
||||||
|
env.bak/
|
||||||
|
ENV/
|
||||||
|
parts/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
profile_default/
|
||||||
|
sdist/
|
||||||
|
share/python-wheels/
|
||||||
|
venv.bak/
|
||||||
|
venv/
|
||||||
|
wheels/
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# DEVELOPMENT & RUNTIME ARTIFACTS
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
|
||||||
|
*.log
|
||||||
|
*.log.*
|
||||||
|
.dmypy.json
|
||||||
|
.mypy_cache/
|
||||||
|
.nox/
|
||||||
|
.pyre/
|
||||||
|
.pytest_cache/
|
||||||
|
.pytype/
|
||||||
|
.tox/
|
||||||
|
dmypy.json
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
pip-log.txt
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# FRAMEWORK-SPECIFIC PATTERNS
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
|
||||||
|
*.cer
|
||||||
|
*.csr
|
||||||
|
*.der
|
||||||
|
*.jks
|
||||||
|
*.manifest
|
||||||
|
*.nupkg
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.p12
|
||||||
|
*.p7b
|
||||||
|
*.p7c
|
||||||
|
*.pfx
|
||||||
|
*.pid
|
||||||
|
*.pid.lock
|
||||||
|
*.py[co]
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.spec
|
||||||
|
*.tgz
|
||||||
|
*.truststore
|
||||||
|
.Python
|
||||||
|
.flask-debug
|
||||||
|
.python-version
|
||||||
|
.flaskenv
|
||||||
|
.installed.cfg
|
||||||
|
cython_debug/
|
||||||
|
downloads/
|
||||||
|
instance/
|
||||||
|
ipython_config.py
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
MANIFEST
|
||||||
|
out/
|
||||||
|
pdm.toml
|
||||||
|
.webassets-cache
|
||||||
|
var/
|
||||||
|
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
# TESTING & QUALITY ASSURANCE
|
||||||
|
# ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
|
||||||
|
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.coverage.xml
|
||||||
|
.coverage_html/
|
||||||
|
.hypothesis/
|
||||||
|
.nyc_output/
|
||||||
|
htmlcov/
|
||||||
|
junit.xml
|
||||||
|
nosetests.xml
|
||||||
|
test-output/
|
||||||
|
test-reports/
|
||||||
|
test-results/
|
||||||
|
testng-results.xml
|
||||||
|
|
||||||
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
# TEMPLATE CUSTOMIZATION & BEST PRACTICES
|
||||||
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
# 1. REVIEW: Examine all patterns before use
|
||||||
|
# 2. CUSTOMIZE: Adapt to your project's specific structure
|
||||||
|
# 3. TEST: Use `git check-ignore` to verify patterns
|
||||||
|
# 4. SECURE: Always protect sensitive data and credentials
|
||||||
|
# 5. UPDATE: Review periodically as technology evolves
|
||||||
|
|
||||||
|
# RECOMMENDED USAGE PATTERNS:
|
||||||
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# BASIC USAGE (STANDALONE):
|
||||||
|
# -------------------------
|
||||||
|
# cp frameworks/flask.gitignore .gitignore
|
||||||
|
#
|
||||||
|
# WITH IDE SUPPORT:
|
||||||
|
# ----------------
|
||||||
|
# cat frameworks/flask.gitignore \
|
||||||
|
# ides/intellij.gitignore | sort -u > .gitignore
|
||||||
|
#
|
||||||
|
# CROSS-PLATFORM DEVELOPMENT:
|
||||||
|
# ---------------------------
|
||||||
|
# cat frameworks/flask.gitignore \
|
||||||
|
# os/linux.gitignore \
|
||||||
|
# os/macos.gitignore \
|
||||||
|
# os/windows.gitignore | sort -u > .gitignore
|
||||||
|
#
|
||||||
|
# IMPORTANT NOTES:
|
||||||
|
# ==============================================================================
|
||||||
|
# 1. This template is self-contained and includes security patterns
|
||||||
|
# 2. No need to add common/security.gitignore separately
|
||||||
|
# 3. Test with `git status --ignored` to ensure proper coverage
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -0,0 +1,347 @@
|
|||||||
|
const dayMap = {
|
||||||
|
"Lundi": 0,
|
||||||
|
"Mardi": 1,
|
||||||
|
"Mercredi": 2,
|
||||||
|
"Jeudi": 3,
|
||||||
|
"Vendredi": 4,
|
||||||
|
"Samedi": 5,
|
||||||
|
"Dimanche": 6
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Cours ajoutés manuellement
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
function addCourse(course = {}) {
|
||||||
|
const tbody = document.getElementById("courses");
|
||||||
|
|
||||||
|
const row = document.createElement("tr");
|
||||||
|
|
||||||
|
row.innerHTML = `
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" class="select-row" checked>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<select class="day">
|
||||||
|
<option value="0">Lundi</option>
|
||||||
|
<option value="1">Mardi</option>
|
||||||
|
<option value="2">Mercredi</option>
|
||||||
|
<option value="3">Jeudi</option>
|
||||||
|
<option value="4">Vendredi</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td><input class="start" type="time"></td>
|
||||||
|
<td><input class="end" type="time"></td>
|
||||||
|
<td><input class="name"></td>
|
||||||
|
<td><input class="prof"></td>
|
||||||
|
<td><input class="room"></td>
|
||||||
|
<td><input class="color" type="color"></td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<button type="button" class="remove">
|
||||||
|
❌
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
`;
|
||||||
|
|
||||||
|
tbody.appendChild(row);
|
||||||
|
|
||||||
|
|
||||||
|
row.querySelector(".day").value = course.day ?? 0;
|
||||||
|
row.querySelector(".start").value = course.start ?? "";
|
||||||
|
row.querySelector(".end").value = course.end ?? "";
|
||||||
|
row.querySelector(".name").value = course.name ?? "";
|
||||||
|
row.querySelector(".prof").value = course.prof ?? "";
|
||||||
|
row.querySelector(".room").value = course.room ?? "";
|
||||||
|
row.querySelector(".color").value =
|
||||||
|
course.color ?? "#80b3ff";
|
||||||
|
|
||||||
|
|
||||||
|
row.querySelector(".remove").onclick = () => {
|
||||||
|
row.remove();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Gestion des UE fondamentales
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
const fonda =
|
||||||
|
[...document.querySelectorAll(
|
||||||
|
"#courses-base .ue-selector"
|
||||||
|
)];
|
||||||
|
|
||||||
|
|
||||||
|
fonda.forEach(cb => {
|
||||||
|
|
||||||
|
cb.addEventListener("change", () => {
|
||||||
|
|
||||||
|
const selected =
|
||||||
|
fonda.filter(x => x.checked);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (selected.length > 2) {
|
||||||
|
cb.checked = false;
|
||||||
|
alert("Choisissez seulement 2 UE parmi les 3.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
updateTD();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updateTD() {
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
"#courses-base input[type=radio]"
|
||||||
|
)
|
||||||
|
.forEach(radio => {
|
||||||
|
|
||||||
|
const ue =
|
||||||
|
radio.dataset.ue;
|
||||||
|
|
||||||
|
|
||||||
|
const selected =
|
||||||
|
document.querySelector(
|
||||||
|
`.ue-selector[data-ue="${ue}"]`
|
||||||
|
)?.checked;
|
||||||
|
|
||||||
|
|
||||||
|
radio.disabled = !selected;
|
||||||
|
|
||||||
|
|
||||||
|
if (!selected)
|
||||||
|
radio.checked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Conversion d'une ligne HTML en cours JSON
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
function rowToCourse(row) {
|
||||||
|
return {
|
||||||
|
|
||||||
|
day:
|
||||||
|
Number(row.dataset.day),
|
||||||
|
|
||||||
|
start:
|
||||||
|
row.dataset.start,
|
||||||
|
|
||||||
|
end:
|
||||||
|
row.dataset.end,
|
||||||
|
|
||||||
|
name:
|
||||||
|
row.dataset.name ?? "",
|
||||||
|
|
||||||
|
prof:
|
||||||
|
row.dataset.prof ?? "",
|
||||||
|
|
||||||
|
room:
|
||||||
|
row.dataset.room ?? "",
|
||||||
|
|
||||||
|
color:
|
||||||
|
row.dataset.color ?? "#ffffff"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Extraction des cours fixes
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
function extractFixedCourses(container) {
|
||||||
|
|
||||||
|
const courses = [];
|
||||||
|
|
||||||
|
|
||||||
|
container
|
||||||
|
.querySelectorAll("tr")
|
||||||
|
.forEach(row => {
|
||||||
|
//console.log(row);
|
||||||
|
|
||||||
|
const checkbox =
|
||||||
|
document.getElementById(row.getAttribute("checkbox-id"))
|
||||||
|
|
||||||
|
enabled = checkbox.checked;
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const course =
|
||||||
|
rowToCourse(row);
|
||||||
|
console.log(course);
|
||||||
|
|
||||||
|
|
||||||
|
if (course)
|
||||||
|
courses.push(course);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return courses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Submit PDF
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById("courseForm")
|
||||||
|
.addEventListener(
|
||||||
|
"submit",
|
||||||
|
async e => {
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
||||||
|
let cours = [];
|
||||||
|
|
||||||
|
|
||||||
|
cours.push(
|
||||||
|
...extractFixedCourses(
|
||||||
|
document.getElementById(
|
||||||
|
"courses-base"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
cours.push(
|
||||||
|
...extractFixedCourses(
|
||||||
|
document.getElementById(
|
||||||
|
"courses-autre"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Cours ajoutés manuellement
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
"#courses tr"
|
||||||
|
)
|
||||||
|
.forEach(row => {
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!row.querySelector(
|
||||||
|
".select-row"
|
||||||
|
).checked
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
cours.push({
|
||||||
|
|
||||||
|
day:
|
||||||
|
Number(
|
||||||
|
row.querySelector(
|
||||||
|
".day"
|
||||||
|
).value
|
||||||
|
),
|
||||||
|
|
||||||
|
start:
|
||||||
|
row.querySelector(
|
||||||
|
".start"
|
||||||
|
).value,
|
||||||
|
|
||||||
|
end:
|
||||||
|
row.querySelector(
|
||||||
|
".end"
|
||||||
|
).value,
|
||||||
|
|
||||||
|
name:
|
||||||
|
row.querySelector(
|
||||||
|
".name"
|
||||||
|
).value,
|
||||||
|
|
||||||
|
prof:
|
||||||
|
row.querySelector(
|
||||||
|
".prof"
|
||||||
|
).value,
|
||||||
|
|
||||||
|
room:
|
||||||
|
row.querySelector(
|
||||||
|
".room"
|
||||||
|
).value,
|
||||||
|
|
||||||
|
color:
|
||||||
|
row.querySelector(
|
||||||
|
".color"
|
||||||
|
).value
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await fetch(
|
||||||
|
"/edt.pdf",
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type":
|
||||||
|
"application/json"
|
||||||
|
},
|
||||||
|
body:
|
||||||
|
JSON.stringify({
|
||||||
|
cours
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const blob =
|
||||||
|
await response.blob();
|
||||||
|
|
||||||
|
|
||||||
|
window.open(
|
||||||
|
URL.createObjectURL(blob)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// Select all cours ajoutés
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
const selectAll =
|
||||||
|
document.getElementById(
|
||||||
|
"select-all"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (selectAll) {
|
||||||
|
|
||||||
|
selectAll.onchange = () => {
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
".select-row"
|
||||||
|
)
|
||||||
|
.forEach(cb => {
|
||||||
|
cb.checked =
|
||||||
|
selectAll.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #f5f6fa;
|
||||||
|
padding: 30px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
background: white;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tbody:nth-child(even) td {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:hover {
|
||||||
|
background: #f1f5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="color"] {
|
||||||
|
height: 35px;
|
||||||
|
padding: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus,
|
||||||
|
select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #4a90e2;
|
||||||
|
box-shadow: 0 0 0 2px rgba(74,144,226,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 15px;
|
||||||
|
transition: 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
button[type="submit"] {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="button"] {
|
||||||
|
background: #e5e7eb;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
background: #333 !important;
|
||||||
|
color: white;
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#courses tr {
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Better mobile display */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#import "@preview/cetz:0.5.1"
|
||||||
|
|
||||||
|
#let time(h,m) = datetime(hour:h, minute: m, second: 0)
|
||||||
|
|
||||||
|
#let parse_time(s) = {
|
||||||
|
let (h, m) = s.match(regex("(\d{2}):(\d{2})")).captures.map(int)
|
||||||
|
time(h,m)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let gety(s) = {
|
||||||
|
let dt = parse_time(s)
|
||||||
|
11-(dt - time(8,0)).hours()
|
||||||
|
}
|
||||||
|
|
||||||
|
#let sans_font = "Fira Sans"
|
||||||
|
|
||||||
|
|
||||||
|
#let titre = "EDT 2026/2027 -- M1 S1"
|
||||||
|
|
||||||
|
#let data = json(bytes(sys.inputs.data))
|
||||||
|
|
||||||
|
#let cours = data.cours
|
||||||
|
/*
|
||||||
|
Un exemple :
|
||||||
|
|
||||||
|
#let cours = (
|
||||||
|
(day: 0, start: "08:15", end: "10:15", name:"Algèbre (CM)", prof:"Jean-Benoît Bost", room: "OA1", color: "#ff80b3"),
|
||||||
|
(day: 0, start: "10:30", end: "13:00", name:"Algèbre (TD)", prof:"x", room: "OA1", color: "#ff80b3"),
|
||||||
|
(day: 3, start: "14:00", end: "16:00", name:"Algèbre (CM)", prof:"Jean-Benoît Bost", room: "OA1", color: "#ff80b3"),
|
||||||
|
(day: 3, start: "16:15", end: "18:45", name:"Algèbre (TD)", prof:"x", room: "OA1", color: "#ff80b3"),
|
||||||
|
|
||||||
|
(day: 0, start: "14:00", end: "16:00", name:"Analyse (CM)", prof:"Blanche Buet", room: "OA1", color: "#80ffcc"),
|
||||||
|
(day: 0, start: "16:15", end: "18:45", name:"Analyse (TD)", prof:"x", room: "OA1", color: "#80ffcc"),
|
||||||
|
(day: 2, start: "08:15", end: "10:15", name:"Analyse (CM)", prof:"Blanche Buet", room: "OA1", color: "#80ffcc"),
|
||||||
|
(day: 2, start: "10:30", end: "13:00", name:"Analyse (TD)", prof:"x", room: "OA1", color: "#80ffcc"),
|
||||||
|
|
||||||
|
(day: 1, start: "14:00", end: "16:00", name:"Cryptographie (CM)", prof:"Stéphane Fischler", room: "OA1", color: "#e6b3ff"),
|
||||||
|
(day: 4, start: "10:30", end: "12:30", name:"Cryptographie (TP)", prof:"Chimène Fischler", room: "OA1", color: "#e6b3ff")
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#set page(
|
||||||
|
paper: "a4",
|
||||||
|
flipped: true,
|
||||||
|
footer: [
|
||||||
|
#set align(right)
|
||||||
|
#set text(font: sans_font, size: 9pt)
|
||||||
|
$copyright$ EDT Valentin Moguérou 2026
|
||||||
|
],
|
||||||
|
margin: (
|
||||||
|
x: 1.5cm,
|
||||||
|
top: 1cm,
|
||||||
|
bottom: 1cm,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
#set par(justify: true)
|
||||||
|
#set text(
|
||||||
|
font: "New Computer Modern",
|
||||||
|
size: 11pt,
|
||||||
|
)
|
||||||
|
|
||||||
|
#set align(center)
|
||||||
|
|
||||||
|
#let jours = ("Lundi","Mardi","Mercredi","Jeudi","Vendredi")
|
||||||
|
|
||||||
|
#align(center, text(titre, size: 15pt, weight: "bold"))
|
||||||
|
|
||||||
|
#cetz.canvas(
|
||||||
|
length: 1.5cm,
|
||||||
|
{
|
||||||
|
import cetz.draw: *
|
||||||
|
|
||||||
|
for heure in range(8,20) {
|
||||||
|
content((-.5,18.85-heure),
|
||||||
|
text([#heure:00], font: sans_font, size: 9pt))
|
||||||
|
|
||||||
|
line((-0.5,19-heure),(0,19-heure), stroke:1pt)
|
||||||
|
|
||||||
|
|
||||||
|
if calc.even(heure) { line((0,19-heure),(15,19-heure), stroke:0.5pt+gray) }
|
||||||
|
|
||||||
|
}
|
||||||
|
line((0,11),(15,11), stroke:1pt) // 8h
|
||||||
|
line((0,0),(15,0), stroke:1pt) // 19h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for c in cours {
|
||||||
|
content(
|
||||||
|
(3*c.day, gety(c.start)+.05),
|
||||||
|
(3*(c.day+1), gety(c.end)-.05),
|
||||||
|
frame: "rect",
|
||||||
|
fill: rgb(c.color),
|
||||||
|
stroke: 0.5pt,
|
||||||
|
align(center+horizon)[
|
||||||
|
*#c.name* \
|
||||||
|
#c.prof
|
||||||
|
|
||||||
|
#set text(size: 9pt, font: sans_font)
|
||||||
|
#if c.room != "" [*#c.room*, ]
|
||||||
|
#(c.start)--#c.end
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for jour in range(5) {
|
||||||
|
content((3*jour+1.5,11.3), text([#jours.at(jour)], font: sans_font, size: 11pt))
|
||||||
|
line((3*jour,11.3),(3*jour,0), stroke:1pt)
|
||||||
|
}
|
||||||
|
line((15,11.5),(15,0), stroke:1pt)
|
||||||
|
})
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>EDT Generator</title>
|
||||||
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>#m1edt</h1>
|
||||||
|
|
||||||
|
<form id="courseForm">
|
||||||
|
|
||||||
|
<h2>Cours fondamentaux : choisir 2 parmi 3</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>UE</th>
|
||||||
|
<th>Sélection</th>
|
||||||
|
<th>Jour</th>
|
||||||
|
<th>Début</th>
|
||||||
|
<th>Fin</th>
|
||||||
|
<th>Atome</th>
|
||||||
|
<th>Enseignant</th>
|
||||||
|
<th>Salle</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody id="courses-base">
|
||||||
|
{% set jours = ["Lundi","Mardi","Mercredi","Jeudi","Vendredi"] %}
|
||||||
|
|
||||||
|
{% for ue in cours_base %}
|
||||||
|
|
||||||
|
{% set rowspan = ue.cm|length + 2 * (ue.td|length) %}
|
||||||
|
|
||||||
|
{# ---------------- CM ---------------- #}
|
||||||
|
|
||||||
|
{% for cm in ue.cm %}
|
||||||
|
|
||||||
|
<tr
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
data-name="{{ ue.name }} CM"
|
||||||
|
data-prof="{{ cm.prof }}"
|
||||||
|
data-room="{{ cm.room }}"
|
||||||
|
data-color="{{ ue.color }}"
|
||||||
|
data-day="{{ cm.day }}"
|
||||||
|
data-start="{{ cm.start }}"
|
||||||
|
data-end="{{ cm.end }}"
|
||||||
|
checkbox-id="checkbox-{{ ue.ue }}-cm">
|
||||||
|
|
||||||
|
{% if loop.first %}
|
||||||
|
<td rowspan="{{ rowspan }}" bgcolor="{{ ue.color }}"></td>
|
||||||
|
<td rowspan="{{ rowspan }}">{{ ue.name }}</td>
|
||||||
|
<td rowspan="{{ ue.cm|length }}">
|
||||||
|
<input
|
||||||
|
id="checkbox-{{ ue.ue }}-cm"
|
||||||
|
class="ue-selector"
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
type="checkbox">
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td>{{ jours[cm.day] }}</td>
|
||||||
|
<td>{{ cm.start }}</td>
|
||||||
|
<td>{{ cm.end }}</td>
|
||||||
|
|
||||||
|
{% if loop.first %}
|
||||||
|
<td rowspan="{{ ue.cm|length }}">CM</td>
|
||||||
|
<td rowspan="{{ ue.cm|length }}">{{ cm.prof }}</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td>{{ cm.room }}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
{# ---------------- TD ---------------- #}
|
||||||
|
|
||||||
|
{% for td in ue.td %}
|
||||||
|
|
||||||
|
{% for slot in td.slots %}
|
||||||
|
|
||||||
|
<tr
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
data-name="{{ ue.name }} TD"
|
||||||
|
data-prof="{{ td.prof }}"
|
||||||
|
data-room="{{ slot.room }}"
|
||||||
|
data-color="{{ ue.color }}"
|
||||||
|
data-day="{{ slot.day }}"
|
||||||
|
data-start="{{ slot.start }}"
|
||||||
|
data-end="{{ slot.end }}"
|
||||||
|
checkbox-id="checkbox-{{ ue.ue }}-td{{ td.group }}">
|
||||||
|
|
||||||
|
{% if loop.first %}
|
||||||
|
<td rowspan="{{ td.slots|length }}">
|
||||||
|
<input
|
||||||
|
id="checkbox-{{ ue.ue }}-td{{ td.group }}"
|
||||||
|
type="radio"
|
||||||
|
name="gr_td_{{ ue.ue }}"
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
disabled>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td>{{ jours[slot.day] }}</td>
|
||||||
|
<td>{{ slot.start }}</td>
|
||||||
|
<td>{{ slot.end }}</td>
|
||||||
|
|
||||||
|
{% if loop.first %}
|
||||||
|
<td rowspan="{{ td.slots|length }}">TD G{{ td.group }}</td>
|
||||||
|
<td rowspan="{{ td.slots|length }}">{{ td.prof }}</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td>{{ slot.room }}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Autres cours</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>UE</th>
|
||||||
|
<th>Sélection</th>
|
||||||
|
<th>Jour</th>
|
||||||
|
<th>Début</th>
|
||||||
|
<th>Fin</th>
|
||||||
|
<th>Atome</th>
|
||||||
|
<th>Enseignant</th>
|
||||||
|
<th>Salle</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="courses-autre">
|
||||||
|
|
||||||
|
|
||||||
|
{% set jours = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi"] %}
|
||||||
|
|
||||||
|
{% for ue in cours_autres %}
|
||||||
|
|
||||||
|
{% set rowspan = ue.atoms|length %}
|
||||||
|
|
||||||
|
{% for atom in ue.atoms %}
|
||||||
|
|
||||||
|
<tr
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
data-name="{{ ue.name }}"
|
||||||
|
data-prof="{{ atom.prof }}"
|
||||||
|
data-room="{{ atom.room }}"
|
||||||
|
data-color="{{ ue.color }}"
|
||||||
|
data-day="{{ atom.day }}"
|
||||||
|
data-start="{{ atom.start }}"
|
||||||
|
data-end="{{ atom.end }}"
|
||||||
|
checkbox-id="checkbox-{{ ue.ue }}">
|
||||||
|
|
||||||
|
{% if loop.first %}
|
||||||
|
<td rowspan="{{ rowspan }}" bgcolor="{{ ue.color }}"></td>
|
||||||
|
<td rowspan="{{ rowspan }}">{{ ue.name }}</td>
|
||||||
|
|
||||||
|
<td rowspan="{{ rowspan }}">
|
||||||
|
<input
|
||||||
|
id="checkbox-{{ ue.ue }}"
|
||||||
|
class="ue-selector"
|
||||||
|
data-ue="{{ ue.ue }}"
|
||||||
|
type="checkbox">
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td>{{ jours[atom.day] }}</td>
|
||||||
|
<td>{{ atom.start }}</td>
|
||||||
|
<td>{{ atom.end }}</td>
|
||||||
|
<td>{{ atom.label }}</td>
|
||||||
|
<td>{{ atom.prof }}</td>
|
||||||
|
<td>{{ atom.room }}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Ajouter des cours</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<input id="select-all"
|
||||||
|
type="checkbox">
|
||||||
|
</th>
|
||||||
|
<th>Jour</th>
|
||||||
|
<th>Début</th>
|
||||||
|
<th>Fin</th>
|
||||||
|
<th>Nom</th>
|
||||||
|
<th>Enseignant</th>
|
||||||
|
<th>Salle</th>
|
||||||
|
<th>Couleur</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody id="courses"></tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" onclick="addCourse()">
|
||||||
|
Ajouter
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="submit">
|
||||||
|
Générer PDF
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="/static/builder.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from flask import render_template, send_file, request, redirect, url_for
|
||||||
|
import typst
|
||||||
|
import json
|
||||||
|
from io import BytesIO
|
||||||
|
import random
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
cours_base = [
|
||||||
|
# ALGEBRE
|
||||||
|
{
|
||||||
|
"ue": "algebre",
|
||||||
|
"name": "Algèbre",
|
||||||
|
"color": "#ff80b3",
|
||||||
|
"cm": [
|
||||||
|
{
|
||||||
|
"prof": "Jean-Benoît Bost",
|
||||||
|
"day": 0, "start": "08:15", "end": "10:15", "room": "Amphi Yoccoz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prof": "Jean-Benoît Bost",
|
||||||
|
"day": 3, "start": "14:00", "end": "16:00", "room": "Amphi Yoccoz",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"td": [
|
||||||
|
{
|
||||||
|
"group": 1,
|
||||||
|
"prof": "Kévin Destagnol",
|
||||||
|
"slots": [
|
||||||
|
{"day": 0, "start": "10:30", "end": "13:00", "room": "0A2"},
|
||||||
|
{"day": 3, "start": "16:15", "end": "18:45", "room": "0A2"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": 2,
|
||||||
|
"prof": "Pierre Lorenzon",
|
||||||
|
"slots": [
|
||||||
|
{"day": 0, "start": "10:30", "end": "13:00", "room": "0A7"},
|
||||||
|
{"day": 3, "start": "16:15", "end": "18:45", "room": "0E1"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# ANALYSE
|
||||||
|
{
|
||||||
|
"ue": "analyse",
|
||||||
|
"name": "Analyse",
|
||||||
|
"color": "#80ffcc",
|
||||||
|
"cm": [
|
||||||
|
{
|
||||||
|
"prof": "Blanche Buet",
|
||||||
|
"day": 0, "start": "14:00", "end": "16:00", "room": "OA2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prof": "Blanche Buet",
|
||||||
|
"day": 2, "start": "08:15", "end": "10:15", "room": "OA1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"td": [
|
||||||
|
{
|
||||||
|
"group": 1,
|
||||||
|
"prof": "Frédéric Valet",
|
||||||
|
"slots": [
|
||||||
|
{"day": 0, "start": "16:15", "end": "18:45", "room": "0A2"},
|
||||||
|
{"day": 2, "start": "10:30", "end": "13:00", "room": "0A1"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": 2,
|
||||||
|
"prof": "Sebastian Bechtel",
|
||||||
|
"slots": [
|
||||||
|
{"day": 0, "start": "16:15", "end": "18:45", "room": "0A7"},
|
||||||
|
{"day": 2, "start": "10:30", "end": "13:00", "room": "0D1"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# PROBAS
|
||||||
|
{
|
||||||
|
"ue": "probas",
|
||||||
|
"name": "Probabilités",
|
||||||
|
"color": "#ffcc99",
|
||||||
|
"cm": [
|
||||||
|
{
|
||||||
|
"prof": "Pierre-Loïc Méliot",
|
||||||
|
"day": 1, "start": "08:15", "end": "10:15", "room": "Amphi Yoccoz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"prof": "Pierre-Loïc Méliot",
|
||||||
|
"day": 3, "start": "08:15", "end": "10:15", "room": "Amphi Yoccoz",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"td": [
|
||||||
|
{
|
||||||
|
"group": 1,
|
||||||
|
"prof": "Sophie Lemaire",
|
||||||
|
"slots": [
|
||||||
|
{"day": 1, "start": "10:30", "end": "13:00", "room": "0D1"},
|
||||||
|
{"day": 3, "start": "10:30", "end": "13:00", "room": "0E1"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": 2,
|
||||||
|
"prof": "A. Legrand",
|
||||||
|
"slots": [
|
||||||
|
{"day": 1, "start": "10:30", "end": "13:00", "room": "Amphi Yoccoz"},
|
||||||
|
{"day": 3, "start": "10:30", "end": "13:00", "room": "0A2"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
cours_autres = [
|
||||||
|
{
|
||||||
|
"ue": "crypto",
|
||||||
|
"name": "Cryptographie",
|
||||||
|
"color": "#e6b3ff",
|
||||||
|
"atoms": [
|
||||||
|
{
|
||||||
|
"label": "CM",
|
||||||
|
"prof": "Stéphane Fischler",
|
||||||
|
"day": 1,
|
||||||
|
"start": "14:00",
|
||||||
|
"end": "16:00",
|
||||||
|
"room": "0A2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TP",
|
||||||
|
"prof": "Chimène Fischler",
|
||||||
|
"day": 4,
|
||||||
|
"start": "10:30",
|
||||||
|
"end": "12:30",
|
||||||
|
"room": "0E10",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ue": "geo_alea",
|
||||||
|
"name": "Géométrie aléatoire",
|
||||||
|
"color": "#ccb3ff",
|
||||||
|
"atoms": [
|
||||||
|
{
|
||||||
|
"label": "CM",
|
||||||
|
"prof": "N. Curien",
|
||||||
|
"day": 1,
|
||||||
|
"start": "16:15",
|
||||||
|
"end": "18:15",
|
||||||
|
"room": "1A7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TP",
|
||||||
|
"prof": "A. Legrand",
|
||||||
|
"day": 4,
|
||||||
|
"start": "08:15",
|
||||||
|
"end": "10:15",
|
||||||
|
"room": "0D10",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ue": "edp_num",
|
||||||
|
"name": "EDP numériques",
|
||||||
|
"color": "#ccebff",
|
||||||
|
"atoms": [
|
||||||
|
{
|
||||||
|
"label": "CM",
|
||||||
|
"prof": "B. Maury",
|
||||||
|
"day": 1,
|
||||||
|
"start": "16:15",
|
||||||
|
"end": "18:15",
|
||||||
|
"room": "0A5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TP",
|
||||||
|
"prof": "B. Graille",
|
||||||
|
"day": 4,
|
||||||
|
"start": "08:15",
|
||||||
|
"end": "10:15",
|
||||||
|
"room": "0E10",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ue": "topalg",
|
||||||
|
"name": "Topologie algébrisée",
|
||||||
|
"color": "#a366ff",
|
||||||
|
"atoms": [
|
||||||
|
{
|
||||||
|
"label": "CI",
|
||||||
|
"prof": "Patrick Massot",
|
||||||
|
"day": 2,
|
||||||
|
"start": "14:00",
|
||||||
|
"end": "18:15",
|
||||||
|
"room": "0A1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return render_template('index.html', cours_base=cours_base, cours_autres=cours_autres)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/favicon.ico")
|
||||||
|
def favicon():
|
||||||
|
return send_file("favicon.ico")
|
||||||
|
|
||||||
|
@app.route('/edt.pdf', methods=["GET", "POST"])
|
||||||
|
def generate_pdf():
|
||||||
|
if request.method != "POST":
|
||||||
|
data = {
|
||||||
|
"cours": [
|
||||||
|
{"day": 0, "start": "08:15", "end": "10:xx", "name": "Algèbre (CM)", "prof": "Jean-Benoît Bost", "room": "OA1", "color": "#ff80b3"},
|
||||||
|
{"day": 0, "start": "10:30", "end": "13:00", "name": "Algèbre (TD)", "prof": "x", "room": "OA1", "color": "#ff80b3"},
|
||||||
|
{"day": 3, "start": "14:00", "end": "16:00", "name": "Algèbre (CM)", "prof": "Jean-Benoît Bost", "room": "OA1", "color": "#ff80b3"},
|
||||||
|
{"day": 3, "start": "16:15", "end": "18:45", "name": "Algèbre (TD)", "prof": "x", "room": "OA1", "color": "#ff80b3"},
|
||||||
|
|
||||||
|
{"day": 0, "start": "14:00", "end": "16:00", "name": "Analyse (CM)", "prof": "Blanche Buet", "room": "OA1", "color": "#80ffcc"},
|
||||||
|
{"day": 0, "start": "16:15", "end": "18:45", "name": "Analyse (TD)", "prof": "x", "room": "OA1", "color": "#80ffcc"},
|
||||||
|
{"day": 2, "start": "08:15", "end": "10:15", "name": "Analyse (CM)", "prof": "Blanche Buet", "room": "OA1", "color": "#80ffcc"},
|
||||||
|
{"day": 2, "start": "10:30", "end": "13:00", "name": "Analyse (TD)", "prof": "x", "room": "OA1", "color": "#80ffcc"},
|
||||||
|
|
||||||
|
{"day": 1, "start": "14:00", "end": "16:00", "name": "Cryptographie (CM)", "prof": "Stéphane Fischler","room": "OA1", "color": "#e6b3ff"},
|
||||||
|
{"day": 4, "start": "10:30", "end": "12:30", "name": "Cryptographie (TP)", "prof": "Chimène Fischler", "room": "OA1", "color": "#e6b3ff"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
print(data)
|
||||||
|
else:
|
||||||
|
data = json.loads(request.data)
|
||||||
|
pprint(data)
|
||||||
|
|
||||||
|
sys_inputs = {"data": json.dumps(data)}
|
||||||
|
|
||||||
|
pdf_file = BytesIO(typst.compile(input="templates/edt.typ", sys_inputs=sys_inputs))
|
||||||
|
|
||||||
|
return send_file(pdf_file, download_name="edt.pdf")
|
||||||
Reference in New Issue
Block a user