diff --git a/cypress.config.js b/cypress.config.js index d6718c8d7..c1ea3b933 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -33,10 +33,13 @@ module.exports = defineConfig({ // the suite can switch the instance to a configuration profile for the run on("before:run", () => suite.beforeRun(config)); - // the profile goes back first; otherwise the SSH forward outlives Cypress + // the profile goes back first; the pool and the SSH forward close even if that fails on("after:run", async () => { - await suite.afterRun(config); - await require("./tests/cypress/tasks/sshTunnel").closeTunnel(); + try { + await suite.afterRun(config); + } finally { + await require("./tests/cypress/tasks/db").closeDb(); + } }); return config; diff --git a/package.json b/package.json index a4496d1cd..938dc37e0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,9 @@ { "scripts": { + "lint": "eslint tests/cypress cypress.config.js eslint.config.js", + "lint:fix": "eslint tests/cypress cypress.config.js eslint.config.js --fix", + "format": "prettier --write \"tests/cypress/**/*.{js,md}\"", + "format:check": "prettier --check \"tests/cypress/**/*.{js,md}\"", "cy:open": "cypress open", "cy:run": "cypress run", "cy:noten": "cypress run --spec \"tests/cypress/e2e/specs/**/*.cy.js\"", @@ -18,5 +22,13 @@ "dotenv": "^17.4.2", "pg": "^8.13.1", "ssh2": "^1.17.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "eslint": "^10.10.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-cypress": "^7.0.2", + "globals": "^17.12.0", + "prettier": "^3.9.7" } } diff --git a/public/js/components/Cis/Benotungstool/notenRules.js b/public/js/components/Cis/Benotungstool/notenRules.js index 49c717a54..ac1e7c8c1 100644 --- a/public/js/components/Cis/Benotungstool/notenRules.js +++ b/public/js/components/Cis/Benotungstool/notenRules.js @@ -8,8 +8,26 @@ * The local fallback applies only while the client has no `verlauf` for a row. */ -/** The maximum number of attempts that count in this tool. The server derives this value. */ -export const maxAntrittCount = (config) => config?.CIS_GESAMTNOTE_MAX_ANTRITTE ?? 1; +/** + * Is the value set? Never test a grade or a count for truthy: the grade key 0 ("Teilnote") is a + * grade and a configured 0 is a number, but both are falsy. The server rewrites an empty grade + * with `if($note=='')`, which catches a 0 under PHP 7 but not under PHP 8, so a 0 does reach us. + */ +const isSet = (value) => value !== null && value !== undefined && value !== ""; + +/** + * The maximum number of attempts that count in this tool. The server derives the value and sends + * an integer. The conversion keeps it a number if it ever arrives as a string, because the callers + * compare it (`<`) and the tests compare it strictly. A configured 0 stays 0 and blocks every + * attempt; only a missing or unusable value falls back to 1. + */ +export const maxAntrittCount = (config) => { + const configured = config?.CIS_GESAMTNOTE_MAX_ANTRITTE; + if (!isSet(configured)) return 1; + + const count = Number(configured); + return Number.isFinite(count) ? count : 1; +}; /** * The attempts that count. The NOTE decides, not the exam type: the grades in NOTEN_OHNE_ANTRITT @@ -25,7 +43,7 @@ export const antrittCountStudent = (student, config, notenOptions) => { if (!ohneAntritt.find((pk) => pk == p.note)) count++; } - if (count === 0 && student.note && !ohneAntritt.find((pk) => pk == student.note)) { + if (count === 0 && isSet(student.note) && !ohneAntritt.find((pk) => pk == student.note)) { const noteOption = notenOptions?.find((n) => n.note == student.note); return noteOption?.lehre ? 1 : 0; } @@ -45,7 +63,8 @@ export const canAddPruefung = (student, config) => { * not from `lv_note`, because `lv_note` contains RELEASED grades only. An entered grade that is * not released still exists. The user interface uses this for a hint only. */ -export const brauchtNeueLvNote = (student) => student.verlauf ? !student.verlauf.hatLvNote : !student.lv_note; +export const brauchtNeueLvNote = (student) => + student.verlauf ? !student.verlauf.hatLvNote : !isSet(student.lv_note); /** * The grade state from the two timestamps: offen = no grade entered (an empty row), changed = a diff --git a/system/seeders/000_fixmissing.sql b/system/seeders/000_fixmissing.sql deleted file mode 100644 index 31becbf65..000000000 --- a/system/seeders/000_fixmissing.sql +++ /dev/null @@ -1,28 +0,0 @@ -UPDATE public.tbl_funktion SET funktion_kurzbz='Student' WHERE funktion_kurzbz='stud'; - -UPDATE public.tbl_benutzer SET uid='demoadmin' WHERE uid='admin'; - --- Add Missing functions -INSERT INTO public.tbl_funktion (funktion_kurzbz, beschreibung, aktiv, fachbereich, semester, hrrelevant, vertragsrelevant) VALUES('hsv', 'Hochschulvertretung', true, false, false, false, false); -INSERT INTO public.tbl_funktion (funktion_kurzbz, beschreibung, aktiv, fachbereich, semester, hrrelevant, vertragsrelevant) VALUES('jgv', 'Jahrgangsvertretung', true, false, true, false, false); -INSERT INTO public.tbl_funktion (funktion_kurzbz, beschreibung, aktiv, fachbereich, semester, hrrelevant, vertragsrelevant) VALUES('oezuordnung', 'Diszpl-Zuordnung', true, false, false, true, true); -INSERT INTO public.tbl_funktion (funktion_kurzbz, beschreibung, aktiv, fachbereich, semester, hrrelevant, vertragsrelevant) VALUES('fachzuordnung', 'Fachliche Zuordnung', true, false, false, true, true); - --- Add Permissions to Admin Role -INSERT INTO "system".tbl_rolleberechtigung (berechtigung_kurzbz, rolle_kurzbz, art, anmerkung, insertamum, insertvon) VALUES('basis/cis', 'admin', 'suid', 'Zugriff auf CIS', now(), 'demoadmin'); - -INSERT INTO "system".tbl_benutzerrolle (rolle_kurzbz, berechtigung_kurzbz, uid, funktion_kurzbz, oe_kurzbz, art, studiensemester_kurzbz, "start", ende, negativ, updateamum, updatevon, insertamum, insertvon, kostenstelle_id, anmerkung) VALUES -(NULL, 'dashboard/benutzer', NULL, 'Mitarbeiter', NULL, 'suid', NULL, NULL, NULL, false, NULL, NULL, now(), 'demoadmin', NULL, NULL), -(NULL, 'dashboard/benutzer', NULL, 'Student', NULL, 'suid', NULL, NULL, NULL, false, NULL, NULL, now(), 'demoadmin', NULL, NULL) -; - -INSERT INTO "system".tbl_webservicetyp (webservicetyp_kurzbz, beschreibung) VALUES('content', 'CIS-Content ID'); - -SELECT setval('campus.seq_contentsprache', (select max(contentsprache_id) from campus.tbl_contentsprache), true); -SELECT setval('campus.seq_contentchild', (select max(contentchild_id) from campus.tbl_contentchild), true); - - -INSERT INTO public.tbl_gruppe (gruppe_kurzbz, studiengang_kz, semester, bezeichnung, beschreibung, sichtbar, lehre, aktiv, sort, mailgrp, generiert, updateamum, updatevon, insertamum, insertvon, ext_id, orgform_kurzbz, content_visible, gesperrt, direktinskription, zutrittssystem, aufnahmegruppe) VALUES -('MA', 0, NULL, 'MA', 'MA', false, false, true, NULL, false, false, now(), 'demoadmin', now(), 'demoadmin', NULL, NULL, true, false, false, false, false), -('STUD', 0, NULL, 'STUD', 'STUD', false, false, true, NULL, false, false, now(), 'demoadmin', now(), 'demoadmin', NULL, NULL, true, false, false, false, false) -; diff --git a/system/seeders/001_helper_functions.sql b/system/seeders/001_helper_functions.sql deleted file mode 100644 index b1ed6d484..000000000 --- a/system/seeders/001_helper_functions.sql +++ /dev/null @@ -1,36 +0,0 @@ -CREATE OR REPLACE FUNCTION NearestWintersemester(var_entfernung integer) RETURNS varchar(32) AS $$ -DECLARE res varchar(32); - BEGIN - WITH nearestws AS - ( - SELECT studiensemester_kurzbz, start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz LIKE 'W%' AND ende>=now() ORDER BY start DESC LIMIT 1 - ) - SELECT studiensemester_kurzbz into res - FROM - ( - SELECT studiensemester_kurzbz, 0 as "entfernung" FROM nearestws - UNION - SELECT studiensemester_kurzbz, rank() over(order by start desc) as "entfernung" FROM public.tbl_studiensemester where start>(SELECT start FROM nearestws) - UNION - SELECT studiensemester_kurzbz, (-1 * rank() over(order by start desc)) as "entfernung" FROM public.tbl_studiensemester WHERE start<(SELECT start FROM nearestws) - ) x where entfernung=var_entfernung; - - return res; - END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION CurrentSemester() RETURNS varchar(32) AS $$ -DECLARE res varchar(32); - BEGIN - SELECT studiensemester_kurzbz into res FROM public.tbl_studiensemester WHERE start<=now() AND ende>=now() ORDER BY start DESC LIMIT 1; - return res; - END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION LastActiveSemester() RETURNS varchar(32) AS $$ -DECLARE res varchar(32); - BEGIN - SELECT studiensemester_kurzbz into res FROM public.tbl_studiensemester WHERE start<=now() ORDER BY start DESC LIMIT 1; - return res; - END; -$$ LANGUAGE plpgsql; diff --git a/system/seeders/002_mitarbeiter.sql b/system/seeders/002_mitarbeiter.sql deleted file mode 100644 index 03ac5cd5f..000000000 --- a/system/seeders/002_mitarbeiter.sql +++ /dev/null @@ -1,40 +0,0 @@ --- Demodaten fuer Mitarbeiter --- Personen -INSERT INTO public.tbl_person (person_id, staatsbuergerschaft,geburtsnation,sprache,anrede,titelpost,titelpre,vorname,nachname,vornamen,gebdatum,gebort,gebzeit,foto,anmerkung,homepage,svnr,ersatzkennzeichen,familienstand,geschlecht,anzahlkinder,aktiv,insertamum,insertvon,updateamum,updatevon,ext_id,bundesland_code,kompetenzen,kurzbeschreibung,zugangscode,foto_sperre,udf_values,bpk,matr_aktiv,matr_nr,zugangscode_timestamp,wahlname,unruly) VALUES -(21,'A','A',NULL,'Herr',NULL,NULL,'Demo','Lektor 1',NULL,'1980-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c21',false,NULL,NULL,false,NULL,NULL,NULL,false), -(22,'A','A',NULL,'Herr',NULL,NULL,'Demo','Lektor 2',NULL,'1980-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c22',false,NULL,NULL,false,NULL,NULL,NULL,false), -(23,'A','A',NULL,'Herr',NULL,NULL,'Demo','Lektor 3',NULL,'1980-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c23',false,NULL,NULL,false,NULL,NULL,NULL,false), -(24,'A','A',NULL,'Herr',NULL,NULL,'Demo','Lektor 4',NULL,'1980-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c24',false,NULL,NULL,false,NULL,NULL,NULL,false), -(25,'A','A',NULL,'Herr',NULL,NULL,'Demo','Lektor 5',NULL,'1980-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c25',false,NULL,NULL,false,NULL,NULL,NULL,false), -(26,'A','A',NULL,'Frau',NULL,NULL,'Demo','Assistenz',NULL,'1985-01-15',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c26',false,NULL,NULL,false,NULL,NULL,NULL,false) -; - - -INSERT INTO public.tbl_benutzer (person_id, uid, aktiv, alias, insertamum, insertvon, updateamum, updatevon, updateaktivam, updateaktivvon, aktivierungscode) VALUES -('21', 'demolektor1' , true, null, now(), 'auto', null, null, null, false, null), -('22', 'demolektor2' , true, null, now(), 'auto', null, null, null, false, null), -('23', 'demolektor3' , true, null, now(), 'auto', null, null, null, false, null), -('24', 'demolektor4' , true, null, now(), 'auto', null, null, null, false, null), -('25', 'demolektor5' , true, null, now(), 'auto', null, null, null, false, null), -('26', 'demoassistenz' , true, null, now(), 'auto', null, null, null, false, null) -; - -INSERT INTO public.tbl_mitarbeiter (mitarbeiter_uid, personalnummer, telefonklappe, kurzbz, lektor, fixangestellt, stundensatz, ausbildungcode, ort_kurzbz, insertamum, insertvon, bismelden) VALUES -('demolektor1', 21, null, 'DemoLKT1', true, true, 80, null, null, now(), 'auto', true), -('demolektor2', 22, null, 'DemoLKT2', true, true, 80, null, null, now(), 'auto', true), -('demolektor3', 23, null, 'DemoLKT3', true, true, 80, null, null, now(), 'auto', true), -('demolektor4', 24, null, 'DemoLKT4', true, true, 80, null, null, now(), 'auto', true), -('demolektor5', 25, null, 'DemoLKT5', true, true, 80, null, null, now(), 'auto', true), -('demoassistenz', 26, null, 'DemoAss', true, true, 80, null, null, now(), 'auto', true) -; - - -INSERT INTO public.tbl_benutzergruppe (uid, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id, studiensemester_kurzbz) VALUES -('demoadmin', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demolektor1', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demolektor2', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demolektor3', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demolektor4', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demolektor5', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), -('demoassistenz', 'MA', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL) -; diff --git a/system/seeders/003_kompetenzfeld.sql b/system/seeders/003_kompetenzfeld.sql deleted file mode 100644 index 1bcd9ed5d..000000000 --- a/system/seeders/003_kompetenzfeld.sql +++ /dev/null @@ -1,27 +0,0 @@ --- Kompetenzfedler -INSERT INTO public.tbl_organisationseinheittyp (organisationseinheittyp_kurzbz, bezeichnung, beschreibung) VALUES('Kompetenzfeld', 'Kompetenzfeld', 'Kompetenzfeld'); - -INSERT INTO public.tbl_organisationseinheit (oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id) VALUES - ('dep', 'etw', 'Fachabteilung', 'Abteilung', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL), - ('kfSprachen', 'dep', 'Sprachen', 'Kompetenzfeld', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL), - ('kfMath', 'dep', 'Mathematik', 'Kompetenzfeld', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL), - ('kfTech', 'dep', 'Technik', 'Kompetenzfeld', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL); - - INSERT INTO public.tbl_organisationseinheit -(oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id, fts_bezeichnung) -VALUES('Lehrgaenge', 'etw', 'Lehrgänge', 'Abteilung', true, false, NULL, NULL, false, NULL, NULL, NULL, NULL, '''abteilung'':1 ''lehrgänge'':2'::tsvector); -INSERT INTO public.tbl_organisationseinheit -(oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id, fts_bezeichnung) -VALUES('studiengaenge', 'etw', 'Studiengänge', 'Abteilung', true, false, NULL, NULL, false, NULL, NULL, NULL, NULL, '''abteilung'':1 ''studiengänge'':2'::tsvector); - -INSERT INTO public.tbl_studienjahr (studienjahr_kurzbz, bezeichnung) VALUES -('2026/27', 'Studienjahr 2026/27'), -('2027/28', 'Studienjahr 2027/28') -; - -INSERT INTO public.tbl_studiensemester (studiensemester_kurzbz, "start", ende, ext_id, bezeichnung, studienjahr_kurzbz, beschreibung, onlinebewerbung) VALUES -('WS2026', '2026-09-01', '2027-01-31', NULL, 'Wintersemester 2026/27', '2026/27', NULL, false), -('SS2027', '2027-02-01', '2027-07-01', NULL, 'Sommersemester 2027', '2026/27', NULL, false), -('WS2027', '2027-09-01', '2028-01-31', NULL, 'Wintersemester 2027/28', '2027/28', NULL, false), -('SS2028', '2028-02-01', '2028-07-01', NULL, 'Sommersemester 2028', '2027/28', NULL, false) -; diff --git a/system/seeders/004_ort.sql b/system/seeders/004_ort.sql deleted file mode 100644 index 5c811cb09..000000000 --- a/system/seeders/004_ort.sql +++ /dev/null @@ -1,25 +0,0 @@ -INSERT INTO public.tbl_ort -(ort_kurzbz, bezeichnung, planbezeichnung, max_person, lehre, reservieren, aktiv, lageplan, dislozierung, kosten, ausstattung, updateamum, updatevon, insertamum, insertvon, ext_id, stockwerk, telefonklappe, standort_id, content_id, m2, gebteil, oe_kurzbz, arbeitsplaetze) -VALUES('EG03', 'Besprechungsruam EG03', 'EG03', 8, true, true, true, NULL, NULL, NULL, NULL, '2023-08-24 14:18:50.000', 'oesi', '2023-08-24 14:17:30.000', 'oesi', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); -INSERT INTO public.tbl_ort -(ort_kurzbz, bezeichnung, planbezeichnung, max_person, lehre, reservieren, aktiv, lageplan, dislozierung, kosten, ausstattung, updateamum, updatevon, insertamum, insertvon, ext_id, stockwerk, telefonklappe, standort_id, content_id, m2, gebteil, oe_kurzbz, arbeitsplaetze) -VALUES('EG01', 'Seminarraum EG01', 'EG01', 10, true, true, true, NULL, NULL, NULL, NULL, '2023-08-24 14:18:52.000', 'oesi', '2023-08-24 14:16:47.000', 'oesi', NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); -INSERT INTO public.tbl_ort -(ort_kurzbz, bezeichnung, planbezeichnung, max_person, lehre, reservieren, aktiv, lageplan, dislozierung, kosten, ausstattung, updateamum, updatevon, insertamum, insertvon, ext_id, stockwerk, telefonklappe, standort_id, content_id, m2, gebteil, oe_kurzbz, arbeitsplaetze) -VALUES('EG02', 'Seminarraum EG02', 'EG02', 10, true, true, true, NULL, NULL, NULL, NULL, '2023-08-24 14:18:54.000', 'oesi', '2023-08-24 14:16:56.000', 'oesi', NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); -INSERT INTO public.tbl_ort -(ort_kurzbz, bezeichnung, planbezeichnung, max_person, lehre, reservieren, aktiv, lageplan, dislozierung, kosten, ausstattung, updateamum, updatevon, insertamum, insertvon, ext_id, stockwerk, telefonklappe, standort_id, content_id, m2, gebteil, oe_kurzbz, arbeitsplaetze) -VALUES('EG04', 'EDV EG04', 'EG04', 20, true, true, true, NULL, NULL, NULL, NULL, '2023-08-24 14:18:55.000', 'oesi', '2023-08-24 14:17:49.000', 'oesi', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - -INSERT INTO public.tbl_ortraumtyp -(ort_kurzbz, hierarchie, raumtyp_kurzbz) -VALUES('EG01', 1, 'SEM'); -INSERT INTO public.tbl_ortraumtyp -(ort_kurzbz, hierarchie, raumtyp_kurzbz) -VALUES('EG02', 1, 'SEM'); -INSERT INTO public.tbl_ortraumtyp -(ort_kurzbz, hierarchie, raumtyp_kurzbz) -VALUES('EG04', 1, 'EDV2'); -INSERT INTO public.tbl_ortraumtyp -(ort_kurzbz, hierarchie, raumtyp_kurzbz) -VALUES('EG04', 2, 'EDV5/6'); diff --git a/system/seeders/005_studenten_stg_1.sql b/system/seeders/005_studenten_stg_1.sql deleted file mode 100644 index e94249826..000000000 --- a/system/seeders/005_studenten_stg_1.sql +++ /dev/null @@ -1,114 +0,0 @@ --- Demodaten fuer Studierende im Studiengang 1 - -INSERT INTO lehre.tbl_studienordnung -(studienordnung_id, studiengang_kz, "version", gueltigvon, gueltigbis, bezeichnung, ects, studiengangbezeichnung, studiengangbezeichnung_englisch, studiengangkurzbzlang, akadgrad_id, insertamum, insertvon, updateamum, updatevon, ext_id, status_kurzbz, standort_id) -VALUES(1, 1, '1', 'WS2023', NULL, 'BS1-WS2023', 180.00, 'Studiengang 1', 'Studiengang 1', 'STG1', NULL, '2023-08-24 14:25:41.728', 'oesi', NULL, NULL, NULL, 'development', NULL); - -INSERT INTO lehre.tbl_studienplan -(studienplan_id, studienordnung_id, orgform_kurzbz, "version", bezeichnung, regelstudiendauer, sprache, aktiv, semesterwochen, testtool_sprachwahl, insertamum, insertvon, updateamum, updatevon, ext_id, ects_stpl, pflicht_sws, pflicht_lvs, onlinebewerbung_studienplan) -VALUES(1, 1, 'VZ', '1', 'BS1-WS2023-VZ', 6, NULL, true, 15, true, '2023-08-24 14:26:12.751', 'oesi', NULL, NULL, NULL, 120.00, NULL, NULL, true); - -INSERT INTO lehre.tbl_studienplan_semester -( studienplan_id, studiensemester_kurzbz, semester) -VALUES(1, 'WS2025', 1); -INSERT INTO lehre.tbl_studienplan_semester -(studienplan_id, studiensemester_kurzbz, semester) -VALUES(1, 'SS2026', 1); - --- Personen -INSERT INTO public.tbl_person (person_id, staatsbuergerschaft,geburtsnation,sprache,anrede,titelpost,titelpre,vorname,nachname,vornamen,gebdatum,gebort,gebzeit,foto,anmerkung,homepage,svnr,ersatzkennzeichen,familienstand,geschlecht,anzahlkinder,aktiv,insertamum,insertvon,updateamum,updatevon,ext_id,bundesland_code,kompetenzen,kurzbeschreibung,zugangscode,foto_sperre,udf_values,bpk,matr_aktiv,matr_nr,zugangscode_timestamp,wahlname,unruly) VALUES - -(101,'A','A',NULL,'Herr',NULL,NULL,'Leonardo','DiCaprio',NULL,'1974-11-11',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c101',false,NULL,NULL,false,NULL,NULL,NULL,false), -(102,'A','A',NULL,'Herr',NULL,NULL,'Robert','Downey Jr.',NULL,'1965-04-04',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c102',false,NULL,NULL,false,NULL,NULL,NULL,false), -(103,'A','A',NULL,'Herr',NULL,NULL,'Denzel','Washington',NULL,'1954-12-28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c103',false,NULL,NULL,false,NULL,NULL,NULL,false), -(104,'A','A',NULL,'Herr',NULL,NULL,'Al','Pacino',NULL,'1940-04-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c104',false,NULL,NULL,false,NULL,NULL,NULL,false), -(105,'A','A',NULL,'Herr',NULL,NULL,'Morgan','Freeman',NULL,'1937-06-01',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c105',false,NULL,NULL,false,NULL,NULL,NULL,false), -(106,'A','A',NULL,'Herr',NULL,NULL,'Daniel','Day-Lewis',NULL,'1957-04-29',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c106',false,NULL,NULL,false,NULL,NULL,NULL,false), -(107,'A','A',NULL,'Herr',NULL,NULL,'Marlon','Brando',NULL,'1924-04-03',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c107',false,NULL,NULL,false,NULL,NULL,NULL,false), -(108,'A','A',NULL,'Herr',NULL,NULL,'Tom','Hanks',NULL,'1956-07-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c108',false,NULL,NULL,false,NULL,NULL,NULL,false), -(109,'A','A',NULL,'Herr',NULL,NULL,'Johnny','Depp',NULL,'1963-06-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c109',false,NULL,NULL,false,NULL,NULL,NULL,false), -(110,'A','A',NULL,'Herr',NULL,NULL,'Brad','Pitt',NULL,'1963-12-18',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c8110',false,NULL,NULL,false,NULL,NULL,NULL,false), -(111,'A','A',NULL,'Herr',NULL,NULL,'Will','Smith',NULL,'1968-09-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c111',false,NULL,NULL,false,NULL,NULL,NULL,false), -(112,'A','A',NULL,'Herr',NULL,NULL,'Keanu','Reeves',NULL,'1964-09-02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c112',false,NULL,NULL,false,NULL,NULL,NULL,false), -(113,'A','A',NULL,'Herr',NULL,NULL,'Robert','De Niro',NULL,'1943-08-17',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647113',false,NULL,NULL,false,NULL,NULL,NULL,false), -(114,'A','A',NULL,'Herr',NULL,NULL,'Harrison','Ford',NULL,'1942-07-13',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c114',false,NULL,NULL,false,NULL,NULL,NULL,false), -(115,'A','A',NULL,'Herr',NULL,NULL,'Samuel L.','Jackson',NULL,'1948-12-21',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c115',false,NULL,NULL,false,NULL,NULL,NULL,false), -(116,'A','A',NULL,'Herr',NULL,NULL,'Christian','Bale',NULL,'1974-01-30',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c116',false,NULL,NULL,false,NULL,NULL,NULL,false), -(117,'A','A',NULL,'Herr',NULL,NULL,'Tom','Cruise',NULL,'1962-07-03',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c1117',false,NULL,NULL,false,NULL,NULL,NULL,false), -(118,'A','A',NULL,'Herr',NULL,NULL,'Arnold','Schwarzenegger',NULL,'1947-07-30',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c118',false,NULL,NULL,false,NULL,NULL,NULL,false), -(119,'A','A',NULL,'Herr',NULL,NULL,'Sylvester','Stallone',NULL,'1946-07-06',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c119',false,NULL,NULL,false,NULL,NULL,NULL,false), -(120,'A','A',NULL,'Herr',NULL,NULL,'Karl','Klammer',NULL,'1963-06-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c120',false,NULL,NULL,false,NULL,NULL,NULL,false) -; -SELECT setval('public.tbl_person_person_id_seq', 1000,true); - --- Prestudenten -INSERT INTO public.tbl_prestudent (prestudent_id, person_id,studiengang_kz,aufmerksamdurch_kurzbz,berufstaetigkeit_code,ausbildungcode,zgv_code,zgvort,zgvdatum,zgvmas_code,zgvmaort,zgvmadatum,aufnahmeschluessel,facheinschlberuf,reihungstest_id,anmeldungreihungstest,reihungstestangetreten,rt_gesamtpunkte,bismelden,insertamum,insertvon,updateamum,updatevon,ext_id,anmerkung,dual,rt_punkte1,rt_punkte2,ausstellungsstaat,rt_punkte3,udf_values,priorisierung,zgvdoktor_code,zgvdoktorort,zgvdoktordatum,mentor,zgvnation,zgvmanation,zgvdoktornation,gsstudientyp_kurzbz,aufnahmegruppe_kurzbz,foerderrelevant,standort_code,zgv_erfuellt,zgvmas_erfuellt,zgvdoktor_erfuellt) VALUES - (1101,101,1,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1102,102,1,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1103,103,1,'k.A.',NULL,NULL,9,NULL,'2020-06-03',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1104,104,1,'k.A.',NULL,NULL,9,NULL,'2020-06-04',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1105,105,1,'k.A.',NULL,NULL,9,NULL,'2020-06-05',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1106,106,1,'k.A.',NULL,NULL,9,NULL,'2020-06-06',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1107,107,1,'k.A.',NULL,NULL,9,NULL,'2020-06-07',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1108,108,1,'k.A.',NULL,NULL,9,NULL,'2020-06-08',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1109,109,1,'k.A.',NULL,NULL,9,NULL,'2020-06-09',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1110,110,1,'k.A.',NULL,NULL,9,NULL,'2020-06-10',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1111,111,1,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1112,112,1,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1113,113,1,'k.A.',NULL,NULL,9,NULL,'2020-06-03',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1114,114,1,'k.A.',NULL,NULL,9,NULL,'2020-06-04',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1115,115,1,'k.A.',NULL,NULL,9,NULL,'2020-06-05',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1116,116,1,'k.A.',NULL,NULL,9,NULL,'2020-06-06',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1117,117,1,'k.A.',NULL,NULL,9,NULL,'2020-06-07',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1118,118,1,'k.A.',NULL,NULL,9,NULL,'2020-06-08',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1119,119,1,'k.A.',NULL,NULL,9,NULL,'2020-06-09',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (1120,120,1,'k.A.',NULL,NULL,9,NULL,'2020-06-10',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false) -; -SELECT setval('tbl_prestudent_prestudent_id_seq', 2000,true); - --- Prestudent Status - -WITH status AS ( - SELECT * FROM (VALUES - ('Interessent','WS2025',1,'2025-01-15','2023-08-24 14:56:04','auto',NULL,NULL,NULL,1,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Bewerber','WS2025',1,'2025-02-20','2023-08-24 14:58:11','auto',NULL,NULL,NULL,1,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Aufgenommener','WS2025',1,'2025-05-01','2023-08-24 14:58:14','auto',NULL,NULL,NULL,1,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student','WS2025',1,'2025-08-24','2023-08-24 14:58:16','auto',NULL,NULL,NULL,1,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL) - ) AS t(status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -), -inserts AS ( - SELECT generate_series(1101, 1120) AS prestudent_id,* - FROM status -) -INSERT INTO public.tbl_prestudentstatus (prestudent_id, status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -SELECT prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester, datum::date, insertamum::timestamp, insertvon, updateamum::timestamp, updatevon,orgform_kurzbz,studienplan_id,bestaetigtam::date,bestaetigtvon,fgm::smallint,faktiv,anmerkung,bewerbung_abgeschicktamum::timestamp,rt_stufe::smallint,statusgrund_id::int -FROM inserts; - --- tbl_benutzer -WITH persons AS ( - SELECT generate_series(101, 120) AS person_id -) -INSERT INTO public.tbl_benutzer (person_id, uid, aktiv, alias, insertamum, insertvon, updateamum, updatevon, updateaktivam, updateaktivvon, aktivierungscode) -SELECT person_id, 's125b' || person_id, true, null, now(), 'auto', null, null, null, false, null -FROM persons; - --- tbl_student -WITH persons AS ( - SELECT generate_series(101, 120) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's125b' || person_id, '2510001' || person_id, ('1' || person_id)::integer, '1', '1', '','', null, null, now(), 'auto' -FROM persons; - --- tbl_studentlehrverband -WITH persons AS ( - SELECT generate_series(101, 120) AS person_id -), -students as ( - SELECT ('s125b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, 'WS2025', '1','1','','', null, null, now(), 'auto' -FROM students; - diff --git a/system/seeders/006_studiengang_3.sql b/system/seeders/006_studiengang_3.sql deleted file mode 100644 index 087b741b2..000000000 --- a/system/seeders/006_studiengang_3.sql +++ /dev/null @@ -1,161 +0,0 @@ --- Demodaten fuer Studiengang 3: Organisationseinheit, Studienordnung, Studiengang, Lehrveranstaltungen - -INSERT INTO public.tbl_organisationseinheit (oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id) -VALUES('stg3', 'studiengaenge', 'Studiengang 3', 'Studiengang', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL); - -INSERT INTO public.tbl_studiengang (studiengang_kz,kurzbz,kurzbzlang,typ,bezeichnung,english,farbe,email,telefon,max_semester,max_verband,max_gruppe,erhalter_kz,bescheid,bescheidbgbl1,bescheidbgbl2,bescheidgz,bescheidvom,titelbescheidvom,aktiv,ext_id,orgform_kurzbz,zusatzinfo_html,moodle,oe_kurzbz,sprache,testtool_sprachwahl,studienplaetze,lgartcode,mischform,projektarbeit_note_anzeige,melderelevant,foerderrelevant,standort_code,onlinebewerbung,melde_studiengang_kz) VALUES - (3,'S3','STG3','b','Studiengang 3','Studiengang 3',NULL,'invalid@example.com',NULL,6,'B','2',5,NULL,NULL,NULL,NULL,NULL,NULL,true,NULL,'VZ','',true,'stg3','German',true,NULL,NULL,false,true,true,true,NULL,false,'0002') -; - -INSERT INTO "system".tbl_benutzerrolle -(rolle_kurzbz, berechtigung_kurzbz, uid, funktion_kurzbz, oe_kurzbz, art, studiensemester_kurzbz, "start", ende, negativ, updateamum, updatevon, insertamum, insertvon, kostenstelle_id, anmerkung) -VALUES('assistenz', NULL, 'demoassistenz', NULL, 'stg3', 'suid', NULL, '2025-09-18', NULL, false, NULL, NULL, '2025-09-18 15:46:02.000', 'demoadmin', NULL, NULL); - -INSERT INTO public.tbl_lehrverband (studiengang_kz, semester, verband, gruppe, aktiv, bezeichnung, ext_id, orgform_kurzbz) VALUES - (3, 1, '','', true, null, null, null), - (3, 1, 'A','', true, null, null, null), - (3, 1, 'B','', true, null, null, null), - (3, 2, '','', true, null, null, null), - (3, 2, 'A','', true, null, null, null), - (3, 2, 'B','', true, null, null, null), - (3, 3, '','', true, null, null, null), - (3, 3, 'A','', true, null, null, null), - (3, 3, 'B','', true, null, null, null), - (3, 4, '','', true, null, null, null), - (3, 4, 'A','', true, null, null, null), - (3, 4, 'B','', true, null, null, null), - (3, 5, '','', true, null, null, null), - (3, 5, 'A','', true, null, null, null), - (3, 5, 'B','', true, null, null, null), - (3, 6, '','', true, null, null, null), - (3, 6, 'A','', true, null, null, null), - (3, 6, 'B','', true, null, null, null) -; - -INSERT INTO lehre.tbl_studienordnung (studienordnung_id, studiengang_kz,"version",gueltigvon,gueltigbis,bezeichnung,ects,studiengangbezeichnung,studiengangbezeichnung_englisch,studiengangkurzbzlang,akadgrad_id,insertamum,insertvon,updateamum,updatevon,ext_id,status_kurzbz,standort_id) VALUES - (301, 3,'1','WS2023',NULL,'BS3-WS2023',180.00,'Studiengang 3','Studiengang 3','STG3',NULL,'2023-08-24 14:25:41.728215','auto',NULL,NULL,NULL,'development',NULL); - -INSERT INTO lehre.tbl_studienplan (studienplan_id, studienordnung_id,orgform_kurzbz,"version",bezeichnung,regelstudiendauer,sprache,aktiv,semesterwochen,testtool_sprachwahl,insertamum,insertvon,updateamum,updatevon,ext_id,ects_stpl,pflicht_sws,pflicht_lvs,onlinebewerbung_studienplan) VALUES - (3011, 301,'VZ','1','BS3-WS2023-VZ',6,NULL,true,15,true,'2023-08-24 14:26:12.751416','auto',NULL,NULL,NULL,180.00,NULL,NULL,true); - -INSERT INTO lehre.tbl_lehrveranstaltung (lehrveranstaltung_id, kurzbz,bezeichnung,studiengang_kz,semester,sprache,ects,semesterstunden,anmerkung,lehre,lehreverzeichnis,aktiv,planfaktor,planlektoren,planpersonalkosten,plankostenprolektor,updateamum,updatevon,insertamum,insertvon,ext_id,sort,zeugnis,koordinator,projektarbeit,lehrform_kurzbz,bezeichnung_english,orgform_kurzbz,incoming,lehrmodus_kurzbz,lehrtyp_kurzbz,oe_kurzbz,raumtyp_kurzbz,anzahlsemester,semesterwochen,lvnr,farbe,old_lehrfach_id,semester_alternativ,sws,lvs,alvs,lvps,las,benotung,lvinfo,lehrauftrag,lehrveranstaltung_template_id) VALUES - (311, 'MOD1.1','Sport',3,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Communication','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (312, 'MOD1.2','Mathematik',3,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Mathematics','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (313, 'MOD1.3','Grundlagen',3,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Basics','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (314, 'MOD1.4','Sprachen',3,1,'English',6.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Communication','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (321, 'MOD2.1','Labor',3,2,'German',10.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Laboratory','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (322, 'MOD2.2','Mathematik',3,2,'German',10.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Mathematics','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (323, 'MOD2.3','Sprachen',3,2,'English',10.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Communication','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (331, 'MOD3.1','Mathematik',3,3,'German',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Mathematics','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (332, 'MOD3.2','Elektrische Signale',3,3,'German',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Electric Signals','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (341, 'MOD4.1','Messtechnik',3,4,'German',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Measurement Technology','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (342, 'MOD4.2','Forschung',3,4,'German',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Research','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (351, 'MOD5.1','Communication',3,5,'English',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Communication','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (352, 'MOD5.2','Regelungstechnik',3,5,'German',15.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Control Engineering','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (361, 'MOD6.1','Bachelorarbeit',3,6,'German',30.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'MOD','Bachelor Thesis','VZ',5,'regulaer','modul','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL) - ; - - INSERT INTO lehre.tbl_lehrveranstaltung (lehrveranstaltung_id, kurzbz,bezeichnung,studiengang_kz,semester,sprache,ects,semesterstunden,anmerkung,lehre,lehreverzeichnis,aktiv,planfaktor,planlektoren,planpersonalkosten,plankostenprolektor,updateamum,updatevon,insertamum,insertvon,ext_id,sort,zeugnis,koordinator,projektarbeit,lehrform_kurzbz,bezeichnung_english,orgform_kurzbz,incoming,lehrmodus_kurzbz,lehrtyp_kurzbz,oe_kurzbz,raumtyp_kurzbz,anzahlsemester,semesterwochen,lvnr,farbe,old_lehrfach_id,semester_alternativ,sws,lvs,alvs,lvps,las,benotung,lvinfo,lehrauftrag,lehrveranstaltung_template_id) VALUES - (3111, 'LS','Leistungssport',3,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'VO','Communication','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3121, 'MAT','Mathematik 1',3,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Mathematics','VZ',5,'regulaer','lv','kfMath',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3131, 'GL','Grundlagen der Programmierung',3,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Development Basics','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3141, 'ENG','Englisch 1',3,1,'English',6.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'VO','Communication','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3211, 'EL','Elektronik Labor',3,2,'German',10.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'LAB','Laboratory','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3221, 'MAT','Mathematik 2',3,2,'German',10.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Mathematics','VZ',5,'regulaer','lv','kfMath',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3231, 'ENG','Communcation Englisch',3,2,'English',10.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'VO','Communication','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3311, 'MAT','Mathematik 3',3,3,'German',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Mathematics','VZ',5,'regulaer','lv','kfMath',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3321, 'ES','Elektrische Signale',3,3,'German',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Electric Signals','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3411, 'MT','Messtechnik',3,4,'German',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Measurement Technology','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3421, 'BAN','Bewegungsanalyse',3,4,'German',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Movement Analytics','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3511, 'ENG','Communication',3,5,'English',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'VO','Communication','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3521, 'RT','Regelungstechnik',3,5,'German',15.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'ILV','Control Engineering','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (3611, 'BA','Bachelorarbeit',3,6,'German',30.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,'2023-08-24 14:28:39','oesi','2023-08-24 14:28:39','oesi',NULL,NULL,true,NULL,false,'SE','Bachelor Thesis','VZ',5,'regulaer','lv','stg3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL) - ; - - INSERT INTO lehre.tbl_studienplan_lehrveranstaltung (studienplan_lehrveranstaltung_id, studienplan_id,lehrveranstaltung_id,semester,studienplan_lehrveranstaltung_id_parent,pflicht,koordinator,insertamum,insertvon,updateamum,updatevon,sort,ext_id,curriculum,export,genehmigung) VALUES - -- MODULE im Studienplan - (301, 3011,311,1,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (302, 3011,312,1,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (303, 3011,313,1,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (304, 3011,314,1,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (305, 3011,321,2,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (306, 3011,322,2,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (307, 3011,323,2,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (308, 3011,331,3,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (309, 3011,332,3,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (310, 3011,341,4,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (311, 3011,342,4,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (312, 3011,351,5,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (313, 3011,352,5,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (314, 3011,361,6,NULL,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - - -- LVS zu Modulen - (315, 3011,3111,1,301,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (316, 3011,3121,1,302,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (317, 3011,3131,1,303,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (318, 3011,3141,1,304,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (319, 3011,3211,2,305,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (320, 3011,3221,2,306,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (321, 3011,3231,2,307,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (322, 3011,3311,3,308,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (323, 3011,3321,3,309,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (324, 3011,3411,4,310,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (325, 3011,3421,4,311,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (326, 3011,3511,5,312,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (327, 3011,3521,5,313,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true), - (328, 3011,3611,6,314,true,NULL,'2023-08-24 14:29:03.506117','oesi',NULL,NULL,NULL,NULL,true,true,true) -; - -INSERT INTO lehre.tbl_studienplan_semester (studienplan_id, studiensemester_kurzbz, semester) VALUES -(3011, 'WS2023', 1), -(3011, 'SS2024', 2), -(3011, 'WS2024', 1), -(3011, 'WS2024', 3), -(3011, 'SS2025', 2), -(3011, 'SS2025', 4), -(3011, 'WS2025', 1), -(3011, 'WS2025', 3), -(3011, 'WS2025', 5), -(3011, 'SS2026', 2), -(3011, 'SS2026', 4), -(3011, 'SS2026', 6); - - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, anmerkung, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht) -VALUES(31001, 3131, 'WS2025', NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, NULL, 3131, NULL, '2023-08-24 14:54:43.000', 'oesi', '2023-08-24 14:54:43.000', 'oesi', NULL, 3131, 1); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(31001, 3, 1, 'A', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'oesi', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(31001, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'oesi', NULL, 0.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, anmerkung, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht) -VALUES(31002, 3131, 'WS2025', NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, NULL, 3131, NULL, '2023-08-24 14:54:43.000', 'oesi', '2023-08-24 14:54:43.000', 'oesi', NULL, 3131, 1); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(31002, 3, 1, 'B', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'oesi', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(31002, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'oesi', NULL, 0.00, NULL, NULL); - --- Stundenplan Eintraege -INSERT INTO lehre.tbl_stundenplandev -(stundenplandev_id, lehreinheit_id, unr, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, mitarbeiter_uid, ort_kurzbz, datum, stunde, titel, anmerkung, fix, updateamum, updatevon, insertamum, insertvon) -VALUES(310011, 31001, 31001, 3, 1, 'A', '', NULL, 'demolektor1', 'EG04', '2025-07-31', 7, NULL, NULL, false, '2025-07-31 13:50:49.419', 'demoadmin', '2025-07-31 13:50:49.419', NULL); - -INSERT INTO lehre.tbl_stundenplan -(stundenplan_id, lehreinheit_id, unr, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, mitarbeiter_uid, ort_kurzbz, datum, stunde, titel, anmerkung, fix, updateamum, updatevon, insertamum, insertvon) -VALUES(310011, 31001, 31001, 3, 1, 'A', '', NULL, 'demolektor1', 'EG04', '2025-07-31', 7, NULL, NULL, false, '2025-07-31 13:50:49.419', 'demoadmin', '2025-07-31 13:50:49.419', NULL); - -INSERT INTO lehre.tbl_stundenplandev -(stundenplandev_id, lehreinheit_id, unr, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, mitarbeiter_uid, ort_kurzbz, datum, stunde, titel, anmerkung, fix, updateamum, updatevon, insertamum, insertvon) -VALUES(310021, 31002, 31002, 3, 1, 'B', '', NULL, 'demolektor1', 'EG04', '2025-08-01', 7, NULL, NULL, false, '2025-07-31 13:50:49.419', 'demoadmin', '2025-07-31 13:50:49.419', NULL); - -INSERT INTO lehre.tbl_stundenplan -(stundenplan_id, lehreinheit_id, unr, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, mitarbeiter_uid, ort_kurzbz, datum, stunde, titel, anmerkung, fix, updateamum, updatevon, insertamum, insertvon) -VALUES(310021, 31002, 31002, 3, 1, 'B', '', NULL, 'demolektor1', 'EG04', '2025-08-01', 7, NULL, NULL, false, '2025-07-31 13:50:49.419', 'demoadmin', '2025-07-31 13:50:49.419', NULL); diff --git a/system/seeders/007_studenten_stg_3.sql b/system/seeders/007_studenten_stg_3.sql deleted file mode 100644 index 89b0074bf..000000000 --- a/system/seeders/007_studenten_stg_3.sql +++ /dev/null @@ -1,120 +0,0 @@ --- Demodaten fuer Studierende im Studiengang 3 --- Personen -INSERT INTO public.tbl_person (person_id, staatsbuergerschaft,geburtsnation,sprache,anrede,titelpost,titelpre,vorname,nachname,vornamen,gebdatum,gebort,gebzeit,foto,anmerkung,homepage,svnr,ersatzkennzeichen,familienstand,geschlecht,anzahlkinder,aktiv,insertamum,insertvon,updateamum,updatevon,ext_id,bundesland_code,kompetenzen,kurzbeschreibung,zugangscode,foto_sperre,udf_values,bpk,matr_aktiv,matr_nr,zugangscode_timestamp,wahlname,unruly) VALUES - -(301,'A','A',NULL,'Herr',NULL,NULL,'Elon','Musk',NULL,'1974-11-11',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c301',false,NULL,NULL,false,NULL,NULL,NULL,false), -(302,'A','A',NULL,'Herr',NULL,NULL,'Steve','Jobs',NULL,'1965-04-04',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c302',false,NULL,NULL,false,NULL,NULL,NULL,false), -(303,'A','A',NULL,'Herr',NULL,NULL,'Bill','Gates',NULL,'1954-12-28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c303',false,NULL,NULL,false,NULL,NULL,NULL,false), -(304,'A','A',NULL,'Herr',NULL,NULL,'Linus','Torvalds',NULL,'1940-04-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c304',false,NULL,NULL,false,NULL,NULL,NULL,false), -(305,'A','A',NULL,'Herr',NULL,NULL,'Mark','Zuckerberg',NULL,'1937-06-01',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c305',false,NULL,NULL,false,NULL,NULL,NULL,false), -(306,'A','A',NULL,'Frau',NULL,NULL,'Ada','Lovelace',NULL,'1957-04-29',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c306',false,NULL,NULL,false,NULL,NULL,NULL,false), -(307,'A','A',NULL,'Herr',NULL,NULL,'Tim','Berners-Lee',NULL,'1924-04-03',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c307',false,NULL,NULL,false,NULL,NULL,NULL,false), -(308,'A','A',NULL,'Frau',NULL,NULL,'Grace','Hopper',NULL,'1956-07-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c308',false,NULL,NULL,false,NULL,NULL,NULL,false), -(309,'A','A',NULL,'Herr',NULL,NULL,'Jeff','Bezos',NULL,'1963-06-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c309',false,NULL,NULL,false,NULL,NULL,NULL,false), -(310,'A','A',NULL,'Herr',NULL,NULL,'Larry','Page',NULL,'1963-12-18',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c8310',false,NULL,NULL,false,NULL,NULL,NULL,false), -(311,'A','A',NULL,'Herr',NULL,NULL,'Sergey','Brin',NULL,'1968-09-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c311',false,NULL,NULL,false,NULL,NULL,NULL,false), -(312,'A','A',NULL,'Frau',NULL,NULL,'Katherine','Johnson',NULL,'1964-09-02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c312',false,NULL,NULL,false,NULL,NULL,NULL,false), -(313,'A','A',NULL,'Herr',NULL,NULL,'Dennis','Ritchie',NULL,'1943-08-17',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647313',false,NULL,NULL,false,NULL,NULL,NULL,false), -(314,'A','A',NULL,'Frau',NULL,NULL,'Margaret','Hamilton',NULL,'1942-07-13',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c314',false,NULL,NULL,false,NULL,NULL,NULL,false), -(315,'A','A',NULL,'Herr',NULL,NULL,'Satya','Nadella',NULL,'1948-12-21',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c315',false,NULL,NULL,false,NULL,NULL,NULL,false), -(316,'A','A',NULL,'Frau',NULL,NULL,'Susan','Wojcicki',NULL,'1974-01-30',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c316',false,NULL,NULL,false,NULL,NULL,NULL,false), -(317,'A','A',NULL,'Frau',NULL,NULL,'Sheryl','Sandberg',NULL,'1962-07-03',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c317',false,NULL,NULL,false,NULL,NULL,NULL,false), -(318,'A','A',NULL,'Herr',NULL,NULL,'Jack','Dorsey',NULL,'1947-07-30',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c318',false,NULL,NULL,false,NULL,NULL,NULL,false), -(319,'A','A',NULL,'Frau',NULL,NULL,'Ginni','Rometty',NULL,'1946-07-06',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c319',false,NULL,NULL,false,NULL,NULL,NULL,false), -(320,'A','A',NULL,'Herr',NULL,NULL,'Sundar','Pichai',NULL,'1963-06-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c320',false,NULL,NULL,false,NULL,NULL,NULL,false) -; -SELECT setval('public.tbl_person_person_id_seq', 1000,true); - --- Prestudenten -INSERT INTO public.tbl_prestudent (prestudent_id, person_id,studiengang_kz,aufmerksamdurch_kurzbz,berufstaetigkeit_code,ausbildungcode,zgv_code,zgvort,zgvdatum,zgvmas_code,zgvmaort,zgvmadatum,aufnahmeschluessel,facheinschlberuf,reihungstest_id,anmeldungreihungstest,reihungstestangetreten,rt_gesamtpunkte,bismelden,insertamum,insertvon,updateamum,updatevon,ext_id,anmerkung,dual,rt_punkte1,rt_punkte2,ausstellungsstaat,rt_punkte3,udf_values,priorisierung,zgvdoktor_code,zgvdoktorort,zgvdoktordatum,mentor,zgvnation,zgvmanation,zgvdoktornation,gsstudientyp_kurzbz,aufnahmegruppe_kurzbz,foerderrelevant,standort_code,zgv_erfuellt,zgvmas_erfuellt,zgvdoktor_erfuellt) VALUES - (3301,301,3,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3302,302,3,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3303,303,3,'k.A.',NULL,NULL,9,NULL,'2020-06-03',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3304,304,3,'k.A.',NULL,NULL,9,NULL,'2020-06-04',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3305,305,3,'k.A.',NULL,NULL,9,NULL,'2020-06-05',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3306,306,3,'k.A.',NULL,NULL,9,NULL,'2020-06-06',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3307,307,3,'k.A.',NULL,NULL,9,NULL,'2020-06-07',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3308,308,3,'k.A.',NULL,NULL,9,NULL,'2020-06-08',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3309,309,3,'k.A.',NULL,NULL,9,NULL,'2020-06-09',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3310,310,3,'k.A.',NULL,NULL,9,NULL,'2020-06-10',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3311,311,3,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3312,312,3,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3313,313,3,'k.A.',NULL,NULL,9,NULL,'2020-06-03',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3314,314,3,'k.A.',NULL,NULL,9,NULL,'2020-06-04',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3315,315,3,'k.A.',NULL,NULL,9,NULL,'2020-06-05',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3316,316,3,'k.A.',NULL,NULL,9,NULL,'2020-06-06',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3317,317,3,'k.A.',NULL,NULL,9,NULL,'2020-06-07',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3318,318,3,'k.A.',NULL,NULL,9,NULL,'2020-06-08',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3319,319,3,'k.A.',NULL,NULL,9,NULL,'2020-06-09',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (3320,320,3,'k.A.',NULL,NULL,9,NULL,'2020-06-10',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false) -; -SELECT setval('tbl_prestudent_prestudent_id_seq', (SELECT max(prestudent_id) FROM public.tbl_prestudent),true); - --- Prestudent Status - -WITH status AS ( - SELECT * FROM (VALUES - ('Interessent','WS2025',1,'2025-01-15','2023-08-24 14:56:04','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Bewerber','WS2025',1,'2025-02-20','2023-08-24 14:58:11','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Aufgenommener','WS2025',1,'2025-05-01','2023-08-24 14:58:14','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student','WS2025',1,'2025-08-24','2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL) - ) AS t(status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -), -inserts AS ( - SELECT generate_series(3301, 3320) AS prestudent_id,* - FROM status -) -INSERT INTO public.tbl_prestudentstatus (prestudent_id, status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -SELECT prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester, datum::date, insertamum::timestamp, insertvon, updateamum::timestamp, updatevon,orgform_kurzbz,studienplan_id,bestaetigtam::date,bestaetigtvon,fgm::smallint,faktiv,anmerkung,bewerbung_abgeschicktamum::timestamp,rt_stufe::smallint,statusgrund_id::int -FROM inserts; - --- tbl_benutzer -WITH persons AS ( - SELECT generate_series(301, 320) AS person_id -) -INSERT INTO public.tbl_benutzer (person_id, uid, aktiv, alias, insertamum, insertvon, updateamum, updatevon, updateaktivam, updateaktivvon, aktivierungscode) -SELECT person_id, 's325b' || person_id, true, null, now(), 'auto', null, null, null, false, null -FROM persons; - --- tbl_student --- A Verband -WITH persons AS ( - SELECT generate_series(301, 310) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's325b' || person_id, '2510003' || person_id, ('3' || person_id)::integer, '3', '1', 'A','', null, null, now(), 'auto' -FROM persons; - --- B Verband -WITH persons AS ( - SELECT generate_series(311, 320) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's325b' || person_id, '2510003' || person_id, ('3' || person_id)::integer, '3', '1', 'B','', null, null, now(), 'auto' -FROM persons; - --- tbl_studentlehrverband --- A Verband -WITH persons AS ( - SELECT generate_series(301, 310) AS person_id -), -students as ( - SELECT ('s325b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, 'WS2025', '3','1','A','', null, null, now(), 'auto' -FROM students; - --- B Verband -WITH persons AS ( - SELECT generate_series(311, 320) AS person_id -), -students as ( - SELECT ('s325b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, 'WS2025', '3','1','B','', null, null, now(), 'auto' -FROM students; - diff --git a/system/seeders/008_studiengang_4.sql b/system/seeders/008_studiengang_4.sql deleted file mode 100644 index 957e14c81..000000000 --- a/system/seeders/008_studiengang_4.sql +++ /dev/null @@ -1,239 +0,0 @@ --- Demodaten fuer Studiengang 4: Organisationseinheit, Studienordnung, Studiengang, Lehrveranstaltungen, Lehreinheiten --- Testdaten fuer LV-Verwaltung, Tempus - -INSERT INTO public.tbl_organisationseinheit (oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id) -VALUES('stg4', 'studiengaenge', 'Tempus Examples', 'Studiengang', true, false, NULL, NULL, true, NULL, NULL, NULL, NULL); - -INSERT INTO public.tbl_studiengang (studiengang_kz,kurzbz,kurzbzlang,typ,bezeichnung,english,farbe,email,telefon,max_semester,max_verband,max_gruppe,erhalter_kz,bescheid,bescheidbgbl1,bescheidbgbl2,bescheidgz,bescheidvom,titelbescheidvom,aktiv,ext_id,orgform_kurzbz,zusatzinfo_html,moodle,oe_kurzbz,sprache,testtool_sprachwahl,studienplaetze,lgartcode,mischform,projektarbeit_note_anzeige,melderelevant,foerderrelevant,standort_code,onlinebewerbung,melde_studiengang_kz) VALUES - (4,'S4','STG4','b','Tempus Beispiele','Tempus Examples',NULL,'invalid@example.com',NULL,6,'B','2',5,NULL,NULL,NULL,NULL,NULL,NULL,true,NULL,'VZ','',true,'stg4','German',true,NULL,NULL,false,true,true,true,NULL,false,'0004') -; - -INSERT INTO public.tbl_lehrverband (studiengang_kz, semester, verband, gruppe, aktiv, bezeichnung, ext_id, orgform_kurzbz) VALUES - (4, 1, '','', true, null, null, null), - (4, 1, 'A','', true, null, null, null), - (4, 1, 'B','', true, null, null, null), - (4, 2, '','', true, null, null, null), - (4, 2, 'A','', true, null, null, null), - (4, 2, 'B','', true, null, null, null), - (4, 3, '','', true, null, null, null), - (4, 3, 'A','', true, null, null, null), - (4, 3, 'B','', true, null, null, null), - (4, 4, '','', true, null, null, null), - (4, 4, 'A','', true, null, null, null), - (4, 4, 'B','', true, null, null, null), - (4, 5, '','', true, null, null, null), - (4, 5, 'A','', true, null, null, null), - (4, 5, 'B','', true, null, null, null), - (4, 6, '','', true, null, null, null), - (4, 6, 'A','', true, null, null, null), - (4, 6, 'B','', true, null, null, null) -; - -INSERT INTO lehre.tbl_studienordnung (studienordnung_id, studiengang_kz,"version",gueltigvon,gueltigbis,bezeichnung,ects,studiengangbezeichnung,studiengangbezeichnung_englisch,studiengangkurzbzlang,akadgrad_id,insertamum,insertvon,updateamum,updatevon,ext_id,status_kurzbz,standort_id) VALUES - (401, 4,'1',NearestWintersemester(-4),NULL,'BS4'||NearestWintersemester(-4),180.00,'Tempus Beispiele','Tempus Examples','STG4',NULL,now(),'anondata',NULL,NULL,NULL,'development',NULL); - -INSERT INTO lehre.tbl_studienplan (studienplan_id, studienordnung_id,orgform_kurzbz,"version",bezeichnung,regelstudiendauer,sprache,aktiv,semesterwochen,testtool_sprachwahl,insertamum,insertvon,updateamum,updatevon,ext_id,ects_stpl,pflicht_sws,pflicht_lvs,onlinebewerbung_studienplan) VALUES - (4011, 401,'VZ','1','BS4-'||NearestWintersemester(-4)||'-VZ',6,NULL,true,15,true,now(),'anondata',NULL,NULL,NULL,180.00,NULL,NULL,true); - -INSERT INTO lehre.tbl_lehrveranstaltung (lehrveranstaltung_id, kurzbz,bezeichnung,studiengang_kz,semester,sprache,ects,semesterstunden,anmerkung,lehre,lehreverzeichnis,aktiv,planfaktor,planlektoren,planpersonalkosten,plankostenprolektor,updateamum,updatevon,insertamum,insertvon,ext_id,sort,zeugnis,koordinator,projektarbeit,lehrform_kurzbz,bezeichnung_english,orgform_kurzbz,incoming,lehrmodus_kurzbz,lehrtyp_kurzbz,oe_kurzbz,raumtyp_kurzbz,anzahlsemester,semesterwochen,lvnr,farbe,old_lehrfach_id,semester_alternativ,sws,lvs,alvs,lvps,las,benotung,lvinfo,lehrauftrag,lehrveranstaltung_template_id) VALUES - (411, 'MOD1.1','Standard',4,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Standard','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (412, 'MOD1.2','Advanced',4,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Advanced','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (413, 'MOD1.3','Wahlmodul',4,1,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Wahlmodul','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (414, 'MOD1.4','Sonstiges',4,1,'English',6.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Sonstiges','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - - (461, 'MOD6.1','Bachelorarbeit',4,6,'German',8.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Bachelorarbeit','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (462, 'MOD6.2','International Skills',4,6,'English',5.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','International Skills','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL), - (463, 'MOD6.3','Berufspraktikum',4,6,'German',17.00,NULL,NULL,true,'mod',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'MOD','Berufspraktikum','VZ',5,'regulaer','modul','stg4',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,true,true,NULL) - ; - - INSERT INTO lehre.tbl_lehrveranstaltung (lehrveranstaltung_id, kurzbz,bezeichnung,studiengang_kz,semester,sprache,ects,semesterstunden,anmerkung,lehre,lehreverzeichnis,aktiv,planfaktor,planlektoren,planpersonalkosten,plankostenprolektor,updateamum,updatevon,insertamum,insertvon,ext_id,sort,zeugnis,koordinator,projektarbeit,lehrform_kurzbz,bezeichnung_english,orgform_kurzbz,incoming,lehrmodus_kurzbz,lehrtyp_kurzbz,oe_kurzbz,raumtyp_kurzbz,anzahlsemester,semesterwochen,lvnr,farbe,old_lehrfach_id,semester_alternativ,sws,lvs,alvs,lvps,las,benotung,lvinfo,lehrauftrag,lehrveranstaltung_template_id) VALUES - (4111, 'S1','Standardvorlesung',4,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'VO','Standardvorlesung','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (4121, 'S2','Vorlesung und Uebung',4,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'ILV','VorlesungUebung','VZ',5,'regulaer','lv','kfMath',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (4131, 'S3','Getrennte Gruppen',4,1,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'ILV','Splittet Groups','VZ',5,'regulaer','lv','kfTech',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (4141, 'A1','Mehrere Lektoren',4,1,'English',6.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'VO','Multilektor','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - - (4611, 'BA','Bachelorarbeit',4,6,'German',8.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'EL','Bachelorarbeit','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (4621, 'INT','International Skills',4,6,'English',5.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'PRJ','International Skills','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL), - (4631, 'BPRAK','Berufspraktikum',4,6,'German',17.00,NULL,NULL,true,'lv',true,NULL,NULL,NULL,NULL,now(),'anondata',now(),'anondata',NULL,NULL,true,NULL,false,'SO','Berufspraktikum','VZ',5,'regulaer','lv','kfSprachen',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,true,true,true,NULL) - ; - - INSERT INTO lehre.tbl_studienplan_lehrveranstaltung (studienplan_lehrveranstaltung_id, studienplan_id,lehrveranstaltung_id,semester,studienplan_lehrveranstaltung_id_parent,pflicht,koordinator,insertamum,insertvon,updateamum,updatevon,sort,ext_id,curriculum,export,genehmigung) VALUES - -- MODULE im Studienplan - (401, 4011,411,1,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (402, 4011,412,1,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (403, 4011,413,1,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (404, 4011,414,1,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - - (461, 4011,461,6,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (462, 4011,462,6,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (463, 4011,463,6,NULL,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - - -- LVS zu Modulen - (415, 4011,4111,1,401,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (416, 4011,4121,1,401,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (417, 4011,4131,1,401,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (418, 4011,4141,1,402,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - - (465, 4011,4611,6,461,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (466, 4011,4621,6,462,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true), - (467, 4011,4631,6,463,true,NULL,now(),'anondata',NULL,NULL,NULL,NULL,true,true,true) -; - -INSERT INTO lehre.tbl_studienplan_semester (studienplan_id, studiensemester_kurzbz, semester) VALUES -(4011, NearestWintersemester(-4), 1), -(4011, NearestWintersemester(-3), 2), -(4011, NearestWintersemester(-2), 1), -(4011, NearestWintersemester(-2), 3), -(4011, NearestWintersemester(-1), 2), -(4011, NearestWintersemester(-1), 4), -(4011, NearestWintersemester(0), 1), -(4011, NearestWintersemester(0), 3), -(4011, NearestWintersemester(0), 5), -(4011, NearestWintersemester(+1), 2), -(4011, NearestWintersemester(+1), 4), -(4011, NearestWintersemester(+1), 6); - --- ===== Standardvorlesung -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41001, 4111, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4111, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4111, 1, 'Standard ein LV-Teil, ein Lektor, eine Gruppe'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41001, 4, '1', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41001, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - --- ===== VORLESUNG UND UEBUNG -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41002, 4121, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4121, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4121, 1, 'Vorlesung'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41002, 4, '1', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41002, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41003, 4121, NearestWintersemester(0), NULL, 'UE', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4121, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4121, 1, 'Uebung'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41003, 4, '1', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41003, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - - --- ======= GETRENNTE GRUPPEN -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41004, 4131, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4131, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4131, 1, 'Vorlesung 1A'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41004, 4, '1', 'A', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41004, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41005, 4131, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4131, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4131, 1, 'Vorlesung 1B'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41005, 4, '1', 'B', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41005, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - --- ======= Mehrere Lektoren -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41006, 4141, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4141, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4141, 1, 'Vorlesung 1A und Lektor 2 und 3'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41006, 4, '1', 'A', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41006, 'demolektor2', 'Lektor', 8, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 8.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41006, 'demolektor3', 'Lektor', 8, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 8.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41007, 4141, NearestWintersemester(0), NULL, 'VO', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4141, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4141, 1, 'Vorlesung 1B und Lektor 4 und 5'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41007, 4, '1', 'B', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41007, 'demolektor4', 'Lektor', 8, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 8.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41007, 'demolektor5', 'Lektor', 8, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 8.00, NULL, NULL); - -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(41008, 4141, NearestWintersemester(0), NULL, 'BE', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4141, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4141, 1, 'LV Leitung die nicht verplant wird'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41008, 4, '1', 'B', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(41008, 4, '1', 'A', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(41008, 'demolektor4', 'LV-Leitung', 0, NULL, 1.00, NULL, false, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 5.00, NULL, NULL); - - --- ===== 6. Semester - --- ===== Bachelorarbeit -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(46111, 4611, NearestWintersemester(1), NULL, 'EL', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4111, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4611, 1, 'keine Verplanung'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(46111, 4, '6', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(46111, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - --- ===== Internation Skills -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(46211, 4621, NearestWintersemester(1), NULL, 'EL', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4111, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4621, 1, 'nur für Zeugnis'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(46211, 4, '6', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(46211, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - --- ===== BPRAK -INSERT INTO lehre.tbl_lehreinheit (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrfach_id_old, lehrform_kurzbz, stundenblockung, wochenrythmus, start_kw, raumtyp, raumtypalternativ, sprache, lehre, unr, lvnr, updateamum, updatevon, insertamum, insertvon, ext_id, lehrfach_id, gewicht, anmerkung) -VALUES(46311, 4631, NearestWintersemester(1), NULL, 'EL', 2, 1, NULL, 'Dummy', 'Dummy', 'German', true, 4111, NULL, '2023-08-24 14:54:43.000', 'anondata', '2023-08-24 14:54:43.000', 'anondata', NULL, 4631, 1, 'keine Verplanung'); - -INSERT INTO lehre.tbl_lehreinheitgruppe -(lehreinheit_id, studiengang_kz, semester, verband, gruppe, gruppe_kurzbz, updateamum, updatevon, insertamum, insertvon, ext_id) -VALUES(46311, 4, '6', '', NULL, NULL, NULL, NULL, '2023-08-24 14:58:26.000', 'anondata', NULL); - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter -(lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz, planstunden, stundensatz, faktor, anmerkung, bismelden, updateamum, updatevon, insertamum, insertvon, ext_id, semesterstunden, standort_id, vertrag_id) -VALUES(46311, 'demolektor1', 'Lektor', 0, NULL, 1.00, NULL, true, NULL, NULL, '2023-08-24 14:58:40.000', 'anondata', NULL, 0.00, NULL, NULL); - diff --git a/system/seeders/009_studenten_stg_4.sql b/system/seeders/009_studenten_stg_4.sql deleted file mode 100644 index 4230e4d9e..000000000 --- a/system/seeders/009_studenten_stg_4.sql +++ /dev/null @@ -1,266 +0,0 @@ --- Demodaten fuer Studierende im Studiengang 4 --- Personen -INSERT INTO public.tbl_person (person_id, staatsbuergerschaft,geburtsnation,sprache,anrede,titelpost,titelpre,vorname,nachname,vornamen,gebdatum,gebort,gebzeit,foto,anmerkung,homepage,svnr,ersatzkennzeichen,familienstand,geschlecht,anzahlkinder,aktiv,insertamum,insertvon,updateamum,updatevon,ext_id,bundesland_code,kompetenzen,kurzbeschreibung,zugangscode,foto_sperre,udf_values,bpk,matr_aktiv,matr_nr,zugangscode_timestamp,wahlname,unruly) VALUES - -(401,'A','A',NULL,'Herr',NULL,NULL,'Mario','Super',NULL,'1974-11-11',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c401',false,NULL,NULL,false,NULL,NULL,NULL,false), -(402,'A','A',NULL,'Herr',NULL,NULL,'Luigi','Green',NULL,'1965-04-04',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c402',false,NULL,NULL,false,NULL,NULL,NULL,false), -(403,'A','A',NULL,'Frau',NULL,NULL,'Peach','Princess',NULL,'1954-12-28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c403',false,NULL,NULL,false,NULL,NULL,NULL,false), -(404,'A','A',NULL,'Herr',NULL,NULL,'Toad','Mushroom',NULL,'1940-04-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c404',false,NULL,NULL,false,NULL,NULL,NULL,false), -(405,'A','A',NULL,'Herr',NULL,NULL,'Bowser','Koopa',NULL,'1937-06-01',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c405',false,NULL,NULL,false,NULL,NULL,NULL,false), -(406,'A','A',NULL,'Frau',NULL,NULL,'Link','Hyrule',NULL,'1957-04-29',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c406',false,NULL,NULL,false,NULL,NULL,NULL,false), -(407,'A','A',NULL,'Frau',NULL,NULL,'Zelda','Hyrule',NULL,'1924-04-03',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c407',false,NULL,NULL,false,NULL,NULL,NULL,false), -(408,'A','A',NULL,'Herr',NULL,NULL,'Donkey','Kong',NULL,'1956-07-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c408',false,NULL,NULL,false,NULL,NULL,NULL,false), -(409,'A','A',NULL,'Herr',NULL,NULL,'Yoshi','Dinosaur',NULL,'1963-06-09',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c409',false,NULL,NULL,false,NULL,NULL,NULL,false), -(410,'A','A',NULL,'Frau',NULL,NULL,'Rosalina','Lumaire',NULL,'1963-12-18',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c8410',false,NULL,NULL,false,NULL,NULL,NULL,false), -(411,'A','A',NULL,'Herr',NULL,NULL,'Wario','Warioh',NULL,'1968-09-25',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'m',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c411',false,NULL,NULL,false,NULL,NULL,NULL,false), -(412,'A','A',NULL,'Frau',NULL,NULL,'Waluigi','Big',NULL,'1964-09-02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c412',false,NULL,NULL,false,NULL,NULL,NULL,false), - -(413,'A','A',NULL,'Frau',NULL,NULL,'Melanie','Muster',NULL,'2010-04-02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c413',false,NULL,NULL,false,NULL,NULL,NULL,false), -(414,'A','A',NULL,'Frau',NULL,NULL,'Tanja','Test',NULL,'2009-03-02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c414',false,NULL,NULL,false,NULL,NULL,NULL,false), -(415,'A','A',NULL,'Frau',NULL,NULL,'Franziska','Fake',NULL,'2003-08-05',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c415',false,NULL,NULL,false,NULL,NULL,NULL,false), -(416,'A','A',NULL,'Herr',NULL,NULL,'Simon','Simulator',NULL,'2007-07-07',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'w',NULL,true,'2023-08-24 14:56:04.509813','auto','2025-05-13 10:57:19.826386',NULL,NULL,NULL,NULL,NULL,'64e753647c416',false,NULL,NULL,false,NULL,NULL,NULL,false) -; -SELECT setval('public.tbl_person_person_id_seq', (SELECT max(person_id) FROM public.tbl_person),true); - --- Prestudenten -INSERT INTO public.tbl_prestudent (prestudent_id, person_id,studiengang_kz,aufmerksamdurch_kurzbz,berufstaetigkeit_code,ausbildungcode,zgv_code,zgvort,zgvdatum,zgvmas_code,zgvmaort,zgvmadatum,aufnahmeschluessel,facheinschlberuf,reihungstest_id,anmeldungreihungstest,reihungstestangetreten,rt_gesamtpunkte,bismelden,insertamum,insertvon,updateamum,updatevon,ext_id,anmerkung,dual,rt_punkte1,rt_punkte2,ausstellungsstaat,rt_punkte3,udf_values,priorisierung,zgvdoktor_code,zgvdoktorort,zgvdoktordatum,mentor,zgvnation,zgvmanation,zgvdoktornation,gsstudientyp_kurzbz,aufnahmegruppe_kurzbz,foerderrelevant,standort_code,zgv_erfuellt,zgvmas_erfuellt,zgvdoktor_erfuellt) VALUES - (4401,401,4,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4402,402,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4403,403,4,'k.A.',NULL,NULL,9,NULL,'2020-06-03',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4404,404,4,'k.A.',NULL,NULL,9,NULL,'2020-06-04',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4405,405,4,'k.A.',NULL,NULL,9,NULL,'2020-06-05',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4406,406,4,'k.A.',NULL,NULL,9,NULL,'2020-06-06',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4407,407,4,'k.A.',NULL,NULL,9,NULL,'2020-06-07',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4408,408,4,'k.A.',NULL,NULL,9,NULL,'2020-06-08',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4409,409,4,'k.A.',NULL,NULL,9,NULL,'2020-06-09',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4410,410,4,'k.A.',NULL,NULL,9,NULL,'2020-06-10',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4411,411,4,'k.A.',NULL,NULL,9,NULL,'2020-06-01',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4412,412,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - - (4413,413,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4414,414,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4415,415,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false), - (4416,416,4,'k.A.',NULL,NULL,9,NULL,'2020-06-02',NULL,NULL,NULL,NULL,false,NULL,NULL,true,NULL,true,NULL,NULL,'2023-08-24 14:56:04.509813',NULL,NULL,NULL,false,NULL,NULL,'A',0.0000,NULL,NULL,NULL,NULL,NULL,NULL,'A',NULL,NULL,'Intern',NULL,NULL,NULL,false,false,false) -; -SELECT setval('tbl_prestudent_prestudent_id_seq', (SELECT max(prestudent_id) FROM public.tbl_prestudent),true); - --- Prestudent Status Drittsemestrige - -WITH status AS ( - SELECT * FROM (VALUES - ('Interessent',NearestWintersemester(-2),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-2)),'2023-08-24 14:56:04','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Bewerber',NearestWintersemester(-2),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-2)),'2023-08-24 14:58:11','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Aufgenommener',NearestWintersemester(-2),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-2)),'2023-08-24 14:58:14','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-2),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-2)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-1),2,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-1)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(0),3,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(0)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL) - ) AS t(status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -), -inserts AS ( - SELECT generate_series(4401, 4412) AS prestudent_id,* - FROM status -) -INSERT INTO public.tbl_prestudentstatus (prestudent_id, status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -SELECT prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester, datum::date, insertamum::timestamp, insertvon, updateamum::timestamp, updatevon,orgform_kurzbz,studienplan_id,bestaetigtam::date,bestaetigtvon,fgm::smallint,faktiv,anmerkung,bewerbung_abgeschicktamum::timestamp,rt_stufe::smallint,statusgrund_id::int -FROM inserts; - --- tbl_benutzer -WITH persons AS ( - SELECT generate_series(401, 412) AS person_id -) -INSERT INTO public.tbl_benutzer (person_id, uid, aktiv, alias, insertamum, insertvon, updateamum, updatevon, updateaktivam, updateaktivvon, aktivierungscode) -SELECT person_id, 's425b' || person_id, true, null, now(), 'auto', null, null, null, false, null -FROM persons; - --- tbl_student --- A Verband -WITH persons AS ( - SELECT generate_series(401, 405) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's425b' || person_id, '2510004' || person_id, ('4' || person_id)::integer, '4', '3', 'A','', null, null, now(), 'auto' -FROM persons; - --- B Verband -WITH persons AS ( - SELECT generate_series(406, 412) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's425b' || person_id, '2510004' || person_id, ('4' || person_id)::integer, '4', '3', 'B','', null, null, now(), 'auto' -FROM persons; - --- tbl_studentlehrverband --- A Verband -WITH persons AS ( - SELECT generate_series(401, 405) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-2), '4','1','A','', null, null, now(), 'auto' -FROM students; -WITH persons AS ( - SELECT generate_series(401, 405) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-1), '4','2','A','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(401, 405) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(0), '4','3','A','', null, null, now(), 'auto' -FROM students; - --- B Verband -WITH persons AS ( - SELECT generate_series(406, 412) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-2), '4','1','B','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(406, 412) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-1), '4','2','B','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(406, 412) AS person_id -), -students as ( - SELECT ('s425b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(0), '4','3','B','', null, null, now(), 'auto' -FROM students; - - ----- 6 Semestrige - -WITH status AS ( - SELECT * FROM (VALUES - ('Interessent',NearestWintersemester(-4),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-4)),'2023-08-24 14:56:04','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Bewerber',NearestWintersemester(-4),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-4)),'2023-08-24 14:58:11','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Aufgenommener',NearestWintersemester(-4),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-4)),'2023-08-24 14:58:14','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-4),1,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-4)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-3),2,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-3)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-2),3,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-2)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(-1),4,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(-1)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(0),5,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(0)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL), - ('Student',NearestWintersemester(+1),6,(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=NearestWintersemester(+1)),'2023-08-24 14:58:16','auto',NULL,NULL,NULL,3011,'2023-08-24','demoadmin',NULL,false,NULL,NULL,NULL,NULL) - ) AS t(status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -), -inserts AS ( - SELECT generate_series(4413, 4416) AS prestudent_id,* - FROM status -) -INSERT INTO public.tbl_prestudentstatus (prestudent_id, status_kurzbz,studiensemester_kurzbz,ausbildungssemester,datum,insertamum,insertvon,updateamum,updatevon,orgform_kurzbz,studienplan_id,bestaetigtam,bestaetigtvon,fgm,faktiv,anmerkung,bewerbung_abgeschicktamum,rt_stufe,statusgrund_id) -SELECT prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester, datum::date, insertamum::timestamp, insertvon, updateamum::timestamp, updatevon,orgform_kurzbz,studienplan_id,bestaetigtam::date,bestaetigtvon,fgm::smallint,faktiv,anmerkung,bewerbung_abgeschicktamum::timestamp,rt_stufe::smallint,statusgrund_id::int -FROM inserts; - --- tbl_benutzer -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -) -INSERT INTO public.tbl_benutzer (person_id, uid, aktiv, alias, insertamum, insertvon, updateamum, updatevon, updateaktivam, updateaktivvon, aktivierungscode) -SELECT person_id, 's46b' || person_id, true, null, now(), 'auto', null, null, null, false, null -FROM persons; - --- tbl_student --- A Verband -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -) -INSERT INTO public.tbl_student (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT 's46b' || person_id, '2510004' || person_id, ('4' || person_id)::integer, '4', '6', 'A','', null, null, now(), 'auto' -FROM persons; - --- tbl_studentlehrverband --- A Verband -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-4), '4','1','A','', null, null, now(), 'auto' -FROM students; -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-3), '4','2','A','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-2), '4','3','A','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(-1), '4','4','A','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(0), '4','5','A','', null, null, now(), 'auto' -FROM students; - -WITH persons AS ( - SELECT generate_series(413, 416) AS person_id -), -students as ( - SELECT ('s46b' || person_id) as student_uid, person_id - FROM persons -) -INSERT INTO public.tbl_studentlehrverband (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe, updateamum, updatevon, insertamum, insertvon) -SELECT student_uid, NearestWintersemester(+1), '4','6','A','', null, null, now(), 'auto' -FROM students; diff --git a/system/seeders/010_projektarbeiten_studiengang_4.sql b/system/seeders/010_projektarbeiten_studiengang_4.sql deleted file mode 100644 index 214705bc4..000000000 --- a/system/seeders/010_projektarbeiten_studiengang_4.sql +++ /dev/null @@ -1,16 +0,0 @@ -INSERT INTO lehre.tbl_projektarbeit -(projektarbeit_id, projekttyp_kurzbz, titel, lehreinheit_id, student_uid, firma_id, note, punkte, beginn, ende, faktor, freigegeben, gesperrtbis, stundensatz, themenbereich, anmerkung, updateamum, updatevon, insertamum, insertvon, ext_id, gesamtstunden, titel_english, sprache, seitenanzahl, abgabedatum, kontrollschlagwoerter, schlagwoerter, schlagwoerter_en, abstract, abstract_en, "final") VALUES -(1, 'Bachelor', 'Auswirkung der Sonneneinstrahlung auf die Gesundheit', 46111, 's46b413', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true), -(2, 'Bachelor', 'Neue Unterrichtsmethoden mit KI', 46111, 's46b414', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true), -(3, 'Bachelor', 'Betrugsbekämpfung bei Anwesenheitskontrolle', 46111, 's46b415', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true), -(4, 'Bachelor', 'Neuronale Netze', 46111, 's46b416', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true) -; - -INSERT INTO lehre.tbl_projektbetreuer -(person_id, projektarbeit_id, note, faktor, "name", punkte, stundensatz, updateamum, updatevon, insertamum, insertvon, ext_id, betreuerart_kurzbz, stunden, zugangstoken, zugangstoken_gueltigbis, vertrag_id) VALUES -(21, 1, NULL, NULL, NULL, NULL, 80.00, NULL, NULL, '2025-12-12 14:07:10.000', 'anondata', NULL, 'Begutachter', 4.0000, NULL, NULL, NULL), -(21, 2, NULL, NULL, NULL, NULL, 80.00, NULL, NULL, '2025-12-12 14:07:10.000', 'anondata', NULL, 'Begutachter', 4.0000, NULL, NULL, NULL), -(21, 3, NULL, NULL, NULL, NULL, 80.00, NULL, NULL, '2025-12-12 14:07:10.000', 'anondata', NULL, 'Begutachter', 4.0000, NULL, NULL, NULL), -(21, 4, NULL, NULL, NULL, NULL, 80.00, NULL, NULL, '2025-12-12 14:07:10.000', 'anondata', NULL, 'Begutachter', 4.0000, NULL, NULL, NULL) -; - diff --git a/system/seeders/011_zeitwuensche.sql b/system/seeders/011_zeitwuensche.sql deleted file mode 100644 index 8895bf5fe..000000000 --- a/system/seeders/011_zeitwuensche.sql +++ /dev/null @@ -1,107 +0,0 @@ -INSERT INTO campus.tbl_zeitwunsch_gueltigkeit -(zeitwunsch_gueltigkeit_id, mitarbeiter_uid, von, bis, insertamum, insertvon, updateamum, updatevon) -VALUES(1, 'demolektor1', '2020-09-01', NULL, NOW(), 'demolektor1', NULL, NULL); - -INSERT INTO campus.tbl_zeitwunsch -(stunde, mitarbeiter_uid, tag, gewicht, updateamum, updatevon, insertamum, insertvon, zeitwunsch_id, zeitwunsch_gueltigkeit_id) VALUES -(1, 'demolektor1', 1, -2, now(), 'demolektor1', now(), 'demolektor1', 1, 1), -(2, 'demolektor1', 1, -2, now(), 'demolektor1', now(), 'demolektor1', 2, 1), -(3, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 3, 1), -(4, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 4, 1), -(5, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 5, 1), -(6, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 6, 1), -(7, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 7, 1), -(8, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 8, 1), -(9, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 9, 1), -(10, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 10, 1), -(11, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 11, 1), -(12, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 12, 1), -(13, 'demolektor1', 1, 2, now(), 'demolektor1', now(), 'demolektor1', 13, 1), -(14, 'demolektor1', 1, -1, now(), 'demolektor1', now(), 'demolektor1', 14, 1), -(15, 'demolektor1', 1, -1, now(), 'demolektor1', now(), 'demolektor1', 15, 1), -(16, 'demolektor1', 1, -1, now(), 'demolektor1', now(), 'demolektor1', 16, 1), -(1, 'demolektor1', 2, -2, now(), 'demolektor1', now(), 'demolektor1', 17, 1), -(2, 'demolektor1', 2, -1, now(), 'demolektor1', now(), 'demolektor1', 18, 1), -(3, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 19, 1), -(4, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 20, 1), -(5, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 21, 1), -(6, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 22, 1), -(7, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 23, 1), -(8, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 24, 1), -(9, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 25, 1), -(10, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 26, 1), -(11, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 27, 1), -(12, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 28, 1), -(13, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 29, 1), -(14, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 30, 1), -(15, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 31, 1), -(16, 'demolektor1', 2, 1, now(), 'demolektor1', now(), 'demolektor1', 32, 1), -(1, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 33, 1), -(2, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 34, 1), -(3, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 35, 1), -(4, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 36, 1), -(5, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 37, 1), -(6, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 38, 1), -(7, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 39, 1), -(8, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 40, 1), -(9, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 41, 1), -(10, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 42, 1), -(11, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 43, 1), -(12, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 44, 1), -(13, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 45, 1), -(14, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 46, 1), -(15, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 47, 1), -(16, 'demolektor1', 3, 1, now(), 'demolektor1', now(), 'demolektor1', 48, 1), -(1, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 49, 1), -(2, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 50, 1), -(3, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 51, 1), -(4, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 52, 1), -(5, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 53, 1), -(6, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 54, 1), -(7, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 55, 1), -(8, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 56, 1), -(9, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 57, 1), -(10, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 58, 1), -(11, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 59, 1), -(12, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 60, 1), -(13, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 61, 1), -(14, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 62, 1), -(15, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 63, 1), -(16, 'demolektor1', 4, 1, now(), 'demolektor1', now(), 'demolektor1', 64, 1), -(1, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 65, 1), -(2, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 66, 1), -(3, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 67, 1), -(4, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 68, 1), -(5, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 69, 1), -(6, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 70, 1), -(7, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 71, 1), -(8, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 72, 1), -(9, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 73, 1), -(10, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 74, 1), -(11, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 75, 1), -(12, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 76, 1), -(13, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 77, 1), -(14, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 78, 1), -(15, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 79, 1), -(16, 'demolektor1', 5, 1, now(), 'demolektor1', now(), 'demolektor1', 80, 1), -(1, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 81, 1), -(2, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 82, 1), -(3, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 83, 1), -(4, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 84, 1), -(5, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 85, 1), -(6, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 86, 1), -(7, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 87, 1), -(8, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 88, 1), -(9, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 89, 1), -(10, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 90, 1), -(11, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 91, 1), -(12, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 92, 1), -(13, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 93, 1), -(14, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 94, 1), -(15, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 95, 1), -(16, 'demolektor1', 6, 1, now(), 'demolektor1', now(), 'demolektor1', 96, 1) -; - - -SELECT setval('campus.seq_zeitwunsch_zeitwunsch_id', (select max(zeitwunsch_id) from campus.tbl_zeitwunsch), true); -SELECT setval('campus.seq_zeitwunsch_gueltigkeit_zeitwunsch_gueltigkeit_id', (select max(zeitwunsch_gueltigkeit_id) from campus.tbl_zeitwunsch_gueltigkeit),true); diff --git a/system/seeders/012_cms_content.sql b/system/seeders/012_cms_content.sql deleted file mode 100644 index 72c381b93..000000000 --- a/system/seeders/012_cms_content.sql +++ /dev/null @@ -1,38 +0,0 @@ -INSERT INTO campus.tbl_content -(content_id, template_kurzbz, oe_kurzbz, insertamum, insertvon, updateamum, updatevon, aktiv, menu_open, beschreibung) VALUES -(30, 'contentmittitel', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(32, 'contentmittitel', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(33, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(34, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(35, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(36, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(37, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL), -(38, 'redirect', 'etw', now(), 'demoadmin', now(), 'demoadmin', true, false, NULL) -; - -INSERT INTO campus.tbl_contentsprache (sprache, content_id, "version", sichtbar, "content", reviewvon, reviewamum, updateamum, updatevon, insertamum, insertvon, titel, gesperrt_uid) VALUES -('German', 30, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'CIS4', NULL), -('German', 32, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Studium', NULL), -('German', 33, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'LV-Plan', NULL), -('German', 34, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Dahsboard', NULL), -('German', 35, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Meine LVs', NULL), -('German', 36, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Studium', NULL), -('German', 37, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Profil', NULL), -('German', 38, 1, true, '', NULL, NULL, now(), 'demoadmin', now(), 'demoadmin', 'Dokumente', NULL) -; - -INSERT INTO campus.tbl_contentchild (content_id, child_content_id, insertamum, insertvon, updateamum, updatevon, sort) VALUES -(30, 37, now(), 'demoadmin', NULL, NULL, 5), -(30, 27, now(), 'demoadmin', NULL, NULL, 7), -(30, 32, now(), 'demoadmin', NULL, NULL, 2), -(30, 34, now(), 'demoadmin', NULL, NULL, 1), -(32, 33, now(), 'demoadmin', NULL, NULL, 1), -(32, 36, now(), 'demoadmin', NULL, NULL, 2), -(32, 38, now(), 'demoadmin', NULL, NULL, 3), -(32, 35, now(), 'demoadmin', NULL, NULL, 4) -; - -INSERT INTO campus.tbl_contentgruppe (content_id, gruppe_kurzbz, insertamum, insertvon) VALUES -(30, 'MA', now(), 'demoadmin'), -(30, 'STUD', now(), 'demoadmin') -; diff --git a/system/seeders/014_betriebsmittel.sql b/system/seeders/014_betriebsmittel.sql deleted file mode 100644 index 6239ccfa9..000000000 --- a/system/seeders/014_betriebsmittel.sql +++ /dev/null @@ -1,11 +0,0 @@ -INSERT INTO wawi.tbl_betriebsmitteltyp -(betriebsmitteltyp, beschreibung, anzahl, kaution, typ_code, mastershapename) -VALUES('Inventar', NULL, NULL, NULL, NULL, NULL); - -INSERT INTO wawi.tbl_betriebsmittel -(betriebsmittel_id, beschreibung, betriebsmitteltyp, nummer, reservieren, updateamum, updatevon, insertamum, insertvon, ext_id, inventarnummer, oe_kurzbz, ort_kurzbz, hersteller, seriennummer, bestellung_id, bestelldetail_id, afa, verwendung, anmerkung, leasing_bis, inventuramum, inventurvon, anschaffungswert, anschaffungsdatum, tiefe, hoehe, breite, nummer2, verplanen) -VALUES -(1, 'pc', 'Laptop', NULL, false, '2024-03-07 08:17:33.000', 'demoadmin', '2015-12-01 14:55:32.000', 'demoadmin', NULL, '00001', NULL, NULL, 'pc', NULL, NULL, NULL, 3, NULL, 'Angelegt von demoadmin für die test', NULL, '2015-12-01 14:55:32.000', 'demoadmin', NULL, NULL, NULL, NULL, NULL, NULL, true), -(2, 'projector', 'Inventar', NULL, false, '2024-03-07 08:17:33.000', 'demoadmin', '2015-12-01 14:55:32.000', 'demoadmin', NULL, '00002', NULL, NULL, 'projector', NULL, NULL, NULL, 3, NULL, 'Angelegt von demoadmin für die test', NULL, '2015-12-01 14:55:32.000', 'demoadmin', NULL, NULL, NULL, NULL, NULL, NULL, true), -(3, 'workstation', 'Inventar', NULL, false, '2024-03-07 08:17:33.000', 'demoadmin', '2015-12-01 14:55:32.000', 'demoadmin', NULL, '00003', NULL, NULL, 'workstation', NULL, NULL, NULL, 3, NULL, 'Angelegt von demoadmin für die test', NULL, '2015-12-01 14:55:32.000', 'demoadmin', NULL, NULL, NULL, NULL, NULL, NULL, true), -(4, 'pc2', 'Laptop', NULL, false, '2024-03-07 08:17:33.000', 'demoadmin', '2015-12-01 14:55:32.000', 'demoadmin', NULL, '00004', NULL, NULL, 'pc2', NULL, NULL, NULL, 3, NULL, 'Angelegt von demoadmin für die test', NULL, '2015-12-01 14:55:32.000', 'demoadmin', NULL, NULL, NULL, NULL, NULL, NULL, true); diff --git a/system/seeders/015_kalender.sql b/system/seeders/015_kalender.sql deleted file mode 100644 index 345e003a3..000000000 --- a/system/seeders/015_kalender.sql +++ /dev/null @@ -1,210 +0,0 @@ --- Rooms setup for calendar tests -INSERT INTO public.tbl_adresse -(adresse_id, person_id, "name", strasse, plz, ort, gemeinde, nation, typ, heimatadresse, zustelladresse, firma_id, updateamum, updatevon, insertamum, insertvon, ext_id, rechnungsadresse, anmerkung, co_name) -VALUES(1, NULL, 'Hauptwohnsitz', 'Stromstraße 18-20/1/10', '1200', 'Wien', 'Wien', 'A', 'h', true, true, NULL, '2007-08-13 10:53:40.298', 'demoadmin', '2007-08-10 10:42:02.579', 'demoadmin', 14470, false, NULL, NULL); - -INSERT INTO public.tbl_standort -(kurzbz, adresse_id, standort_id, bezeichnung, insertvon, insertamum, updatevon, updateamum, ext_id, firma_id, code) -VALUES('Vienna Universit', 1, 1, 'Vienna University of Technology, Institute of Design and Assessment of Technology', 'demoadmin', '2012-02-02 10:24:11.803', 'demoadmin', '2015-05-27 09:05:53.894', NULL, 6033, NULL); - -INSERT INTO public.tbl_ort -(ort_kurzbz, bezeichnung, planbezeichnung, max_person, lehre, reservieren, aktiv, lageplan, dislozierung, kosten, ausstattung, updateamum, updatevon, insertamum, insertvon, ext_id, stockwerk, telefonklappe, standort_id, content_id, m2, gebteil, oe_kurzbz, arbeitsplaetze) -VALUES -('Bro_F7.37', 'Büro', 'F7.37', NULL, true, true, true, NULL, NULL, NULL, NULL, '2023-09-19 10:35:20.000', 'demoadmin', '2012-09-05 15:20:25.979', 'demoadmin', NULL, 7, NULL, 1, NULL, 21.58, 'F', 'etw', NULL), -('Bro_F7.38', 'Büro', 'F7.38', NULL, true, true, true, NULL, NULL, NULL, NULL, '2023-09-19 10:35:20.000', 'demoadmin', '2012-09-05 15:20:25.979', 'demoadmin', NULL, 7, NULL, 1, NULL, 21.58, 'F', 'etw', NULL), -('Bro_F7.39', 'Büro', 'F7.39', NULL, true, true, true, NULL, NULL, NULL, NULL, '2023-09-19 10:35:20.000', 'demoadmin', '2012-09-05 15:20:25.979', 'demoadmin', NULL, 7, NULL, 1, NULL, 21.58, 'F', 'etw', NULL), -('Bro_F7.40', 'Büro', 'F7.40', NULL, true, true, true, NULL, NULL, NULL, NULL, '2023-09-19 10:35:20.000', 'demoadmin', '2012-09-05 15:20:25.979', 'demoadmin', NULL, 7, NULL, 1, NULL, 21.58, 'F', 'etw', NULL), -('Bro_F7.41', 'Büro', 'F7.41', NULL, true, true, true, NULL, NULL, NULL, NULL, '2023-09-19 10:35:20.000', 'demoadmin', '2012-09-05 15:20:25.979', 'demoadmin', NULL, 7, NULL, 1, NULL, 21.58, 'F', 'etw', NULL); - -INSERT INTO public.tbl_ortraumtyp -(ort_kurzbz, hierarchie, raumtyp_kurzbz) -VALUES -('Bro_F7.37', 1, 'Dummy'), -('Bro_F7.38', 1, 'Dummy'), -('Bro_F7.39', 1, 'Dummy'), -('Bro_F7.40', 1, 'Dummy'), -('Bro_F7.41', 1, 'Dummy'); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for event drag and drop tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:00:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:45:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:45:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:30:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_ort -(location, ort_kurzbz, kalender_id) -VALUES(NULL, 'Bro_F7.37', 1); - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51001, 1), -(51002, 2), -(51003, 3), -(51003, 4), -(51002, 5), -(51006, 6), -(51002, 7), -(51006, 8); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for resize tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '08:00:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '08:45:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51001, 9), -(51003, 10), -(51002, 11); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for role preview tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51001, 12), -(51002, 13); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - --- Calendar setup for API event creation tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51003, 14), -(51005, 15); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for API event update tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) -VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '1 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '1 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '21:00:00', 'reservierung', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_ort -(location, ort_kurzbz, kalender_id) -VALUES -(NULL, 'Bro_F7.37', 17), -(NULL, 'Bro_F7.37', 18); - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51001, 16), -(51001, 17), -(51003, 18), -(51001, 19), -(51003, 20), -(51003, 21), -(51006, 22), -(51004, 23), -(51005, 24), -(51004, 25), -(51006, 26); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for Stundenraster disabled tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:20:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '12:05:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:20:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '12:05:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51002, 27), -(51006, 28); --- //////////////////////////////////////////////////////////////////////////////////////////////////// - - --- Calendar setup for resources tests -INSERT INTO lehre.tbl_kalender -(von, bis, typ, status_kurzbz, vorgaenger_kalender_id, eindeutige_gruppen_id, insertamum, insertvon, updateamum, updatevon) -VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, 'ec1bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, 'ec2bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '17:50:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '18:35:00', 'lehreinheit', 'live', NULL, 'ec3bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, 'ec4bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin') -; - -INSERT INTO lehre.tbl_kalender_lehreinheit -(lehreinheit_id, kalender_id) -VALUES -(51004, 29), -(51006, 30), -(51006, 31), -(51004, 32); - --- INSERT INTO public.tbl_variablenname --- (name, defaultwert) --- VALUES('ignore_resources_collisions', 'false'); - -INSERT INTO public.tbl_variable -(name, uid, wert) -VALUES('ignore_resources_collisions', 'demoadmin', 'false'); - -INSERT INTO lehre.tbl_betriebsmittel_kalender -(eindeutige_kalender_gruppen_id, betriebsmittel_id, anmerkung, quelle, insertamum, insertvon, updateamum, updatevon) -VALUES -('ec1bd001-facf-4b21-a671-bcb2d4f037fd'::uuid, 1, '', 'tempus_neu', '2026-06-17 16:48:59.669', 'demoadmin', '2026-06-17 17:13:23.000', 'demoadmin'), -('ec2bd001-facf-4b21-a671-bcb2d4f037fd'::uuid, 1, '', 'tempus_neu', '2026-06-17 16:48:59.669', 'demoadmin', '2026-06-17 17:13:23.000', 'demoadmin'), -('ec3bd001-facf-4b21-a671-bcb2d4f037fd'::uuid, 2, '', 'tempus_neu', '2026-06-17 16:48:59.669', 'demoadmin', '2026-06-17 17:13:23.000', 'demoadmin'), -('ec4bd001-facf-4b21-a671-bcb2d4f037fd'::uuid, 3, '', 'tempus_neu', '2026-06-17 16:48:59.669', 'demoadmin', '2026-06-17 17:13:23.000', 'demoadmin'); --- //////////////////////////////////////////////////////////////////////////////////////////////////-- - - -INSERT INTO lehre.tbl_kalender_event -(kalender_id, titel, beschreibung) -VALUES(26, 'Test reservation', NULL); - -INSERT INTO lehre.tbl_kalender_event_teilnehmer -(kalender_id, rolle_kurzbz, uid, studiensemester_kurzbz, gruppe_kurzbz, studiengang_kz, semester, verband, gruppe, studentenlehrverband_id) -VALUES(26, 'teilnehmer', 'demolektor4', NULL, NULL, NULL, NULL, NULL, NULL, NULL); - -INSERT INTO campus.tbl_zeitsperre -(zeitsperre_id, zeitsperretyp_kurzbz, mitarbeiter_uid, bezeichnung, vondatum, vonstunde, bisdatum, bisstunde, vertretung_uid, updateamum, updatevon, insertamum, insertvon, erreichbarkeit_kurzbz, freigabeamum, freigabevon) -VALUES(1, 'DienstV', 'demolektor1', 'Test', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day', NULL, date_trunc('week', CURRENT_DATE) + INTERVAL '5 day', NULL, 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', 't', NULL, NULL); - - diff --git a/system/seeders/016_benotungstool_noten.sql b/system/seeders/016_benotungstool_noten.sql deleted file mode 100644 index 1b254ef03..000000000 --- a/system/seeders/016_benotungstool_noten.sql +++ /dev/null @@ -1,183 +0,0 @@ --- Demo data for the Benotungstool / Gesamtnoteneingabe test suite. --- --- campus.vw_student_lehrveranstaltung, the source of getStudentsByLv(), links students to --- Lehreinheiten through tbl_lehreinheitgruppe.gruppe_kurzbz = tbl_benutzergruppe.gruppe_kurzbz AND --- a matching Studiensemester. --- --- RESULT: demolektor1 -> LV 5221 (12 students), demolektor2 -> LV 5121 (6, the foreign LV for the --- access tests). - -BEGIN; - --- Test semester: the running one, else the last started. Same rule as the suite. -CREATE TEMP TABLE sem AS -SELECT studiensemester_kurzbz AS kurzbz - FROM public.tbl_studiensemester - WHERE start <= now() - ORDER BY (ende >= now()) DESC, start DESC - LIMIT 1; - --- The two LV fixtures. Own Lehreinheiten (511xx) so the tempus fixtures 51001-51006 stay untouched. --- members_up_to = highest person_id that joins this group. -CREATE TEMP TABLE lv AS -SELECT v.*, l.semester - FROM (VALUES - (true, 5221, 51101, 'GRP_CYNOTEN_H', 'Cypress Noten Haupt', 'demolektor1', 512), - (false, 5121, 51102, 'GRP_CYNOTEN_F', 'Cypress Noten Fremd', 'demolektor2', 506) - ) AS v(main, lv_id, le_id, grp, grp_text, lektor, members_up_to) - JOIN lehre.tbl_lehrveranstaltung l ON l.lehrveranstaltung_id = v.lv_id; - --- The 12 students. person_id is the anchor for every derived key. -CREATE TEMP TABLE stud AS -SELECT id AS person_id, 5000 + id AS prestudent_id, 's525b' || id AS uid - FROM generate_series(501, 512) AS g(id); - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM sem) THEN - RAISE EXCEPTION 'No Studiensemester found, the base dump is missing.'; - END IF; - IF (SELECT count(*) FROM lv) <> 2 THEN - RAISE EXCEPTION 'LV 5221/5121 missing, apply 013_studiengang_5.sql.'; - END IF; -END $$; - --- Termin3 is absent from the base dump; without it every Termin3 insert hits a foreign key error. -INSERT INTO lehre.tbl_pruefungstyp (pruefungstyp_kurzbz, beschreibung) -VALUES ('Termin3', '3. Termin') - ON CONFLICT DO NOTHING; - --- ------------------------------------------------------------------------------------- students -INSERT INTO public.tbl_person (person_id, vorname, nachname, gebdatum, geschlecht, aktiv) -SELECT person_id, 'Noten', 'Student ' || (person_id - 500), '2000-01-15', 'm', true - FROM stud - ON CONFLICT DO NOTHING; - -INSERT INTO public.tbl_prestudent (prestudent_id, person_id, studiengang_kz) -SELECT prestudent_id, person_id, 5 - FROM stud - ON CONFLICT DO NOTHING; - -INSERT INTO public.tbl_prestudentstatus - (prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester) -SELECT s.prestudent_id, 'Student', sem.kurzbz, lv.semester - FROM stud s, sem, lv - WHERE lv.main - ON CONFLICT DO NOTHING; - -INSERT INTO public.tbl_benutzer (uid, person_id, aktiv) -SELECT uid, person_id, true - FROM stud - ON CONFLICT DO NOTHING; - --- matrikelnr is UNIQUE; scheme of the existing seeders is '251000' + studiengang_kz + person_id -INSERT INTO public.tbl_student - (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe) -SELECT s.uid, '2510005' || s.person_id, s.prestudent_id, 5, lv.semester, '', '' - FROM stud s, lv - WHERE lv.main - ON CONFLICT DO NOTHING; - --- Lehrverband assignment; (5, , '', '') is created by 013_studiengang_5.sql. -INSERT INTO public.tbl_studentlehrverband - (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe) -SELECT s.uid, sem.kurzbz, 5, lv.semester, '', '' - FROM stud s, sem, lv - WHERE lv.main - ON CONFLICT DO NOTHING; - --- ------------------------------------------------------------------- Lehreinheiten and Lektoren -INSERT INTO lehre.tbl_lehreinheit - (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrform_kurzbz, - wochenrythmus, raumtyp, raumtypalternativ, sprache, lehrfach_id) -SELECT lv.le_id, lv.lv_id, sem.kurzbz, 'VO', 1, 'Dummy', 'Dummy', 'German', lv.lv_id - FROM lv, sem - ON CONFLICT DO NOTHING; - --- Fix the semester if the Lehreinheit is left over from a run in a different one. -UPDATE lehre.tbl_lehreinheit le - SET studiensemester_kurzbz = sem.kurzbz - FROM lv, sem - WHERE le.lehreinheit_id = lv.le_id - AND le.studiensemester_kurzbz IS DISTINCT FROM sem.kurzbz; - -INSERT INTO lehre.tbl_lehreinheitmitarbeiter (lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz) -SELECT le_id, lektor, 'Lektor' - FROM lv - ON CONFLICT DO NOTHING; - --- --------------------------------------------------------------------------------------- groups -INSERT INTO public.tbl_gruppe (gruppe_kurzbz, studiengang_kz, semester, bezeichnung, aktiv) -SELECT grp, 5, semester, grp_text, true - FROM lv - ON CONFLICT DO NOTHING; - --- The row the existing seeders lack: attach the group to the Lehreinheit with gruppe_kurzbz set. --- The primary key is a serial, so NOT EXISTS instead of ON CONFLICT. -INSERT INTO lehre.tbl_lehreinheitgruppe (lehreinheit_id, studiengang_kz, semester, gruppe_kurzbz) -SELECT lv.le_id, 5, lv.semester, lv.grp - FROM lv - WHERE NOT EXISTS (SELECT 1 FROM lehre.tbl_lehreinheitgruppe g - WHERE g.lehreinheit_id = lv.le_id AND g.gruppe_kurzbz = lv.grp); - --- Membership WITH a semester. The primary key is (uid, gruppe_kurzbz) and excludes the semester, --- so DO UPDATE repairs a row from an earlier run instead of duplicating it. -INSERT INTO public.tbl_benutzergruppe (uid, gruppe_kurzbz, studiensemester_kurzbz) -SELECT s.uid, lv.grp, sem.kurzbz - FROM stud s, lv, sem - WHERE s.person_id <= lv.members_up_to - ON CONFLICT (uid, gruppe_kurzbz) DO UPDATE - SET studiensemester_kurzbz = EXCLUDED.studiensemester_kurzbz; - --- -------------------------------------------------------------------------------- Notenschluessel -INSERT INTO lehre.tbl_notenschluessel (notenschluessel_kurzbz, bezeichnung) -VALUES ('CYNOTEN', 'Cypress Testnotenschluessel') - ON CONFLICT DO NOTHING; - --- getNote() takes the row with the largest punkte value <= the points given. The 0 threshold makes --- sure every value maps to a grade. Serial primary key, so NOT EXISTS. -INSERT INTO lehre.tbl_notenschluesselaufteilung (notenschluessel_kurzbz, note, punkte) -SELECT 'CYNOTEN', a.note, a.punkte - FROM (VALUES (5, 0.0), (4, 51.0), (3, 64.0), (2, 77.0), (1, 90.0)) AS a(note, punkte) - WHERE NOT EXISTS (SELECT 1 FROM lehre.tbl_notenschluesselaufteilung x - WHERE x.notenschluessel_kurzbz = 'CYNOTEN' AND x.punkte = a.punkte); - --- Set the semester explicitly: getKurzbzForLv() builds "... AND studiensemester_kurzbz = ? OR --- studiensemester_kurzbz IS NULL" without parentheses, so a NULL-semester assignment would apply --- to every Lehrveranstaltung through AND/OR precedence. -INSERT INTO lehre.tbl_notenschluesselzuordnung - (notenschluessel_kurzbz, lehrveranstaltung_id, studiensemester_kurzbz) -SELECT 'CYNOTEN', lv.lv_id, sem.kurzbz - FROM lv, sem - WHERE lv.main - AND NOT EXISTS (SELECT 1 FROM lehre.tbl_notenschluesselzuordnung z - WHERE z.notenschluessel_kurzbz = 'CYNOTEN' - AND z.lehrveranstaltung_id = lv.lv_id - AND z.studiensemester_kurzbz = sem.kurzbz); - -COMMIT; - --- Fires if the view stays empty anyway, which is the bug this seeder exists to fix. -DO $$ -DECLARE v_count integer; -BEGIN - SELECT count(*) INTO v_count - FROM campus.vw_student_lehrveranstaltung v, sem - WHERE v.lehrveranstaltung_id = 5221 AND v.studiensemester_kurzbz = sem.kurzbz; - - IF v_count = 0 THEN - RAISE EXCEPTION 'No students in LV 5221 (%), fixture unusable.', (SELECT kurzbz FROM sem); - END IF; - - RAISE NOTICE 'OK: % students in LV 5221 (%)', v_count, (SELECT kurzbz FROM sem); -END $$; - -SELECT (SELECT kurzbz FROM sem) AS semester, - (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem - WHERE v.lehrveranstaltung_id = 5221 AND v.studiensemester_kurzbz = sem.kurzbz) AS lv5221, - (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem - WHERE v.lehrveranstaltung_id = 5121 AND v.studiensemester_kurzbz = sem.kurzbz) AS lv5121, - (SELECT note FROM lehre.tbl_note WHERE bezeichnung = 'entschuldigt') AS entschuldigt, - (SELECT note FROM lehre.tbl_note WHERE bezeichnung = 'Noch nicht eingetragen') AS noch_nicht, - (SELECT count(*) FROM lehre.tbl_notenschluesselaufteilung - WHERE notenschluessel_kurzbz = 'CYNOTEN') AS notenschluessel; diff --git a/system/seeders/017_schema_grants.sql b/system/seeders/017_schema_grants.sql deleted file mode 100644 index 6b8582c8a..000000000 --- a/system/seeders/017_schema_grants.sql +++ /dev/null @@ -1,40 +0,0 @@ --- Vollzugriff auf ALLE Anwendungsschemata für alle DB-Rollen. - -DO $$ -DECLARE - v_grantee text; - v_target text; - v_schema text; - v_grantees text[] := ARRAY['web', 'vilesci', 'wawi', 'admin', 'PUBLIC']; - v_done integer := 0; -BEGIN - FOREACH v_grantee IN ARRAY v_grantees - LOOP - IF v_grantee = 'PUBLIC' THEN - v_target := 'PUBLIC'; - ELSE - CONTINUE WHEN NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = v_grantee); - v_target := quote_ident(v_grantee); - END IF; - - FOR v_schema IN - SELECT nspname - FROM pg_namespace - WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' - ORDER BY nspname - LOOP - EXECUTE format('GRANT ALL ON SCHEMA %I TO %s', v_schema, v_target); - EXECUTE format('GRANT ALL ON ALL TABLES IN SCHEMA %I TO %s', v_schema, v_target); - EXECUTE format('GRANT ALL ON ALL SEQUENCES IN SCHEMA %I TO %s', v_schema, v_target); - EXECUTE format('GRANT ALL ON ALL FUNCTIONS IN SCHEMA %I TO %s', v_schema, v_target); - - EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON TABLES TO %s', v_schema, v_target); - EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON SEQUENCES TO %s', v_schema, v_target); - EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON FUNCTIONS TO %s', v_schema, v_target); - - v_done := v_done + 1; - END LOOP; - END LOOP; - - RAISE NOTICE 'Grants auf % Schema/Rollen-Kombinationen vergeben.', v_done; -END $$; diff --git a/system/seeders/013_studiengang_5.sql b/system/seeders/TST60873_000_GesamtnoteneingabeCis4.sql similarity index 56% rename from system/seeders/013_studiengang_5.sql rename to system/seeders/TST60873_000_GesamtnoteneingabeCis4.sql index 682ff9325..7ead314e5 100644 --- a/system/seeders/013_studiengang_5.sql +++ b/system/seeders/TST60873_000_GesamtnoteneingabeCis4.sql @@ -1,3 +1,25 @@ +-- Seeder of feature-60873/GesamtnoteneingabeCis4. A "-- ==== ====" line starts a group; tests/cypress/tools/dbCheck.js applies single groups. + +-- ==== helper_functions ==== +-- Semester helpers for group studiengang_5. BS001_helper_functions.sql does not define them. + +CREATE OR REPLACE FUNCTION CurrentSemester() RETURNS varchar(32) AS $$ +DECLARE res varchar(32); + BEGIN + SELECT studiensemester_kurzbz into res FROM public.tbl_studiensemester WHERE start<=now() AND ende>=now() ORDER BY start DESC LIMIT 1; + return res; + END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION LastActiveSemester() RETURNS varchar(32) AS $$ +DECLARE res varchar(32); + BEGIN + SELECT studiensemester_kurzbz into res FROM public.tbl_studiensemester WHERE start<=now() ORDER BY start DESC LIMIT 1; + return res; + END; +$$ LANGUAGE plpgsql; + +-- ==== studiengang_5 ==== -- Demodaten fuer Studiengang 5: Organisationseinheit, Studienordnung, Studiengang, Lehrveranstaltungen INSERT INTO public.tbl_organisationseinheit (oe_kurzbz, oe_parent_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv, mailverteiler, freigabegrenze, kurzzeichen, lehre, standort, warn_semesterstunden_frei, warn_semesterstunden_fix, standort_id) @@ -229,3 +251,470 @@ INSERT INTO public.tbl_benutzergruppe (uid, gruppe_kurzbz, updateamum, updatevon ('s125b101', 'GRP_51003', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL), ('s125b101', 'GRP_51004', now(), 'demoadmin', now(), 'demoadmin', NULL, NULL) ; + +-- ==== benotungstool_noten ==== +-- Demo data for the Benotungstool / Gesamtnoteneingabe test suite. +-- +-- campus.vw_student_lehrveranstaltung, the source of getStudentsByLv(), links students to +-- Lehreinheiten through tbl_lehreinheitgruppe.gruppe_kurzbz = tbl_benutzergruppe.gruppe_kurzbz AND +-- a matching Studiensemester. +-- +-- RESULT: demolektor1 -> LV 5221 (12 students), demolektor2 -> LV 5121 (6, the foreign LV for the +-- access tests). + +BEGIN; + +-- Test semester: the running one, else the last started. Same rule as the suite. +CREATE TEMP TABLE sem AS +SELECT studiensemester_kurzbz AS kurzbz + FROM public.tbl_studiensemester + WHERE start <= now() + ORDER BY (ende >= now()) DESC, start DESC + LIMIT 1; + +-- The two LV fixtures. Own Lehreinheiten (511xx) so the tempus fixtures 51001-51006 stay untouched. +-- members_up_to = highest person_id that joins this group. +CREATE TEMP TABLE lv AS +SELECT v.*, l.semester + FROM (VALUES + (true, 5221, 51101, 'GRP_CYNOTEN_H', 'Cypress Noten Haupt', 'demolektor1', 512), + (false, 5121, 51102, 'GRP_CYNOTEN_F', 'Cypress Noten Fremd', 'demolektor2', 506) + ) AS v(main, lv_id, le_id, grp, grp_text, lektor, members_up_to) + JOIN lehre.tbl_lehrveranstaltung l ON l.lehrveranstaltung_id = v.lv_id; + +-- The 12 students. person_id is the anchor for every derived key. +CREATE TEMP TABLE stud AS +SELECT id AS person_id, 5000 + id AS prestudent_id, 's525b' || id AS uid + FROM generate_series(501, 512) AS g(id); + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM sem) THEN + RAISE EXCEPTION 'No Studiensemester found, the base dump is missing.'; + END IF; + IF (SELECT count(*) FROM lv) <> 2 THEN + RAISE EXCEPTION 'LV 5221/5121 missing, apply group studiengang_5.'; + END IF; +END $$; + +-- Termin3 is absent from the base dump; without it every Termin3 insert hits a foreign key error. +INSERT INTO lehre.tbl_pruefungstyp (pruefungstyp_kurzbz, beschreibung) +VALUES ('Termin3', '3. Termin') + ON CONFLICT DO NOTHING; + +-- ------------------------------------------------------------------------------------- students +INSERT INTO public.tbl_person (person_id, vorname, nachname, gebdatum, geschlecht, aktiv) +SELECT person_id, 'Noten', 'Student ' || (person_id - 500), '2000-01-15', 'm', true + FROM stud + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_prestudent (prestudent_id, person_id, studiengang_kz) +SELECT prestudent_id, person_id, 5 + FROM stud + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_prestudentstatus + (prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester) +SELECT s.prestudent_id, 'Student', sem.kurzbz, lv.semester + FROM stud s, sem, lv + WHERE lv.main + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_benutzer (uid, person_id, aktiv) +SELECT uid, person_id, true + FROM stud + ON CONFLICT DO NOTHING; + +-- matrikelnr is UNIQUE; scheme of the existing seeders is '251000' + studiengang_kz + person_id +INSERT INTO public.tbl_student + (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe) +SELECT s.uid, '2510005' || s.person_id, s.prestudent_id, 5, lv.semester, '', '' + FROM stud s, lv + WHERE lv.main + ON CONFLICT DO NOTHING; + +-- Lehrverband assignment; (5, , '', '') is created by group studiengang_5. +INSERT INTO public.tbl_studentlehrverband + (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe) +SELECT s.uid, sem.kurzbz, 5, lv.semester, '', '' + FROM stud s, sem, lv + WHERE lv.main + ON CONFLICT DO NOTHING; + +-- ------------------------------------------------------------------- Lehreinheiten and Lektoren +INSERT INTO lehre.tbl_lehreinheit + (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrform_kurzbz, + wochenrythmus, raumtyp, raumtypalternativ, sprache, lehrfach_id) +SELECT lv.le_id, lv.lv_id, sem.kurzbz, 'VO', 1, 'Dummy', 'Dummy', 'German', lv.lv_id + FROM lv, sem + ON CONFLICT DO NOTHING; + +-- Fix the semester if the Lehreinheit is left over from a run in a different one. +UPDATE lehre.tbl_lehreinheit le + SET studiensemester_kurzbz = sem.kurzbz + FROM lv, sem + WHERE le.lehreinheit_id = lv.le_id + AND le.studiensemester_kurzbz IS DISTINCT FROM sem.kurzbz; + +INSERT INTO lehre.tbl_lehreinheitmitarbeiter (lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz) +SELECT le_id, lektor, 'Lektor' + FROM lv + ON CONFLICT DO NOTHING; + +-- --------------------------------------------------------------------------------------- groups +INSERT INTO public.tbl_gruppe (gruppe_kurzbz, studiengang_kz, semester, bezeichnung, aktiv) +SELECT grp, 5, semester, grp_text, true + FROM lv + ON CONFLICT DO NOTHING; + +-- The row the existing seeders lack: attach the group to the Lehreinheit with gruppe_kurzbz set. +-- The primary key is a serial, so NOT EXISTS instead of ON CONFLICT. +INSERT INTO lehre.tbl_lehreinheitgruppe (lehreinheit_id, studiengang_kz, semester, gruppe_kurzbz) +SELECT lv.le_id, 5, lv.semester, lv.grp + FROM lv + WHERE NOT EXISTS (SELECT 1 FROM lehre.tbl_lehreinheitgruppe g + WHERE g.lehreinheit_id = lv.le_id AND g.gruppe_kurzbz = lv.grp); + +-- Membership WITH a semester. The primary key is (uid, gruppe_kurzbz) and excludes the semester, +-- so DO UPDATE repairs a row from an earlier run instead of duplicating it. +INSERT INTO public.tbl_benutzergruppe (uid, gruppe_kurzbz, studiensemester_kurzbz) +SELECT s.uid, lv.grp, sem.kurzbz + FROM stud s, lv, sem + WHERE s.person_id <= lv.members_up_to + ON CONFLICT (uid, gruppe_kurzbz) DO UPDATE + SET studiensemester_kurzbz = EXCLUDED.studiensemester_kurzbz; + +-- -------------------------------------------------------------------------------- Notenschluessel +INSERT INTO lehre.tbl_notenschluessel (notenschluessel_kurzbz, bezeichnung) +VALUES ('CYNOTEN', 'Cypress Testnotenschluessel') + ON CONFLICT DO NOTHING; + +-- getNote() takes the row with the largest punkte value <= the points given. The 0 threshold makes +-- sure every value maps to a grade. Serial primary key, so NOT EXISTS. +INSERT INTO lehre.tbl_notenschluesselaufteilung (notenschluessel_kurzbz, note, punkte) +SELECT 'CYNOTEN', a.note, a.punkte + FROM (VALUES (5, 0.0), (4, 51.0), (3, 64.0), (2, 77.0), (1, 90.0)) AS a(note, punkte) + WHERE NOT EXISTS (SELECT 1 FROM lehre.tbl_notenschluesselaufteilung x + WHERE x.notenschluessel_kurzbz = 'CYNOTEN' AND x.punkte = a.punkte); + +-- Set the semester explicitly: getKurzbzForLv() builds "... AND studiensemester_kurzbz = ? OR +-- studiensemester_kurzbz IS NULL" without parentheses, so a NULL-semester assignment would apply +-- to every Lehrveranstaltung through AND/OR precedence. +INSERT INTO lehre.tbl_notenschluesselzuordnung + (notenschluessel_kurzbz, lehrveranstaltung_id, studiensemester_kurzbz) +SELECT 'CYNOTEN', lv.lv_id, sem.kurzbz + FROM lv, sem + WHERE lv.main + AND NOT EXISTS (SELECT 1 FROM lehre.tbl_notenschluesselzuordnung z + WHERE z.notenschluessel_kurzbz = 'CYNOTEN' + AND z.lehrveranstaltung_id = lv.lv_id + AND z.studiensemester_kurzbz = sem.kurzbz); + +COMMIT; + +-- Fires if the view stays empty anyway, which is the bug this seeder exists to fix. +DO $$ +DECLARE v_count integer; +BEGIN + SELECT count(*) INTO v_count + FROM campus.vw_student_lehrveranstaltung v, sem + WHERE v.lehrveranstaltung_id = 5221 AND v.studiensemester_kurzbz = sem.kurzbz; + + IF v_count = 0 THEN + RAISE EXCEPTION 'No students in LV 5221 (%), fixture unusable.', (SELECT kurzbz FROM sem); + END IF; + + RAISE NOTICE 'OK: % students in LV 5221 (%)', v_count, (SELECT kurzbz FROM sem); +END $$; + +SELECT (SELECT kurzbz FROM sem) AS semester, + (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem + WHERE v.lehrveranstaltung_id = 5221 AND v.studiensemester_kurzbz = sem.kurzbz) AS lv5221, + (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem + WHERE v.lehrveranstaltung_id = 5121 AND v.studiensemester_kurzbz = sem.kurzbz) AS lv5121, + (SELECT note FROM lehre.tbl_note WHERE bezeichnung = 'entschuldigt') AS entschuldigt, + (SELECT note FROM lehre.tbl_note WHERE bezeichnung = 'Noch nicht eingetragen') AS noch_nicht, + (SELECT count(*) FROM lehre.tbl_notenschluesselaufteilung + WHERE notenschluessel_kurzbz = 'CYNOTEN') AS notenschluessel; + +-- ==== schema_grants ==== +-- Vollzugriff auf ALLE Anwendungsschemata für alle DB-Rollen. + +DO $$ +DECLARE + v_grantee text; + v_target text; + v_schema text; + v_grantees text[] := ARRAY['web', 'vilesci', 'wawi', 'admin', 'PUBLIC']; + v_done integer := 0; +BEGIN + FOREACH v_grantee IN ARRAY v_grantees + LOOP + IF v_grantee = 'PUBLIC' THEN + v_target := 'PUBLIC'; + ELSE + CONTINUE WHEN NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = v_grantee); + v_target := quote_ident(v_grantee); + END IF; + + FOR v_schema IN + SELECT nspname + FROM pg_namespace + WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' + ORDER BY nspname + LOOP + EXECUTE format('GRANT ALL ON SCHEMA %I TO %s', v_schema, v_target); + EXECUTE format('GRANT ALL ON ALL TABLES IN SCHEMA %I TO %s', v_schema, v_target); + EXECUTE format('GRANT ALL ON ALL SEQUENCES IN SCHEMA %I TO %s', v_schema, v_target); + EXECUTE format('GRANT ALL ON ALL FUNCTIONS IN SCHEMA %I TO %s', v_schema, v_target); + + EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON TABLES TO %s', v_schema, v_target); + EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON SEQUENCES TO %s', v_schema, v_target); + EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON FUNCTIONS TO %s', v_schema, v_target); + + v_done := v_done + 1; + END LOOP; + END LOOP; + + RAISE NOTICE 'Grants auf % Schema/Rollen-Kombinationen vergeben.', v_done; +END $$; + +-- ==== benotungstool_berechtigungen ==== +-- Benotungstool permissions for the demo accounts. Without them every endpoint answers 403. +-- +-- demolektor1 teacher; no oe_kurzbz - assertLvAccess scopes him by the Lehreinheiten he teaches +-- demoassistenz programme assistant for stg3 and stg5 (test courses 5221 and 5121 live in stg5) +-- +-- Idempotent. + +BEGIN; + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM public.tbl_benutzer WHERE uid = 'demolektor1') THEN + RAISE EXCEPTION 'Benutzer demolektor1 fehlt, die Basisdaten sind unvollstaendig.'; + END IF; + IF NOT EXISTS (SELECT 1 FROM public.tbl_benutzer WHERE uid = 'demoassistenz') THEN + RAISE EXCEPTION 'Benutzer demoassistenz fehlt, die Basisdaten sind unvollstaendig.'; + END IF; +END $$; + +-- Der Lektor: darf das Werkzeug öffnen, sieht aber nur seine eigenen Lehrveranstaltungen. +INSERT INTO system.tbl_benutzerrolle (uid, berechtigung_kurzbz, art, oe_kurzbz, insertvon, insertamum) +SELECT 'demolektor1', 'lehre/benotungstool', 'suid', NULL, 'seeder', now() + WHERE NOT EXISTS ( + SELECT 1 FROM system.tbl_benutzerrolle + WHERE uid = 'demolektor1' + AND berechtigung_kurzbz = 'lehre/benotungstool' + AND oe_kurzbz IS NULL + ); + +-- Die Assistenz: darf die Lehrveranstaltungen ihrer Studiengänge benoten. +INSERT INTO system.tbl_benutzerrolle (uid, berechtigung_kurzbz, art, oe_kurzbz, insertvon, insertamum) +SELECT 'demoassistenz', 'lehre/benotungstool_assistenz', 'suid', oe.oe_kurzbz, 'seeder', now() + FROM (VALUES ('stg3'), ('stg5')) AS oe(oe_kurzbz) + WHERE NOT EXISTS ( + SELECT 1 FROM system.tbl_benutzerrolle b + WHERE b.uid = 'demoassistenz' + AND b.berechtigung_kurzbz = 'lehre/benotungstool_assistenz' + AND b.oe_kurzbz = oe.oe_kurzbz + ); + +COMMIT; + +-- Zurücknehmen: +-- DELETE FROM system.tbl_benutzerrolle +-- WHERE insertvon = 'seeder' AND berechtigung_kurzbz LIKE 'lehre/benotungstool%'; + +-- ==== benotungstool_fixture_erweitert ==== +-- Extensions of the Benotungstool fixture. Apply after group benotungstool_noten. +-- +-- LE 51103 a second Lehreinheit of LV 5221 with two Lektoren and two students of its own. The write +-- paths replace a foreign Lehreinheit, and the grader rules need a Lehreinheit with more +-- than one Lektor. demoadmin sorts before demolektor1, so "the caller" and "the first +-- Lektor" give different results. +-- LE 51104 demolektor1 in LV 5221 in the last Sommersemester with a passed grade entry deadline. +-- The deadline tests need a semester in which the user teaches. +-- Vorlagen demo texts for 'Notenfreigabe' and 'Sancho_Mail_Template'. Without them every release +-- mail has an empty body. The dbupdate script creates only the tbl_vorlage row. +-- +-- The new students sort after 'Student 1'..'Student 12', so the first twelve students of the suite +-- stay the same. Idempotent. + +BEGIN; + +-- group benotungstool_noten creates temp tables with the same names when both groups run in one session +DROP TABLE IF EXISTS pg_temp.sem, pg_temp.sem_frist, pg_temp.lv, pg_temp.stud; + +-- Test semester: the running one, else the last started. Same rule as the suite and group benotungstool_noten. +CREATE TEMP TABLE sem AS +SELECT studiensemester_kurzbz AS kurzbz + FROM public.tbl_studiensemester + WHERE start <= now() + ORDER BY (ende >= now()) DESC, start DESC + LIMIT 1; + +-- The last Sommersemester after its deadline. NOTENEINTRAGUNGSFRIST_SS defaults to 15 November. +CREATE TEMP TABLE sem_frist AS +SELECT studiensemester_kurzbz AS kurzbz + FROM public.tbl_studiensemester + WHERE studiensemester_kurzbz ~ '^SS[0-9]{4}$' + AND make_date(substring(studiensemester_kurzbz FROM 3 FOR 4)::int, 11, 15) < current_date + ORDER BY start DESC + LIMIT 1; + +CREATE TEMP TABLE lv AS +SELECT lehrveranstaltung_id AS lv_id, semester + FROM lehre.tbl_lehrveranstaltung + WHERE lehrveranstaltung_id = 5221; + +CREATE TEMP TABLE stud AS +SELECT id AS person_id, 5000 + id AS prestudent_id, 's525b' || id AS uid, vorname + FROM (VALUES (513, 'Eins'), (514, 'Zwei')) AS g(id, vorname); + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM sem) THEN + RAISE EXCEPTION 'No Studiensemester found, the base dump is missing.'; + END IF; + IF NOT EXISTS (SELECT 1 FROM sem_frist) THEN + RAISE EXCEPTION 'No Sommersemester with a passed grade entry deadline.'; + END IF; + IF NOT EXISTS (SELECT 1 FROM lv) THEN + RAISE EXCEPTION 'LV 5221 missing, apply group studiengang_5.'; + END IF; + IF NOT EXISTS (SELECT 1 FROM lehre.tbl_lehreinheit WHERE lehreinheit_id = 51101) THEN + RAISE EXCEPTION 'Lehreinheit 51101 missing, apply group benotungstool_noten first.'; + END IF; + IF (SELECT count(*) FROM public.tbl_mitarbeiter WHERE mitarbeiter_uid IN ('demoadmin', 'demolektor1')) <> 2 THEN + RAISE EXCEPTION 'demoadmin or demolektor1 missing, apply BS002_mitarbeiter.sql.'; + END IF; +END $$; + +-- ------------------------------------------------------------------------------------- students +INSERT INTO public.tbl_person (person_id, vorname, nachname, gebdatum, geschlecht, aktiv) +SELECT person_id, vorname, 'Zweitgruppe', '2000-01-15', 'm', true + FROM stud + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_prestudent (prestudent_id, person_id, studiengang_kz) +SELECT prestudent_id, person_id, 5 + FROM stud + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_prestudentstatus + (prestudent_id, status_kurzbz, studiensemester_kurzbz, ausbildungssemester) +SELECT s.prestudent_id, 'Student', sem.kurzbz, lv.semester + FROM stud s, sem, lv + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_benutzer (uid, person_id, aktiv) +SELECT uid, person_id, true + FROM stud + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_student + (student_uid, matrikelnr, prestudent_id, studiengang_kz, semester, verband, gruppe) +SELECT s.uid, '2510005' || s.person_id, s.prestudent_id, 5, lv.semester, '', '' + FROM stud s, lv + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_studentlehrverband + (student_uid, studiensemester_kurzbz, studiengang_kz, semester, verband, gruppe) +SELECT s.uid, sem.kurzbz, 5, lv.semester, '', '' + FROM stud s, sem, lv + ON CONFLICT DO NOTHING; + +-- ------------------------------------------------------------------------------ Lehreinheit 51103 +INSERT INTO lehre.tbl_lehreinheit + (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrform_kurzbz, + wochenrythmus, raumtyp, raumtypalternativ, sprache, lehrfach_id) +SELECT 51103, lv.lv_id, sem.kurzbz, 'VO', 1, 'Dummy', 'Dummy', 'German', lv.lv_id + FROM lv, sem + ON CONFLICT DO NOTHING; + +UPDATE lehre.tbl_lehreinheit le + SET studiensemester_kurzbz = sem.kurzbz + FROM sem + WHERE le.lehreinheit_id = 51103 + AND le.studiensemester_kurzbz IS DISTINCT FROM sem.kurzbz; + +INSERT INTO lehre.tbl_lehreinheitmitarbeiter (lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz) +SELECT 51103, l.uid, 'Lektor' + FROM (VALUES ('demoadmin'), ('demolektor1')) AS l(uid) + ON CONFLICT DO NOTHING; + +INSERT INTO public.tbl_gruppe (gruppe_kurzbz, studiengang_kz, semester, bezeichnung, aktiv) +SELECT 'GRP_CYNOTEN_Z', 5, semester, 'Cypress Noten Zweitgruppe', true + FROM lv + ON CONFLICT DO NOTHING; + +INSERT INTO lehre.tbl_lehreinheitgruppe (lehreinheit_id, studiengang_kz, semester, gruppe_kurzbz) +SELECT 51103, 5, lv.semester, 'GRP_CYNOTEN_Z' + FROM lv + WHERE NOT EXISTS (SELECT 1 FROM lehre.tbl_lehreinheitgruppe g + WHERE g.lehreinheit_id = 51103 AND g.gruppe_kurzbz = 'GRP_CYNOTEN_Z'); + +-- the students of 51103 are members of this group only, so each has exactly one Lehreinheit +INSERT INTO public.tbl_benutzergruppe (uid, gruppe_kurzbz, studiensemester_kurzbz) +SELECT s.uid, 'GRP_CYNOTEN_Z', sem.kurzbz + FROM stud s, sem + ON CONFLICT (uid, gruppe_kurzbz) DO UPDATE + SET studiensemester_kurzbz = EXCLUDED.studiensemester_kurzbz; + +-- ------------------------------------------------------------------------------ Lehreinheit 51104 +-- getLvForLektorInSemester needs no group, only the Lehreinheit and its Lektor +INSERT INTO lehre.tbl_lehreinheit + (lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, lehrform_kurzbz, + wochenrythmus, raumtyp, raumtypalternativ, sprache, lehrfach_id) +SELECT 51104, lv.lv_id, sf.kurzbz, 'VO', 1, 'Dummy', 'Dummy', 'German', lv.lv_id + FROM lv, sem_frist sf + ON CONFLICT DO NOTHING; + +UPDATE lehre.tbl_lehreinheit le + SET studiensemester_kurzbz = sf.kurzbz + FROM sem_frist sf + WHERE le.lehreinheit_id = 51104 + AND le.studiensemester_kurzbz IS DISTINCT FROM sf.kurzbz; + +INSERT INTO lehre.tbl_lehreinheitmitarbeiter (lehreinheit_id, mitarbeiter_uid, lehrfunktion_kurzbz) +VALUES (51104, 'demolektor1', 'Lektor') + ON CONFLICT DO NOTHING; + +-- ---------------------------------------------------------------------------------------- Vorlagen +INSERT INTO public.tbl_vorlage (vorlage_kurzbz, bezeichnung, anmerkung, mimetype) +VALUES ('Notenfreigabe', 'Notenfreigabe', NULL, 'text/html'), + ('Sancho_Mail_Template', 'Sancho Mail Template', 'Demo layout of the test instance', 'text/html') + ON CONFLICT (vorlage_kurzbz) DO NOTHING; + +-- Placeholders of Noten::sendFreigabeEmail: lektor, lvaname, neuenotencount, studlist, adressen. +-- An existing active text stays. Studiengang 0 and oe 'etw' are the root, as for the other Vorlagen. +INSERT INTO public.tbl_vorlagestudiengang + (vorlage_kurzbz, studiengang_kz, version, text, oe_kurzbz, aktiv, insertamum, insertvon) +SELECT v.kurzbz, 0, 1, v.text, 'etw', true, now(), 'seeder' + FROM (VALUES + ('Notenfreigabe', + '

{lektor} hat {neuenotencount} Note(n) freigegeben: {lvaname}

{studlist}

Empfänger: {adressen}

'), + ('Sancho_Mail_Template', '{content}') + ) AS v(kurzbz, text) + WHERE NOT EXISTS (SELECT 1 FROM public.tbl_vorlagestudiengang x + WHERE x.vorlage_kurzbz = v.kurzbz AND x.aktiv); + +COMMIT; + +DO $$ +BEGIN + IF (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem + WHERE v.lehreinheit_id = 51103 AND v.studiensemester_kurzbz = sem.kurzbz) = 0 THEN + RAISE EXCEPTION 'No students in Lehreinheit 51103 (%), fixture unusable.', (SELECT kurzbz FROM sem); + END IF; +END $$; + +SELECT (SELECT kurzbz FROM sem) AS semester, + (SELECT kurzbz FROM sem_frist) AS semester_frist, + (SELECT count(*) FROM campus.vw_student_lehrveranstaltung v, sem + WHERE v.lehreinheit_id = 51103 AND v.studiensemester_kurzbz = sem.kurzbz) AS le51103_studenten, + (SELECT count(*) FROM lehre.tbl_lehreinheitmitarbeiter + WHERE lehreinheit_id = 51103) AS le51103_lektoren, + (SELECT count(*) FROM public.tbl_vorlagestudiengang + WHERE vorlage_kurzbz IN ('Notenfreigabe', 'Sancho_Mail_Template') AND aktiv) AS vorlagen; diff --git a/system/setup_testinstance.php b/system/setup_testinstance.php deleted file mode 100644 index f76191be0..000000000 --- a/system/setup_testinstance.php +++ /dev/null @@ -1,229 +0,0 @@ - FHComplete-3.3.sql -> - * checksystem.php -> seeders. This script only adds what db_setup.sh does not cover — addon - * dbupdates, extension SQL and a closing health check. - * - * needs psql and db_setup.sh. Connection data comes from config/system.config.inc.php. - */ - -if (php_sapi_name() !== 'cli') { - http_response_code(403); - exit("Command line only.\n"); -} - -error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_WARNING); -set_time_limit(0); -ini_set('memory_limit', '1024M'); - -define('SETUP_ROOT', dirname(__DIR__)); -define('DB_SETUP_SH', '/home/testing/fhc-coreutils/tests/automated/db_setup.sh'); - -function out($msg = '') { fwrite(STDOUT, $msg . PHP_EOL); } -function step($msg) { out(''); out('=== ' . $msg . ' ' . str_repeat('=', max(0, 62 - strlen($msg)))); } -function info($msg) { out(' ' . $msg); } -function ok($msg) { out(' + ' . $msg); } -function warn($msg) { out(' ! ' . $msg); } -function bail($msg) { out(''); out(' X ' . $msg); out(''); exit(1); } - -function loadConfig() -{ - $file = SETUP_ROOT . '/config/system.config.inc.php'; - if (!is_file($file)) bail("Config not found: $file"); - - require_once($file); - - // the FHC config sets error_reporting(E_ALL); restore ours, or every include of the legacy - // classes prints deprecation notices over the output - error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_WARNING); - - foreach (['DB_HOST', 'DB_NAME', 'DB_USER'] as $const) { - if (!defined($const)) bail("$const is not defined in $file."); - } - putenv('PGPASSWORD=' . (defined('DB_PASSWORD') ? DB_PASSWORD : '')); -} - -function connectDb() -{ - $conn = @pg_connect(sprintf( - 'host=%s port=%s dbname=%s user=%s password=%s', - DB_HOST, defined('DB_PORT') ? DB_PORT : '5432', DB_NAME, DB_USER, - defined('DB_PASSWORD') ? DB_PASSWORD : '' - )); - if ($conn === false) bail('Cannot connect to ' . DB_NAME . '@' . DB_HOST . ' as ' . DB_USER . '.'); - return $conn; -} - -function scalar($conn, $sql) -{ - $res = @pg_query($conn, $sql); - if ($res === false) return null; - $row = pg_fetch_row($res); - return $row ? $row[0] : null; -} - -/** Runs one .sql file. Returns the error count; "already exists" is normal on a repeat run. */ -function psqlFile($file) -{ - exec(sprintf('psql -h %s -p %s -U %s -d %s -f %s 2>&1', - escapeshellarg(DB_HOST), escapeshellarg(defined('DB_PORT') ? DB_PORT : '5432'), - escapeshellarg(DB_USER), escapeshellarg(DB_NAME), escapeshellarg($file)), $lines); - - $errors = 0; - foreach ($lines as $line) { - if (stripos($line, 'ERROR') !== false && stripos($line, 'already exists') === false) $errors++; - } - return $errors; -} - -/** Guards, before anything is dropped: --setup empties the target, so refuse anything but cy-*. */ -function preflight() -{ - step('preflight'); - - if (!shell_exec('command -v psql')) bail('psql is missing. Run this on the dev machine.'); - if (!is_file(DB_SETUP_SH)) bail('db_setup.sh not found: ' . DB_SETUP_SH); - - if (strpos(DB_NAME, 'cy-') !== 0) { - bail("Target is '" . DB_NAME . "'. --setup drops every schema and only touches cy-* databases."); - } - - $seeders = glob(SETUP_ROOT . '/system/seeders/*.sql'); - if (!$seeders) bail('No seeders in ' . SETUP_ROOT . '/system/seeders/ — the rebuild would leave an empty database.'); - - ok(count($seeders) . ' seeders, target ' . DB_NAME); -} - -/** Output is passed through verbatim, checksystem.php's HTML included. */ -function rebuild() -{ - step('db_setup.sh'); - info('truncate -> FHComplete-3.3.sql -> checksystem.php -> seeders'); - out(''); - - passthru(escapeshellarg(DB_SETUP_SH) . ' ' . escapeshellarg(SETUP_ROOT), $code); - if ($code !== 0) bail('db_setup.sh failed with exit code ' . $code . '.'); - - ok('database rebuilt'); -} - -/** - * Addon DB updates. Their install.php files are web installers and empty stubs; the DDL sits in - * addons//system/dbupdate_*.php and expects CHECKSYSTEM and a $db in scope. - */ -function runAddons() -{ - step('addons'); - - $files = glob(SETUP_ROOT . '/addons/*/system/dbupdate_*.php'); - if (!$files) { info('none found'); return; } - - if (!defined('CHECKSYSTEM')) define('CHECKSYSTEM', 'setup_testinstance'); - require_once(SETUP_ROOT . '/include/basis_db.class.php'); - $db = new basis_db(); - - foreach ($files as $file) { - $name = basename(dirname(dirname($file))) . '/' . basename($file); - ob_start(); - try { - require($file); - ob_end_clean(); - ok($name); - } catch (Throwable $t) { - ob_end_clean(); - warn($name . ': ' . $t->getMessage()); - } - } -} - -/** Extension SQL, for an instance that has the files but never ran their sql//*.sql. */ -function runExtensions() -{ - step('extensions'); - - $dirs = glob(SETUP_ROOT . '/application/extensions/*/sql', GLOB_ONLYDIR); - if (!$dirs) { info('none found'); return; } - - foreach ($dirs as $dir) { - // every version the extension ships, oldest first; a test instance always wants the newest schema - $files = glob($dir . '/*/*.sql') ?: []; - sort($files, SORT_NATURAL); - - $errors = 0; - foreach ($files as $file) $errors += psqlFile($file); - - $label = sprintf('%s (%d file(s)%s)', basename(dirname($dir)), count($files), $errors ? ", $errors errors" : ''); - if ($errors) warn($label); else ok($label); - } -} - -/** - * General signs of a usable instance only. Whether a given suite's fixture is in place is that - * suite's own business (see tests/cypress/tools/dbCheck.js). - */ -function verify($conn) -{ - step('verify'); - - $checks = [ - // dump applied - ['Tables', "SELECT count(*) FROM information_schema.tables - WHERE table_schema IN ('public','lehre','campus')", function ($v) { return $v > 200; }], - // checksystem.php ran - ['Phrases', "SELECT count(*) FROM system.tbl_phrase", function ($v) { return $v > 0; }], - ['Permissions', "SELECT count(*) FROM system.tbl_berechtigung", function ($v) { return $v > 0; }], - // seeders ran - ['Studiensemester', "SELECT count(*) FROM public.tbl_studiensemester - WHERE start <= now()", function ($v) { return $v > 0; }], - ['Mitarbeiter', "SELECT count(*) FROM public.tbl_mitarbeiter", function ($v) { return $v > 0; }], - ['Studenten', "SELECT count(*) FROM public.tbl_student", function ($v) { return $v > 0; }], - ]; - - $failed = 0; - foreach ($checks as list($label, $sql, $test)) { - $value = scalar($conn, $sql); - $passed = $test($value); - if (!$passed) $failed++; - out(sprintf(' [%s] %-20s %s', $passed ? 'OK ' : 'XX ', $label, $value === null ? '(null)' : $value)); - } - - return $failed === 0; -} - -$flags = array_slice($argv, 1); -$setup = in_array('--setup', $flags, true); -$verify = in_array('--verify', $flags, true); - -// --setup must be spelled out: the run empties the target database. -if (!$setup && !$verify) { - out(''); - out(' php system/setup_testinstance.php --setup rebuild the database, then verify'); - out(' php system/setup_testinstance.php --verify verify only, write nothing'); - out(''); - exit(0); -} - -loadConfig(); - -out(''); -out(' Target : ' . DB_NAME . ' @ ' . DB_HOST); - -if ($setup) { - preflight(); - rebuild(); - runAddons(); - runExtensions(); -} - -$success = verify(connectDb()); - -out(''); -out($success ? ' Done.' : ' Finished with findings, see above.'); -out(''); - -exit($success ? 0 : 1); diff --git a/tests/cypress/e2e/specs/api/noten/noten.access.cy.js b/tests/cypress/e2e/specs/api/noten/noten.access.cy.js index 956783f64..142501f5f 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.access.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.access.cy.js @@ -6,40 +6,30 @@ */ import { notenApi } from "../../../../support/api/notenApi"; -import { - expectAuthError, - expectNotenError, - expectNotenSuccess, -} from "../../../../support/helpers/notenErrors"; +import { expectAuthError, expectNotenError, expectNotenSuccess } from "../../../../support/helpers/notenErrors"; import { attemptDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, } from "../../../../support/helpers/notenTestData"; +import { skipWenn } from "../../../../support/helpers/notenConfig"; import { assistenzAuth, - assistenzConfigured, assistenzKontext, assistenzLvMitLehreinheiten, + requireAssistenz, } from "../../../../support/helpers/notenAssistenz"; const NOTEN_API = "/index.ci.php/api/frontend/v1/Noten"; -const teacherConfigured = () => - Boolean(Cypress.env("NOTEN_TEACHER_USER") && Cypress.env("NOTEN_FOREIGN_LV_ID")); +const teacherConfigured = () => Boolean(Cypress.env("NOTEN_TEACHER_USER") && Cypress.env("NOTEN_FOREIGN_LV_ID")); const getAs = (auth, path, qs) => cy.request({ method: "GET", url: `${NOTEN_API}/${path}`, qs, auth, failOnStatusCode: false }); -const skipOhneAssistenz = (test) => { - if (assistenzConfigured()) return; - Cypress.log({ name: "skip", message: "Übersprungen: NOTEN_ASSISTENZ_USER / NOTEN_ASSISTENZ_PASSWORD fehlen." }); - test.skip(); -}; - /** A getStudentenNoten call as an explicitly chosen user (or with no credentials at all). */ const getStudentenNotenAs = (auth, lvId, semKurzbz) => cy.request({ @@ -50,7 +40,7 @@ const getStudentenNotenAs = (auth, lvId, semKurzbz) => failOnStatusCode: false, }); -describe("Noten API - access control", () => { +describe("Noten API - Zugriffsschutz", () => { let ctx; before(() => { @@ -59,11 +49,11 @@ describe("Noten API - access control", () => { }); }); - it("rejects requests that are not authenticated", () => { + it("lehnt eine Anfrage ohne Anmeldung ab", () => { cy.clearAllCookies(); // otherwise the previous login is still active - cy.request({ method: "GET", url: `${NOTEN_API}/getCisConfig`, failOnStatusCode: false }).then( - (response) => expectAuthError(response), + cy.request({ method: "GET", url: `${NOTEN_API}/getCisConfig`, failOnStatusCode: false }).then((response) => + expectAuthError(response), ); cy.request({ @@ -74,8 +64,8 @@ describe("Noten API - access control", () => { }).then((response) => expectAuthError(response)); }); - describe("the configured API user", () => { - it("can read the students of the test LV", () => { + describe("der konfigurierte API-Benutzer", () => { + it("liest die Studierenden der Test-LV", () => { notenApi.getStudentenNoten(ctx.lvId, ctx.semKurzbz).then((response) => { const data = expectNotenSuccess(response, "getStudentenNoten on the own/admin LV"); expect(data[0], "student list").to.be.an("array").and.not.be.empty; @@ -83,18 +73,15 @@ describe("Noten API - access control", () => { }); }); - describe("teacher scoping", () => { + describe("Scope der Lehrperson", () => { beforeEach(function () { - if (!teacherConfigured()) { - Cypress.log({ - name: "skip", - message: - "Skipped: needs NOTEN_TEACHER_USER / NOTEN_TEACHER_PASSWORD and NOTEN_FOREIGN_LV_ID " + - "(an LV that teacher does NOT teach). This API has no impersonation, so a second " + - "real login is required.", - }); - this.skip(); - } + skipWenn( + this, + !teacherConfigured(), + "Übersprungen: braucht NOTEN_TEACHER_USER / NOTEN_TEACHER_PASSWORD und NOTEN_FOREIGN_LV_ID " + + "(eine LV, die diese Lehrperson NICHT unterrichtet). Die API kennt keine Identitätsübernahme, " + + "deshalb braucht der Test ein zweites echtes Konto.", + ); // cy.request reuses the session cookie of the previous (admin) call and the server prefers // it over the Basic header - without this every test here silently runs as the admin user. cy.clearAllCookies(); @@ -106,17 +93,13 @@ describe("Noten API - access control", () => { }); // assertLvAccess denies through terminateWithError -> 500 + phrase, not a 401. - it("denies a teacher access to an LV they do not teach", () => { - getStudentenNotenAs( - teacherAuth(), - Cypress.env("NOTEN_FOREIGN_LV_ID"), - ctx.semKurzbz, - ).then((response) => { + it("verweigert einer Lehrperson eine fremde LV", () => { + getStudentenNotenAs(teacherAuth(), Cypress.env("NOTEN_FOREIGN_LV_ID"), ctx.semKurzbz).then((response) => { expectNotenError(response, "keineBerechtigungNoten"); }); }); - it("denies a teacher writing a grade in an LV they do not teach", () => { + it("verweigert einer Lehrperson die Note in einer fremden LV", () => { cy.request({ method: "POST", url: `${NOTEN_API}/saveNotenvorschlag`, @@ -134,7 +117,7 @@ describe("Noten API - access control", () => { }); }); - it("denies a teacher the Lehreinheiten of an LV they do not teach", () => { + it("verweigert einer Lehrperson die Lehreinheiten einer fremden LV", () => { getAs(teacherAuth(), "getLehreinheitenFuerLv", { lv_id: Cypress.env("NOTEN_FOREIGN_LV_ID"), sem_kurzbz: ctx.semKurzbz, @@ -147,7 +130,7 @@ describe("Noten API - access control", () => { describe("getBenotungstoolContext als Assistenz", () => { beforeEach(function () { - skipOhneAssistenz(this); + requireAssistenz(this); cy.clearAllCookies(); }); @@ -223,12 +206,12 @@ describe("Noten API - access control", () => { i >= ctx.students.length ? cy.wrap(null, { log: false }) : cy - .task("noten:db:andereLvNoten", { - lvId: ctx.lvId, - semKurzbz: ctx.semKurzbz, - studentUid: ctx.students[i].uid, - }) - .then((anzahl) => (anzahl === 0 ? ctx.students[i] : suche(i + 1))); + .task("noten:db:andereLvNoten", { + lvId: ctx.lvId, + semKurzbz: ctx.semKurzbz, + studentUid: ctx.students[i].uid, + }) + .then((anzahl) => (anzahl === 0 ? ctx.students[i] : suche(i + 1))); suche(0).then((found) => { student = found; @@ -236,21 +219,18 @@ describe("Noten API - access control", () => { }); it("ändert bei lv_id=null keine LV-Note", function () { - if (!student) { - Cypress.log({ name: "skip", message: "Übersprungen: jeder Studierende hat LV-Noten in anderen LVs." }); - this.skip(); - } + skipWenn(this, !student, "Übersprungen: jeder Studierende hat LV-Noten in anderen LVs."); const g2 = ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); resetNotenState(ctx); - seedBaseline(ctx, student.uid); + seedBaseline(ctx, student); notenApi .saveNotenvorschlag(null, ctx.semKurzbz, student.uid, g2) .then((response) => expectNotenError(response, "wrongParameters")); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(String(row.note), "die LV-Note bleibt").to.eq(String(ctx.notes.negativ)); }); }); @@ -260,7 +240,9 @@ describe("Noten API - access control", () => { // W10: Der Endpunkt liefert alle Lehreinheiten der LV, für jede Rolle mit Zugriff auf die LV. describe("getLehreinheitenFuerLv", () => { const lehreinheitenDerLv = (lvId) => - cy.task("noten:db:lehreinheitenDerLv", { lvId, semKurzbz: ctx.semKurzbz }).then((ids) => ids.map(String).sort()); + cy + .task("noten:db:lehreinheitenDerLv", { lvId, semKurzbz: ctx.semKurzbz }) + .then((ids) => ids.map(String).sort()); // die Abfrage liefert eine Zeile je Gruppe, eine Lehreinheit kann also mehrfach vorkommen const idsOf = (rows) => [...new Set(rows.map((r) => String(r.lehreinheit_id)))].sort(); @@ -272,8 +254,18 @@ describe("Noten API - access control", () => { const rows = expectNotenSuccess(response, "getLehreinheitenFuerLv"); expect(rows, "Lehreinheiten").to.be.an("array").and.not.be.empty; expect(rows[0], "Felder einer Lehreinheit").to.include.all.keys( - "lehreinheit_id", "lehrveranstaltung_id", "lehrform_kurzbz", "direktinskription", "semester", - "verband", "gruppe", "gruppe_kurzbz", "kurzbz", "kurzbzlang", "termincount", "studentcount", + "lehreinheit_id", + "lehrveranstaltung_id", + "lehrform_kurzbz", + "direktinskription", + "semester", + "verband", + "gruppe", + "gruppe_kurzbz", + "kurzbz", + "kurzbzlang", + "termincount", + "studentcount", ); lehreinheitenDerLv(ctx.lvId).then((ids) => { @@ -283,7 +275,7 @@ describe("Noten API - access control", () => { }); it("liefert einer Assistenz die Lehreinheiten einer LV ihres Studiengangs", function () { - skipOhneAssistenz(this); + requireAssistenz(this); cy.clearAllCookies(); assistenzLvMitLehreinheiten(ctx.semKurzbz).then((ziel) => { diff --git a/tests/cypress/e2e/specs/api/noten/noten.bulk.cy.js b/tests/cypress/e2e/specs/api/noten/noten.bulk.cy.js index cab6e785e..e5bea18ea 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.bulk.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.bulk.cy.js @@ -4,31 +4,24 @@ */ import { notenApi } from "../../../../support/api/notenApi"; -import { - expectBulkRowAccepted, - expectBulkRowError, - expectNotenSuccess, -} from "../../../../support/helpers/notenErrors"; +import { expectBulkRowAccepted, expectBulkRowError, expectNotenSuccess } from "../../../../support/helpers/notenErrors"; import { requireKonfiguration, + requireNotenModus, requirePunkteModus, requireWiederholung, } from "../../../../support/helpers/notenConfig"; import { attemptDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, } from "../../../../support/helpers/notenTestData"; -import { - addPruefung, - attemptsOfStudent, - readState, -} from "../../../../support/helpers/notenScenario"; +import { addPruefung, attemptsOfStudent, readStateViaApi } from "../../../../support/helpers/notenScenario"; -describe("Noten API - bulk paths", () => { +describe("Noten API - Sammelpfade", () => { let ctx; before(() => { @@ -58,13 +51,13 @@ describe("Noten API - bulk paths", () => { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF", true); }); - it("rejects only the row that breaks a §1 rule and accepts the rest", () => { + it("lehnt nur die Zeile gegen eine §1-Regel ab und nimmt die übrigen an", () => { const atCap = ctx.students[0]; const fresh = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, atCap.uid); - seedBaseline(ctx, fresh.uid); + seedBaseline(ctx, atCap); + seedBaseline(ctx, fresh); const datum = bisZurGrenze(atCap); @@ -86,7 +79,7 @@ describe("Noten API - bulk paths", () => { expectBulkRowAccepted(data, fresh.uid); }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const created = attemptsOfStudent(data, fresh.uid); expect( created.map((p) => String(p.datum).slice(0, 10)), @@ -94,7 +87,6 @@ describe("Noten API - bulk paths", () => { ).to.include(datum); }); }); - }); describe("savePruefungenBulk", () => { @@ -104,20 +96,17 @@ describe("Noten API - bulk paths", () => { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF", true); }); - it("applies the §1 rules per row", function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus leitet der Endpunkt die Note aus den Punkten ab; die Regelprüfung - // deckt der punktebasierte Test unten ab - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv, siehe den punktebasierten Test." }); - this.skip(); - } + it("wendet die §1-Regeln je Zeile an", function () { + // im Punktemodus leitet der Endpunkt die Note aus den Punkten ab; die Regelprüfung + // deckt der punktebasierte Test unten ab + requireNotenModus(this, ctx); const atCap = ctx.students[0]; const fresh = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, atCap.uid); - seedBaseline(ctx, fresh.uid); + seedBaseline(ctx, atCap); + seedBaseline(ctx, fresh); const datum = bisZurGrenze(atCap); @@ -157,8 +146,8 @@ describe("Noten API - bulk paths", () => { const punkte = 70; resetNotenState(ctx); - seedBaseline(ctx, atCap.uid); - seedBaseline(ctx, fresh.uid); + seedBaseline(ctx, atCap); + seedBaseline(ctx, fresh); const datum = bisZurGrenze(atCap); const zeile = (student) => ({ @@ -178,8 +167,10 @@ describe("Noten API - bulk paths", () => { notenApi.getNoteByPunkte(punkte, ctx.lvId, ctx.semKurzbz).then((antwort) => { const erwartet = antwort.body.data; - readState(ctx).then((data) => { - const neu = attemptsOfStudent(data, fresh.uid).find((p) => String(p.datum).slice(0, 10) === datum); + readStateViaApi(ctx).then((data) => { + const neu = attemptsOfStudent(data, fresh.uid).find( + (p) => String(p.datum).slice(0, 10) === datum, + ); expect(neu, "der neue Termin").to.exist; expect(String(neu.note), "die aus den Punkten abgeleitete Note").to.eq(String(erwartet)); }); @@ -189,12 +180,9 @@ describe("Noten API - bulk paths", () => { }); describe("saveNotenvorschlagBulk", () => { - it("writes an LV note for every row", function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus kommt die Note aus dem Notenschlüssel, siehe den Punktemodus-Block - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv." }); - this.skip(); - } + it("schreibt für jede Zeile eine LV-Note", function () { + // im Punktemodus kommt die Note aus dem Notenschlüssel, siehe den Punktemodus-Block + requireNotenModus(this, ctx); const [a, b] = ctx.students; @@ -212,12 +200,12 @@ describe("Noten API - bulk paths", () => { expectBulkRowAccepted(data, b.uid); }); - readLvGesamtnote(ctx, a.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, a.uid).then((row) => { expect(row, `row for ${a.uid}`).to.not.be.null; expect(String(row.note)).to.eq(String(ctx.gradeNotes[0])); }); - readLvGesamtnote(ctx, b.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, b.uid).then((row) => { expect(row, `row for ${b.uid}`).to.not.be.null; expect(String(row.note)).to.eq(String(ctx.gradeNotes[1])); }); @@ -246,7 +234,7 @@ describe("Noten API - bulk paths", () => { expectBulkRowAccepted(data, mitPunkten.uid); }); - readLvGesamtnote(ctx, ohnePunkte.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, ohnePunkte.uid).then((row) => { expect(row, "die übersprungene Zeile bleibt ungeschrieben").to.be.null; }); }); diff --git a/tests/cypress/e2e/specs/api/noten/noten.freigabe.cy.js b/tests/cypress/e2e/specs/api/noten/noten.freigabe.cy.js index f3d9e51d1..035f5beb6 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.freigabe.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.freigabe.cy.js @@ -18,7 +18,7 @@ import { attemptDate, baselineBenotungsdatum, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -29,12 +29,11 @@ import { attemptsOfStudent, givenBaseline, lvNoteOf, - readState, + readStateViaApi, verlaufOfStudent, } from "../../../../support/helpers/notenScenario"; -const freigabePassword = () => - Cypress.env("NOTEN_FREIGABE_PASSWORD") || Cypress.env("adminpassword"); +const freigabePassword = () => Cypress.env("NOTEN_FREIGABE_PASSWORD") || Cypress.env("adminpassword"); /** The payload shape saveStudentenNoten expects per student (see the studlist builder). */ const notenPayload = (student, noteBezeichnung) => ({ @@ -55,8 +54,8 @@ describe("Noten API - Notenfreigabe", () => { }); }); - describe("password gate", () => { - it("rejects a Freigabe with a wrong password and changes nothing", function () { + describe("Passwortschutz", () => { + it("lehnt eine Freigabe mit falschem Passwort ab und ändert nichts", function () { // ohne Passwortpflicht gibt der Aufruf frei requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_FREIGABE_PASSWORT", true); requireDbReset(); @@ -64,53 +63,42 @@ describe("Noten API - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false, benotungsdatum: baselineBenotungsdatum(ctx), }); notenApi - .saveStudentenNoten( - "definitely-not-the-password", - [notenPayload(student)], - ctx.lvId, - ctx.semKurzbz, - ) + .saveStudentenNoten("definitely-not-the-password", [notenPayload(student)], ctx.lvId, ctx.semKurzbz) .then((response) => { expectNotenError(response, "wrongPassword"); }); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(row, "the row still exists").to.not.be.null; expect(row.freigabedatum, "a rejected Freigabe must not stamp freigabedatum").to.be.null; }); }); - }); - describe("happy path", () => { + describe("der normale Ablauf", () => { beforeEach(() => { requireDbReset(); }); - it("stamps freigabedatum on a changed note", () => { + it("setzt das freigabedatum auf einer geänderten Note", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false, benotungsdatum: baselineBenotungsdatum(ctx), }); notenApi - .saveStudentenNoten( - freigabePassword(), - [notenPayload(student)], - ctx.lvId, - ctx.semKurzbz, - ) + .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) .then((response) => { const data = expectNotenSuccess(response, "saveStudentenNoten"); expect(data, "freigegebene rows are reported back").to.be.an("array"); @@ -122,13 +110,13 @@ describe("Noten API - Notenfreigabe", () => { expect(entry.verlauf.pruefungen, "inklusive der Termine").to.be.an("array"); }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const grades = lvNoteOf(data, student.uid); expect(grades.freigabedatum, "the note is now freigegeben").to.exist; }); // C1: Die Freigabe brach früher vor dem Schreiben ab. - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(row.freigabedatum, "C1: die Freigabe schreibt freigabedatum").to.not.be.null; }); }); @@ -139,17 +127,19 @@ describe("Noten API - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false }); notenApi .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) .then((response) => { const entry = expectNotenSuccess(response, "saveStudentenNoten").find((r) => r.uid === student.uid); // ohne den Verlauf in der Antwort zeigt die Tabelle den neuen Termin erst nach einem Reload - expect(entry.verlauf.pruefungen, "der erste Antritt kommt mit der Antwort zurück").to.have.length(1); + expect(entry.verlauf.pruefungen, "der erste Antritt kommt mit der Antwort zurück").to.have.length( + 1, + ); }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "genau ein Termin").to.have.length(1); expect(attempts[0].antritt_nr, "als Antritt 1").to.eq(1); @@ -162,7 +152,7 @@ describe("Noten API - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false }); notenApi .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) @@ -171,7 +161,7 @@ describe("Noten API - Notenfreigabe", () => { expect(entry.freigabedatum, "die Freigabe gilt trotzdem").to.exist; }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(attemptsOfStudent(data, student.uid), "kein Termin").to.have.length(0); expect(verlaufOfStudent(data, student.uid).antrittCount, "die LV-Note zählt als Antritt 1").to.eq(1); }); @@ -183,32 +173,35 @@ describe("Noten API - Notenfreigabe", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false }); notenApi.saveStudentenNoten("", [notenPayload(student)], ctx.lvId, ctx.semKurzbz).then((response) => { const data = expectNotenSuccess(response, "Freigabe ohne Passwort"); - expect(data.map((r) => r.uid), "freigegebene Zeilen").to.include(student.uid); + expect( + data.map((r) => r.uid), + "freigegebene Zeilen", + ).to.include(student.uid); }); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(row.freigabedatum, "freigabedatum").to.not.be.null; }); }); // W7: Eine einzelne Wiederholung ist nicht Antritt 1. Die Freigabe überschreibt ihre Note nicht. - it("keeps the grade of a single repeat", () => { + it("behält die Note einer einzelnen Wiederholung", () => { const student = ctx.students[1]; const g2 = ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: false, erstantritt: false }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false, erstantritt: false }); seedPruefung(ctx, student, { note: g2, datum: attemptDate(ctx, 1), typ: "Termin2" }); notenApi .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) .then((response) => expectNotenSuccess(response, "saveStudentenNoten")); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "the Freigabe adds no exam").to.have.length(1); expect(String(attempts[0].note), "the repeat keeps its grade").to.eq(String(g2)); @@ -217,12 +210,12 @@ describe("Noten API - Notenfreigabe", () => { // Das Datum eines Termins gehört der Person, die ihn eingetragen hat. Die Freigabe macht die // Note verbindlich und verschiebt kein Datum. - it("keeps the date of an exam that already exists", () => { + it("behält das Datum einer bestehenden Prüfung", () => { const student = ctx.students[2]; const pruefungsdatum = attemptDate(ctx, 2); resetNotenState(ctx); - seedBaseline(ctx, student.uid, { + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false, erstantritt: false, @@ -235,23 +228,21 @@ describe("Noten API - Notenfreigabe", () => { .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) .then((response) => expectNotenSuccess(response, "saveStudentenNoten")); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "der Termin bleibt der einzige").to.have.length(1); - expect(String(attempts[0].datum).slice(0, 10), "mit seinem eigenen Datum").to.eq( - pruefungsdatum, - ); + expect(String(attempts[0].datum).slice(0, 10), "mit seinem eigenen Datum").to.eq(pruefungsdatum); }); }); - it("only touches rows whose benotungsdatum is newer than their freigabedatum", () => { + it("ändert nur Zeilen mit einem benotungsdatum nach dem freigabedatum", () => { const changed = ctx.students[0]; const alreadyReleased = ctx.students[1]; resetNotenState(ctx); // changed: benotungsdatum after freigabedatum -> must be re-freigegeben - seedBaseline(ctx, changed.uid, { + seedBaseline(ctx, changed, { note: ctx.gradeNotes[0], freigegeben: true, freigabedatum: `${ctx.semKurzbz.slice(2, 6)}-01-05 08:00:00`, @@ -259,7 +250,7 @@ describe("Noten API - Notenfreigabe", () => { }); // already freigegeben and untouched since -> must be left alone - seedBaseline(ctx, alreadyReleased.uid, { + seedBaseline(ctx, alreadyReleased, { note: ctx.gradeNotes[0], freigegeben: true, freigabedatum: `${ctx.semKurzbz.slice(2, 6)}-01-10 08:00:00`, @@ -284,7 +275,7 @@ describe("Noten API - Notenfreigabe", () => { ).to.not.include(alreadyReleased.uid); }); - readLvGesamtnote(ctx, alreadyReleased.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, alreadyReleased.uid).then((row) => { expect( new Date(row.freigabedatum).toISOString().slice(0, 10), "the untouched row keeps its original freigabedatum", @@ -318,7 +309,7 @@ describe("Noten API - Notenfreigabe", () => { const student = ctx.students[3]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: false }); notenApi .saveStudentenNoten(freigabePassword(), [notenPayload(student)], ctx.lvId, ctx.semKurzbz) @@ -327,7 +318,7 @@ describe("Noten API - Notenfreigabe", () => { expect(entry, `${student.uid} ist freigegeben`).to.exist; }); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(row.freigabedatum, "freigabedatum").to.not.be.null; }); }); @@ -353,7 +344,7 @@ describe("Noten API - Notenfreigabe", () => { .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, andereNote()) .then((response) => expectNotenError(response, "freigabeEndgueltig")); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(String(row.note), "die LV-Note bleibt").to.eq(String(ctx.notes.negativ)); }); }); @@ -367,7 +358,7 @@ describe("Noten API - Notenfreigabe", () => { expectNotenError(response, "freigabeEndgueltig"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(attemptsOfStudent(data, student.uid), "nur Antritt 1").to.have.length(1); }); }); @@ -379,8 +370,8 @@ describe("Noten API - Notenfreigabe", () => { const [freigegeben, offen] = ctx.students; resetNotenState(ctx); - seedBaseline(ctx, freigegeben.uid, { freigegeben: true }); - seedBaseline(ctx, offen.uid, { freigegeben: false }); + seedBaseline(ctx, freigegeben, { freigegeben: true }); + seedBaseline(ctx, offen, { freigegeben: false }); notenApi .saveNotenvorschlagBulk(ctx.lvId, ctx.semKurzbz, [ diff --git a/tests/cypress/e2e/specs/api/noten/noten.frist.cy.js b/tests/cypress/e2e/specs/api/noten/noten.frist.cy.js index adbda29a2..94941a6ea 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.frist.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.frist.cy.js @@ -6,15 +6,11 @@ * direkt nach der Zugriffsprüfung, ein abgelehnter Request schreibt also nichts. Die Meldung nennt die Frist * und prüft damit ihre Ableitung aus NOTENEINTRAGUNGSFRIST_SS/WS. * - * Seeder 019 legt das Sommersemester an, in dem der Testbenutzer nach der Frist unterrichtet. + * Die Seeder-Gruppe benotungstool_fixture_erweitert legt das Sommersemester an, in dem der Testbenutzer nach der Frist unterrichtet. */ import { notenApi } from "../../../../support/api/notenApi"; -import { - expectNotenError, - expectNotenSuccess, - messageMatchesPhrase, -} from "../../../../support/helpers/notenErrors"; +import { expectNotenError, expectNotenSuccess, messageMatchesPhrase } from "../../../../support/helpers/notenErrors"; import { attemptDate, expectedFristString, @@ -54,7 +50,8 @@ describe("Noten API - Noteneintragungsfrist (Prüfungsordnung §1)", () => { // ein fehlendes Semester ist ein Fixturefehler und kein übersprungener Test const paarFuer = (typ) => { - expect(abgelaufen[typ], `ein ${typ} mit abgelaufener Frist, in dem der Testbenutzer unterrichtet`).to.not.be.null; + expect(abgelaufen[typ], `ein ${typ} mit abgelaufener Frist, in dem der Testbenutzer unterrichtet`).to.not.be + .null; return abgelaufen[typ]; }; @@ -118,7 +115,8 @@ describe("Noten API - Noteneintragungsfrist (Prüfungsordnung §1)", () => { sem_kurzbz: paar.semKurzbz, pruefung_id: null, }), - saveNotenvorschlag: (paar) => notenApi.saveNotenvorschlag(paar.lvId, paar.semKurzbz, s0().uid, ctx.gradeNotes[0]), + saveNotenvorschlag: (paar) => + notenApi.saveNotenvorschlag(paar.lvId, paar.semKurzbz, s0().uid, ctx.gradeNotes[0]), saveNotenvorschlagBulk: (paar) => notenApi.saveNotenvorschlagBulk(paar.lvId, paar.semKurzbz, [ { uid: s0().uid, note: ctx.gradeNotes[0], punkte: null }, @@ -154,8 +152,10 @@ describe("Noten API - Noteneintragungsfrist (Prüfungsordnung §1)", () => { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_FRIST_AUSNAHME_GILT", false); const paar = paarFuer(typ); - expect(fristHasPassed(paar.semKurzbz, fristSS(), fristWS()), `die Frist von ${paar.semKurzbz} ist vorbei`) - .to.be.true; + expect( + fristHasPassed(paar.semKurzbz, fristSS(), fristWS()), + `die Frist von ${paar.semKurzbz} ist vorbei`, + ).to.be.true; aufruf(paar).then((response) => { expectNotenError(response, "noteneintragungsfristVorbei"); diff --git a/tests/cypress/e2e/specs/api/noten/noten.notenschluessel.cy.js b/tests/cypress/e2e/specs/api/noten/noten.notenschluessel.cy.js index c776e8495..a74a2c74c 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.notenschluessel.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.notenschluessel.cy.js @@ -7,7 +7,7 @@ import { notenApi } from "../../../../support/api/notenApi"; import { expectNotenError, expectNotenSuccess } from "../../../../support/helpers/notenErrors"; -import { requirePunkteModus } from "../../../../support/helpers/notenConfig"; +import { requirePunkteModus, skipWenn } from "../../../../support/helpers/notenConfig"; import { attemptDate, loadNotenContext, @@ -15,7 +15,7 @@ import { resetNotenState, seedBaseline, } from "../../../../support/helpers/notenTestData"; -import { attemptsOfStudent, givenBaseline, readState } from "../../../../support/helpers/notenScenario"; +import { attemptsOfStudent, givenBaseline, readStateViaApi } from "../../../../support/helpers/notenScenario"; const MAX_PUNKTE = 100; @@ -44,7 +44,7 @@ describe("Noten API - Notenschlüssel (getNoteByPunkte)", () => { return cy.then(() => observed); }; - it("maps every point value through a monotonic, exact grade scale", () => { + it("bildet jeden Punktewert auf eine monotone und exakte Notenskala ab", () => { sweepScale().then((observed) => { const graded = observed.filter((entry) => entry.note !== null && entry.note !== undefined); @@ -84,11 +84,7 @@ describe("Noten API - Notenschlüssel (getNoteByPunkte)", () => { } } - cy.log( - `Notenschlüssel of LV ${lvId}: ${boundaries - .map((b) => `>=${b.punkte} -> ${b.note}`) - .join(", ")}`, - ); + cy.log(`Notenschlüssel of LV ${lvId}: ${boundaries.map((b) => `>=${b.punkte} -> ${b.note}`).join(", ")}`); expect( boundaries.length, @@ -128,15 +124,12 @@ describe("Noten API - Notenschlüssel (getNoteByPunkte)", () => { beforeEach(function () { requirePunkteModus(this, ctx); - if (schwelleUnterNull) { - Cypress.log({ name: "skip", message: "Übersprungen: der Notenschlüssel hat eine Schwelle unter 0 Punkten." }); - this.skip(); - } + skipWenn(this, schwelleUnterNull, "Übersprungen: der Notenschlüssel hat eine Schwelle unter 0 Punkten."); requireDbReset(); }); const expectNurAntritt1 = (students) => - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { students.forEach((s) => { expect(attemptsOfStudent(data, s.uid), `Prüfungen von ${s.uid}`).to.have.length(1); }); @@ -167,7 +160,7 @@ describe("Noten API - Notenschlüssel (getNoteByPunkte)", () => { const students = ctx.students.slice(0, 2); resetNotenState(ctx); - students.forEach((s) => seedBaseline(ctx, s.uid)); + students.forEach((s) => seedBaseline(ctx, s)); notenApi .createPruefungen( @@ -183,5 +176,4 @@ describe("Noten API - Notenschlüssel (getNoteByPunkte)", () => { expectNurAntritt1(students); }); }); - }); diff --git a/tests/cypress/e2e/specs/api/noten/noten.notenvorschlag.cy.js b/tests/cypress/e2e/specs/api/noten/noten.notenvorschlag.cy.js index 1dff10b94..9740f1c13 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.notenvorschlag.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.notenvorschlag.cy.js @@ -14,7 +14,7 @@ import { baselineBenotungsdatum, baselineDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -24,7 +24,7 @@ import { addPruefung, attemptsOfStudent, lvNoteOf, - readState, + readStateViaApi, verlaufOfStudent, } from "../../../../support/helpers/notenScenario"; @@ -38,41 +38,38 @@ describe("Noten API - Notenvorschlag", () => { }); }); - const readRow = (uid) => readLvGesamtnote(ctx, uid); + const readRow = (uid) => readLvGesamtnoteViaDb(ctx, uid); - describe("saving a Notenvorschlag on a student without a grade", () => { - it("returns the stored note with a benotungsdatum and no freigabedatum", () => { + describe("ein Notenvorschlag für einen Studierenden ohne Note", () => { + it("gibt die gespeicherte Note mit benotungsdatum und ohne freigabedatum zurück", () => { const student = ctx.students[0]; resetNotenState(ctx); - notenApi - .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[0]) - .then((response) => { - const data = expectNotenSuccess(response, "saveNotenvorschlag"); - expect(data, "saveNotenvorschlag returns [ lvgesamtnote ]").to.be.an("array").and.not - .be.empty; + notenApi.saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[0]).then((response) => { + const data = expectNotenSuccess(response, "saveNotenvorschlag"); + expect(data, "saveNotenvorschlag returns [ lvgesamtnote ]").to.be.an("array").and.not.be.empty; - const row = data[0]; - expect(String(row.note), "stored note").to.eq(String(ctx.gradeNotes[0])); - expect(row.benotungsdatum, "benotungsdatum is stamped on save").to.exist; - expect(row.freigabedatum, "a fresh Notenvorschlag is not freigegeben").to.be.oneOf([ - null, - undefined, - "", - ]); - }); + const row = data[0]; + expect(String(row.note), "stored note").to.eq(String(ctx.gradeNotes[0])); + expect(row.benotungsdatum, "benotungsdatum is stamped on save").to.exist; + expect(row.freigabedatum, "a fresh Notenvorschlag is not freigegeben").to.be.oneOf([ + null, + undefined, + "", + ]); + }); }); // getStudentenNoten liest seit dem Wechsel auf den ungefilterten Getter auch noch nicht // freigegebene Noten - sonst sind LV-Note und Freigabestatus nach einem Reload leer. - it("reports the offen note back through getStudentenNoten", () => { + it("meldet die offene Note über getStudentenNoten zurück", () => { const student = ctx.students[0]; resetNotenState(ctx); notenApi.saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[0]); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const grades = lvNoteOf(data, student.uid); expect(grades, `grades entry for ${student.uid}`).to.exist; expect( @@ -93,7 +90,7 @@ describe("Noten API - Notenvorschlag", () => { describe("das gewählte Benotungsdatum", () => { // Die LV-Note IST Antritt 1. Ohne diese Zeile bekäme die nächste Prüfung Termin2, und der // Legacy-Typ der ganzen Kette verschiebt sich um eine Stelle. - it("writes attempt 1 with the chosen day", function () { + it("schreibt Antritt 1 mit dem gewählten Tag", function () { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_ERSTANTRITT_BEI_UEBERNAHME", true); const student = ctx.students[1]; @@ -109,7 +106,7 @@ describe("Noten API - Notenvorschlag", () => { expect(row.verlauf.antrittCount, "die LV-Note ist Antritt 1").to.eq(1); expect(row.verlauf.hatWiederholung, "Antritt 1 ist keine Wiederholung").to.be.false; }) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "genau ein Antritt").to.have.length(1); @@ -118,7 +115,7 @@ describe("Noten API - Notenvorschlag", () => { }); }); - it("makes the next exam attempt 2, not attempt 1 again", function () { + it("macht die nächste Prüfung zu Antritt 2 statt wieder zu Antritt 1", function () { requireWiederholung(this, ctx); const student = ctx.students[2]; @@ -126,19 +123,15 @@ describe("Noten API - Notenvorschlag", () => { resetNotenState(ctx); notenApi - .saveNotenvorschlag( - ctx.lvId, ctx.semKurzbz, student.uid, ctx.notes.negativ, null, baselineDate(ctx), - ) + .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.notes.negativ, null, baselineDate(ctx)) .then((response) => expectNotenSuccess(response, "übernehmen")); addPruefung(ctx, student, { note: ctx.gradeNotes[1], datum: attemptDate(ctx, 1) }) .then((response) => { const [saved] = expectNotenSuccess(response, "Wiederholung"); - expect(saved.pruefungstyp_kurzbz, "die Wiederholung ist nicht Antritt 1").to.not.eq( - "Termin1", - ); + expect(saved.pruefungstyp_kurzbz, "die Wiederholung ist nicht Antritt 1").to.not.eq("Termin1"); }) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.antrittCount, "die Übernahme und die Prüfung sind zwei Antritte").to.eq(2); @@ -160,7 +153,7 @@ describe("Noten API - Notenvorschlag", () => { expect(row.verlauf.antrittCount, "die LV-Note zählt als Antritt 1").to.eq(1); }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(attemptsOfStudent(data, student.uid), "kein Termin").to.have.length(0); }); }); @@ -182,15 +175,17 @@ describe("Noten API - Notenvorschlag", () => { expectNotenSuccess(response, "erster Termin"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "Antritt 1 und der neue Termin").to.have.length(2); expect(String(attempts[0].note), "Antritt 1 trägt die LV-Note").to.eq(String(ctx.notes.negativ)); - expect(attempts.map((p) => p.antritt_nr), "Antrittsnummern").to.deep.eq([1, 2]); + expect( + attempts.map((p) => p.antritt_nr), + "Antrittsnummern", + ).to.deep.eq([1, 2]); expect(verlaufOfStudent(data, student.uid).antrittCount, "zwei Antritte").to.eq(2); }); }); - }); // W5: Eine Abfrage liest alle LV-Noten der LV. Das Ergebnis je Studierendem bleibt gleich. @@ -199,10 +194,10 @@ describe("Noten API - Notenvorschlag", () => { const [freigegeben, offen, ohneNote] = ctx.students; resetNotenState(ctx); - seedBaseline(ctx, freigegeben.uid, { freigegeben: true }); - seedBaseline(ctx, offen.uid, { freigegeben: false }); + seedBaseline(ctx, freigegeben, { freigegeben: true }); + seedBaseline(ctx, offen, { freigegeben: false }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const f = lvNoteOf(data, freigegeben.uid); expect(f.note_lv, "LV-Note der freigegebenen Zeile").to.exist; expect(f.freigabedatum, "freigabedatum der freigegebenen Zeile").to.exist; @@ -224,18 +219,20 @@ describe("Noten API - Notenvorschlag", () => { it("sperrt die Übernahme", () => { const student = ctx.students[3]; const g2 = - ctx.notes.positiv ?? ctx.notes.bestnote ?? ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); + ctx.notes.positiv ?? + ctx.notes.bestnote ?? + ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); const g3 = ctx.gradeNotes.find((n) => String(n) !== String(g2)); resetNotenState(ctx); - seedBaseline(ctx, student.uid, { erstantritt: false }); + seedBaseline(ctx, student, { erstantritt: false }); let wiederholungId; seedPruefung(ctx, student, { note: g2, datum: attemptDate(ctx, 1), typ: "Termin2" }).then((seeded) => { wiederholungId = seeded.pruefungId; }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(verlaufOfStudent(data, student.uid).hatWiederholung, "hatWiederholung").to.be.true; }); @@ -243,7 +240,7 @@ describe("Noten API - Notenvorschlag", () => { .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, g3, null, baselineDate(ctx)) .then((response) => expectNotenError(response, "c4notenvorschlagGesperrt")); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const pruefung = attemptsOfStudent(data, student.uid).find( (p) => String(p.pruefung_id) === String(wiederholungId), ); @@ -255,17 +252,17 @@ describe("Noten API - Notenvorschlag", () => { }); }); - describe("re-grading an already freigegebene note", () => { + describe("eine bereits freigegebene Note neu benoten", () => { // eine endgültige Freigabe verbietet genau das, siehe noten.freigabe beforeEach(function () { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_FREIGABE_FINAL", false); }); - it("moves the state from freigegeben to changed", () => { + it("wechselt den Status von freigegeben auf geändert", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: true, erstantritt: false, @@ -273,7 +270,7 @@ describe("Noten API - Notenvorschlag", () => { }); // baseline: benotungsdatum == freigabedatum -> freigegeben, not changed - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const grades = lvNoteOf(data, student.uid); expect(grades.note_lv, "seeded freigegebene note is visible").to.exist; expect( @@ -282,18 +279,14 @@ describe("Noten API - Notenvorschlag", () => { ).to.be.false; }); - notenApi - .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[1]) - .then((response) => { - expectNotenSuccess(response, "re-grade after Freigabe"); - }); + notenApi.saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[1]).then((response) => { + expectNotenSuccess(response, "re-grade after Freigabe"); + }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const grades = lvNoteOf(data, student.uid); - expect(String(grades.note_lv), "the new grade is stored").to.eq( - String(ctx.gradeNotes[1]), - ); + expect(String(grades.note_lv), "the new grade is stored").to.eq(String(ctx.gradeNotes[1])); expect(grades.freigabedatum, "the old Freigabe timestamp is kept").to.exist; expect( new Date(grades.benotungsdatum) > new Date(grades.freigabedatum), @@ -302,11 +295,11 @@ describe("Noten API - Notenvorschlag", () => { }); }); - it("overwrites the grade rather than adding a second row", () => { + it("überschreibt die Note, statt eine zweite Zeile anzulegen", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: true, erstantritt: false, @@ -320,5 +313,4 @@ describe("Noten API - Notenvorschlag", () => { }); }); }); - }); diff --git a/tests/cypress/e2e/specs/api/noten/noten.pruefungsantritte.cy.js b/tests/cypress/e2e/specs/api/noten/noten.pruefungsantritte.cy.js index d1ae51f80..1e891c841 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.pruefungsantritte.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.pruefungsantritte.cy.js @@ -14,6 +14,7 @@ import { requireKommissionellerAntritt, requireKonfiguration, requireWiederholung, + skipWenn, } from "../../../../support/helpers/notenConfig"; import { attemptDate, @@ -30,7 +31,7 @@ import { countingAttemptsOfStudent, editPruefung, givenBaseline, - readState, + readStateViaApi, verlaufOfStudent, } from "../../../../support/helpers/notenScenario"; @@ -47,10 +48,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { `entschuldigt=${ctx.notes.entschuldigt}`, ); - expect( - ctx.maxAntritte, - "needs room for at least one retake beyond the first Antritt", - ).to.be.greaterThan(1); + expect(ctx.maxAntritte, "needs room for at least one retake beyond the first Antritt").to.be.greaterThan(1); }); }); @@ -58,11 +56,12 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { const studentFor = (index) => ctx.students[index % ctx.students.length]; /** Skip, wenn der letzte Antritt der Kette nicht der kommissionelle ist. */ - const skipOhneKommissionLetzt = (test) => { - if (ctx.cisConfig.CIS_GESAMTNOTE_KOMMISSIONELL_AB_ANTRITT === ctx.maxAntritte) return; - Cypress.log({ name: "skip", message: "Übersprungen: der letzte Antritt ist nicht kommissionell." }); - test.skip(); - }; + const skipOhneKommissionLetzt = (test) => + skipWenn( + test, + ctx.cisConfig.CIS_GESAMTNOTE_KOMMISSIONELL_AB_ANTRITT !== ctx.maxAntritte, + "Übersprungen: der letzte Antritt ist nicht kommissionell.", + ); /** Adds counting attempts until the cap is reached. Baseline already provides Antritt 1. */ const fillToCap = (student, firstIndex = 1) => { @@ -80,7 +79,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { // Die Konfiguration nennt die Sondernoten nur mit ihrer Bezeichnung. Die API antwortet mit dem // aufgelösten Primärschlüssel, auf Demodaten ist entschuldigt die 14. Scheitert die Auflösung, // greifen alle Regeln stillschweigend auf der falschen Note. - it("resolves the special notes from tbl_note by their Bezeichnung", () => { + it("löst die Sondernoten über ihre Bezeichnung aus tbl_note auf", () => { notenApi.getCisConfig().then((response) => { const config = expectNotenSuccess(response, "getCisConfig"); @@ -96,8 +95,8 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - describe("Rule A - maximum number of Prüfungsantritte", () => { - it("rejects an attempt once the configured maximum is reached", function () { + describe("Regel A - die Höchstzahl der Prüfungsantritte", () => { + it("lehnt einen Antritt ab, sobald das konfigurierte Maximum erreicht ist", function () { // ohne Anlage der kommissionellen Prüfung endet die Kette früher, siehe den Test zu kommPruefNichtErlaubt requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF", true); @@ -112,17 +111,19 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); // and nothing was written for the rejected attempt - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const dates = attemptsOfStudent(data, student.uid).map((p) => String(p.datum).slice(0, 10)); expect(dates, "no row may carry the rejected date").to.not.include(nextDate); - expect(countingAttemptsOfStudent(data, student.uid), "exactly the possible counting rows") - .to.have.length(ctx.maxAntritte); + expect( + countingAttemptsOfStudent(data, student.uid), + "exactly the possible counting rows", + ).to.have.length(ctx.maxAntritte); }); }); }); - describe("Rule B - attempts are taken in chronological order", () => { + describe("Regel B - die Antritte folgen der Zeitordnung", () => { beforeEach(function () { requireWiederholung(this, ctx); }); @@ -135,50 +136,46 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }; - it("rejects a new attempt dated before an existing one", () => { + it("lehnt einen neuen Antritt vor einem bestehenden ab", () => { const student = studentFor(1); givenOpenAttemptOn(student, attemptDate(ctx, 2)); - addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 1) }).then( - (response) => { - expectNotenError(response, "pruefungDatumBeforeExisting"); - }, - ); + addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 1) }).then((response) => { + expectNotenError(response, "pruefungDatumBeforeExisting"); + }); }); - it("accepts a new attempt dated after every existing one", () => { + it("nimmt einen neuen Antritt nach allen bestehenden an", () => { const student = studentFor(1); givenOpenAttemptOn(student, attemptDate(ctx, 2)); - addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 3) }).then( - (response) => { - expectNotenSuccess(response, "attempt strictly after the existing one"); - }, - ); + addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 3) }).then((response) => { + expectNotenSuccess(response, "attempt strictly after the existing one"); + }); }); }); - describe("Rule C - 'entschuldigt' may be assigned only once", () => { + describe("Regel C - 'entschuldigt' gilt nur einmal", () => { beforeEach(function () { requireWiederholung(this, ctx); }); - it("rejects a second entschuldigt attempt", () => { + it("lehnt einen zweiten entschuldigten Antritt ab", () => { const student = studentFor(2); givenBaseline(ctx, student); - addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 1) }).then( - (response) => expectNotenSuccess(response, "first entschuldigt attempt"), + addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 1) }).then((response) => + expectNotenSuccess(response, "first entschuldigt attempt"), ); - addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 2) }).then( - (response) => expectNotenError(response, "noteOccuranceLimitReached"), + addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 2) }).then((response) => + expectNotenError(response, "noteOccuranceLimitReached"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const excused = attemptsOfStudent(data, student.uid).filter( (p) => String(p.note) === String(ctx.notes.entschuldigt), ); @@ -187,30 +184,29 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - describe("entschuldigt does not consume an attempt", () => { + describe("'entschuldigt' verbraucht keinen Antritt", () => { beforeEach(function () { requireWiederholung(this, ctx); }); - it("still accepts a real grade after an excused attempt", () => { + it("nimmt nach einem entschuldigten Antritt weiter eine echte Note an", () => { const student = studentFor(0); givenBaseline(ctx, student); - addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 1) }).then( - (response) => expectNotenSuccess(response, "excused attempt"), + addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 1) }).then((response) => + expectNotenSuccess(response, "excused attempt"), ); // excused must not count, so this real grade is still within the cap - addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 2) }).then( - (response) => - expectNotenSuccess( - response, - "a real grade after an excused attempt (excused must not count towards the cap)", - ), + addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 2) }).then((response) => + expectNotenSuccess( + response, + "a real grade after an excused attempt (excused must not count towards the cap)", + ), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect( verlaufOfStudent(data, student.uid).antrittCount, "baseline + the real grade, the excused one not counted", @@ -233,8 +229,8 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { // bis zum vorletzten Antritt auffüllen for (let i = 1; i < ctx.maxAntritte - 1; i += 1) { - addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, i) }).then( - (response) => expectNotenSuccess(response, `Antritt ${i + 1}`), + addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, i) }).then((response) => + expectNotenSuccess(response, `Antritt ${i + 1}`), ); } @@ -248,7 +244,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { ); }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.antrittCount, "die kommissionelle zählt als Antritt").to.eq(ctx.maxAntritte); expect(verlauf.canAdd, "danach ist kein Antritt mehr möglich").to.be.false; @@ -267,12 +263,12 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { // bis zum vorletzten Antritt auffüllen; danach wäre der kommissionelle fällig for (let i = 1; i < ctx.maxAntritte - 1; i += 1) { - addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, i) }).then( - (response) => expectNotenSuccess(response, `Antritt ${i + 1}`), + addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, i) }).then((response) => + expectNotenSuccess(response, `Antritt ${i + 1}`), ); } - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.kommPruefGesperrt, "der Verlauf nennt den Grund").to.be.true; expect(verlauf.canAdd, "und lässt keinen Antritt mehr zu").to.be.false; @@ -297,19 +293,19 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { typ: "kommPruef", }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.terminal, "die Kette ist geschlossen").to.be.true; expect(verlauf.canAdd, "kein weiterer Antritt möglich").to.be.false; }); - addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 2) }).then( - (response) => expectNotenError(response, "maxAntritteReached"), + addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 2) }).then((response) => + expectNotenError(response, "maxAntritteReached"), ); }); }); - describe("'Noch nicht eingetragen' does not consume an attempt", () => { + describe("'Noch nicht eingetragen' verbraucht keinen Antritt", () => { beforeEach(function () { requireWiederholung(this, ctx); }); @@ -322,7 +318,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { (response) => expectNotenSuccess(response, "offener Termin"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const offen = attemptsOfStudent(data, student.uid).find( (p) => String(p.note) === String(ctx.notes.nochNichtEingetragen), ); @@ -336,20 +332,17 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - describe("Anrechnung - no Prüfungen at all", () => { - it("refuses an attempt while the Zeugnisnote is angerechnet", function () { + describe("Anrechnung - gar keine Prüfungen", () => { + it("lehnt einen Antritt bei angerechneter Zeugnisnote ab", function () { const angerechnet = (ctx.cisConfig.NOTEN_ANRECHNUNG || [])[0]; - if (angerechnet === undefined) { - Cypress.log({ name: "skip", message: "Übersprungen: NOTEN_ANRECHNUNG löst keine Note auf." }); - this.skip(); - } + skipWenn(this, angerechnet === undefined, "Übersprungen: NOTEN_ANRECHNUNG löst keine Note auf."); const student = studentFor(4); givenBaseline(ctx, student); seedZeugnisnote(ctx, student.uid, angerechnet); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.angerechnet, "the Verlauf marks the Anrechnung").to.be.true; expect(verlauf.canAdd, "and blocks further attempts").to.be.false; @@ -361,7 +354,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - describe("edit guards", () => { + describe("Schutz beim Bearbeiten", () => { beforeEach(function () { requireWiederholung(this, ctx); }); @@ -373,7 +366,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum: attemptDate(ctx, 1) }); addPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 2) }); - return readState(ctx).then((data) => { + return readStateViaApi(ctx).then((data) => { const excused = attemptsOfStudent(data, student.uid).find( (p) => String(p.note) === String(ctx.notes.entschuldigt), ); @@ -382,7 +375,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }; - it("rejects changing the grade once a later attempt exists", function () { + it("lehnt eine Notenänderung nach einem späteren Antritt ab", function () { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_NOTE_SPERRE_BEI_SPAETEREM_TERMIN", true); const student = studentFor(1); @@ -396,7 +389,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - it("still allows a date-only correction between the neighbouring attempts", () => { + it("erlaubt weiter eine reine Datumskorrektur zwischen den Nachbarantritten", () => { const student = studentFor(1); givenThreeAttempts(student).then((excused) => { @@ -407,7 +400,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { datum: shiftDate(attemptDate(ctx, 1), 3), }) .then((response) => expectNotenSuccess(response, "date-only correction inside the bounds")) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const moved = attemptsOfStudent(data, student.uid).find( (p) => p.pruefung_id === excused.pruefung_id, @@ -420,7 +413,7 @@ describe("Noten API - Prüfungsantritte (Prüfungsordnung §1)", () => { }); }); - it("rejects a date on or before the previous attempt", () => { + it("lehnt ein Datum am oder vor dem vorherigen Antritt ab", () => { const student = studentFor(2); givenThreeAttempts(student).then((excused) => { diff --git a/tests/cypress/e2e/specs/api/noten/noten.pruefungstermin.cy.js b/tests/cypress/e2e/specs/api/noten/noten.pruefungstermin.cy.js index ec5d59717..32be13b19 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.pruefungstermin.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.pruefungstermin.cy.js @@ -12,7 +12,7 @@ import { attemptDate, baselineDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedPruefung, @@ -23,14 +23,14 @@ import { attemptsOfStudent, editPruefung, givenBaseline, - readState, + readStateViaApi, verlaufOfStudent, } from "../../../../support/helpers/notenScenario"; import { notenApi, pruefungenOf } from "../../../../support/api/notenApi"; const dayOf = (value) => String(value).slice(0, 10); -describe("Noten API - Prüfungstermin (write path)", () => { +describe("Noten API - Prüfungstermin (Schreibpfad)", () => { let ctx; before(() => { @@ -43,7 +43,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { const studentFor = (index) => ctx.students[index % ctx.students.length]; - it("writes exactly one Prüfung per add - no snapshot alongside it", function () { + it("schreibt je Anlage genau eine Prüfung, ohne Kopie daneben", function () { requireWiederholung(this, ctx); const student = studentFor(0); @@ -60,14 +60,14 @@ describe("Noten API - Prüfungstermin (write path)", () => { expect(verlauf, "verlauf is returned").to.exist; expect(verlauf.pruefungen, "verlauf carries the attempts").to.be.an("array"); }) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "baseline Antritt 1 plus exactly one added row").to.have.length(2); }); }); - it("derives position and Antrittsnummer server-side", function () { + it("leitet Position und Antrittsnummer auf dem Server ab", function () { requireWiederholung(this, ctx); const student = studentFor(1); @@ -75,26 +75,33 @@ describe("Noten API - Prüfungstermin (write path)", () => { givenBaseline(ctx, student); addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, 1) }) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const attempts = attemptsOfStudent(data, student.uid); - expect(attempts.map((p) => p.position), "positions are 1..n in date order").to.deep.eq([1, 2]); - expect(attempts.map((p) => p.antritt_nr), "both count as attempts").to.deep.eq([1, 2]); + expect( + attempts.map((p) => p.position), + "positions are 1..n in date order", + ).to.deep.eq([1, 2]); + expect( + attempts.map((p) => p.antritt_nr), + "both count as attempts", + ).to.deep.eq([1, 2]); attempts.forEach((p) => expect(p.zaehlt, `zaehlt of position ${p.position}`).to.be.true); const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.antrittCount, "both attempts counted").to.eq(2); expect(verlauf.maxAntritte, "the cap comes from the server").to.eq(ctx.maxAntritte); // der letzte Antritt ist kommissionell; darf das Tool ihn nicht anlegen, ist hier Schluss - const anlegbar = ctx.cisConfig.CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF !== false - ? ctx.maxAntritte - : ctx.maxAntritte - 1; + const anlegbar = + ctx.cisConfig.CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF !== false + ? ctx.maxAntritte + : ctx.maxAntritte - 1; expect(verlauf.canAdd, `canAdd with 2 of ${anlegbar} possible`).to.eq(2 < anlegbar); }); }); - it("appends a new row per add instead of overwriting the previous one", function () { + it("hängt je Anlage eine neue Zeile an, statt die vorherige zu überschreiben", function () { requireWiederholung(this, ctx); // nur eine explizite pruefung_id aktualisiert, ein Add fügt immer ein @@ -109,16 +116,19 @@ describe("Noten API - Prüfungstermin (write path)", () => { return addPruefung(ctx, student, { note: ctx.gradeNotes[1], datum: attemptDate(ctx, 2) }); }) .then((response) => expectNotenSuccess(response, "second add")) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "baseline + two added rows").to.have.length(3); - expect(attempts.map((p) => p.pruefung_id), "the first add still exists").to.include(firstId); + expect( + attempts.map((p) => p.pruefung_id), + "the first add still exists", + ).to.include(firstId); }); }); - it("edits the pruefung identified by pruefung_id", () => { + it("bearbeitet die Prüfung mit der übergebenen pruefung_id", () => { // An excused and a real attempt side by side - no endpoint builds this, hence the direct seed const student = studentFor(2); const excusedDate = attemptDate(ctx, 1); @@ -142,7 +152,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { }), ) .then((response) => expectNotenSuccess(response, "moving the excused attempt")) - .then(() => readState(ctx)) + .then(() => readStateViaApi(ctx)) .then((data) => { const rows = pruefungenOf(data, student.uid); const excused = rows.find((p) => p.pruefung_id === excusedId); @@ -150,16 +160,14 @@ describe("Noten API - Prüfungstermin (write path)", () => { // the untargeted row first: silently rewriting a real grade is the worse outcome expect(graded, "the other attempt still exists").to.exist; - expect(String(graded.note), "the untargeted attempt keeps its grade").to.eq( - String(ctx.gradeNotes[0]), - ); + expect(String(graded.note), "the untargeted attempt keeps its grade").to.eq(String(ctx.gradeNotes[0])); expect(excused, "the excused attempt still exists").to.exist; expect(dayOf(excused.datum), "the row named by pruefung_id moved").to.eq(movedTo); }); }); - it("writes the LV note from the attempt's grade", function () { + it("schreibt die LV-Note aus der Note des Antritts", function () { requireWiederholung(this, ctx); const student = studentFor(3); @@ -168,11 +176,9 @@ describe("Noten API - Prüfungstermin (write path)", () => { addPruefung(ctx, student, { note: ctx.gradeNotes[1], datum: attemptDate(ctx, 1) }) .then((response) => expectNotenSuccess(response, "attempt with a grade")) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { - expect(String(row.note), "the LV note follows the newest attempt").to.eq( - String(ctx.gradeNotes[1]), - ); + expect(String(row.note), "the LV note follows the newest attempt").to.eq(String(ctx.gradeNotes[1])); }); }); @@ -188,12 +194,15 @@ describe("Noten API - Prüfungstermin (write path)", () => { expectNotenSuccess(response, "erster Termin neben der LV-Note"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const attempts = attemptsOfStudent(data, student.uid); expect(attempts, "Antritt 1 und der neue Termin").to.have.length(2); expect(String(attempts[0].note), "Antritt 1 trägt die LV-Note").to.eq(String(ctx.notes.negativ)); expect(dayOf(attempts[0].datum) < attemptDate(ctx, 1), "Antritt 1 liegt vor dem neuen Termin").to.be.true; - expect(attempts.map((p) => p.antritt_nr), "Antrittsnummern").to.deep.eq([1, 2]); + expect( + attempts.map((p) => p.antritt_nr), + "Antrittsnummern", + ).to.deep.eq([1, 2]); expect(verlaufOfStudent(data, student.uid).antrittCount, "zwei Antritte").to.eq(2); }); }); @@ -203,16 +212,18 @@ describe("Noten API - Prüfungstermin (write path)", () => { // Die LV-Note ist nie 'entschuldigt'. describe("LV-Note nach einem Termin", () => { const g2 = () => - ctx.notes.positiv ?? ctx.notes.bestnote ?? ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); + ctx.notes.positiv ?? + ctx.notes.bestnote ?? + ctx.gradeNotes.find((n) => String(n) !== String(ctx.notes.negativ)); const expectLvNote = (student, note, message) => - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(String(row.note), message).to.eq(String(note)); return row; }); const expectAntritte = (student, anzahl) => - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(verlaufOfStudent(data, student.uid).antrittCount, "antrittCount").to.eq(anzahl); }); @@ -226,7 +237,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { expectNotenSuccess(response, "Termin 2"), ); - readState(ctx) + readStateViaApi(ctx) .then((data) => { const t1 = attemptsOfStudent(data, student.uid)[0]; // die Note bleibt gleich, sonst meldet validateEdit pruefungNoteLocked @@ -269,7 +280,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { expect(row.punkte, "ohne Punkte").to.be.null; }); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const verlauf = verlaufOfStudent(data, student.uid); expect(verlauf.antrittCount, "der entschuldigte Termin verbraucht keinen Antritt").to.eq(0); expect(verlauf.canAdd, "ein weiterer Termin ist möglich").to.be.true; @@ -279,7 +290,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { expectNotenSuccess(response, "erster zählender Termin"), ); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const zaehlend = attemptsOfStudent(data, student.uid).find( (p) => String(p.note) === String(ctx.notes.negativ), ); @@ -292,7 +303,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { givenBaseline(ctx, student); - readState(ctx) + readStateViaApi(ctx) .then((data) => { const t1 = attemptsOfStudent(data, student.uid)[0]; return editPruefung(ctx, student, { @@ -318,7 +329,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { expectNotenSuccess(response, "Termin 2"), ); - readState(ctx) + readStateViaApi(ctx) .then((data) => { const t2 = attemptsOfStudent(data, student.uid)[1]; return editPruefung(ctx, student, { @@ -385,7 +396,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { addPruefung(ctx, student, { note: ctx.notes.negativ, datum: attemptDate(ctx, 1) }).then((response) => expectNotenSuccess(response, "Termin nach der Freigabe"), ); - return readLvGesamtnote(ctx, student.uid); + return readLvGesamtnoteViaDb(ctx, student.uid); }; it("hebt die Freigabe mit einem neuen Termin auf", function () { @@ -407,7 +418,7 @@ describe("Noten API - Prüfungstermin (write path)", () => { }); }); - it("creates the LV note when a student has none yet", () => { + it("legt die LV-Note an, wenn ein Studierender noch keine hat", () => { // der Bulk-Pfad läuft durch denselben Kern und schreibt die LV-Note vor dem Termin const student = studentFor(0); @@ -425,13 +436,10 @@ describe("Noten API - Prüfungstermin (write path)", () => { expect(data[student.uid], `row result for ${student.uid}`).to.be.an("object"); expect(data[student.uid].savedPruefung, "the Prüfung was written").to.exist; }) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { expect(row, "the LV note was created alongside").to.not.be.null; - expect(String(row.note), "carries the Prüfung's note").to.eq( - String(ctx.notes.nochNichtEingetragen), - ); + expect(String(row.note), "carries the Prüfung's note").to.eq(String(ctx.notes.nochNichtEingetragen)); }); }); - }); diff --git a/tests/cypress/e2e/specs/api/noten/noten.ueberschreiben.cy.js b/tests/cypress/e2e/specs/api/noten/noten.ueberschreiben.cy.js index 88c3bb08e..52db022b3 100644 --- a/tests/cypress/e2e/specs/api/noten/noten.ueberschreiben.cy.js +++ b/tests/cypress/e2e/specs/api/noten/noten.ueberschreiben.cy.js @@ -8,19 +8,29 @@ */ import { expectBulkRowError, expectNotenError, expectNotenSuccess } from "../../../../support/helpers/notenErrors"; -import { requireKonfiguration, requireWiederholung } from "../../../../support/helpers/notenConfig"; +import { + requireKonfiguration, + requireNotenModus, + requireWiederholung, + skipWenn, +} from "../../../../support/helpers/notenConfig"; import { attemptDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedZeugnisnote, } from "../../../../support/helpers/notenTestData"; -import { addPruefung, attemptsOfStudent, givenBaseline, readState } from "../../../../support/helpers/notenScenario"; +import { + addPruefung, + attemptsOfStudent, + givenBaseline, + readStateViaApi, +} from "../../../../support/helpers/notenScenario"; import { notenApi } from "../../../../support/api/notenApi"; -describe("Noten API - Notenvorschlag overwrite rules", () => { +describe("Noten API - Regeln zum Überschreiben des Notenvorschlags", () => { let ctx; before(() => { @@ -32,11 +42,10 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { const studentFor = (index) => ctx.students[index % ctx.students.length]; - it("refuses a note the editor list never offers", function () { + it("lehnt eine Note ab, die die Auswahlliste nicht anbietet", function () { requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_VORSCHLAG_NUR_LEHRENOTEN", true); - if (ctx.notes.nichtLehre === null) { - this.skip(); // every active note is a lehre note on this instance - } + // auf dieser Instanz kann jede aktive Note eine Lehrenote sein + skipWenn(this, ctx.notes.nichtLehre === null, "Übersprungen: keine Verwaltungsnote in tbl_note."); const student = studentFor(0); @@ -46,7 +55,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { notenApi .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.notes.nichtLehre) .then((response) => expectNotenError(response, "c4noteNichtInLehre")) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { expect(String(row.note), "a non-lehre note must not become the LV note").to.eq( String(ctx.notes.negativ), @@ -54,7 +63,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { }); }); - it("refuses to change the Notenvorschlag once a Prüfung exists", function () { + it("lehnt eine Änderung des Notenvorschlags nach einer Prüfung ab", function () { requireWiederholung(this, ctx); const student = studentFor(1); @@ -69,18 +78,15 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { notenApi .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[0]) .then((response) => expectNotenError(response, "c4notenvorschlagGesperrt")) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { - expect(String(row.note), "the attempt's grade must survive the call").to.eq( - String(ctx.gradeNotes[1]), - ); + expect(String(row.note), "the attempt's grade must survive the call").to.eq(String(ctx.gradeNotes[1])); }); }); - it("refuses to overwrite a locked Zeugnisnote", function () { - if (ctx.notes.nichtUeberschreibbar === null) { - this.skip(); // every active note allows the teacher to overwrite it on this instance - } + it("lehnt das Überschreiben einer gesperrten Zeugnisnote ab", function () { + // auf dieser Instanz darf die Lehrperson jede aktive Note überschreiben + skipWenn(this, ctx.notes.nichtUeberschreibbar === null, "Übersprungen: keine gesperrte Note in tbl_note."); const student = studentFor(4); @@ -90,7 +96,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { notenApi .saveNotenvorschlag(ctx.lvId, ctx.semKurzbz, student.uid, ctx.gradeNotes[1]) .then((response) => expectNotenError(response, "c4zeugnisnoteGesperrt")) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { expect(String(row.note), "the LV note must not change").to.eq(String(ctx.notes.negativ)); }); @@ -103,14 +109,13 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { requireKonfiguration(test, ctx, "CIS_GESAMTNOTE_VORSCHLAG_NUR_LEHRENOTEN", true); const ohneAntritt = (ctx.cisConfig.NOTEN_OHNE_ANTRITT || []).map(String); - if (ctx.notes.nichtLehre !== null && !ohneAntritt.includes(String(ctx.notes.nichtLehre))) return; + const brauchbar = ctx.notes.nichtLehre !== null && !ohneAntritt.includes(String(ctx.notes.nichtLehre)); - Cypress.log({ name: "skip", message: "Übersprungen: keine Verwaltungsnote, die einen Antritt verbraucht." }); - test.skip(); + skipWenn(test, !brauchbar, "Übersprungen: keine Verwaltungsnote, die einen Antritt verbraucht."); }; const expectNurAntritt1 = (student) => - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { expect(attemptsOfStudent(data, student.uid), "nur Antritt 1").to.have.length(1); }); @@ -126,7 +131,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { ); expectNurAntritt1(student); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(String(row.note), "die LV-Note bleibt").to.eq(String(ctx.notes.negativ)); }); }); @@ -139,10 +144,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { const gesperrt = ctx.notenOptions.find( (n) => n.lkt_ueberschreibbar === false && !anrechnung.includes(String(n.note)), ); - if (!gesperrt) { - Cypress.log({ name: "skip", message: "Übersprungen: keine gesperrte Note ausser den Anrechnungsnoten." }); - this.skip(); - } + skipWenn(this, !gesperrt, "Übersprungen: keine gesperrte Note ausser den Anrechnungsnoten."); const student = studentFor(1); @@ -177,7 +179,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { }); students.forEach((s) => - readLvGesamtnote(ctx, s.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, s.uid).then((row) => { expect(row, `keine LV-Note für ${s.uid}`).to.be.null; }), ); @@ -188,25 +190,20 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { // antwortet 200 und meldet die abgelehnte Zeile in data[uid]. describe("saveNotenvorschlagBulk", () => { beforeEach(function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus leitet der Import die Note aus den Punkten ab und verwirft eine - // Zeile ohne Punkte, bevor eine dieser Regeln greift - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv." }); - this.skip(); - } + // im Punktemodus leitet der Import die Note aus den Punkten ab und verwirft eine + // Zeile ohne Punkte, bevor eine dieser Regeln greift + requireNotenModus(this, ctx); requireWiederholung(this, ctx); }); - it("refuses to change the Notenvorschlag once a Prüfung exists", () => { + it("lehnt je Zeile eine Änderung des Notenvorschlags nach einer Prüfung ab", () => { const student = studentFor(3); givenBaseline(ctx, student); - addPruefung(ctx, student, { note: ctx.gradeNotes[1], datum: attemptDate(ctx, 1) }).then( - (response) => { - expectNotenSuccess(response, "seed a Prüfung"); - }, - ); + addPruefung(ctx, student, { note: ctx.gradeNotes[1], datum: attemptDate(ctx, 1) }).then((response) => { + expectNotenSuccess(response, "seed a Prüfung"); + }); notenApi .saveNotenvorschlagBulk(ctx.lvId, ctx.semKurzbz, [ @@ -216,7 +213,7 @@ describe("Noten API - Notenvorschlag overwrite rules", () => { const data = expectNotenSuccess(response, "saveNotenvorschlagBulk"); expectBulkRowError(data, student.uid, "c4notenvorschlagGesperrt"); }) - .then(() => readLvGesamtnote(ctx, student.uid)) + .then(() => readLvGesamtnoteViaDb(ctx, student.uid)) .then((row) => { expect(String(row.note), "the attempt's grade must survive the import").to.eq( String(ctx.gradeNotes[1]), diff --git a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.freigabe.cy.js b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.freigabe.cy.js index 0aca8a1ad..1f7301c59 100644 --- a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.freigabe.cy.js +++ b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.freigabe.cy.js @@ -3,7 +3,7 @@ import { requireKonfiguration } from "../../../../support/helpers/notenConfig"; import { baselineDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -37,7 +37,7 @@ context("Benotungstool UI - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.gradeNotes[0], freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false }); page.visitAndWaitForTable(ctx); page.expectFreigabeState(student.uid, "changed"); @@ -53,7 +53,7 @@ context("Benotungstool UI - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.gradeNotes[0], freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false }); page.visitAndWaitForTable(ctx); page.openFreigabeModal(); @@ -65,7 +65,7 @@ context("Benotungstool UI - Notenfreigabe", () => { page.expectAbgelehnt("@saveStudentenNoten"); page.expectFreigabeState(student.uid, "changed"); - readLvGesamtnote(ctx, student.uid).then((rowData) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((rowData) => { expect(rowData.freigabedatum, "eine abgelehnte Freigabe stempelt nichts").to.be.null; }); }); @@ -76,7 +76,7 @@ context("Benotungstool UI - Notenfreigabe", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.gradeNotes[0], freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false }); page.visitAndWaitForTable(ctx); page.expectFreigabeState(student.uid, "changed"); @@ -94,7 +94,7 @@ context("Benotungstool UI - Notenfreigabe", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.gradeNotes[0], freigegeben: false }); + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: false }); page.visitAndWaitForTable(ctx); page.openFreigabeModal(); diff --git a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.import.cy.js b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.import.cy.js index 110b50558..84752c126 100644 --- a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.import.cy.js +++ b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.import.cy.js @@ -1,5 +1,10 @@ import { benotungstoolPage as page } from "../../../../support/pages/benotungstool.po"; -import { requireKonfiguration, requireWiederholung } from "../../../../support/helpers/notenConfig"; +import { + requireKonfiguration, + requireNotenModus, + requireWiederholung, + skipWenn, +} from "../../../../support/helpers/notenConfig"; import { attemptDate, loadNotenContext, @@ -30,11 +35,8 @@ context("Benotungstool UI - Import", () => { }); beforeEach(function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus erwarten beide Importe Punkte statt einer Note - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv." }); - this.skip(); - } + // im Punktemodus erwarten beide Importe Punkte statt einer Note + requireNotenModus(this, ctx); }); /** @@ -45,7 +47,10 @@ context("Benotungstool UI - Import", () => { const kuerzelNote = () => { if (!ctx.cisConfig.CIS_GESAMTNOTE_IMPORT_NOTENKUERZEL) return null; - const kuerzelVon = (n) => String(n.anmerkung ?? "").trim().toLowerCase(); + const kuerzelVon = (n) => + String(n.anmerkung ?? "") + .trim() + .toLowerCase(); return (ctx.notenOptions ?? []).find((n) => { const k = kuerzelVon(n); @@ -60,10 +65,7 @@ context("Benotungstool UI - Import", () => { describe("Notenimport", () => { beforeEach(function () { - if (!ctx.cisConfig.CIS_GESAMTNOTE_NOTENIMPORT) { - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_NOTENIMPORT ist aus, der Button existiert nicht." }); - this.skip(); - } + requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_NOTENIMPORT", true); }); it("schreibt die LV-Note für jede Zeile", () => { @@ -102,10 +104,7 @@ context("Benotungstool UI - Import", () => { it("nimmt das Kürzel aus der Notenliste, sobald die Option das erlaubt", function () { const kuerzel = kuerzelNote(); - if (!kuerzel) { - Cypress.log({ name: "skip", message: "Skipped: keine Note mit brauchbarem Kürzel in tbl_note.anmerkung." }); - this.skip(); - } + skipWenn(this, !kuerzel, "Übersprungen: keine Note mit brauchbarem Kürzel in tbl_note.anmerkung."); const student = ctx.students[1]; @@ -120,10 +119,7 @@ context("Benotungstool UI - Import", () => { describe("Prüfungsimport", () => { beforeEach(function () { - if (!ctx.cisConfig.CIS_GESAMTNOTE_PRUEFUNGSIMPORT) { - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PRUEFUNGSIMPORT ist aus, der Button existiert nicht." }); - this.skip(); - } + requireKonfiguration(this, ctx, "CIS_GESAMTNOTE_PRUEFUNGSIMPORT", true); }); it("legt je Zeile einen datierten Antritt an", function () { @@ -134,8 +130,8 @@ context("Benotungstool UI - Import", () => { const datum = page.importDatum(attemptDate(ctx, 1), ctx.cisConfig.CIS_GESAMTNOTE_IMPORT_DATUMSFORMAT); resetNotenState(ctx); - seedBaseline(ctx, a.uid, { note: ctx.notes.negativ }); - seedBaseline(ctx, b.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, a, { note: ctx.notes.negativ }); + seedBaseline(ctx, b, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); @@ -157,11 +153,13 @@ context("Benotungstool UI - Import", () => { resetNotenState(ctx); page.visitAndWaitForTable(ctx); - page.importPruefungen([[ - student.uid, - page.importDatum(attemptDate(ctx, 1), ctx.cisConfig.CIS_GESAMTNOTE_IMPORT_DATUMSFORMAT), - ctx.gradeNotes[0], - ]]); + page.importPruefungen([ + [ + student.uid, + page.importDatum(attemptDate(ctx, 1), ctx.cisConfig.CIS_GESAMTNOTE_IMPORT_DATUMSFORMAT), + ctx.gradeNotes[0], + ], + ]); page.expectPruefung(student.uid, "antritt_1", { note: ctx.gradeNotes[0], antritt: 1 }); page.expectLvNote(student.uid, bezeichnung(ctx.gradeNotes[0])); @@ -185,8 +183,8 @@ context("Benotungstool UI - Import", () => { expect(perMatrikelnr.matrikelnr, "Matrikelnummer des Studierenden").to.be.a("string").and.not.be.empty; resetNotenState(ctx); - seedBaseline(ctx, perUid.uid, { note: ctx.notes.negativ }); - seedBaseline(ctx, perMatrikelnr.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, perUid, { note: ctx.notes.negativ }); + seedBaseline(ctx, perMatrikelnr, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); page.importPruefungen([ @@ -205,7 +203,10 @@ context("Benotungstool UI - Import", () => { page.expectWarnungen(4); page.gesendeteUids("@savePruefungenBulk", "pruefungen").then((uids) => { - expect(uids, "nur die gültigen Zeilen, die Matrikelnummer aufgelöst").to.deep.eq([perUid.uid, perMatrikelnr.uid]); + expect(uids, "nur die gültigen Zeilen, die Matrikelnummer aufgelöst").to.deep.eq([ + perUid.uid, + perMatrikelnr.uid, + ]); }); }); diff --git a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.notenvorschlag.cy.js b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.notenvorschlag.cy.js index c2142fd01..29a7201f3 100644 --- a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.notenvorschlag.cy.js +++ b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.notenvorschlag.cy.js @@ -1,10 +1,10 @@ import { benotungstoolPage as page } from "../../../../support/pages/benotungstool.po"; -import { requireKonfiguration } from "../../../../support/helpers/notenConfig"; +import { requireKonfiguration, requireNotenModus } from "../../../../support/helpers/notenConfig"; import { attemptDate, baselineDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -31,11 +31,8 @@ context("Benotungstool UI - Notenvorschlag", () => { }); beforeEach(function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus ist die Vorschlagsspalte gesperrt, die Note kommt aus den Punkten - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv." }); - this.skip(); - } + // im Punktemodus ist die Vorschlagsspalte gesperrt, die Note kommt aus den Punkten + requireNotenModus(this, ctx); }); it("trägt einen Vorschlag über den Zelleneditor ein", () => { @@ -84,9 +81,10 @@ context("Benotungstool UI - Notenvorschlag", () => { page.expectLvNote(student.uid, bezeichnung(ctx.gradeNotes[0])); page.getCell(student.uid, "antritt_1").should("contain.text", page.toDDMMYYYY(datum)); - readLvGesamtnote(ctx, student.uid).then((rowData) => { - expect(String(rowData.benotungsdatum).slice(0, 10), "das benotungsdatum bleibt heute") - .to.eq(new Date().toISOString().slice(0, 10)); + readLvGesamtnoteViaDb(ctx, student.uid).then((rowData) => { + expect(String(rowData.benotungsdatum).slice(0, 10), "das benotungsdatum bleibt heute").to.eq( + new Date().toISOString().slice(0, 10), + ); }); }); @@ -97,11 +95,13 @@ context("Benotungstool UI - Notenvorschlag", () => { const kontrolle = ctx.students[4]; // Sehr Gut zuerst: setNotenvorschlag vergleicht mit contains, "Gut" träfe "Sehr Gut" const vorschlag = ctx.gradeNotes[0]; - const pruefungsnote = ctx.gradeNotes.find((n) => ![vorschlag, ctx.notes.negativ].map(String).includes(String(n))); + const pruefungsnote = ctx.gradeNotes.find( + (n) => ![vorschlag, ctx.notes.negativ].map(String).includes(String(n)), + ); resetNotenState(ctx); - seedBaseline(ctx, wiederholung.uid, { erstantritt: false }); - seedBaseline(ctx, kontrolle.uid); + seedBaseline(ctx, wiederholung, { erstantritt: false }); + seedBaseline(ctx, kontrolle); seedPruefung(ctx, wiederholung, { note: pruefungsnote, datum: attemptDate(ctx, 1), typ: "Termin2" }); page.visitAndWaitForTable(ctx); @@ -123,11 +123,13 @@ context("Benotungstool UI - Notenvorschlag", () => { page.getCell(student.uid, "note_vorschlag").click(); // exakter Vergleich: "unentschuldigt" enthält "entschuldigt" - cy.get(".tabulator-edit-list-item").should("have.length.greaterThan", 0).then((items) => { - const labels = [...items].map((item) => item.innerText.trim()); - expect(labels, "Optionen des Editors").to.include(bezeichnung(ctx.gradeNotes[0])); - expect(labels, "Optionen des Editors").to.not.include(bezeichnung(ctx.notes.entschuldigt)); - }); + cy.get(".tabulator-edit-list-item") + .should("have.length.greaterThan", 0) + .then((items) => { + const labels = [...items].map((item) => item.innerText.trim()); + expect(labels, "Optionen des Editors").to.include(bezeichnung(ctx.gradeNotes[0])); + expect(labels, "Optionen des Editors").to.not.include(bezeichnung(ctx.notes.entschuldigt)); + }); }); it("blendet den Übernehmen-Button aus, sobald Vorschlag und LV-Note übereinstimmen", () => { @@ -141,5 +143,4 @@ context("Benotungstool UI - Notenvorschlag", () => { page.getUebernehmenButton(student.uid).should("not.exist"); }); - }); diff --git a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.pruefung.cy.js b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.pruefung.cy.js index a091cee4d..299863d84 100644 --- a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.pruefung.cy.js +++ b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.pruefung.cy.js @@ -3,14 +3,16 @@ import { waitForOk } from "../../../../support/helpers/network"; import { requireKommissionellerAntritt, requireKonfiguration, + requireNotenModus, requireWiederholung, + skipWenn, } from "../../../../support/helpers/notenConfig"; import { expectNotenSuccess } from "../../../../support/helpers/notenErrors"; import { addPruefung } from "../../../../support/helpers/notenScenario"; import { attemptDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -39,11 +41,8 @@ context("Benotungstool UI - Prüfungen", () => { }); beforeEach(function () { - if (ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE) { - // im Punktemodus ist das Notenfeld gesperrt, die Note kommt aus dem Notenschlüssel - Cypress.log({ name: "skip", message: "Skipped: CIS_GESAMTNOTE_PUNKTE ist aktiv." }); - this.skip(); - } + // im Punktemodus ist das Notenfeld gesperrt, die Note kommt aus dem Notenschlüssel + requireNotenModus(this, ctx); }); it("legt aus der Zelle eine Wiederholung an und zählt sie als Antritt 2", function () { @@ -52,7 +51,7 @@ context("Benotungstool UI - Prüfungen", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, student, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); @@ -68,7 +67,7 @@ context("Benotungstool UI - Prüfungen", () => { page.expectLvNote(student.uid, bezeichnung(ctx.gradeNotes[1])); // die Zelle zeigt den Freigabestatus, den der Server geschrieben hat; die Regel prüft noten.pruefungstermin - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { const geaendert = new Date(row.benotungsdatum) > new Date(row.freigabedatum); page.expectFreigabeState(student.uid, geaendert ? "changed" : "ok"); }); @@ -99,7 +98,7 @@ context("Benotungstool UI - Prüfungen", () => { const neuesDatum = attemptDate(ctx, 2); resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, student, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); @@ -120,7 +119,7 @@ context("Benotungstool UI - Prüfungen", () => { const student = ctx.students[0]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, student, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); @@ -147,8 +146,8 @@ context("Benotungstool UI - Prüfungen", () => { const [a, b] = ctx.students; resetNotenState(ctx); - seedBaseline(ctx, a.uid, { note: ctx.notes.negativ }); - seedBaseline(ctx, b.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, a, { note: ctx.notes.negativ }); + seedBaseline(ctx, b, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); @@ -175,7 +174,7 @@ context("Benotungstool UI - Prüfungen", () => { // 'entschuldigt' verbraucht keinen Antritt, deshalb bleibt ein weiterer Termin möglich const mitTerminAm = (student, datum) => { resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, student, { note: ctx.notes.negativ }); addPruefung(ctx, student, { note: ctx.notes.entschuldigt, datum }).then((response) => expectNotenSuccess(response, "bestehender Termin"), ); @@ -215,15 +214,16 @@ context("Benotungstool UI - Prüfungen", () => { it("legt den letzten Antritt als kommissionelle Prüfung an", function () { requireKommissionellerAntritt(this, ctx); - if (ctx.cisConfig.CIS_GESAMTNOTE_KOMMISSIONELL_AB_ANTRITT !== ctx.maxAntritte) { - Cypress.log({ name: "skip", message: "Übersprungen: der letzte Antritt ist nicht kommissionell." }); - this.skip(); - } + skipWenn( + this, + ctx.cisConfig.CIS_GESAMTNOTE_KOMMISSIONELL_AB_ANTRITT !== ctx.maxAntritte, + "Übersprungen: der letzte Antritt ist nicht kommissionell.", + ); const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ }); + seedBaseline(ctx, student, { note: ctx.notes.negativ }); page.visitAndWaitForTable(ctx); diff --git a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.punkte.cy.js b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.punkte.cy.js index ee12dc61d..3db49cbc1 100644 --- a/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.punkte.cy.js +++ b/tests/cypress/e2e/specs/ui/benotungstool/benotungstool.punkte.cy.js @@ -1,14 +1,10 @@ import { benotungstoolPage as page } from "../../../../support/pages/benotungstool.po"; -import { - requireKonfiguration, - requirePunkteModus, - requireWiederholung, -} from "../../../../support/helpers/notenConfig"; -import { attemptsOfStudent, readState } from "../../../../support/helpers/notenScenario"; +import { requireKonfiguration, requirePunkteModus, requireWiederholung } from "../../../../support/helpers/notenConfig"; +import { attemptsOfStudent, readStateViaApi } from "../../../../support/helpers/notenScenario"; import { attemptDate, loadNotenContext, - readLvGesamtnote, + readLvGesamtnoteViaDb, requireDbReset, resetNotenState, seedBaseline, @@ -82,7 +78,7 @@ context("Benotungstool UI - Punktemodus", () => { page.expectLvNote(student.uid, page.bezeichnungOf(ctx, noteMitte)); page.expectFreigabeState(student.uid, "changed"); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(String(row.note), "abgeleitete Note").to.eq(String(noteMitte)); expect(Number(row.punkte), "die Punkte werden mitgeschrieben").to.eq(MITTE); }); @@ -94,7 +90,7 @@ context("Benotungstool UI - Punktemodus", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.gradeNotes[0], freigegeben: true }); + seedBaseline(ctx, student, { note: ctx.gradeNotes[0], freigegeben: true }); seedPruefung(ctx, student, { note: ctx.gradeNotes[0], datum: attemptDate(ctx, 1), @@ -113,7 +109,7 @@ context("Benotungstool UI - Punktemodus", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: true }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: true }); page.visitAndWaitForTable(ctx); page.getPruefungAddButton(student.uid, "antritt_2").click(); @@ -127,7 +123,7 @@ context("Benotungstool UI - Punktemodus", () => { const student = ctx.students[1]; resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: true }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: true }); page.visitAndWaitForTable(ctx); page.getPruefungAddButton(student.uid, "antritt_2").click(); @@ -153,8 +149,8 @@ context("Benotungstool UI - Punktemodus", () => { const [a, b] = [ctx.students[2], ctx.students[3]]; resetNotenState(ctx); - seedBaseline(ctx, a.uid, { note: ctx.notes.negativ, freigegeben: true }); - seedBaseline(ctx, b.uid, { note: ctx.notes.negativ, freigegeben: true }); + seedBaseline(ctx, a, { note: ctx.notes.negativ, freigegeben: true }); + seedBaseline(ctx, b, { note: ctx.notes.negativ, freigegeben: true }); page.visitAndWaitForTable(ctx); page.addPruefungBulk({ uids: [a.uid, b.uid], punkte: MITTE, datum: page.toDDMMYYYY(attemptDate(ctx, 1)) }); @@ -179,14 +175,14 @@ context("Benotungstool UI - Punktemodus", () => { const datum = page.importDatum(attemptDate(ctx, 1), ctx.cisConfig.CIS_GESAMTNOTE_IMPORT_DATUMSFORMAT); resetNotenState(ctx); - seedBaseline(ctx, student.uid, { note: ctx.notes.negativ, freigegeben: true }); + seedBaseline(ctx, student, { note: ctx.notes.negativ, freigegeben: true }); page.visitAndWaitForTable(ctx); page.importPruefungen([[student.uid, datum, eingabe]]); cy.get("@savePruefungenBulk").its("request.body.pruefungen.0.punkte").should("eq", PUNKTE); - readState(ctx).then((data) => { + readStateViaApi(ctx).then((data) => { const neu = attemptsOfStudent(data, student.uid)[1]; expect(neu, "der importierte Termin").to.exist; expect(Number(neu.punkte), "die Punkte des Termins").to.eq(PUNKTE); @@ -205,7 +201,7 @@ context("Benotungstool UI - Punktemodus", () => { cy.get("@saveNotenvorschlagBulk").its("request.body.noten.0.punkte").should("eq", PUNKTE); - readLvGesamtnote(ctx, student.uid).then((row) => { + readLvGesamtnoteViaDb(ctx, student.uid).then((row) => { expect(row, "die importierte LV-Note").to.not.be.null; expect(Number(row.punkte), "die Punkte der LV-Note").to.eq(PUNKTE); }); diff --git a/tests/cypress/e2e/specs/unit/notenRules.cy.js b/tests/cypress/e2e/specs/unit/notenRules.cy.js index 49a52b7fe..f3f62573f 100644 --- a/tests/cypress/e2e/specs/unit/notenRules.cy.js +++ b/tests/cypress/e2e/specs/unit/notenRules.cy.js @@ -39,18 +39,48 @@ const student = (props) => ({ pruefungen: [], note: null, hoechsterAntritt: 0, . /** A row whose Verlauf the server has already delivered. */ const withVerlauf = (verlauf, props = {}) => student({ verlauf: { maxAntritte: 2, ...verlauf }, ...props }); -describe("Benotungstool rules (client)", () => { +describe("Benotungstool-Regeln (Client)", () => { describe("maxAntrittCount", () => { + it("liest die Zahl aus der Konfiguration", () => { + expect(maxAntrittCount(configWith(3))).to.eq(3); + expect(maxAntrittCount(configWith(1))).to.eq(1); + }); + + it("nimmt 1, solange die Konfiguration keine Zahl liefert", () => { + // getCisConfig liefert den Schlüssel erst nach dem Laden; bis dahin gilt ein Antritt + expect(maxAntrittCount({}), "Schlüssel fehlt").to.eq(1); + expect(maxAntrittCount({ CIS_GESAMTNOTE_MAX_ANTRITTE: null }), "Schlüssel ist null").to.eq(1); + expect(maxAntrittCount(undefined), "keine Konfiguration").to.eq(1); + expect(maxAntrittCount(null), "Konfiguration ist null").to.eq(1); + }); + + // Der Rückfall nutzt ??, nicht ||. Mit || würde eine konfigurierte 0 zu 1 werden und das + // Werkzeug liesse einen Antritt zu, den die Konfiguration verbietet. + it("behält eine konfigurierte 0", () => { + expect(maxAntrittCount(configWith(0))).to.eq(0); + }); + + // getMaxAntritte auf dem Server liefert ein int. Die Umwandlung hält den Wert auch dann eine + // Zahl, wenn er je als Text ankommt: die Aufrufer vergleichen ihn, die Tests streng. + it("gibt immer eine Zahl zurück", () => { + expect(maxAntrittCount(configWith("4")), "Text mit Zahl").to.eq(4); + expect(maxAntrittCount(configWith(3)), "bleibt eine Zahl").to.eq(3); + }); + + it("nimmt 1, wenn der Wert keine Zahl ist", () => { + expect(maxAntrittCount(configWith("abc")), "unbrauchbarer Text").to.eq(1); + expect(maxAntrittCount(configWith("")), "leerer Text").to.eq(1); + }); }); describe("antrittCountStudent", () => { - it("takes the count from the Verlauf when the server delivered one", () => { + it("nimmt die Anzahl aus dem Verlauf, wenn der Server einen liefert", () => { const s = withVerlauf({ antrittCount: 2 }, { note: 1, pruefungen: [{ note: 5 }] }); expect(antrittCountStudent(s, ours, notenOptions), "server wins over the local fallback").to.eq(2); }); - describe("local fallback (Verlauf not loaded yet)", () => { - it("does not count entschuldigt, 'noch nicht eingetragen' or 'nicht beurteilt'", () => { + describe("lokaler Rückfall, solange der Verlauf fehlt", () => { + it("zählt entschuldigt, 'noch nicht eingetragen' und 'nicht beurteilt' nicht mit", () => { // still just the original note: none of these consumed an attempt, which is what lets a // second retake be entered const s = student({ @@ -60,31 +90,34 @@ describe("Benotungstool rules (client)", () => { expect(antrittCountStudent(s, ours, notenOptions)).to.eq(1); }); - it("counts the original LV note as the first Antritt", () => { + it("zählt die ursprüngliche LV-Note als ersten Antritt", () => { expect(antrittCountStudent(student({ note: 1 }), ours, notenOptions)).to.eq(1); }); + // dieselbe Falle wie in brauchtNeueLvNote: die Note 0 ist eine Note, kein fehlender Wert + it("zählt auch die Note 0 als ersten Antritt", () => { + const mitNullNote = [...notenOptions, { note: 0, lehre: true }]; + expect(antrittCountStudent(student({ note: 0 }), ours, mitNullNote)).to.eq(1); + }); }); }); describe("canAddPruefung", () => { - it("follows the Verlauf", () => { + it("folgt dem Verlauf", () => { expect(canAddPruefung(withVerlauf({ canAdd: true, antrittCount: 1 }), ours)).to.be.true; expect(canAddPruefung(withVerlauf({ canAdd: false, antrittCount: 2 }), ours)).to.be.false; }); - it("blocks an angerechnet row even though attempts are left", () => { + it("sperrt eine angerechnete Zeile trotz freier Antritte", () => { // the server sets canAdd:false for an Anrechnung; the client must not second-guess it const s = withVerlauf({ canAdd: false, antrittCount: 0, angerechnet: true }); expect(canAddPruefung(s, ours)).to.be.false; }); - it("falls back to the cap and the terminal attempt without a Verlauf", () => { + it("fällt ohne Verlauf auf das Maximum und den letzten Antritt zurück", () => { expect(canAddPruefung(student({ note: 1 }), ours), "one attempt of two used").to.be.true; - expect( - canAddPruefung(student({ note: 1, pruefungen: [{ note: 5 }, { note: 4 }] }), ours), - "cap reached", - ).to.be.false; + expect(canAddPruefung(student({ note: 1, pruefungen: [{ note: 5 }, { note: 4 }] }), ours), "cap reached").to + .be.false; expect( canAddPruefung(student({ note: 1, pruefungen: [{ note: 5, kommissionell: true }] }), ours), "terminal attempt exists", @@ -93,7 +126,7 @@ describe("Benotungstool rules (client)", () => { // Bekannte Lücke, hier festgenagelt: die LV-Note zählt nur solange gar keine Prüfung // existiert. Deshalb schreibt die Freigabe Antritt 1 als echte Zeile. - it("stops counting the LV note once a Prüfung exists", () => { + it("zählt die LV-Note nicht mehr mit, sobald eine Prüfung existiert", () => { const s = student({ note: 1, pruefungen: [{ note: 5 }] }); expect(antrittCountStudent(s, ours, notenOptions), "the LV note is no longer added").to.eq(1); expect(canAddPruefung(s, ours), "so another attempt still looks available").to.be.true; @@ -101,10 +134,50 @@ describe("Benotungstool rules (client)", () => { }); describe("brauchtNeueLvNote", () => { + /** + * Der Verlauf schlägt lv_note, und zwar genau deshalb: lv_note trägt nur FREIGEGEBENE Noten + * (Benotungstool.js setzt es aus getLvGesamtNoten), hatLvNote dagegen zählt auch die + * eingetragene, noch nicht freigegebene Note mit. Noten.php nennt das Feld + * "ungefiltert, also inklusive noch nicht freigegebener". + */ + it("meldet keinen Bedarf, wenn die LV-Note nur noch nicht freigegeben ist", () => { + const s = { verlauf: { hatLvNote: true }, lv_note: null }; + expect(brauchtNeueLvNote(s), "die Note existiert, sie ist nur nicht freigegeben").to.be.false; + }); + + it("meldet Bedarf, wenn der Verlauf keine LV-Note kennt", () => { + // auch wenn lv_note gesetzt ist: der Verlauf entscheidet + expect(brauchtNeueLvNote({ verlauf: { hatLvNote: false }, lv_note: 1 })).to.be.true; + expect(brauchtNeueLvNote({ verlauf: { hatLvNote: false }, lv_note: null })).to.be.true; + }); + + // verlaufSummary hat für hatLvNote den Vorgabewert null. Ein Aufrufer, der ihn nicht + // übergibt, erzeugt damit den Hinweis "noch keine LV-Note". + it("meldet Bedarf, wenn der Verlauf das Feld nicht trägt", () => { + expect(brauchtNeueLvNote({ verlauf: {} })).to.be.true; + }); + + describe("lokaler Rückfall, solange der Verlauf fehlt", () => { + it("liest lv_note", () => { + expect(brauchtNeueLvNote({ lv_note: 1 }), "eine Note ist da").to.be.false; + expect(brauchtNeueLvNote({ lv_note: null }), "keine Note").to.be.true; + expect(brauchtNeueLvNote({}), "Feld fehlt").to.be.true; + }); + + // Die Note 0 ("Teilnote") ist eine Note. Ein truthy-Test hielte sie für "keine Note" und + // das Werkzeug verspräche eine neue LV-Note, obwohl eine existiert. + it("erkennt die Note 0 als Note", () => { + expect(brauchtNeueLvNote({ lv_note: 0 })).to.be.false; + }); + + it("hält einen leeren Text für keine Note", () => { + expect(brauchtNeueLvNote({ lv_note: "" })).to.be.true; + }); + }); }); describe("checkFreigabe", () => { - it("derives the state from the two timestamps", () => { + it("leitet den Status aus den beiden Zeitstempeln ab", () => { expect(checkFreigabe(null, null), "no grade at all").to.eq("offen"); expect(checkFreigabe(null, "2026-01-10 08:00:00"), "never released").to.eq("changed"); expect(checkFreigabe("2026-01-10 08:00:00", "2026-01-20 08:00:00"), "re-graded").to.eq("changed"); diff --git a/tests/cypress/profiles/noten.js b/tests/cypress/profiles/noten.js index f92b69fbd..29b7d45aa 100644 --- a/tests/cypress/profiles/noten.js +++ b/tests/cypress/profiles/noten.js @@ -106,7 +106,8 @@ module.exports = { }, offen: { - beschreibung: "frühere Noten änderbar, künftiges Benotungsdatum, keine Datumsfrist, ein Termin hebt die Freigabe nicht auf", + beschreibung: + "frühere Noten änderbar, künftiges Benotungsdatum, keine Datumsfrist, ein Termin hebt die Freigabe nicht auf", config: { CIS_GESAMTNOTE_NOTE_SPERRE_BEI_SPAETEREM_TERMIN: false, CIS_GESAMTNOTE_DATUM_ZUKUNFT: true, diff --git a/tests/cypress/suites/noten.js b/tests/cypress/suites/noten.js index aaee5df80..85eec77b8 100644 --- a/tests/cypress/suites/noten.js +++ b/tests/cypress/suites/noten.js @@ -16,20 +16,22 @@ const parallelPost = ({ path, bodies }) => { const base = String(process.env.BASE_URL).replace(/\/+$/, ""); const auth = "Basic " + Buffer.from(`${process.env.USER_NAME}:${process.env.USER_PASSWORD}`).toString("base64"); - return Promise.all(bodies.map((body) => - fetch(`${base}/index.ci.php/api/frontend/v1/Noten/${path}`, { - method: "POST", - headers: { Authorization: auth, "Content-Type": "application/json" }, - body: JSON.stringify(body), - }).then(async (r) => { - const text = await r.text(); - try { - return { status: r.status, body: JSON.parse(text) }; - } catch (e) { - return { status: r.status, body: null, text: text.slice(0, 500) }; - } - }), - )); + return Promise.all( + bodies.map((body) => + fetch(`${base}/index.ci.php/api/frontend/v1/Noten/${path}`, { + method: "POST", + headers: { Authorization: auth, "Content-Type": "application/json" }, + body: JSON.stringify(body), + }).then(async (r) => { + const text = await r.text(); + try { + return { status: r.status, body: JSON.parse(text) }; + } catch (e) { + return { status: r.status, body: null, text: text.slice(0, 500) }; + } + }), + ), + ); }; module.exports = { diff --git a/tests/cypress/support/api/notenApi.js b/tests/cypress/support/api/notenApi.js index 79d304cd2..2a29e41f6 100644 --- a/tests/cypress/support/api/notenApi.js +++ b/tests/cypress/support/api/notenApi.js @@ -26,11 +26,9 @@ export const notenApi = { getNoten: () => apiGet("getNoten"), - getBenotungstoolContext: (sem_kurzbz, lv_id = null) => - apiGet("getBenotungstoolContext", { sem_kurzbz, lv_id }), + getBenotungstoolContext: (sem_kurzbz, lv_id = null) => apiGet("getBenotungstoolContext", { sem_kurzbz, lv_id }), - getLvForStudiengang: (studiengang_kz, sem_kurzbz) => - apiGet("getLvForStudiengang", { studiengang_kz, sem_kurzbz }), + getLvForStudiengang: (studiengang_kz, sem_kurzbz) => apiGet("getLvForStudiengang", { studiengang_kz, sem_kurzbz }), getLehrendeFuerLehreinheit: (lehreinheit_id, lv_id, sem_kurzbz) => apiGet("getLehrendeFuerLehreinheit", { lehreinheit_id, lv_id, sem_kurzbz }), @@ -50,10 +48,26 @@ export const notenApi = { /** data -> [savedPruefung, lvgesamtnote, verlauf]. Kein `typ` auf der Leitung. Ohne mitarbeiter_uid fehlt das Feld. */ saveStudentPruefung: ({ - student_uid, note, punkte = null, datum, lva_id, lehreinheit_id, sem_kurzbz, pruefung_id = null, mitarbeiter_uid, + student_uid, + note, + punkte = null, + datum, + lva_id, + lehreinheit_id, + sem_kurzbz, + pruefung_id = null, + mitarbeiter_uid, }) => apiPost("saveStudentPruefung", { - student_uid, note, punkte, datum, lva_id, lehreinheit_id, sem_kurzbz, pruefung_id, mitarbeiter_uid, + student_uid, + note, + punkte, + datum, + lva_id, + lehreinheit_id, + sem_kurzbz, + pruefung_id, + mitarbeiter_uid, }), /** @@ -66,8 +80,7 @@ export const notenApi = { saveStudentenNoten: (password, noten, lv_id, sem_kurzbz) => apiGet("getCisConfig").then(() => apiPost("saveStudentenNoten", { password, noten, lv_id, sem_kurzbz })), - getNoteByPunkte: (punkte, lv_id, sem_kurzbz) => - apiPost("getNoteByPunkte", { punkte, lv_id, sem_kurzbz }), + getNoteByPunkte: (punkte, lv_id, sem_kurzbz) => apiPost("getNoteByPunkte", { punkte, lv_id, sem_kurzbz }), // Bulk-Pfade antworten 200 und melden Fehler je Zeile in data[uid] saveNotenvorschlagBulk: (lv_id, sem_kurzbz, noten) => @@ -83,8 +96,7 @@ export const notenApi = { // --- selectors over the getStudentenNoten payload --- -export const pruefungenOf = (data, uid) => - (data[1] || []).filter((p) => p.student_uid === uid); +export const pruefungenOf = (data, uid) => (data[1] || []).filter((p) => p.student_uid === uid); /** Antritte in Verlaufsreihenfolge. Specs prüfen position/zaehlt/antritt_nr/terminal, nie den Typ. */ export const attemptsOf = (data, uid) => @@ -94,8 +106,7 @@ export const attemptsOf = (data, uid) => export const countingAttemptsOf = (data, uid) => attemptsOf(data, uid).filter((p) => p.zaehlt); /** Legacy projection written for old reports. Asserted in exactly one spec, never used as a rule. */ -export const pruefungenOfTyp = (data, uid, typ) => - pruefungenOf(data, uid).filter((p) => p.pruefungstyp_kurzbz === typ); +export const pruefungenOfTyp = (data, uid, typ) => pruefungenOf(data, uid).filter((p) => p.pruefungstyp_kurzbz === typ); export const gradesOf = (data, uid) => (data[3] || {})[uid]; diff --git a/tests/cypress/support/commands.js b/tests/cypress/support/commands.js index 35423667a..e3fa720da 100644 --- a/tests/cypress/support/commands.js +++ b/tests/cypress/support/commands.js @@ -2,26 +2,26 @@ /** Visits a page and fails if any request returned >= 400. */ Cypress.Commands.add("checkPageResources", (url) => { - const failedRequests = []; + const failedRequests = []; - cy.intercept("**", (req) => { - req.on("response", (res) => { - if (res.statusCode >= 400) { - failedRequests.push({ url: req.url, status: res.statusCode }); - } - }); - }); + cy.intercept("**", (req) => { + req.on("response", (res) => { + if (res.statusCode >= 400) { + failedRequests.push({ url: req.url, status: res.statusCode }); + } + }); + }); - cy.env(["adminusername", "adminpassword"]).then(({ adminusername, adminpassword }) => { - cy.visit(url, { auth: { username: adminusername, password: adminpassword } }); - }); + cy.env(["adminusername", "adminpassword"]).then(({ adminusername, adminpassword }) => { + cy.visit(url, { auth: { username: adminusername, password: adminpassword } }); + }); - cy.then(() => { - if (failedRequests.length > 0) { - const message = failedRequests.map((r) => `${r.status} - ${r.url}`).join("\n"); - throw new Error(`Broken resources detected:\n${message}`); - } - }); + cy.then(() => { + if (failedRequests.length > 0) { + const message = failedRequests.map((r) => `${r.status} - ${r.url}`).join("\n"); + throw new Error(`Broken resources detected:\n${message}`); + } + }); }); /** @@ -30,22 +30,19 @@ Cypress.Commands.add("checkPageResources", (url) => { * Ohne Argumente meldet sich der Suite-Benutzer an. */ Cypress.Commands.add("login", (username, password) => { - const { adminusername, adminpassword } = Cypress.env(); - const auth = { username: username || adminusername, password: password || adminpassword }; - const probe = () => - cy - .request({ url: "/index.ci.php/api/frontend/v1/AuthInfo/getAuthUID", auth }) - .its("status") - .should("eq", 200); + const { adminusername, adminpassword } = Cypress.env(); + const auth = { username: username || adminusername, password: password || adminpassword }; + const probe = () => + cy.request({ url: "/index.ci.php/api/frontend/v1/AuthInfo/getAuthUID", auth }).its("status").should("eq", 200); - cy.session(["benotungstool-login", auth.username], probe, { - cacheAcrossSpecs: true, - validate: probe, - }); + cy.session(["benotungstool-login", auth.username], probe, { + cacheAcrossSpecs: true, + validate: probe, + }); }); // Anwendungsfehler sollen den Test nicht abbrechen, aber sichtbar sein. Cypress.on("uncaught:exception", (err) => { - Cypress.log({ name: "app error", message: err.message, consoleProps: () => ({ error: err }) }); - return false; + Cypress.log({ name: "app error", message: err.message, consoleProps: () => ({ error: err }) }); + return false; }); diff --git a/tests/cypress/support/helpers/network.js b/tests/cypress/support/helpers/network.js index 7a9a7b2cb..6e95ada6a 100644 --- a/tests/cypress/support/helpers/network.js +++ b/tests/cypress/support/helpers/network.js @@ -1,2 +1 @@ -export const waitForOk = (alias) => - cy.wait(alias).its("response.statusCode").should("eq", 200); +export const waitForOk = (alias) => cy.wait(alias).its("response.statusCode").should("eq", 200); diff --git a/tests/cypress/support/helpers/notenAssistenz.js b/tests/cypress/support/helpers/notenAssistenz.js index d206eb0d8..7d9b5fb35 100644 --- a/tests/cypress/support/helpers/notenAssistenz.js +++ b/tests/cypress/support/helpers/notenAssistenz.js @@ -7,6 +7,7 @@ */ import { expectNotenSuccess } from "./notenErrors"; +import { skipWenn } from "./notenConfig"; const NOTEN_API = "/index.ci.php/api/frontend/v1/Noten"; const SEMESTER_SUCHTIEFE = 6; @@ -14,6 +15,14 @@ const SEMESTER_SUCHTIEFE = 6; export const assistenzConfigured = () => Boolean(Cypress.env("NOTEN_ASSISTENZ_USER") && Cypress.env("NOTEN_ASSISTENZ_PASSWORD")); +/** Skip, wenn kein Konto der Assistenz konfiguriert ist. */ +export const requireAssistenz = (testContext) => + skipWenn( + testContext, + !assistenzConfigured(), + "Übersprungen: NOTEN_ASSISTENZ_USER / NOTEN_ASSISTENZ_PASSWORD fehlen.", + ); + export const assistenzAuth = () => ({ username: Cypress.env("NOTEN_ASSISTENZ_USER"), password: Cypress.env("NOTEN_ASSISTENZ_PASSWORD"), @@ -48,9 +57,9 @@ export const assistenzKontext = (startSem) => { i >= liste.length ? cy.wrap(null, { log: false }) : getAlsAssistenz("getBenotungstoolContext", { sem_kurzbz: liste[i] }).then((response) => { - const data = expectNotenSuccess(response, `Kontext der Assistenz in ${liste[i]}`); - return data.studiengaenge.length ? { sem: liste[i], data } : probiere(i + 1); - }); + const data = expectNotenSuccess(response, `Kontext der Assistenz in ${liste[i]}`); + return data.studiengaenge.length ? { sem: liste[i], data } : probiere(i + 1); + }); return probiere(0); }; @@ -67,19 +76,24 @@ export const assistenzLvMitLehreinheiten = (startSem) => j >= lvs.length ? cy.wrap(null, { log: false }) : cy - .task("noten:db:lehreinheitenDerLv", { lvId: lvs[j].lehrveranstaltung_id, semKurzbz: sem }) - .then((ids) => - ids.length - ? { sem, lvId: lvs[j].lehrveranstaltung_id, lehreinheiten: ids.map(String).sort() } - : ersteLvMitLehreinheiten(lvs, j + 1), - ); + .task("noten:db:lehreinheitenDerLv", { lvId: lvs[j].lehrveranstaltung_id, semKurzbz: sem }) + .then((ids) => + ids.length + ? { sem, lvId: lvs[j].lehrveranstaltung_id, lehreinheiten: ids.map(String).sort() } + : ersteLvMitLehreinheiten(lvs, j + 1), + ); const probiereStudiengang = (i) => i >= studiengaenge.length ? cy.wrap(null, { log: false }) - : getAlsAssistenz("getLvForStudiengang", { studiengang_kz: studiengaenge[i].studiengang_kz, sem_kurzbz: sem }) - .then((response) => ersteLvMitLehreinheiten(expectNotenSuccess(response, "LVs des Studiengangs"), 0)) - .then((ziel) => ziel || probiereStudiengang(i + 1)); + : getAlsAssistenz("getLvForStudiengang", { + studiengang_kz: studiengaenge[i].studiengang_kz, + sem_kurzbz: sem, + }) + .then((response) => + ersteLvMitLehreinheiten(expectNotenSuccess(response, "LVs des Studiengangs"), 0), + ) + .then((ziel) => ziel || probiereStudiengang(i + 1)); return probiereStudiengang(0); }); diff --git a/tests/cypress/support/helpers/notenConfig.js b/tests/cypress/support/helpers/notenConfig.js index d9b108184..5fcf2a1de 100644 --- a/tests/cypress/support/helpers/notenConfig.js +++ b/tests/cypress/support/helpers/notenConfig.js @@ -10,6 +10,19 @@ * vor - passt die Instanz nicht dazu, scheitert der Lauf sofort und laut. */ +/** + * Der einzige Weg, einen Test zu überspringen. `bedingung` wahr -> überspringen, `grund` sagt warum. + * In it(function(){...}) / beforeEach(function(){...}) aufrufen, nie in einer Pfeilfunktion: eine + * Pfeilfunktion bindet kein `this` und erreicht test.skip() nicht. + * + * Die require*-Helfer unten nennen je eine fachliche Voraussetzung und rufen ihrerseits skipWenn. + */ +export const skipWenn = (testContext, bedingung, grund) => { + if (!bedingung) return; + Cypress.log({ name: "skip", message: grund }); + testContext.skip(); +}; + /** Ist der Punktemodus auf dieser Instanz aktiv? */ export const punkteModus = (ctx) => Boolean(ctx.cisConfig.CIS_GESAMTNOTE_PUNKTE); @@ -35,24 +48,19 @@ export const assertPunkteModus = (ctx) => { }; /** Skip, wenn der Punktemodus aus ist. Als erste Zeile in beforeEach(function(){...}) aufrufen. */ -export const requirePunkteModus = (testContext, ctx) => { - if (punkteModus(ctx)) return; - cy.log("Übersprungen: CIS_GESAMTNOTE_PUNKTE ist aus."); - testContext.skip(); -}; +export const requirePunkteModus = (testContext, ctx) => + skipWenn(testContext, !punkteModus(ctx), "Übersprungen: CIS_GESAMTNOTE_PUNKTE ist aus."); /** * Skip, wenn der Schlüssel aus getCisConfig nicht den Zweig trägt, den der Test prüft. Ein Profil aus * tests/cypress/profiles/noten.js schaltet den anderen Zweig ein. */ -export const requireKonfiguration = (testContext, ctx, key, wert) => { - if (ctx.cisConfig[key] === wert) return; - Cypress.log({ - name: "skip", - message: `Übersprungen: ${key} ist ${JSON.stringify(ctx.cisConfig[key])}, der Test braucht ${JSON.stringify(wert)}.`, - }); - testContext.skip(); -}; +export const requireKonfiguration = (testContext, ctx, key, wert) => + skipWenn( + testContext, + ctx.cisConfig[key] !== wert, + `Übersprungen: ${key} ist ${JSON.stringify(ctx.cisConfig[key])}, der Test braucht ${JSON.stringify(wert)}.`, + ); /** * Skip, wenn das Werkzeug keinen zweiten Antritt anlegt. Ohne CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF @@ -64,9 +72,7 @@ export const requireWiederholung = (testContext, ctx) => { ctx.cisConfig.CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF === false && ab !== null ? Math.min(ctx.maxAntritte, ab - 1) : ctx.maxAntritte; - if (anlegbar >= 2) return; - Cypress.log({ name: "skip", message: `Übersprungen: das Werkzeug legt nur ${anlegbar} Antritt an.` }); - testContext.skip(); + skipWenn(testContext, anlegbar < 2, `Übersprungen: das Werkzeug legt nur ${anlegbar} Antritt an.`); }; /** @@ -76,17 +82,14 @@ export const requireWiederholung = (testContext, ctx) => { export const requireKommissionellerAntritt = (testContext, ctx) => { const ab = ctx.cisConfig.CIS_GESAMTNOTE_KOMMISSIONELL_AB_ANTRITT ?? null; const anlegbar = ctx.cisConfig.CIS_GESAMTNOTE_ALLOW_CREATE_KOMMPRUEF !== false; - if (anlegbar && ab !== null && ab >= 2 && ab <= ctx.maxAntritte) return; - Cypress.log({ - name: "skip", - message: `Übersprungen: kein anlegbarer kommissioneller Antritt (ab ${JSON.stringify(ab)}, anlegen ${anlegbar}).`, - }); - testContext.skip(); + const moeglich = anlegbar && ab !== null && ab >= 2 && ab <= ctx.maxAntritte; + skipWenn( + testContext, + !moeglich, + `Übersprungen: kein anlegbarer kommissioneller Antritt (ab ${JSON.stringify(ab)}, anlegen ${anlegbar}).`, + ); }; /** Skip, wenn der Punktemodus an ist. */ -export const requireNotenModus = (testContext, ctx) => { - if (!punkteModus(ctx)) return; - cy.log("Übersprungen: CIS_GESAMTNOTE_PUNKTE ist aktiv."); - testContext.skip(); -}; +export const requireNotenModus = (testContext, ctx) => + skipWenn(testContext, punkteModus(ctx), "Übersprungen: CIS_GESAMTNOTE_PUNKTE ist aktiv."); diff --git a/tests/cypress/support/helpers/notenErrors.js b/tests/cypress/support/helpers/notenErrors.js index 37f3ac96a..d86f0ed1a 100644 --- a/tests/cypress/support/helpers/notenErrors.js +++ b/tests/cypress/support/helpers/notenErrors.js @@ -116,7 +116,12 @@ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Split on the {n} placeholders first, then escape - the other order breaks on the braces. const toPattern = (text) => - new RegExp(text.split(/\{\d+\}/).map(escapeRegExp).join("[\\s\\S]*?")); + new RegExp( + text + .split(/\{\d+\}/) + .map(escapeRegExp) + .join("[\\s\\S]*?"), + ); const patternsFor = (key) => { const phrase = PHRASES[key]; @@ -141,7 +146,7 @@ export const expectNotenError = (response, key) => { export const expectNotenSuccess = (response, context = "request") => { // carry the server's message into the assertion, or a 500 says only "expected 200" - const errors = (response.body && response.body.errors || []).map((e) => e.message).join(" | "); + const errors = ((response.body && response.body.errors) || []).map((e) => e.message).join(" | "); expect(response.status, `HTTP status for ${context}${errors ? ` -- ${errors}` : ""}`).to.eq(200); expect(response.body, context).to.have.nested.property("meta.status", "success"); return response.body.data; @@ -164,7 +169,6 @@ export const expectBulkRowError = (data, uid, key) => { export const expectBulkRowAccepted = (data, uid) => { expect(data).to.have.property(uid); const value = data[uid]; - const isError = - typeof value === "string" && Object.keys(PHRASES).some((k) => messageMatchesPhrase(value, k)); + const isError = typeof value === "string" && Object.keys(PHRASES).some((k) => messageMatchesPhrase(value, k)); expect(isError, `expected row "${uid}" accepted, got: ${JSON.stringify(value)}`).to.be.false; }; diff --git a/tests/cypress/support/helpers/notenScenario.js b/tests/cypress/support/helpers/notenScenario.js index 67e3acb2a..8a71f6200 100644 --- a/tests/cypress/support/helpers/notenScenario.js +++ b/tests/cypress/support/helpers/notenScenario.js @@ -35,7 +35,11 @@ export const editPruefung = (context, student, { pruefungId, note, datum }) => pruefung_id: pruefungId, }); -export const readState = (context) => +/** + * Liest den Zustand über die API (getStudentenNoten): was der Server MELDET. + * Das Gegenstück ist readLvGesamtnoteViaDb - es liest, was wirklich gespeichert ist. + */ +export const readStateViaApi = (context) => notenApi .getStudentenNoten(context.lvId, context.semKurzbz) .then((response) => expectNotenSuccess(response, "getStudentenNoten")); @@ -53,4 +57,4 @@ export const lvNoteOf = (data, uid) => gradesOf(data, uid); /** Clears the suite's rows and re-seeds the Antritt-1 baseline for one student. */ export const givenBaseline = (context, student, options = {}) => - resetNotenState(context).then(() => seedBaseline(context, student.uid, options)); + resetNotenState(context).then(() => seedBaseline(context, student, options)); diff --git a/tests/cypress/support/helpers/notenTestData.js b/tests/cypress/support/helpers/notenTestData.js index 7f3e955a6..dbfeac156 100644 --- a/tests/cypress/support/helpers/notenTestData.js +++ b/tests/cypress/support/helpers/notenTestData.js @@ -10,8 +10,13 @@ import { expectNotenSuccess } from "./notenErrors"; // the client rule; it now only reads back what the server derived, so a mismatch is a config bug import { maxAntrittCount as computeMaxAntritte } from "../../../../public/js/components/Cis/Benotungstool/notenRules.js"; import { - describeFailure, performRead, performReset, performSeed, performSeedPruefung, - performSeedZeugnisnote, resolveResetStrategy, + describeFailure, + performRead, + performReset, + performSeed, + performSeedPruefung, + performSeedZeugnisnote, + resolveResetStrategy, } from "./notenReset"; import { assertPunkteModus } from "./notenConfig"; @@ -24,8 +29,7 @@ let cachedContext = null; export const pad2 = (n) => String(n).padStart(2, "0"); -export const toDateString = (date) => - `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`; +export const toDateString = (date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`; export const shiftDate = (dateString, days) => { const [y, m, d] = dateString.split("-").map(Number); @@ -35,11 +39,7 @@ export const shiftDate = (dateString, days) => { }; /** Deadline the server derives (computeNoteneintragungsfrist): SS -> 15.11.yyyy, WS -> 15.05.yyyy+1. */ -export const expectedFristString = ( - semKurzbz, - ssConfig = { month: 11, day: 15 }, - wsConfig = { month: 5, day: 15 }, -) => { +export const expectedFristString = (semKurzbz, ssConfig = { month: 11, day: 15 }, wsConfig = { month: 5, day: 15 }) => { const type = semKurzbz.slice(0, 2).toUpperCase(); const year = Number(semKurzbz.slice(2, 6)); const cfg = type === "SS" ? ssConfig : wsConfig; @@ -60,7 +60,7 @@ export const fristHasPassed = (semKurzbz, ssConfig = { month: 11, day: 15 }, wsC * A semester + course where the logged-in user actually teaches AND the grade deadline has passed. * * Both are needed: assertLvAccess runs BEFORE the deadline check, so a semester the user does not - * teach in fails there and never reaches the deadline. Seeder 019 provides the Sommersemester. + * teach in fails there and never reaches the deadline. Seeder group benotungstool_fixture_erweitert provides the Sommersemester. * * @param {string} type "SS" or "WS" * @returns {Cypress.Chainable<{semKurzbz: string, lvId: number}|null>} @@ -137,7 +137,6 @@ const resolveLehrveranstaltung = (semKurzbz) => { }); }; - /** -> { semKurzbz, lvId, cisConfig, maxAntritte, notes, gradeNotes, students, studentUids } */ export const loadNotenContext = () => { if (cachedContext) return cy.wrap(cachedContext, { log: false }); @@ -183,7 +182,10 @@ export const loadNotenContext = () => { context.gradeNotes = ordinary.length > 1 ? ordinary - : usable.map((n) => n.note).filter((n) => Number(n) !== 0).sort((a, b) => Number(a) - Number(b)); + : usable + .map((n) => n.note) + .filter((n) => Number(n) !== 0) + .sort((a, b) => Number(a) - Number(b)); expect(context.gradeNotes.length, "need two ordinary grades to vary one on edit").to.be.greaterThan(1); @@ -244,8 +246,7 @@ export const loadNotenContext = () => { // --- fixture state --- -export const resetNotenState = (context, studentUids) => - performReset(context, studentUids || context.studentUids); +export const resetNotenState = (context, studentUids) => performReset(context, studentUids || context.studentUids); /** * Baseline für Antritt 1: freigegebene LV-Note PLUS die Prüfungszeile dazu - das ist, was die @@ -254,18 +255,24 @@ export const resetNotenState = (context, studentUids) => * * `erstantritt: false` (bzw. `freigegeben: false`) seedet die Altdaten-Form ohne diese Zeile. */ -export const seedBaseline = (context, studentUid, options = {}) => { +export const seedBaseline = (context, student, options = {}) => { + expect(student, "seedBaseline braucht das Studierenden-Objekt aus context.students, nicht die uid").to.be.an( + "object", + ); + // Defaults to a NEGATIVE grade: only after one may another attempt follow. Pass // context.notes.bestnote explicitly to close the chain. const note = options.note !== undefined ? options.note : context.notes.negativ; // Mit CIS_GESAMTNOTE_FREIGABE_FINAL ist eine freigegebene Note endgültig. Ohne ausdrückliches // freigegeben sät die Baseline dann eine offene Note, damit ein Test weitere Termine anlegen kann. const freigegeben = - options.freigegeben !== undefined ? options.freigegeben : context.cisConfig.CIS_GESAMTNOTE_FREIGABE_FINAL !== true; + options.freigegeben !== undefined + ? options.freigegeben + : context.cisConfig.CIS_GESAMTNOTE_FREIGABE_FINAL !== true; // Antritt 1 fehlt nur bei ausdrücklichem erstantritt: false oder freigegeben: false const erstantritt = options.erstantritt !== undefined ? options.erstantritt : options.freigegeben !== false; - return performSeed(context, studentUid, { + return performSeed(context, student.uid, { note, punkte: options.punkte !== undefined ? options.punkte : null, benotungsdatum: options.benotungsdatum || baselineBenotungsdatum(context), @@ -274,10 +281,7 @@ export const seedBaseline = (context, studentUid, options = {}) => { }).then((seeded) => { if (!erstantritt) return cy.wrap(seeded, { log: false }); - const student = context.students.find((s) => s.uid === studentUid); - expect(student, `student ${studentUid} in the loaded LV`).to.exist; - - return performSeedPruefung(context, studentUid, { + return performSeedPruefung(context, student.uid, { lehreinheitId: student.lehreinheit_id, note, datum: baselineDate(context), @@ -296,11 +300,13 @@ export const seedPruefung = (context, student, { note, datum, typ }) => }); /** Zeugnisnote setzen. Nur die Studierendenverwaltung schreibt sie, kein Endpunkt dieses Tools. */ -export const seedZeugnisnote = (context, studentUid, note) => - performSeedZeugnisnote(context, studentUid, { note }); +export const seedZeugnisnote = (context, studentUid, note) => performSeedZeugnisnote(context, studentUid, { note }); -/** Raw row, bypassing the freigabedatum filter of getLvGesamtNoten. */ -export const readLvGesamtnote = (context, studentUid) => performRead(context, studentUid); +/** + * Liest die LV-Note direkt aus der DATENBANK: was wirklich gespeichert ist, ohne den + * freigabedatum-Filter von getLvGesamtNoten. Das Gegenstück ist readStateViaApi. + */ +export const readLvGesamtnoteViaDb = (context, studentUid) => performRead(context, studentUid); /** Anchor date; attempt dates derive from it so ordering is known. */ export const baselineBenotungsdatum = (context) => `${Number(context.semKurzbz.slice(2, 6))}-01-10 08:00:00`; diff --git a/tests/cypress/support/pages/benotungstool.po.js b/tests/cypress/support/pages/benotungstool.po.js index 3fc504383..daa7be82d 100644 --- a/tests/cypress/support/pages/benotungstool.po.js +++ b/tests/cypress/support/pages/benotungstool.po.js @@ -19,8 +19,7 @@ const API = "**/api/frontend/v1/Noten"; * Exakter Textvergleich für Optionslisten. Nötig, weil die Notenbezeichnungen einander enthalten: * contains("Gut") trifft zuerst "Sehr Gut", contains("Genügend") zuerst "Nicht Genügend". */ -const exactText = (text) => - new RegExp(`^\\s*${String(text).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`); +const exactText = (text) => new RegExp(`^\\s*${String(text).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`); class BenotungstoolPage { selectors = { @@ -73,10 +72,8 @@ class BenotungstoolPage { getFreigabeState = (uid) => this.getCell(uid, "freigegeben").find("[data-cy='freigabe-state']"); getPruefungCell = (uid, spalte) => this.getCell(uid, spalte).find("[data-cy='pruefung-cell']"); getUebernehmenButton = (uid) => this.getCell(uid, "übernehmen").find("[data-cy='btn-uebernehmen']"); - getPruefungAddButton = (uid, spalte) => - this.getCell(uid, spalte).find("[data-cy='btn-pruefung-add']"); - getPruefungEditButton = (uid, spalte) => - this.getCell(uid, spalte).find("[data-cy='btn-pruefung-edit']"); + getPruefungAddButton = (uid, spalte) => this.getCell(uid, spalte).find("[data-cy='btn-pruefung-add']"); + getPruefungEditButton = (uid, spalte) => this.getCell(uid, spalte).find("[data-cy='btn-pruefung-edit']"); getPruefungModal = () => cy.get("[data-cy='modal-pruefung']"); getNeuePruefungModal = () => cy.get("[data-cy='modal-neue-pruefung']"); @@ -89,8 +86,7 @@ class BenotungstoolPage { // --- Zustand prüfen -------------------------------------------------------------------------- /** offen | changed | ok */ - expectFreigabeState = (uid, state) => - this.getFreigabeState(uid).should("have.attr", "data-state", state); + expectFreigabeState = (uid, state) => this.getFreigabeState(uid).should("have.attr", "data-state", state); expectLvNote = (uid, bezeichnung) => this.getCell(uid, "lv_note").should("contain.text", bezeichnung); @@ -149,7 +145,11 @@ class BenotungstoolPage { cy.get(".p-toast-message-warn", { timeout: TABLE_TIMEOUT }).should("have.length.at.least", anzahl); /** Die uids des letzten Requests eines Sammelpfads. feld: "noten" oder "pruefungen" */ - gesendeteUids = (alias, feld) => cy.get(alias).its(`request.body.${feld}`).then((zeilen) => zeilen.map((z) => z.uid)); + gesendeteUids = (alias, feld) => + cy + .get(alias) + .its(`request.body.${feld}`) + .then((zeilen) => zeilen.map((z) => z.uid)); // --- Notenvorschlag -------------------------------------------------------------------------- @@ -184,8 +184,7 @@ class BenotungstoolPage { cy.contains(".p-dropdown-panel .p-dropdown-item", exactText(label)).click(); }; - setDatum = (dataCy, ddmmyyyy) => - cy.get(`[data-cy='${dataCy}'] input`).first().clear().type(`${ddmmyyyy}{enter}`); + setDatum = (dataCy, ddmmyyyy) => cy.get(`[data-cy='${dataCy}'] input`).first().clear().type(`${ddmmyyyy}{enter}`); /** * Nach jeder Speicherung zeigt das Tool einen Erfolgs-Toast ohne Ablaufzeit. Er liegt über dem Modal @@ -279,8 +278,7 @@ class BenotungstoolPage { .find("[data-cy='freigabe-row-released']") .should("contain.text", releasedBezeichnung); - typeFreigabePasswort = (password) => - cy.get("[data-cy='freigabe-passwort'] input").type(password, { log: false }); + typeFreigabePasswort = (password) => cy.get("[data-cy='freigabe-passwort'] input").type(password, { log: false }); submitFreigabe = () => cy.get("[data-cy='freigabe-submit']").click(); @@ -349,8 +347,7 @@ class BenotungstoolPage { waitForOk("@getNoteByPunkte"); }; - expectPunkte = (uid, punkte) => - this.getPunkteCell(uid).should("contain.text", String(punkte)); + expectPunkte = (uid, punkte) => this.getPunkteCell(uid).should("contain.text", String(punkte)); /** Sobald ein Termin existiert, ist die Punktespalte gesperrt (editable-Guard der Spalte). */ expectPunkteZelleGesperrt = (uid) => { @@ -373,14 +370,12 @@ class BenotungstoolPage { }; /** Punktefeld der Sammelanlage; dort leitet erst der Server beim Speichern ab. */ - setNeuePruefungPunkte = (punkte) => - cy.get("[data-cy='neue-pruefung-punkte'] input").clear().type(String(punkte)); + setNeuePruefungPunkte = (punkte) => cy.get("[data-cy='neue-pruefung-punkte'] input").clear().type(String(punkte)); // --- Hilfen ---------------------------------------------------------------------------------- /** Die Bezeichnung zu einer Noten-PK, wie sie in Dropdowns und Zellen steht. */ - bezeichnungOf = (ctx, note) => - (ctx.notenOptions ?? []).find((n) => String(n.note) === String(note))?.bezeichnung; + bezeichnungOf = (ctx, note) => (ctx.notenOptions ?? []).find((n) => String(n.note) === String(note))?.bezeichnung; toDDMMYYYY = (isoDate) => { const [y, m, d] = isoDate.split("-"); @@ -388,8 +383,7 @@ class BenotungstoolPage { }; /** Date in the configured import format; kept apart from toDDMMYYYY, which the dialog uses. */ - importDatum = (isoDate, format) => - format === "yyyy-MM-dd" ? isoDate : this.toDDMMYYYY(isoDate); + importDatum = (isoDate, format) => (format === "yyyy-MM-dd" ? isoDate : this.toDDMMYYYY(isoDate)); } export const benotungstoolPage = new BenotungstoolPage(); diff --git a/tests/cypress/tasks/db.js b/tests/cypress/tasks/db.js index 8bcd3f09f..d97a9be01 100644 --- a/tests/cypress/tasks/db.js +++ b/tests/cypress/tasks/db.js @@ -24,7 +24,6 @@ const getPool = () => { if (pool) return pool; // lazy require so the suite loads without pg when no DB task is used - // eslint-disable-next-line global-require const { Pool } = require("pg"); // with a tunnel up, bind to its local end - that is what gets us past pg_hba @@ -37,8 +36,16 @@ const getPool = () => { user: env("USER"), password: env("PASSWORD"), max: 4, + // tells these connections apart from the web application in pg_stat_activity + application_name: "cypress", + connectionTimeoutMillis: 15000, + // the server ends a stuck statement or transaction before the 60 s task timeout, so no lock wait holds a connection + statement_timeout: 30000, + idle_in_transaction_session_timeout: 30000, ssl: String(env("SSL")).toLowerCase() === "true" ? { rejectUnauthorized: false } : undefined, }); + // an idle client that loses its connection emits here; without a listener the config process crashes + pool.on("error", (error) => console.warn(`[db] idle connection lost: ${error.message}`)); return pool; }; @@ -115,19 +122,27 @@ const checkAvailability = async ({ requireWrites = true } = {}) => { } catch (error) { // a failed pool is poisoned - drop it so a retry reconnects cleanly if (pool) { - try { await pool.end(); } catch (e) { /* ignore */ } + const failed = pool; pool = null; + try { + await failed.end(); + } catch (e) { + /* ignore */ + } } return { available: false, reason: explainFailure(error) }; } }; const closeDb = async () => { - if (pool) { - await pool.end(); - pool = null; + // drop the reference first: a later task must not get a pool that is ending + const open = pool; + pool = null; + try { + if (open) await open.end(); + } finally { + await closeTunnel(); } - await closeTunnel(); return null; }; diff --git a/tests/cypress/tasks/notenDb.js b/tests/cypress/tasks/notenDb.js index 83380e41d..152ab2916 100644 --- a/tests/cypress/tasks/notenDb.js +++ b/tests/cypress/tasks/notenDb.js @@ -9,9 +9,7 @@ * No unscoped DELETE in this file. */ -const { - assertWritable, dbConfigured, withClient, inTransaction, checkAvailability, closeDb, -} = require("./db"); +const { assertWritable, dbConfigured, withClient, inTransaction, checkAvailability, closeDb } = require("./db"); const REQUIRED_SCOPE = ["lvId", "semKurzbz", "studentUids"]; @@ -83,8 +81,15 @@ const seedLvGesamtnote = async (scope) => { assertScope({ ...scope, studentUids: [scope.studentUid] }); const { - lvId, semKurzbz, studentUid, note, punkte = null, mitarbeiterUid, - benotungsdatum, freigegeben = false, freigabedatum = null, + lvId, + semKurzbz, + studentUid, + note, + punkte = null, + mitarbeiterUid, + benotungsdatum, + freigegeben = false, + freigabedatum = null, } = scope; if (note === undefined || note === null) throw new Error("noten:db seed - note is required"); @@ -107,8 +112,15 @@ const seedLvGesamtnote = async (scope) => { mitarbeiter_uid, benotungsdatum, freigabedatum, freigabevon_uid, insertamum, insertvon) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), $6)`, [ - studentUid, lvId, semKurzbz, note, punkte, mitarbeiterUid, - benotungsdatum, resolvedFreigabe, resolvedFreigabe ? mitarbeiterUid : null, + studentUid, + lvId, + semKurzbz, + note, + punkte, + mitarbeiterUid, + benotungsdatum, + resolvedFreigabe, + resolvedFreigabe ? mitarbeiterUid : null, ], ); @@ -140,7 +152,9 @@ const seedPruefung = async (scope) => { [lehreinheitId, lvId, semKurzbz], ); if (!owned.rowCount) { - throw new Error(`noten:db seedPruefung refused - lehreinheit ${lehreinheitId} is outside ${lvId}/${semKurzbz}`); + throw new Error( + `noten:db seedPruefung refused - lehreinheit ${lehreinheitId} is outside ${lvId}/${semKurzbz}`, + ); } const res = await client.query( @@ -336,7 +350,8 @@ const lehrendeDerLehreinheit = async ({ lehreinheitId } = {}) => { /** The grading person of one exam row, or null. */ const pruefungMitarbeiter = async ({ pruefungId, studentUid } = {}) => { assertReadable(); - if (!pruefungId || !studentUid) throw new Error("noten:db pruefungMitarbeiter - pruefungId and studentUid are required"); + if (!pruefungId || !studentUid) + throw new Error("noten:db pruefungMitarbeiter - pruefungId and studentUid are required"); const rows = await readRows( "SELECT mitarbeiter_uid FROM lehre.tbl_pruefung WHERE pruefung_id = $1 AND student_uid = $2", diff --git a/tests/cypress/tasks/notenProfil.js b/tests/cypress/tasks/notenProfil.js index bc89fe875..9b53f229c 100644 --- a/tests/cypress/tasks/notenProfil.js +++ b/tests/cypress/tasks/notenProfil.js @@ -46,12 +46,15 @@ const sshKonfiguriert = () => Boolean(envWert("SSH_HOST") && envWert("SSH_USER") const verbinde = () => new Promise((resolve, reject) => { - // eslint-disable-next-line global-require const { Client } = require("ssh2"); let auth; try { - auth = resolveAuth({ keyPath: envWert("SSH_KEY"), passphrase: envWert("SSH_PASSPHRASE"), agent: envWert("SSH_AGENT") }); + auth = resolveAuth({ + keyPath: envWert("SSH_KEY"), + passphrase: envWert("SSH_PASSPHRASE"), + agent: envWert("SSH_AGENT"), + }); } catch (error) { reject(error); return; @@ -60,7 +63,9 @@ const verbinde = () => const client = new Client(); client .on("ready", () => client.sftp((err, sftp) => (err ? reject(err) : resolve({ client, sftp })))) - .on("error", (err) => reject(new Error(`SSH zu ${envWert("SSH_USER")}@${envWert("SSH_HOST")} gescheitert: ${err.message}`))) + .on("error", (err) => + reject(new Error(`SSH zu ${envWert("SSH_USER")}@${envWert("SSH_HOST")} gescheitert: ${err.message}`)), + ) .connect({ host: envWert("SSH_HOST"), port: Number(envWert("SSH_PORT") || 22), @@ -133,7 +138,9 @@ const mitFlags = (original, flags) => { Object.entries(flags).forEach(([flag, wert]) => { const muster = new RegExp(`^([ \\t]*)define\\(\\s*['"]${flag}['"]\\s*,[^;]*;`, "m"); if (!muster.test(text)) { - throw new Error(`${DATEIEN.flags} definiert ${flag} nicht. Ein Profil ändert nur einen bestehenden Schalter.`); + throw new Error( + `${DATEIEN.flags} definiert ${flag} nicht. Ein Profil ändert nur einen bestehenden Schalter.`, + ); } text = text.replace(muster, (treffer, einzug) => `${einzug}define('${flag}', ${phpWert(wert)});`); }); @@ -198,7 +205,8 @@ const setze = async (sftp, zustand, schluessel, umbau) => { } original = await lies(sftp, sicherung); } else { - if (eintrag) console.warn(`[profil] ${entfernt} ist seit dem letzten Profil neu ausgerollt und gilt als Original.`); + if (eintrag) + console.warn(`[profil] ${entfernt} ist seit dem letzten Profil neu ausgerollt und gilt als Original.`); await schreibeRoh(sftp, sicherung, aktuell, 0o600); } @@ -232,7 +240,9 @@ const leseCisConfig = async (url, auth) => { // unter 500 steht eine PHP-Meldung vor dem JSON: die Datei ist kaputt, Warten hilft nicht if (antwort.status < 500) { - throw new Error(`getCisConfig antwortet nach dem Profilwechsel mit HTTP ${antwort.status}: ${text.slice(0, 300)}`); + throw new Error( + `getCisConfig antwortet nach dem Profilwechsel mit HTTP ${antwort.status}: ${text.slice(0, 300)}`, + ); } return { ist: null, grund: `getCisConfig antwortet mit HTTP ${antwort.status}` }; }; @@ -259,7 +269,9 @@ const pruefeInstanz = async (daten) => { const abweichend = pruefbar.filter((key) => !gleich(ist[key], erwartet[key])); if (!abweichend.length) return; - const liste = abweichend.map((k) => ` ${k}: ${JSON.stringify(ist[k])} statt ${JSON.stringify(erwartet[k])}`); + const liste = abweichend.map( + (k) => ` ${k}: ${JSON.stringify(ist[k])} statt ${JSON.stringify(erwartet[k])}`, + ); offen = `die Instanz zeigt das Profil nicht:\n${liste.join("\n")}`; } @@ -295,7 +307,9 @@ const anwenden = async (name) => { const daten = profilDaten(name); const root = envWert("REMOTE_ROOT"); if (!sshKonfiguriert() || !root) { - throw new Error(`Profil "${name}" braucht ${PREFIX}_SSH_HOST, ${PREFIX}_SSH_USER und ${PREFIX}_REMOTE_ROOT in tests/cypress/.env.`); + throw new Error( + `Profil "${name}" braucht ${PREFIX}_SSH_HOST, ${PREFIX}_SSH_USER und ${PREFIX}_REMOTE_ROOT in tests/cypress/.env.`, + ); } await mitSftp(async (sftp) => { @@ -303,12 +317,15 @@ const anwenden = async (name) => { const zustand = (await leseZustand(sftp)) || { dateien: {} }; if (zustand.root && zustand.root !== root && Object.keys(zustand.dateien).length) { - throw new Error(`Auf ${zustand.root} ist noch "${zustand.profil}" aktiv. Zuerst: npm run noten:profil -- wiederherstellen`); + throw new Error( + `Auf ${zustand.root} ist noch "${zustand.profil}" aktiv. Zuerst: npm run noten:profil -- wiederherstellen`, + ); } zustand.root = root; zustand.profil = name; - if (Object.keys(daten.config).length) await setze(sftp, zustand, "config", (o) => mitConfig(o, name, daten.config)); + if (Object.keys(daten.config).length) + await setze(sftp, zustand, "config", (o) => mitConfig(o, name, daten.config)); else await stelleHer(sftp, zustand, "config"); if (Object.keys(daten.flags).length) await setze(sftp, zustand, "flags", (o) => mitFlags(o, daten.flags)); diff --git a/tests/cypress/tasks/sshTunnel.js b/tests/cypress/tasks/sshTunnel.js index 35ff49f25..a7ad23e06 100644 --- a/tests/cypress/tasks/sshTunnel.js +++ b/tests/cypress/tasks/sshTunnel.js @@ -53,7 +53,6 @@ const openTunnel = (cfg) => if (localPort) return resolve(localPort); if (!cfg.sshHost || !cfg.sshUser) return reject(new Error("Tunnel needs an SSH host and user.")); - // eslint-disable-next-line global-require const { Client } = require("ssh2"); let auth; @@ -68,6 +67,8 @@ const openTunnel = (cfg) => sshClient .on("ready", () => { server = net.createServer((socket) => { + // an error before the channel is up must not crash the process + socket.on("error", () => socket.destroy()); sshClient.forwardOut( socket.remoteAddress || "127.0.0.1", socket.remotePort || 0, @@ -75,6 +76,10 @@ const openTunnel = (cfg) => cfg.dbPort, (err, stream) => { if (err) return socket.destroy(); + if (socket.destroyed) return stream.destroy(); + // pipe forwards only a clean end; an aborted side must close the other, or the channel keeps its Postgres connection + socket.on("close", () => stream.destroy()); + stream.on("error", () => socket.destroy()).on("close", () => socket.destroy()); socket.pipe(stream).pipe(socket); }, ); @@ -85,7 +90,6 @@ const openTunnel = (cfg) => // port 0: let the OS pick, so a leftover process cannot collide server.listen(0, "127.0.0.1", () => { localPort = server.address().port; - // eslint-disable-next-line no-console console.log( `[db] SSH tunnel up: 127.0.0.1:${localPort} -> ${cfg.dbHost}:${cfg.dbPort} ` + `via ${cfg.sshUser}@${cfg.sshHost} (${auth.description})`, @@ -114,14 +118,15 @@ const openTunnel = (cfg) => }); const closeTunnel = async () => { - if (server) { - await new Promise((resolve) => server.close(resolve)); - server = null; - } + // the SSH connection first: its closing channels close the local sockets, which server.close waits for if (sshClient) { sshClient.end(); sshClient = null; } + if (server) { + await new Promise((resolve) => server.close(resolve)); + server = null; + } localPort = null; return null; }; diff --git a/tests/cypress/tools/checks/noten.js b/tests/cypress/tools/checks/noten.js index cc0f88680..944910024 100644 --- a/tests/cypress/tools/checks/noten.js +++ b/tests/cypress/tools/checks/noten.js @@ -9,9 +9,18 @@ const path = require("path"); // tests/cypress/tools/checks -> repo root is four levels up -const seeder = (name) => path.join(__dirname, "..", "..", "..", "..", "system", "seeders", name); +const SEEDER = path.join( + __dirname, + "..", + "..", + "..", + "..", + "system", + "seeders", + "TST60873_000_GesamtnoteneingabeCis4.sql", +); -/** Test semester: the running one, else the last started. Same rule as the suite and seeder 016. */ +/** Test semester: the running one, else the last started. Same rule as the suite and seeder group benotungstool_noten. */ const SEM = `(SELECT studiensemester_kurzbz FROM public.tbl_studiensemester WHERE start <= now() ORDER BY (ende >= now()) DESC, start DESC LIMIT 1)`; @@ -19,7 +28,10 @@ module.exports = { title: "Gesamtnoteneingabe", sqlFiles: { - seed: [seeder("016_benotungstool_noten.sql"), seeder("019_benotungstool_fixture_erweitert.sql")], + // the idempotent fixture groups; studiengang_5 inserts without ON CONFLICT and needs a rebuild + seed: ["benotungstool_noten", "benotungstool_berechtigungen", "benotungstool_fixture_erweitert"].map( + (group) => ({ file: SEEDER, group }), + ), }, checks: [ @@ -27,20 +39,20 @@ module.exports = { label: "Test semester (latest started)", sql: `SELECT ${SEM} AS value`, ok: (r) => Boolean(r.value), - hint: "No studiensemester with start <= now(). Apply the base dump + 003_kompetenzfeld.sql.", + hint: "No studiensemester with start <= now(). Apply the base dump + BS003_kompetenzfeld.sql.", }, { label: "demolektor1 exists", sql: `SELECT COUNT(*)::int AS value FROM public.tbl_mitarbeiter WHERE mitarbeiter_uid = 'demolektor1'`, ok: (r) => r.value > 0, - hint: "Apply 002_mitarbeiter.sql.", + hint: "Apply BS002_mitarbeiter.sql.", }, { label: "STG5 Lehrveranstaltungen (5121 / 5221)", sql: `SELECT COUNT(*)::int AS value FROM lehre.tbl_lehrveranstaltung WHERE lehrveranstaltung_id IN (5121, 5221)`, ok: (r) => r.value === 2, - hint: "Apply 013_studiengang_5.sql.", + hint: "Rebuild the database. Seeder group studiengang_5 creates them.", }, { label: "Lehreinheiten of demolektor1 in the test semester", @@ -50,8 +62,8 @@ module.exports = { WHERE mitarbeiter_uid = 'demolektor1' AND le.studiensemester_kurzbz = ${SEM}`, ok: (r) => r.value > 0, hint: - "demolektor1 teaches nothing in the CURRENT test semester. The 013 seeder pins its " + - "Lehreinheiten to the semester that was active when it ran. Apply 016_benotungstool_noten.sql.", + "demolektor1 teaches nothing in the CURRENT test semester. Seeder group studiengang_5 pins its" + + "Lehreinheiten to the semester that was active when it ran. Apply seeder group benotungstool_noten.", }, { label: "Lehreinheitgruppe rows with a non-NULL gruppe_kurzbz", @@ -60,7 +72,7 @@ module.exports = { ok: (r) => r.value > 0, hint: "campus.vw_student_lehrveranstaltung joins ONLY on gruppe_kurzbz. Lehrverband-style rows " + - "(verband set, gruppe_kurzbz NULL) never match. Apply 016_benotungstool_noten.sql.", + "(verband set, gruppe_kurzbz NULL) never match. Apply seeder group benotungstool_noten.", }, { label: "Group memberships carrying a studiensemester", @@ -69,14 +81,14 @@ module.exports = { ok: (r) => r.value > 0, hint: "tbl_benutzergruppe.studiensemester_kurzbz must equal tbl_lehreinheit.studiensemester_kurzbz. " + - "NULL never matches. Apply 016_benotungstool_noten.sql.", + "NULL never matches. Apply seeder group benotungstool_noten.", }, { label: "Students visible in LV 5221 (the test LV)", sql: `SELECT COUNT(*)::int AS value FROM campus.vw_student_lehrveranstaltung WHERE lehrveranstaltung_id = 5221 AND studiensemester_kurzbz = ${SEM}`, ok: (r) => r.value >= 3, - hint: "The suite needs at least 3 enrolled students. Apply 016_benotungstool_noten.sql.", + hint: "The suite needs at least 3 enrolled students. Apply seeder group benotungstool_noten.", }, { label: "tbl_note 'entschuldigt' (resolved by Bezeichnung)", @@ -100,7 +112,7 @@ module.exports = { ok: (r) => r.value.includes("Termin1") && r.value.includes("Termin2"), hint: "Termin3 is absent from the base dump. Harmless while CIS_GESAMTNOTE_PRUEFUNG_TERMIN3 is " + - "off, but a Termin3 insert would hit a foreign key error. 016 adds it.", + "off, but a Termin3 insert would hit a foreign key error. Seeder group benotungstool_noten adds it.", }, { label: "Notenschluessel assigned to LV 5221", @@ -111,20 +123,20 @@ module.exports = { ok: (r) => r.value > 0, hint: "The Notenschluessel tables are empty in the base dump, so getNoteByPunkte always returns " + - "null. Apply 016_benotungstool_noten.sql.", + "null. Apply seeder group benotungstool_noten.", }, { label: "Students in the second Lehreinheit of LV 5221", sql: `SELECT COUNT(*)::int AS value FROM campus.vw_student_lehrveranstaltung WHERE lehreinheit_id = 51103 AND studiensemester_kurzbz = ${SEM}`, ok: (r) => r.value > 0, - hint: "The Lehreinheit check of the write paths needs it. Apply 019_benotungstool_fixture_erweitert.sql.", + hint: "The Lehreinheit check of the write paths needs it. Apply seeder group benotungstool_fixture_erweitert.", }, { label: "Lektoren of Lehreinheit 51103", sql: "SELECT COUNT(*)::int AS value FROM lehre.tbl_lehreinheitmitarbeiter WHERE lehreinheit_id = 51103", ok: (r) => r.value >= 2, - hint: "The grader rules need two Lektoren. Apply 019_benotungstool_fixture_erweitert.sql.", + hint: "The grader rules need two Lektoren. Apply seeder group benotungstool_fixture_erweitert.", }, { label: "Sommersemester after its deadline, taught by demolektor1", @@ -136,7 +148,7 @@ module.exports = { AND make_date(substring(le.studiensemester_kurzbz FROM 3 FOR 4)::int, 11, 15) < current_date ORDER BY le.studiensemester_kurzbz DESC LIMIT 1), '') AS value`, ok: (r) => r.value !== "", - hint: "The deadline tests need it. Apply 019_benotungstool_fixture_erweitert.sql.", + hint: "The deadline tests need it. Apply seeder group benotungstool_fixture_erweitert.", }, { label: "Texts of the Vorlagen Notenfreigabe and Sancho_Mail_Template", @@ -144,7 +156,7 @@ module.exports = { WHERE vorlage_kurzbz IN ('Notenfreigabe', 'Sancho_Mail_Template') AND aktiv AND COALESCE(text, '') <> ''`, ok: (r) => r.value === 2, - hint: "Without both texts every release mail has an empty body. Apply 019_benotungstool_fixture_erweitert.sql.", + hint: "Without both texts every release mail has an empty body. Apply seeder group benotungstool_fixture_erweitert.", }, ], }; diff --git a/tests/cypress/tools/dbCheck.js b/tests/cypress/tools/dbCheck.js index 016f88ee1..1d80cd34f 100644 --- a/tests/cypress/tools/dbCheck.js +++ b/tests/cypress/tools/dbCheck.js @@ -7,7 +7,8 @@ * node tests/cypress/tools/dbCheck.js noten env print the .env block to use * * A suite contributes tools/checks/.js exporting { title, checks, sqlFiles }. Connection, - * tunnel and output are shared and live here. + * tunnel and output are shared and live here. A sqlFiles entry is a path or { file, group }; a + * "-- ==== ====" line starts a group. * * `check` is read-only; `seed` needs _DB_ALLOW_WRITES=true and an owner role. */ @@ -32,12 +33,14 @@ const loadSuite = (name) => { const file = path.join(CHECKS_DIR, `${name}.js`); if (!fs.existsSync(file)) { const available = fs.existsSync(CHECKS_DIR) - ? fs.readdirSync(CHECKS_DIR).map((f) => f.replace(/\.js$/, "")).join(", ") + ? fs + .readdirSync(CHECKS_DIR) + .map((f) => f.replace(/\.js$/, "")) + .join(", ") : "(none)"; console.error(`\nUnknown suite "${name}". Available: ${available}\n`); process.exit(2); } - // eslint-disable-next-line global-require, import/no-dynamic-require return require(file); }; @@ -74,7 +77,18 @@ const runChecks = async (client, suite) => { return 1; }; -const applySqlFile = async (client, file) => { +/** The SQL of a file, or of one group in it. A group ends at the next group header. */ +const readSql = (file, group) => { + const sql = fs.readFileSync(file, "utf8"); + if (!group) return sql; + const parts = sql.split(/^-- ==== (.+?) ====[ \t]*\r?$/m); + for (let i = 1; i < parts.length; i += 2) if (parts[i] === group) return parts[i + 1]; + return null; +}; + +const applySqlFile = async (client, entry) => { + const { file, group } = typeof entry === "string" ? { file: entry } : entry; + const label = path.relative(process.cwd(), file) + (group ? ` [${group}]` : ""); if (!db.writesAllowed()) { console.error(`\nRefusing to write: set ${db.PREFIX}_DB_ALLOW_WRITES=true first.\n`); return 2; @@ -84,13 +98,19 @@ const applySqlFile = async (client, file) => { return 2; } - console.log(`\nApplying ${path.relative(process.cwd(), file)} ...\n`); + const sql = readSql(file, group); + if (sql === null) { + console.error(`\nGroup "${group}" not found in ${file}\n`); + return 2; + } + + console.log(`\nApplying ${label} ...\n`); // One connection, one call: the seeders rely on running as a unit (temp tables, DO blocks and a // closing verification query). let result; try { - result = await client.query(fs.readFileSync(file, "utf8")); + result = await client.query(sql); } catch (error) { // `check` gets by as the application role; seeding creates and grants objects. if (/permission denied/i.test(error.message)) { @@ -107,11 +127,10 @@ const applySqlFile = async (client, file) => { const last = results.filter((r) => r && r.rows && r.rows.length).pop(); if (last) { console.log("Verification\n" + "-".repeat(50)); - last.rows.forEach((row) => - Object.entries(row).forEach(([k, v]) => console.log(` ${k.padEnd(24)} ${v}`))); + last.rows.forEach((row) => Object.entries(row).forEach(([k, v]) => console.log(` ${k.padEnd(24)} ${v}`))); } - console.log(`\nDone: ${path.basename(file)}\n`); + console.log(`\nDone: ${label}\n`); return 0; }; @@ -175,7 +194,7 @@ const main = async () => { client.on("notice", (n) => console.log(` NOTICE: ${n.message}`)); if (mode !== "check") { - // a suite can name several files; they run in this order + // a suite can name several files or groups; they run in this order for (const file of [].concat(suite.sqlFiles[mode])) { const code = await applySqlFile(client, file); if (code !== 0) return code;