diff --git a/databases/migrations/0003_add_session2_and_malus.sql b/databases/migrations/0003_add_session2_and_malus.sql
new file mode 100644
index 0000000..d3a950b
--- /dev/null
+++ b/databases/migrations/0003_add_session2_and_malus.sql
@@ -0,0 +1,3 @@
+ALTER TABLE "notes" ADD COLUMN "noteSession2" double precision;
+--> statement-breakpoint
+ALTER TABLE "ajustements" ADD COLUMN "malus" integer NOT NULL DEFAULT 0;
diff --git a/databases/migrations/meta/_journal.json b/databases/migrations/meta/_journal.json
index e4f070f..f81c27d 100644
--- a/databases/migrations/meta/_journal.json
+++ b/databases/migrations/meta/_journal.json
@@ -22,6 +22,13 @@
"when": 1777155028710,
"tag": "0002_update_permission_names",
"breakpoints": true
+ },
+ {
+ "idx": 3,
+ "version": "7",
+ "when": 1777155028711,
+ "tag": "0003_add_session2_and_malus",
+ "breakpoints": true
}
]
}
diff --git a/databases/schema.ts b/databases/schema.ts
index 823c7a2..9bf678d 100644
--- a/databases/schema.ts
+++ b/databases/schema.ts
@@ -75,6 +75,7 @@ export const notes = pgTable("notes", {
numEtud: integer("numEtud").notNull().references(() => students.numEtud),
idModule: text("idModule").notNull().references(() => modules.id),
note: doublePrecision("note").notNull(),
+ noteSession2: doublePrecision("noteSession2"),
}, (t) => ({
pk: primaryKey({ columns: [t.numEtud, t.idModule] }),
}));
@@ -83,6 +84,7 @@ export const ajustements = pgTable("ajustements", {
numEtud: integer("numEtud").notNull().references(() => students.numEtud),
idUE: integer("idUE").notNull().references(() => ues.id),
valeur: doublePrecision("valeur").notNull(),
+ malus: integer("malus").notNull().default(0),
}, (t) => ({
pk: primaryKey({ columns: [t.numEtud, t.idUE] }),
}));
diff --git a/databases/seeds/test_data.sql b/databases/seeds/test_data.sql
new file mode 100644
index 0000000..fb81726
--- /dev/null
+++ b/databases/seeds/test_data.sql
@@ -0,0 +1,358 @@
+-- ============================================================
+-- PolyMPR — Test seed data
+-- Source: JIN7SAA Semestre 7 Informatique FISE
+-- ============================================================
+
+-- ------------------------------------------------------------
+-- 1. Promotion
+-- ------------------------------------------------------------
+INSERT INTO promotions ("idPromo", "annee") VALUES
+ ('4AFISE', '2024')
+ON CONFLICT ("idPromo") DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 2. Students
+-- ------------------------------------------------------------
+INSERT INTO students ("numEtud", nom, prenom, "idPromo") VALUES
+ (24029625, 'MARTIN', 'Sophie', '4AFISE'),
+ (22005810, 'DUPONT', 'Lucas', '4AFISE'),
+ (24026283, 'BERNARD', 'Emma', '4AFISE'),
+ (24024101, 'THOMAS', 'Hugo', '4AFISE'),
+ (24021136, 'PETIT', 'Léa', '4AFISE'),
+ (24027947, 'ROBERT', 'Nathan', '4AFISE'),
+ (22001491, 'RICHARD', 'Alice', '4AFISE'),
+ (22023423, 'SIMON', 'Théo', '4AFISE'),
+ (21217292, 'LAURENT', 'Camille', '4AFISE'),
+ (24024550, 'LEFEBVRE', 'Maxime', '4AFISE'),
+ (22019957, 'MICHEL', 'Inès', '4AFISE'),
+ (22008222, 'GARCIA', 'Baptiste', '4AFISE'),
+ (22006557, 'DAVID', 'Manon', '4AFISE'),
+ (22019337, 'BERTRAND', 'Julien', '4AFISE'),
+ (22017498, 'ROUX', 'Chloé', '4AFISE'),
+ (22019070, 'VINCENT', 'Tom', '4AFISE'),
+ (21213966, 'FOURNIER', 'Jade', '4AFISE'),
+ (25027910, 'MOREL', 'Enzo', '4AFISE'),
+ (24025920, 'GIRARD', 'Anaïs', '4AFISE'),
+ (21212006, 'ANDRÉ', 'Romain', '4AFISE'),
+ (21230594, 'LEFÈVRE', 'Pauline', '4AFISE'),
+ (22010753, 'MERCIER', 'Axel', '4AFISE'),
+ (24031005, 'DUPUIS', 'Clara', '4AFISE'),
+ (24029523, 'LAMBERT', 'Florian', '4AFISE'),
+ (24025433, 'BONNET', 'Mathilde', '4AFISE'),
+ (23024748, 'FRANCOIS', 'Louis', '4AFISE'),
+ (24016406, 'MARTINEZ', 'Zoé', '4AFISE'),
+ (24028169, 'LEBLANC', 'Kévin', '4AFISE'),
+ (22017365, 'GARNIER', 'Julie', '4AFISE'),
+ (23026015, 'CHEVALIER', 'Antoine', '4AFISE')
+ON CONFLICT ("numEtud") DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 3. Role: Professeur
+-- ------------------------------------------------------------
+INSERT INTO roles (nom) VALUES ('Professeur')
+ON CONFLICT DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 4. Permissions du rôle Professeur
+-- ------------------------------------------------------------
+INSERT INTO role_permissions ("idRole", "idPermission")
+SELECT r.id, p.id
+FROM roles r, permissions p
+WHERE r.nom = 'Professeur'
+ AND p.id IN ('note_read', 'note_write', 'student_read', 'module_read')
+ON CONFLICT DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 5. Professor users
+-- ------------------------------------------------------------
+INSERT INTO users (id, nom, prenom, "idRole")
+SELECT prof.id, prof.nom, prof.prenom, r.id
+FROM roles r,
+(VALUES
+ ('prof.jin701b', 'DUBOIS', 'Pierre'),
+ ('prof.jin701c', 'MOREAU', 'Claire'),
+ ('prof.jin710a', 'DURAND', 'François'),
+ ('prof.jin702a', 'LEROY', 'Anne'),
+ ('prof.jin702b', 'GIRARD', 'Michel'),
+ ('prof.jin702c', 'MOREL', 'Patricia'),
+ ('prof.jin703a', 'SIMON', 'Jacques'),
+ ('prof.jin703b', 'LAURENT', 'Sylvie'),
+ ('prof.jin703c', 'LEFEBVRE', 'René'),
+ ('prof.jin712a', 'ROUSSEAU', 'Hélène'),
+ ('prof.jin712b', 'BLANC', 'Philippe'),
+ ('prof.jin712c', 'GUERIN', 'Stéphane'),
+ ('prof.jtr701a', 'THOMAS', 'Sarah'),
+ ('prof.jtr701d', 'ROBIN', 'Christine'),
+ ('prof.jtr701e', 'DAVID', 'Bernard'),
+ ('prof.jtr701f', 'FAURE', 'Daniel')
+) AS prof(id, nom, prenom)
+WHERE r.nom = 'Professeur'
+ON CONFLICT (id) DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 6. Modules
+-- ------------------------------------------------------------
+INSERT INTO modules (id, nom) VALUES
+ ('JIN701B', 'Programmation distribuée'),
+ ('JIN701C', 'Projet développement 1'),
+ ('JIN710A', 'Virtualisation et Conteneurisation'),
+ ('JIN702A', 'Probabilités'),
+ ('JIN702B', 'Statistiques'),
+ ('JIN702C', 'Optimisation'),
+ ('JIN703A', 'Programmation graphique'),
+ ('JIN703B', 'Analyse d''images'),
+ ('JIN703C', 'Modélisation géométrique'),
+ ('JIN712A', 'Apprentissage automatique'),
+ ('JIN712B', 'Fouilles de données'),
+ ('JIN712C', 'Base de données avancées'),
+ ('JTR701A', 'Anglais'),
+ ('JTR701D', 'Gestion commerciale et marketing'),
+ ('JTR701E', 'Management de la qualité'),
+ ('JTR701F', 'Management de Projet')
+ON CONFLICT (id) DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 7. UEs
+-- ------------------------------------------------------------
+INSERT INTO ues (nom) VALUES
+ ('Conception et développement Avancés 1'),
+ ('Mathématiques pour l''Informatique 2'),
+ ('Introduction à la réalité mixte'),
+ ('IA et Science des Données Avancées'),
+ ('Langues et SHEJS 3')
+ON CONFLICT DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 8. UE-Module associations (coeff 1 for all)
+-- ------------------------------------------------------------
+INSERT INTO ue_modules ("idModule", "idUE", "idPromo", coeff)
+SELECT m, u.id, '4AFISE', 1
+FROM ues u,
+(VALUES
+ ('JIN701B', 'Conception et développement Avancés 1'),
+ ('JIN701C', 'Conception et développement Avancés 1'),
+ ('JIN710A', 'Conception et développement Avancés 1'),
+ ('JIN702A', 'Mathématiques pour l''Informatique 2'),
+ ('JIN702B', 'Mathématiques pour l''Informatique 2'),
+ ('JIN702C', 'Mathématiques pour l''Informatique 2'),
+ ('JIN703A', 'Introduction à la réalité mixte'),
+ ('JIN703B', 'Introduction à la réalité mixte'),
+ ('JIN703C', 'Introduction à la réalité mixte'),
+ ('JIN712A', 'IA et Science des Données Avancées'),
+ ('JIN712B', 'IA et Science des Données Avancées'),
+ ('JIN712C', 'IA et Science des Données Avancées'),
+ ('JTR701A', 'Langues et SHEJS 3'),
+ ('JTR701D', 'Langues et SHEJS 3'),
+ ('JTR701E', 'Langues et SHEJS 3'),
+ ('JTR701F', 'Langues et SHEJS 3')
+) AS mapping(m, ue_nom)
+WHERE u.nom = mapping.ue_nom
+ON CONFLICT DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 9. Enseignements
+-- ------------------------------------------------------------
+INSERT INTO enseignements ("idProf", "idModule", "idPromo") VALUES
+ ('prof.jin701b', 'JIN701B', '4AFISE'),
+ ('prof.jin701c', 'JIN701C', '4AFISE'),
+ ('prof.jin710a', 'JIN710A', '4AFISE'),
+ ('prof.jin702a', 'JIN702A', '4AFISE'),
+ ('prof.jin702b', 'JIN702B', '4AFISE'),
+ ('prof.jin702c', 'JIN702C', '4AFISE'),
+ ('prof.jin703a', 'JIN703A', '4AFISE'),
+ ('prof.jin703b', 'JIN703B', '4AFISE'),
+ ('prof.jin703c', 'JIN703C', '4AFISE'),
+ ('prof.jin712a', 'JIN712A', '4AFISE'),
+ ('prof.jin712b', 'JIN712B', '4AFISE'),
+ ('prof.jin712c', 'JIN712C', '4AFISE'),
+ ('prof.jtr701a', 'JTR701A', '4AFISE'),
+ ('prof.jtr701d', 'JTR701D', '4AFISE'),
+ ('prof.jtr701e', 'JTR701E', '4AFISE'),
+ ('prof.jtr701f', 'JTR701F', '4AFISE')
+ON CONFLICT DO NOTHING;
+
+-- ------------------------------------------------------------
+-- 10. Notes (ABI / #VALEUR! entries are skipped)
+-- ------------------------------------------------------------
+INSERT INTO notes ("numEtud", "idModule", note) VALUES
+ -- 24029625 MARTIN Sophie
+ (24029625,'JIN701B',14.00),(24029625,'JIN701C',13.50),(24029625,'JIN710A',15.00),
+ (24029625,'JIN702A',15.50),(24029625,'JIN702B',17.00),(24029625,'JIN702C',13.00),
+ (24029625,'JIN703A',15.00),(24029625,'JIN703B',14.00),(24029625,'JIN703C',8.44),
+ (24029625,'JIN712A',15.50),(24029625,'JIN712B',13.80),(24029625,'JIN712C',13.10),
+ (24029625,'JTR701A',16.10),(24029625,'JTR701D',11.00),(24029625,'JTR701E',14.21),(24029625,'JTR701F',15.48),
+ -- 22005810 DUPONT Lucas
+ (22005810,'JIN701B',10.50),(22005810,'JIN701C',14.00),(22005810,'JIN710A',14.00),
+ (22005810,'JIN702A',20.00),(22005810,'JIN702B',16.00),(22005810,'JIN702C',16.00),
+ (22005810,'JIN703A',15.00),(22005810,'JIN703B',13.00),(22005810,'JIN703C',7.50),
+ (22005810,'JIN712A',10.85),(22005810,'JIN712B',11.50),(22005810,'JIN712C',10.80),
+ (22005810,'JTR701A',12.10),(22005810,'JTR701D',10.00),(22005810,'JTR701E',11.85),(22005810,'JTR701F',12.47),
+ -- 24026283 BERNARD Emma
+ (24026283,'JIN701B',11.50),(24026283,'JIN701C',16.50),(24026283,'JIN710A',13.00),
+ (24026283,'JIN702A',17.00),(24026283,'JIN702B',15.00),(24026283,'JIN702C',14.00),
+ (24026283,'JIN703A',14.00),(24026283,'JIN703B',12.00),(24026283,'JIN703C',11.25),
+ (24026283,'JIN712A',13.25),(24026283,'JIN712B',13.00),(24026283,'JIN712C',15.70),
+ (24026283,'JTR701A',16.10),(24026283,'JTR701D',14.00),(24026283,'JTR701E',15.50),(24026283,'JTR701F',13.91),
+ -- 24024101 THOMAS Hugo
+ (24024101,'JIN701B',10.50),(24024101,'JIN701C',13.50),(24024101,'JIN710A',12.00),
+ (24024101,'JIN702A',13.00),(24024101,'JIN702B',11.00),(24024101,'JIN702C',14.00),
+ (24024101,'JIN703A',17.00),(24024101,'JIN703B',12.00),(24024101,'JIN703C',11.88),
+ (24024101,'JIN712A',6.50),(24024101,'JIN712B',18.30),(24024101,'JIN712C',13.90),
+ (24024101,'JTR701A',17.50),(24024101,'JTR701D',17.50),(24024101,'JTR701E',16.09),(24024101,'JTR701F',15.04),
+ -- 24021136 PETIT Léa
+ (24021136,'JIN701B',15.00),(24021136,'JIN701C',15.00),(24021136,'JIN710A',12.00),
+ (24021136,'JIN702A',16.50),(24021136,'JIN702B',17.00),(24021136,'JIN702C',10.00),
+ (24021136,'JIN703A',14.00),(24021136,'JIN703B',13.00),(24021136,'JIN703C',9.38),
+ (24021136,'JIN712A',8.50),(24021136,'JIN712B',13.90),(24021136,'JIN712C',15.20),
+ (24021136,'JTR701A',18.20),(24021136,'JTR701D',15.00),(24021136,'JTR701E',12.83),(24021136,'JTR701F',14.06),
+ -- 24027947 ROBERT Nathan
+ (24027947,'JIN701B',7.50),(24027947,'JIN701C',15.00),(24027947,'JIN710A',13.50),
+ (24027947,'JIN702A',20.00),(24027947,'JIN702B',17.00),(24027947,'JIN702C',14.00),
+ (24027947,'JIN703A',13.00),(24027947,'JIN703B',10.00),(24027947,'JIN703C',8.75),
+ (24027947,'JIN712A',7.50),(24027947,'JIN712B',13.90),(24027947,'JIN712C',10.00),
+ (24027947,'JTR701A',17.30),(24027947,'JTR701D',16.00),(24027947,'JTR701E',14.71),(24027947,'JTR701F',11.61),
+ -- 22001491 RICHARD Alice
+ (22001491,'JIN701B',17.50),(22001491,'JIN701C',13.50),(22001491,'JIN710A',15.00),
+ (22001491,'JIN702A',20.00),(22001491,'JIN702B',15.00),(22001491,'JIN702C',14.00),
+ (22001491,'JIN703A',15.00),(22001491,'JIN703B',15.00),(22001491,'JIN703C',15.94),
+ (22001491,'JIN712A',5.50),(22001491,'JIN712B',18.10),(22001491,'JIN712C',15.75),
+ (22001491,'JTR701A',17.70),(22001491,'JTR701D',11.50),(22001491,'JTR701E',14.35),(22001491,'JTR701F',15.61),
+ -- 22023423 SIMON Théo
+ (22023423,'JIN701B',13.00),(22023423,'JIN701C',16.00),(22023423,'JIN710A',13.00),
+ (22023423,'JIN702A',20.00),(22023423,'JIN702B',18.00),(22023423,'JIN702C',14.50),
+ (22023423,'JIN703A',13.00),(22023423,'JIN703B',11.00),(22023423,'JIN703C',14.69),
+ (22023423,'JIN712A',7.00),(22023423,'JIN712B',13.70),(22023423,'JIN712C',14.95),
+ (22023423,'JTR701A',18.10),(22023423,'JTR701D',18.00),(22023423,'JTR701E',14.82),(22023423,'JTR701F',14.36),
+ -- 21217292 LAURENT Camille
+ (21217292,'JIN701B',16.00),(21217292,'JIN701C',13.50),(21217292,'JIN710A',15.00),
+ (21217292,'JIN702A',5.00),(21217292,'JIN702B',8.00),(21217292,'JIN702C',19.00),
+ (21217292,'JIN703A',14.00),(21217292,'JIN703B',14.00),(21217292,'JIN703C',11.88),
+ (21217292,'JIN712A',15.00),(21217292,'JIN712B',16.10),(21217292,'JIN712C',12.95),
+ (21217292,'JTR701A',18.10),(21217292,'JTR701D',14.50),(21217292,'JTR701E',12.57),(21217292,'JTR701F',13.61),
+ -- 24024550 LEFEBVRE Maxime
+ (24024550,'JIN701B',16.00),(24024550,'JIN701C',13.50),(24024550,'JIN710A',13.00),
+ (24024550,'JIN702A',20.00),(24024550,'JIN702B',9.00),(24024550,'JIN702C',15.00),
+ (24024550,'JIN703A',17.00),(24024550,'JIN703B',12.00),(24024550,'JIN703C',10.31),
+ (24024550,'JIN712A',16.50),(24024550,'JIN712B',12.40),(24024550,'JIN712C',16.60),
+ (24024550,'JTR701A',16.80),(24024550,'JTR701D',18.00),(24024550,'JTR701E',14.70),(24024550,'JTR701F',13.41),
+ -- 22019957 MICHEL Inès (JIN703C=ABI skipped)
+ (22019957,'JIN701B',10.50),(22019957,'JIN701C',14.00),(22019957,'JIN710A',12.00),
+ (22019957,'JIN702A',14.00),(22019957,'JIN702B',18.00),(22019957,'JIN702C',11.50),
+ (22019957,'JIN703A',15.00),(22019957,'JIN703B',10.00),
+ (22019957,'JIN712A',4.00),(22019957,'JIN712B',15.90),(22019957,'JIN712C',10.00),
+ (22019957,'JTR701A',15.80),(22019957,'JTR701D',18.00),(22019957,'JTR701E',14.77),(22019957,'JTR701F',14.11),
+ -- 22008222 GARCIA Baptiste
+ (22008222,'JIN701B',16.00),(22008222,'JIN701C',14.00),(22008222,'JIN710A',18.00),
+ (22008222,'JIN702A',18.00),(22008222,'JIN702B',17.00),(22008222,'JIN702C',14.50),
+ (22008222,'JIN703A',15.00),(22008222,'JIN703B',13.00),(22008222,'JIN703C',15.31),
+ (22008222,'JIN712A',15.50),(22008222,'JIN712B',17.00),(22008222,'JIN712C',16.40),
+ (22008222,'JTR701A',17.90),(22008222,'JTR701D',16.00),(22008222,'JTR701E',13.62),(22008222,'JTR701F',13.04),
+ -- 22006557 DAVID Manon
+ (22006557,'JIN701B',13.50),(22006557,'JIN701C',17.50),(22006557,'JIN710A',14.00),
+ (22006557,'JIN702A',20.00),(22006557,'JIN702B',18.00),(22006557,'JIN702C',10.50),
+ (22006557,'JIN703A',15.00),(22006557,'JIN703B',15.00),(22006557,'JIN703C',9.38),
+ (22006557,'JIN712A',17.00),(22006557,'JIN712B',14.40),(22006557,'JIN712C',16.50),
+ (22006557,'JTR701A',13.80),(22006557,'JTR701D',17.00),(22006557,'JTR701E',15.77),(22006557,'JTR701F',14.75),
+ -- 22019337 BERTRAND Julien
+ (22019337,'JIN701B',11.00),(22019337,'JIN701C',14.00),(22019337,'JIN710A',13.50),
+ (22019337,'JIN702A',15.00),(22019337,'JIN702B',17.00),(22019337,'JIN702C',11.50),
+ (22019337,'JIN703A',15.00),(22019337,'JIN703B',13.00),(22019337,'JIN703C',10.00),
+ (22019337,'JIN712A',2.00),(22019337,'JIN712B',12.70),(22019337,'JIN712C',14.05),
+ (22019337,'JTR701A',14.20),(22019337,'JTR701D',10.00),(22019337,'JTR701E',10.84),(22019337,'JTR701F',14.23),
+ -- 22017498 ROUX Chloé
+ (22017498,'JIN701B',8.00),(22017498,'JIN701C',16.00),(22017498,'JIN710A',12.00),
+ (22017498,'JIN702A',20.00),(22017498,'JIN702B',18.00),(22017498,'JIN702C',10.00),
+ (22017498,'JIN703A',15.00),(22017498,'JIN703B',14.00),(22017498,'JIN703C',9.06),
+ (22017498,'JIN712A',16.00),(22017498,'JIN712B',10.60),(22017498,'JIN712C',16.00),
+ (22017498,'JTR701A',15.80),(22017498,'JTR701D',13.00),(22017498,'JTR701E',14.19),(22017498,'JTR701F',13.61),
+ -- 22019070 VINCENT Tom
+ (22019070,'JIN701B',18.00),(22019070,'JIN701C',15.00),(22019070,'JIN710A',13.50),
+ (22019070,'JIN702A',14.00),(22019070,'JIN702B',13.00),(22019070,'JIN702C',17.50),
+ (22019070,'JIN703A',16.00),(22019070,'JIN703B',14.00),(22019070,'JIN703C',16.88),
+ (22019070,'JIN712A',18.50),(22019070,'JIN712B',16.20),(22019070,'JIN712C',12.65),
+ (22019070,'JTR701A',18.80),(22019070,'JTR701D',16.50),(22019070,'JTR701E',11.63),(22019070,'JTR701F',15.11),
+ -- 21213966 FOURNIER Jade (JTR701D=ABI skipped)
+ (21213966,'JIN701B',7.50),(21213966,'JIN701C',14.00),(21213966,'JIN710A',14.00),
+ (21213966,'JIN702A',17.00),(21213966,'JIN702B',17.00),(21213966,'JIN702C',12.50),
+ (21213966,'JIN703A',15.00),(21213966,'JIN703B',13.00),(21213966,'JIN703C',3.75),
+ (21213966,'JIN712A',4.50),(21213966,'JIN712B',12.50),(21213966,'JIN712C',13.75),
+ (21213966,'JTR701A',11.00),(21213966,'JTR701E',15.99),(21213966,'JTR701F',11.61),
+ -- 25027910 MOREL Enzo
+ (25027910,'JIN701B',7.50),(25027910,'JIN701C',15.00),(25027910,'JIN710A',13.00),
+ (25027910,'JIN702A',3.00),(25027910,'JIN702B',4.00),(25027910,'JIN702C',10.50),
+ (25027910,'JIN703A',12.00),(25027910,'JIN703B',12.00),(25027910,'JIN703C',6.25),
+ (25027910,'JIN712A',7.85),(25027910,'JIN712B',10.20),(25027910,'JIN712C',13.00),
+ (25027910,'JTR701A',14.30),(25027910,'JTR701D',12.00),(25027910,'JTR701E',13.36),(25027910,'JTR701F',14.86),
+ -- 24025920 GIRARD Anaïs (JIN712C=ABI, JTR701D=ABI skipped)
+ (24025920,'JIN701B',10.50),(24025920,'JIN701C',12.00),(24025920,'JIN710A',13.00),
+ (24025920,'JIN702A',19.00),(24025920,'JIN702B',19.00),(24025920,'JIN702C',7.50),
+ (24025920,'JIN703A',11.00),(24025920,'JIN703B',10.00),(24025920,'JIN703C',7.19),
+ (24025920,'JIN712A',8.25),(24025920,'JIN712B',10.20),
+ (24025920,'JTR701A',10.60),(24025920,'JTR701E',4.29),(24025920,'JTR701F',8.73),
+ -- 21212006 ANDRÉ Romain
+ (21212006,'JIN701B',12.50),(21212006,'JIN701C',17.50),(21212006,'JIN710A',17.00),
+ (21212006,'JIN702A',12.00),(21212006,'JIN702B',9.00),(21212006,'JIN702C',10.00),
+ (21212006,'JIN703A',15.00),(21212006,'JIN703B',14.00),(21212006,'JIN703C',13.44),
+ (21212006,'JIN712A',16.50),(21212006,'JIN712B',12.00),(21212006,'JIN712C',16.40),
+ (21212006,'JTR701A',18.30),(21212006,'JTR701D',16.00),(21212006,'JTR701E',10.85),(21212006,'JTR701F',13.29),
+ -- 21230594 LEFÈVRE Pauline
+ (21230594,'JIN701B',18.00),(21230594,'JIN701C',16.50),(21230594,'JIN710A',11.00),
+ (21230594,'JIN702A',5.00),(21230594,'JIN702B',13.00),(21230594,'JIN702C',17.50),
+ (21230594,'JIN703A',11.00),(21230594,'JIN703B',12.00),(21230594,'JIN703C',18.44),
+ (21230594,'JIN712A',16.00),(21230594,'JIN712B',15.90),(21230594,'JIN712C',11.60),
+ (21230594,'JTR701A',18.80),(21230594,'JTR701D',16.00),(21230594,'JTR701E',14.61),(21230594,'JTR701F',14.61),
+ -- 22010753 MERCIER Axel
+ (22010753,'JIN701B',9.00),(22010753,'JIN701C',14.00),(22010753,'JIN710A',14.00),
+ (22010753,'JIN702A',17.00),(22010753,'JIN702B',15.00),(22010753,'JIN702C',13.00),
+ (22010753,'JIN703A',13.00),(22010753,'JIN703B',13.00),(22010753,'JIN703C',7.50),
+ (22010753,'JIN712A',5.50),(22010753,'JIN712B',15.00),(22010753,'JIN712C',15.15),
+ (22010753,'JTR701A',13.40),(22010753,'JTR701D',15.50),(22010753,'JTR701E',15.80),(22010753,'JTR701F',13.11),
+ -- 24031005 DUPUIS Clara
+ (24031005,'JIN701B',8.00),(24031005,'JIN701C',15.00),(24031005,'JIN710A',13.00),
+ (24031005,'JIN702A',16.00),(24031005,'JIN702B',19.00),(24031005,'JIN702C',9.50),
+ (24031005,'JIN703A',15.00),(24031005,'JIN703B',13.00),(24031005,'JIN703C',9.06),
+ (24031005,'JIN712A',5.00),(24031005,'JIN712B',10.90),(24031005,'JIN712C',14.35),
+ (24031005,'JTR701A',15.00),(24031005,'JTR701D',12.00),(24031005,'JTR701E',10.78),(24031005,'JTR701F',13.36),
+ -- 24029523 LAMBERT Florian
+ (24029523,'JIN701B',13.00),(24029523,'JIN701C',16.50),(24029523,'JIN710A',12.50),
+ (24029523,'JIN702A',14.00),(24029523,'JIN702B',6.00),(24029523,'JIN702C',10.50),
+ (24029523,'JIN703A',14.00),(24029523,'JIN703B',11.00),(24029523,'JIN703C',14.38),
+ (24029523,'JIN712A',11.50),(24029523,'JIN712B',9.50),(24029523,'JIN712C',15.60),
+ (24029523,'JTR701A',16.30),(24029523,'JTR701D',18.00),(24029523,'JTR701E',10.99),(24029523,'JTR701F',12.23),
+ -- 24025433 BONNET Mathilde
+ (24025433,'JIN701B',9.50),(24025433,'JIN701C',10.00),(24025433,'JIN710A',11.00),
+ (24025433,'JIN702A',8.00),(24025433,'JIN702B',6.00),(24025433,'JIN702C',20.00),
+ (24025433,'JIN703A',2.50),(24025433,'JIN703B',12.00),(24025433,'JIN703C',18.44),
+ (24025433,'JIN712A',13.50),(24025433,'JIN712B',14.20),(24025433,'JIN712C',5.25),
+ (24025433,'JTR701A',16.00),(24025433,'JTR701D',17.50),(24025433,'JTR701E',11.38),(24025433,'JTR701F',13.11),
+ -- 23024748 FRANCOIS Louis
+ (23024748,'JIN701B',11.50),(23024748,'JIN701C',11.00),(23024748,'JIN710A',15.00),
+ (23024748,'JIN702A',18.00),(23024748,'JIN702B',15.00),(23024748,'JIN702C',10.00),
+ (23024748,'JIN703A',15.00),(23024748,'JIN703B',13.00),(23024748,'JIN703C',7.50),
+ (23024748,'JIN712A',4.00),(23024748,'JIN712B',10.90),(23024748,'JIN712C',10.00),
+ (23024748,'JTR701A',14.30),(23024748,'JTR701D',12.00),(23024748,'JTR701E',14.42),(23024748,'JTR701F',12.61),
+ -- 24016406 MARTINEZ Zoé
+ (24016406,'JIN701B',11.50),(24016406,'JIN701C',16.50),(24016406,'JIN710A',12.00),
+ (24016406,'JIN702A',19.00),(24016406,'JIN702B',15.00),(24016406,'JIN702C',7.00),
+ (24016406,'JIN703A',15.00),(24016406,'JIN703B',14.00),(24016406,'JIN703C',11.56),
+ (24016406,'JIN712A',14.00),(24016406,'JIN712B',12.20),(24016406,'JIN712C',16.20),
+ (24016406,'JTR701A',18.50),(24016406,'JTR701D',13.00),(24016406,'JTR701E',15.01),(24016406,'JTR701F',12.81),
+ -- 24028169 LEBLANC Kévin
+ (24028169,'JIN701B',9.00),(24028169,'JIN701C',11.00),(24028169,'JIN710A',17.00),
+ (24028169,'JIN702A',15.50),(24028169,'JIN702B',13.00),(24028169,'JIN702C',14.50),
+ (24028169,'JIN703A',14.00),(24028169,'JIN703B',14.00),(24028169,'JIN703C',9.06),
+ (24028169,'JIN712A',7.00),(24028169,'JIN712B',15.10),(24028169,'JIN712C',13.30),
+ (24028169,'JTR701A',14.80),(24028169,'JTR701D',17.50),(24028169,'JTR701E',10.99),(24028169,'JTR701F',9.23),
+ -- 22017365 GARNIER Julie
+ (22017365,'JIN701B',15.50),(22017365,'JIN701C',17.50),(22017365,'JIN710A',15.00),
+ (22017365,'JIN702A',13.50),(22017365,'JIN702B',17.00),(22017365,'JIN702C',19.00),
+ (22017365,'JIN703A',15.00),(22017365,'JIN703B',14.00),(22017365,'JIN703C',17.50),
+ (22017365,'JIN712A',17.50),(22017365,'JIN712B',14.40),(22017365,'JIN712C',16.70),
+ (22017365,'JTR701A',17.50),(22017365,'JTR701D',15.00),(22017365,'JTR701E',15.35),(22017365,'JTR701F',15.61),
+ -- 23026015 CHEVALIER Antoine
+ (23026015,'JIN701B',9.00),(23026015,'JIN701C',11.00),(23026015,'JIN710A',15.00),
+ (23026015,'JIN702A',20.00),(23026015,'JIN702B',18.00),(23026015,'JIN702C',13.50),
+ (23026015,'JIN703A',14.00),(23026015,'JIN703B',12.00),(23026015,'JIN703C',11.56),
+ (23026015,'JIN712A',7.00),(23026015,'JIN712B',16.50),(23026015,'JIN712C',11.40),
+ (23026015,'JTR701A',12.30),(23026015,'JTR701D',11.00),(23026015,'JTR701E',10.67),(23026015,'JTR701F',12.40)
+ON CONFLICT DO NOTHING;
diff --git a/defaults/ImportResultPopup.tsx b/defaults/ImportResultPopup.tsx
new file mode 100644
index 0000000..075db00
--- /dev/null
+++ b/defaults/ImportResultPopup.tsx
@@ -0,0 +1,102 @@
+import { useState } from "preact/hooks";
+
+export type ImportResult = {
+ added: number;
+ modified: number;
+ ignored: number;
+ errors: number;
+ details: ImportDetail[];
+};
+
+export type ImportDetail = {
+ type: "change" | "error";
+ message: string;
+};
+
+type Props = {
+ result: ImportResult;
+ onClose: () => void;
+};
+
+export default function ImportResultPopup({ result, onClose }: Props) {
+ const [showDetails, setShowDetails] = useState(false);
+ const hasErrors = result.errors > 0;
+ const changes = result.details.filter((d) => d.type === "change");
+ const errors = result.details.filter((d) => d.type === "error");
+
+ return (
+
+ );
+}
diff --git a/fresh.gen.ts b/fresh.gen.ts
index ffa7923..bd47e97 100644
--- a/fresh.gen.ts
+++ b/fresh.gen.ts
@@ -12,15 +12,22 @@ import * as $_apps_admin_api_modules_idModule_ from "./routes/(apps)/admin/api/m
import * as $_apps_admin_api_permissions from "./routes/(apps)/admin/api/permissions.ts";
import * as $_apps_admin_api_roles from "./routes/(apps)/admin/api/roles.ts";
import * as $_apps_admin_api_roles_idRole_ from "./routes/(apps)/admin/api/roles/[idRole].ts";
+import * as $_apps_admin_api_ue_modules from "./routes/(apps)/admin/api/ue-modules.ts";
+import * as $_apps_admin_api_ue_modules_idModule_idUE_idPromo_ from "./routes/(apps)/admin/api/ue-modules/[idModule]/[idUE]/[idPromo].ts";
+import * as $_apps_admin_api_ues from "./routes/(apps)/admin/api/ues.ts";
+import * as $_apps_admin_api_ues_idUE_ from "./routes/(apps)/admin/api/ues/[idUE].ts";
import * as $_apps_admin_api_users from "./routes/(apps)/admin/api/users.ts";
import * as $_apps_admin_api_users_id_ from "./routes/(apps)/admin/api/users/[id].ts";
import * as $_apps_admin_index from "./routes/(apps)/admin/index.tsx";
import * as $_apps_admin_modules_idModule_ from "./routes/(apps)/admin/modules/[idModule].tsx";
import * as $_apps_admin_partials_enseignements from "./routes/(apps)/admin/partials/enseignements.tsx";
+import * as $_apps_admin_partials_import_maquette from "./routes/(apps)/admin/partials/import-maquette.tsx";
import * as $_apps_admin_partials_index from "./routes/(apps)/admin/partials/index.tsx";
import * as $_apps_admin_partials_modules from "./routes/(apps)/admin/partials/modules.tsx";
import * as $_apps_admin_partials_permissions from "./routes/(apps)/admin/partials/permissions.tsx";
+import * as $_apps_admin_partials_promotions from "./routes/(apps)/admin/partials/promotions.tsx";
import * as $_apps_admin_partials_roles from "./routes/(apps)/admin/partials/roles.tsx";
+import * as $_apps_admin_partials_ues from "./routes/(apps)/admin/partials/ues.tsx";
import * as $_apps_admin_partials_users from "./routes/(apps)/admin/partials/users.tsx";
import * as $_apps_admin_users_id_ from "./routes/(apps)/admin/users/[id].tsx";
import * as $_apps_mobility_api_insert_mobility from "./routes/(apps)/mobility/api/insert_mobility.ts";
@@ -33,15 +40,10 @@ import * as $_apps_notes_api_ajustements_numEtud_idUE_ from "./routes/(apps)/not
import * as $_apps_notes_api_notes from "./routes/(apps)/notes/api/notes.ts";
import * as $_apps_notes_api_notes_numEtud_idModule_ from "./routes/(apps)/notes/api/notes/[numEtud]/[idModule].ts";
import * as $_apps_notes_api_notes_import_xlsx from "./routes/(apps)/notes/api/notes/import-xlsx.ts";
-import * as $_apps_notes_api_ue_modules from "./routes/(apps)/notes/api/ue-modules.ts";
-import * as $_apps_notes_api_ue_modules_idModule_idUE_idPromo_ from "./routes/(apps)/notes/api/ue-modules/[idModule]/[idUE]/[idPromo].ts";
-import * as $_apps_notes_api_ues from "./routes/(apps)/notes/api/ues.ts";
-import * as $_apps_notes_api_ues_idUE_ from "./routes/(apps)/notes/api/ues/[idUE].ts";
import * as $_apps_notes_edition_numEtud_ from "./routes/(apps)/notes/edition/[numEtud].tsx";
import * as $_apps_notes_index from "./routes/(apps)/notes/index.tsx";
import * as $_apps_notes_partials_admin_courses from "./routes/(apps)/notes/partials/(admin)/courses.tsx";
import * as $_apps_notes_partials_admin_import from "./routes/(apps)/notes/partials/(admin)/import.tsx";
-import * as $_apps_notes_partials_admin_ues from "./routes/(apps)/notes/partials/(admin)/ues.tsx";
import * as $_apps_notes_partials_index from "./routes/(apps)/notes/partials/index.tsx";
import * as $_apps_notes_partials_notes from "./routes/(apps)/notes/partials/notes.tsx";
import * as $_apps_notes_recap_numEtud_ from "./routes/(apps)/notes/recap/[numEtud].tsx";
@@ -53,7 +55,6 @@ import * as $_apps_students_api_students_import_csv from "./routes/(apps)/studen
import * as $_apps_students_edit_numEtud_ from "./routes/(apps)/students/edit/[numEtud].tsx";
import * as $_apps_students_index from "./routes/(apps)/students/index.tsx";
import * as $_apps_students_partials_admin_consult from "./routes/(apps)/students/partials/(admin)/consult.tsx";
-import * as $_apps_students_partials_admin_promotions from "./routes/(apps)/students/partials/(admin)/promotions.tsx";
import * as $_apps_students_partials_admin_upload from "./routes/(apps)/students/partials/(admin)/upload.tsx";
import * as $_apps_students_partials_index from "./routes/(apps)/students/partials/index.tsx";
import * as $_apps_students_types_d from "./routes/(apps)/students/types.d.ts";
@@ -71,19 +72,20 @@ import * as $_islands_Navbar from "./routes/(_islands)/Navbar.tsx";
import * as $_apps_admin_islands_AdminEnseignements from "./routes/(apps)/admin/(_islands)/AdminEnseignements.tsx";
import * as $_apps_admin_islands_AdminModules from "./routes/(apps)/admin/(_islands)/AdminModules.tsx";
import * as $_apps_admin_islands_AdminPermissions from "./routes/(apps)/admin/(_islands)/AdminPermissions.tsx";
+import * as $_apps_admin_islands_AdminPromotions from "./routes/(apps)/admin/(_islands)/AdminPromotions.tsx";
import * as $_apps_admin_islands_AdminRoles from "./routes/(apps)/admin/(_islands)/AdminRoles.tsx";
+import * as $_apps_admin_islands_AdminUEs from "./routes/(apps)/admin/(_islands)/AdminUEs.tsx";
import * as $_apps_admin_islands_AdminUsers from "./routes/(apps)/admin/(_islands)/AdminUsers.tsx";
import * as $_apps_admin_islands_EditModule from "./routes/(apps)/admin/(_islands)/EditModule.tsx";
import * as $_apps_admin_islands_EditUser from "./routes/(apps)/admin/(_islands)/EditUser.tsx";
+import * as $_apps_admin_islands_ImportMaquette from "./routes/(apps)/admin/(_islands)/ImportMaquette.tsx";
import * as $_apps_mobility_islands_ConsultMobility from "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx";
import * as $_apps_mobility_islands_EditMobility from "./routes/(apps)/mobility/(_islands)/EditMobility.tsx";
import * as $_apps_mobility_islands_ImportFile from "./routes/(apps)/mobility/(_islands)/ImportFile.tsx";
import * as $_apps_notes_islands_AdminConsultNotes from "./routes/(apps)/notes/(_islands)/AdminConsultNotes.tsx";
-import * as $_apps_notes_islands_AdminUEs from "./routes/(apps)/notes/(_islands)/AdminUEs.tsx";
import * as $_apps_notes_islands_ImportNotes from "./routes/(apps)/notes/(_islands)/ImportNotes.tsx";
import * as $_apps_notes_islands_NoteRecap from "./routes/(apps)/notes/(_islands)/NoteRecap.tsx";
import * as $_apps_notes_islands_NotesView from "./routes/(apps)/notes/(_islands)/NotesView.tsx";
-import * as $_apps_students_islands_AdminPromotions from "./routes/(apps)/students/(_islands)/AdminPromotions.tsx";
import * as $_apps_students_islands_ConsultStudents from "./routes/(apps)/students/(_islands)/ConsultStudents.tsx";
import * as $_apps_students_islands_EditStudents from "./routes/(apps)/students/(_islands)/EditStudents.tsx";
import * as $_apps_students_islands_UploadStudents from "./routes/(apps)/students/(_islands)/UploadStudents.tsx";
@@ -105,6 +107,11 @@ const manifest = {
"./routes/(apps)/admin/api/roles.ts": $_apps_admin_api_roles,
"./routes/(apps)/admin/api/roles/[idRole].ts":
$_apps_admin_api_roles_idRole_,
+ "./routes/(apps)/admin/api/ue-modules.ts": $_apps_admin_api_ue_modules,
+ "./routes/(apps)/admin/api/ue-modules/[idModule]/[idUE]/[idPromo].ts":
+ $_apps_admin_api_ue_modules_idModule_idUE_idPromo_,
+ "./routes/(apps)/admin/api/ues.ts": $_apps_admin_api_ues,
+ "./routes/(apps)/admin/api/ues/[idUE].ts": $_apps_admin_api_ues_idUE_,
"./routes/(apps)/admin/api/users.ts": $_apps_admin_api_users,
"./routes/(apps)/admin/api/users/[id].ts": $_apps_admin_api_users_id_,
"./routes/(apps)/admin/index.tsx": $_apps_admin_index,
@@ -112,11 +119,16 @@ const manifest = {
$_apps_admin_modules_idModule_,
"./routes/(apps)/admin/partials/enseignements.tsx":
$_apps_admin_partials_enseignements,
+ "./routes/(apps)/admin/partials/import-maquette.tsx":
+ $_apps_admin_partials_import_maquette,
"./routes/(apps)/admin/partials/index.tsx": $_apps_admin_partials_index,
"./routes/(apps)/admin/partials/modules.tsx": $_apps_admin_partials_modules,
"./routes/(apps)/admin/partials/permissions.tsx":
$_apps_admin_partials_permissions,
+ "./routes/(apps)/admin/partials/promotions.tsx":
+ $_apps_admin_partials_promotions,
"./routes/(apps)/admin/partials/roles.tsx": $_apps_admin_partials_roles,
+ "./routes/(apps)/admin/partials/ues.tsx": $_apps_admin_partials_ues,
"./routes/(apps)/admin/partials/users.tsx": $_apps_admin_partials_users,
"./routes/(apps)/admin/users/[id].tsx": $_apps_admin_users_id_,
"./routes/(apps)/mobility/api/insert_mobility.ts":
@@ -136,11 +148,6 @@ const manifest = {
$_apps_notes_api_notes_numEtud_idModule_,
"./routes/(apps)/notes/api/notes/import-xlsx.ts":
$_apps_notes_api_notes_import_xlsx,
- "./routes/(apps)/notes/api/ue-modules.ts": $_apps_notes_api_ue_modules,
- "./routes/(apps)/notes/api/ue-modules/[idModule]/[idUE]/[idPromo].ts":
- $_apps_notes_api_ue_modules_idModule_idUE_idPromo_,
- "./routes/(apps)/notes/api/ues.ts": $_apps_notes_api_ues,
- "./routes/(apps)/notes/api/ues/[idUE].ts": $_apps_notes_api_ues_idUE_,
"./routes/(apps)/notes/edition/[numEtud].tsx":
$_apps_notes_edition_numEtud_,
"./routes/(apps)/notes/index.tsx": $_apps_notes_index,
@@ -148,8 +155,6 @@ const manifest = {
$_apps_notes_partials_admin_courses,
"./routes/(apps)/notes/partials/(admin)/import.tsx":
$_apps_notes_partials_admin_import,
- "./routes/(apps)/notes/partials/(admin)/ues.tsx":
- $_apps_notes_partials_admin_ues,
"./routes/(apps)/notes/partials/index.tsx": $_apps_notes_partials_index,
"./routes/(apps)/notes/partials/notes.tsx": $_apps_notes_partials_notes,
"./routes/(apps)/notes/recap/[numEtud].tsx": $_apps_notes_recap_numEtud_,
@@ -167,8 +172,6 @@ const manifest = {
"./routes/(apps)/students/index.tsx": $_apps_students_index,
"./routes/(apps)/students/partials/(admin)/consult.tsx":
$_apps_students_partials_admin_consult,
- "./routes/(apps)/students/partials/(admin)/promotions.tsx":
- $_apps_students_partials_admin_promotions,
"./routes/(apps)/students/partials/(admin)/upload.tsx":
$_apps_students_partials_admin_upload,
"./routes/(apps)/students/partials/index.tsx":
@@ -193,14 +196,20 @@ const manifest = {
$_apps_admin_islands_AdminModules,
"./routes/(apps)/admin/(_islands)/AdminPermissions.tsx":
$_apps_admin_islands_AdminPermissions,
+ "./routes/(apps)/admin/(_islands)/AdminPromotions.tsx":
+ $_apps_admin_islands_AdminPromotions,
"./routes/(apps)/admin/(_islands)/AdminRoles.tsx":
$_apps_admin_islands_AdminRoles,
+ "./routes/(apps)/admin/(_islands)/AdminUEs.tsx":
+ $_apps_admin_islands_AdminUEs,
"./routes/(apps)/admin/(_islands)/AdminUsers.tsx":
$_apps_admin_islands_AdminUsers,
"./routes/(apps)/admin/(_islands)/EditModule.tsx":
$_apps_admin_islands_EditModule,
"./routes/(apps)/admin/(_islands)/EditUser.tsx":
$_apps_admin_islands_EditUser,
+ "./routes/(apps)/admin/(_islands)/ImportMaquette.tsx":
+ $_apps_admin_islands_ImportMaquette,
"./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx":
$_apps_mobility_islands_ConsultMobility,
"./routes/(apps)/mobility/(_islands)/EditMobility.tsx":
@@ -209,16 +218,12 @@ const manifest = {
$_apps_mobility_islands_ImportFile,
"./routes/(apps)/notes/(_islands)/AdminConsultNotes.tsx":
$_apps_notes_islands_AdminConsultNotes,
- "./routes/(apps)/notes/(_islands)/AdminUEs.tsx":
- $_apps_notes_islands_AdminUEs,
"./routes/(apps)/notes/(_islands)/ImportNotes.tsx":
$_apps_notes_islands_ImportNotes,
"./routes/(apps)/notes/(_islands)/NoteRecap.tsx":
$_apps_notes_islands_NoteRecap,
"./routes/(apps)/notes/(_islands)/NotesView.tsx":
$_apps_notes_islands_NotesView,
- "./routes/(apps)/students/(_islands)/AdminPromotions.tsx":
- $_apps_students_islands_AdminPromotions,
"./routes/(apps)/students/(_islands)/ConsultStudents.tsx":
$_apps_students_islands_ConsultStudents,
"./routes/(apps)/students/(_islands)/EditStudents.tsx":
diff --git a/routes/(apps)/_middleware.ts b/routes/(apps)/_middleware.ts
index e60886b..ece0de4 100644
--- a/routes/(apps)/_middleware.ts
+++ b/routes/(apps)/_middleware.ts
@@ -21,16 +21,20 @@ export const handler: MiddlewareHandler[] = [
`./${currentApp}/(_props)/props.ts`
)).default;
- context.state.availablePages = properties.pages;
+ context.state.availablePages = { ...properties.pages };
const isStudent =
- context.state.session.eduPersonPrimaryAffiliation == "student" &&
- Deno.env.get("LOCAL") != "true";
+ context.state.session.eduPersonPrimaryAffiliation === "student";
+ const isLocal = Deno.env.get("LOCAL") === "true";
if (isStudent) {
+ // Students only see studentOnly pages (+ non-restricted pages)
properties.adminOnly.forEach((page) =>
delete context.state.availablePages[page]
);
+ } else if (isLocal) {
+ // In local mode, employees see all pages (admin + student)
} else {
+ // In prod, employees don't see studentOnly pages
properties.studentOnly?.forEach((page) =>
delete context.state.availablePages[page]
);
diff --git a/routes/(apps)/students/(_islands)/AdminPromotions.tsx b/routes/(apps)/admin/(_islands)/AdminPromotions.tsx
similarity index 92%
rename from routes/(apps)/students/(_islands)/AdminPromotions.tsx
rename to routes/(apps)/admin/(_islands)/AdminPromotions.tsx
index 7f32f91..68c71c6 100644
--- a/routes/(apps)/students/(_islands)/AdminPromotions.tsx
+++ b/routes/(apps)/admin/(_islands)/AdminPromotions.tsx
@@ -74,13 +74,26 @@ export default function AdminPromotions() {
}
async function deletePromo(id: string) {
- if (!confirm(`Supprimer la promotion ${id} ?`)) return;
+ if (studentCount(id) > 0) {
+ setError(
+ `Impossible de supprimer ${id} : des étudiants y sont encore assignés. Réassignez-les d'abord.`,
+ );
+ return;
+ }
+ if (
+ !confirm(`Supprimer la promotion ${id} et toutes ses données liées ?`)
+ ) {
+ return;
+ }
try {
const res = await fetch(
`/students/api/promotions/${encodeURIComponent(id)}`,
{ method: "DELETE" },
);
- if (!res.ok) throw new Error("Suppression échouée");
+ if (!res.ok) {
+ const body = await res.json().catch(() => ({}));
+ throw new Error(body.error ?? "Suppression échouée");
+ }
await load();
} catch (e) {
setError(e instanceof Error ? e.message : "Erreur");
@@ -218,6 +231,10 @@ export default function AdminPromotions() {