feat: Bloquer la création de devoirs non conformes en mode hard
Les établissements utilisant le mode "Hard" des règles de devoirs empêchent désormais les enseignants de créer des devoirs hors règles. Contrairement au mode "Soft" (avertissement avec possibilité de passer outre), le mode "Hard" est un blocage strict : même acknowledgeWarning ne permet pas de contourner. L'API retourne 422 (au lieu de 409 pour le soft) avec des dates conformes suggérées calculées via le calendrier scolaire (weekends, fériés, vacances exclus). Le frontend affiche un modal de blocage avec les raisons, des dates cliquables, et une validation client inline qui empêche la soumission de dates non conformes.
This commit is contained in:
@@ -623,6 +623,75 @@ final class HomeworkEndpointsTest extends ApiTestCase
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 5.5-FUNC-001 (P0) - POST /homework with hard rules violated → 422 with blocked response
|
||||
// =========================================================================
|
||||
|
||||
#[Test]
|
||||
public function createHomeworkReturns422WhenHardRulesViolated(): void
|
||||
{
|
||||
$this->persistHardRulesWithMinimumDelay(7);
|
||||
$this->seedTeacherAssignment();
|
||||
|
||||
$client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);
|
||||
|
||||
$tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');
|
||||
|
||||
$client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => [
|
||||
'classId' => self::CLASS_ID,
|
||||
'subjectId' => self::SUBJECT_ID,
|
||||
'title' => 'Devoir test 422',
|
||||
'dueDate' => $tomorrow,
|
||||
],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
$json = $client->getResponse()->toArray(false);
|
||||
self::assertSame('homework_rules_blocked', $json['type']);
|
||||
self::assertNotEmpty($json['warnings']);
|
||||
self::assertSame('minimum_delay', $json['warnings'][0]['ruleType']);
|
||||
self::assertArrayHasKey('suggestedDates', $json);
|
||||
self::assertArrayHasKey('exceptionRequestPath', $json);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 5.5-FUNC-002 (P0) - POST /homework with hard rules violated + acknowledgeWarning → still 422
|
||||
// =========================================================================
|
||||
|
||||
#[Test]
|
||||
public function createHomeworkReturns422EvenWhenHardRulesAcknowledged(): void
|
||||
{
|
||||
$this->persistHardRulesWithMinimumDelay(7);
|
||||
$this->seedTeacherAssignment();
|
||||
|
||||
$client = $this->createAuthenticatedClient(self::OWNER_TEACHER_ID, ['ROLE_PROF']);
|
||||
|
||||
$tomorrow = (new DateTimeImmutable('+1 weekday'))->format('Y-m-d');
|
||||
|
||||
$client->request('POST', 'http://ecole-alpha.classeo.local/api/homework', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => [
|
||||
'classId' => self::CLASS_ID,
|
||||
'subjectId' => self::SUBJECT_ID,
|
||||
'title' => 'Devoir bypass hard',
|
||||
'dueDate' => $tomorrow,
|
||||
'acknowledgeWarning' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
$json = $client->getResponse()->toArray(false);
|
||||
self::assertSame('homework_rules_blocked', $json['type']);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Helpers
|
||||
// =========================================================================
|
||||
@@ -657,6 +726,19 @@ final class HomeworkEndpointsTest extends ApiTestCase
|
||||
);
|
||||
}
|
||||
|
||||
private function persistHardRulesWithMinimumDelay(int $days): void
|
||||
{
|
||||
/** @var Connection $connection */
|
||||
$connection = static::getContainer()->get(Connection::class);
|
||||
$rulesJson = json_encode([['type' => 'minimum_delay', 'params' => ['days' => $days]]], JSON_THROW_ON_ERROR);
|
||||
$connection->executeStatement(
|
||||
"INSERT INTO homework_rules (id, tenant_id, rules, enforcement_mode, enabled, created_at, updated_at)
|
||||
VALUES (gen_random_uuid(), :tid, :rules::jsonb, 'hard', true, NOW(), NOW())
|
||||
ON CONFLICT (tenant_id) DO UPDATE SET rules = :rules::jsonb, enforcement_mode = 'hard', enabled = true, updated_at = NOW()",
|
||||
['tid' => self::TENANT_ID, 'rules' => $rulesJson],
|
||||
);
|
||||
}
|
||||
|
||||
private function seedTeacherAssignment(): void
|
||||
{
|
||||
/** @var Connection $connection */
|
||||
|
||||
Reference in New Issue
Block a user