feat: Permettre aux enseignants de contourner les règles de devoirs avec justification
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled

Akeneo permet de configurer des règles de devoirs en mode Hard qui bloquent
totalement la création. Or certains cas légitimes (sorties scolaires, événements
exceptionnels) nécessitent de passer outre ces règles. Sans mécanisme d'exception,
l'enseignant est bloqué et doit contacter manuellement la direction.

Cette implémentation ajoute un flux complet d'exception : l'enseignant justifie
sa demande (min 20 caractères), le devoir est créé immédiatement, et la direction
est notifiée par email. Le handler vérifie côté serveur que les règles sont
réellement bloquantes avant d'accepter l'exception, empêchant toute fabrication
de fausses exceptions via l'API. La direction dispose d'un rapport filtrable
par période, enseignant et type de règle.
This commit is contained in:
2026-03-19 21:58:56 +01:00
parent d34d31976f
commit 14c7849179
35 changed files with 3477 additions and 23 deletions

View File

@@ -112,13 +112,7 @@ function seedHardRules() {
);
}
function clearRules() {
try {
runSql(`DELETE FROM homework_rules WHERE tenant_id = '${TENANT_ID}'`);
} catch {
// Table may not exist
}
}
async function openCreateAndFillForm(page: import('@playwright/test').Page, title: string, daysFromNow: number) {
await page.getByRole('button', { name: /nouveau devoir/i }).click();
@@ -168,7 +162,10 @@ test.describe('Homework Rules - Hard Mode Blocking (Story 5.5)', () => {
// Table may not exist
}
clearRules();
// NOTE: Do NOT call clearRules() here — it deletes rules for the shared
// tenant and creates race conditions with other spec files running in
// parallel. Each test seeds its own rules via seedHardRules() which uses
// ON CONFLICT DO UPDATE, so prior state is irrelevant.
clearCache();
});
@@ -276,7 +273,7 @@ test.describe('Homework Rules - Hard Mode Blocking (Story 5.5)', () => {
// AC3: Exception request information
// ============================================================================
test.describe('AC3: Exception request information', () => {
test('shows exception contact information in blocking modal', async ({ page }) => {
test('shows exception request button in blocking modal', async ({ page }) => {
seedHardRules();
clearCache();
@@ -287,8 +284,8 @@ test.describe('Homework Rules - Hard Mode Blocking (Story 5.5)', () => {
const blockedDialog = page.getByRole('alertdialog');
await expect(blockedDialog).toBeVisible({ timeout: 10000 });
// Exception information visible
await expect(blockedDialog.getByText(/exception.*contactez/i)).toBeVisible();
// Exception request button visible (Story 5.6 replaced static text with a real button)
await expect(blockedDialog.getByRole('button', { name: /demander une exception/i })).toBeVisible();
});
});