From aa2597d8b59abc25131d8eb1dfd308ef6e910b7b Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 17 May 2019 14:37:24 +0200 Subject: [PATCH 001/500] Add column Stufe to tbl_dokumentstudiengang --- system/dbupdate_3.3.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 7b16bb880..6d79d4f56 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -2911,6 +2911,17 @@ if(!$result = @$db->db_query("SELECT nationengruppe_kurzbz FROM public.tbl_bewer echo '
public.tbl_bewerbungstermine: Spalte nationengruppe_kurzbz hinzugefuegt'; } +// Add column Stufe to tbl_dokumentstudiengang +if(!$result = @$db->db_query("SELECT stufe FROM public.tbl_dokumentstudiengang LIMIT 1")) +{ + $qry = "ALTER TABLE public.tbl_dokumentstudiengang ADD COLUMN stufe smallint;"; + + if(!$db->db_query($qry)) + echo 'public.tbl_dokumentstudiengang: '.$db->db_last_error().'
'; + else + echo '
public.tbl_dokumentstudiengang: Spalte stufe hinzugefuegt'; +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen @@ -3074,7 +3085,7 @@ $tabellen=array( "public.tbl_buchungstyp" => array("buchungstyp_kurzbz","beschreibung","standardbetrag","standardtext","aktiv","credit_points"), "public.tbl_dokument" => array("dokument_kurzbz","bezeichnung","ext_id","bezeichnung_mehrsprachig","dokumentbeschreibung_mehrsprachig","ausstellungsdetails"), "public.tbl_dokumentprestudent" => array("dokument_kurzbz","prestudent_id","mitarbeiter_uid","datum","updateamum","updatevon","insertamum","insertvon","ext_id"), - "public.tbl_dokumentstudiengang" => array("dokument_kurzbz","studiengang_kz","ext_id", "onlinebewerbung", "pflicht","beschreibung_mehrsprachig","nachreichbar"), + "public.tbl_dokumentstudiengang" => array("dokument_kurzbz","studiengang_kz","ext_id", "onlinebewerbung", "pflicht","beschreibung_mehrsprachig","nachreichbar","stufe"), "public.tbl_erhalter" => array("erhalter_kz","kurzbz","bezeichnung","dvr","logo","zvr"), "public.tbl_fachbereich" => array("fachbereich_kurzbz","bezeichnung","farbe","studiengang_kz","aktiv","ext_id","oe_kurzbz"), "public.tbl_filter" => array("filter_id","kurzbz","sql","valuename","showvalue","insertamum","insertvon","updateamum","updatevon","type","htmlattr", "bezeichnung"), From 8e83de0672092d3e849988b1a1a07b8526221055 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 17 May 2019 14:43:21 +0200 Subject: [PATCH 002/500] Column Stufe in Class and studiengang_dokumente --- include/dokument.class.php | 13 ++++++++++--- vilesci/stammdaten/studiengang_dokumente.php | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/dokument.class.php b/include/dokument.class.php index 05497f744..4040c7a4a 100644 --- a/include/dokument.class.php +++ b/include/dokument.class.php @@ -36,6 +36,7 @@ class dokument extends basis_db public $bezeichnung_mehrsprachig; public $dokumentbeschreibung_mehrsprachig; public $ausstellungsdetails = false; + public $stufe; public $prestudent_id; public $mitarbeiter_uid; @@ -428,6 +429,7 @@ class dokument extends basis_db $dok->nachreichbar = $this->db_parse_bool($row->nachreichbar); $dok->onlinebewerbung = $this->db_parse_bool($row->onlinebewerbung); $dok->ausstellungsdetails = $this->db_parse_bool($row->ausstellungsdetails); + $dok->stufe = $row->stufe; $this->result[] = $dok; } return true; @@ -467,6 +469,7 @@ class dokument extends basis_db $dok->nachreichbar = $this->db_parse_bool($row->nachreichbar); $dok->onlinebewerbung = $this->db_parse_bool($row->onlinebewerbung); $dok->ausstellungsdetails = $this->db_parse_bool($row->ausstellungsdetails); + $dok->stufe = $row->stufe; $this->result[] = $dok; } @@ -545,6 +548,7 @@ class dokument extends basis_db $this->pflicht = $this->db_parse_bool($row->pflicht); $this->nachreichbar = $this->db_parse_bool($row->nachreichbar); $this->beschreibung_mehrsprachig = $sprache->parseSprachResult('beschreibung_mehrsprachig',$row); + $this->stufe = $row->stufe; return true; } else @@ -605,7 +609,7 @@ class dokument extends basis_db $qry.=" beschreibung_mehrsprachig[$idx],"; } - $qry.=' pflicht, nachreichbar, onlinebewerbung) + $qry.=' pflicht, nachreichbar, onlinebewerbung, stufe) VALUES ('. $this->db_add_param($this->dokument_kurzbz).','. $this->db_add_param($this->studiengang_kz,FHC_INTEGER).','; @@ -615,7 +619,8 @@ class dokument extends basis_db $qry.= $this->db_add_param($this->pflicht,FHC_BOOLEAN).','. $this->db_add_param($this->nachreichbar,FHC_BOOLEAN).','. - $this->db_add_param($this->onlinebewerbung,FHC_BOOLEAN).')'; + $this->db_add_param($this->onlinebewerbung,FHC_BOOLEAN).','. + $this->db_add_param($this->stufe,FHC_INTEGER).')'; } else { @@ -628,7 +633,8 @@ class dokument extends basis_db $qry.=" beschreibung_mehrsprachig[$idx]=".$this->db_add_param($value).","; } $qry.=' pflicht='.$this->db_add_param($this->pflicht, FHC_BOOLEAN).', - nachreichbar='.$this->db_add_param($this->nachreichbar, FHC_BOOLEAN).' + nachreichbar='.$this->db_add_param($this->nachreichbar, FHC_BOOLEAN).', + stufe='.$this->db_add_param($this->stufe, FHC_INTEGER).' WHERE dokument_kurzbz='.$this->db_add_param($this->dokument_kurzbz).' AND studiengang_kz='.$this->db_add_param($this->studiengang_kz); @@ -714,6 +720,7 @@ class dokument extends basis_db $dok->dokumentbeschreibung_mehrsprachig = $sprache->parseSprachResult('dokumentbeschreibung_mehrsprachig', $row); $dok->beschreibung_mehrsprachig = $sprache->parseSprachResult('beschreibung_mehrsprachig', $row); $dok->ausstellungsdetails = $this->db_parse_bool($row->ausstellungsdetails); + $dok->stufe = $row->stufe; $this->result[] = $dok; } diff --git a/vilesci/stammdaten/studiengang_dokumente.php b/vilesci/stammdaten/studiengang_dokumente.php index 898ace746..fd392a928 100644 --- a/vilesci/stammdaten/studiengang_dokumente.php +++ b/vilesci/stammdaten/studiengang_dokumente.php @@ -34,6 +34,7 @@ $dokument_kurzbz = isset($_REQUEST['dokument_kurzbz']) ? $_REQUEST['dokument_kur $onlinebewerbung = isset($_REQUEST['onlinebewerbung']); $pflicht = isset($_POST['pflicht']); $nachreichbar = isset($_POST['nachreichbar']); +$stufe = isset($_REQUEST['stufe']) ? $_REQUEST['stufe'] : ''; $sprache = new sprache(); $sprache->getAll(true, 'index'); @@ -64,6 +65,7 @@ if($action == 'add') $dokument->onlinebewerbung = $onlinebewerbung; $dokument->pflicht = $pflicht; $dokument->nachreichbar = $nachreichbar; + $dokument->stufe = $stufe; $beschreibung_mehrsprachig = array(); foreach($sprache->result as $row_sprache) @@ -453,6 +455,7 @@ else echo' Online-Bewerbung Pflicht Nachreichbar + Stufe '; } echo' @@ -491,6 +494,7 @@ else echo' + '.$dok->stufe.' '; if($rechte->isBerechtigt('assistenz', $stg_kz, 'su')) echo ''; @@ -546,6 +550,9 @@ else nachreichbar?'checked="checked"':'').'> + + + '; From f409aa2c6f3fe24340b65114a585d8e23cfe2404 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 May 2019 15:37:40 +0200 Subject: [PATCH 003/500] =?UTF-8?q?Ausbildungsvertrag=20au=C3=9Ferordentli?= =?UTF-8?q?ch=20Studierende=20-=20Vorlage=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/xsl/Ausbildungsver_9005.xsl | 68 ++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/system/xsl/Ausbildungsver_9005.xsl b/system/xsl/Ausbildungsver_9005.xsl index db74f0dbf..f781dc811 100644 --- a/system/xsl/Ausbildungsver_9005.xsl +++ b/system/xsl/Ausbildungsver_9005.xsl @@ -367,7 +367,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn Familienname: Vorname: - Akademische/r Titel: + Akademische/r Titel: @@ -390,7 +390,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - Studienort sind die Räumlichkeiten der FH Technikum Wien, 1200 Wien, Höchstädtplatz und 1210 Wien, Giefinggasse. Bei Bedarf kann der Erhalter einen anderen Studienort in Wien festlegen, außerhochschulische Aktivitäten (zB Exkursionen) können auch außerhalb von Wien stattfinden. + Studienort sind die Räumlichkeiten der FH Technikum Wien, 1200 Wien, Standort Höchstädtplatz und 1210 Wien, Standort Giefinggasse. Bei Bedarf kann der Erhalter einen anderen Studienort in Wien festlegen, außerhochschulische Aktivitäten (zB Exkursionen) können auch außerhalb von Wien stattfinden. @@ -436,8 +436,6 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn 5.1 Rechte Der Erhalter führt eine periodische Überprüfung des die Lehrveranstaltungen anbietenden Studiengangs im Hinblick auf Relevanz und Aktualität durch und ist im Einvernehmen mit dem FH-Kollegium berechtigt, daraus Änderungen im Lehrangebot des Studienganges abzuleiten. - - Der Erhalter ist berechtigt, die Daten der/des ao. Studierenden an den FH Technikum Wien Alumni Club zu übermitteln. Der Alumni Club ist der AbsolventInnenverein der FH Technikum Wien. Er hat zum Ziel, AbsolventInnen, Studierende und Lehrende miteinander zu vernetzen sowie AbsolventInnen laufend über Aktivitäten an der FH Technikum Wien zu informieren. Einer Zusendung von Informationen durch den Alumni Club kann jederzeit widersprochen werden. @@ -475,7 +473,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn 6.2 Pflichten 6.2.1 Einhaltung studienrelevanter Bestimmungen - Die ao. Studentin bzw der ao. Student ist verpflichtet, insbesondere folgende Bestimmungen einzuhalten: + Folgende Bestimmungen sind Bestandteil des Ausbildungsvertrags und von der ao. StudentIn/dem Studenten einzuhalten: Studienordnung und Studienrechtliche Bestimmungen / Prüfungsordnung idgF @@ -494,7 +492,25 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - Diese Dokumente sind öffentlich zugänglich unter www.technikum-wien.at. + Diese Dokumente sind öffentlich zugänglich unter www.technikum-wien.at und nach Erhalt der Zugangsdaten auch im Intranet + abrufbar + + + + 1 + + + + + + https://www.technikum-wien.at/ueber-uns/satzung-und-leitbild-der-fh-technikum-wien/ oder CIS – Dokumente – Satzung + + + + + + + und werden bei den Einführungsveranstaltungen vorgestellt. 6.2.2 Studienbeitrag Die ao. Studentin bzw. der ao. Student ist verpflichtet, vor Beginn jedes Semesters bis zum jeweils bekannt gegebenen Termin einen Studienbeitrag gemäß Fachhochschul-Studiengesetz idgF in der Höhe von derzeit € 363,36 netto pro Semester zu entrichten. Im Falle einer Erhöhung des gesetzlichen Studienbeitragssatzes erhöht sich der angeführte Betrag entsprechend. Die vollständige Bezahlung des Studienbeitrags ist Voraussetzung für die Aufnahme bzw. die Fortsetzung des ao. Studiums. Bei Nichtantritt des ao. Studiums oder Abbruch zu Beginn oder während des Semesters verfällt der Studienbeitrag. 6.2.3 ÖH-Beitrag @@ -503,15 +519,18 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn Pro Semester ist ein Unkostenbeitrag zu entrichten. Die Höhe des Unkostenbeitrages beträgt € 75,– pro Semester. Eine allfällige Anpassung wird durch Aushang bekannt gemacht. Der Unkostenbeitrag ist gleichzeitig mit dem Studienbeitrag vor Beginn des Semesters zu entrichten. Bei Vertragsauflösung vor dem Ende der besuchten Lehrveranstaltungen aus Gründen, die die ao. Studentin bzw. der ao. Student zu vertreten hat, oder auf deren bzw. dessen Wunsch, wird der Unkostenbeitrag zur Abdeckung der dem Erhalter erwachsenen administrativen Zusatzkosten einbehalten. 6.2.5 Lehr- und Lernbehelfe Die Anschaffung unterrichtsbezogener Literatur und individueller Lernbehelfe ist durch den Unkostenbeitrag nicht abgedeckt. Eventuelle zusätzliche Kosten, die sich beispielsweise durch die lehrveranstaltungsbezogene, gemeinsame Anschaffung von Lehr- bzw. Lernbehelfen (Skripten, CDs, Bücher, Projektmaterialien, Kopierpapier etc.) oder durch Exkursionen ergeben, werden von jedem Studiengang individuell eingehoben. - 6.2.6 Beibringung persönlicher Daten - Die ao. Studentin bzw. der ao. Student ist verpflichtet, persönliche Daten beizubringen, die auf Grund eines Gesetzes, einer Verordnung oder eines Bescheides vom Erhalter erfasst werden müssen oder zur Erfüllung des Ausbildungsvertrages bzw für den Studienbetrieb unerlässlich sind. - 6.2.7 Aktualisierung eigener Daten und Bezug von Informationen + 6.2.6 Beibringung und Aktualisierung von personenbezogenen Daten + Die ao. Studentin bzw. der ao. Student ist verpflichtet, personenbezogene Daten beizubringen, die auf Grund eines Gesetzes, einer Verordnung oder eines Bescheides vom Erhalter erfasst werden müssen oder zur Erfüllung des Ausbildungsvertrages bzw. für den Studienbetrieb unerlässlich sind. Die ao. Studentin bzw. der ao. Student hat unaufgefordert dafür zu sorgen, dass die von ihr/ihm beigebrachten Daten aktuell sind. Änderungen sind der Studiengangsassistenz unverzüglich schriftlich mitzuteilen. Darüber hinaus trifft sie/ihn die Pflicht, sich von studienbezogenen Informationen, die ihr/ihm an die vom Erhalter zur Verfügung gestellte Emailadresse zugestellt werden, in geeigneter Weise Kenntnis zu verschaffen. + Es ist der ao. Studentin/dem ao. Studenten untersagt, die Daten des von der FH zur Verfügung gestellten Studierendenaccounts weiterzugeben. + 6.2.7 Bezug von Informationen durch die FH Gruppe + Der Erhalter ist berechtigt, die Daten der/des ao. Studierenden an den FH Technikum Wien Alumni Club zu übermitteln. Der Alumni Club ist der AbsolventInnenverein der FH Technikum Wien. Er hat zum Ziel, AbsolventInnen, Studierende und Lehrende miteinander zu vernetzen sowie AbsolventInnen laufend über Aktivitäten an der FH Technikum Wien zu informieren. Einer Zusendung von Informationen durch den Alumni Club kann jederzeit widersprochen werden. + Der/die ao. Studierende stimmt zu, dass ihm/ihr Informationen der FH Gruppe (FH Technikum Wien, Technikum Wien GmbH sowie Technikum Wien Alumni Club) zur Pflege der Kontakte per E-Mail zugestellt werden (§ 107 TKG 2003 idgF). Ein Abbestellen dieser Informationen ist jederzeit möglich. 6.2.8 Verwertungsrechte Sofern nicht im Einzelfall andere Regelungen zwischen dem Erhalter und der ao. Studentin oder dem ao. Studenten getroffen wurden, ist die ao. Studentin oder der ao. Student verpflichtet, dem Erhalter die Rechte an Forschungs- und Entwicklungsergebnissen, die im Rahmen von geförderten Projekten geschaffen wurden, auf dessen schriftliche Anfrage hin einzuräumen. 6.2.9 Aufzeichnungen und Mitschnitte - Es ist der/dem ao. Studierenden ausdrücklich untersagt, Lehrveranstaltungen als Ganzes oder nur Teile davon aufzuzeichnen und/oder mitzuschneiden (z.B. durch Film- und/oder Tonaufnahmen oder sonstige hierfür geeignete audiovisuelle Mittel). Darüber hinaus ist jede Form der öffentlichen Zurverfügungstellung (drahtlos oder drahtgebunden) der vorgenannten Aufnahmen z.B. in sozialen Netzwerken wie Facebook, StudiVZ etc, aber auch auf Youtube usw. oder durch sonstige für diese Zwecke geeignete Kommunikationsmittel untersagt. Diese Regelungen gelten sinngemäß auch für Skripten, sonstige Lernbehelfe und Prüfungsangaben. - Ausgenommen hiervon ist eine Aufzeichnung zu ausschließlichen Lern-, Studien- und Forschungszwecken und zum privaten Gebrauch, sofern hierfür der/die Vortragende vorab ausdrücklich seine/ihre schriftliche Zustimmung erteilt hat. + Es ist der/dem ao. Studierenden ausdrücklich untersagt, Lehrveranstaltungen als Ganzes oder nur Teile davon aufzuzeichnen und/oder mitzuschneiden (z.B. durch Film- und/oder Tonaufnahmen oder sonstige hierfür geeignete audiovisuelle Mittel) oder in Lehrveranstaltungen zu fotografieren. Darüber hinaus ist jede Form der öffentlichen Zurverfügungstellung (drahtlos oder drahtgebunden) der vorgenannten Aufnahmen z.B. in sozialen Netzwerken wie Facebook, StudiVZ etc, aber auch auf Youtube usw. oder durch sonstige für diese Zwecke geeignete Kommunikationsmittel untersagt. Diese Regelungen gelten sinngemäß auch für Skripten, sonstige Lernbehelfe und Prüfungsangaben. + Ausgenommen hiervon ist eine Aufzeichnung zu ausschließlichen Lern-, Studien- und Forschungszwecken und zum privaten Gebrauch, sofern hierfür der/die Vortragende und alle auf diesen Aufnahmen erkennbaren Personen vorab ausdrücklich seine/ihre schriftliche Zustimmung erteilt hat. 6.2.10 Geheimhaltungspflicht Die ao. Studentin bzw. der ao. Student ist zur Geheimhaltung von Forschungs- und Entwicklungsaktivitäten und -ergebnissen gegenüber Dritten verpflichtet. 6.2.11 Unfallmeldung @@ -540,7 +559,25 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn Der Erhalter kann die ao. Studentin bzw. den ao. Studenten aus wichtigem Grund mit sofortiger Wirkung vom weiteren Besuch einer bestimmten Lehrveranstaltung ausschließen, und zwar beispielsweise wegen - nicht genügender Leistung im Sinne der Prüfungsordnung; + nicht genügender Leistung im Sinne der + Prüfungsordnung + + + + 2 + + + + + + https://www.technikum-wien.at/ueber-uns/satzung-und-leitbild-der-fh-technikum-wien/ oder CIS – Dokumente - Satzung + + + + + + + ; mehrmaligem unentschuldigten Verletzen der Anwesenheitspflicht ; @@ -592,9 +629,9 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - Das gesamte Studienprogramm wird in englischer Sprache angeboten. Die ao. Studentin bzw. der ao. Student erklärt, die englische Sprache in Wort und Schrift in dem für eine akademische Ausbildung erforderlichen Ausmaß zu beherrschen. + Falls das gesamte Studienprogramm in englischer Sprache angeboten wird, erklärt die ao. Studentin bzw. der ao. Student, die englische Sprache in Wort und Schrift in dem für eine akademische Ausbildung erforderlichen Ausmaß zu beherrschen. - Ao. Studierende des Studiengangs sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehrelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet) trägt der ao. Student bzw. die ao. Studentin. + Ao. Studierende sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehrelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet und e-mail) trägt der ao. Student bzw. die ao. Studentin. @@ -622,8 +659,6 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn Der Ausbildungsvertrag ist gebührenfrei. - - Wien, @@ -641,7 +676,6 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - From 70c26869327dfbbac8ff7a85b22f8d3f876682f9 Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 27 May 2019 17:25:04 +0200 Subject: [PATCH 004/500] - Added new controller system/DBSkel to call DBSkel procedure form CLI - Removed libraries/MigrationLib.php - Removed MigrationLib from libraries/CallerLib.php --- application/controllers/system/DBSkel.php | 24 ++ application/libraries/CallerLib.php | 1 - application/libraries/MigrationLib.php | 466 ---------------------- 3 files changed, 24 insertions(+), 467 deletions(-) create mode 100644 application/controllers/system/DBSkel.php delete mode 100644 application/libraries/MigrationLib.php diff --git a/application/controllers/system/DBSkel.php b/application/controllers/system/DBSkel.php new file mode 100644 index 000000000..071cfaa9e --- /dev/null +++ b/application/controllers/system/DBSkel.php @@ -0,0 +1,24 @@ +load->library('DBSkelLib'); + } + + /** + * Starts the migration procedure + */ + public function start() + { + $this->dbskellib->start(); + } +} diff --git a/application/libraries/CallerLib.php b/application/libraries/CallerLib.php index 0b46cf0c6..82883cac4 100644 --- a/application/libraries/CallerLib.php +++ b/application/libraries/CallerLib.php @@ -19,7 +19,6 @@ class CallerLib private static $RESOURCES_BLACK_LIST = array( 'CallerLib', // disabled self loading 'LogLib', // hardly usefull and virtually dangerous - 'MigrationLib', // virtually dangerous, DB manipulation 'FilesystemLib', // virtually dangerous, direct access to file system 'PermissionLib', // usefull? 'PersonLogLib' diff --git a/application/libraries/MigrationLib.php b/application/libraries/MigrationLib.php deleted file mode 100644 index a461d7a82..000000000 --- a/application/libraries/MigrationLib.php +++ /dev/null @@ -1,466 +0,0 @@ -load->library('EPrintfLib'); - } - - /** - * Check if a column exists in a table and schema - */ - private function columnExists($name, $schema, $table) - { - $query = sprintf("SELECT %s FROM %s.%s LIMIT 1", $name, $schema, $table); - - if (@$this->db->simple_query($query)) - { - return true; - } - - return false; - } - - /** - * Print an info about the starting of method up - */ - protected function startUP() - { - $this->eprintflib->printInfo( - sprintf("%s Start method up of class %s %s", EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the ending of method up - */ - protected function endUP() - { - $this->eprintflib->printInfo( - sprintf("%s End method up of class %s %s", EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the starting of method down - */ - protected function startDown() - { - $this->eprintflib->printInfo( - sprintf("%s Start method down of class %s %s", EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the ending of method down - */ - protected function endDown() - { - $this->eprintflib->printInfo( - sprintf("%s End method down of class %s %s", EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Adds a column, with attributes, to a table and schema - */ - protected function addColumn($schema, $table, $fields) - { - foreach ($fields as $name => $definition) - { - if (!$this->columnExists($name, $schema, $table)) - { - if ($this->dbforge->add_column($schema.'.'.$table, array($name => $definition))) - { - $this->eprintflib->printMessage(sprintf("Column %s.%s.%s of type %s added", $schema, $table, $name, $definition["type"])); - } - else - { - $this->eprintflib->printError(sprintf("Error while adding column %s.%s.%s of type %s", $schema, $table, $name, $definition["type"])); - } - } - else - { - $this->eprintflib->printInfo(sprintf("Column %s.%s.%s already exists", $schema, $table, $name)); - } - } - } - - /** - * Modifies a column, and its attributes, of a table and schema - */ - protected function modifyColumn($schema, $table, $fields) - { - foreach ($fields as $name => $definition) - { - if ($this->columnExists($name, $schema, $table)) - { - if ($this->dbforge->modify_column($schema.'.'.$table, array($name => $definition))) - { - $this->eprintflib->printMessage(sprintf("Column %s.%s.%s has been modified", $schema, $table, $name)); - } - else - { - $this->eprintflib->printError(sprintf("Error while modifying column %s.%s.%s", $schema, $table, $name)); - } - } - else - { - $this->eprintflib->printInfo(sprintf("Column %s.%s.%s doesn't exist", $schema, $table, $name)); - } - } - } - - /** - * Drops a column from a table and schema - */ - protected function dropColumn($schema, $table, $field) - { - if ($this->columnExists($field, $schema, $table)) - { - if ($this->dbforge->drop_column($schema.'.'.$table, $field)) - { - $this->eprintflib->printMessage(sprintf("Column %s.%s.%s has been dropped", $schema, $table, $field)); - } - else - { - $this->eprintflib->printError(sprintf("Error while dropping column %s.%s.%s", $schema, $table, $field)); - } - } - else - { - $this->eprintflib->printInfo(sprintf("Column %s.%s.%s doesn't exist", $schema, $table, $field)); - } - } - - /** - * Sets a column as primary key of a table and schema - */ - protected function addPrimaryKey($schema, $table, $name, $fields) - { - $stringFields = null; - - if (is_array($fields)) - { - if (count($fields) > 0) - { - $stringFields = ""; - for ($i = 0; $i < count($fields); $i++) - { - $stringFields .= $fields[$i]; - if ($i != count($fields) - 1) - { - $stringFields .= ", "; - } - } - $query = sprintf("ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)", $schema, $table, $name, $stringFields); - } - } - else - { - $query = sprintf("ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)", $schema, $table, $name, $fields); - } - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf("Added primary key %s on table %s.%s", $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Adding primary key %s on table %s.%s", $name, $schema, $table)); - } - } - - /** - * Sets a column as foreign key of a table and schema - */ - protected function addForeingKey($schema, $table, $name, $field, $schemaDest, $tableDest, $fieldDest, $attributes) - { - $query = sprintf( - "ALTER TABLE %s.%s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s.%s (%s) %s", - $schema, - $table, - $name, - $field, - $schemaDest, - $tableDest, - $fieldDest, - $attributes - ); - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf("Added foreign key %s on table %s.%s", $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Adding foreign key %s on table %s.%s", $name, $schema, $table)); - } - } - - /** - * Sets a column as unique key of a table and schema - */ - protected function addUniqueKey($schema, $table, $name, $fields) - { - $stringFields = null; - - if (is_array($fields)) - { - if (count($fields) > 0) - { - $stringFields = ""; - for ($i = 0; $i < count($fields); $i++) - { - $stringFields .= $fields[$i]; - if ($i != count($fields) - 1) - { - $stringFields .= ", "; - } - } - $query = sprintf("CREATE UNIQUE INDEX %s ON %s.%s (%s)", $name, $schema, $table, $stringFields); - } - } - else - { - $query = sprintf("CREATE UNIQUE INDEX %s ON %s.%s (%s)", $name, $schema, $table, $fields); - } - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf("Added unique key %s on table %s.%s", $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Adding unique key %s on table %s.%s", $name, $schema, $table)); - } - } - - /** - * Grants permissions to a user on a table and schema - */ - protected function grantTable($permissions, $schema, $table, $user) - { - $stringPermission = null; - - if (is_array($permissions)) - { - if (count($permissions) > 0) - { - $stringPermission = ""; - for ($i = 0; $i < count($permissions); $i++) - { - $stringPermission .= $permissions[$i]; - if ($i != count($permissions) - 1) - { - $stringPermission .= ", "; - } - } - $query = sprintf("GRANT %s ON TABLE %s.%s TO %s", $stringPermission, $schema, $table, $user); - } - } - else - { - $query = sprintf("GRANT %s ON TABLE %s.%s TO %s", $permissions, $schema, $table, $user); - } - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage( - sprintf( - "Granted permissions %s on table %s.%s to user %s", - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $table, - $user - ) - ); - } - else - { - $this->eprintflib->printError( - sprintf( - "Granting permissions %s on table %s.%s to user %s", - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $table, - $user - ) - ); - } - } - - /** - * Creates a table in a schema with columns - */ - protected function createTable($schema, $table, $fields) - { - $this->dbforge->add_field($fields); - - if ($this->dbforge->create_table($schema.'.'.$table, true)) - { - $this->eprintflib->printMessage(sprintf("Table %s.%s created or existing", $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Creating table %s.%s", $schema, $table)); - } - } - - /** - * Drops a table from a schema - */ - protected function dropTable($schema, $table) - { - if ($this->dbforge->drop_table($schema.".".$table)) - { - $this->eprintflib->printMessage(sprintf("Table %s.%s has been dropped", $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Dropping table %s.%s", $schema, $table)); - } - } - - /** - * Initializes a sequence with the max value of a column - */ - protected function initializeSequence($schemaSrc, $sequence, $schemaDst, $table, $field) - { - $query = sprintf("SELECT SETVAL('%s.%s', (SELECT MAX(%s) FROM %s.%s))", $schemaSrc, $sequence, $field, $schemaDst, $table); - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf("Sequence %s.%s has been initialized", $schemaSrc, $sequence)); - } - else - { - $this->eprintflib->printError(sprintf("Initializing sequence %s.%s", $schemaSrc, $sequence)); - } - } - - /** - * Add comment to a column - */ - protected function addCommentToColumn($schema, $table, $field, $comment) - { - $query = sprintf("COMMENT ON COLUMN %s.%s.%s IS ?", $schema, $table, $field); - - if (@$this->db->query($query, array($comment))) - { - $this->eprintflib->printMessage(sprintf("Comment added to %s.%s.%s", $schema, $table, $field)); - } - else - { - $this->eprintflib->printError(sprintf("Error while adding comment to %s.%s.%s", $schema, $table, $field)); - } - } - - /** - * Add comment to a table - */ - protected function addCommentToTable($schema, $table, $comment) - { - $query = sprintf("COMMENT ON TABLE %s.%s IS ?", $schema, $table, $field); - - if (@$this->db->query($query, array($comment))) - { - $this->eprintflib->printMessage(sprintf("Comment added to %s.%s", $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf("Error while adding comment to %s.%s", $schema, $table)); - } - } - /** - * Grants permissions to a user on a sequence - */ - protected function grantSequence($permissions, $schema, $sequence, $user) - { - $stringPermission = null; - - if (is_array($permissions)) - { - if (count($permissions) > 0) - { - $stringPermission = ""; - for ($i = 0; $i < count($permissions); $i++) - { - $stringPermission .= $permissions[$i]; - if ($i != count($permissions) - 1) - { - $stringPermission .= ", "; - } - } - $query = sprintf("GRANT %s ON SEQUENCE %s.%s TO %s", $stringPermission, $schema, $sequence, $user); - } - } - else - { - $query = sprintf("GRANT %s ON SEQUENCE %s.%s TO %s", $permissions, $schema, $sequence, $user); - } - - if (@$this->db->simple_query($query)) - { - $this->eprintflib->printMessage( - sprintf( - "Granted permissions %s on sequence %s.%s to user %s", - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $sequence, - $user - ) - ); - } - else - { - $this->eprintflib->printError( - sprintf( - "Granting permissions %s on sequence %s.%s to user %s", - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $sequence, - $user - ) - ); - } - } - - /** - * Executes the given query - */ - protected function execQuery($query) - { - if (! @$this->db->simple_query($query)) - { - $error = $this->db->error(); - - if (is_array($error) && isset($error["message"])) - { - $this->eprintflib->printError($error["message"]); - } - else - { - $this->eprintflib->printError("Error while executing a query"); - } - } - - $this->eprintflib->printInfo( - "Query correctly executed: ". - substr(preg_replace("/\s+/", " ", trim($query)), 0, EPrintfLib::PRINT_QUERY_LEN). - (strlen($query) > EPrintfLib::PRINT_QUERY_LEN ? "..." : "") - ); - } -} From e8aeefd966915f3962a690db0ac2e67163536f28 Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 28 May 2019 17:10:30 +0200 Subject: [PATCH 005/500] - Added configuration file for DBSkel - Added library for DBSkel logic --- application/config/dbskel.php | 27 + application/libraries/DBSkelLib.php | 1146 +++++++++++++++++++++++++++ 2 files changed, 1173 insertions(+) create mode 100644 application/config/dbskel.php create mode 100644 application/libraries/DBSkelLib.php diff --git a/application/config/dbskel.php b/application/config/dbskel.php new file mode 100644 index 000000000..dafdc0d31 --- /dev/null +++ b/application/config/dbskel.php @@ -0,0 +1,27 @@ +_ci =& get_instance(); // get code igniter instance + + // Loads DB conns and confs using system settings + $this->_ci->load->database('system'); + + // Loads dbskel configs + $this->_ci->config->load('dbskel'); + + // Loads library EPrintfLib + $this->_ci->load->library('EPrintfLib'); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Starts the DBSkel procedure + * Returns false on failure and true on success + * All errors/warnings/infos are printed here using EPrintfLib + */ + public function start() + { + $start = false; + + // Checks if DBSkel is enabled + if ($this->_ci->config->item(self::CONF_ENABLED) === true) + { + // Gets all the directories in application/dbskel + $start = $this->_processDirectories(glob(self::DBSKEL_DIR.'*', GLOB_ONLYDIR)); + + $this->_printSchemaSeparator(); + } + else + { + $this->_printMessage('DBSkel is NOT enabled'); + } + + return $start; + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Process every single directory present in dbskel directory + */ + private function _processDirectories($directories) + { + $processDirectories = false; // failure by default + + // For each directory + foreach ($directories as $directory) + { + $processDirectories = false; // Reset to false at the beginning of each loop + + $this->_printSchemaSeparator(); + $this->_printInfo('Found directory >>> '.basename($directory).' <<<'); + + // NOTE: the order in which these methods are called has a meaning! + // If a step fails then the loop is stopped + + // 1 - Checks file naming convention in current directory + // NOTE: no need to check a failure! NOT a blocking check!! + $this->_checkFilenaming($directory); + + $this->_printFileSeparator(); + + // 2 - Process schema file + if (!$this->_processSchemaFile($directory)) break; + + $this->_printFileSeparator(); + + // 3 - Process sequence file + if (!$this->_processSequencesFile($directory)) break; + + $this->_printFileSeparator(); + + // 4 - Process table files + if (!$this->_processTableFiles($directory)) break; + + $this->_printFileSeparator(); + + // 5 - Process views file + if (!$this->_processViewsFile($directory)) break; + + $this->_printFileSeparator(); + + // 6 - Process functions file + if (!$this->_processFunctionsFile($directory)) break; + + $this->_printFileSeparator(); + + // 7 - Process grants file + if (!$this->_processGrantsFile($directory)) break; + + $this->_printFileSeparator(); + + // 7 - Process extra file + if (!$this->_processExtraFile($directory)) break; + + $processDirectories = true; // If all the steps ends successfully + + $this->_printSchemaSeparator(); + } + + return $processDirectories; + } + + /** + * Checks file names are compliant with the file naming convention + */ + private function _checkFilenaming($directory) + { + $files = array_filter(glob($directory.'/*'), 'is_file'); + + // For each file + foreach ($files as $file) + { + $fileName = basename($file); // File name + // If the file name is NOT compliant with the file naming convention + if (!$this->_isFilenameValid($fileName)) + { + $this->_printInfo('Not valid file name, it is going to be ignored: '.$fileName); + } + } + } + + /** + * Checks if the file name is compliant with the file naming convention + */ + private function _isFilenameValid($fileName) + { + return $fileName == self::SCHEMA_FILENAME // Schema file + || $fileName == self::SEQUENCES_FILENAME // Sequences file + || (substr($fileName, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX + && substr($fileName, -5, strlen(self::JSON_EXT)) == self::JSON_EXT) // Table files + || $fileName == self::VIEWS_FILENAME // Views file + || $fileName == self::FUNCTIONS_FILENAME // Function file + || $fileName == self::GRANTS_FILENAME // Grants file + || $fileName == self::EXTRA_FILENAME; // Extra file + } + + /** + * Process the schema file + */ + private function _processSchemaFile($directory) + { + // Looks for a schema file + $files = array_filter(glob($directory.'/'.self::SCHEMA_FILENAME), 'is_file'); + + // If a schema file is found... + if (count($files) > 0) + { + $this->_printMessage('Found schema file: '.$files[0]); + + //...process it! + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> would be executed in new and diff mode'); + } + else // new or diff mode + { + return $this->_execSQLFile($files[0]); + } + } + else + { + $this->_printMessage('No schema file found'); + } + + return true; // If no files are found then go forward -> is a success + } + + /** + * Process sequences file + * - Looks for sequences present in current schema, then sequences that are not present in php file are dropped + * - Looks for sequences present in php files, then sequences that are not present in database are installed + */ + private function _processSequencesFile($directory) + { + // Looks for a sequences file + $files = array_filter(glob($directory.'/'.self::SEQUENCES_FILENAME), 'is_file'); + + // If a sequences file is found... + if (count($files) > 0) + { + $this->_printMessage('Found sequences file: '.$files[0]); + + //...process it! + require_once($files[0]); // Read sequences file + $schema = basename($directory); // retrieves schema name from directory path + $dbSequencesArray = $this->_listSequencesBySchema($schema); // get list of sequences currently present in DB + + // Loops through list of sequences currently present in database + foreach ($dbSequencesArray as $dbSequence) + { + // If NOT in new mode and if the sequence present in database is NOT present in the list of sequences from php file + if (!$this->_isNewMode() && !array_key_exists($dbSequence, $sequencesArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> sequence '.$dbSequence.' not found in sequences file >> would be removed in diff mode'); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then drop it and objects that depends on it from database! If it fails then ends execution + if (!$this->_execQuery(sprintf('DROP SEQUENCE %s.%s CASCADE', $schema, $dbSequence))) + { + $this->_printError('Error occurred while dropping sequence: '.$dbSequence); + return false; + } + else + { + $this->_printMessage('Sequence dropped successfully: '.$dbSequence); + } + } + } + } + + // Loops through list of sequences from php file + foreach ($sequencesArray as $sequenceName => $sequenceSQL) + { + // If the sequence from php file is NOT present in database + if (!in_array($sequenceName, $dbSequencesArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> sequence '.$sequenceName.' not found database >> would be added in new and diff mode'); + } + else + { + // Then install it! If it fails then ends execution + if (!$this->_execQuery($sequenceSQL)) + { + $this->_printError('Error occurred while adding sequence: '.$sequenceName); + return false; + } + else + { + $this->_printMessage('Sequence added successfully: '.$sequenceName); + } + } + } + } + } + else + { + $this->_printMessage('No sequences file found'); + } + + return true; // If ends of procedure with no failures or no files are found then is a success + } + + /** + * Process table files + */ + private function _processTableFiles($directory) + { + // Looks for table files + $files = array_filter(glob($directory.'/'.self::TABLE_PREFIX.'*'.self::JSON_EXT), 'is_file'); + + // If table files are found... + if (count($files) > 0) + { + //...process them! + } + else + { + $this->_printMessage('No table files found'); + } + + return true; // If no files are found then go forward -> is a success + } + + /** + * Process views file + * - Looks for views present in current schema, then views that are not present in php file are dropped + * - Looks for views present in php files and install them all + */ + private function _processViewsFile($directory) + { + // Looks for a views file + $files = array_filter(glob($directory.'/'.self::VIEWS_FILENAME), 'is_file'); + + // If a views file is found... + if (count($files) > 0) + { + $this->_printMessage('Found views file: '.$files[0]); + + //...process it! + require_once($files[0]); // Read views file + $schema = basename($directory); // retrieves schema name from directory path + $dbViewsArray = $this->_listViewsBySchema($schema); // get list of views currently present in DB + + // Loops through list of views currently present in database + foreach ($dbViewsArray as $dbView) + { + // If NOT in new mode and if the view present in database is NOT present in the list of views from php file + if (!$this->_isNewMode() && !array_key_exists($dbView, $viewsArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> view '.$dbView.' not found in views file >> would be removed in diff mode'); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then drop it and objects that depends on it from database! If it fails then ends execution + if (!$this->_execQuery(sprintf('DROP VIEW %s.%s CASCADE', $schema, $dbView))) + { + $this->_printError('Error occurred while dropping view: '.$dbView); + return false; + } + else + { + $this->_printMessage('View dropped successfully: '.$dbView); + } + } + } + } + + // Loops through list of views from php file + foreach ($viewsArray as $viewName => $viewSQL) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> view '.$viewName.' would be added in new and diff mode'); + } + else + { + // Then install it! If it fails then ends execution + if (!$this->_execQuery($viewSQL)) + { + $this->_printError('Error occurred while adding view: '.$viewName); + return false; + } + else + { + $this->_printMessage('View added successfully: '.$viewName); + } + } + } + } + else + { + $this->_printMessage('No views file found'); + } + + return true; // If ends of procedure with no failures or no files are found then is a success + } + + /** + * Process functions file + */ + private function _processFunctionsFile($directory) + { + // Looks for a functions file + $files = array_filter(glob($directory.'/'.self::FUNCTIONS_FILENAME), 'is_file'); + + // If a functions file is found... + if (count($files) > 0) + { + $this->_printMessage('Found functions file: '.$files[0]); + + //...process it! + require_once($files[0]); // Read functions file + $schema = basename($directory); // retrieves schema name from directory path + $dbFunctionsArray = $this->_listFunctionsBySchema($schema); // get list of functions currently present in DB + + // Loops through list of functions currently present in database + foreach ($dbFunctionsArray as $dbFunction) + { + // If NOT in new mode and if the function present in database is NOT present in the list of functions from php file + if (!$this->_isNewMode() && !array_key_exists($dbFunction, $functionsArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> function '.$dbFunction.' not found in fucntions file >> would be removed in diff mode'); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then drop it and objects that depends on it from database! If it fails then ends execution + if (!$this->_execQuery(sprintf('DROP FUNCTION %s.%s CASCADE', $schema, $dbFunction))) + { + $this->_printError('Error occurred while dropping function: '.$dbFunction); + return false; + } + else + { + $this->_printMessage('Function dropped successfully: '.$dbFunction); + } + } + } + } + + // Loops through list of functions from php file + foreach ($functionsArray as $functionName => $functionSQL) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> view '.$functionName.' would be added in new and diff mode'); + } + else + { + // Then install it! If it fails then ends execution + if (!$this->_execQuery($functionSQL)) + { + $this->_printError('Error occurred while adding function: '.$functionName); + return false; + } + else + { + $this->_printMessage('Function added successfully: '.$functionName); + } + } + } + } + else + { + $this->_printMessage('No functions file found'); + } + + return true; // If ends of procedure with no failures or no files are found then is a success + } + + /** + * Process grants file + */ + private function _processGrantsFile($directory) + { + // Looks for a grants file + $files = array_filter(glob($directory.'/'.self::GRANTS_FILENAME), 'is_file'); + + // If a grants file is found... + if (count($files) > 0) + { + $this->_printMessage('Found grants file: '.$files[0]); + + //...process it! + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> would be executed in new and diff mode'); + } + else // new or diff mode + { + return $this->_execSQLFile($files[0]); + } + } + else + { + $this->_printMessage('No grants file found'); + } + + return true; // If no files are found then go forward -> is a success + } + + /** + * Process extra file + */ + private function _processExtraFile($directory) + { + // Looks for an extra file + $files = array_filter(glob($directory.'/'.self::EXTRA_FILENAME), 'is_file'); + + // If an extra file is found... + if (count($files) > 0) + { + $this->_printMessage('Found extra file: '.$files[0]); + + //...process it! + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> would be executed in new and diff mode'); + } + else // new or diff mode + { + return $this->_execSQLFile($files[0]); + } + } + else + { + $this->_printMessage('No extra file found'); + } + + return true; // If no files are found then go forward -> is a success + } + + /** + * Load SQL from a file and then execute such SQL + */ + private function _execSQLFile($file) + { + $sql = file_get_contents($file); // Read the file content + if ($sql === false) // If failed + { + $this->_printError('Error occurred while reading file: '.$file); + } + else // otherwise + { + // Exec query + if ($this->_execQuery($sql) == false) // if failed + { + $this->_printError('Error occurred while executing SQL from file: '.$file); + } + else // otherwise + { + $this->_printMessage('Successfully executed SQL from file: '.$file); + return true; + } + } + + return false; + } + + /** + * + */ + private function _isDryrunMode() + { + return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_DRYRUN; + } + + /** + * + */ + private function _isDiffMode() + { + return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_DIFF; + } + + /** + * + */ + private function _isNewMode() + { + return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_NEW; + } + + //------------------------------------------------------------------------------------------------------------------ + // Private database methods + + /** + * Executes the given query + */ + private function _execQuery($query) + { + if (!@$this->_ci->db->simple_query($query)) + { + $error = $this->_ci->db->error(); + if (is_array($error) && isset($error['message'])) + { + $this->_printError($error['message']); + } + + return false; + } + + return true; + } + + /** + * + */ + private function _listSequencesBySchema($schema) + { + $sequencesArray = array(); + $query = sprintf('SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = \'%s\'', $schema); + + if ($sequences = @$this->_ci->db->query($query)) + { + foreach ($sequences->result() as $sequence) + { + $sequencesArray[] = $sequence->sequence_name; + } + } + + return $sequencesArray; + } + + /** + * + */ + private function _listViewsBySchema($schema) + { + $viewsArray = array(); + $query = sprintf('SELECT table_name FROM information_schema.views WHERE table_schema = \'%s\'', $schema); + + if ($views = @$this->_ci->db->query($query)) + { + foreach ($views->result() as $view) + { + $viewsArray[] = $view->table_name; + } + } + + return $viewsArray; + } + + /** + * + */ + private function _listFunctionsBySchema($schema) + { + $functionsArray = array(); + $query = sprintf('SELECT p.proname as "view_name" + FROM pg_catalog.pg_proc p + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace + WHERE n.nspname <> \'pg_catalog\' + AND n.nspname <> \'information_schema\' + AND n.nspname = \'%s\'', $schema); + + if ($functions = @$this->_ci->db->query($query)) + { + foreach ($functions->result() as $function) + { + $functionsArray[] = $function->view_name; + } + } + + return $functionsArray; + } + + + + + + + + + + + + + + + + + + + + /** + * Check if a column exists in a table and schema + */ + private function _columnExists($name, $schema, $table) + { + $query = sprintf('SELECT %s FROM %s.%s LIMIT 1', $name, $schema, $table); + + if (@$this->_ci->db->simple_query($query)) + { + return true; + } + + return false; + } + + /** + * Print an info about the starting of method up + */ + private function _startUP() + { + $this->eprintflib->printMessage( + sprintf('%s Start method up of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) + ); + } + + /** + * Print an info about the ending of method up + */ + private function _endUP() + { + $this->eprintflib->printMessage( + sprintf('%s End method up of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) + ); + } + + /** + * Print an info about the starting of method down + */ + private function _startDown() + { + $this->eprintflib->printMessage( + sprintf('%s Start method down of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) + ); + } + + /** + * Print an info about the ending of method down + */ + private function _endDown() + { + $this->eprintflib->printMessage( + sprintf('%s End method down of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) + ); + } + + /** + * Adds a column, with attributes, to a table and schema + */ + private function _addColumn($schema, $table, $fields) + { + foreach ($fields as $name => $definition) + { + if (!$this->columnExists($name, $schema, $table)) + { + if ($this->_ci->dbforge->add_column($schema.'.'.$table, array($name => $definition))) + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s of type %s added', $schema, $table, $name, $definition['type'])); + } + else + { + $this->eprintflib->printError(sprintf('Error while adding column %s.%s.%s of type %s', $schema, $table, $name, $definition['type'])); + } + } + else + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s already exists', $schema, $table, $name)); + } + } + } + + /** + * Modifies a column, and its attributes, of a table and schema + */ + private function _modifyColumn($schema, $table, $fields) + { + foreach ($fields as $name => $definition) + { + if ($this->columnExists($name, $schema, $table)) + { + if ($this->_ci->dbforge->modify_column($schema.'.'.$table, array($name => $definition))) + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s has been modified', $schema, $table, $name)); + } + else + { + $this->eprintflib->printError(sprintf('Error while modifying column %s.%s.%s', $schema, $table, $name)); + } + } + else + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s does NOTt exist', $schema, $table, $name)); + } + } + } + + /** + * Drops a column from a table and schema + */ + private function _dropColumn($schema, $table, $field) + { + if ($this->columnExists($field, $schema, $table)) + { + if ($this->_ci->dbforge->drop_column($schema.'.'.$table, $field)) + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s has been dropped', $schema, $table, $field)); + } + else + { + $this->eprintflib->printError(sprintf('Error while dropping column %s.%s.%s', $schema, $table, $field)); + } + } + else + { + $this->eprintflib->printMessage(sprintf('Column %s.%s.%s does NOT t exist', $schema, $table, $field)); + } + } + + /** + * Sets a column as primary key of a table and schema + */ + private function _addPrimaryKey($schema, $table, $name, $fields) + { + $stringFields = null; + + if (is_array($fields)) + { + if (count($fields) > 0) + { + $stringFields = ''; + for ($i = 0; $i < count($fields); $i++) + { + $stringFields .= $fields[$i]; + if ($i != count($fields) - 1) + { + $stringFields .= ', '; + } + } + $query = sprintf('ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)', $schema, $table, $name, $stringFields); + } + } + else + { + $query = sprintf('ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)', $schema, $table, $name, $fields); + } + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage(sprintf('Added primary key %s on table %s.%s', $name, $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Adding primary key %s on table %s.%s', $name, $schema, $table)); + } + } + + /** + * Sets a column as foreign key of a table and schema + */ + private function _addForeingKey($schema, $table, $name, $field, $schemaDest, $tableDest, $fieldDest, $attributes) + { + $query = sprintf( + 'ALTER TABLE %s.%s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s.%s (%s) %s', + $schema, + $table, + $name, + $field, + $schemaDest, + $tableDest, + $fieldDest, + $attributes + ); + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage(sprintf('Added foreign key %s on table %s.%s', $name, $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Adding foreign key %s on table %s.%s', $name, $schema, $table)); + } + } + + /** + * Sets a column as unique key of a table and schema + */ + private function _addUniqueKey($schema, $table, $name, $fields) + { + $stringFields = null; + + if (is_array($fields)) + { + if (count($fields) > 0) + { + $stringFields = ''; + for ($i = 0; $i < count($fields); $i++) + { + $stringFields .= $fields[$i]; + if ($i != count($fields) - 1) + { + $stringFields .= ', '; + } + } + $query = sprintf('CREATE UNIQUE INDEX %s ON %s.%s (%s)', $name, $schema, $table, $stringFields); + } + } + else + { + $query = sprintf('CREATE UNIQUE INDEX %s ON %s.%s (%s)', $name, $schema, $table, $fields); + } + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage(sprintf('Added unique key %s on table %s.%s', $name, $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Adding unique key %s on table %s.%s', $name, $schema, $table)); + } + } + + /** + * Grants permissions to a user on a table and schema + */ + private function _grantTable($permissions, $schema, $table, $user) + { + $stringPermission = null; + + if (is_array($permissions)) + { + if (count($permissions) > 0) + { + $stringPermission = ''; + for ($i = 0; $i < count($permissions); $i++) + { + $stringPermission .= $permissions[$i]; + if ($i != count($permissions) - 1) + { + $stringPermission .= ', '; + } + } + $query = sprintf('GRANT %s ON TABLE %s.%s TO %s', $stringPermission, $schema, $table, $user); + } + } + else + { + $query = sprintf('GRANT %s ON TABLE %s.%s TO %s', $permissions, $schema, $table, $user); + } + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage( + sprintf( + 'Granted permissions %s on table %s.%s to user %s', + is_null($stringPermission) ? $permissions : $stringPermission, + $schema, + $table, + $user + ) + ); + } + else + { + $this->eprintflib->printError( + sprintf( + 'Granting permissions %s on table %s.%s to user %s', + is_null($stringPermission) ? $permissions : $stringPermission, + $schema, + $table, + $user + ) + ); + } + } + + /** + * Creates a table in a schema with columns + */ + private function _createTable($schema, $table, $fields) + { + $this->_ci->dbforge->add_field($fields); + + if ($this->_ci->dbforge->create_table($schema.'.'.$table, true)) + { + $this->eprintflib->printMessage(sprintf('Table %s.%s created or existing', $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Creating table %s.%s', $schema, $table)); + } + } + + /** + * Drops a table from a schema + */ + private function _dropTable($schema, $table) + { + if ($this->_ci->dbforge->drop_table($schema.'.'.$table)) + { + $this->eprintflib->printMessage(sprintf('Table %s.%s has been dropped', $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Dropping table %s.%s', $schema, $table)); + } + } + + /** + * Initializes a sequence with the max value of a column + */ + private function _initializeSequence($schemaSrc, $sequence, $schemaDst, $table, $field) + { + $query = sprintf('SELECT SETVAL(\'%s.%s\', (SELECT MAX(%s) FROM %s.%s))', $schemaSrc, $sequence, $field, $schemaDst, $table); + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage(sprintf('Sequence %s.%s has been initialized', $schemaSrc, $sequence)); + } + else + { + $this->eprintflib->printError(sprintf('Initializing sequence %s.%s', $schemaSrc, $sequence)); + } + } + + /** + * Add comment to a column + */ + private function _commentOnColumn($schema, $table, $field, $comment) + { + $query = sprintf('COMMENT ON COLUMN %s.%s.%s IS ?', $schema, $table, $field); + + if (@$this->_ci->db->query($query, array($comment))) + { + $this->eprintflib->printMessage(sprintf('Comment added to %s.%s.%s', $schema, $table, $field)); + } + else + { + $this->eprintflib->printError(sprintf('Error while adding comment to %s.%s.%s', $schema, $table, $field)); + } + } + + /** + * Add comment to a table + */ + private function _commentOnTable($schema, $table, $comment) + { + $query = sprintf('COMMENT ON TABLE %s.%s IS ?', $schema, $table, $field); + + if (@$this->_ci->db->query($query, array($comment))) + { + $this->eprintflib->printMessage(sprintf('Comment added to %s.%s', $schema, $table)); + } + else + { + $this->eprintflib->printError(sprintf('Error while adding comment to %s.%s', $schema, $table)); + } + } + /** + * Grants permissions to a user on a sequence + */ + private function _grantSequence($permissions, $schema, $sequence, $user) + { + $stringPermission = null; + + if (is_array($permissions)) + { + if (count($permissions) > 0) + { + $stringPermission = ''; + for ($i = 0; $i < count($permissions); $i++) + { + $stringPermission .= $permissions[$i]; + if ($i != count($permissions) - 1) + { + $stringPermission .= ', '; + } + } + $query = sprintf('GRANT %s ON SEQUENCE %s.%s TO %s', $stringPermission, $schema, $sequence, $user); + } + } + else + { + $query = sprintf('GRANT %s ON SEQUENCE %s.%s TO %s', $permissions, $schema, $sequence, $user); + } + + if (@$this->_ci->db->simple_query($query)) + { + $this->eprintflib->printMessage( + sprintf( + 'Granted permissions %s on sequence %s.%s to user %s', + is_null($stringPermission) ? $permissions : $stringPermission, + $schema, + $sequence, + $user + ) + ); + } + else + { + $this->eprintflib->printError( + sprintf( + 'Granting permissions %s on sequence %s.%s to user %s', + is_null($stringPermission) ? $permissions : $stringPermission, + $schema, + $sequence, + $user + ) + ); + } + } + + //------------------------------------------------------------------------------------------------------------------ + // Private output methods + + /** + * + */ + private function _printInfo($string) + { + $this->_ci->eprintflib->printInfo($string); + } + + /** + * + */ + private function _printError($string) + { + $this->_ci->eprintflib->printError($string); + } + + /** + * + */ + private function _printMessage($string) + { + $this->_ci->eprintflib->printMessage($string); + } + + /** + * + */ + private function _printSchemaSeparator() + { + $this->_printInfo('--------------------------------------------------------------------------------------------'); + } + + /** + * + */ + private function _printFileSeparator() + { + $this->_printMessage('--------------------------------------------------------------------------------------------'); + } +} From 0f61a9e814a4062c0f6a9be9426e7ab16fd0547e Mon Sep 17 00:00:00 2001 From: Paolo Date: Wed, 5 Jun 2019 10:22:14 +0200 Subject: [PATCH 006/500] - Added parameters steps and selectedDirectories to controller controllers/system/DBSkel - Added exit status to controller controllers/system/DBSkel - Removed old code from libraries/DBSkelLib - Added steps parameter to libraries/DBSkelLib to select the step/s to perform (colon separated) - Added selectedDirectories parameter to libraries/DBSkelLib to select the directory/ies to process (colon separated) - All DBSkel structure files are in php and SQL formats - The steps order is the following: schema, sequences, tables, constraints, views, functions, grants and extras - Current running modes are: dry run, new and diff - Diff mode is still under construction --- application/controllers/system/DBSkel.php | 8 +- application/libraries/DBSkelLib.php | 968 ++++++++++++---------- 2 files changed, 528 insertions(+), 448 deletions(-) diff --git a/application/controllers/system/DBSkel.php b/application/controllers/system/DBSkel.php index 071cfaa9e..94ba18cf6 100644 --- a/application/controllers/system/DBSkel.php +++ b/application/controllers/system/DBSkel.php @@ -15,10 +15,12 @@ class DBSkel extends CLI_Controller } /** - * Starts the migration procedure + * Starts the DBSkel procedure */ - public function start() + public function start($step = null, $selectedDirectories = null) { - $this->dbskellib->start(); + // If the DBSkel procedure fails then exit with an error + // In this way it's possible to undestand from console what is the exit status of the procedure + $this->dbskellib->start($step, $selectedDirectories) === true ? exit(0) : exit(1); } } diff --git a/application/libraries/DBSkelLib.php b/application/libraries/DBSkelLib.php index ed9be19f1..df8a71a6c 100644 --- a/application/libraries/DBSkelLib.php +++ b/application/libraries/DBSkelLib.php @@ -11,29 +11,45 @@ class DBSkelLib const CONF_ENABLED = 'dbskel_enabled'; const CONF_MODE = 'dbskel_mode'; + const SEPARATOR = ':'; // Step parameter character separator + // Run modes const RUN_MODE_DRYRUN = 'dryrun'; // run without changing the database, useful for testing const RUN_MODE_NEW = 'new'; // build a new database or if database is already present creates only new objects const RUN_MODE_DIFF = 'diff'; // like new, but it also remove object from database that are NOT present in configuration files + const STEP_SCHEMA = 1; + const STEP_SEQUENCES = 2; + const STEP_TABLES = 3; + const STEP_CONSTRAINTS = 4; + const STEP_VIEWS = 5; + const STEP_FUNCTIONS = 6; + const STEP_GRANTS = 7; + const STEP_EXTRA = 8; + + const MAX_STEPS = 8; // Maximum number of steps + // Configuration file names const SCHEMA_FILENAME = 'schema.sql'; // File name that contains schema creation SQL and SQL to comment a schema const SEQUENCES_FILENAME = 'sequences.php'; // PHP file that contains all the sequences const TABLE_PREFIX = 'TBL-'; // Table file prefix + const CONSTRAINTS_FILENAME = 'constraints.php'; // PHP file that contains all the constraints const VIEWS_FILENAME = 'views.php'; // PHP file that contains all the views const FUNCTIONS_FILENAME = 'functions.php'; // PHP file that contains all the functions const GRANTS_FILENAME = 'grants.sql'; // Grants SQL file name const EXTRA_FILENAME = 'extra.sql'; // Extra SQL file name - // JSON file extension - const JSON_EXT = '.json'; + // PHP file extension + const PHP_EXT = '.php'; - // Directory that containts the database skel + // Directory that contains the database skel const DBSKEL_DIR = APPPATH.'dbskel/'; - // Tables JSON properties name - const JSON_NAME = 'name'; - const JSON_SQL = 'sql'; + // Table properties + const T_COMMENT = 'comment'; + const T_TYPE = 'type'; + const T_NULL = 'null'; + const T_DEFAULT = 'default'; private $_ci; // Code igniter instance @@ -61,22 +77,42 @@ class DBSkelLib * Starts the DBSkel procedure * Returns false on failure and true on success * All errors/warnings/infos are printed here using EPrintfLib + * Accept the step parameter that can be used to run only a wanted step */ - public function start() + public function start($steps, $selectedDirectories) { $start = false; // Checks if DBSkel is enabled if ($this->_ci->config->item(self::CONF_ENABLED) === true) { - // Gets all the directories in application/dbskel - $start = $this->_processDirectories(glob(self::DBSKEL_DIR.'*', GLOB_ONLYDIR)); + // Checks if the given steps parameter is fine + if ($this->_checkParameterStep($steps)) + { + $this->_printSchemaSeparator(); - $this->_printSchemaSeparator(); + $this->_printRunningMode(); + + // By default perform all steps + $stepsArray = range(1, self::MAX_STEPS); + // If steps parameter is given then use it to select the steps to be performed + if ($steps != null) $stepsArray = explode(self::SEPARATOR, $steps); + + // Gets all the directories in application/dbskel + $directories = glob(self::DBSKEL_DIR.'*', GLOB_ONLYDIR); + + // Checks if the selectedDirectories parameter is fine + if ($this->_checkParameterSelectedDirectories($selectedDirectories, $directories)) + { + $start = $this->_processDirectories($directories, $stepsArray); + + $this->_printSchemaSeparator(); + } + } } else { - $this->_printMessage('DBSkel is NOT enabled'); + $this->_printInfo('DBSkel is NOT enabled'); } return $start; @@ -88,7 +124,7 @@ class DBSkelLib /** * Process every single directory present in dbskel directory */ - private function _processDirectories($directories) + private function _processDirectories($directories, $stepsArray) { $processDirectories = false; // failure by default @@ -103,44 +139,73 @@ class DBSkelLib // NOTE: the order in which these methods are called has a meaning! // If a step fails then the loop is stopped - // 1 - Checks file naming convention in current directory - // NOTE: no need to check a failure! NOT a blocking check!! + // 0 - Checks file naming convention in current directory + // NOTE: no need to check a failure! NOT a blocking check!! Always performed!!! $this->_checkFilenaming($directory); $this->_printFileSeparator(); - // 2 - Process schema file - if (!$this->_processSchemaFile($directory)) break; + // 1 - Process schema file + if (in_array(self::STEP_SCHEMA, $stepsArray)) + { + if (!$this->_processSchemaFile($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } - // 3 - Process sequence file - if (!$this->_processSequencesFile($directory)) break; + // 2 - Process sequence file + if (in_array(self::STEP_SEQUENCES, $stepsArray)) + { + if (!$this->_processSequencesFile($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } - // 4 - Process table files - if (!$this->_processTableFiles($directory)) break; + // 3 - Process table files + if (in_array(self::STEP_TABLES, $stepsArray)) + { + if (!$this->_processTableFiles($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } + + // 4 - Process constraints + if (in_array(self::STEP_CONSTRAINTS, $stepsArray)) + { + if (!$this->_processConstraintsFile($directory)) break; + + $this->_printFileSeparator(); + } // 5 - Process views file - if (!$this->_processViewsFile($directory)) break; + if (in_array(self::STEP_VIEWS, $stepsArray)) + { + if (!$this->_processViewsFile($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } // 6 - Process functions file - if (!$this->_processFunctionsFile($directory)) break; + if (in_array(self::STEP_FUNCTIONS, $stepsArray)) + { + if (!$this->_processFunctionsFile($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } // 7 - Process grants file - if (!$this->_processGrantsFile($directory)) break; + if (in_array(self::STEP_GRANTS, $stepsArray)) + { + if (!$this->_processGrantsFile($directory)) break; - $this->_printFileSeparator(); + $this->_printFileSeparator(); + } - // 7 - Process extra file - if (!$this->_processExtraFile($directory)) break; + // 8 - Process extra file + if (in_array(self::STEP_EXTRA, $stepsArray)) + { + if (!$this->_processExtraFile($directory)) break; + } $processDirectories = true; // If all the steps ends successfully @@ -177,7 +242,8 @@ class DBSkelLib return $fileName == self::SCHEMA_FILENAME // Schema file || $fileName == self::SEQUENCES_FILENAME // Sequences file || (substr($fileName, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX - && substr($fileName, -5, strlen(self::JSON_EXT)) == self::JSON_EXT) // Table files + && substr($fileName, -4, strlen(self::PHP_EXT)) == self::PHP_EXT) // Table files + || $fileName == self::CONSTRAINTS_FILENAME // Constraints file || $fileName == self::VIEWS_FILENAME // Views file || $fileName == self::FUNCTIONS_FILENAME // Function file || $fileName == self::GRANTS_FILENAME // Grants file @@ -217,8 +283,8 @@ class DBSkelLib /** * Process sequences file - * - Looks for sequences present in current schema, then sequences that are not present in php file are dropped - * - Looks for sequences present in php files, then sequences that are not present in database are installed + * - Looks for sequences present in current schema, then sequences that are NOT present in php file are dropped (diff mode only) + * - Looks for sequences present in php files, then sequences that are NOT present in database are installed */ private function _processSequencesFile($directory) { @@ -233,7 +299,7 @@ class DBSkelLib //...process it! require_once($files[0]); // Read sequences file $schema = basename($directory); // retrieves schema name from directory path - $dbSequencesArray = $this->_listSequencesBySchema($schema); // get list of sequences currently present in DB + $dbSequencesArray = $this->_listSequencesBySchema($schema); // get list of sequences currently present in DB schema // Loops through list of sequences currently present in database foreach ($dbSequencesArray as $dbSequence) @@ -243,7 +309,7 @@ class DBSkelLib { if ($this->_isDryrunMode()) // If dry run mode enabled { - $this->_printInfo('Dry run >> sequence '.$dbSequence.' not found in sequences file >> would be removed in diff mode'); + $this->_printInfo('Dry run >> sequence '.$dbSequence.' NOT found in sequences file >> would be removed in diff mode'); } elseif ($this->_isDiffMode()) // only if in diff mode { @@ -269,7 +335,7 @@ class DBSkelLib { if ($this->_isDryrunMode()) // If dry run mode enabled { - $this->_printInfo('Dry run >> sequence '.$sequenceName.' not found database >> would be added in new and diff mode'); + $this->_printInfo('Dry run >> sequence '.$sequenceName.' NOT found database >> would be added in new and diff mode'); } else { @@ -285,6 +351,10 @@ class DBSkelLib } } } + else + { + $this->_printMessage('Sequence already present in database: '.$sequenceName); + } } } else @@ -301,12 +371,101 @@ class DBSkelLib private function _processTableFiles($directory) { // Looks for table files - $files = array_filter(glob($directory.'/'.self::TABLE_PREFIX.'*'.self::JSON_EXT), 'is_file'); + $files = array_filter(glob($directory.'/'.self::TABLE_PREFIX.'*'.self::PHP_EXT), 'is_file'); // If table files are found... if (count($files) > 0) { //...process them! + $schema = basename($directory); // retrieves schema name from directory path + $dbTablesArray = $this->_listTablesBySchema($schema); // get list of tables currently present in DB schema + + // For each table file + foreach ($files as $file) + { + $this->_printMessage('Found table file: '.$file); + + require_once($file); // Read table file + + // Loops through list of tables currently present in database + foreach ($dbTablesArray as $dbTable) + { + // If NOT in new mode and if the table present in database is NOT present in the php table file + if (!$this->_isNewMode() && !array_key_exists($dbTable, $tableArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> table '.$dbTable.' NOT found in table file >> would be removed in diff mode'); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then drop it! If it fails then ends execution + if (!$this->_execQuery(sprintf('DROP TABLE %s.%s', $schema, $dbTable))) + { + $this->_printError('Error occurred while dropping table: '.$dbTable); + return false; + } + else + { + $this->_printMessage('Table dropped successfully: '.$dbTable); + } + } + } + } + + // Retrieves all the elements from the $tableArray except the element 'comment' + $tableElements = array_keys(array_diff_key($tableArray, array(self::T_COMMENT => null))); + if (is_array($tableElements) && count($tableElements) == 1) // If there is only one element left... + { + $tableName = $tableElements[0]; // ...then it is the name of the table + + // If the table from php file is NOT present in database + if (!in_array($tableName, $dbTablesArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> table '.$tableName.' would be created in new and diff mode'); + } + else // new and diff mode + { + // Then create the new table! If it fails then ends execution + if ($this->_createTable($schema, $tableArray)) + { + $this->_printMessage('Table created successfully: '.$tableName); + } + else + { + $this->_printError('Error occurred while creating a new table: '.$tableName); + return false; + } + } + } + else // if table is already present in database + { + if ($this->_isNewMode()) // only if in new mode + { + $this->_printMessage('Table already present in database: '.$tableName); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then diff the already present table with the one from php file! If it fails then ends execution + if ($this->_diffTable($schema, $tableArray)) + { + $this->_printMessage('Table diff success: '.$tableName); + } + else + { + $this->_printError('Error occurred while diff table: '.$tableName); + return false; + } + } + } + } + else // otherwise the array present in the php table file is not well formatted + { + $this->_printError('Table file with a bad format is going to be ignored: '.$file); + } + } } else { @@ -316,9 +475,96 @@ class DBSkelLib return true; // If no files are found then go forward -> is a success } + /** + * Process constraints file + * - Looks for constraints present in current schema, then constraints that are NOT present in php file are dropped (diff mode only) + * - Looks for constraints present in php files, then constraints that are NOT present in database are installed + */ + private function _processConstraintsFile($directory) + { + // Looks for a constraints file + $files = array_filter(glob($directory.'/'.self::CONSTRAINTS_FILENAME), 'is_file'); + + // If a constraints file is found... + if (count($files) > 0) + { + $this->_printMessage('Found constraints file: '.$files[0]); + + //...process it! + require_once($files[0]); // Read constraints file + $schema = basename($directory); // retrieves schema name from directory path + $dbConstraintsArray = $this->_listConstraintsBySchema($schema); // get list of constraints currently present in DB schema + $dbConstraintsNamesArray = array(); // Contains only the names of the constraints + + // Loops through list of constraints currently present in database + foreach ($dbConstraintsArray as $dbConstraint) + { + $dbConstraintsNamesArray[] = $dbConstraint['name']; // Copy only the name of the constraint + + // If NOT in new mode and if the constraint present in database is NOT present in the list of constraints from php file + if (!$this->_isNewMode() && !array_key_exists($dbConstraint['name'], $constraintsArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> constraint '.$dbConstraint['name'].' NOT found in constraints file >> would be removed in diff mode'); + } + elseif ($this->_isDiffMode()) // only if in diff mode + { + // Then drop it and objects that depends on it from database! If it fails then ends execution + if (!$this->_execQuery(sprintf('ALTER TABLE %s.%s DROP CONSTRAINT %s', $schema, $dbConstraint['table'], $dbConstraint['name']))) + { + $this->_printError('Error occurred while dropping constraint: '.$dbConstraint['name']); + return false; + } + else + { + $this->_printMessage('Constraint dropped successfully: '.$dbConstraint['name']); + } + } + } + } + + // Loops through list of constraints from php file + foreach ($constraintsArray as $constraintName => $constraintSQL) + { + // If the constraint from php file is NOT present in database + if (!in_array($constraintName, $dbConstraintsNamesArray)) + { + if ($this->_isDryrunMode()) // If dry run mode enabled + { + $this->_printInfo('Dry run >> constraint '.$constraintName.' would be added in new and diff mode'); + } + else + { + // Then install it! If it fails then ends execution + if (!$this->_execQuery($constraintSQL)) + { + $this->_printError('Error occurred while adding constraint: '.$constraintName); + return false; + } + else + { + $this->_printMessage('Constraint added successfully: '.$constraintName); + } + } + } + else + { + $this->_printMessage('Constraint already present in database: '.$constraintName); + } + } + } + else + { + $this->_printMessage('No constraints file found'); + } + + return true; // If ends of procedure with no failures or no files are found then is a success + } + /** * Process views file - * - Looks for views present in current schema, then views that are not present in php file are dropped + * - Looks for views present in current schema, then views that are NOT present in php file are dropped (diff mode only) * - Looks for views present in php files and install them all */ private function _processViewsFile($directory) @@ -334,7 +580,7 @@ class DBSkelLib //...process it! require_once($files[0]); // Read views file $schema = basename($directory); // retrieves schema name from directory path - $dbViewsArray = $this->_listViewsBySchema($schema); // get list of views currently present in DB + $dbViewsArray = $this->_listViewsBySchema($schema); // get list of views currently present in DB schema // Loops through list of views currently present in database foreach ($dbViewsArray as $dbView) @@ -344,7 +590,7 @@ class DBSkelLib { if ($this->_isDryrunMode()) // If dry run mode enabled { - $this->_printInfo('Dry run >> view '.$dbView.' not found in views file >> would be removed in diff mode'); + $this->_printInfo('Dry run >> view '.$dbView.' NOT found in views file >> would be removed in diff mode'); } elseif ($this->_isDiffMode()) // only if in diff mode { @@ -394,6 +640,8 @@ class DBSkelLib /** * Process functions file + * - Looks for functions present in current schema, then functions that are NOT present in php file are dropped (diff mode only) + * - Looks for functions present in php files and install them all */ private function _processFunctionsFile($directory) { @@ -408,7 +656,7 @@ class DBSkelLib //...process it! require_once($files[0]); // Read functions file $schema = basename($directory); // retrieves schema name from directory path - $dbFunctionsArray = $this->_listFunctionsBySchema($schema); // get list of functions currently present in DB + $dbFunctionsArray = $this->_listFunctionsBySchema($schema); // get list of functions currently present in DB schema // Loops through list of functions currently present in database foreach ($dbFunctionsArray as $dbFunction) @@ -418,7 +666,7 @@ class DBSkelLib { if ($this->_isDryrunMode()) // If dry run mode enabled { - $this->_printInfo('Dry run >> function '.$dbFunction.' not found in fucntions file >> would be removed in diff mode'); + $this->_printInfo('Dry run >> function '.$dbFunction.' NOT found in fucntions file >> would be removed in diff mode'); } elseif ($this->_isDiffMode()) // only if in diff mode { @@ -556,7 +804,7 @@ class DBSkelLib } /** - * + * Checks if the running mode is 'dryrun' */ private function _isDryrunMode() { @@ -564,7 +812,7 @@ class DBSkelLib } /** - * + * Checks if the running mode is 'diff' */ private function _isDiffMode() { @@ -572,13 +820,80 @@ class DBSkelLib } /** - * + * Checks if the running mode is 'new' */ private function _isNewMode() { return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_NEW; } + /** + * Checks if the parameter step is correct + */ + private function _checkParameterStep($steps) + { + if ($steps != null) // if it was given + { + $stepsArray = explode(self::SEPARATOR, $steps); // split the string in an array + foreach ($stepsArray as $step) + { + if (!is_numeric($step)) // if it is not a number + { + $this->_ci->eprintflib->printError('The given parameter must be a number or a string in the following format: 1:3:5'); + return false; + } + elseif ($step > self::MAX_STEPS) // if it is a number but > MAX_STEPS + { + $this->_ci->eprintflib->printError('The maximun value fot this parameter is: '.self::MAX_STEPS); + return false; + } + elseif ($step < 1) // if it is a number but < 1 + { + $this->_ci->eprintflib->printError('The minimum value fot this parameter is 1'); + return false; + } + } + } + + return true; + } + + /** + * Checks if the parameter selectedDirectories is correct and stores the result in $directories + */ + private function _checkParameterSelectedDirectories($selectedDirectories, &$directories) + { + if ($selectedDirectories != null) + { + $selectedDirectoriesArray = explode(self::SEPARATOR, $selectedDirectories); + + $found = true; + + foreach ($selectedDirectoriesArray as $key => $value) + { + $selectedDirectoriesArray[$key] = self::DBSKEL_DIR.$value; + + if (!in_array(self::DBSKEL_DIR.$value, $directories)) + { + $found = false; + break; + } + } + + if ($found) + { + $directories = $selectedDirectoriesArray; + } + else + { + $this->_printError('One or more of the given directories does NOT exist'); + return false; + } + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------ // Private database methods @@ -602,12 +917,14 @@ class DBSkelLib } /** - * + * Retrieves all the sequences present in the given database schema */ private function _listSequencesBySchema($schema) { $sequencesArray = array(); - $query = sprintf('SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = \'%s\'', $schema); + $query = sprintf('SELECT sequence_name + FROM information_schema.sequences + WHERE sequence_schema = \'%s\'', $schema); if ($sequences = @$this->_ci->db->query($query)) { @@ -621,12 +938,63 @@ class DBSkelLib } /** - * + * Retrieves all the tables present in the given database schema + */ + private function _listTablesBySchema($schema) + { + $tablesArray = array(); + $query = sprintf('SELECT table_name + FROM information_schema.tables + WHERE table_type = \'BASE TABLE\' + AND table_schema = \'%s\'', $schema); + + if ($tables = @$this->_ci->db->query($query)) + { + foreach ($tables->result() as $table) + { + $tablesArray[] = $table->table_name; + } + } + + return $tablesArray; + } + + /** + * Retrieves all the constraints present in the given database schema + * Returns an array with all the constraints, each element of the array is an array with two elements: + * - name: the name of the constraint + * - table: the name of the table where the constraint is applied + * NOTE: does not retrieve NOT NULL constraints + */ + private function _listConstraintsBySchema($schema) + { + $constraintsArray = array(); + $query = sprintf('SELECT constraint_name, + table_name + FROM information_schema.table_constraints + WHERE table_schema = \'%s\' + AND constraint_name NOT LIKE \'%%_not_null\'', $schema); // avoid to retrieve NOT NULL constraints + + if ($constraints = @$this->_ci->db->query($query)) + { + foreach ($constraints->result() as $constraint) + { + $constraintsArray[] = array('name' => $constraint->constraint_name, 'table' => $constraint->table_name); + } + } + + return $constraintsArray; + } + + /** + * Retrieves all the views present in the given database schema */ private function _listViewsBySchema($schema) { $viewsArray = array(); - $query = sprintf('SELECT table_name FROM information_schema.views WHERE table_schema = \'%s\'', $schema); + $query = sprintf('SELECT table_name + FROM information_schema.views + WHERE table_schema = \'%s\'', $schema); if ($views = @$this->_ci->db->query($query)) { @@ -640,465 +1008,165 @@ class DBSkelLib } /** - * + * Retrieves all the functions present in the given database schema */ private function _listFunctionsBySchema($schema) { $functionsArray = array(); - $query = sprintf('SELECT p.proname as "view_name" - FROM pg_catalog.pg_proc p - LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace - WHERE n.nspname <> \'pg_catalog\' - AND n.nspname <> \'information_schema\' - AND n.nspname = \'%s\'', $schema); + $query = sprintf('SELECT routine_name + FROM information_schema.routines + WHERE specific_schema != \'pg_catalog\' + AND specific_schema != \'information_schema\' + AND routine_schema = \'%s\'', $schema); if ($functions = @$this->_ci->db->query($query)) { foreach ($functions->result() as $function) { - $functionsArray[] = $function->view_name; + $functionsArray[] = $function->routine_name; } } return $functionsArray; } - - - - - - - - - - - - - - - - - - /** - * Check if a column exists in a table and schema + * Retrieves all the columns from a database table */ - private function _columnExists($name, $schema, $table) + private function _listColumns($schema, $table) { - $query = sprintf('SELECT %s FROM %s.%s LIMIT 1', $name, $schema, $table); + $columnsArray = array(); + $query = sprintf('SELECT * + FROM information_schema.columns + WHERE table_schema = \'%s\' + AND table_name = \'%s\'', $schema, $table); - if (@$this->_ci->db->simple_query($query)) + if ($columns = @$this->_ci->db->query($query)) { - return true; - } - - return false; - } - - /** - * Print an info about the starting of method up - */ - private function _startUP() - { - $this->eprintflib->printMessage( - sprintf('%s Start method up of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the ending of method up - */ - private function _endUP() - { - $this->eprintflib->printMessage( - sprintf('%s End method up of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the starting of method down - */ - private function _startDown() - { - $this->eprintflib->printMessage( - sprintf('%s Start method down of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Print an info about the ending of method down - */ - private function _endDown() - { - $this->eprintflib->printMessage( - sprintf('%s End method down of class %s %s', EPrintfLib::SEPARATOR, get_called_class(), EPrintfLib::SEPARATOR) - ); - } - - /** - * Adds a column, with attributes, to a table and schema - */ - private function _addColumn($schema, $table, $fields) - { - foreach ($fields as $name => $definition) - { - if (!$this->columnExists($name, $schema, $table)) + foreach ($columns->result() as $column) { - if ($this->_ci->dbforge->add_column($schema.'.'.$table, array($name => $definition))) - { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s of type %s added', $schema, $table, $name, $definition['type'])); - } - else - { - $this->eprintflib->printError(sprintf('Error while adding column %s.%s.%s of type %s', $schema, $table, $name, $definition['type'])); - } - } - else - { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s already exists', $schema, $table, $name)); + $columnsArray[] = $column->routine_name; } } + + return $columnsArray; } /** - * Modifies a column, and its attributes, of a table and schema + * Creates a new table in database using the given schema and an array that defines the table structure */ - private function _modifyColumn($schema, $table, $fields) + private function _createTable($schema, $tableArray) { - foreach ($fields as $name => $definition) + $tableName = ''; + $tableComment = ''; + $tableStructure = null; + + // For each element of the table array from the php file + foreach ($tableArray as $key => $value) { - if ($this->columnExists($name, $schema, $table)) + if ($key == self::T_COMMENT) // If it is the comment element { - if ($this->_ci->dbforge->modify_column($schema.'.'.$table, array($name => $definition))) - { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s has been modified', $schema, $table, $name)); - } - else - { - $this->eprintflib->printError(sprintf('Error while modifying column %s.%s.%s', $schema, $table, $name)); - } + $tableComment = $value; } - else + else // otherwise is the table structure element { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s does NOTt exist', $schema, $table, $name)); + $tableName = $key; + $tableStructure = $value; } } - } - /** - * Drops a column from a table and schema - */ - private function _dropColumn($schema, $table, $field) - { - if ($this->columnExists($field, $schema, $table)) + // Query to create a table + $query = sprintf('CREATE TABLE %s.%s (', $schema, $tableName); + // Query to comment the table and its columns + $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); + + // For each element of the table structure + foreach ($tableStructure as $colName => $colStructure) { - if ($this->_ci->dbforge->drop_column($schema.'.'.$table, $field)) + $notNull = ''; // by default the column could be null + if (isset($colStructure[self::T_NULL]) && $colStructure[self::T_NULL] === false) { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s has been dropped', $schema, $table, $field)); + $notNull = 'NOT NULL'; // set to NOT NULL } - else + + $default = ''; // by default there is no default for a column + if (isset($colStructure[self::T_DEFAULT])) { - $this->eprintflib->printError(sprintf('Error while dropping column %s.%s.%s', $schema, $table, $field)); + $default = 'DEFAULT '.$colStructure[self::T_DEFAULT]; // set as given by the table structure + } + + // Part of the query related to this column + $query .= sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); + + // If a comment is present for this column then the query is built + if (isset($colStructure[self::T_COMMENT])) + { + $queryComment .= sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); } } - else - { - $this->eprintflib->printMessage(sprintf('Column %s.%s.%s does NOT t exist', $schema, $table, $field)); - } + + // Removes the last comma from the query + $query = substr($query, 0, strlen($query) - 1); + + // Close the round bracket + $query .= ');'; + + return $this->_execQuery($query.$queryComment); // executes query and returns its result } /** - * Sets a column as primary key of a table and schema + * TODO + * Changes the structure of a table using the given schema and an array that defines the table structure */ - private function _addPrimaryKey($schema, $table, $name, $fields) + private function _diffTable($schema, $tableArray) { - $stringFields = null; + $tableName = ''; + $tableComment = ''; + $tableStructure = null; - if (is_array($fields)) + // For each element of the table array from the php file + foreach ($tableArray as $key => $value) { - if (count($fields) > 0) + if ($key == self::T_COMMENT) // If it is the comment element { - $stringFields = ''; - for ($i = 0; $i < count($fields); $i++) - { - $stringFields .= $fields[$i]; - if ($i != count($fields) - 1) - { - $stringFields .= ', '; - } - } - $query = sprintf('ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)', $schema, $table, $name, $stringFields); + $tableComment = $value; + } + else // otherwise is the table structure element + { + $tableName = $key; + $tableStructure = $value; } } - else - { - $query = sprintf('ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s)', $schema, $table, $name, $fields); - } - if (@$this->_ci->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf('Added primary key %s on table %s.%s', $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Adding primary key %s on table %s.%s', $name, $schema, $table)); - } - } + // Query to alter the table + $query = ''; + // Query to comment the table and its columns + $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); - /** - * Sets a column as foreign key of a table and schema - */ - private function _addForeingKey($schema, $table, $name, $field, $schemaDest, $tableDest, $fieldDest, $attributes) - { - $query = sprintf( - 'ALTER TABLE %s.%s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s.%s (%s) %s', - $schema, - $table, - $name, - $field, - $schemaDest, - $tableDest, - $fieldDest, - $attributes - ); - - if (@$this->_ci->db->simple_query($query)) + // For each element of the table structure + foreach ($tableStructure as $colName => $colStructure) { - $this->eprintflib->printMessage(sprintf('Added foreign key %s on table %s.%s', $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Adding foreign key %s on table %s.%s', $name, $schema, $table)); - } - } - - /** - * Sets a column as unique key of a table and schema - */ - private function _addUniqueKey($schema, $table, $name, $fields) - { - $stringFields = null; - - if (is_array($fields)) - { - if (count($fields) > 0) + $notNull = ''; // by default the column could be null + if (isset($colStructure[self::T_NULL]) && $colStructure[self::T_NULL] === false) { - $stringFields = ''; - for ($i = 0; $i < count($fields); $i++) - { - $stringFields .= $fields[$i]; - if ($i != count($fields) - 1) - { - $stringFields .= ', '; - } - } - $query = sprintf('CREATE UNIQUE INDEX %s ON %s.%s (%s)', $name, $schema, $table, $stringFields); + $notNull = 'NOT NULL'; // set to NOT NULL } - } - else - { - $query = sprintf('CREATE UNIQUE INDEX %s ON %s.%s (%s)', $name, $schema, $table, $fields); - } - if (@$this->_ci->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf('Added unique key %s on table %s.%s', $name, $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Adding unique key %s on table %s.%s', $name, $schema, $table)); - } - } - - /** - * Grants permissions to a user on a table and schema - */ - private function _grantTable($permissions, $schema, $table, $user) - { - $stringPermission = null; - - if (is_array($permissions)) - { - if (count($permissions) > 0) + $default = ''; // by default there is no default for a column + if (isset($colStructure[self::T_DEFAULT])) { - $stringPermission = ''; - for ($i = 0; $i < count($permissions); $i++) - { - $stringPermission .= $permissions[$i]; - if ($i != count($permissions) - 1) - { - $stringPermission .= ', '; - } - } - $query = sprintf('GRANT %s ON TABLE %s.%s TO %s', $stringPermission, $schema, $table, $user); + $default = 'DEFAULT '.$colStructure[self::T_DEFAULT]; // set as given by the table structure } - } - else - { - $query = sprintf('GRANT %s ON TABLE %s.%s TO %s', $permissions, $schema, $table, $user); - } - if (@$this->_ci->db->simple_query($query)) - { - $this->eprintflib->printMessage( - sprintf( - 'Granted permissions %s on table %s.%s to user %s', - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $table, - $user - ) - ); - } - else - { - $this->eprintflib->printError( - sprintf( - 'Granting permissions %s on table %s.%s to user %s', - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $table, - $user - ) - ); - } - } + // Part of the query related to this column + $query .= sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); - /** - * Creates a table in a schema with columns - */ - private function _createTable($schema, $table, $fields) - { - $this->_ci->dbforge->add_field($fields); - - if ($this->_ci->dbforge->create_table($schema.'.'.$table, true)) - { - $this->eprintflib->printMessage(sprintf('Table %s.%s created or existing', $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Creating table %s.%s', $schema, $table)); - } - } - - /** - * Drops a table from a schema - */ - private function _dropTable($schema, $table) - { - if ($this->_ci->dbforge->drop_table($schema.'.'.$table)) - { - $this->eprintflib->printMessage(sprintf('Table %s.%s has been dropped', $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Dropping table %s.%s', $schema, $table)); - } - } - - /** - * Initializes a sequence with the max value of a column - */ - private function _initializeSequence($schemaSrc, $sequence, $schemaDst, $table, $field) - { - $query = sprintf('SELECT SETVAL(\'%s.%s\', (SELECT MAX(%s) FROM %s.%s))', $schemaSrc, $sequence, $field, $schemaDst, $table); - - if (@$this->_ci->db->simple_query($query)) - { - $this->eprintflib->printMessage(sprintf('Sequence %s.%s has been initialized', $schemaSrc, $sequence)); - } - else - { - $this->eprintflib->printError(sprintf('Initializing sequence %s.%s', $schemaSrc, $sequence)); - } - } - - /** - * Add comment to a column - */ - private function _commentOnColumn($schema, $table, $field, $comment) - { - $query = sprintf('COMMENT ON COLUMN %s.%s.%s IS ?', $schema, $table, $field); - - if (@$this->_ci->db->query($query, array($comment))) - { - $this->eprintflib->printMessage(sprintf('Comment added to %s.%s.%s', $schema, $table, $field)); - } - else - { - $this->eprintflib->printError(sprintf('Error while adding comment to %s.%s.%s', $schema, $table, $field)); - } - } - - /** - * Add comment to a table - */ - private function _commentOnTable($schema, $table, $comment) - { - $query = sprintf('COMMENT ON TABLE %s.%s IS ?', $schema, $table, $field); - - if (@$this->_ci->db->query($query, array($comment))) - { - $this->eprintflib->printMessage(sprintf('Comment added to %s.%s', $schema, $table)); - } - else - { - $this->eprintflib->printError(sprintf('Error while adding comment to %s.%s', $schema, $table)); - } - } - /** - * Grants permissions to a user on a sequence - */ - private function _grantSequence($permissions, $schema, $sequence, $user) - { - $stringPermission = null; - - if (is_array($permissions)) - { - if (count($permissions) > 0) + // If a comment is present for this column then the query is built + if (isset($colStructure[self::T_COMMENT])) { - $stringPermission = ''; - for ($i = 0; $i < count($permissions); $i++) - { - $stringPermission .= $permissions[$i]; - if ($i != count($permissions) - 1) - { - $stringPermission .= ', '; - } - } - $query = sprintf('GRANT %s ON SEQUENCE %s.%s TO %s', $stringPermission, $schema, $sequence, $user); + $queryComment .= sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); } } - else - { - $query = sprintf('GRANT %s ON SEQUENCE %s.%s TO %s', $permissions, $schema, $sequence, $user); - } - - if (@$this->_ci->db->simple_query($query)) - { - $this->eprintflib->printMessage( - sprintf( - 'Granted permissions %s on sequence %s.%s to user %s', - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $sequence, - $user - ) - ); - } - else - { - $this->eprintflib->printError( - sprintf( - 'Granting permissions %s on sequence %s.%s to user %s', - is_null($stringPermission) ? $permissions : $stringPermission, - $schema, - $sequence, - $user - ) - ); - } } //------------------------------------------------------------------------------------------------------------------ @@ -1143,4 +1211,14 @@ class DBSkelLib { $this->_printMessage('--------------------------------------------------------------------------------------------'); } + + /** + * + */ + private function _printRunningMode() + { + if ($this->_isDryrunMode()) $this->_printInfo('>> DBSkel is running in dry run mode <<'); + elseif ($this->_isNewMode()) $this->_printInfo('>> DBSkel is running in new mode <<'); + elseif ($this->_isDiffMode()) $this->_printInfo('>> DBSkel is running in diff mode <<'); + } } From 6062579948dd2864926bb327fedca77cdbfccf42 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 6 Jun 2019 16:38:14 +0200 Subject: [PATCH 007/500] =?UTF-8?q?Ausbildungsvertrag=20for=20Lehrg=C3=A4n?= =?UTF-8?q?ge=20=C3=BCberarbeitet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/xsl/Ausbildungsver_Lehrgaenge.xsl | 96 +++++++++++++++--------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/system/xsl/Ausbildungsver_Lehrgaenge.xsl b/system/xsl/Ausbildungsver_Lehrgaenge.xsl index 616d90c1f..19108a7ba 100644 --- a/system/xsl/Ausbildungsver_Lehrgaenge.xsl +++ b/system/xsl/Ausbildungsver_Lehrgaenge.xsl @@ -433,7 +433,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" Adresse: ; Geburtsdatum: - (kurz „ao. Studentin“ bzw. „ao. Student“ genannt) andererseits, im Rahmen des Lehrgangs zur Weiterbildung nach §9 FHStG idgF + (kurz „ao. Studentin“ bzw. „ao. Student“ genannt) andererseits, im Rahmen des Lehrgangs zur Weiterbildung nach §9 FHStG idgF. @@ -442,7 +442,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" in der Organisationsform eines - + + Lehrgangs zur Weiterbildung. - Dieser Lehrgang wird von der Technikum Wien GmbH organisiert und gemeinsam mit der Fachhochschule Technikum Wien durchgeführt. Es gelten die AGB der Technikum Wien GmbH, diese sind unter https://academy.technikum-wien.at/agb jederzeit abrufbar. + Dieser Lehrgang wird in Kooperation mit der Technikum Wien GmbH organisiert und durchgeführt. Es gelten die AGB der Technikum Wien GmbH, diese sind unter https://academy.technikum-wien.at/agb jederzeit abrufbar. @@ -477,7 +478,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Die Ausbildung erfolgt auf der Grundlage des Fachhochschul-Studiengesetzes, BGBl. Nr. 340/1993 idgF und des Hochschul-Qualitätssicherungsgesetzes, BGBl. I Nr. 74/2011 idgF und der Satzung der Fachhochschule Technikum Wien idgF. + Die Ausbildung erfolgt auf Grundlage des Fachhochschul-Studiengesetzes, BGBI. Nr. 340/1993 idgF und des Hochschul-Qualitätssicherungsgesetzes, BGBI. Nr. 74/2011 idgF, des genehmigten Lehrgangantrags durch das Fachhoschul-Kollegium und der Satzung der Fachhoschule Technikum Wien idgF. @@ -488,7 +489,8 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Die Ausbildungsdauer beträgt Semester. + Die Ausbildungsdauer beträgt Semester. + In dieser Zeit sind von der Studierenden/dem Studierendem die Prüfungs- und Studienleistungen gemäß Studienordnung und Satzungsteil Studienrechtliche Bestimmungen/Prüfungsordnung zu erbringen. Die ao. Studentin bzw. der ao. Student hat das Recht, eine Anerkennung nachgewiesener Kenntnisse beim Lehrgang zu beantragen. Eine solche Anerkennung setzt voraus, dass die erworbenen Kenntnisse mit dem Inhalt und dem Umfang der Lehrveranstaltung gleichwertig sind und bewirkt die Anrechnung der entsprechenden Lehrveranstaltung. @@ -503,13 +505,13 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Nach Abschluss aller vorgeschriebenen Prüfungen wird der akademische Grad "" verliehen. + Nach positivem Abschluss aller vorgeschriebenen Prüfungen wird der Mastergrad "" verliehen. - Nach Abschluss aller vorgeschriebenen Prüfungen wird der Titel "" verliehen. + Nach positivem Abschluss aller vorgeschriebenen Prüfungen wird der Titel "" verliehen. - Nach Abschluss aller vorgeschriebenen Prüfungen wird ein Zertifizierungsdiplom der Technikum Wien Academy verliehen. + Nach positivem Abschluss aller vorgeschriebenen Prüfungen wird ein Zertifizierungsdiplom der Technikum Wien Academy verliehen. @@ -526,19 +528,18 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 5.1 Rechte Der Erhalter führt eine periodische Überprüfung des Studiums im Hinblick auf Relevanz und Aktualität durch und ist im Einvernehmen mit dem FH-Kollegium berechtigt, daraus Änderungen des Lehrgangs zur Weiterbildung abzuleiten. - Der Erhalter ist berechtigt, die Daten der/des ao. Studierenden an den FH Technikum Wien Alumni Club zu übermitteln. Der Alumni Club ist der AbsolventInnenverein der FH Technikum Wien. Er hat zum Ziel, AbsolventInnen, Studierende und Lehrende miteinander zu vernetzen sowie AbsolventInnen laufend über Aktivitäten an der FH Technikum Wien zu informieren. Einer Zusendung von Informationen durch den Alumni Club kann jederzeit widersprochen werden. - + 5.2 Pflichten Der Erhalter verpflichtet sich zur ordnungsgemäßen Planung und Durchführung des Lehrgangs. Der Erhalter ist verpflichtet, allfällige Änderungen des Lehrgangs zeitgerecht bekannt zu geben. - Der Erhalter verpflichtet sich, jedenfalls folgende Dokumente zur Verfügung zu stellen: Studierendenausweis, Diploma Supplement, Urkunde über die Verleihung des akademischen Grades, Studienerfolgsbestätigung, Inskriptionsbestätigung. + Der Erhalter verpflichtet sich, jedenfalls folgende Dokumente zur Verfügung zu stellen: Studierendenausweis, Studienerfolgsbestätigung und Inskriptionsbestätigung, sowie je nach absolviertem Lehrgang ein Zertifikat über den positiven Abschluss des Zertifikatslehrgangs bzw. einen Bescheid über die Verleihung des akademischen Grades inkl. Diploma Supplement. Der Erhalter verpflichtet sich zur sorgfaltsgemäßen Verwendung der personenbezogenen Daten der ao. Studierenden. Die Daten werden nur im Rahmen der gesetzlichen und vertraglichen Verpflichtungen sowie des Studienbetriebes verwendet und nicht an nicht berechtigte Dritte weitergegeben. @@ -555,32 +556,52 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 6.1 Rechte - Die ao. Studentin bzw. der ao. Student hat das Recht auf einen Studienbetrieb gemäß den im Lehrgang zur Weiterbildung idgf und in der Satzung der FH Technikum Wien idgF festgelegten Bedingungen. + Die ao. Studentin bzw. der ao. Student hat das Recht auf einen Studienbetrieb gemäß den im Lehrgang zur Weiterbildung idgF. und in der Satzung der FH Technikum Wien idgF. festgelegten Bedingungen. 6.2 Pflichten 6.2.1 Einhaltung studienrelevanter Bestimmungen - Die ao. Studentin bzw. der ao. Student ist verpflichtet, insbesondere folgende Bestimmungen einzuhalten: + Folgende Bestimmungen sind Bestandteil des Ausbildungsvertrags und von der ao. Studentin/dem ao. Studenten einzuhalten: - Studienordnung und Prüfungsordnung für Lehrgänge idgF + Studienordnung und studienrechtliche Bestimmungen/Prüfungsordnung für Lehrgänge idgF. - Hausordnung idgF + Hausordnung idgF. - Brandschutzordnung idgF + Brandschutzordnung idgF. - Bibliotheksordnung idgF + Bibliotheksordnung idgF. - Die für den jeweiligen Lehrgang geltende/n Laborordnung/en idgF + Die für den jeweiligen Lehrgang geltende/n Laborordnung/en idgF. - Diese Dokumente sind öffentlich zugänglich unter www.technikum-wien.at. + Diese Dokumente sind öffentlich zugänglich unter www.technikum-wien.at und nach Erhalt der Zugangsdaten auch im Intranet + abrufbar + + + + 1 + + + + + + https://www.technikum-wien.at/ueber-uns/satzung-und-leitbild-der-fh-technikum-wien/ oder CIS – Dokumente – Satzung + + + + + + + . + + Darüber hinaus sind die AGB der Technikum Wien GmbH Bestandteil dieses Vertrages (https://academy.technikum-wien.at/agb). @@ -590,20 +611,25 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" Gemäß § 4 Abs. 10 FHStG sind ao. Studierende an Fachhochschulen Mitglieder der Österreichischen HochschülerInnenschaft (ÖH). Der/Die ao. Studierende hat semesterweise einen ÖH-Beitrag an den Erhalter zu entrichten, der diesen an die ÖH abführt. Die Entrichtung des Betrags ist Voraussetzung für die Zulassung zum Studium bzw. für dessen Fortsetzung. - 6.2.3 Beibringung persönlicher Daten - Die ao. Studentin bzw. der ao. Student ist verpflichtet, persönliche Daten beizubringen, die auf Grund eines Gesetzes, einer Verordnung oder eines Bescheides vom Erhalter erfasst werden müssen oder zur Erfüllung des Ausbildungsvertrages bzw für den Studienbetrieb unerlässlich sind. - 6.2.4 Aktualisierung eigener Daten und Bezug von Informationen + 6.2.3 Beibringung und Aktualisierung von personenbezogenen Daten + Die ao. Studentin bzw. der ao. Student ist verpflichtet, personenbezogene Daten beizubringen, die auf Grund eines Gesetzes, einer Verordnung oder eines Bescheides vom Erhalter erfasst werden müssen oder zur Erfüllung des Ausbildungsvertrages bzw. für den Studienbetrieb unerlässlich sind. Die ao. Studentin bzw. der ao. Student hat unaufgefordert dafür zu sorgen, dass die von ihr/ihm beigebrachten Daten aktuell sind. Änderungen sind der Lehrgangsassistenz unverzüglich schriftlich mitzuteilen. Darüber hinaus trifft sie/ihn die Pflicht, sich von studienbezogenen Informationen, die ihr/ihm an die vom Erhalter zur Verfügung gestellte Emailadresse zugestellt werden, in geeigneter Weise Kenntnis zu verschaffen. + Es ist der ao. Studentin/dem ao. Studenten untersagt, die Daten des von der FH zur Verfügung gestellten Studierendenaccounts weiterzugeben. + 6.2.4 Bezug von Informationen durch die FH Gruppe + Der Erhalter ist berechtigt, die Daten der/des ao. Studierenden an den FH Technikum Wien Alumni Club zu übermitteln. Der Alumni Club ist der AbsolventInnenverein der FH Technikum Wien. Er hat zum Ziel, AbsolventInnen, Studierende und Lehrende miteinander zu vernetzen sowie AbsolventInnen laufend über Aktivitäten an der FH Technikum Wien zu informieren. Einer Zusendung von Informationen durch den Alumni Club kann jederzeit widersprochen werden. + Der/die ao. Studierende stimmt zu, dass ihm/ihr nach Studienende Informationen der FH Gruppe /FH Technikum Wien, Technikum Wien GmbH sowie Technikum Wien Alumni Club) zur Pflege der Kontakte zu den Absolventinnen und Absolventen per E-Mail zugestellt werden (§ 107 TKG 2003 idgF.) Ein Abbestellen dieser Informationen ist jederzeit möglich. 6.2.5 Verwertungsrechte Sofern nicht im Einzelfall andere Regelungen zwischen dem Erhalter und der ao. Studentin oder dem ao. Studenten getroffen wurden, ist die ao. Studentin oder der ao. Student verpflichtet, dem Erhalter die Rechte an Forschungs- und Entwicklungsergebnissen, die im Rahmen von geförderten Projekten geschaffen wurden, auf dessen schriftliche Anfrage hin einzuräumen. 6.2.6 Aufzeichnungen und Mitschnitte - Es ist der/dem ao. Studierenden ausdrücklich untersagt, Lehrveranstaltungen als Ganzes oder nur Teile davon aufzuzeichnen und/oder mitzuschneiden (z.B. durch Film- und/oder Tonaufnahmen oder sonstige hierfür geeignete audiovisuelle Mittel). Darüber hinaus ist jede Form der öffentlichen Zurverfügungstellung (drahtlos oder drahtgebunden) der vorgenannten Aufnahmen z.B. in sozialen Netzwerken wie Facebook, WhatsAPP, LinkedIn, Xing etc, aber auch auf Youtube, Instagram usw. oder durch sonstige für diese Zwecke geeignete Kommunikationsmittel untersagt. Diese Regelungen gelten sinngemäß auch für Skripten, sonstige Lernbehelfe und Prüfungsangaben. - Ausgenommen hiervon ist eine Aufzeichnung zu ausschließlichen Lern-, Studien- und Forschungszwecken und zum privaten Gebrauch, sofern hierfür der/die Vortragende vorab ausdrücklich seine/ihre schriftliche Zustimmung erteilt hat. + Es ist der/dem ao. Studierenden ausdrücklich untersagt, Lehrveranstaltungen als Ganzes oder nur Teile davon aufzuzeichnen und/oder mitzuschneiden (z.B. durch Film- und/oder Tonaufnahmen oder sonstige hierfür geeignete audiovisuelle Mittel) oder in Lehrveranstaltungen zu fotografieren. Darüber hinaus ist jede Form der öffentlichen Zurverfügungstellung (drahtlos und drahtgebunden) der vorgenannten Aufnahmen z.B. in sozialen Netzwerken wie Facebook, WhatsAPP, LinkedIn, Xing etc., aber auch Youtube, Instagram usw. oder durch sonstige für diese Zwecke geeignete Kommunikationsmittel untersagt. Diese Regelungen gelten sinngemäß auch für Skripten, sonstige Lernbehelfe und Prüfungsangaben. + Ausgenommen hiervon ist eine Aufzeichnung zu ausschließlichen Lern-, Studien- und Forschungszwecken und zum privaten Gebrauch, sofern hierfür der/die Vortragende und alle auf diesen Aufnahmen erkennbaren Personen vorab ausdrücklich seine/ihre schriftliche Zustimmung erteilt hat. 6.2.7 Geheimhaltungspflicht Die ao. Studentin bzw. der ao. Student ist zur Geheimhaltung von Forschungs- und Entwicklungsaktivitäten und -ergebnissen gegenüber Dritten verpflichtet. 6.2.8 Schadensmeldung Im Falle des Eintretens eines Schadens am Inventar der Fachhochschule ist der/die ao. Studierende verpflichtet, diesen unverzüglich, spätestens aber innerhalb von drei Tagen dem Lehrgangssekretariat zu melden. Allfällige Haftungsansprüche bleiben hiervon unberührt. - 6.2.9 Rückgabeverpflichtung bei Studienende + 6.2.9 Unfallmeldung + Im Falle eines Unfalles mit körperlicher Verletzung des/der Studierenden im Zusammenhang mit dem Studium ist die/der ao. Studierende verpflichtet, diesen innerhalb von drei Tagen dem Lehrgangssekretariat zu melden. Dies betrifft auch Wegunfälle zur oder von der FH. + 6.2.10 Rückgabeverpflichtung bei Studienende Die ao. Studentin bzw. der ao. Student ist verpflichtet, bei einer Beendigung des Lehrgangs unverzüglich alle zur Verfügung gestellten Gerätschaften, Bücher, Schlüssel und sonstige Materialien zurückzugeben. @@ -616,8 +642,8 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - 7.1 Auflösung im beiderseitigen Einvernehmen - Im beiderseitigen Einvernehmen ist die Auflösung des Ausbildungsvertrages jederzeit ohne Angabe von Gründen möglich. Die einvernehmliche Auflösung bedarf der Schriftform. + 7.1 Auflösung im beiderseitigem Einvernehmen + Im beiderseitigem Einvernehmen ist die Auflösung des Ausbildungsvertrages jederzeit ohne Angabe von Gründen möglich. Die einvernehmliche Auflösung bedarf der Schriftform. 7.2 Kündigung durch die ao. Studentin bzw. den ao. Studenten Die ao. Studentin bzw. der ao. Student kann den Ausbildungsvertrag schriftlich jeweils zum Ende eines Semesters kündigen. Die Verpflichtung zur vollständigen Leistung der Lehrgangskosten wird von einer Kündigung durch die ao. Studentin bzw. den ao. Studenten nicht berührt. @@ -643,9 +669,6 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" persönlichem Verhalten, das zu einer Beeinträchtigung des Images und/oder Betriebes des Lehrgangs, der Fachhochschule bzw. des Erhalters oder von Personen führt, die für die Fachhochschule bzw. den Erhalter tätig sind; - - Weigerung zur Beibringung von Daten (siehe Pkt. 6.2.3); - Verletzung der Verpflichtung, dem Erhalter die Rechte an Forschungs- und Entwicklungsergebnissen einzuräumen (siehe Pkt. 6.2.5); @@ -658,6 +681,9 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" Nichterfüllung finanzieller Verpflichtungen trotz Mahnung; + + Weigerung zur Beibringung von Daten (siehe Pkt. 6.2.3) + Plagiieren im Rahmen wissenschaftlicher Arbeiten. @@ -679,7 +705,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Ao. Studierende des Programms sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehrelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet) trägt der ao. Student bzw. die ao. Studentin. + Ao. Studierende des Lehrgangs sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehreelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet und E-Mail) trägt der ao. Student bzw. die ao. Studentin. @@ -704,8 +730,8 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Die Ausfertigung dieses Vertrages erfolgt in zweifacher Ausführung. Ein Original verbleibt im zuständigen Administrationsbüro des Lehrgangs. Eine Ausfertigung wird der ao. Studentin bzw. dem ao. Studenten übergeben. - Für Streitigkeiten aus diesem Vertrag gilt österreichisches Recht als vereinbart, allfällige Klagen sind beim sachlich zuständigen Gericht in Wien einzubringen. + Die Ausfertigung dieses Vertrages erfolgt in zweifacher Ausführung. In Original verbleibt im zuständigen Administrationsbüro des Fachhochschul-Lehrgangs. Eine Ausfertigung wird der ao. Studentin bzw. dem ao. Studenten übergeben. + Für Streitigkeiten aus diesem Vertrag gilt österreichisches Recht vereinbart, allfällige Klagen gegen den Erhalter sind, sofern gesetzlich zulässig, beim sachlich zuständigen Gericht in Wien einzubringen. Der Ausbildungsvertrag ist gebührenfrei. From e55247487ad5cb0763c0c26b9a6e11b95d85199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Tue, 11 Jun 2019 07:56:35 +0200 Subject: [PATCH 008/500] =?UTF-8?q?Suche=20nach=20Lehrveranstaltungen=20im?= =?UTF-8?q?=20FAS=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/fasoverlay.js.php | 50 +++++++++++++++++++ .../lehrveranstaltungoverlay.xul.php | 2 + rdf/lehrveranstaltung_einheiten.rdf.php | 31 ++++++++++++ 3 files changed, 83 insertions(+) diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php index 0c80221e9..d5da31104 100644 --- a/content/fasoverlay.js.php +++ b/content/fasoverlay.js.php @@ -503,6 +503,56 @@ function onVerbandSelect(event) } } +// **** +// * Wenn im Suchfeld Enter gedrueckt wird, dann die Suchfunktion starten +// **** +function LehrveranstaltungSearchFieldKeyPress(event) +{ + if(event.keyCode==13) //Enter + LehrveranstaltungSuche(); +} + +function LehrveranstaltungSuche() +{ + var filter = document.getElementById("lehrveranstaltung-toolbar-textbox-suche").value; + // Lehrveranstaltung + document.getElementById('statusbar-progressmeter').setAttribute('mode','undetermined'); + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + try + { + url = 'rdf/lehrveranstaltung_einheiten.rdf.php?filter='+filter+'&'+gettimestamp(); + var treeLV=document.getElementById('lehrveranstaltung-tree'); + + try + { + LvTreeDatasource.removeXMLSinkObserver(LvTreeSinkObserver); + treeLV.builder.removeListener(LvTreeListener); + } + catch(e) + {} + + //Alte DS entfernen + var oldDatasources = treeLV.database.GetDataSources(); + while(oldDatasources.hasMoreElements()) + { + treeLV.database.RemoveDataSource(oldDatasources.getNext()); + } + + var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService); + LvTreeDatasource = rdfService.GetDataSource(url); + LvTreeDatasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource); + LvTreeDatasource.QueryInterface(Components.interfaces.nsIRDFXMLSink); + treeLV.database.AddDataSource(LvTreeDatasource); + LvTreeDatasource.addXMLSinkObserver(LvTreeSinkObserver); + treeLV.builder.addListener(LvTreeListener); + document.getElementById('lehrveranstaltung-toolbar-lehrauftrag').hidden=true; + } + catch(e) + { + debug(e); + } +} + function onFachbereichSelect(event) { var tree=document.getElementById('tree-fachbereich'); diff --git a/content/lvplanung/lehrveranstaltungoverlay.xul.php b/content/lvplanung/lehrveranstaltungoverlay.xul.php index 628f80747..a43b5ca33 100644 --- a/content/lvplanung/lehrveranstaltungoverlay.xul.php +++ b/content/lvplanung/lehrveranstaltungoverlay.xul.php @@ -79,6 +79,8 @@ echo ' + + '; From e4b66935af26aae30008642849bc29455767c57c Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 25 Jun 2019 11:20:50 +0200 Subject: [PATCH 023/500] bewerbung_abgeschicktamum auskommentiert Leider gibt es bestaetigte Bewerbungen, die nie abgeschickt wurden --- vilesci/stammdaten/auswertung_fhtw.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vilesci/stammdaten/auswertung_fhtw.php b/vilesci/stammdaten/auswertung_fhtw.php index a817614c3..685473499 100644 --- a/vilesci/stammdaten/auswertung_fhtw.php +++ b/vilesci/stammdaten/auswertung_fhtw.php @@ -1348,7 +1348,7 @@ if (isset($_REQUEST['reihungstest'])) ORDER BY start ASC LIMIT 1 ) ) - AND bewerbung_abgeschicktamum IS NOT NULL + /*AND bewerbung_abgeschicktamum IS NOT NULL*/ /* Leider gibt es bestaetigte Bewerbungen, die nie abgeschickt wurden */ AND bestaetigtam IS NOT NULL AND tbl_gebiet.gebiet_id != 7 "; From 8a07fe69a485af8048fbdea60814ac5ddbd8f606 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 25 Jun 2019 11:21:20 +0200 Subject: [PATCH 024/500] =?UTF-8?q?Vorlagen=20f=C3=BCr=20Diploma=20Supplem?= =?UTF-8?q?ent=20Debug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/vorlage_zip/DiplSupplementDebug.odt | Bin 0 -> 600675 bytes system/xsl/diplomaSuppDebug.xsl | 2948 ++++++++++++++++++++ 2 files changed, 2948 insertions(+) create mode 100644 system/vorlage_zip/DiplSupplementDebug.odt create mode 100644 system/xsl/diplomaSuppDebug.xsl diff --git a/system/vorlage_zip/DiplSupplementDebug.odt b/system/vorlage_zip/DiplSupplementDebug.odt new file mode 100644 index 0000000000000000000000000000000000000000..aaee7c600a4dfe4384ab102c5f881153548a8535 GIT binary patch literal 600675 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

  • {w=HS`1mgiB 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
  • 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≷49R+;6-YUhxLRg?mwzS?uQ$G_vQ?{{4Q)C?ke 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 literal 0 HcmV?d00001 diff --git a/system/xsl/diplomaSuppDebug.xsl b/system/xsl/diplomaSuppDebug.xsl new file mode 100644 index 000000000..6d3feaf42 --- /dev/null +++ b/system/xsl/diplomaSuppDebug.xsl @@ -0,0 +1,2948 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ANHANG ZUM DIPLOM + DIPLOMA SUPPLEMENT + + + + + + -Studiengang + + + + + + + + ’s degree program + + + + + + + Verliehener Titel ist nicht gesetzt + Regelstudiendauer wurde nicht gefunden + ECTS wurden nicht gefunden + Kein Sponsionsdatum gesetzt + Keine Studiengangsleitung eingetragen + Datum der Abschlussprüfung ist nicht gesetzt + Abschlussbeurteilung ist nicht gesetzt + + + + + + + + + + TRANSCRIPT OF RECORDS + + Semester - + + ’s degree program + + + Student ID: + Program Code: + + + First Name/Last Name: + + Date of Birth: + + Within the period of studies at the University of Applied Sciences Technikum Wien from to in the ’s degree program examinations in the following subjects were passed: + + + + + + + + + + + Date + + + Course + + + Type1 + + + SP/W2 + + + ECTS credits + + + Grade³ + + + + + + Total + + + + - + + + + + - + + + + + - + + + + + + + + - + + + + + + ¹ Type: Laboratory (LAB), Lecture (VO), Integrated Course (ILV), Seminar (SE), Tutorial (TUT), Project (PRJ), Exercise (UE), Distance Learning (FL), Other (SO) + ² 1 Semester period per week = 45 minutes + ³ Grading Scheme: excellent (1), good (2), satisfactory (3), sufficient (4), Credit based on previous experience/work (ar), successfully completed (ea), Participated with success (met), participated (tg) + + + + + + + + + Final Examination + + + + + + 's Examination on + + + + + + + + Grading Scheme: Passed with distinction, Passed with merit, Passed + + + + + + + + + + + + + + + Vienna, + Place, Date + + + + + + Program Director + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Σ + + + + + - + + + + + - + + + + + - + + + + + + + + + + - + + + + + + + + + + + + + + + + ID: + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cd54b90b31714ba6e52b69bf7ff8a3a2a4bd87fb Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 25 Jun 2019 11:24:58 +0200 Subject: [PATCH 025/500] Spalte stufe in function getStudiengaengeDokument --- include/dokument.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/dokument.class.php b/include/dokument.class.php index ac0108f4b..164c9e54f 100644 --- a/include/dokument.class.php +++ b/include/dokument.class.php @@ -845,7 +845,8 @@ class dokument extends basis_db */ public function getStudiengaengeDokument($dokument_kurzbz, $person_id = null) { - $qry = " SELECT DISTINCT studiengang_kz,typ||kurzbz AS kuerzel, bezeichnung, english FROM public.tbl_dokumentstudiengang + $qry = " SELECT DISTINCT studiengang_kz,typ||kurzbz AS kuerzel, bezeichnung, english , stufe + FROM public.tbl_dokumentstudiengang JOIN public.tbl_prestudent USING (studiengang_kz) JOIN public.tbl_prestudentstatus USING (prestudent_id) JOIN public.tbl_studiengang USING (studiengang_kz) @@ -866,6 +867,7 @@ class dokument extends basis_db $stg_obj->kuerzel = $row->kuerzel; $stg_obj->bezeichnung = $row->bezeichnung; $stg_obj->studiengang_kz = $row->studiengang_kz; + $stg_obj->stufe = $row->stufe; $this->result[] = $stg_obj; } From 19def99066ce2c0f47deb83d68fa85d1e9468b22 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 25 Jun 2019 16:50:16 +0200 Subject: [PATCH 026/500] Changed CIS 'Allgemeiner Downloadlink'-URL from CIS to Moodle --- cms/news.php | 2 +- system/templates/news_xslt_xhtml.xslt | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cms/news.php b/cms/news.php index 1f5d4a931..420243793 100644 --- a/cms/news.php +++ b/cms/news.php @@ -438,9 +438,9 @@ function getStgContent($studiengang_kz, $semester, $sprache) $xml.=' t('global/lehrziele').']]> t('global/allgemeinerdownload').']]> - t('global/newsgroups').']]> kuerzel).']]> kurzbzlang).']]> + '; } diff --git a/system/templates/news_xslt_xhtml.xslt b/system/templates/news_xslt_xhtml.xslt index 577cc61b7..25a58b9f5 100644 --- a/system/templates/news_xslt_xhtml.xslt +++ b/system/templates/news_xslt_xhtml.xslt @@ -162,11 +162,10 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - + From c70b69b94e2b07f2336a9a9b7c128b7ea83ae434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Wed, 26 Jun 2019 08:19:49 +0200 Subject: [PATCH 027/500] Course Search in FAS is now case insensitive and supports umlauts --- content/fasoverlay.js.php | 2 +- rdf/lehrveranstaltung_einheiten.rdf.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php index d5da31104..29ec12d4f 100644 --- a/content/fasoverlay.js.php +++ b/content/fasoverlay.js.php @@ -520,7 +520,7 @@ function LehrveranstaltungSuche() netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); try { - url = 'rdf/lehrveranstaltung_einheiten.rdf.php?filter='+filter+'&'+gettimestamp(); + url = 'rdf/lehrveranstaltung_einheiten.rdf.php?filter='+encodeURIComponent(filter)+'&'+gettimestamp(); var treeLV=document.getElementById('lehrveranstaltung-tree'); try diff --git a/rdf/lehrveranstaltung_einheiten.rdf.php b/rdf/lehrveranstaltung_einheiten.rdf.php index d1238f16f..ff672dc8f 100644 --- a/rdf/lehrveranstaltung_einheiten.rdf.php +++ b/rdf/lehrveranstaltung_einheiten.rdf.php @@ -176,7 +176,7 @@ elseif($filter != '') $additionalfilter.= " OR lehrveranstaltung_id=".$db->db_add_param($filter)." OR lehreinheit_id=".$db->db_add_param($filter); } - + $qry = " SELECT distinct on(lehrveranstaltung_id) @@ -192,8 +192,8 @@ elseif($filter != '') WHERE studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND - (lv_bezeichnung like '%".$db->db_escape($filter)."%' - OR lv_bezeichnung_english like '%".$db->db_escape($filter)."%' + (lower(lv_bezeichnung) like '%".$db->db_escape(mb_strtolower($filter))."%' + OR lower(lv_bezeichnung_english) like '%".$db->db_escape(mb_strtolower($filter))."%' $additionalfilter ) "; From 0c9225925b8465ab7e3af796382e752fdb35f2e3 Mon Sep 17 00:00:00 2001 From: Cris Date: Thu, 27 Jun 2019 09:31:50 +0200 Subject: [PATCH 028/500] Removed 'Lehrziele'-link --- cms/news.php | 1 - system/templates/news_xslt_xhtml.xslt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cms/news.php b/cms/news.php index 420243793..2686b19aa 100644 --- a/cms/news.php +++ b/cms/news.php @@ -436,7 +436,6 @@ function getStgContent($studiengang_kz, $semester, $sprache) if(CIS_EXT_MENU) { $xml.=' - t('global/lehrziele').']]> t('global/allgemeinerdownload').']]> kuerzel).']]> kurzbzlang).']]> diff --git a/system/templates/news_xslt_xhtml.xslt b/system/templates/news_xslt_xhtml.xslt index 25a58b9f5..04c6845f0 100644 --- a/system/templates/news_xslt_xhtml.xslt +++ b/system/templates/news_xslt_xhtml.xslt @@ -163,8 +163,7 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - From f204b7448e46bb11923a23033decd099c95df203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 27 Jun 2019 17:49:43 +0200 Subject: [PATCH 029/500] Dont display Courses withour Grades on Transcript --- system/xsl/ZeugnisEng_0.xsl | 2 +- system/xsl/ZeugnisEng_Lehrgaenge.xsl | 2 +- system/xsl/Zeugnis_0.xsl | 2 +- system/xsl/Zeugnis_Lehrgaenge.xsl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/system/xsl/ZeugnisEng_0.xsl b/system/xsl/ZeugnisEng_0.xsl index 3a6f8b866..2d0e6266a 100644 --- a/system/xsl/ZeugnisEng_0.xsl +++ b/system/xsl/ZeugnisEng_0.xsl @@ -530,7 +530,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - + diff --git a/system/xsl/ZeugnisEng_Lehrgaenge.xsl b/system/xsl/ZeugnisEng_Lehrgaenge.xsl index 82f6d3330..da226877f 100644 --- a/system/xsl/ZeugnisEng_Lehrgaenge.xsl +++ b/system/xsl/ZeugnisEng_Lehrgaenge.xsl @@ -519,7 +519,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - + diff --git a/system/xsl/Zeugnis_0.xsl b/system/xsl/Zeugnis_0.xsl index c11a385bb..8fe4a3c43 100644 --- a/system/xsl/Zeugnis_0.xsl +++ b/system/xsl/Zeugnis_0.xsl @@ -505,7 +505,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - + diff --git a/system/xsl/Zeugnis_Lehrgaenge.xsl b/system/xsl/Zeugnis_Lehrgaenge.xsl index 95b40f733..a8fae63ca 100644 --- a/system/xsl/Zeugnis_Lehrgaenge.xsl +++ b/system/xsl/Zeugnis_Lehrgaenge.xsl @@ -504,7 +504,7 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - + From e0b5f0ba8e62982171ba0657e89153c136a6c6ed Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 28 Jun 2019 13:23:00 +0200 Subject: [PATCH 030/500] - Only assistance who created the reservation or for whom is reserved can delete reservierungen - logging every time a reservation is deleted --- cis/private/lvplan/stpl_week.php | 2 +- content/lvplanung/timetable-week.xul.php | 24 ------------------------ include/reservierung.class.php | 17 +++++++++++++++++ include/wochenplan.class.php | 2 +- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/cis/private/lvplan/stpl_week.php b/cis/private/lvplan/stpl_week.php index 56b06f292..edc50e8c2 100644 --- a/cis/private/lvplan/stpl_week.php +++ b/cis/private/lvplan/stpl_week.php @@ -368,7 +368,7 @@ if (isset($reservtodelete)) { if ($reservierung->load($delete_id)) { - if ($reservberechtigt || $reservierung->uid==$uid || $reservierung->insertvon==$uid) + if ($reservberechtigt && ($reservierung->insertvon==$uid || $reservierung->uid==$uid)) { if($reservierung->delete($delete_id)) $reservdelcount++; diff --git a/content/lvplanung/timetable-week.xul.php b/content/lvplanung/timetable-week.xul.php index 32042e9e8..18eaf6076 100644 --- a/content/lvplanung/timetable-week.xul.php +++ b/content/lvplanung/timetable-week.xul.php @@ -384,18 +384,6 @@ elseif ($aktion=='stpl_delete_single' || $aktion=='stpl_delete_block') $logdata = var_export($logdata_reservierung, true); $reservierung->delete($reservierung_id); $error_msg.=$reservierung->errormsg; - // Logeintrag zum mitloggen von geloeschten Reservierungen - if($error_msg=='') - { - $log = new log(); - $log->executetime = date('Y-m-d H:i:s'); - $log->sqlundo = ''; - $log->sql = 'DELETE FROM campus.tbl_reservierung WHERE reservierung_id='.$reservierung_id.'; LogData:'.$logdata; - $log->beschreibung = 'Löschen der Reservierung '.$reservierung_id; - $log->mitarbeiter_uid = $uid; - if(!$log->save(true)) - $error_msg.='Fehler: '.$log->errormsg; - } } } @@ -410,18 +398,6 @@ elseif ($aktion=='stpl_delete_single' || $aktion=='stpl_delete_block') $logdata = var_export($logdata_reservierung, true); $reservierung->delete($reservierung_id); $error_msg.=$reservierung->errormsg; - // Logeintrag zum mitloggen von geloeschten Reservierungen - if($error_msg=='') - { - $log = new log(); - $log->executetime = date('Y-m-d H:i:s'); - $log->sqlundo = ''; - $log->sql = 'DELETE FROM campus.tbl_reservierung WHERE reservierung_id='.$reservierung_id.'; LogData:'.$logdata; - $log->beschreibung = 'Löschen der Reservierung '.$reservierung_id; - $log->mitarbeiter_uid = $uid; - if(!$log->save(true)) - $error_msg.='Fehler: '.$log->errormsg; - } } } } diff --git a/include/reservierung.class.php b/include/reservierung.class.php index 2edac6844..da5ccdb12 100644 --- a/include/reservierung.class.php +++ b/include/reservierung.class.php @@ -21,6 +21,7 @@ */ require_once(dirname(__FILE__).'/basis_db.class.php'); require_once(dirname(__FILE__).'/datum.class.php'); +require_once(dirname(__FILE__).'/log.class.php'); class reservierung extends basis_db { @@ -242,7 +243,23 @@ class reservierung extends basis_db $qry = "DELETE FROM campus.tbl_reservierung WHERE reservierung_id=".$this->db_add_param($reservierung_id, FHC_INTEGER); if($this->db_query($qry)) + { + $reservierung = new reservierung($reservierung_id); + $logdata_reservierung = (array)$reservierung; + $logdata = var_export($logdata_reservierung, true); + $log = new log(); + $log->executetime = date('Y-m-d H:i:s'); + $log->sqlundo = ''; + $log->sql = 'DELETE FROM campus.tbl_reservierung WHERE reservierung_id='.$reservierung_id.'; LogData:'.$logdata; + $log->beschreibung = 'Löschen der Reservierung '.$reservierung_id; + $log->mitarbeiter_uid = $this->uid; + if(!$log->save(true)) + { + $this->errormsg = 'Fehler: '.$log->errormsg; + return false; + } return true; + } else { $this->errormsg = 'Fehler beim Loeschen der Reservierung'; diff --git a/include/wochenplan.class.php b/include/wochenplan.class.php index 5b4e47894..9af13b8ab 100644 --- a/include/wochenplan.class.php +++ b/include/wochenplan.class.php @@ -2754,7 +2754,7 @@ class wochenplan extends basis_db { while ($row = $this->db_fetch_object($result)) { - if ($reservberechtigt || $row->uid == $user_uid || $row->insertvon == $user_uid) + if ($reservberechtigt && ($row->uid == $user_uid || $row->insertvon == $user_uid)) { $deleteberechtigt = true; $reservtodelete[] = $row->reservierung_id; From fff467536fcbe8e3258112e3dedbfa89f525455b Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 28 Jun 2019 13:38:10 +0200 Subject: [PATCH 031/500] - correct mitarbeiter uid when deleting reservierung - reservierung data saved correctly --- include/reservierung.class.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/reservierung.class.php b/include/reservierung.class.php index da5ccdb12..b3c8221e0 100644 --- a/include/reservierung.class.php +++ b/include/reservierung.class.php @@ -22,6 +22,7 @@ require_once(dirname(__FILE__).'/basis_db.class.php'); require_once(dirname(__FILE__).'/datum.class.php'); require_once(dirname(__FILE__).'/log.class.php'); +require_once(dirname(__FILE__).'/authentication.class.php'); class reservierung extends basis_db { @@ -239,12 +240,12 @@ class reservierung extends basis_db $this->errormsg = 'Reservierung_id muss eine gueltige Zahl sein'; return false; } - + + $reservierung = new reservierung($reservierung_id); $qry = "DELETE FROM campus.tbl_reservierung WHERE reservierung_id=".$this->db_add_param($reservierung_id, FHC_INTEGER); - + if($this->db_query($qry)) { - $reservierung = new reservierung($reservierung_id); $logdata_reservierung = (array)$reservierung; $logdata = var_export($logdata_reservierung, true); $log = new log(); @@ -252,7 +253,9 @@ class reservierung extends basis_db $log->sqlundo = ''; $log->sql = 'DELETE FROM campus.tbl_reservierung WHERE reservierung_id='.$reservierung_id.'; LogData:'.$logdata; $log->beschreibung = 'Löschen der Reservierung '.$reservierung_id; - $log->mitarbeiter_uid = $this->uid; + $auth = new authentication(); + $uid = $auth->getUser(); + $log->mitarbeiter_uid = $uid; if(!$log->save(true)) { $this->errormsg = 'Fehler: '.$log->errormsg; From 162b935b8cf413a028d114ec2811c828daedf454 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 15:49:45 +0200 Subject: [PATCH 032/500] Bugfix RT-Auswertung --- include/reihungstest.class.php | 9 ++ vilesci/stammdaten/auswertung_fhtw.php | 137 +++++++++++++------------ 2 files changed, 79 insertions(+), 67 deletions(-) diff --git a/include/reihungstest.class.php b/include/reihungstest.class.php index 38e4d328f..f5cd72b4a 100644 --- a/include/reihungstest.class.php +++ b/include/reihungstest.class.php @@ -53,6 +53,15 @@ class reihungstest extends basis_db public $anmeldefrist; //date public $aufnahmegruppe_kurzbz; // varchar(32) + public $rt_person_id; // integer + public $rt_id; // integer + public $person_id; // integer + public $studienplan_id; // integer + public $anmeldedatum; // date + public $teilgenommen; // boolean + public $punkte; // numeric + + /** * Konstruktor * @param int $reihungstest_id ID der Adresse die geladen werden soll (Default=null). diff --git a/vilesci/stammdaten/auswertung_fhtw.php b/vilesci/stammdaten/auswertung_fhtw.php index 685473499..939093ecf 100644 --- a/vilesci/stammdaten/auswertung_fhtw.php +++ b/vilesci/stammdaten/auswertung_fhtw.php @@ -732,6 +732,7 @@ if ($punkteUebertragen) $msg_error .= '
    Sie haben keine Rechte, um für diesen Studiengang Ergebnisse ins FAS zu übertragen'; continue; } + // Checken, ob Person-Reihungstest-Studienplan zuteilung existiert if ($reihungstest->checkPersonRtStudienplanExists($prestudentrolle->person_id, $_POST['reihungstest_id'], $prestudentrolle->studienplan_id)) { @@ -763,12 +764,16 @@ if ($punkteUebertragen) else { $setRTPunkte = new reihungstest(); - $setRTPunkte->getPersonReihungstest($prestudentrolle->person_id, $_POST['reihungstest_id']); + $setRTPunkte->getPersonReihungstest($prestudentrolle->person_id, $_POST['reihungstest_id'], $prestudentrolle->studienplan_id); // Check, ob Punkte schon befüllt sind if ($setRTPunkte->punkte == '') { $setRTPunkte->new = true; + $setRTPunkte->person_id = $prestudentrolle->person_id; + $setRTPunkte->reihungstest_id = $_POST['reihungstest_id']; + $setRTPunkte->anmeldedatum = ''; + $setRTPunkte->ort_kurzbz = ''; $setRTPunkte->studienplan_id = $prestudentrolle->studienplan_id; $setRTPunkte->punkte = number_format($array['ergebnis'], 4); $setRTPunkte->insertamum = date('Y-m-d H:i:s'); @@ -2364,6 +2369,7 @@ else error: function(data) { $("#msgbox").attr("class","alert alert-danger"); + $(".loaderIcon").hide(); $("#msgbox").show(); $("#msgbox").html(data["msg"]); } @@ -2451,83 +2457,80 @@ else } else { - //if (confirm("Setzt bei allen markierten Personen \'Zum Reihungstest angetreten\' und informiert die entsprechende Studiengangsassistenz. Wollen Sie fortfahren?")) + $("input.prestudentCheckbox:checked").each(function() { - $("input.prestudentCheckbox:checked").each(function() + if ($("#uebertragenOptionPhysik:checked").length === 1) { - if ($("#uebertragenOptionPhysik:checked").length === 1) - { - prestudentPunkteArr.push({ - prestudent_id: $(this).attr("name"), - ergebnis: $(this).parents("tr").find(".erg_gesamt_mit_physik").text() - }); - } - else - { - prestudentPunkteArr.push({ - prestudent_id: $(this).attr("name"), - ergebnis: $(this).parents("tr").find(".erg_gesamt_ohne_physik").text() - }); - } - }); - - $(".loaderIcon").show(); - if ($("#uebertragenOptionGesamtpunkte:checked").length === 1) - { - gesamtpunkteSetzen = true; + prestudentPunkteArr.push({ + prestudent_id: $(this).attr("name"), + ergebnis: $(this).parents("tr").find(".erg_gesamt_mit_physik").text() + }); } - if ($("#uebertragenOptionBewerber:checked").length === 1) + else { - zuBewerberMachen = true; + prestudentPunkteArr.push({ + prestudent_id: $(this).attr("name"), + ergebnis: $(this).parents("tr").find(".erg_gesamt_ohne_physik").text() + }); } - - data = { - reihungstest_id: reihungstest, - prestudentPunkteArr: prestudentPunkteArr, - gesamtpunkteSetzen: gesamtpunkteSetzen, - zuBewerberMachen: zuBewerberMachen, - punkteUebertragen: true - }; + }); + + $(".loaderIcon").show(); + if ($("#uebertragenOptionGesamtpunkte:checked").length === 1) + { + gesamtpunkteSetzen = true; + } + if ($("#uebertragenOptionBewerber:checked").length === 1) + { + zuBewerberMachen = true; + } + + data = { + reihungstest_id: reihungstest, + prestudentPunkteArr: prestudentPunkteArr, + gesamtpunkteSetzen: gesamtpunkteSetzen, + zuBewerberMachen: zuBewerberMachen, + punkteUebertragen: true + }; - $.ajax({ - url: "auswertung_fhtw.php", - data: data, - type: "POST", - dataType: "json", - success: function(data) + $.ajax({ + url: "auswertung_fhtw.php", + data: data, + type: "POST", + dataType: "json", + success: function(data) + { + $("#msgbox").html(""); + if(data["msg_success"] !== "") { - $("#msgbox").html(""); - if(data["msg_success"] !== "") - { - $("#msgbox").attr("class","alert alert-success"); - $(".loaderIcon").hide(); - $("#msgbox").show(); - $("#msgbox").append(data["msg_success"]); - } - if(data["msg_warning"] !== "") - { - $("#msgbox").attr("class","alert alert-warning"); - $(".loaderIcon").hide(); - $("#msgbox").show(); - $("#msgbox").append(data["msg_warning"]); - //$("#msgbox").html(data["msg"]).delay(2000).fadeOut(); - } - if(data["msg_error"] !== "") - { - $("#msgbox").attr("class","alert alert-danger"); - $(".loaderIcon").hide(); - $("#msgbox").show(); - $("#msgbox").append(data["msg_error"]); - } - }, - error: function(data) + $("#msgbox").attr("class","alert alert-success"); + $(".loaderIcon").hide(); + $("#msgbox").show(); + $("#msgbox").append(data["msg_success"]); + } + if(data["msg_warning"] !== "") + { + $("#msgbox").attr("class","alert alert-warning"); + $(".loaderIcon").hide(); + $("#msgbox").show(); + $("#msgbox").append(data["msg_warning"]); + //$("#msgbox").html(data["msg"]).delay(2000).fadeOut(); + } + if(data["msg_error"] !== "") { $("#msgbox").attr("class","alert alert-danger"); + $(".loaderIcon").hide(); $("#msgbox").show(); - $("#msgbox").html(data["msg"]); + $("#msgbox").append(data["msg_error"]); } - }); - } + }, + error: function(data) + { + $("#msgbox").attr("class","alert alert-danger"); + $("#msgbox").show(); + $("#msgbox").html(data["msg"]); + } + }); } } From 45947dfca2d5d376485ed50bd9b2ef71fc47e9b1 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 15:54:36 +0200 Subject: [PATCH 033/500] Added DiplomasupplementDebug Shows just Table of Records with Course ID --- system/xsl/diplomaSuppDebug.xsl | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/xsl/diplomaSuppDebug.xsl b/system/xsl/diplomaSuppDebug.xsl index 6d3feaf42..807c0873c 100644 --- a/system/xsl/diplomaSuppDebug.xsl +++ b/system/xsl/diplomaSuppDebug.xsl @@ -2908,7 +2908,6 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn
    - @@ -2941,7 +2940,6 @@ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn - From b27ed8abd0e5f525bdfd574887efea016e941ec4 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 15:55:01 +0200 Subject: [PATCH 034/500] Uncomment check for Levelgleichverteilung --- include/gebiet.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gebiet.class.php b/include/gebiet.class.php index d421a9d4c..98a2535a9 100644 --- a/include/gebiet.class.php +++ b/include/gebiet.class.php @@ -372,7 +372,7 @@ class gebiet extends basis_db { if($row->anzahl>$this->maxfragen) { - $this->errormsg .= "Wenn Levelgleichverteilung gesetzt ist, muss maxfragen groesser als die Anzahl der verwendeten Levels sein\n"; + //$this->errormsg .= "Wenn Levelgleichverteilung gesetzt ist, muss maxfragen groesser als die Anzahl der verwendeten Levels sein\n"; } } } From 6fca967be057ebb4ed42c3cef94857ad82f4993a Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 15:55:27 +0200 Subject: [PATCH 035/500] =?UTF-8?q?Vorlage=20Best=C3=A4tigung=20der=20Lehr?= =?UTF-8?q?t=C3=A4tigkeit=20gegendert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/xsl/lehrtaetigkeit_0.xsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/xsl/lehrtaetigkeit_0.xsl b/system/xsl/lehrtaetigkeit_0.xsl index 69eb20b21..8a8807425 100644 --- a/system/xsl/lehrtaetigkeit_0.xsl +++ b/system/xsl/lehrtaetigkeit_0.xsl @@ -166,8 +166,8 @@ seit - für die FH Technikum Wien als Hochschullehrer tätig ist. - Seine Tätigkeit umfasst die Konzeption, Organisation und Abhaltung von Lehrveranstaltungen. + für die FH Technikum Wien als HochschullektorIn tätig ist. + Die Tätigkeit umfasst die Konzeption, Organisation und Abhaltung von Lehrveranstaltungen. From d333555d06ce7ffc13f51f55c3e9920c2ce21350 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 15:58:18 +0200 Subject: [PATCH 036/500] Added Stufe to Function getStudiengaengeDokument --- include/dokument.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dokument.class.php b/include/dokument.class.php index 164c9e54f..7585bc38b 100644 --- a/include/dokument.class.php +++ b/include/dokument.class.php @@ -845,7 +845,7 @@ class dokument extends basis_db */ public function getStudiengaengeDokument($dokument_kurzbz, $person_id = null) { - $qry = " SELECT DISTINCT studiengang_kz,typ||kurzbz AS kuerzel, bezeichnung, english , stufe + $qry = " SELECT DISTINCT studiengang_kz,typ||kurzbz AS kuerzel, bezeichnung, english, stufe FROM public.tbl_dokumentstudiengang JOIN public.tbl_prestudent USING (studiengang_kz) JOIN public.tbl_prestudentstatus USING (prestudent_id) From 93ecdaaf0bc3ef089be219defb21e38c4ac49e28 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 28 Jun 2019 16:23:14 +0200 Subject: [PATCH 037/500] =?UTF-8?q?Erg=C3=A4nzung=20BugFix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vilesci/stammdaten/auswertung_fhtw.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vilesci/stammdaten/auswertung_fhtw.php b/vilesci/stammdaten/auswertung_fhtw.php index 939093ecf..4bae503ca 100644 --- a/vilesci/stammdaten/auswertung_fhtw.php +++ b/vilesci/stammdaten/auswertung_fhtw.php @@ -743,7 +743,7 @@ if ($punkteUebertragen) if ($setRTPunkte->punkte == '') { $setRTPunkte->new = false; - $setRTPunkte->punkte = number_format($array['ergebnis'], 4); + $setRTPunkte->punkte = number_format(floatval($array['ergebnis']), 4); $setRTPunkte->updateamum = date('Y-m-d H:i:s'); $setRTPunkte->updatevon = $user; @@ -775,7 +775,7 @@ if ($punkteUebertragen) $setRTPunkte->anmeldedatum = ''; $setRTPunkte->ort_kurzbz = ''; $setRTPunkte->studienplan_id = $prestudentrolle->studienplan_id; - $setRTPunkte->punkte = number_format($array['ergebnis'], 4); + $setRTPunkte->punkte = number_format(floatval($array['ergebnis']), 4); $setRTPunkte->insertamum = date('Y-m-d H:i:s'); $setRTPunkte->insertvon = $user; From 7886cfc9e39e07ebb18dcebc538e613951fcf991 Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Mon, 1 Jul 2019 14:37:14 +0200 Subject: [PATCH 038/500] =?UTF-8?q?Tooltiptext=20f=C3=BCr=20Notendurchschn?= =?UTF-8?q?itt=20auf=20Gradeliste=20hinzugef=C3=BCgt.=20Men=C3=BCpunkt=20i?= =?UTF-8?q?m=20FAS=20gegendert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/views/person/gradelist/semester.php | 2 ++ locale/de-AT/fas.dtd | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/application/views/person/gradelist/semester.php b/application/views/person/gradelist/semester.php index e3614744f..532ef56aa 100644 --- a/application/views/person/gradelist/semester.php +++ b/application/views/person/gradelist/semester.php @@ -143,8 +143,10 @@ diff --git a/locale/de-AT/fas.dtd b/locale/de-AT/fas.dtd index 86415c024..61e7c6bb0 100644 --- a/locale/de-AT/fas.dtd +++ b/locale/de-AT/fas.dtd @@ -115,7 +115,7 @@ - + From 71791ada4bab73c5f452b2449722037a957e5984 Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Mon, 1 Jul 2019 14:42:27 +0200 Subject: [PATCH 039/500] =?UTF-8?q?Infotext=20Phrase=20f=C3=BCr=20Notendur?= =?UTF-8?q?chschnitt=20angepasst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/phrasesupdate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 4f5145034..0ee2aeda5 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -2425,7 +2425,7 @@ $phrases = array( 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Notendurchschnitt über alle Noten (inkl. negative)', + 'text' => 'Notendurchschnitt über alle studienplanrelevanten Noten (inkl. negative)', 'description' => '', 'insertvon' => 'system' ) @@ -2439,7 +2439,7 @@ $phrases = array( 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Notendurchschnitt über alle Noten (inkl. negative) gewichtet nach ECTS der LV. = (Summe (Note der LV * ECTS der LV))/Gesamtsumme der ECTS', + 'text' => 'Notendurchschnitt über alle studienplanrelevanten Noten (inkl. negative) gewichtet nach ECTS der LV. = (Summe (Note der LV * ECTS der LV))/Gesamtsumme der ECTS', 'description' => '', 'insertvon' => 'system' ) From a8f7199ee8076bbd0fe3272c6c5baf4583c0d695 Mon Sep 17 00:00:00 2001 From: raab Date: Mon, 1 Jul 2019 15:53:57 +0200 Subject: [PATCH 040/500] =?UTF-8?q?nur=20f=C3=BCr=20fixangestellte,=20neue?= =?UTF-8?q?r=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cis/private/profile/zeitwunsch.php | 25 +++++++++++++++++-------- include/zeitaufzeichnung_gd.class.php | 2 +- system/dbupdate_3.3.php | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/cis/private/profile/zeitwunsch.php b/cis/private/profile/zeitwunsch.php index 8f7e0238d..623bc78fe 100644 --- a/cis/private/profile/zeitwunsch.php +++ b/cis/private/profile/zeitwunsch.php @@ -32,6 +32,7 @@ require_once('../../../include/zeitwunsch.class.php'); require_once('../../../include/studiensemester.class.php'); require_once('../../../include/zeitaufzeichnung_gd.class.php'); require_once('../../../include/benutzer.class.php'); +require_once('../../../include/mitarbeiter.class.php'); require_once('../../../include/phrasen.class.php'); require_once('../../../include/sprache.class.php'); @@ -48,6 +49,7 @@ $uid = get_uid(); if(!check_lektor($uid)) die($p->t('global/keineBerechtigungFuerDieseSeite')); + $PHP_SELF = $_SERVER['PHP_SELF']; if(isset($_GET['type'])) @@ -109,6 +111,9 @@ $person = new benutzer(); if(!$person->load($uid)) die($person->errormsg); +$ma = new mitarbeiter($uid); +$fixangestellt = $ma->fixangestellt; + // Nächstes Studiensemester $ss = new Studiensemester(); $ss->getNextStudiensemester(); @@ -175,23 +180,28 @@ if (isset($_GET['selbstverwaltete-pause']) && !empty($_GET['submit']))
    ^mD@USf`&TDY#I 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΅RIgOvme}_36 zC|W2KP?fuDKLwXVeIQeL8ld&)aV$Zg#e$vs=32gMg;F#5=JLC%r`2zxV>K~;HjhS$I=YTclSx^~G5Ot5i=AZWQ~_hQmD{PotHZ_Fw_;~G7+7MIlbGk;Si3B;v0bL{~c%pod6SV{_C&c_eGLZn_$9_9pbmv_@!4z`OkNZhH~8` zlK))m{_Bz&3^LH=*)d(!y-dDm4Elh$$QVU>^ypEL@W1@?8$mv%iy9T*W3JByKPyV~ z)ZrCDyh7_I&$EzlD7i4S{Jq{El}};QTd#d!?ZEea-3HxiJLFT)5SglV`nzuzia3Wp z;nW^nxbc)A@l!=o+0`_(nFESL2hV&`g*v7vRdyznSs`0)i_y#DN}f31jojRexw2q zq?8BOCEP3%MeBS2!YTCCxrn%i8OA$ZW@8|ehzaZ8s)c1!V$7 z#Qw;k!aJm?WJ>ms5qj39(J+k55VfaD4e@BTiBPDvp1R$?jqJIjS>Ed2=^))xJDLXV zhTTiEXAvo?tpxpM0p9bCb4SfRLvXo=kPH1av!nBJ-nh=?1_|jC=jzUbyW>WLp0q7f z!+#7Sxz(2EC%7m3fr)~}ZhoL>A6^Tl*4S3(x=A&!S%(YR&l%Kv`d!ZTkEj{q`-8AY z`Q&X``hsB|&IlII9l`Tb6$c7G?Q7uSSCd8;6; z^v?SAVv+|?hsKi5!lzYYSkJ?M)T!4Q`{8mt$$R#NG|VHKT_OB=DZ{F%+lAby zJU$MxQs-v0J!Ph_zGkDwQnenJ$Qde<0N%Qx(*R>)7T-2~Azu#NBk}ylalY!Grk6fg zyks2l^Vly=0!6slPKsCC^@FX-mJtktBp;ofj*fxoaQ)T>QiB{%9sCD&f-W2C)k(>g z>nq5DXi|+W@2-UT4``@1@}YC#vPst_CBWGm^68xE47y#Q}&&q}qo zKh;D!WR-6jR{m5?JU{ud_9q0y6~UA;2d;;g6=vV)1Qh;sgt`L^Fqp~;7@ojb7a%W1 zFi%+ct2UUlJY8P=;9p8lqqh-`(NxTphyFYX^utOQyk_odlSj`8lU!g%LTOhg)4C#Q zT?uSO|1%x9)8Xc?)&Ly~r+6RKVkb9DTymQ8pm)*aCZOJpSyBEK{oPK7-{)KB%?OP< z8F5jXr^o*w$=?VcH**_p2%Rr~7Y)q&^ z7Y6VeueO3W*>=r`C7Q8S)o^FO5~dDq#WB&SqDh8Ic)PwNaj1Gu75Dd@ z-KAf?hQIQe5@A^x*T_cQmSB-_Q*XJgBb_KQK=BZ*6sJo+W0u*>e_A)ZGCFeFDe-Xq z=TYZD=hqS~!hvSG*9E>hTe;WA>(9v6s?lY>_s=U(?d?w9*}#5e&g`f2UH+(mQc@f+9R`C)z1zJ)ILX`loQhS@5Vp~oVcDYTy}5?H*hH~Y@TfWdW;dgoXLRKpEF3t& zPS!t(=$~J=gPA}9bF0vtconcB9}Vg*MQqj0y*CLeJFza39c8!mFld*0nF6 znW>uWt@%&&16}?BHOiJi3O9NhK5CK&T}}$U7#Zzja0-NHQpl}sWs3EK>ey2&T@TMu z5yhQrvc%N1>TevS7dkh-uSc6bXLBa`_Q-6-N7=f)dqbcMp+hJ`5F+d3U+<4Z zcz!+VlF~&ZG49-J0doZvgDo)glD7QC!v~-5Nj*Tuz|o!nJy0Fqi!Xb+nL2oQ^s0@R zv^^oUKE?DIk}HTHFEY8r%av`e%zY|rs8moEds=V%p03w0J{|D$=wF

    {~%dcH5eB0K@Ozs#wyoKGzD*Fj`85;b$ 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

      ~nvnNnyL zpsei9FoS~hky_H#1NK-F229eNZAtgA3M^k~k5uaOtQ@@^kZ8%hnp^KRYRM6e-Ms5& zT+4wrTXG;<(a2kKWm}aBLs|UYcCQ>?1Y9gIw%NcV5+itOq;~#a<@-?;&E1afu--C5 zUw2-@z~c6g-G^+}lh`rBmX9am`ErG<=-uP-eRQK?o5y8ON1y+;rh-)5bkC1{9zbKg zl0d_IXq=&`2P%v3#ViF!tY*;lch+R3{&mhsxumkuMS3}Iby4)?{^YE#^g8-)zx8He z-xJrKWeo_v78~BEbxpda{As!AO_>SYQBx~2{AT_*nuNk8qn(ix;KLaKG>M?s9lyC0 z*8T5jPWHbaa<COwxL*lsJFDC+An0 z|BIH>W#O_c)lRBRnJRm8S>@cBjA6H7l~{~Df1fn>#|G(4t1@aYy|bh;p{8$rc4lW5 zqD)X0t=NtwSc(xWCG4xaC{$R4MHp@^L+z&l`+Nnk)ZC{MKM$ZuKqT?!vgz;=mFZ7c znE5CJDYGI+ed+U5OV-tYic%)5?T_HTP@?|)`T1V;thsikttvzal@OhOTqk8m);@X) zR+SLF|GMYLF7m5Fh2W-pgd@E4X)Jly6_|=;FBlcO&pw)4)8TE@sv#J{4qVJG#k(_r zvIyi9ZhoP9*zN)upZx@YRvcXn02Z!|<7$FH%<=Y&=ZyJ{Dch+DDow1%C;18?!yDf4 z1~zaQ3+mx1CR?uSVE|PF#}b4vQKii4r-6nJ*HWpl#C>Z{AFb~cDSv0>=r==KTu5)* z;>|ZhvUj&IDneyGF0XSBh3>aWrDA=kP!TP7FMUog0O)5c#MA0#W;nnF00~#Lu*BgW zvL#Q!K8^1JXnAf=6hRoB9VrvS%*U^diH)I3i8AxCJo~&&Iins}X;binP=QB}m$>3B zTC+FhqY?Ba`1}RgrXZxVt-**!#q#vdki~eVBA_{`SDY$fgYZ?xk|=7GguPJ*g3;{D zmx2M{kOTlU&;Djf_1s`uqwWC;WxheC0hl>7N_W(2?uWVWeiW8HMYO>*O|CDZQI@h zdk*iJx+mtn;!Kwfu#V)MSHbjJxQ*GUK)Bm0PS{lc6!5>$J-fFIT)2;3kY8gZhOrq3 zx-rPWL7aP{=#H`?*bWSnC{rP6YJXl5Ve+MkDkY&(VIT{CFnr7RF95(h zjprpNC8NRf9QM=j)43&STj)>HArm$29DpM}i)pc2lCeCRoZU`r=diH0*{T(UzK2I< zF}=9vO@`gO_v10G7#bC-qAvkoH^(f-<`%ws>!h&l^q9|OlSE8o?OO}4zT==~Q3hJk ztSbr%@#kx=+Jje$s7NhT5^yXO@Z_dC4*0s<*GmMlA?* zM{yKK@=3ll@yVD{EX5w`DGUoQY-hYFG!s1aRj;o;r~tViW#;GOoO->*m3mivu9~h} zScb#+T-$iRGl~aHmkg-DcuhT+eHS*WVfUtzm_{IH1yefy391AKZ_V)|$L*JdN{E#n z*rqE2sFuDKt(9+YUEq4u?nf)?EbGhNjXgK`KVm2V292ERHRBOBXFL*dCK) z>#3+ZnPJ8c7{a9Qo^%MHNGUUl(TM;s^=-*XcU2g2Ep1%f-Zv_DeP5TD~45 zeWGZl%1C<37xnT2GZmrOnu-iP^;qZ$+r#blZClkSL2u%Vxg2M3h?Cixr72UU%23{^ zU*c-t)K+DDU8JOilRE%i|EMKOvG`3^HUO#WG&619-b=H73FJ6J0-k-Y@b5t^>HvE= zOI%IqXdI9x1KV^YQ=8&KPRARyU?grD)Nh5^2A_fX*@x>0WlqRNCH?$d0=*~;l_o}R zbWX7P5x~NbzBJ0#DO6ZX-0S_?Q45|KTs%jouYX^YIaOZq%`)nbEiF!LZ2f3-}hKelw82!*SOj-n?P|ma?Tqab83KdFxxwl6p+;bIeTA$GtQ~NO@XHBBaFMy8+@2S}- z-xP1vsNZYN=|@;4JKa&CHxnaY`7+dQ7jX1yb>^fJ@f`R;DuIckW^wvq`cG&HeEO^SPtg6nrV%gKXJ!|irr6z>gC$gubGdnZSQGfK~`^??)96N3OABgrOL=#^a|@V zjujZ|P!qx^*as2KNld7JJkI`YJx7gS))*60KnN6&98gi^s;SZ>C9we zNlGH+ud#c-Y5_N!x=Mu=$cPZW@K-+Z%pYJSQH%0l3fp`F0B>CDc-ilYpYRhF%EFg{ z^!t0#9{{B*mWot`q3%>*Fco&^BmCN&4U%FH6cxMK(I17tF7GxMhMJa|0Ro^uxcL#u_McUc` zHJP)tZ;o|m2rXhP`)%|gtX=r4Wt{}1q{7AhtLS|Wy0ZP9xjfLZxGkN~e&iH8cQJ&- zLafgEY``rZ5;p^-*VPE2fpG@@lOAaSYdJ1h<+(XKfnLESs8VGeW;?-3J28qILXitp z9l-ogeE;;Ns%^?br5{7D?df&zoliE0c4QsKGl&rBN=N$t6({ECL&&XIo0aYKGu2kb zRiVl_0>Jb;zVxLR!6{T3!ytMIfBI6r*5cCaONVdLvXL+G6?SK7QIreLYg&9GeM?u^ zljAR$Sd5SQ0LwU(z^#P*l*JSRz&mqb_jG1DDk=(r*yFNG{FvernxmEEQ`ynO-4W~A zGDz$emGEMVTril!-_imV-^!jtci~Y`rNkz=+VcELaKHL3x<19HIG^4LBa-Ot361Q8 zY03|jC-FwcdPrZ`Z zBv#^(NwuvrS(Cv6-0&N)7~8`l4fB#)Uk(0Q7ID1ZuvWwI=1~B4u7(xtHX8sE>{_8X zqYtvE!eheT^GnN4G zMzey1Fwx`&>s1-Rp&d7*sdqGmp(I0unGjW3_``5Yx_=D>i*vze_DG4R=rDlKAFsEs z(w(v_!&)q|XVbf`jar;(I{y&HvfJX@PI$ z1McRg)i`0RHUCu~D%n&csyw2-by$4XRqxGOKZA&b>=nc7u)Ee?^VIrNyG)%ub@$Zw z2ikwP=sq*2+m* zB_9rB?$TKoQzn7k2>^@r;2iozyF}$GBATsM1ChE~01?8**J@0BWq|WjJ<|8#*zpcF zDl)Tby6MK9S*{0q0jVv$sp^4RS#Sqe0Z@Yq75a-;lCrZYuN+W)5>Du3S{@(t&g|GeI0f+VfC`_^;qdwTbJ1-7*BtC3ox297#-LvaIYTBvGjqn>rU@kaXkn-R9U4g zVzY${#axxC61-D4ONZ~6tr=mBuV(L2yIfFQtXmUJ8Vd`R-V9>|qgaDpX}$*<9~gXK z&VeHb&L!m@>jJ<${r7^S5&L53Lx?2SWT5Uisr}~3bxXU4@}-XI;HwH7)~DpPC5a&mh9u^$IYY{hjXC`AfZVl3i$H+-HocsxJeD z3Ikc0DJ)Qa1nbhoU`G5|;=teoZ*O5%+eugz zN+NzwR*W!IIj99^?AV!|2mYgij}!1>c7T|i?f3M2Rh3n9CC-4@p7>Y;uR0T$L=y|J z?CoNE=YGAGm1qy+H~)BPnOMS!xdO?U%v~gIJ|#rNmAD%V^B z{_v)Si5$#z`w-AQ5SVe+=P$(p0WHe8mfl>(7j+cU2w|SL%3WsvH~`}?9>B|2+Fg<_ zDVIuLdh*hDEr9L#-y;^*=27wX$b~jf&NIE7-&G|zF_?wO-=-L$5c2W(3s=svCqLB^bep!S#dV zgNFq_6`GqYn+o9F-(r9BcT#C27U6_VwWU zwtgrhxN~IJ8MUWlVt;mG14gl^UJ*cblDb;enF+-|Pcq+}DU0pw#i_L95r!*g{E^T|2c-5|c{QCQcwG?>U4E_>(7mRp*fu!tb~(3@UV3AXq;cfqeU z{!gU%>%l87o_+BIqX;DGz`ju=xc6d!6?_N*5z6_!jIF!r8qn2kVG^Y|@j0!lY?In2 z^uqj9LtLUOR4oL4k|T@+Y{r!5HQd-t@KRe~ww+hZ%uaudyV^ghy_?7gdn2zJKa0Mf z?7CNJ7%+pdIYqPpf0gE2?XP`S@}3t%L2c0%y*tx}>1&(eIanP{YuU1dqA$2=DHWH= zR0*+!pVpqyut&o>4b2V5d~!NhTi2~UUeN`tcf<*jX3ag*c5pX4zrHUk6a#AR(&H6G zB!Qj)fcT*SR45CH%{hs+Z2^cT;jN>oeyse@K<&~pKl`#ai+S#|;a&3q=H)!^q zeO#-%DF;b@S=zn913Dl)OU+i6jt~#>n1dd6f5#viacD?m9 z{ST?TYZ8vJ5h9!=PH*_wlc>eck2RH}(yUB3)8H{03fMVEYvmAtcM>9OQy6Qthq9jk z4OA&JVbg(J-?$C~nDV&4llH8*4YH1y^RbtSS}enZcEFcbdQ#E#N{LN>qWs=i2$f;< z%V%G#{e=ldsbp9X$uSN~K9lws^c0>oD_<;>BI}YXBEZfKksfTQ$(d*Z0~dry1)Lns zlFj&0U7{r*64_!b^XC@p{?y!T+lA_|>Ade+0>eChm(RQ-E~r#kIP-`#tt*1%p6Ztz z!ncnU)Fp*1D(Go}Wrt|fFf~_mzs>`=Dew3o+~$pO#0%2#V+Z+k4Vc2cR@jUmS0iUC zXLOUPF!WnmW<$%+oef|QiwJi>p1Wu*L7KbsIq;|k3%rzZkmAb+L51Le zx9;_3r<>QZ4R6D908pJORTkjnlDQX!kOW|T*YHm*E{L#Ug_}8oYu++DOU0}2%zEtA znm1%BqA_b&owEY85^|sRm4r&^eE^vMhUUV3>;i<6p}y?Mv?dlj3rtv|Qf0{R8(J(X zXFPX&2eY=ZI|cak9WbVsKTT{wNG;xXL@gA`tn)Yh2hIiqT!MX!JIXA}xFbt3y)X%jU{k9^gP-5b586FaUQSw?@dXR=a=~x(B!n;>Q+4pQW3?uuPZGL z`F&Yn|3KJn=9#grww>2I3jnn!2|sr02LKH~({{fjb!#xd%~RKyNI7*`Ne<;3)7+*f zi73{M{NMJD)OI%4m|;arf@C=Rux7{h9_%tlCH#A>$nyA~a*Jgz0H{obD!u;t#eFNj zv$aBnLX}l`@6`$q19%}J$jEl3kDfqC+4HZag^lm{tHAF*P7`K7(cM^?yQ8)b^m7Q~ zFp$%sd?hqcG$SRTwHwc!iBA&PKHNk_gwpG(&usu`{4GRDMhWOq7Ma3PRA@O10K0-~ z(=5C=`WgVtMWtaQLkn$n|@OggxAUhwUot`Yr9D5ZQS|PyAGIJOWq2V^3 zqmAdaU8V%z%*8gLGpGuMejM&zocF8mOO*;A|H4x@e0^|P2Z`3?uxDSWGXUV(sqw4h z^bj~_W&;aSp)87U^{fk>2lkI}gC3}~5EbShSvYRjgdLpR$~E7?%#cb}6Km7K1U_JuFc$S(~6T4L#LeFcq(M^RY7&=JfD%c=BY1 z&|a(5rYqRy;;4PSH5C>k@P#G5t(SWb6)j9^Iz2Il0|;|5n;mbH*P;~-*P;{n{Y4@P zV3h5X>0?zlq2v(r{#J#`BHSJe0B-6)!d$ zStJ8=){iskONC9^e%PS-pQYIKnu)4VX<{LMT>UNXy*BRJ)7Rc&&iwzGQ}IVN$4WB- zMRSR5S2p&eLX~~p?-IlH^up9;*}3T5q6XHsh@{cYA7UZu)v$Gb3s44L)>NzV<>9&g0zY{C32NqX5UY@XIQ_Yc(kVc@3WxrPY`1pK8?Wf9jbnlyc- zEA;y_`;Js=r4y>!1$b4eBi?)}pAV>tevsUpHoJ*kndDux>3m}%E|N($F0p>OuP#rRGJvO_pK~4y3UF|z;ju=N6#yuLRgQz=knE=mo>Pn z)0OOCb+WK9m_s{crXm1K8-&=HrQB^#4w|zfllHYQci-G;GQNEcz|1pVEX-{#6$4yA zF;R@23LM=3>b2Q-?Bi>_I4?_CN8cv7b7dGz3zVcxlL)$*__NoIP%f|JENg2xNYhe` zFJblBk{>W-f=noSz)moS#V!u*Yz0Fuud8CO2;^?Nz~}R8Wv)uHW0ucZ^;fN*@yGGi zSv~%U6+$K0eV@x$qxWe{yY)SQ$*OI%vbjOggHsd1lo7_qXSy3W^ zv#S~*$?E{5B=;a#`}l8<=Xb(gUA^`y>k&Bk!aED*UWHw)LzUGw(NBMmOzxgQStxYp zXaz6SUOYX59hX(1Oo`PvP~T3!uQz#2r7?B4v|>@c2CeZlk)%|VFAr(+hn6_5*qL>T zLx~Pm&mbG!1ep1BV=5eQkrDT&Qus`iIv>aKtM|9dbc-*#aZJ-Oh30l-X}zE{ICN{) z`Am!0D00+Atu3|RM3w%`dR@^|JGHH$%uT09ly`1#=)K9uzRKQWyxP@=s?fqow%*B| zA^g0cW2uiNROxqT3qK#J3g;LE#f7yLLL9hLeRFBPX{TK(dQplR9L3E9rut~szOzyG z)&P^pNE*sae97_XgFe7U)*~p<L0dtE5VM@ldG04LoRztJx#Q=XWvHOawuHmSaF#&o>zZRCbVMP5WlNiG#sR+Bwda z+Wpv``V1w6?AFn&(!|HPxo2a>&|U2=GgDcSCKt`zB#LoN)6M|S2Shfn%Hr&QC>_Vn zJ^0^sS*$(K>~*hg)frAje@j=Ttj5h0& zWD2Kv*h=4MFgT04nq-9u(Q;)jK+x%~=-Tmh#$NWJ%90m0?geOyp=5QIOc2Q&=8zet z*wr~0(EXLxX|Y_KueuH7Al&%NlI7>_o|HaU3*jPIUknolEM1u`jQ$-o1L0 zj$;{5l@OAXpU~!3778`sF^a>pZ16XlDO07)l?@&B2H8TDCdSUlDwem{QdL*M9kta8mR!5G>G+hfQ6P$zv)WrA4~nH{uoS^U{|(|)LKY2bMlO74%H1TJ63U9 zWL_aKuE?@(Dir}oz0uK0D$KN89yJG;gTnyEW+-P(?8T^VlL#y>RGem8fT8Nf90W&j z`g7iwR!6+$57cv0uPcncR2WX6#~OQx%rMEqxifAtw3w@pgGvT1{yT{gzdv^a$gO6A zdxy9B+3)8N`cttBsB|1Nt)@>rr?Xv@veK+Mbg~S?t(*y}u6z1MEy;$HW@dSP$=Vj$ z#)%0BRLDn_3j2PO!Ny(K(}Ol@d?#86R%DwS>a)qu3|jDQeL&Nw+g`Fy#n!aNlC0Zp zV26BESjwSwk`Zdx=PK~r^DNSYvsUJJ3G#N-%)mB07CUesz^Tv#XdoVwNPo6&Q-;UvSEllive61KxNz^8Tdad?#jaU=)xUZ4D-wI%V6~<4r`=Q}8>z7auckP}cQ6a>uSr%V66SPR|W^{5aXbqR& znUd8D9q6s;Dk0B07Sb(TP2Z?GpTzy3Dknkp)@Zu3I%hgLcNHqapZ()gn)p*;K9+MI z|1T7F;OTZpJM^mRp8?Kb_leLpJ^LsvSGLtEbY&d6s7-WXj{Yn7`aVwi6^L~cgrn$5 zJ8KAYx6*jMiBoEi`!QgZj>WM5Xa>W{AUF(Q)~|5ch)Z#B!llvW zsfe=dV^CS`ZjfB-XG+JhpzCh%Mvhd-IpWwE2lJ*nNe$~qoK#AYV6tD~XQ{5UyjvIX@i7@WJ z6~0tN085-X8rPi3thYk4%fC|GR&y+PsN;Tx7LFQmwp`IW?%pDvTVn2)tPS{7NY$|=(Qn1{h%Xx+c&I7CaIf>A=X_(8{}Hw!2Ul`@Bo%-Z$0BRroLZ(Q(6o9n#m z6qzbbOsSGZw*ndtGdUR~5W#H9j=FBVWnJ!jWX>a_D2ArZ!rTO|gb{dlDFm#8uJv*1 zKI4j&YDSMy)hn4keBls;Bl}2HDCzaew7-ncWZO5g{+X=*CF|O)NjqAEaN(-on=4a} z4Jl&tsJUXZs#7&{l|DSwy9#Ad@Eah12KB)0O|smi-AlD1$kAtD0Qkfsf~iO`k0M3nB5joH*n1UT-&d_d7Z`4yMBKtxlo8( zSyhR5{0dQFW7etQ?N;AZ+@}eOCs?WQJ_6nED0UgK{!F|X$Obn{-6?EMyb;O?xEC%(iGQ&vldR6o5b-{ybII@jLHjDpeL_b;Tau>R4Da-3DcOXWtgA zE%oOKxV@|f3tssR8~?+e3r!@=jeM6Gr@uc62?^!now~EKjLANY4tPx zP=up6I<#ZaH9qUp_~!YBezWBo6d?cz5CXzX-7ocEQtMw~5%Xi}^*==+0NVEjsNNyl%nn9fQyL9Er$t5`qF66acB+e&hOnz!C@~%?bcijO^UEWrMpq zW?&5nfi}mIH%wH;uNbu@Ff^@&HdmYg@CctJI06MhsIN%^#KAg_dpG#Y<)q({-bWV? z`?tq;Nl1Ug3V}BPzK80Sg3ZywHWV-Dy5O`-%Yj7pWdzm`%uV`LAW(i)`IA5m z0^?TTw4rmyFU47)2RHE0%nUph*o$BD;K%;_K0lfb;P@#T5!jOJE(0CI++Tn?Bwa%u zf)%cn{t;5Ab0u+)=f4+sqsm-&TK$loP?|7xmuy?H@oDIi^+UE+1{(dzljP|%f(jvv zCVTR~WOBwC{&@`DYqFULIWDE5e3EymCBn^p(e zp&)@)Q&R{iLgESLz8{l@w=T5O)SvH|YRJ$}WEsp@E#QSOCyq&{uz>jG*CL6J2~+7t{sMcQ$)F03u}JRxY5>|c0CAF1JeB8@i#dA<~R~DaIxQa zjWYXl@5y+I6uKP_e@kS6Cr$)zA5loqHZyatdHPh#>~Ze6l&;wBQo9BZtyCl@taQ}T zgb>#`=I3jb((cYrM@?a@6GxK)or1Muip`$B@Mto|q9P^;Q21Y;Bh1xEC_5Dd0Emke zv=Hq7nwrrXbn(nOg<$JOZ3$lcy&`~Z7E?X_yl^wedrH~m|)H8fk z%9`00gsU5~(Ccpl2sW+(h2We?IjAy}^eb=IwABfWwQJgOc1?RQ6-_%~3S<)^I;G=h zc|n#~HCl)wqf^NRF3xW}qrcE(CIYh_0v+A6CtGcdpPAV0Xl zL`GS_fYpZH1r%WOW>Nx(cwI(0fLMr21H~zqqs3Y`sxqLJ$b>{BaPaoDxn;Akv*v=! z=jp89tPI8Z13AB&-7)UuB#^yN9eZ?lWbztzE3Wlv_4Fx=z-rf&BAHc5*mR)+1we&P ze?q~l*gCXXu7Z90O%^G(B_`9f#^)-s;5nm@Ese6-;7Q{c4zJnSy`;D%-+$WMYaSLq zsb8?PFtn|(uNS}#?!7#?W?CURrB-Fab0p#%{utmCv3x0Q`r>gM;$%7y0!Iu-EH>Vl zU6$Wo-y{l|KMTh8Sifc3Qt_Age$b5L;zrsCZD8(^n}3BOk{+i3kwL@;19QVVEwS!b zQ9f>1fqMKyCSS58J}kNtiim)D8ytj!Q0xM0GXw;HWwXM66|W$)0tx^L@#loiIX5jS z>TE~|2;@b!WX1&{puh_m#4fCl&IyoC!l+aW|&Ss~yCU_L>~dEXf*t>eMOZ0>YXS$IV1w z#kPo7HV=LrSo|+fDpDa>*~xLu%fYEc-ZW;G>j)XN;ZXYERKmc$2*j3G>CUfu*hF&J zTsJfP>;UCSPfqXm->FzqgBsI*G%-54%fk^0@Ea5mdF*Z#(&$YAK1zclhel2P@j8>V ztg*Z*h+h3!H=sDiRh(H+L;tBYcc?!mkoM)@_$}A%$s%ltCNkrS`Kfepid4}>Sd=8F zNkKM%ez-2ZIrU7%SH9-&(*Kk-9wFDNN}vy{_NyTb+D|yl#L%c$#q&=x37>kUZwG@& zaB%SiD3;+s%R=9eiLqitw?ZZZ!MN^E!YV#UpgrX zam!5su0cQ`3*N@DC`*rBhhU(tHoH^Mio)A=wY&=8IkxO2TVl+>QF}L1nD}kd0vvZ1 z*aSYBy+N@r(MguA8}_wMunUxcKm#O-r+xv-6P)eywZp>xPi6tkSIO8@13;Yn?l)^T z-iAV&uY^E6Ljn7%CG0q{f@uvB_x*~^?e2ap&@nN=epUi_jMlS&k0QO}PUmU;@REsS zPB^{Wx4V$YDg}gH{&fuW>B-4&;j{KNeUMlvKSq1`2@vVtvMF2v(7)!w%jd~t08@e} zH~UC+ATus`w0?S+zM^fG8ZOHsG~p;lnGk_Q*->p6mni3YTI#D#wxw}Ig?E;dB1u4) z6_Ate2S_BEztQ0{!(JwcL`YNgY%hQSkciQdm(^flT||-OUOg24O@+hX!UWq? zobz8?fpXfX1Aa`v;*cVCi&a2C!PRtCO97(^vD$Olu}EAo*EQ<|H(Us5vP2b0mawPr z`S9%%*^L-h*0`r9pu|}v2w``f-jwe zvpONR#`$|%vo_V}_aOz)ELldcMsVtKpbd5EG6x-dE-c4v0MtLuQ87o=90z=C*Zj7P zO3`lAXrWsqdPEv^Mku~lyiHRW1R(!qV+GE@3P&$YTHHw? zL`Ry@NUvrk3hG4ggg8aYrX1 zQ_vW3Vqykj|L}`&s?Hi6IfRhEQu$9pJ8nL>oW9W-J9V{WOO~oGN;80q6Ojs)$m;dE z9)R~N13euYNZDR9mFwFZ$L~jt-T98mEXGHBQlmvqq;eS&0xBxKb(6@7y{IgvY3+&$ z071BnE}J)Kd&gZxVa)8h&=aERosSL_LBIGv2nWZ-upbKoXtu{H$D_(4M>oZ=64Rr1 zfJ6?VI0N+1T+?rccsRBq~QCF1=`Dw5|dC}OmA=uDv9 zTHy8!2mxsVbmp~l(h>leg-ovHF&7PXycuewH#G`Ffq)c*at<;@;PP!5kxqXFnLjh* zTc2t3K(MI}d{cFyMHhfGj%#HF<%E7Xo1fB6G+zY=+|v-Myl}sJ2O&;@T|#5kg#Lqp ztu76I|1Ux-;bmPaONJ1|)OpWyCMID8#7ADo*I9A+8>>Sk&bTHO=^D2i5rVzGhbm%+ z4l9cwHytnp@iY5Qtc~9IC4P@6`+P&?@*ie-Be4IQ8Q$hy`W=cbP*~y}nc7|fF*@!# zA^b&D2(Y6-f+?s1fE7g$1_6jEUlmlJ1iM@WVp4f!B|xAAuG;{72qa=qLinzVngzE# z=jQz{1p$7@dNJxkg|Q04=LKJXc3j#au0$01t;*is-vbPbS7g ztj^~y9J9W3@#}z109Kl&?K*U37Th{=uE$_(GA~{GNr4)(m zcV65C_D+=!sfa3mx?5sR0_#FMI)1@TG`PGq{;G6dX#|J_Y+eFn#_x8dlmLPO6oDIl z#~@_7{OU$yF4Pmi4Fo{QtvM3HRfluXzYG(w$6ICf# zR5m66w2Mi`e@Jicli=D9fE?5aMBWgolo8gK>j>`OA9+zYl(!U)2WA)YXYRScfG@JY zvLp7*{Eg>;dMr<%QZ`>F&hYi@HCiKbj!Z!rs!?S%0)EUw0H{mA5|g~*H~60IEG+=^ zCuIAHct?x`%RQYM3sW)PWfghffk_R+!g=Qg3(;WumwDHU_L%Ozy?`zpHK>3<`FtU` zx?$<)KiL`d{mDmjaL|nX5~z*83ZPs$RZZHa;re{Qj%~e>^vB{F9Q!4ys%kg)D#qSlN=}k_X7B+O(xdv{VoV?{(CAl7ACsBBSH%R z!GvtSz*raoph&Xz8X7fva&lz=s6a0ss@Abn@~T~(3Y!vW$-D&g%Z}A#76vs0vi)h0 z?p1qs!}GsfZAPvq(A8x2w&BAA2q>J%pUb(Y%2@8&{}EB{I$M!en6H}amK#zIu$QkeU1<7fsT5@H<9g9`vIAQTRDRuBLrt^vq}hX8=U#NVVXBsvwg;O!XL z+HS6X;Z5C9{@WJ7ZDh}%ls{&xPJ0Z%2lt_>Mv6C+A-uJw6?qnU{T$xwoCScJ9YL0M zi0lcQI+Vm_0nql$<_uL_XEP?p-nU*c38+9blML+OTdZkY0C=B}C%4)@i3QNgiP^xW ziHw=Hz6IW@3izZ-R8)#ULAJJQS_k8yA<*kjqqcMq6aBgn=(ei!DWETb#VaCy1^N+K zye#4@@GFcMqL9I+v|W0vd?k^O0o?B{fQ+N ze%v4eEDn>lVvJqWI?f|Mm!wP1MVlAEcYGH#t#?|q{e07-C03!trR$jGS)hi^oGk=q z{5n}(tD%V!pXa==J=aFB2xQp4Vc-3fEdyX>2>_>%3ukhr&m!Ph-ck~P7oM7b?ZRmQ zCvcj;835PtgY7r|0N@YA;W3Zk2`=Cs9^)_`;wUcR0cbsNMnirWiHwd{2>|(U3&18k zPq6|DT*h~^#7}Lo4V#+-xqTsp(@IGIXW_j#c|)Ev*of-lUC2jxinm^9Ti|mvWbS}N z;>Z)ne%N)dJ~jnXLXyzw3LREFjnAJjr(}Xl;tJr)C#l&*{$iFpEhmqdw&kZy!?5RiqOqR$vCY5e8^a@7(9|V3PzT zfw@q3-hvZ39xaoP&yV5{_zL~e9aE73gT$X&Q9dXxkdjzKA|B_Zf-oFIg1tVBNJJ#o zdR(pMw&oT9AP$Q{T>jw(E9Mb}9ZLl)_#@qqc!mH(qv^#XpWHd8IEdvl0Bzi@DV$?r z-@_$fOT}iJvpqPB*m^)hX;mqc*^Q)V@2Pk+r0qcI3gkO@Cyrx=GaurfKHjPdXU#v0tg4`#5q#L6G0T5>sJ2m(McKPwKc@=kFyVaDD! zCIG|4b536jOg>snL*{{ihOGdK znL@hen*F>V3RI6h56YT;;s2Fl79jfC7 zz^o6?BGE3ggunwq3jnA9Havj<;xI83iTu|(!ZSWwP6dERXhL+~FkbK!!MeJWjn213AHl#J-mJ??Zz)ZZ@veL#Z0 zh-a0dVr91UaL4l`bO00Uto|kA{TfVsR&r0}aOp%sr0EA5Vl|KrzvHI>4a5`9I$QJJ zxqt2RoZfONHz~ve3@j0H{V0GEIDtoYu>}AN!r_Hu0Cs=n?qnPoquJdmp#bnye4jU- zdr%e|AutP(J`E3BaRNGyKu0X%v2e{2-*-u1Z7m+{?(^e!WMUQ8Mn3XAKg`m%>bC8l zHLkMuK0NX4sI?f8i!aIm+{s^c%rPl#XPWXmV7^81azEcAY7gm#B1wu;S?`sp2*)NBAEYEH(r$3FL- zux;Fe$hG&Gz@aF%QX&yiCkj1TIqYZDMuln1ad^lRCosw;ah~M>Ahdoq0LSp$LC;BK zr$_*fF3h-S4^P{L^C@l@yy2I0GabQx;qdPfTFp>`fZ(z5ZH64LT?lu~+$GxGJqvQi zJ^9}+FL3d6MD_VMofl&O&;3{y)B7FLvVCi zubb4JeX`!d4u^{=g2;%WZpH2Z>5*>%p!BrJ+^YcKc#6f}#^nV7R}roOnOua)oJeGY zil_S54UeN&&#uG%qT--ORdE*oV+-C^oe^I`K%*5Gx^BR?;<1BjAS~kh=EOXFk4L!s zS@Y)!_G`HcAQI2KVih2})71e2=>Y)0{2Ocq5SP>M$@k89E1HqrY=NSA8nK=q-UUsY zP#f!9|GXDB{(j8PAI^Xf2taL7e2zc`0DJfEN708L90Gt{DbPMcpcXd*fIG;T59qy1 z+Uvt6F&e~~#KHg$4;2E*j0;_Si3QDEbGA5s34rf&SOItZgdwf&v-Q|N=-kagK;jVk zoLPWS2y|2~JCrf%0E*x)jspmTr1NVKkAo*Jb}W+Y+Eb(NJO$tZ&;IzX2<^d0H!lE? z&;oH260}=yZ}Z4hqsr!1>3Sp#y!)AQxQH>q-@Ypq2Sg(uzQV|Sz>qKZ0{}9IUq|vp z6F`CYvumKMC&JGGnrl)>;J%3MD`uqAs8mVVDRsq>AkO9_J%{SLs*pmRJ)r}fBB3b$ z3KF0TI-#+KV>T;v-dBfuUPXCawTBl3wgSlT?c?Gn0o<>s$Iz)k$YqoX!=j9fLXZhh zkO5B-gh%HJ4TDk@_fQK&B)sky*$Tu%KofJZu}X;@ncsn@D@~%lyg-#mH)?cY=sS=E z-jh(9@G$cc7#e5Lo%h=b0F&t&{dol+M$p!oyL~F{IW)SlLoHy(<&0+Xp)EmM$WK|M zxt>5wq?$_gmeKsEQmU;;-Q<*H$>>RmhF%0Lv4@rpj!z=zP65WuQ^Tnvn$K7EOlC>p6H$sOqCjSnR(*7p=k}W4vk}}_(DLy zir;zlt)EsrfX65$G9oEAtMRwMKnxNq&%|VZiol(K(fHw_lN*-Axn0)+#3}}dLQ;@c z5l6!5^Px6+ftav)|s{p_*&ewHZo5GiRw>j?C}G`{;#OS1%Y*D=;@A<{ZZqtVE+LSC>CW>n*nZ zE~F@D6aetJ_Se8Z1OrGaq$9j=@_Hr9<@AeM>LRI9Ajz$gxbw+ckuGOy?(8$D{vFl` zIt#P$uOhDS;#Zxcs`Lu9AIr!b%Zu*-G`V{3phU_}3wLmU232)g-0uxI{O zMB@EfHvjxOQf7E1u#X1-9KfN^0pN_i8D4sHQyc!Z^Y%@rc1I2w1M=f^FMt6tXoG=>APE2Q&fO9Ikz$2V6{|dmWqS-_wN<&;X+_ARY zdb}#k)CLf`SRy|ze*CR}y3fpK9044P_M=XXo!)Yw_BepN1ZpMx(kN^E^#~v<8%(ox zb0H%3gKIY1_C8iyI57_DW|L&T2hi6eE@T=21e<$6Ry_ek{FGY9THS7&&J*QQZDOaf z?;v0SAz##1&x?IpPN{3NYAX@|D)w?Guna&xdsEaTJK3F3jC!xy?BN3#EC{yY3m~r( zA403$z{a=w`Njf~8g;s{dL#hLJ&hV$y!Fuq76KO&gBIV&wWHm3pgDJ5w{08co11y~ zv7hb1t-X~bLP@POsuPICyb|8*Fzpurwuc@_pzR+>wYjoURTe=2@JLl?Raut+73~Eg zty7a4S2vzPAvLoX*KtJGRro_600?hnN%0+UtNFa@aELch#;=RR^Scb7!zjhxdRmj< z_c3q#^X)R$XrnzYQUNpqa1LX?m1E%&a5*M%BEKBJEn=ff>B@D}PxGH803c}A@9^5y z|6VOD!6M$z{@)PRQN3UC!ep6V&S1N?6OeglO7#38{ndjNxq zZ^@{(8xzgh38A4~eqiQX9YM-G3=~ih0sv8W1vPr`b@kT!|266y03m~uN)MV$P z!1UYg_&@`I(gc54m9%e}TOyg3)v22jRiVC4`U2}W7?rN=ego3IutT}Ql+c5~hr|nY zDFArBu+O+*f>eJ9^s{;p)yz}CsLi?5o}H%sUMB|EzL;`Ed;^SJpf=NOA`QkYycq#Zvu)ZsxoDvcG7=BE+eoq znbn%~pBn+7(BHIeHm+gubs#u@VGg(i0JWbqumV8DlhSN#bw096qm2E~B9~){%5cCH ztg$os9l4pKSkELTb67u^_clM@lEzH#0sv;*1$9Dheai!W+5w%K%*an`20pEvyX)dw zyiyrhvZV-1P-WAaNqgST=JnLMr5)JlMnOi$06=lhI13Pk_Z5F~XcI7ukXj1o%TY^u z5PshXAVUh40-ZV)*^dBF;i{H`&BjI>XR}miHU@w%Rsg`p6-F1GE6ssADf;vp5Zd=K z*bV@z2w9K|y-zsZkxKx+SX}%}7z?n(qoJGL-e-FSKu&5@SjZ6C?;b#E1jp`u`-Rqr z!$)P4$C;TQxHg{V#ZOBEBlS}I;jY>PB)e)2y8&#B{tztP5cdqESOMc0a$?* z01ENvi^kldQgOu&4F+b$1ndBS)yznR8&VXG&jN5(8LSV|ztVuWoAuLZhtl#cfDHg# zsS~V~rb4?M0I*r8U7_nh=epCsqADWmkylLxJHjrFH}qajvc{9SRi6326J z3j`quLD6}Ov1~q9=bo`t7&-(?<>>YqFnUlaw+eKtazCD^Y z6dCyRk;)g_#x~8}(?Rss+*=k7oIt^eYBGdZWrd+Y4@ixgEMP+BX@JvOHs&^dyP7L}U=DuSt;?W%%(pN0 ze3uN!HR-}sPUl<-X6MkR$7ah&mQfiA0zWTv*uC{&xnVj|$eSlIi!*>8c751ypp^hu- zJb3fs^k#}D>+FTucKj3LgVxljF%M^_X|K^xs?-SUXY0~>f>!}dTAuCkpv1!+I(=^0 z8O4t5$6iNK4n>PH7o(|3N2f@mAA$A&epI^sy8I9T#5T_Rr{ch{oy__)e=0H$&qpMk zIgeBL!GN;*I#iI&n*8@Jo$d3m5pm%F(2X;S8hHbbZktAp7Iq^L5cA0n0I0x^DpD(* zpmB5MH!rrWue3bcu|6{awbSk-yDik1FKHEW8>3TW23AQ^p!>7)` zkf+ND_y}Md*Kr+xuJYM;aKb!wYOF;gj+DpEolOn_Q@gv`1yf5UY-{`1hsPXNr%6kZ ziWmm-OsKJa5P*>mFHCa7zpNT^JeKOuAwpk#O&Jv0De4B5unAFdG5Vw zk)0conHpUg^nChhm|oKB9(&RirB02JNupC?gi4LBgxHv7F_W(Wgixc-`~*(Cft$Gz zK-i_sM8A&A&IYW{2CUA)Y)x1l9U7fFYtVpIJltI9%5b_k^f}Oz30RWA!8-g`TXw@G zs0cr=r2=}naY{AYHN{|ChLRLAHM-=a^BFqagT7SQYaTEg%O^uB3}sacyWS5bkom#+ z8UT=v`zv1t(DSg$R;32M(a6_|HMT1UgIVLxu`>Z%*79q!XwwB#r_OFkLOXQ?s1b5y znySES$hX_TM7OkkGq>-AQ)<*yLK_fe$TI zrJ?t-alk!Qrqr^Ad)DNMlhq#LnX09#%IIYGH5*l#Qg>_AWJa#PtkXhwTIj)a483xp z2+%J>MSAkRn-@MA`zXn_Rru(=f&{MN;AGsk9lJd1zhMlanvra7p9N$H=iY7*K*fOE z{`>d^#r)D4alL^twhw=v1gTL;^VXEp*2Ah(k>PLXwuZ4I0bo%(7e<~{f5=6DddWph zdhjYI*V1)Y!mieCw}6)BnJ(jIt*j~P z6KpyWvW{KxTn4bqJ0CTvQxtzwGJTe-0Y{x$sU4RWfdy_)jv|`KWo`g(tF*OPX^1YLv{tOu0YX5b7QA4Fp z!PX-jKJ=wV)$HM&c7vHc%%yL6m$W6K+zp_^wg`ToX@vmBja1{St?ajQ*|WoQ+}V~% zmZvX^rU!uKTT5@4;t&z6Ody=6#{|uO35r*! zWlnY9%c{Fjqe|*g-xr`KH7Qu?0x+yNuyHy#tg#Dgwz3JiV_Yb2l15_-)*%2)9G&k@ z(q5N7iafr#`YtiAe}N=S{6OU62U*nlcEDrB1R zLmq6=`iXm@Znh!zX_wZw@xb-g_E&J+SV;A;cx;h6ePwxvg*lAtGC0SN_5mpNM;$^` zBd`aDx?AX)s7ala1x9v2^41mNpk97J3ey zUd+bvor!U-?={n@(O*VCDbDd)fgRt;;&LD!$+633+)~NpNU;= zZyrNfWmy!~gRp1+YW9d=_9x#yH|G7SqdHX+@Nxv^38@qEv&pZ2GJ6|`%`Qn72mPkA zD*wwA{>_N#|oKBJCgi+QH>g~7prmFq>!^SF9UlALF!bb z&PfXZp!=q-GiDZUb%KY`60tA z8gVHXdf4=U)X88+TN8LcXMR>-wOn7d^k(}GMhlYGw{SJrtwR|N{I@$xX9ITm)gS=O z%&Z62+F@H1!8QBTbI$HnaFyzIN5zvZYE<$DfWkRi5t#QEMvMrYpBVtgejao+;OgXs zH3ER2&HzBczs60@#LR5|r!#X+okZ3CT6{oYOhA#3>))^F|9?en_X41Q$D5WoH>yrA zFk}fX>CrQzZAJLkfY($=jY1BllVAV7cV_C;*fQ>QUHX=hp+5%E;v}#-Ars+U~$f@I)uR25hI2GK&E8yQ5m+&0qic{J_rDc zQn!O*n(V+Le*Vd-8(Q9)7V2-WAW&JxB$%jP767`lCbP5qP`lM1UXG!c4zB}_SLhTI z&W}s`J@3gDKR&5vShN7}MXt!*A`doBITJdCV$dWwYqjq=I4;dO?FniQ>zRB6e-)1*={7E z%q>>eWL1W*qZ$j~$AYD+4UUIZbAYz0=4&@VOIF0=Ll$oOzoZA}CcCmByF6Q5$L3ex zo>+p_>jjk`!*=|DBiLQ$Wm~owTyEX23OW3ytnJMZrenwI?Q3-oH?F4cC{Uv&-C2xb z`@gQ@8&SK)&Yv@IP0RmVV*3jKYJ=8iIhf6vBZ7@yimxE(V~ra9n9nj>mD zv%HdUOUO>Y1C34hBuStJS1mQd4ZzCQt=N*gZa{-&cdhF5mTROhvp-tf6(|xLL7iU` ztjTcBFbQivrX~X!TYI(3;mW?O$?B}aR&-^@fgAo$h-*>}%(K89@l&4-Wo9SWETZ_! z9IZArYRtdJ>_6ti?jJTe-;|xWrHG*!3t(s$iyf0S*AZ)<-+^|kA+;2l1l~`_2lUBQ!43!6 zUgn(ll4F=LW~6ZL(CYWR2`q{5`;h&G*_Q5XIpcnTW3yJxYnnSd8-*F)YSPnk zsM$xftc~zy%l`w(i3cZ*nNoIg*cbI!g8ozq3Bn-&q0#UDPZ|F0(XIdpp-!Dy&mXrW z+xXoYBlWBQ{g=JSz5%25WMz_1Yos%)^rrW%#g71+$7~xH8oNrvZDH{=*RmDCPy#32 zz4m5)zWcrr4j9A;5_K{jQ@5n+bqmZz$OByT=+Flru^=H;>A}j^&Q&lNZ<7S;(}0$N z08rd9i%a^^@6Pt808q;O)Rwp4V*VU99sqhh^myRvU@}2&Ch%!s<&3+NW!KFDaI`{| zYhKg{8NsPm@CzD6QGs-m9x^xo=LP`N&H+Ha=_+&aLNy8(T zrbyjO{E(13g^c(#t#9n=-H<(*uX-RsRx!+h*`QK``58^GQ~9YVDcl)61k&uvnXqQ@!3vLlL|kw8li+vW9R|^qYfK^giw~ELY-g>6QgzKnIVe- zFrCXE3SkGV-XqX}=~*d0^)!=_5xr;nQYT%TGQZ47Sak++x^!dtAMPsvPkzj%WZ&jXgu<1eda6y@cJ`@!8b=Hz1Z!IY#qLX=E=3FD6Lh6L| z%Ok05H0&;KZm#t*hg>O)T2;dp0dq5C@BC58V>wP13IGp+8QJFfH))#MG0nda3$mgt z$-&>`d>C>Yl^gP2IbgH^^3xXE(izOI((hQ|+h7jXJirV0rfH4dyW zi{QL3^Z&B0JkT89c7hp@t#P3u6>0=OxoG1a$Z^2XpF`%A8qzlrvIsq>Q^=!(fxA<{ z#e9)@!wfYJ6k~U*JDGXp9{+?+bbn6Yk7fejmCnzs%n;Y}t36eK0jD5Kk%8XaUhPeY z?T`W4jE*EumU{9kIKz5})R>O>S%$7(*Wa@FB{`aM+*eIHl%Xj%_L-_tqbqAxdAWmr zZ>eg&LxnlBV;>LV?`_q~0Ge>zrBbe2EopgMHvsNq7*-}DixB`mWktG5A322ppj%e= zuuze?IeTWY4E+h|$&Yteb>)lUZw`qEfXF|=>d%2?1kX)>q5^XOl(nNI3qMJ3KCBvZ zs!CxZxN{%doW3au;G@bdVnLPTyB-9PpXK>thlZfmnnA2bW)lzV%6X;%SBt*Vg)WIR z9?p2^^~l0tei&41sLC>x(j3eJP=;zU`#pIgr$SILfGs(LC47o{jPuy!X|vt`{n%c~ zi#j#dVG`))a3Q73xETaV-@fc5+J94)MJF$*4#cHLwHW<%P0!<{W1(#9_D*jdU~>eN{MCB6FpQf?80zcVEM>!`pQ%=Z&e zll`t`zwRS(z3M|>>$w}Q58HAffpS~B(3_wp1;hU~qk|ra>%rqZBUTUn@hnh_% z_oE_h+GTXYjQTb!t~!B&_GJ@t=S|yeS7prdt6*6Iz$d>!YV_~%cjvD>#f81Y>l17x zTk|`Uxzm@;WmT>T27m$wiqZYfFRi+aqrlCMH<#T!^_q*+ zx-T-g%W9Utmii7kZ>!YlN+WiZ_9Fw0e5r#^)=2fB5=T? zeAylqAPPP9p~A4)gQyWG^tZ>Vb{A6Tkm~?2D|{;Fk;dX3p6_uIa*}~w(WSLQWs>HwGAbj1n@8{xY*{#geR4)NqB;aRJjY zltFtk9WF?}AAy1Oe7QM|h4wgrFb6Bvg~9Ca;J&|JTG98ZOPzlF?nR{Ea~>NBU{j91 z8KLb^C7MXA_mr+_bNnp_I+FgoKJ#K`Rv*-UQ#$5lQj%Q%IiZZ8&XUX|ef|;Oq<1Fj zgmuK7Bh`&h9%OAD-Si+F61o+c=L*nxhi&2XV4UCC?k-NX4q*(a`*981jN6tgOGPT? zqW_}Nw)}Kjn1TM>xeYkrQHUcVfnTTM&h05a7n!Tw-U-|2Re-Y?!OUEd=9>0sR9;%B zII!+OYHUrt^ub!d>r91WUc=DJdGp1)2oLI184#290{d%F*~czsomIJOt^* z*Jp0Y91#yv1u7&(!#MdV@Ck)BDmIz(xEKm4j6teE1BvfT=9=jQ&8EZ#-CnfFJj!acN^LfEiwc!fV=7p-l8Zy3ms~ z<8MX2zE;wc_8ZxUpZr~waWr-6%*VwU(sttAE@mnj;dA_X4KY9U;0-8R~LY2O(#R)02-99_;wYYdXsxl)(2&+!jL?kU# zq#MgfTePS8CSZS8$Ku8y0`=U|Ju*brhczTIa`=|x>u{a?zj`z%hM>xW0Rm{~@?x!Bj%O1Xzd5%wo( z=v=`{3>oS=LQEMo><6_ zfusryH`DDjsneSUpC4=zXh7-Gmwz?{n*I()oKk+=5m>n&)TB<8QCv2{J1D4?s_HhShV{ol1W_Y#vbTWq75rr5(bV_u@HzoB zq)|ulCdcu1CGPl8vzH`kX4S&`d_Vi*^acj-D&q>~WynK~nn^SL!rg{`B&bnv;>EO? z;I5-Z6D{WSjJ#Tdax>S%*HcTB>`hgh9DjcwP>>CRYvgRq+5`rA8`=KL42b-zvBX#a z2xMmS*0j!=onRQj0@efmwi`a-5%?Z=w1P6?d2_a6f41(hJouwOz053x?3`B?*pw|( zyfayI@2db%agJGhBfV}OjtveOw4f7PvJ+=50+wCYS(wZ6+ZNx6or77JUWClZFV+HO zYSm=5?S@n0!rgYE9WXB9761&nmz^QRotg(OY_9qSat|)2FcyH-Q9;qw2&?L#iWI3a zKa1}9v%#yKr#ax}N(*(CSo*g+UTb9B?kul)@*4q+t6cerk;-RiD#5I`XYL5QVnFg~ zLx!++5>6d2mzV8Xh=m>iUBqVZf^_hMOY|hh0YCwI5&$l}mxbVfX+Zpdg3rHC_f6&= zGd|(*62S2ecX}D$`>7O=n6Xv0lC+_-IwQLPK%dT*WWmckMiW;{ReQn=WP^hpN&&>8 zqUJJN8US_<=*#{cwulj57%oUn3h93LvPbz^rC6EeSh`0cs=Q`i@B@b28HPy`O5U>&R zSNkT95rlb}F^od$gdFovR9dYlXd$?G)a#w{Sb8``PFy%`BvfG0a^qoIxU0?UzRm9e z=tWo7fuI0|6io*?Otn+aIIOipjw}-AzJgMF<7UzD? zgB9YAwFN?sW@1 J9WQu7&Bz+9iLf8$eACk$E^omUMWvON|?R3jkWjRT~Zff2cqD zq_vjKK%IqOpk53&wzKD^R^`mZZ@X>m0KLaCRsFL~P4@0Yh8xeYz$du|s+vRSae$f(pYp zfWY@!@EWs5z7|22Ie-_#yULn+}G3q~;9>xN= zY$@npmM|&QjYpZ!=_0;H$$)ew6N`~8l{TaFu7UiPzvXI>J`eXeKzgHYfG*VO#&80g z-OA91B?5uMTwVv*6!)b)&CZ2|*`GxnYHf`NGJ}Se+2o(sLAzKSQs50+n6nU3|SvZZX3RACH^-F^!I%EXO$ z140W-3-Y2){oiOlQ*^iA%yrv46)wnsH!{sI?qlJ9?xRj6@6W2i_80nJ&2?rgd&Scp z;XtXz70eoJ&7mxOcCv%e=Db;(-c+m^*-{qxqPuH; zrekzq*Z`e9A}0UOLeP~ORr+%Ri_zU)s%IlrT1Z=Rghq}?%%u=asWh7qs}l+^8OcRo3qD=i}inH z*JuNP^`WJDc-o^TIw7+%(CF*RSy7IA7X}bYO=@)Gpftm4Chae@+xV@-&l3(OectSz zCWj{0J8~~)9@gMZB`^IM9q83hml{pCQD$Vm$5WmpZ^gKdWZz@QmZYvx<1nZg)t zimJ-;H+0js%gX3Vi;tBr23%_wzSYNpi^j-U2w?x?#pq_Yg9U?F*pla4jV=)=-;B9G z1%N1e$nQqmt~{8z*@hjdu=eP*4=0qLZQP6eq*wB7f43qV`r)&ke97eWtrbBFRc6}! zFTW6A&|k`Pm0op-0Z)JbjHb}sGVoaipW_ID^MOa1QXJD{gSKy#)^ z#i_GQd|z8Fs&u6rgROb*Sf0<1JCm(CVdt+kj#`93#j{BcOtx5{DBT%ZqI0b(Y)*oC z+dAR20UX7zcsl>eI1Eo~P0J$QW_O8dMU!jOrzQUB+XG(VjEx@|7VTFt|MCm%jvD@b zMA;Rukfc4KN1@+fXBp9@%BZI+CKw)jwBcRLj>DY46Bn9?V7{FejMBY7;HKZ z0ogpLn_UT$p@5YpbbVbcdoNgUqI?M4cPmC4?&tvkx7rc}U1cNsj0ehZ5>jO^)^|0+ z6F^Ugl0=LBy45d|BJXy$Oa^kkR|$uZW*;^fEvTo+=XYlnvn+8bg$wB_5JGnF*?uM9gmE3=#n-ES&%gt%0p(a@fCnyA7*1)4yvEVF4zD+voNXO?Bt+iOS2?Dc<<}W9k~Rc z6*Z~TiyxGF2_~AJ4~$~6p|8Mx9E*8XRnwsuH$O7D=w$JyCUvIg@Z4c|lcNiO(?j=d z0`>}^8G!ufDqEWovZl$2WxP7AvSlHpPQ}ClYyy~*r?wkM>b}H{igYIBNJo87+j84n zy{|ZzokY%{<%93te@#xH3~MPiF>^#m4z)Omw4g>+y0F<5*&rmFgp%+5{Q1nz&d%KV=DS}#CyKT0Gxle?C;B+|l9|)e z=3R(1bFxhdT)MA^bQdfH!`O!^72bOm6MD9osOJ{5Bh1))p9X-GDgJ3OR2j)$^fvLW zV1I(Y2Tts+nbc5C`TV|FBSgHTyR`I5FbDoY@3$HUuwx-BZQ~h%v^Wea_Tkcd^%sA@ zDcDt78TH#LpX^DmUDN62WDxO&^80grN?p*XF^V_YmwNzh(kw!wB1YwLkp{g8=?QM{ zl|8(A=faetM?x7lOEe=ubY_q!&2fCH>Mon(LYJ~mf6BC}LS>^lzbTc!G}Q5)KUSRh z+xwG;JP5Js>-X9KK+Uy!Aw}j}MG#e?(T@+r183YfmhVCzSQ>cT~KlTAJ^vf=6JgoDiD3)N=KU>sGkr4J?{O^dvP5Zx}z*@4L5%kZ_ zl8#yI=s(KSmsMDk)(9thI`msqDfLiq6OAcXBn>kkbKs!88 zRWhcfz0*}X0^wZVB=gwRi;9@W5oJ83lMwsSDVYx+`AtPyg;mt%Bm6|7Le!fX!J2H# zXeMl)_}`*}N)KSNF3)3}g`9&-MKE$YKK_p`c`e+k!PyXn6=6m{oYSe3xjQl)Ehie~)I6TXRb6SE1a#!cU?PEAx{U;4Al zg{j=Wg@z%(^ z-Q=N1L#a`t7Z*L3yW-7dxuu&7pAL<_bW`taDgvun%w3)oXKfQW6GP-`u?v05b) z<}-n@lbVl>P79YXKY+d$m0?Sn+W9OANMs47#m+}MfNwngPWIxGryrVuDOK5=t6nHN zmE8b$(MAwmGEr zyx6tj3pNR%Z1Iq7obw0g<+rD0=+J}>Hs$f+=L2X(p-Mp0w73uWrrM!+`7o^(mz@_lGcC}fFNsJXLgNUzV>?Q2=c{031TeVr; zR)$4>b(GGwwv@n&O5FoS!?&T1e)houUzUjfD=W-pb<+2>lbML&`oG=y%wqtMLX8?L z9ec;3$K8YcOEn8>_G1F@@~)a}$0qa^F`^a^)o#de_9z4x>YV__o^HwCtIWU76QA*g zpE;wU3XOFxFb+6Us;;mKjaHUBeb{#MmU2rizYLWseR(`O&o@vNmEzo~QWcN!=BOPU zw&2}>Gi<~i05;aI#LU(jt8iyk`tNAECuL8y-H}&~Gz;wQ_ZOs-000b(KUR$u7|1xj zF&BtATUm^DAibCVB^9C2m}a}rVRul3*ZFecVw5ZBgURc zp~YvF3COfMV9Y>oxtS_lRG>7)2LK4`+>$|)$1;dNYy|4F0{ih?$6tCm2BC|?!l-bW zRGtJ{30kNS?5mT|t%4KQ+W_{7J!7j8RG$zANL#NTV8pD7Fw%LpX1 z34_H@2C#wXQ3x5@G&HQ>D@{lUCxu)u%>JRo_z}JioxwJGQ4<WJDtcT92Ag z>BGSd^NC=fGizH|cdskgOv490UY9c~N2QtaG!U6BOL1g+sr^>j^0#Qn$O3<4&(%$0 zs;J1x)a+h_Xm_s3KUMd~k6vDSrvd=uwQ96*uv`e04fxcgl$o7pt{Dc5Qh?PfVfM&o zzK&LoU!s3w>HKChAD@}_R1l+n)NObSRe8SC0N#F}>hPXy$cmy8!?|(@@a1ezw&K-%M$s8Dhm`x)u;7nEmSP>P@%!Yq&Qq7B= zZ7Wq(t`=R<9o&AE9yRy--c?HzkK|5WOLy>xK86+Gtl0H zRk);ai-d-(B08DM*>?-<7BS$0-YNE>1Cn3p;HH~WPgrQpLh0;9P^G7+oaLpv6b|fA z-l-Z+Rrv6!D*E(PbCwicKYpOaun)rQUi4-I5zjJg$9tQ;X(_zK)@T6B{^M?jSzzK% z*E>EPz}JnMFVcbdEF$6a)I53K?G1&_eo+bWGO6huq+?`QS$+TnXk)wy zH)o^5M0Pz_f+_>K_|vTRY){#tvnN4bdcXqn!-FY39d zVc>-`FxhF>jQzKmn3fV!#oIS59F^UP(E}U(i8VVva$4}tAJQADKi=PB2z``p8>4Nmcm~g zdVfOj77w6Fq1^Ef0QDaIJu%ZMGwd5SK%(qY*|^Asx7A{!o>*`2 zXa3Li@q@2$l&s^6fVG1WQ_kaxmHgnUJZFC--G@&Xqw&Cn7k8%tE z`fRzpnSazV%z>kf++(96(wIn3F>y;F-Yy=XRcLhMlby0!-(ke&`=dBw5skB@L*iNa9XlK}dkFlt+Wm&yM5<}ndw zZ1ilCG6@Cv4x}^JQGdJb$T!;G`S-=!-R&M?#hf@(A zT(hJg1F^got#whMu{`(ORQ z_LKy3K*%b}xcIt)<$TAu`a!P0wFMLPp0AQ8N4Vwhjfj8+;8Fg>5=&o1L| zi%KnoFo3IPyqS7q$DaaFm9h3PCO)mtyDm8F#lR(ndCk@Sr*}<+^1c9PUCa&l!lWDU z;lj8;$p`D|!elgmc2 zx8UMh`MH*n%OO;%B9u3asd!Ve-am%=;B$W38qxt&lx=K2JbD8P#(nydow#+9)2uSYtY`)eZ=GLFs}X-)zt=iVU`#a#5wv+>vfpt8h!8&S|uL!IB% zrzNBLYj}Qqu8pZ)^40^nal!Q);Cce6`L)qrU6yOd7OP)gqz8b~QHkoAmuX9fbM1$0 zPlR}BHLn|h^|Z^bFrjk5BWcC@mq+O&5g=8nq5}bD!H(T(OEmg`uQB-absUTauUHvC zM&(`Ergw3pMpb~{zEub}{^DeBIdA#()V!Z%I)Dz#jd;|PB{z(7O4+*u!04j}P=q%d z^)6PuJo}K-Au`+3AtE?#N7jL&SGE|FZxO9qT=!f<#=Vng+c6Em{jxmVYO1R#pmUM? z&gzCe>PY^Q@W6w6y(B4IUH;J4nHQB|U3c1GAG3(IyLlZ9hS30;7VGA9q@+naXdvh| zJ-Dd45mc`S&{D!)H_HRe>rJ=@KfCz9=HyS^_Rdr{6Ujfg!_cnEMZaF7aE$u)j2YcgOU(1aECcX-`=2zW|mD9N# zL^GS-WE#mn4%iF|J6|&Tt9~jS^@mOt8hrY*0!l>nk$h??UuJbq3S64dLX8@`<(onL z0CKx@B3{0cHenESRN=nSIh$qD0etwW9<2HB<)mT-%}r9@hENF(ywd!2i#eyK2~Vz- zC_o?npw}xs85im5U;hd~$LIADm6hKODdd|!7gj+k)QnXHasD03x#$KaDgu~vSm%7S zuo720$&b;iv@!iErWKbSa+O0h44$5GwWd!mO~tN*qGZt#G+~eTU{Z1{ z`sIw(vGnlaJ08>sQJaI70@LmqKetU#9U7G_jT)PASDDNV&3*t~WM}jUiE=&$!16As z4vc4Rro%9;k!#XYjdoZacz}vfPT@=!Ba>Qwtt%RN8R9F?XAxz1p+(M8!6ORQCRAjy zCX)|w!f#pUTj^2B#JvT3-$nK|1i(Xodu0MoiPBuv1MoF$9y$)TNSYFww4pTt^g8Nm z?qi11-@i7$*K-oUn9X`--;I-6uPXW_npP=PzPEF~bwNtR(lxpaHQE@>CAm&nU38x& zLj|Lb-tlVIPO9P`^drCe=%2B8v%6cKhX6~Ya&b?ik9Ns_6q8XSJN`oQVVl{1m&`XS zbjz1xH4iHT%1OqW=D*z{W%iu_hUs=sRB(xEOvkGc>+4_7DFF_*DP>p#;m2=AW%sAY zT{h-NHJN0&`;_)1fM?Fws0ssa-i>YAFIRvQnBY-aPkf0@|K$AU-i{@x36&4h6{GqO z>6u^=dn-MI=@_I2oVQY=A{u41Qe2bT&wVl>20+YyRTdh;_*u5J%ywl&lvjqXvL0q@ z2<}3e4&b@YO)~>5VP)&T_0JNv>Rx84jEgn1e(L~$d6ma7d4en21|R=c|8*~}ot77# zqym(0x0aAz(!v5(j|Bia{UX~Hg(v4cn=_{|MTQeLHp=vSkuwu--)Q!EfC4oC z&d&_6EFyv%Rs$@h2VHLL)zwMrQMtb1xKZia!dv3brfs>!mT?DwVY47vW9yAA*g4tR zzp7^Gp?UY54LjRjl@zC9B0Jm7-qCDQ2|&uFBC5>f%jXBSKepw>&3$ipPk)J>t5T&W zA3O*QdtRroOJ%`Wz#UkZ`>}>N000)!NklT2_qsh4wiSQ{gJRPX35N0f zO)|jz_-xg$GW~q;VJ_?I^S3^K`+Bp2xLyXu%Mh>;|7mbb4x*mI9<`%6G5czFNH#+k zFNEr824HD)Hpt$ojJtd+z5fT)G?jK|wjqmwz7g^~ZhtZG_E6h4f0*z@j2?gU+xKc( zg=Q8I%5gG5l~x9Q;p!{x0pOkti%_YFNVc>txOEqGPn85YuF;V6a`oA}E00tNk);QS z2Y9kn&S4+ASCicdl}HbuhT+lXP};}jke`(!yWTF&LBeIlq@9Z)(CDVVy&gc%xKtV( zJXV%w099%%NqEh7Va0F(fM$pEOnLwZ#NE=1nx+g4(bY;3l~3hoz}Tsk^^KR|gjK`} z=gFA9D-?M|m9YTO!nCwIwmUBBy2(a=L*sw424y4Md&m3{bZf3}(q+Z;OJN_JhrWPm z3d=YB#w!a!pGHNDb7A7EXtyL>$0E>mew0BHY@QA=Amw~oU(Rw}3*$nqCP9cBEjx7dv@TO26& zyzTvJ?9bDARxI#xAmh`m?x$m1cb#vam#b@k>hf(cwRZ}@(r;vi%--c7u+T+kKJ1_P zvL7{}(T5AFJ6EW2)Kg(rE|ei!52GH$nGTlr#jc99FnyRk(0iO#p%S8W5oC7tWY)L2 zCSOKghAf#&5af^Yjy;il5$0qrL;^Rpcf}o?1n}HSIb|Z+{tFM;EhY0MT0g`>`^~fW z<(@fc-`PfRTP_B0YBNu1XKQhduc5RCwda%Djm?X`r7r1z4P;VK_J{5#ZS$ZkN;|EP zR_@zYN%ZIR+Rp9MxXYkME5l8m^N-%o+wV*V@G9MeO{hX)dwveeq?}iF(KIba6&Dq?MDf`+&dT4DjbgoqZ z7-41)45g)4MF|WPp2HHHQhavlSM4d*C1rhG$`Aw_^0i0uodp2^T=3czy}>W@ul2(H zGMR!IyVDs>fNp8QXFe+VmntVXhS$#fm23d8_8Zqd_lbVB^;R1Z!4tD^yGeHt)i3GR z)`MGqE$H9-ETFE?bHv`9?2sy-VIcgmr&QVpwi?BWrbDxO#s>g3ROb$7>nuDz;{nK~ zXx4QBfqnaQ>yd!d73kL|^Cg@SUY0g9$Wl4}N9UGSBiMA)`wv6H$w%gE6P^lJ&G&Uz z#`>0%g)y%ze4L>B`$WCM?X>#`o=`7@zx_TTP0HJtVNAX_Y}(z|Z}FuPatUibD=d)XS~ zngx*Ez{4CA?o>d;1xNOBh$XYKqk)f;?m@G6fjYm-)R!2t@K!KV<15vcDqEiGp1eKv z6}m!HkdMd0kL(5cYvp7uu4Fd5GlRy2L-KY2c-jmRH($zmmKw5jQH?quSf&g+u79r# zr<8Sc8;JUESai~9VHI&a5NQCJsBF&MBKv_7m}p3rt4-dUnT6GVE61yOSq>My3rwGG zME|u|)M=$20AkG?`l}BYEcZ}>%fWteQf(|OC~I35_svpd*0EhS?wy%ZnZcCp!17dM zqO9i8oc{5W_K+%*oTJnhbzC3aslrdnnW2nwF)n_EhnZBXwuU|ckSx)6Qkffy0A~f0<&XxUe z`^(9xW#u~v`#ZlDgiZK9qPiRn@#29jQTJ$|k)cvew*wWP*QC$-#E_g_3-M1I8}qEW zSwErbep(q$Ci;qsd15|b=fR8#vNZaAT&F5UN zwg;k`NL1-1Ph?M$smVt6py_rXSTeZuaT>fdmwQ4GnJtagRLbr( z$_$VHUKCIFG-5EpubfPBd9g=_TbaJ)Cgu3lI3tR;zj(;iRgxJ1#;=RMR`Cxg*~gu= zWFvdfcUvO$Y(@xS$w`*Er=^F4d770Y3G`5$0qnj|D(&Z$@0Sb(D*gG~2aZR-P2C=b z(>aIu0U%7bkl8)(&hphp=+Htevz?QWKPMLoXn4FK!$ zT)28wlP!S%ty8#e-_i}iW|C{w!?;tW>LsK5r_*_$FuJH(BzrJ3`>E2#;ZERmhaf55 zOIGvyewOp|kuq@?M__bFDT6gq)Fn_l$I+$WEz@kD40V20Y2`{wkM+Hu9sfS1z23mC zkZ#Z7iDB->?qu(D71(UP4)wXs1U&BlmF|pKMRU?pIL~o9fKBI(IlVxxeew=f*wX-r zcE9VkLSv0{h4HJY$?mi{wBUJOrp=l48+qO;y;kPbLNu0Y`XJxEFTlhEc$9Q^wqGXDc3Ek$XOz+#1xu?LLpcK>6>X6J!ozNtA0}w3%ggP*L z6>0;3K&kZi39Bq5*!V~WEzZ0Bdm={q(KB*U+HK{c zAESie&bhS#z0g~U6TCD1`TM3Qau%T(3rBsL9nwvYmEQY~&%&K9-2u#_!3t*MYkhha zu+q9a;LLQPzO`kSg>M^0hfpURJG)mS6DCMH8I5~?p6gbehB&FTqjOQ(o#iXZd~tF% zr5*FP{#)h0xFXNr%3z%kbxCV^YP2zilf4~%`3SQuXz~9F+LvWe%?zvTd#FyJ@T+l_ z!dBYXFdxH}Mc)#nq7WmNogbsa92JZN9vlQK2m;7plj*B4K4*xi%=ObJ$u&%NGE%-@ z{>{Q9*hwf*(DK}wTpLwtAP@v#!J%A^Ncic8uM{W%vctPHU8QgNp0%gh0AL`lmEbi% z0hBM%eu)nN0?16jgaa6wW&;4I7~}I&R6#}xzoo_hdeCA4kRe(hJ*WUcBJL8I92O)a zPa9t#3ruO(1K2z;;glpTn-MX7byzh^#UWIwGMeMEFwcDASJ$r6Dm+=5aR~+Y z)Vj6sqD?}9&b*AfOHKml5K>>}7%d_t1F#jWn-JZeE6OcHOyU7O=2vq74A+(${j#I_fA0X$XN}QLssAs8soCg~ zwtZ&hXjY7Rw@P-O+%>WQz$4%K=;dV*z_sUZ^QM@*$w1|cD$Ql>9-kP~*px?Sa z97_w?z7j!a4LzIOlJt}ktNjCviwL-?d$xWj-mv91!{E0pH!vnc+8xlt(Qxj{MnB)| zl3oJIT568_(CX0t6~ZL%>{(L)=wBeKmkwY>Kz|vDKt!^C+-=(}n}7LOZM{PlLxnqE z`nD+MU%ww^^maM#NSI)&DsA7Oe*j=Yx?VYR;|qOqwd>0iskEQua?F$ikZ6v(Yh?W- zdY%qeWXp0jAB0qMu(ZKU_RgtT1xeUhPIrr_vJqQYi*`=gQnX6zld&oB!Dmzeiekrr zO4Zl8bt~K}Sb>&*TLCD@pw~0btjBKr4}b!&felE(wD8)B0>I9h%YJE_i=~C3ap}2u z>jD7b?88*r0Vue}bz>a@w6l|&R)9kNyhL`$gK+szLCDz6K|Dby3V^_w+Zv|YfiT?V z^66GhruHq2=YaABJL8aDx|(S$mUQ;{%aK;ID67{hD-F==R2C-u$N4#DEHkY4lYN~Z zG3kJw+6v>x*?=~`oG1rr*!;1q?LVy>+k{nU3}%f}k9igR%A5eOKBDbWBSGoOF_L1A-7~x%i*2OBkWjvbp6X=voE2_RkEs==uw@2d^*ie)?5gR=Y6PWjlZcts^DI0z@p=Omj}B zcbCc_01xl-H=D(~WgIM1IJF%e;_{tQ~y;TN~{hX@$iT;q@ zXUC6o+NP5@=HYWfSA}j)FgDxE$%i)C&b`6Ge=S(q4}g~0*Sw8}QqlZ;v6kkLl^_OI zDrwfPJg==>Raje5z3VE2!Cu(GRG~C1QtO#i(`lWv=MZ)RXd*3?pHrnyiFB92-6ba= zo3F@SCxk_}88hY{W}*PUMZ?w?OAa~GC33al4SF+l@riqidZ{keH#U0P>=zvVK774i zeOH-y%o!TPsCjyN$|9=R>8bzCa1aR9B1nZU0MOz2Fo~O{ zFojRFzKauF|1RkO=KNGb*2+}Iuv0Ltxpk!$hI}v_!m1-7EXev`D^t_Ez3dx)%6T78 zmoFtpaa7^KiS#R@hN1NQcF(Y!^pREJ$+Qm6LeB1`gXzx_=}RtWp9wB#nFavfMtq^t zgULSu%ZnBB`Z68BlxrZhmW!v6;636n`(8pNgEt_^{vu5xAAqS zC1WpDDkdVVLE2}dKf5`f#=#<6t%i@+HiFc`mGM6Y$_96f24jz&Nv-rO_fZ-pd93uIKs`HjT*! z0MonNFDD~Z;lXwpw;LbDEg)NZ-eZgo3LBG)7=h235^XsVLmtw*~*DMztM_yFi$e+P)Tzdt29$L(BsxgZtKX6 z-#qsG@IJ#ac*gMDf*O0&u*d2T*M?h$*B_oVeBnrj8A+vEM@B8LZ1y;-Z29GPLyC1T zAM&?v-0#Multq+htJs|$Md9mRU%t96*Y+d;qD%SalGR-mD$87Q;Y%6!6|l&Jv{e+-bZgOy;bsUOD{udU0Z)u$y*mH@ET85O&=dXsmnu+qa4f2riQo0EoGfP2@JF36<{l(HX`TS1dQLvg_^M8JcvvR1wOd zm0wqjO9%xb52w{7%z^0`R(ys5cV!2CKGc-~?Pes(*WX5nP4o`A(9m00u7) zG?5CeB7o2ASyBopUi5#H^#I;0_4=MDGk2`gj~y=;uS}uD>09fMIpJ-VdaaCN*8|0_ z!oSNi2dYw)?LVpjTb~?X|Bi;)xRqo+fa9^1H(RjWQA7YM?0u(O@!AxL45ESKstJuYd#68+3JLoA>oCao8hs zQ@uTf%B&!`jioywY-YG+r7uH&TXY4uT^lCvYS9O~Ur7vT*q(4GU0P^iSynvRZTHVL z0AT%Xl^W9(k+EZTm;XG99wsf6MhhXT^LY-fPp!Dlbq53}te?209{mVmHRrV;z#5!F zxB83kqc3nP_c$4S74Ih3OM2w_=G5e!7{03~?_tHa*X+FW1J1ifbg%ARUsx70R^r7N z8>%L3^rr8XUKe-S9o77na|Qw@{T*@9mu@n+)J*IbUrr({FZlw%isFZTr^!wLz?y#L z#@x>^LMY6flm#JznaF!KCQN;H>Q#xzzM%-O6QFh7%q~;wt!>M4v^v;UjaEYVuo)AV zO`Zf4BNN;OG7tdp&XuHJJ^u8TgiV>GO%{S+BM#-ON4)%dm3XB@x;d9xFjw_F@@?q9s`V+@ecGi3U-$a@W@9H{gB%XTqjO20eJ9*H)wpSX3yW zToeHT!VCTgz}X|E&Njh4sGU(G#rXaU`Nj|2k%eGm{pWkH?8Aq)stwNLGJb;s3oP<# z2nE*w5nySCkd?$?ry*!jtPa*sfgJ(>;EBqp zfMA4Td}DvNI*3FWgd++WYNH##V)?q+g^UY0fPe4_&f(x+^Y@&=Pxuk(IEM^EQJ`k| zRRKFy#TOy?>&L3c2Ku#%FMdwNO6%Z7CIA3d`>jJ#ojES={`1KG{~;>G{~A^-pYP-$ayb#i5MFLHHm zWOH<7ZE$65UuI}@cV9C#ZEY@aZfA*5PDc$28VUda01Zhsv9(8xG5mQ!q2~kAck-qZ@^En4>udfE4Yp!yiZ9+E)iIBB9UDtYsDX) z2VTN!_$j`RAK?x7M||HvNc!v7&0tq89V;s5~RX6yxU6K();cQV5gm6FI#l8uq? zz4i*O;2ORU;&~_zHQ@bPG3*kr_uZ-{NDToB4q+b-;707lA-ok@GUpPNlE@%QGyT1- zzrm~c4t|8o!b7Hy3b2rikI2k>^>fFp^5NmNQA zaaAMV-FgX4d>`w0HNXym!*Ow|nCNy$uWX;yJ1;P7mLZo#LSNOP_#8Wg>mkY|*fMgyI)WSVcHE4+l6je^ltg-Gk^JS> zOL!44;ne^o5GC57iyl-3-j26`P;ebL;E<(uu0yfTL1Vh;e-l5(-x!Jsc+oi93n5ld zkU|lUJ%pQZ1UKW|$qY?YN+R8n2A{_jyl7Y?ZWklmJvoRQ@n#$Xa0vUL;9rjHf4w`` zy24igynrG62!D&~crnn939^Y4+=?T(75}Ph*P2M8Qg)##xrmFn=JDtlYJVKS0o;te zct_utyU52&de>?vYUdDgH8eR>sRov?45RTvo{!OA<5|xrj)L6;+t?%Gj{5UXhDmyf9 z$4$5y6UQem4CWnwck41X@O?ZF|2&aymFWRt062b!{O zj3NVn%LO=y+i-7!Xh~GcZc-+qWdhF}&ORK)JMqg&4UC6nxANKx_@)D&<5n;?;`YR1 zNo1$XSsr65@JD5iWiB%rt1wwBp60JQMsJTXhAHcJmQ}7#C8L$dj*|wbIVw!`VL^$Q zuL`X4(uriOT9Yrb%&akzsxg|XG_ENgW{u5sGFFM~klnOuP5Bg6V<#1V#yHJIZVo47 zwH=i`$6H)VT2?Kk#QIBQ(B&Kp(r#%_c>VtwmbjQq^Nz{-RFyf0>m!eRmX*X3Ok^-^ zlZs)Rq&!@l6vy~$JeMewuGxh-Np(9dmqMb*6B#5~^sr6r37z3gGNF6waEdOF?FwZ% z%fC~TaY`iC(oCOb)+0P<{v1ofggurOp0dK?Ud~X7jYPdC64za^#Eg$0uX3DKt`(C} zil5z>;v{Q{T1g~cvdn@{5LS0|mXawO0}HZhS&(jPCCh4JKPD0nndf02S4U-z^T|Yw zmDE|1o|POjKbcsPiS$=$QUFk%rZWi&BIfprSMWT=nMAE5(w}Kr;h0CrPi2bZtR%p- z*vnZS^GPwMIKz6f9VF5pb)q_~6D5V#>W5&~9Ryobp zWD*XXYz|jB?qjWJiSwFBx7Eq0hbl=i!*T-i9%!jC=a~sgF`rl~iFDuD5vN{;l_aaP zBV>tr53H?jtt5cBL^`~OWjs@lS=N$3?2eMUfH0E5iqi@2N+O++1&(`EwCd_48J(Rd zYsHd7si>A(Nj8u~wz+5J942t0PIil0nf8Ih%_VMbBJEBp&9nG#JW(gR$XfBDNEl0I zKq9S5GhKE}CR3d(B$H`Z$)yvTXC3oIk_Sp8x}3IJI7oQo~ z|N3s;b-%my0)}wW7#BhTa4UdAm^eOhA&Q#55eJdqWwYuWKZaKw@9o1w__qoY*&TAm zL8PQZ?RRr%ZGEcB3E%cvdOjn{d2FnP#_}#2&t|&pfmlgW%e!RpXdVxLZWpT)5pM3y z8K0sWNu{h6MP-!XZW~885Fx{}i6gzUrDoYDb~r7!iy33rr;d5D=*kq`QLU6E>(e^H z;_e&Iiic7zB&8fXRW?SPO)U3tETTcbGv%z5Kv#V%6tk8k+Jdq_GaY$k7g^si)JCfo zhpqkdGfB6}ooSY4TpV56uBM=_xk$NXJ4JpkN~EdWvR$LgVdHa?EbRyks+X-&-Zi$$ zE{RE(`M7brw6Z*(!tX1)S)qKw7za7)bqMdoTL2uv75oSauHgzU;}txEyFy1x;|s!H zU%&?=j&F+Mv-#&8@Kjd#aaqvaI>;q?^N0 zY==?74pg}kafDYLPiE)FRWdx2I6#9h^Fo`^R^kHjlm_dpvBDbb+fa(lbjE@D>5zQ*7^*Hl52! zX&>K-80L);EpdPbUCJ)H$K1dba@9R)37tKK%zGS-$lbp_l@bV4FPVSWc8myrt$^a)$?yxuWF3(?8AErhh6kOLzpFRvSdQJWt<(^;CW|I1iD0X# z;HfYs#qDkY_$$FZsZzd|sNuJ_q);*{sbRIa>>Vp&X4aXeYM$WZuG*}XF!F#wI^LfzV zsKZv7NC0qgG9dRD@bbaU^)ER5>*&*K+~EfJDI=}TAZobCy^#E=oN_D}Wsh#lBgkr6 zpOVW6#(YL+eX3;T`r`k@&8UiM-Pz$JRNGI{%K}C4S7x9eNI_bDt<*~|y9xn=tQ585 zDy894C&K}%MYWV>PWs%bfa{reD5s!}LuXbSjIG7l4pklSIXuv!qhw{Sjrf_3tz3~@ zUe;P@ancc*^v)pUrINv1M^nhdzDQpu>er8jKPW(1a-1=2TnCB3;*4v=5>#zp{Lq|Z zQXY$)LTOOrNw%^q+ovL0bSzKrP~T*iGCma_*jez8Q>g?ow90V*oyNXzg8|IDTu78k zuNSKmj}fatTxxa8nj)rq1s2gi%sE|J}%ASPhV zagLojqis7Z$^Z0FmIW+^8cUsCwaBxhr)uY<<<`34UUtMPygc%`E)@;trSF!{+Tb!P zEK`%7n(Coug5ylGW3}^05Y~!0$B0ZPN~Je4@9@xnCK7t1mvYjv8%IM%%BFqm>}HJ! z(5b2;meDDARYtnspeT@TzZB^1BpmGORa`|1J8xz?ql0R~s?r;;(+RteUwqtILYIwn zg_>mcwi8|)3k6OsIl`ocj*MM1-G0enR1p8F%W2w~)X>uo%k6NYRJtn*lG!}WiI{c@ ztT=YyC<@};(qx)#gw|ed4`r=pHAe|19r8Wc0t?|IQnbGEVq*9r2*l&ZTRE7rW zVo&iw0052dD8GoWk7%*%jPk(9KI2Li016(DkWBt5Aas3c=fNB@e(Ps>$>WIquip&C z7(W_Hdi!_#G62PB2{nX$Eq%^xC8c10m`!sW((%CWqBF_X2J6O89PqYZR6cDzM+Lx3 zxN|G9RJtN1$Ic&b@N&(8!3dAvms)TGyk%JmetK8TlpQ?DJp zX^+(Oc2r_BZS&5k2KriMmM8mO7hH3=c@qizt@{e46#Fi^PD4FxQdAtR8Mfzus6I}O z8|S+HonEdGuC+`NsYXs{mpsrf?Il~+ilsotyeunytz)h^pn(adwhKWk@v#pAwNl-I z77eop<{gu|^?uDuj-}y!RMzo5nQdEpxwaD1a!_|P;-^070hw!EsZ=~DAyS@a?w=*> z#9k#zrK1W(9Y_$66Id3!e=iGab5C0){W7Ca1yo(RlkElo<-~NAWm(}em$*Jv=OWA0 ziLlg|RFSPZ;y#J{vuz8-US|D-y_x8}u19OhQm~~x5Py*S z6XaMn(-SUQC^fL%`8>y5VcdRI7B!gRo{nbecA=DGRBPN!%U9Eyk=}4j%OJq|g3E`G zK6R#B4DPNl7sz4a6}(8ApYkmyY6u`^f~Hn$ixvj+sEur zCiZk=v6fn_ER?!qVYRwf&9rbgP9B(JjIOxU7Abs8RjEcMPV$P+v}bM9rR!~f_s=@6 z-dm+Dx*WQw&O=Q&e}BOXx>7Mwz6tepOXA$CPxjq&)V8JKHb%tH?g_L#W?jxlEs}DW zXruNS0G6qRvazXDndK?Z&~jb+WVXe8kJ>hsgE(GcuzovoWM66YYMvFtKFIaG(Wt3Z z5=&*97D^m|ZI@2Sd--?^53_DL7*T?l8zULVjvBt7Hq$vrp=c)K@J zad_>~Cgr6Q1s@l}A9HfX0~HaZA~r@2JC1MHji_^(70wy|)dRU;y;ajnODW_qjx!2mb+s-#?2o_6JC7*2(&MdHPsMAEj14H7yibFrMry>_UxzFT zBU;Vq((K&8*9$&kRT}=PK@nf@cw)yZ&LM~JDXoQt=HG&UQU&9``7?oLSF3ZGrkF0)Jy=Kp=#McJ8v@8U7=?+z(VtDPOdpV*DVzG={{N5 zg#@JUC5w*5*!uuuD-Xg%V%nC-w^{ZGqNX_RIf3hrB@&L2Smm?>$YuvFX9gr3+wNAA z^+>^cDU?y4ZOEDJ>CTd?Ij$?$vrSP?X{g&GLEmxGaPU_3zM7}x8DcdqfUuVoUxgk>d^Wp`$9KaoMsVuO>rU8!u0WTh$6 zYtFW2`fwW_uolqQSFZvN3Idv}C~8+H`p(*RO3eD$DA@oOon^=K=>|2y`qZdn4)i(_ zxJtQ%qqe)}Q%;y3dwPzQ)fGzX6xnr$O`=LhZ#eaVv%l|LqEsR+ozpB)GlJk6HO_`C zUZ<0Js^jClIh=Fx&GgAhvjb6Iy<|CJ-|J{~-lYhNFI^_r}^pd zm)<&yQub-rK=f-4hKqg&l4>q|Nz^K6o8{fSm)0I(Mc`i9NhN=AlF4nxyxg)moOAU% ziccNz-0mZiT#?YS@u=rH>FO;P6;FH8@wrwF>+y(4mPFc>C8K*!=kVFuHZq01kU~s? z3Oy2=6(wHOF(ubDiME^RVP?^NX)OSFuJ0WbcfJ%lssh@bDg9bw>P}};nTc&Zg4X6# zsX8Jtr9?%;SG(>i)g0tpJM_WI%-)&U=}xD?7}Z2}R{Us*N{OAUTAdeEsf@7B zcIL0TEg}QmhUhl`o9v*S+L?1wZa%dbOM}r(^BAQoUBNL`6NE_|mCC3mMM9S4NC{w_ z&(EtCy0sL8y>WHdMK-%TsUg(s11u+{2NBme^r}m#M42!)o4e_~CS`!}lfP3nSKYX3 z6>b*zdjX+x(Sr42my5oMi0A1p3!8}zR}J#j9X2PIq=y-2-|n0TW7uj7bOkDt&MNVh zie;;~2{-rfjPFy+ds--}FiWC6@fjEYTQ}W*IihlGC(TK_qDSpn6lHU`&<5t^(ute{ z7n!2UiBPb$vu3HAOzeqlN7jl355=HAZ$F!%=|Mt(a>AB5x`b)q|@o3fG3S>NUZ{#@kvs<#2+$lm9iB!(*3g zxEsx8eHU%RWuf$j&wgd+0rW4O$Os@T&d>ZSXxbr;Mw8V)2{Gte^_A)($x*N##@NnDS2Td_=(N7KDq3s_CamgUGs$st*v*O` zj_EDAaz6>=erG#BssJcxJra|OB}1*upnrOBX7F^6;ca2pA}f`wtD-d8(3Tt!x}@#s z&K8|Lr@dvTxgsfXL9G@fM{Gc1f-=il|A(^V8!~GZb~NEoP6^f0PFE`J&EC_l*%lv0 zVjcFT4pwpNxUgu)V{yrvgj}@C+4nHhQeAX2J&`DsL?XLPHq}y`uCFS^c?N(#ztS?z zV)sRC<|OVPtw-RS>2V{>yOJoBL_B0gs!mq71%Pj+yJO>P5<(^Bxl6g4AU?5%W_rS< zRL0s;3k{AYV7EkkM6A1Swa2!5re(VXo^MD>FXpw$a`2~{n)TFJs^R9{Mz{j_}nIYo>uqWSDg)-KbS$Wn~OgI{;;ll2aMZpAKW{Db? zC8M~)I;+e{6cz7IM$eL&4keBk9rbD5K|n1^o9np_e#21bPBqJyp@0Ag1)u8Lqg&;1 zykfk*hI%9#ByM(7?qqO@*36nHbifmyB<$C#tWJSUmsDA$S_XPIJ-d1{>DbkbbJ z5U(n*b^-_Eo^i6I?J(+wXIomF@{X{Q?k@} zn#)Wv%PezDae^~OSk`>H8do{NYKu+EcdBd-Pq@lFT173@nDJy+DRkX(kdeMIiYhMk zq<@XGQTBG|Y`pks=aL12NoJ`rM~xZgIKx@P?Xmx_F~bSwnPWB~qJpynMC;&*X1d@y zgYJm*rr<+d2Qf+}|B|rZcQ1K7>F`#!r@{5iyu3FgRXce$nB#&Grq!6|C^b$p!%5~j z$~-5TYmsw(!b(VOV%bex{S9qEQ&JQMkX@{lMLMH~dlwEWg{UAcf z3-Odr1TB>9pCZevfRU5G7f&kPxpDnlV0_avxT^!-)8KIf17MzcFTR3zE4z1zl=%z} z;T7BffH-13SHQ&cY@i8%_z^a69(iTAE0roAwq75?B_;aY`#4_mc#%Z$3IG5g07*na zRR16z?a17YF6&eO^VjXa9>oJnpH)hQk6Ev8z}m?E*Sm4si@Z;m-1p=2N;l360Q+|J zLQ(lgXhOkN{J$W8m!V)k6kNtlP_Tgm(7{oMun#ZdHhfZPWvrh7a4R0@(j4iZmHse( z4B`;J7WvN3@KIcYVnEsKrTBh4`o^FAr{3FIPYWvT2mPJ>o5LcNfAV~&Mg9d^tx#}X^7bBQvIK{LI~B`$N3b1d+%10%gwl$S)q^_$Y zl~s;=PJ1`DQ)5|T7M^!Nr52f@O26$PT&3(ZrDKCDRY%%69u}MIarDV*>XnURBK-8q zo=J9VNDI5Xc(Cr%bknc5fXXauT;c-f47k2nDOK~aDD{>n;WaQjtwcie7|+pIkxADi z>~0^{g6w^D7a}H3=KQXGUsI{VhFW)GZi>Q+I9KtbrO2Mq7eAr$j>B zeuu3-;c?r-#12=py&wBZ&ukPxoVXJ^RHZanijXlo+@)AjjTz3hq)x=AU*@8;JZc6m z+3CEPeW<4y<(aEH2A{j?F>0M~EjEWcYvs%fEosJjo%hk>DCYF*c8+9Jn(W)X)oLs! zYMm*Lh7k5uyA+;oP;>O}RXr?{Jr37r564)M3NSWC&hezx&2hn{P%@DTnybcl1t0al zb&=|;lQKzF;!_#xNO-!=Y{&DTS>f6DIG!RV!@9qhXdUb=yWDjaiguNBI6gt^I8Uf; z1*!p|Sig65^6N?FT*u{HBV4uW$nz0Gvl%1v;6GY5=3~?rG)UHpY6qIVc(1_W4g&{k z!lu$w8&Qr9cOPwc%8_f>&bi8#CmS~+>zuV9OFny#);439cT`5taupmw*Hj073X&5y z&#bUZ2dnc2OTt<7CLa~+XO6SfEEP635IE=49dEb3J~bhnud|k#SQ*{kmF{WhLua?_ zV!Iphv98wy{DSn?3s~aaZGY!80080z{0eG(AV$?Zzk%NcK>$zVY21CWv)l8+-@CPed+{(XvA7@Uk}r| zd`B9yBik;^Tj0B;V%NuUmLKleJiZSP+gm~J21(Rpy}+8bjO7K?Z`Pp7TwV6KV*@(AuxuafYas@NC zcex%@3J$i|c75oqaE|y*$&xhroUX_yXSr6K723q>i?7_WYTO)_CyVZE6qw^Qb+w!0 zsNrI!B0}GE6{rSAW!#yb&EbNF(imkk-Aro^ifGm4T-67n05LCJ`*zN>#EfgKbk^8T z)(6e@g!I+1EY+U(Q(baRymlfua;;FjGCym@1x~waKjexKJyUSjwP4j2d0-cXDx0!3 zP0L)Q$_%qsW~RbMK!imNc}I0w9(t9JsLC>)>Z(LwGBjS3W1e%K`}10{8ly@rO?sx= zjRHDHd5mW}e5V^DVr#Ma1>QNnByoj)L3SNxlpiMl{J=_^;ITf@;M_- z&=rn(?6_w7GUKDBR8I1Yk6pIHd47QQ%;FvV75C4xF^SP=%NQdujW^|1}2;xT7^CrXY5R(Z^75E}%3v+)ZXBfwhm zG>?T^GB#v?V5fiQ*yWh;$%BRdCck_ zQ?J4-fjVn0Px*|8%1|R#`y6I1;91m|;$bVCs@D^#o|s*`E>fG78zyRsl7~^v}g=8m_X+ zl83LHqejiqV5C7{C2(Pj9iq#Y$1NML4W?+41L_Odb|EVsib{=GJg9P%bDp+qGd(9^ zMk^75uglCa#b)}f!}ZIu;!0b`Tk35l7RsIuWN!#1wcZ2?D#B!&?8~yO`Ap`ZG}F~c&mR6W{sXIWy3XSq3CXWd94R}CAY znVvJyu9<+$j_PTSn@!fjlDpZ+RnBY0wW8+vZ&{XjW6FxjOy-A#( z>kU*SD@><;F+D7J46|ye756nQ&^>vpF`k4C&a=$CqpzZ_CUQ)1hS^Z7L7xB(rZ~?G zbDqlf98(+>$OCH3bCidL$-d09Z19}VQdfPlF*e^uQ0P#O$OS7F-LX9uXf0{1a52^x zmAW)S(-F!hy~n(lb2lsCjk=UWTkHeG&EHZ{eX{fgs~)7_xy#0}p?Wi2=Nu=Qp=t#v z&Hq#*UbHzJ?tqw|Y7nS!oXY_$uO*j3yUI~le5~PXKd6E4s#KZtbx7+iR11~3LirP_ zZ%#?$Y;1`><@{aH65SluJe|tJJ+`jTbU&4>Noa(AKAuGh(a_4zM63$UHiyr$%v=bZ ztU#c_$pA&_Twqn|S)CPuNT9)G$8u}9#$u5vW;rQ26B>`PnJxw3PILuQl9=Cvu`+X! zpVvtO>r)#eCWK(vL#3&%Zo;K5RBLblS!bjOm0#xPtdPJL@3h?W=#g9;+=c9}9ix{+ zfcXz^8gHC;zNYH4roGzoq!8nSSLfH-{$z!pm-KPQN$r znpF1L6>Zf+4uuxt5*5$fj%tC_du#SCQe&Qz%u8HmUbfSozzL-?W8`k~oa7{bDMG$S zrebVJ)<}xKMxD4|oMX%}B?JOBmU)ItY!Fyvoy)9oiF4GLWr{iJnJ>7mdXZH}KCNyg zJlBd7u4P;gxqkO6U~@PdS_vIq9o?1vwnb}o+UE)GaVWxg@am2VBiX@>lgXahw+*$rubG}PQtKIm6tcu|VcOr>)~RhjWGvV?T>AUkBB%-dV1JcLr#K$5NHTw*3dk zRXi;zIYJc|IA*y!-Nr+cco6Y6EB4_+Vh-!qXZ<8A3c$&%aHHQ z;dz!Qo@1POmUzZf-Ih4YGB2H2D;7A<1~p5;h(`FN<63H5D~@^`XIo3Egt#vGsuMr> zT%F4yZjFrP@lsi%ti&V-WRI&moSp3fn{(^tL@>R0%aRptesx#3=8A5qWPPT4^pZT& z-YENk;Qc?lkG-ea5&(uguz_L)onrMIxO9`0nU7T#xWHx_Xh_!c5*G~4 zmPIbH&KgV13`EbL?QUYz!iaV1eswm)REHY#!3oRlWNFr=6ZIY4*t`*t-qtK?#+2YY zpEH=;%rJN}JsAOnFH_v}?#3-n zut{nxTMZlrf%QC!6j*RH##mvUbr*MuZW)v$az;INpha+-%G6tDRk_@jf?g};9EF$q zlTNX~IV+s0V>?Tn35WrWv6yQ2BP%X4Du*9`uGcD&JRB3j`ktVYH za_L0bK_uB}xX0PfqEn6u7u!kJ@mgT%+o+*t=2+#@4pK8-kE>)AL8=0k(dO_HCnLc4 zI+56GaFJ(NXVsvsSYUw#moL7^Oo+WyA+SW1Z?Nj8^|NOU8t20SHLXGU920Q2R=jjV zZVEBRtVL;QI+G`PZU@g7XC$WJ)90wORAXX&S3B&vl0hZ%wRYA zX)d+7C&x!NhifcxR49BK7eG(u9v@7&q(>7vcTF23C1wM{dUZ#$FXy%BB!~sU^ft+) z#;98>{?uLOO!EWQmk4YQmsoKWHR#G~fi+G`eFY|2=Hd=^tT#q#u6UMnTrwTA+RB}4 zv?CH8&Gf)V@q?=SL4q=zG}KI$%L76mSa)QCvMd`6@ACe#!g;RdSXU<|Rl|i8VG@qgVTh z3`+!>=|X7ve>Z~4rmf%vUDZRL#-wG9)LAjO=~RpBqaMPvGb5=IRXFP$OPpXx0V-rTB9z?? z9JAli7@z%Qkrl(+S0!4*wIZ-FQgKj1ir}n`5jTCeSM;K@qFG>p1~u16E{7HytQGaD zp0y&NGuztBcQKUrx8_-!Z3iOPr|JP{+hL|Wv8T&iVuf?mEP`-TRcXvqqsB6qVxMGg zrq4*6HC~%kiRpG&%>fnGMbGSK~0Q^R)C1EM1LK*YBCk-xfnRBdI30hN) z6f8wzPLPTt_^LWGIY5c0xX3!sdWLC7+d>H~vTVV@GD0%jyndZat-%`CihvVeG8>xE zF0o9U8a>nsJP)m6j(tL?Caaf2lva&d7Z?Pk+f(YzRM z|9f)6Wp}cSX~nffDr~UES!$dN%mhVIE4{Q)R#|72B~BVUptSYsHdf zov0x(5z?w|AL<-BGz>6%2YW%WyJnuPnpHNW}=Nip@Q;t{#cabk6ho za%`rX=^RI?mqGe7_la)hPEjj0hJy)adO(Aa+kV3xQ7?5Gh`-{>q?a7^uyrmPF!8+5 zen5?o8;W-uhGu%!fj~+5W;j-<8Na>k88O$>OjlXqoDbwH#ThQT=$}+aN9AT(%+`2~ z;!>oJK3-Q)=P4E}g|ab{lRjZ?0tMf5=GaVc4v)4NRm%-XOAi0JQejwok}PL?6d9^+ zzb1L1tK1DM4*FwNXn^Hs{4KNQioEP`c$OODJw-ARmqUhUI8Kegw|y-dQw^_AjS7gC z({u;fqf|cUcDJPjwdqnXYIsCE0C;RxP2mr~QQ4oe*M47$$ocUh*G6N>&b855Go zc3hpXJgC;GGQM7!7~-DM4Q=0WL{P$&3Q&;-bcuD&vBH8-a}wWuspi{i%YWCubiyu_ za~t_%#=ZWUqg2kVRC2!91y$-4os}#DF(xIWY=f(a!>}@L+H3Qv&3SOg>T_bP*i6@3 z?u%fS3=UR?XWrMbrw|$x z&wA!)!t#C2EvxKOoJ(w`bA~-uZ==nMNfNa*5H65eN36Q|-o#vBwNL2asxUL!NDb6{ z;~brJf1LbYw*>4cvn~Y0V0gsSEiVL}rl3NgnQo>RX)Y(#GYsusLSksLASjBH(%zO2 zX|)y3LN8X>h{pu6ek^#XFWs>=2@h1sz^+=m;;A;dXX8z8V9K)5!N89jM<-=p?BiWD zw#Ps%wzTM`$JP)UK7_?o#9EH!0Z}Q7%oy;k=#9%|2ECGj6LANrP20`Az2^6b7O-ohJ#Qm6LLHSSpil+-!<}sh%kebyzBNdT`%FkWM#kj1{ZtALfMo=<5 zwcYBP4v6R&w>*{^0X5QX-IsAi>b;c8f-h@(e5KrGS46S4*W9h=JQ{X3Xhz~yA6ENp zU_7iQwbu$`j|;kwWk(+x|0h&+p*>aKHX0QIDP|mP=hc=}iFkKo9&x6)$gzN|&O%J0 zK_csLi%I&rFul6pMR-N>A62HLhTrz$818Dgxbvzq7t&NCd`XOQ%)$lLeXDd;4`t&t zRkIOD1;Y9Y1$E15rfZI{s^3wF4cL6yxka21O2so(VZh6j{K9q-U})#A7LUHksmkB=zU(F!hO zm4I_6TjVud3%qvuKAHgj+sIuCaKz&p^*eKaN*-F<5G58pff z=SrOB`dx~>PA{S*mGS~$P5pb{h#n}F^LVo{A@py(f~lWK%wXa&h`BncGsnk_yHTu3 zt_b(1_$~tRU3~%nN9Bvk{dg+?;5roFtYC zya!tB;&HOtKabBV6Bpt(w{N%R$2GJNDqf#b1s9}uj>4G3MAbZkjB%&bUY{yO>@Fkv z%0XdLcML*}WbPlMnD+C&+Sv$Mo@o92bO+XUn-*E|NHl5@a4ltlaMFh3X97Nv;WB~E z;esm!9(FHTpVlM&kfGh}O+yVerEFhol;f>ib6%%`64r|W0OHG`lnXWiu zLc<=_(qgn?oD19>Uh%=y>c=~3IQqsSdvjYyOot{hD@Ukb?w zXrWEOOdq`@5dLfq7eZQcqzrDCc?%=sou~3vp7EiWoRO|Cj@)#5xp z+rB-kE`(`GS{Q0 zfVJwIwrnLmJ87}dWhBMmlyebk&2v@>qsgDT7{Co;zs_@WShsb{0fAxiKGMk?B(_ zE8KrAg6*I`yJ?|YU^6|(Jyryv+-7Rq%g(SB{W$?vCo0@!D+g5$z2o&MV3k0fc?Yq# zceYEl@?&-C-%xG=xaWNLFi-VSu}n(rCvj9Mv%=U%^cWh#P#5}eQwu_8W7P#hkJ|t* zJ8+}H%0z!PYr)QHp{mH-sjD33C>IDc({dXGzeTPqpGzm?N~$r+PDnOjPj5x7$ZoU# zFYmTs@N(zne8|}}0xO0hZKiAVhR1o2R>k;K&ap9t;ek_qp7r9EYCo^V7%G*z)U_be zM=HXAFZAV>7JL`wY>b9@ed@F)VL;fA#$|(jrV{BhSpxIS87afuq*BJXF;d|;7p!I*xi)PTuji*<{Ui@NVk@=K^UhGm^^^^pYA#Z^HDg#AYejGF zm1qstN_}p0I^HMlpXf5y>J~4$8U2C)FL*xwOiVC@&2)_gA1g%lp@kCj7tT;-@RHTr zP3X$uBv&a`?RYQntgC}@nRyl*PNQZNe{GD+QSTwB|NF*Bopn|tEJ00R^_OQ#L%3tN zyL#zFcxbs~QF&Jx#Yxi@re@5ODuHIYEU6m%$c&Hb%yfmdwN#Q30s#0TE>k+Y(pL{A4n(T7 z<*n9ShJ7xErl4ql_*3|;8qUrFqNUxpLaxu~dQSYh$Do znyWY)5Dh7_#yU5L8*Slb_6XJUCKsMIaP8OSs_stKBIz9$Iu$~W!0*=Rc#T1I+h?42 zO`C~WLY3=GF&7X4pR*umwTKC4)uSzCGYzb8nKf3r($dt%)P`G7`X_$X(YHFBO~bUX z{P4u4Th=c8ZjV*U(M*?O6WVW0vaS+^?Zp7=)ZNL>5Q8)X6&?~zsrn}VI$Xx#VPyF?)C~8*!)XK(*kQHSTBJr;$q3ZLVtcy6kk` zG!wN%My%!R3?^kvm=f)ualxZSM7)$rHNXI@2oH0WquVIa(|2*bp?t&lJcVr-`k5B4 z>8#PCILD2Vx`iTkH|45ZOCIHr!E(brIa=5Pco4l9DkO#6#~CZ zmCIc6DNZzldKypiOpAVaD@j|`$j=1D(JFzR^4ws-MLKcW)H478AOJ~3K~%}PRUbNt zOvuPNiP-IyY~=xI!O`kft`*O+EOhJiOZ|6dWs535plsmMiRispqRDCDi~T`6bt8dT z3Dn99jt;Q#pA>bg`>;NZH%7(-X&A#{Z>ojFt#j4aMN(ZM&r@8C6n|>9l<*9JX4)Ng zZ}1eyTXI=Urj%M}KF7>|TN>cHn-qIp7aGiaE6wf&;N)lA3t#%j_Uza*n`X06@ zeED2Qmh7=ek(Akp@s{~6H!JJ3Ix!dYvXKe-r4SXOGR3zUOC_w7utKwHRgK8GnzHJI z{3X{$H@~dp@-@>7hRHn~!np7JStZcmILpHF7!IJmZbU$>xZ^rIMXiX=WK=Tmltqu# zi7OC$YDd_k)DA6Ku}P`_WY(hkWkyO_ZKsP!4_%-$)}t2V3b_c?v<04yK$D=Gug!Eb zJtr+*HBv3~1gpM_sTCAR)oMX&KC{i?ioj2&hGwy3_7b~Lz8uImqgs%@Rn`q)VQ`S! zX&*P!3(PXb3}*+dy=jA|S>oY<%6B!?q2ALWb0Ozy|Kho{)$oJbNHvAUX6zduj}%jh zCz!gKUg8{cLWPuQag}^{-Q@b=hDWctlxKIossVk=)0;>s%#|v6ET%?FHp)DgnPS#D z&!VfbSCp()#=z>7IK!&3ksXdmMv!AOZMSR>vg*7{^Eyi$V~V9%QV58$K2>9xc~3>_ z-+w`lJZ6PsIukS~3k4~@h%;5Fl;}(rB%GojSQc)4Cc^jDVuUAbrWaYEMrYfuyknY% z^P6PY;KoR%1*TW$2)D`>n{t)$*IROVP7%mitR{t!FtgttI!B-?f#c@_`P;x8L>cJC`=`0c^{EM_I3tk} zq#`*V`Zw8d^#)rD&T0hotlQ>rE>H#d#Z&CftHBz9GRw?H4CI<)bdr85yOlD*^{F~5 ztZ*S_dBj$qr|A)BtZ>mW4<}mz(MOQga1d*)*eQjl2DwrdVJGZFaMq;eO+|>L z3_?2%+di4F64~L%#`(~xt_Kfo;+@kG3gc8Orm|LS7#y=vQ_4ZgZBL7R{90`(Do_4d z7C6QwE*V?cWF#xc4A3t*wyRQv&n^s@Qkj+_BHs5l!IHEg_{~U>Yp>jqahMcln$H0# zPujnBr6yz}f+HzvEcjWX$;QZG-|(he&W19gl#F^_J48Fy!a`m$(6o9;Q*E(fs>*0B z)Wcku)~zGe+O{@E)~A*XzP_;*6q(97nswhMokJl6*`p4erE%r3@p{O3<^2Q|ydO_0z$!m(yz^f1ki0DV3wrr~!L%1P|f~eDC-Vl&>m}D0eCQUk8A<3(wQ9vFN*%eb%$O+>xvM zMF2y_h_Cy(DQX9ivtli!e-IeHNXJ$KA|HP`9I4xMc z+f2sS=skh5JY~e7HbycmQ;(^%65(jKd1>o$l($-8T)nKZZk6(dp)LIH{}k=^8ah;N zCXxyq97{#qa?b@^btXbYa<1bE7+b}A1ZXQA2D{gMCZ8r%@+`%^2do^Jjmp#FZ290< zA7c}9X1Fn;wGhpak6Pp$Rc5$Cpu$XB)<(OkCF=2I>R`%IHq&dx=>VnHiYlyg)w
    - + - + - + '; echo ''; echo ''; + echo ''; echo ''; echo ''; echo ''; From eeeb2f0583ae81bd51a326f89b44f0134cb93be8 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 6 Sep 2019 15:36:03 +0200 Subject: [PATCH 130/500] Reservierung check auf Titel und Beschreibung --- include/reservierung.class.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/reservierung.class.php b/include/reservierung.class.php index b3c8221e0..44d989600 100644 --- a/include/reservierung.class.php +++ b/include/reservierung.class.php @@ -131,11 +131,21 @@ class reservierung extends basis_db $this->errormsg = 'Stunde ist ungueltig'; return false; } + if($this->titel=='') + { + $this->errormsg = 'Es muss ein Titel angegeben werden'; + return false; + } if(mb_strlen($this->titel)>10) { $this->errormsg = 'Titel darf nicht laenger als 10 Zeichen sein'; return false; } + if($this->beschreibung=='') + { + $this->errormsg = 'Es muss eine Beschreibung angegeben werden'; + return false; + } if(mb_strlen($this->beschreibung)>32) { $this->beschreibung = 'Beschreibung darf nicht laenger als 32 Zeichen sein'; From be91fc93c030a0ffb763901c9e51afcea407f2ff Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 6 Sep 2019 15:36:32 +0200 Subject: [PATCH 131/500] - organisation/Studiensemester_model: added getPreviousFrom method, getNextFrom(): next studiensemester with start = ende is not skipped --- .../organisation/Studiensemester_model.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/application/models/organisation/Studiensemester_model.php b/application/models/organisation/Studiensemester_model.php index 9248b241d..9878ab5be 100644 --- a/application/models/organisation/Studiensemester_model.php +++ b/application/models/organisation/Studiensemester_model.php @@ -61,7 +61,7 @@ class Studiensemester_model extends DB_Model start, ende FROM public.tbl_studiensemester - WHERE start > ( + WHERE start >= ( SELECT ende FROM public.tbl_studiensemester WHERE studiensemester_kurzbz = ? @@ -72,6 +72,26 @@ class Studiensemester_model extends DB_Model return $this->execQuery($query, array($studiensemester_kurzbz)); } + /** + * getPreviousFrom + */ + public function getPreviousFrom($studiensemester_kurzbz) + { + $query = 'SELECT studiensemester_kurzbz, + start, + ende + FROM public.tbl_studiensemester + WHERE ende <= ( + SELECT start + FROM public.tbl_studiensemester + WHERE studiensemester_kurzbz = ? + ) + ORDER BY start DESC + LIMIT 1'; + + return $this->execQuery($query, array($studiensemester_kurzbz)); + } + /** * getNearest */ From 5255e6166df3c040c538397ca8a6095c281660fd Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 6 Sep 2019 15:49:47 +0200 Subject: [PATCH 132/500] crm/Prestudent_model, education/Lehrveransaltung_mode, person/Person_model: models are loaded in constructor to avoid multiple load --- application/models/crm/Prestudent_model.php | 6 ++---- application/models/education/Lehrveranstaltung_model.php | 8 +++----- application/models/person/Person_model.php | 6 +++--- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/application/models/crm/Prestudent_model.php b/application/models/crm/Prestudent_model.php index ffc6afb0e..32673d10d 100644 --- a/application/models/crm/Prestudent_model.php +++ b/application/models/crm/Prestudent_model.php @@ -10,6 +10,8 @@ class Prestudent_model extends DB_Model parent::__construct(); $this->dbTable = 'public.tbl_prestudent'; $this->pk = 'prestudent_id'; + + $this->load->model('crm/prestudentstatus_model', 'PrestudentstatusModel'); } /** @@ -208,7 +210,6 @@ class Prestudent_model extends DB_Model return error('prestudent could not be loaded'); //Prestudentstatus - $this->load->model('crm/prestudentstatus_model', 'PrestudentstatusModel'); $lastStatus = $this->PrestudentstatusModel->getLastStatus($prestudent_id); if ($lastStatus->error) @@ -310,8 +311,6 @@ class Prestudent_model extends DB_Model if (!hasData($prestudents)) return $bewerbungen; - $this->load->model('crm/prestudentstatus_model', 'PrestudentstatusModel'); - foreach ($prestudents->retval as $prestudent) { $lastStatus = $this->PrestudentstatusModel->getLastStatus($prestudent->prestudent_id, $studiensemester_kurzbz); @@ -424,7 +423,6 @@ class Prestudent_model extends DB_Model if (!hasData($prestudent)) return false; - $this->load->model('prestudentstatus_model', 'PrestudentstatusModel'); $lastStatus = $this->PrestudentstatusModel->getLastStatus($prestudent_id, null, 'Interessent'); if (!hasData($lastStatus)) diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 1685ddf81..1235769ac 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -10,6 +10,9 @@ class Lehrveranstaltung_model extends DB_Model parent::__construct(); $this->dbTable = 'lehre.tbl_lehrveranstaltung'; $this->pk = 'lehrveranstaltung_id'; + + $this->load->model('organisation/studiengang_model', 'StudiengangModel'); + $this->load->model('organisation/studiensemester_model', 'StudiensemesterModel'); } /** @@ -22,8 +25,6 @@ class Lehrveranstaltung_model extends DB_Model */ public function getLehrveranstaltungGroupNames($studiensemester_kurzbz, $ausbildungssemester = null, $studiengang_kz = null, $lehrveranstaltung_ids = null) { - $this->load->model('organisation/studiengang_model', 'StudiengangModel'); - $studiengang_kz_arr = array(); $ausbildungssemester_arr = array(); $lehrveranstaltung_id_arr = array(); @@ -59,7 +60,6 @@ class Lehrveranstaltung_model extends DB_Model } else { - $this->load->model('organisation/studiensemester_model', 'StudiensemesterModel'); foreach ($studiengang_kz_arr as $studiengang_kz_item) { $result = $this->StudiensemesterModel->getAusbildungssemesterByStudiensemesterAndStudiengang($studiensemester_kurzbz, $studiengang_kz_item); @@ -214,8 +214,6 @@ class Lehrveranstaltung_model extends DB_Model */ public function getLvsWithIncomingPlaces($studiensemester_kurzbz) { - $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - $studsemres = $this->StudiensemesterModel->load($studiensemester_kurzbz); if (!hasData($studsemres)) diff --git a/application/models/person/Person_model.php b/application/models/person/Person_model.php index b689f4fcb..1291427b6 100644 --- a/application/models/person/Person_model.php +++ b/application/models/person/Person_model.php @@ -10,6 +10,9 @@ class Person_model extends DB_Model parent::__construct(); $this->dbTable = 'public.tbl_person'; $this->pk = 'person_id'; + + $this->load->model('person/kontakt_model', 'KontaktModel'); + $this->load->model('person/adresse_model', 'AdresseModel'); } /** @@ -162,9 +165,6 @@ class Person_model extends DB_Model if(count($person->retval) < 1) return success(null); - $this->load->model('person/kontakt_model', 'KontaktModel'); - $this->load->model('person/adresse_model', 'AdresseModel'); - $this->KontaktModel->addDistinct(); $this->KontaktModel->addSelect('kontakttyp, anmerkung, kontakt, zustellung'); $this->KontaktModel->addOrder('kontakttyp'); From 562e509875131e55843b3bebe34540fd60e08447 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 6 Sep 2019 16:31:01 +0200 Subject: [PATCH 133/500] - added tbl_variablenname table, which is referenced by tbl_variable for storing available Variables and their defaults --- system/dbupdate_3.3.php | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 4e720daef..66504cd5a 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3030,6 +3030,59 @@ if(!$result = @$db->db_query("SELECT stufe FROM public.tbl_dokumentstudiengang L echo '
    public.tbl_dokumentstudiengang: Spalte stufe hinzugefuegt'; } +// Create TABLE public.tbl_variablenname +if(!@$db->db_query("SELECT 0 FROM public.tbl_variablenname WHERE 0 = 1")) { + $qry = ' + CREATE TABLE public.tbl_variablenname + ( + name varchar(64) NOT NULL constraint pk_tbl_variablenname primary key, + defaultwert varchar(64) + ); + COMMENT ON TABLE public.tbl_variablenname IS \'Namen aller benutzerdefinierten Variablen\'; + + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'termin_export_db_stpl_table\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'sleep_time\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'semester_aktuell\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'reihungstestverwaltung_punkteberechnung\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'number_displayed_past_studiensemester\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'max_kollision\', \'0\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'locale\', \'de-AT\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'kontofilterstg\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'kollision_student\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'infocenter_studiensemester\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'ignore_zeitsperre\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'ignore_reservierung\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'ignore_kollision\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'fas_id\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'fasfunktionfilter\', \'alle\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'emailadressentrennzeichen\', null); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'db_stpl_table\', \'stundenplan\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'allow_lehrstunde_drop\', \'false\'); + INSERT INTO public.tbl_variablenname (name, defaultwert) VALUES (\'alle_unr_mitladen\', \'false\'); + + ALTER TABLE public.tbl_variable ADD CONSTRAINT variablenname_variable FOREIGN KEY (name) REFERENCES public.tbl_variablenname(name) ON UPDATE CASCADE ON DELETE RESTRICT; + '; + + if (!$db->db_query($qry)) + echo 'public.tbl_variablenname ' . $db->db_last_error() . '
    '; + else + echo '
    Created public.tbl_variablenname'; + + // GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO web; + $qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO web;'; + if (!$db->db_query($qry)) + echo 'public.tbl_variablenname ' . $db->db_last_error() . '
    '; + else + echo '
    Granted privileges to web on public.tbl_variablenname'; + + // GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO vilesci; + $qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO vilesci;'; + if (!$db->db_query($qry)) + echo 'public.tbl_variablenname ' . $db->db_last_error() . '
    '; + else + echo '
    Granted privileges to vilesci on public.tbl_variablenname'; +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; @@ -3258,6 +3311,7 @@ $tabellen=array( "public.tbl_studiensemester" => array("studiensemester_kurzbz","bezeichnung","start","ende","studienjahr_kurzbz","ext_id","beschreibung","onlinebewerbung"), "public.tbl_tag" => array("tag"), "public.tbl_variable" => array("name","uid","wert"), + "public.tbl_variablenname" => array("name","defaultwert"), "public.tbl_vorlage" => array("vorlage_kurzbz","bezeichnung","anmerkung","mimetype","attribute","archivierbar","signierbar","stud_selfservice","dokument_kurzbz"), "public.tbl_vorlagedokument" => array("vorlagedokument_id","sort","vorlagestudiengang_id","dokument_kurzbz"), "public.tbl_vorlagestudiengang" => array("vorlagestudiengang_id","vorlage_kurzbz","studiengang_kz","version","text","oe_kurzbz","style","berechtigung","anmerkung_vorlagestudiengang","aktiv","sprache","subject","orgform_kurzbz"), From 36ff38b0eec4888b7e4d5904528a4470c19cf9ef Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 6 Sep 2019 17:29:22 +0200 Subject: [PATCH 134/500] - FilterWidget: added method reloadDataset() for reload of dataset only --- application/controllers/system/Filters.php | 10 ++++++++++ application/libraries/FiltersLib.php | 8 ++++++++ public/js/FilterWidget.js | 23 +++++++++++++++++++--- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/application/controllers/system/Filters.php b/application/controllers/system/Filters.php index 3bdb6dde2..b29bd2bb0 100644 --- a/application/controllers/system/Filters.php +++ b/application/controllers/system/Filters.php @@ -216,6 +216,16 @@ class Filters extends FHC_Controller $this->outputJsonSuccess('Success'); } + /** + * Reloads the dataset + */ + public function reloadDataset() + { + $this->filterslib->reloadDataset(); + + $this->outputJsonSuccess('Success'); + } + //------------------------------------------------------------------------------------------------------------------ // Private methods diff --git a/application/libraries/FiltersLib.php b/application/libraries/FiltersLib.php index 6346150d8..6875d16ec 100644 --- a/application/libraries/FiltersLib.php +++ b/application/libraries/FiltersLib.php @@ -528,6 +528,14 @@ class FiltersLib return $applyFilters; } + /** + * Reloads dataset by setting session variable to true + */ + public function reloadDataset() + { + $this->setSessionElement(self::SESSION_RELOAD_DATASET, true); + } + /** * Add a filter (SQL where clause) to be applied to the current filter */ diff --git a/public/js/FilterWidget.js b/public/js/FilterWidget.js index 767cd228a..6aad74562 100644 --- a/public/js/FilterWidget.js +++ b/public/js/FilterWidget.js @@ -92,7 +92,7 @@ var FHC_FilterWidget = { }, /** - * Alias call to method display only to inprove the readability of the code + * Alias call to method display only to improve the readability of the code */ refresh: function() { @@ -100,13 +100,30 @@ var FHC_FilterWidget = { }, /** - * To retrive the page where the FilterWidget is used, using the FHC_JS_DATA_STORAGE_OBJECT + * To retrieve the page where the FilterWidget is used, using the FHC_JS_DATA_STORAGE_OBJECT */ getFilterPage: function() { return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method; }, + /** + * Reload of dataset, also reloads page to show changes + */ + reloadDataset: function() { + FHC_AjaxClient.ajaxCallPost( + "system/Filters/reloadDataset", + { + filter_page: FHC_FilterWidget.getFilterPage() + }, + { + successCallback: function(data, textStatus, jqXHR) { + FHC_FilterWidget._failOrReload(data); + } + } + ); + }, + //------------------------------------------------------------------------------------------------------------------ // Private methods @@ -197,7 +214,7 @@ var FHC_FilterWidget = { }, /** - * This method calls all the other methods needed to rendere the GUI for a FilterWidget + * This method calls all the other methods needed to render the GUI for a FilterWidget * The parameter data contains all the data about the FilterWidget and it is given as parameter * to all the methods that here are called * NOTE: think very carefully before changing the order of the calls From 67415a47077ce997967793cdb54e451c6392555c Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 6 Sep 2019 17:33:56 +0200 Subject: [PATCH 135/500] =?UTF-8?q?-=20possible=20to=20read=20and=20write?= =?UTF-8?q?=20user=20Variables=20in=20Codeigniter=20-=20added=20Variablenn?= =?UTF-8?q?ame=5Fmodel,=20VariableLib,=20Variables=20controller=20-=20Info?= =?UTF-8?q?center=20=C3=9Cbersicht=20-=20infocenterData,=20infocenterFreig?= =?UTF-8?q?egebenData,=20infocenterReihungstestAbsolviertData:=20added=20p?= =?UTF-8?q?ossibility=20of=20toggle=20of=20infocenter=5Fstudiensemester=20?= =?UTF-8?q?variable,=20only=20prestudents=20of=20selected=20Studiensemeste?= =?UTF-8?q?r=20are=20shown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/controllers/system/Variables.php | 78 +++++++++++ .../system/infocenter/InfoCenter.php | 2 + application/libraries/VariableLib.php | 131 ++++++++++++++++++ application/models/system/Variable_model.php | 87 ++++++++++++ .../models/system/Variablenname_model.php | 78 +++++++++++ .../views/system/infocenter/infocenter.php | 2 +- .../system/infocenter/infocenterData.php | 20 +-- .../infocenter/infocenterFreigegeben.php | 2 +- .../infocenter/infocenterFreigegebenData.php | 5 +- .../infocenterReihungstestAbsolviert.php | 2 +- .../infocenterReihungstestAbsolviertData.php | 3 +- .../infocenter/infocenterPersonDataset.css | 7 + .../js/infocenter/infocenterPersonDataset.js | 94 ++++++++++++- 13 files changed, 485 insertions(+), 26 deletions(-) create mode 100644 application/controllers/system/Variables.php create mode 100644 application/libraries/VariableLib.php create mode 100644 application/models/system/Variablenname_model.php create mode 100644 public/css/infocenter/infocenterPersonDataset.css diff --git a/application/controllers/system/Variables.php b/application/controllers/system/Variables.php new file mode 100644 index 000000000..20303118b --- /dev/null +++ b/application/controllers/system/Variables.php @@ -0,0 +1,78 @@ + 'basis/variable:rw', + 'getVar' => 'basis/variable:rw', + 'changeStudiensemesterVar' => 'basis/variable:rw' + ) + ); + + $this->load->model('system/variable_model', 'VariableModel'); + + $this->_setAuthUID(); + + $this->load->library('VariableLib', array('uid' => $this->_uid)); + } + + /** + * Sets a user variable based on received post parameters, outputs JSON response. + */ + public function setVar() + { + $name = $this->input->post('name'); + $wert = $this->input->post('wert'); + + $result = $this->VariableModel->setVariable($this->_uid, $name, $wert); + + $this->outputJson($result); + } + + /** + * gets a user variable based on received post parameter, outputs JSON response. + */ + public function getVar() + { + $name = $this->input->get('name'); + $this->outputJson($this->VariableModel->getVariables($this->_uid, array($name))); + } + + /** + * Changes a user variable containing a Studiensemester based on received post parameters, outputs JSON response. + */ + public function changeStudiensemesterVar() + { + $name = $this->input->post('name'); + $change = $this->input->post('change'); + + $result = $this->variablelib->changeStudiensemesterVar($this->_uid, $name, $change); + + $this->outputJson($result); + } + + /** + * Retrieve the UID of the logged user and checks if it is valid + */ + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) show_error('User authentification failed'); + } +} diff --git a/application/controllers/system/infocenter/InfoCenter.php b/application/controllers/system/infocenter/InfoCenter.php index d59c058cf..c803520ed 100644 --- a/application/controllers/system/infocenter/InfoCenter.php +++ b/application/controllers/system/infocenter/InfoCenter.php @@ -136,6 +136,8 @@ class InfoCenter extends Auth_Controller $this->_setAuthUID(); // sets property uid + $this->load->library('VariableLib', array('uid' => $this->_uid)); + $this->setControllerId(); // sets the controller id } diff --git a/application/libraries/VariableLib.php b/application/libraries/VariableLib.php new file mode 100644 index 000000000..3d732984f --- /dev/null +++ b/application/libraries/VariableLib.php @@ -0,0 +1,131 @@ +_ci =& get_instance(); + + $this->_variables = null; + + $this->_ci->load->model('system/Variable_model', 'VariableModel'); + $this->_ci->load->model('organisation/studiensemester_model', 'StudiensemesterModel'); + + if (isset($loggeduid['uid']) && !isEmptyString($loggeduid['uid'])) + $this->_setVariables($loggeduid['uid']); + else + { + show_error('uid of logged user not passed!'); + } + } + + /** + * Gets an already loaded user variable by variable name. + * @param $name + * @return mixed|null + */ + public function getVar($name) + { + return isset($this->_variables[$name]) ? $this->_variables[$name] : null; + } + + /** + * Changes variables having Studiensemester as value. Sets variable value to next or previous Semester. + * @param $uid variable is set for this user + * @param $name variable name + * @param $change if positive, variable value is set to next semester, negative - previous semester + * @return array if change was successfull, uid and variable name. Infotext otherwise. + */ + public function changeStudiensemesterVar($uid, $name, $change) + { + $result = error('error when setting variable!'); + $notchangedtext = "Studiensemester variable not changed."; + + if (!isEmptyString($uid) && !isEmptyString($name) && is_numeric($change)) + { + $change = (int) $change; + $varres = $this->_ci->VariableModel->getVariables($uid, array($name)); + + if (isSuccess($varres)) + { + if (hasData($varres)) + { + $currStudiensemester = getData($varres); + + if ($change === 0) + { + $result = success($notchangedtext); + } + else + { + if ($change > 0) + { + $changedsem = $this->_ci->StudiensemesterModel->getNextFrom($currStudiensemester[$name]); + } + elseif ($change < 0) + { + $changedsem = $this->_ci->StudiensemesterModel->getPreviousFrom($currStudiensemester[$name]); + } + + if (hasData($changedsem)) + { + $changedsem = getData($changedsem); + + $result = $this->_ci->VariableModel->setVariable($uid, $name, $changedsem[0]->studiensemester_kurzbz); + //update property + $this->_setVariable($uid, $name); + } + else + { + $result = success($notchangedtext); + } + } + } + } + } + return $result; + } + + /** + * "Refreshes" variable value with given name by retrieving current value from db and saving it. + * @param $uid + * @param $name + */ + private function _setVariable($uid, $name) + { + $variable = $this->_ci->VariableModel->getVariables($uid, array($name)); + + if (hasData($variable)) + { + $variable = getData($variable); + $this->_variables[$name] = $variable[$name]; + } + } + + /** + * "Refreshes" all variable values by retrieving current values from db and saving them. + * @param $uid + */ + private function _setVariables($uid) + { + $variables = $this->_ci->VariableModel->getVariables($uid); + if (hasData($variables)) + { + $this->_variables = getData($variables); + } + } +} diff --git a/application/models/system/Variable_model.php b/application/models/system/Variable_model.php index 9800999fe..1fcb5b274 100644 --- a/application/models/system/Variable_model.php +++ b/application/models/system/Variable_model.php @@ -10,5 +10,92 @@ class Variable_model extends DB_Model parent::__construct(); $this->dbTable = 'public.tbl_variable'; $this->pk = array('uid', 'name'); + $this->hasSequence = false; + + $this->load->model('system/Variablenname_model', 'VariablennameModel'); + } + + /** + * Gets user variables and values for a uid. + * If no value found in tbl_variable, default as defined in variablename_model is retrieved. + * @param $uid + * @param null $names optionally get only certain variables + * @return array + */ + public function getVariables($uid, $names = null) + { + if (isEmptyString($uid) || (isset($names) && !is_array($names))) + $result = error('wrong parameters passed'); + else + { + $vardata = array(); + + $qry = "SELECT name, wert FROM public.tbl_variable WHERE uid = ?"; + + if (isset($names)) + { + $qry .= " AND name IN ('".implode(',', $names)."')"; + } + $qry .= ";"; + + $varresults = $this->execQuery($qry, array($uid)); + + if (hasData($varresults)) + { + $varresults = getData($varresults); + foreach ($varresults as $varresult) + { + if (isset($varresult->wert)) + $vardata[$varresult->name] = $varresult->wert; + } + } + + $vardefaults = $this->VariablennameModel->getDefaults($names); + + if (hasData($vardefaults)) + { + $vardefaults = getData($vardefaults); + + + foreach ($vardefaults as $vardefault) + { + if (!isset($vardata[$vardefault->name]) && isset($vardefault->defaultwert)) + { + $vardata[$vardefault->name] = $vardefault->defaultwert; + } + } + } + $result = success($vardata); + } + + return $result; + } + + /** + * Sets a variable value for a uid. Adds new entry if not present, updates entry otherwise. + * @param $uid + * @param $name + * @param $wert + * @return array + */ + public function setVariable($uid, $name, $wert) + { + $result = error('error when setting variable!'); + if (!isEmptyString($uid) && !isEmptyString($name) && !isEmptyString($wert)) + { + $varres = $this->loadWhere(array('uid' => $uid, 'name' => $name)); + + if (isSuccess($varres)) + { + if (hasData($varres)) + { + $result = $this->VariableModel->update(array('uid' => $uid, 'name' => $name), array('wert' => $wert)); + } + else + $result = $this->VariableModel->insert(array('uid' => $uid, 'name' => $name, 'wert' => $wert)); + } + } + + return $result; } } diff --git a/application/models/system/Variablenname_model.php b/application/models/system/Variablenname_model.php new file mode 100644 index 000000000..ada1d330c --- /dev/null +++ b/application/models/system/Variablenname_model.php @@ -0,0 +1,78 @@ + 'SELECT studiensemester_kurzbz FROM public.tbl_studiensemester WHERE ende>now() ORDER BY start LIMIT 1', + 'infocenter_studiensemester' => 'SELECT studiensemester_kurzbz FROM ( + SELECT DISTINCT ON (studienjahr_kurzbz) start, studiensemester_kurzbz + FROM public.tbl_studiensemester + ORDER BY studienjahr_kurzbz, start + ) sem + WHERE start > now() + LIMIT 1;' + ); + + /** + * Constructor + */ + public function __construct() + { + parent::__construct(); + $this->dbTable = 'public.tbl_variablenname'; + $this->pk ='name'; + } + + /** + * Gets defaults for user variables. + * If no default value present in table, SQL can be executed for retrieving the value. + * @param null $names optionally get only defaults for certain variables + * @return array + */ + public function getDefaults($names = null) + { + $defaults = array(); + + $qry = "SELECT name, defaultwert FROM public.tbl_variablenname"; + + if (isset($names) && is_array($names)) + { + $qry .= " WHERE name IN ('".implode(',', $names)."')"; + } + $qry .= ";"; + + $defaultsres = $this->execQuery($qry); + + if (hasData($defaultsres)) + { + $defaults = getData($defaultsres); + + foreach ($defaults as $default) + { + if (!isset($default->defaultwert)) + { + if (isset($this->_dynamic_defaults[$default->name])) + { + $dyndefault = $this->execQuery($this->_dynamic_defaults[$default->name]); + if (hasData($dyndefault)) + { + $dyndefault = getData($dyndefault); + + if (count($dyndefault) === 1) + { + foreach ($dyndefault[0] as $value) + { + $default->defaultwert = $value; + break; + } + } + } + } + } + } + } + + return success($defaults); + } +} diff --git a/application/views/system/infocenter/infocenter.php b/application/views/system/infocenter/infocenter.php index ebc99ba93..4005518a1 100644 --- a/application/views/system/infocenter/infocenter.php +++ b/application/views/system/infocenter/infocenter.php @@ -18,7 +18,7 @@ 'global' => array('mailAnXversandt'), 'ui' => array('bitteEintragWaehlen') ), - 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', + 'customCSSs' => array('public/css/sbadmin2/tablesort_bootstrap.css', 'public/css/infocenter/infocenterPersonDataset.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/infocenter/infocenterPersonDataset.js') ) ); diff --git a/application/views/system/infocenter/infocenterData.php b/application/views/system/infocenter/infocenterData.php index d888f6cd7..6dd0ee957 100644 --- a/application/views/system/infocenter/infocenterData.php +++ b/application/views/system/infocenter/infocenterData.php @@ -11,16 +11,9 @@ $STATUS_KURZBZ = '\'Wartender\', \'Bewerber\', \'Aufgenommener\', \'Student\''; $ADDITIONAL_STG = '10021,10027'; $AKTE_TYP = '\'identity\', \'zgv_bakk\''; + $STUDIENSEMESTER = '\''.$this->variablelib->getVar('infocenter_studiensemester').'\''; $query = ' - WITH currentOrNextStudiensemester AS ( - SELECT ss.studiensemester_kurzbz - FROM public.tbl_studiensemester ss - WHERE ss.ende > NOW() - ORDER BY ss.ende - LIMIT 3 - ) - SELECT p.person_id AS "PersonId", p.vorname AS "Vorname", @@ -100,7 +93,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT cnss.studiensemester_kurzbz FROM currentOrNextStudiensemester cnss) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss @@ -125,7 +118,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT cnss.studiensemester_kurzbz FROM currentOrNextStudiensemester cnss) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss @@ -149,7 +142,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT cnss.studiensemester_kurzbz FROM currentOrNextStudiensemester cnss) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss @@ -173,7 +166,8 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT cnss.studiensemester_kurzbz FROM currentOrNextStudiensemester cnss) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' + AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss @@ -252,7 +246,7 @@ WHERE spss.prestudent_id = sps.prestudent_id AND spss.status_kurzbz = '.$INTERESSENT_STATUS.' AND spss.bestaetigtam IS NULL - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ) ) ORDER BY "LastAction" ASC'; diff --git a/application/views/system/infocenter/infocenterFreigegeben.php b/application/views/system/infocenter/infocenterFreigegeben.php index 40f69528d..15e73f1b6 100644 --- a/application/views/system/infocenter/infocenterFreigegeben.php +++ b/application/views/system/infocenter/infocenterFreigegeben.php @@ -18,7 +18,7 @@ 'global' => array('mailAnXversandt'), 'ui' => array('bitteEintragWaehlen') ), - 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', + 'customCSSs' => array('public/css/sbadmin2/tablesort_bootstrap.css', 'public/css/infocenter/infocenterPersonDataset.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/infocenter/infocenterPersonDataset.js') ) ); diff --git a/application/views/system/infocenter/infocenterFreigegebenData.php b/application/views/system/infocenter/infocenterFreigegebenData.php index 059e30a80..20548d3f4 100644 --- a/application/views/system/infocenter/infocenterFreigegebenData.php +++ b/application/views/system/infocenter/infocenterFreigegebenData.php @@ -8,6 +8,7 @@ $REJECTED_STATUS = '\'Abgewiesener\''; $ADDITIONAL_STG = '10021,10027,10002'; $STATUS_KURZBZ = '\'Wartender\', \'Bewerber\', \'Aufgenommener\', \'Student\''; + $STUDIENSEMESTER = '\''.$this->variablelib->getVar('infocenter_studiensemester').'\''; $query = ' SELECT @@ -179,7 +180,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.studiensemester_kurzbz = \'WS2019\') + AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.studiensemester_kurzbz = '.$STUDIENSEMESTER.') ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestApplied", @@ -215,7 +216,7 @@ AND pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND pss.bestaetigtam IS NOT NULL AND pss.bewerbung_abgeschicktamum IS NOT NULL - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss diff --git a/application/views/system/infocenter/infocenterReihungstestAbsolviert.php b/application/views/system/infocenter/infocenterReihungstestAbsolviert.php index d40b7a572..79f75885b 100644 --- a/application/views/system/infocenter/infocenterReihungstestAbsolviert.php +++ b/application/views/system/infocenter/infocenterReihungstestAbsolviert.php @@ -18,7 +18,7 @@ 'global' => array('mailAnXversandt'), 'ui' => array('bitteEintragWaehlen') ), - 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', + 'customCSSs' => array('public/css/sbadmin2/tablesort_bootstrap.css', 'public/css/infocenter/infocenterPersonDataset.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/infocenter/infocenterPersonDataset.js') ) ); diff --git a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php index ff488b6dc..46f952ec3 100644 --- a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php +++ b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php @@ -6,6 +6,7 @@ $TAETIGKEIT_KURZBZ = '\'bewerbung\', \'kommunikation\''; $LOGDATA_NAME = '\'Login with code\', \'Login with user\', \'New application\''; $ADDITIONAL_STG = '10021,10027'; + $STUDIENSEMESTER = '\''.$this->variablelib->getVar('infocenter_studiensemester').'\''; $query = ' SELECT @@ -191,7 +192,7 @@ AND pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND pss.bestaetigtam IS NOT NULL AND pss.bewerbung_abgeschicktamum IS NOT NULL - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ) ) ORDER BY "LastAction" DESC'; diff --git a/public/css/infocenter/infocenterPersonDataset.css b/public/css/infocenter/infocenterPersonDataset.css new file mode 100644 index 000000000..2e0edf07f --- /dev/null +++ b/public/css/infocenter/infocenterPersonDataset.css @@ -0,0 +1,7 @@ +/* styles for infocenter overview page */ + +/* horizontal line after Studiensemester in dataset table header */ +hr.studiensemesterline +{ + margin: 6px 6px; +} \ No newline at end of file diff --git a/public/js/infocenter/infocenterPersonDataset.js b/public/js/infocenter/infocenterPersonDataset.js index dc6af2284..54933165d 100644 --- a/public/js/infocenter/infocenterPersonDataset.js +++ b/public/js/infocenter/infocenterPersonDataset.js @@ -19,18 +19,26 @@ if (FHC_JS_DATA_STORAGE_OBJECT.called_method == 'index') * */ var InfocenterPersonDataset = { + infocenter_studiensemester_variablename: 'infocenter_studiensemester', /** * adds person table additional actions html (above and beneath it) */ - appendTableActionsHtml: function() + appendTableActionsHtml: function(infocenter_studiensemester) { - var currurl = window.location.href; var url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/system/Messages/write"; var formHtml = '
    '; $("#datasetActionsTop").before(formHtml); + var studienSemesterHtml = ' ' + + infocenter_studiensemester + + ' '; + var selectAllHtml = '
    ' + ' Alle  ' + @@ -44,6 +52,21 @@ var InfocenterPersonDataset = { var legendHtml = ' Gesperrt    ' + ' Geparkt'; + // userdefined Semestervariable shown independently of personcount, + // it is possible to change the semester + $("#datasetActionsTop, #datasetActionsBottom").append( + "
    "+ + "
    "+studienSemesterHtml+"
    "+ + "

    "); + + $("button.incStudiensemester").click(function() { + InfocenterPersonDataset.changeStudiensemesterUservar(1); + }); + + $("button.decStudiensemester").click(function() { + InfocenterPersonDataset.changeStudiensemesterUservar(-1); + }); + var personcount = 0; FHC_AjaxClient.ajaxCallGet( @@ -70,9 +93,9 @@ var InfocenterPersonDataset = { $("#datasetActionsTop, #datasetActionsBottom").append( "
    "+ - "
    " + selectAllHtml + "  " + actionHtml + "
    "+ - "
    " + legendHtml + "
    "+ - "
    " + + "
    " + selectAllHtml + "  " + actionHtml + "
    "+ + "
    " + legendHtml + "
    "+ + "
    " + "" + countHtml + "
    "+ "
    "+ @@ -125,8 +148,65 @@ var InfocenterPersonDataset = { trs.find("input[name=PersonId\\[\\]]").prop("checked", false); } ); - } + }, + /** + * initializes change of the uservariable infocenter_studiensemesster, either + * to next semester (change > 0) or previous semester (change < 0) + */ + changeStudiensemesterUservar: function(change) + { + FHC_AjaxClient.showVeil(); + + FHC_AjaxClient.ajaxCallPost( + 'system/Variables/changeStudiensemesterVar', + { + 'name': InfocenterPersonDataset.infocenter_studiensemester_variablename, + 'change': change + }, + { + successCallback: function(data, textStatus, jqXHR) { + if (FHC_AjaxClient.hasData(data)) + { + // refresh filterwidget with page reload + FHC_FilterWidget.reloadDataset(); + } + }, + errorCallback: function(jqXHR, textStatus, errorThrown) { + FHC_AjaxClient.hideVeil(); + alert(textStatus);//TODO dialoglib + } + } + ); + }, + + /** + * initializes call to get the Studiensemester user variable + */ + getStudiensemesterUservar: function(callback) + { + FHC_AjaxClient.ajaxCallGet( + 'system/Variables/getVar', + { + 'name': InfocenterPersonDataset.infocenter_studiensemester_variablename + }, + { + successCallback: function(data, textStatus, jqXHR) { + if (FHC_AjaxClient.hasData(data)) + { + if (typeof callback === "function") + { + var infocenter_studiensemester = FHC_AjaxClient.getData(data); + callback(infocenter_studiensemester[InfocenterPersonDataset.infocenter_studiensemester_variablename]); + } + } + }, + errorCallback: function(jqXHR, textStatus, errorThrown) { + alert(textStatus); + } + } + ); + } }; /** @@ -134,6 +214,6 @@ var InfocenterPersonDataset = { */ $(document).ready(function() { - InfocenterPersonDataset.appendTableActionsHtml(); + InfocenterPersonDataset.getStudiensemesterUservar(InfocenterPersonDataset.appendTableActionsHtml); }); From 66b605de458a33d9ee4d1d6fd47eac9e0cb427cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Mon, 9 Sep 2019 14:20:07 +0200 Subject: [PATCH 136/500] =?UTF-8?q?Berechtigung=20f=C3=BCr=20das=20L=C3=B6?= =?UTF-8?q?schen=20von=20Reservierungen=20korrigiert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cis/private/lvplan/stpl_reserve_list.php | 28 ++++++++++++------------ include/wochenplan.class.php | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cis/private/lvplan/stpl_reserve_list.php b/cis/private/lvplan/stpl_reserve_list.php index 82f70b612..5e6e1fa85 100644 --- a/cis/private/lvplan/stpl_reserve_list.php +++ b/cis/private/lvplan/stpl_reserve_list.php @@ -23,15 +23,15 @@ require_once('../../../config/cis.config.inc.php'); require_once('../../../include/functions.inc.php'); require_once('../../../include/datum.class.php'); require_once('../../../include/benutzerberechtigung.class.php'); -require_once('../../../include/phrasen.class.php'); -require_once('../../../include/reservierung.class.php'); +require_once('../../../include/phrasen.class.php'); +require_once('../../../include/reservierung.class.php'); if (!$db = new basis_db()) die($p->t('global/fehlerBeimOeffnenDerDatenbankverbindung')); - -$sprache = getSprache(); -$p=new phrasen($sprache); - + +$sprache = getSprache(); +$p=new phrasen($sprache); + $uid = get_uid(); if (isset($_GET['id'])) @@ -67,7 +67,7 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) $reservierung = new reservierung(); if($reservierung->load($id)) { - if(($reservierung->uid==$uid || $reservierung->insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) + if(($reservierung->uid==$uid || $reservierung->insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) { if($reservierung->delete($id)) echo ''.$p->t('lvplan/reservierungWurdeGeloescht').'
    '; @@ -79,17 +79,17 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo ''.$p->t('global/keineBerechtigung').'
    '; } } - else + else echo ''.$p->t('global/fehleraufgetreten').'!
    '; } //Aktuelle Reservierungen abfragen. $datum = time(); $datum = date("Y-m-d",$datum); - + //EIGENE - $sql_query="SELECT * FROM campus.vw_reservierung - WHERE datum>=".$db->db_add_param($datum)." + $sql_query="SELECT * FROM campus.vw_reservierung + WHERE datum>=".$db->db_add_param($datum)." AND (uid=".$db->db_add_param($uid)." OR insertvon=".$db->db_add_param($uid).") ORDER BY datum, titel, ort_kurzbz, stunde"; @@ -97,7 +97,7 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) die($db->db_last_error()); $num_rows_res=$db->db_num_rows($erg_res); - + if ($num_rows_res>0) { echo $p->t('lvplan/eigeneReservierungen').':
    '; @@ -135,7 +135,7 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo '
    '; echo ''; $z=$i-1; - if (($pers_uid==$uid || $insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) + if (($pers_uid==$uid || $insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo ''; echo ''; } @@ -145,7 +145,7 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo '

    '; flush(); - + ?> diff --git a/include/wochenplan.class.php b/include/wochenplan.class.php index 9af13b8ab..d2ef43101 100644 --- a/include/wochenplan.class.php +++ b/include/wochenplan.class.php @@ -702,7 +702,7 @@ class wochenplan extends basis_db $datum=$datum_mon=$this->datum; $rechte = new benutzerberechtigung(); $rechte->getBerechtigungen($user_uid); - $reservberechtigt = $rechte->isBerechtigt('lehre/reservierung', null, 'suid'); + $reservberechtigt = $rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid'); for ($i=1; $i<=TAGE_PRO_WOCHE; $i++) { From b3caf988fdefa78af205dd7ebf2ef4e959b62b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Mon, 9 Sep 2019 15:00:49 +0200 Subject: [PATCH 137/500] EMail an Studierende Link im CIS zeigt nur noch Spezialgruppen an die nicht leer sind --- include/tw/cis_menu_lv.inc.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/tw/cis_menu_lv.inc.php b/include/tw/cis_menu_lv.inc.php index e7936b5a7..3a4a8f13b 100644 --- a/include/tw/cis_menu_lv.inc.php +++ b/include/tw/cis_menu_lv.inc.php @@ -411,12 +411,17 @@ function checkZeilenUmbruch() { if($row->gruppe_kurzbz!='') { - if(!$db->db_parse_bool($row->mailgrp)) + $bngrp = new benutzergruppe(); + $bngrp->load_uids($row->gruppe_kurzbz, $angezeigtes_stsem); + if(isset($bngrp->uids) && count($bngrp->uids) > 0) { - $nomail=$row->gruppe_kurzbz.' '; + if(!$db->db_parse_bool($row->mailgrp)) + { + $nomail=$row->gruppe_kurzbz.' '; + } + else + $mailto.=mb_strtolower($row->gruppe_kurzbz.'@'.DOMAIN.$variable->variable->emailadressentrennzeichen); } - else - $mailto.=mb_strtolower($row->gruppe_kurzbz.'@'.DOMAIN.$variable->variable->emailadressentrennzeichen); } else $mailto.=mb_strtolower($row->stg_typ.$row->stg_kurzbz.$row->semester.trim($row->verband).trim($row->gruppe).'@'.DOMAIN.$variable->variable->emailadressentrennzeichen); From 9237087b338884c38850ce612c908acb5bfeea46 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Mon, 9 Sep 2019 15:59:16 +0200 Subject: [PATCH 138/500] BugFix --- content/fasoverlay.xul.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/fasoverlay.xul.php b/content/fasoverlay.xul.php index 8fef59273..51564dc19 100644 --- a/content/fasoverlay.xul.php +++ b/content/fasoverlay.xul.php @@ -229,13 +229,13 @@ echo ' - + - + From a91cf041d82f58b6cf97f00274864edae155521c Mon Sep 17 00:00:00 2001 From: Nikolaus Krondraf Date: Tue, 10 Sep 2019 08:19:05 +0200 Subject: [PATCH 139/500] Methodenaufruf korrigiert --- cis/private/profile/studienplan.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cis/private/profile/studienplan.php b/cis/private/profile/studienplan.php index dab3e4d73..6097ed136 100644 --- a/cis/private/profile/studienplan.php +++ b/cis/private/profile/studienplan.php @@ -235,7 +235,7 @@ $studiensemester_start = $prestudent->studiensemester_kurzbz; $ausbildungssemester_start = $prestudent->ausbildungssemester; $orgform_kurzbz = $prestudent->orgform_kurzbz; -$prestudent->getLastStatus($student->prestudent_id, 'Student'); +$prestudent->getLastStatus($student->prestudent_id, '', 'Student'); $studienplan_id = $prestudent->studienplan_id; $studienplan = new studienplan(); From 4126167e818effd961497bbb0d47d36ddc2529fa Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Tue, 10 Sep 2019 14:53:04 +0200 Subject: [PATCH 140/500] =?UTF-8?q?PHP7=20Bugfix=20f=C3=BCr=20Notebook=20r?= =?UTF-8?q?egistrierung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cis/private/tools/notebook_registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cis/private/tools/notebook_registration.php b/cis/private/tools/notebook_registration.php index b5704b572..05faf11be 100644 --- a/cis/private/tools/notebook_registration.php +++ b/cis/private/tools/notebook_registration.php @@ -38,7 +38,7 @@ else function ip_increment($ip = "") { - $ip = split("\.", $ip); + $ip = explode(".", $ip); if($ip[3] > 0 && $ip[3] < 254) { From fc98365e09bb60fea41e190254468991e3774ba7 Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Tue, 10 Sep 2019 16:05:42 +0200 Subject: [PATCH 141/500] Bugfix Notebookregistration PHP7 --- cis/private/tools/notebook_registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cis/private/tools/notebook_registration.php b/cis/private/tools/notebook_registration.php index 05faf11be..66dbd2486 100644 --- a/cis/private/tools/notebook_registration.php +++ b/cis/private/tools/notebook_registration.php @@ -128,7 +128,7 @@ function ip_increment($ip = "") { $VLAN = $mfiles->match[1]; $fuser = $mfiles->match[2]; - $fuser = split(" ", $fuser); + $fuser = explode(" ", $fuser); $fuser = $fuser[0]; //hier könnte man noch eine email oder dgl. schicken if ($fuser != $txtUID) From c95b865b2f1b6e1cb7ac0f63df20788e8fcf373b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Tue, 10 Sep 2019 17:42:45 +0200 Subject: [PATCH 142/500] =?UTF-8?q?Bei=20Kartenr=C3=BCcknahme=20wird=20nun?= =?UTF-8?q?=20zus=C3=A4tzlich=20der=20Typ=20des=20Betriebsmittels=20gepr?= =?UTF-8?q?=C3=BCft=20damit=20nicht=20unbeabsichtigt=20andere=20Betriebsmi?= =?UTF-8?q?ttel=20mit=20der=20selben=20Nummer=20ausgetragen=20werden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/betriebsmittelperson.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/betriebsmittelperson.class.php b/include/betriebsmittelperson.class.php index f6a9c1d3d..90be34eb7 100644 --- a/include/betriebsmittelperson.class.php +++ b/include/betriebsmittelperson.class.php @@ -535,6 +535,7 @@ class betriebsmittelperson extends basis_db OR tbl_betriebsmittel.nummer2='.$this->db_add_param('0000'.$nummer).' OR tbl_betriebsmittel.nummer2='.$this->db_add_param('00000'.$nummer).' ) + AND tbl_betriebsmittel.betriebsmitteltyp=\'Zutrittskarte\' AND (ausgegebenam<=now() OR ausgegebenam is NULL) AND (retouram>=now() OR retouram is NULL)'; @@ -595,6 +596,7 @@ class betriebsmittelperson extends basis_db wawi.tbl_betriebsmittel JOIN wawi.tbl_betriebsmittelperson USING(betriebsmittel_id) WHERE tbl_betriebsmittel.nummer='.$this->db_add_param($nummer).' + AND tbl_betriebsmittel.betriebsmitteltyp=\'Zutrittskarte\' AND tbl_betriebsmittelperson.person_id='.$this->db_add_param($person_id); if($this->db_query($qry)) From e17bde6b2105c7d3910c81b9b3690e16d932baca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Wed, 11 Sep 2019 14:43:04 +0200 Subject: [PATCH 143/500] =?UTF-8?q?Fragensprache=20und=20Interface-Sprache?= =?UTF-8?q?=20im=20Testtool=20zusammengef=C3=BChrt.=20Wenn=20die=20Testspr?= =?UTF-8?q?ache=20ge=C3=A4ndert=20wird,=20wird=20jetzt=20auch=20automatisc?= =?UTF-8?q?h=20das=20User=20Interface=20angepasst.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cis/testtool/frage.php | 67 +++------ cis/testtool/gebietfertig.php | 46 ++----- cis/testtool/login.php | 250 ++++++++++++++++------------------ cis/testtool/menu.php | 67 +++------ cis/testtool/topbar.php | 78 ++++------- locale/de-AT/testtool.php | 1 + locale/en-US/testtool.php | 1 + 7 files changed, 192 insertions(+), 318 deletions(-) diff --git a/cis/testtool/frage.php b/cis/testtool/frage.php index 33ec654c6..5dfe3b437 100644 --- a/cis/testtool/frage.php +++ b/cis/testtool/frage.php @@ -42,51 +42,20 @@ if (!$db = new basis_db()) $PHP_SELF=$_SERVER["PHP_SELF"]; -function getSpracheUser() -{ - if(isset($_SESSION['sprache_user'])) - { - $sprache_user=$_SESSION['sprache_user']; - } - else - { - if(isset($_COOKIE['sprache_user'])) - { - $sprache_user=$_COOKIE['sprache_user']; - } - else - { - $sprache_user=DEFAULT_LANGUAGE; - } - setSpracheUser($sprache_user); - } - return $sprache_user; -} - -function setSpracheUser($sprache) -{ - $_SESSION['sprache_user']=$sprache; - setcookie('sprache_user',$sprache,time()+60*60*24*30,'/'); -} - -if(isset($_GET['sprache_user'])) -{ - $sprache_user = new sprache(); - if($sprache_user->load($_GET['sprache_user'])) - { - setSpracheUser($_GET['sprache_user']); - } - else - setSpracheUser(DEFAULT_LANGUAGE); -} - -$sprache_user = getSpracheUser(); -$p = new phrasen($sprache_user); - -$sprache = getSprache(); - +// Start session session_start(); +// If language is changed by language select menu, reset language variables +if (isset($_GET['sprache_user']) && !empty($_GET['sprache_user'])) +{ + $_SESSION['sprache_user'] = $_GET['sprache_user']; + $sprache_user = $_GET['sprache_user']; +} + +// Set language variable, which impacts the question language +$sprache_user = (isset($_SESSION['sprache_user']) && !empty($_SESSION['sprache_user'])) ? $_SESSION['sprache_user'] : DEFAULT_LANGUAGE; +$p = new phrasen($sprache_user); + if(isset($_GET['gebiet_id'])) $gebiet_id = $_GET['gebiet_id']; else @@ -489,7 +458,7 @@ else if($frage->frage_id!='') { $frage_id = $frage->frage_id; - $frage->getFrageSprache($frage_id, $_SESSION['sprache']); + $frage->getFrageSprache($frage_id, $_SESSION['sprache_user']); if(!$demo) { @@ -574,7 +543,7 @@ if($frage->frage_id!='') { echo '
    -


    +


    '; } @@ -585,7 +554,7 @@ if($frage->frage_id!='') { echo '
    -
    '; echo '
    -

    Zustimmung zu selbstverwalteten Pausen

    +

    Zustimmung zur Verplanung in geteilter Arbeitszeit

    -

    Erklärung zu Pausen bei geteilten Arbeitszeiten


    - Ich bin mit der Verplanung meiner Lehre in getrennten Blöcken (Vormittags und Abends) einverstanden und berücksichtige bei der Einteilung meiner Pause,
    - dass ich die tägliche Höchstgrenze laut AZG (10 Stunden) nicht überschreite. Diese Zustimmung gilt jeweils für ein Semester. + Ich bin mit der Verplanung meiner Lehre in getrennten Blöcken (vormittags und abends an einem Tag) einverstanden. +
    Diese Zustimmung gilt jeweils für ein Semester. +

    + Erklärung zu täglichen Ruhepausen bei geteilter Arbeitszeit: Die Verplanung bei geteilter Arbeitszeit hat eine Auswirkung +
    auf die zeitliche Gestaltung/Lage der täglichen Ruhepausen. +

    + Ich berücksichtige bei der Einteilung meiner täglichen Ruhepause, dass ich die tägliche Höchstgrenze der Arbeitszeit +
    von 10 Stunden laut Arbeitszeitgesetz nicht überschritten wird. load($uid, $next_ss); if ( ! $gd->uid ) { - echo '

    Für das kommende Studiensemester '.$next_ss.' erkläre ich mich einverstanden, meine Pausen entsprechend selbst zu verwalten: '; + echo '

    Zustimmung für '.$next_ss.': '; echo 'ja'; echo 'nein'; echo '




    '; @@ -206,11 +216,10 @@ if (isset($_GET['selbstverwaltete-pause']) && !empty($_GET['submit']))

    -

    t('zeitwunsch/zeitwunsch');?>

    diff --git a/include/zeitaufzeichnung_gd.class.php b/include/zeitaufzeichnung_gd.class.php index e91e2158a..db678addb 100644 --- a/include/zeitaufzeichnung_gd.class.php +++ b/include/zeitaufzeichnung_gd.class.php @@ -41,7 +41,7 @@ class zeitaufzeichnung_gd extends basis_db /** * Loads entry for specific user and semester - * @return boolean True, if saving succeeded. + * @return boolean True, if entry is found. */ public function load($user, $sem) { diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index dfb52baad..dcac98148 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -2991,7 +2991,7 @@ if(!@$db->db_query("SELECT 0 FROM campus.tbl_zeitaufzeichnung_gd WHERE 0 = 1")) ALTER TABLE campus.tbl_zeitaufzeichnung_gd ADD CONSTRAINT fk_zeitaufzeichnung_gd_uid FOREIGN KEY (uid) REFERENCES public.tbl_benutzer(uid) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE campus.tbl_zeitaufzeichnung_gd ADD CONSTRAINT fk_zeitaufzeichnung_gd_studiensemester_kurzbz FOREIGN KEY (studiensemester_kurzbz) REFERENCES public.tbl_studiensemester(studiensemester_kurzbz) ON UPDATE CASCADE ON DELETE RESTRICT; - ALTER TABLE campus.tbl_zeitaufzeichnung_gd ADD CONSTRAINT uk_uid_stsem UNIQUE (uid, studiensemester_kurzbz); + ALTER TABLE campus.tbl_zeitaufzeichnung_gd ADD CONSTRAINT uk_zeitaufzeichnung_gd_uid_stsem UNIQUE (uid, studiensemester_kurzbz); COMMENT ON TABLE campus.tbl_zeitaufzeichnung_gd IS \'Table to manage the lectors parted working times; gd = Geteilte Dienste\'; COMMENT ON COLUMN campus.tbl_zeitaufzeichnung_gd.selbstverwaltete_pause IS \'Lectors (dis-)agreement to self-manage breaks\'; From c3cd354f4ccec5ec9abf12da63a7b0321d04275b Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Mon, 1 Jul 2019 16:03:52 +0200 Subject: [PATCH 041/500] =?UTF-8?q?Spalte=20"Fixangestellt"=20hinzugef?= =?UTF-8?q?=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/statistik/lvplanung.xls.php | 48 +++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/content/statistik/lvplanung.xls.php b/content/statistik/lvplanung.xls.php index 5e23fae10..286554392 100644 --- a/content/statistik/lvplanung.xls.php +++ b/content/statistik/lvplanung.xls.php @@ -198,8 +198,10 @@ $worksheet->write($zeile,$spalte,"Studiengang", $format_bold); $maxlength[$spalte]=11; $worksheet->write($zeile,++$spalte,"Organisationseinheit", $format_bold); $maxlength[$spalte]=25; -$worksheet->write($zeile,++$spalte,"Lektor", $format_bold); +$worksheet->write($zeile,++$spalte,"LektorIn", $format_bold); $maxlength[$spalte]=6; +$worksheet->write($zeile,++$spalte,"Fixangestellt", $format_bold); +$maxlength[$spalte]=10; $worksheet->write($zeile,++$spalte,"Bezeichnung", $format_bold); $maxlength[$spalte]=25; $worksheet->write($zeile,++$spalte,"Semester", $format_bold); @@ -268,6 +270,11 @@ if($result = $db->db_query($qry)) if($maxlength[$spalte]nachname.' '.$mitarbeiter->vorname)) $maxlength[$spalte]=mb_strlen($mitarbeiter->nachname.' '.$mitarbeiter->vorname); + //Fixangestellt + $worksheet->write($zeile,++$spalte,($mitarbeiter->fixangestellt ? 'Ja' : 'Nein')); + if($maxlength[$spalte]fixangestellt ? 'Ja' : 'Nein')) + $maxlength[$spalte]=mb_strlen($mitarbeiter->fixangestellt ? 'Ja' : 'Nein'); + //Lehrfach $worksheet->write($zeile,++$spalte,$row->lf_bezeichnung); //if($maxlength[$spalte]lf_bezeichnung)) @@ -380,7 +387,8 @@ if($result = $db->db_query($qry)) student_uid, stunden, tbl_projektbetreuer.stundensatz, - tbl_projektbetreuer.faktor + tbl_projektbetreuer.faktor, + tbl_projektbetreuer.person_id FROM lehre.tbl_projektarbeit, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, @@ -419,6 +427,39 @@ if($result = $db->db_query($qry)) $spalte=0; $zeile++; + $benutzer = new benutzer(); + $benutzer->getBenutzerFromPerson($row->person_id, false); + if (count($benutzer->result) > 0) + { + foreach ($benutzer->result AS $bn) + { + $mitarbeiter = new mitarbeiter($bn->uid); + if ($mitarbeiter->load($bn->uid)) + { + if ($mitarbeiter->fixangestellt) + { + $fixangestellt = 'Ja'; + break; + } + else + { + $fixangestellt = 'Nein'; + break; + } + } + else + { + continue; + } + + } + } + else + { + $fixangestellt = 'Extern'; + } + + //Studiengang $worksheet->write($zeile,$spalte,$stg_obj->kuerzel_arr[$row->studiengang_kz]); if($maxlength[$spalte]kuerzel_arr[$row->studiengang_kz])) @@ -434,6 +475,9 @@ if($result = $db->db_query($qry)) //if($maxlength[$spalte]nachname.' '.$row->vorname)) //$maxlength[$spalte]=mb_strlen($row->nachname.' '.$row->vorname); + //Fixangestellt + $worksheet->write($zeile,++$spalte,$fixangestellt); + //Lehrfach $worksheet->write($zeile,++$spalte,$row->bezeichnung); //if($maxlength[$spalte]bezeichnung)) From 12d0bbfa520d5a605111424b2d04edfa9b81dd48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Wed, 3 Jul 2019 18:07:29 +0200 Subject: [PATCH 042/500] Fixed invalid Session Handling on Infoterminal Page --- cis/infoterminal/index.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cis/infoterminal/index.php b/cis/infoterminal/index.php index acbd7b0e4..1a913c421 100644 --- a/cis/infoterminal/index.php +++ b/cis/infoterminal/index.php @@ -20,14 +20,6 @@ * Rudolf Hangl < rudolf.hangl@technikum-wien.at > * Gerald Simane-Sequens < gerald.simane-sequens@technikum-wien.at > */ - -// ------------------------------------------------------------------------------------------ -// Session Starten - Merk Anwenderdaten -// ------------------------------------------------------------------------------------------ - $SESSIONID=trim((isset($_REQUEST['SESSIONID']) ? $_REQUEST['SESSIONID']:'')); - if (session_start($SESSIONID)) - $SESSIONID=@session_id(); - require_once('../../config/cis.config.inc.php'); require_once('../../include/wochenplan.class.php'); require_once('../../include/benutzerberechtigung.class.php'); From f8ecc0b91649e287c4bebb9915264dc3bf0efa9f Mon Sep 17 00:00:00 2001 From: Nikolaus Krondraf Date: Thu, 4 Jul 2019 10:40:38 +0200 Subject: [PATCH 043/500] =?UTF-8?q?matr=5Fnr=20bei=20Studenten=20erg=C3=A4?= =?UTF-8?q?nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/zutrittskarte.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/zutrittskarte.php b/content/zutrittskarte.php index f319dad73..70a0f91b0 100644 --- a/content/zutrittskarte.php +++ b/content/zutrittskarte.php @@ -40,6 +40,7 @@ require_once('../include/studiengang.class.php'); require_once('../include/benutzerfunktion.class.php'); require_once('../include/organisationseinheit.class.php'); require_once('../include/dokument_export.class.php'); +require_once('../include/person.class.php'); $user = get_uid(); $db = new basis_db(); @@ -232,6 +233,8 @@ foreach ($uid_arr as $uid) $konto = new konto(); $studiengang = new studiengang(); $studiengang->load($student->studiengang_kz); + $person = new person(); + $person->getPersonFromBenutzer($uid); $stsem_obj = new studiensemester(); $stsem = $stsem_obj->getaktorNext(); @@ -265,6 +268,7 @@ foreach ($uid_arr as $uid) 'studiengang' => $studiengang->kurzbzlang, 'gebdatum' => $datum_obj->formatDatum($bn->gebdatum, 'd.m.Y'), 'matrikelnummer' => $student->matrikelnr, + 'matr_nr' => $person->matr_nr, 'ausstellungsdatum' => date('M.Y'), 'gueltigbis' => $datum_obj->formatDatum($gueltigbis, 'd.m.Y') ); From 8f5b32ee94ded55616b897c7c6bc723b213edf41 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 4 Jul 2019 11:21:30 +0200 Subject: [PATCH 044/500] education/Lehreinheit_model: getLesForLv method: Lehreinheiten ordered by lehreinheit_id by default --- .../models/education/Lehreinheit_model.php | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/application/models/education/Lehreinheit_model.php b/application/models/education/Lehreinheit_model.php index 22778cb6a..10c122b94 100644 --- a/application/models/education/Lehreinheit_model.php +++ b/application/models/education/Lehreinheit_model.php @@ -28,6 +28,7 @@ class Lehreinheit_model extends DB_Model { $lehreinheiten = array(); + $this->addOrder('lehreinheit_id'); $les = $this->loadWhere( array('lehrveranstaltung_id' => $lehrveranstaltung_id, 'studiensemester_kurzbz' => $studiensemester) @@ -62,17 +63,17 @@ class Lehreinheit_model extends DB_Model if (hasData($studiengangresponse)) { $studiengang = $studiengangresponse->retval[0]; - $stgkuerzel = mb_strtoupper($studiengang->typ . $studiengang->kurzbz); + $stgkuerzel = mb_strtoupper($studiengang->typ.$studiengang->kurzbz); - $letoadd->lehreinheitgruppen[] = array( - 'semester' => $lehreinheitgruppe->semester, - 'verband' => $lehreinheitgruppe->verband, - 'gruppe' => $lehreinheitgruppe->gruppe, - 'gruppe_kurzbz' => $lehreinheitgruppe->gruppe_kurzbz, - 'direktinskription' => $lehreinheitgruppe->direktinskription, - 'studiengang_kz' => $lehreinheitgruppe->studiengang_kz, - 'studiengang_kuerzel' => $stgkuerzel - ); + $letoadd->lehreinheitgruppen[] = array( + 'semester' => $lehreinheitgruppe->semester, + 'verband' => $lehreinheitgruppe->verband, + 'gruppe' => $lehreinheitgruppe->gruppe, + 'gruppe_kurzbz' => $lehreinheitgruppe->gruppe_kurzbz, + 'direktinskription' => $lehreinheitgruppe->direktinskription, + 'studiengang_kz' => $lehreinheitgruppe->studiengang_kz, + 'studiengang_kuerzel' => $stgkuerzel + ); } } } From f664f1442fa4f86da4b21c5e492f2f7a3b40b54b Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 4 Jul 2019 11:25:32 +0200 Subject: [PATCH 045/500] - public/js/DialogLib.js: if dialog already present, it is removed before new one is attached (if dialogs are displayed on same page one afte another) --- public/js/DialogLib.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/js/DialogLib.js b/public/js/DialogLib.js index 05558844a..f5d373604 100644 --- a/public/js/DialogLib.js +++ b/public/js/DialogLib.js @@ -55,7 +55,12 @@ var FHC_DialogLib = { */ alertDefault: function(title, html, width) { - var strDivDialog = "
    "; + var dialogdiv = $("#fhc-dialoglib-dialog"); + + if (dialogdiv.length) + dialogdiv.remove(); + + var strDivDialog = "
    "; strDivDialog += html; strDivDialog += "
    "; From 48c57136882495a88901533fcc5c4f209f1c86af Mon Sep 17 00:00:00 2001 From: raab Date: Thu, 4 Jul 2019 17:02:11 +0200 Subject: [PATCH 046/500] geteilte arbeitszeit konfigurierbar --- cis/private/profile/zeitwunsch.php | 11 ++--------- config/cis.config-default.inc.php | 4 ++++ locale/de-AT/zeitwunsch.php | 5 +++-- locale/en-US/zeitwunsch.php | 5 +++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cis/private/profile/zeitwunsch.php b/cis/private/profile/zeitwunsch.php index 623bc78fe..73ba51bf9 100644 --- a/cis/private/profile/zeitwunsch.php +++ b/cis/private/profile/zeitwunsch.php @@ -180,7 +180,7 @@ if (isset($_GET['selbstverwaltete-pause']) && !empty($_GET['submit']))
    - +'; echo ''; $z=$i-1; - if (($pers_uid==$uid)|| ($insertvon==$uid) || $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) - echo ''; + if (($pers_uid==$uid || $insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) + echo ''; echo ''; } echo '
    @@ -188,15 +188,8 @@ if (isset($_GET['selbstverwaltete-pause']) && !empty($_GET['submit']))

    - Ich bin mit der Verplanung meiner Lehre in getrennten Blöcken (vormittags und abends an einem Tag) einverstanden. -
    Diese Zustimmung gilt jeweils für ein Semester. -

    - Erklärung zu täglichen Ruhepausen bei geteilter Arbeitszeit: Die Verplanung bei geteilter Arbeitszeit hat eine Auswirkung -
    auf die zeitliche Gestaltung/Lage der täglichen Ruhepausen. -

    - Ich berücksichtige bei der Einteilung meiner täglichen Ruhepause, dass ich die tägliche Höchstgrenze der Arbeitszeit -
    von 10 Stunden laut Arbeitszeitgesetz nicht überschritten wird. t('zeitwunsch/geteilteArbeitszeit'); $gd = new zeitaufzeichnung_gd(); $gd->load($uid, $next_ss); if ( ! $gd->uid ) diff --git a/config/cis.config-default.inc.php b/config/cis.config-default.inc.php index 3f75b0af3..28376a04f 100644 --- a/config/cis.config-default.inc.php +++ b/config/cis.config-default.inc.php @@ -245,4 +245,8 @@ define('CIS_LVMENUE_CUTLENGTH', 21); // Gibt an, auf welche Seite TicketIds ala #1234 im Jahresplan verlinkt werden zB zur Verlinkung in Bugtracker define('JAHRESPLAN_TICKET_LINK','https://bug.technikum-wien.at/otrs/index.pl?Action=AgentTicketZoom;TicketNumber='); + +//Gibt an ob der Block zu Verplanung in geteilter Arbeitszeit bei den Zeitwünschen angezeigt wird. Default: false +define('CIS_ZEITWUNSCH_GD', false); + ?> diff --git a/locale/de-AT/zeitwunsch.php b/locale/de-AT/zeitwunsch.php index 19e188530..a84da2b0e 100644 --- a/locale/de-AT/zeitwunsch.php +++ b/locale/de-AT/zeitwunsch.php @@ -14,7 +14,7 @@ $this->phrasen['zeitwunsch/bedeutung']='Bedeutung'; $this->phrasen['zeitwunsch/hierMoechteIchUnterrichten']='Hier möchte ich unterrichten'; $this->phrasen['zeitwunsch/hierKannIchUnterrichten']='Hier kann ich unterrichten'; $this->phrasen['zeitwunsch/nurInNotfaellen']='Hier unterrichte ich nur ungern'; -$this->phrasen['zeitwunsch/hierAufGarKeinenFall']='Hier kann ich gar nicht unterrichten'; +$this->phrasen['zeitwunsch/hierAufGarKeinenFall']='Hier kann ich gar nicht unterrichten'; $this->phrasen['zeitwunsch/folgendePunkteSindZuBeachten']='Folgende Punkte sind zu beachten'; $this->phrasen['zeitwunsch/verwendenSieDenWertNur']='Verwenden Sie den Wert -2 nur, wenn Sie zu dieser Stunde wirklich nicht können, um eine bessere Optimierung zu ermöglichen.'; $this->phrasen['zeitwunsch/sperrenSieNurTermine']='Markieren Sie mit den Werten -1 und -2 bitte nur Termine, die für die Lehre an der FH nicht in Frage kommen.
    Die Zeitsperren sind nicht dafür gedacht, bereits zugesagte Stunden für bestimmte Studiengänge zu reservieren.'; @@ -22,4 +22,5 @@ $this->phrasen['zeitwunsch/esSolltenFuerJedeStunde']='Es sollten für jede Stund $this->phrasen['zeitwunsch/erklaerung']='Erklärung'; $this->phrasen['zeitwunsch/beiProblemenWendenSieSichAn']='Bei Problemen wenden Sie sich bitte an die'; $this->phrasen['zeitwunsch/profil']='Profil'; -?> \ No newline at end of file +$this->phrasen['zeitwunsch/geteilteArbeitszeit']='Ich bin mit der Verplanung meiner Lehre in getrennten Blöcken am Tagesrand einverstanden.'; +?> diff --git a/locale/en-US/zeitwunsch.php b/locale/en-US/zeitwunsch.php index 9d6e32119..dd9abdc3e 100644 --- a/locale/en-US/zeitwunsch.php +++ b/locale/en-US/zeitwunsch.php @@ -14,7 +14,7 @@ $this->phrasen['zeitwunsch/bedeutung']='Meaning'; $this->phrasen['zeitwunsch/hierMoechteIchUnterrichten']='I would like to teach at this time'; $this->phrasen['zeitwunsch/hierKannIchUnterrichten']='I can teach at this time'; $this->phrasen['zeitwunsch/nurInNotfaellen']='I would prefer not to teach at this time'; -$this->phrasen['zeitwunsch/hierAufGarKeinenFall']='I can not at all teach at this time'; +$this->phrasen['zeitwunsch/hierAufGarKeinenFall']='I can not at all teach at this time'; $this->phrasen['zeitwunsch/folgendePunkteSindZuBeachten']='Please note:'; $this->phrasen['zeitwunsch/verwendenSieDenWertNur']='To make a better optimization possible, please only use the value of -2 if you really can not teach at this time.'; $this->phrasen['zeitwunsch/sperrenSieNurTermine']='Please only mark times where you are absolutely not available to teach at the UAS with the numbers 1 and 2.
    Do not mark times for specific courses that you have already been assigned to teach at the UAS as unavailable.'; @@ -22,4 +22,5 @@ $this->phrasen['zeitwunsch/esSolltenFuerJedeStunde']='The amount of preferred te $this->phrasen['zeitwunsch/erklaerung']='Explanation'; $this->phrasen['zeitwunsch/beiProblemenWendenSieSichAn']='If you are having problems, please contact the '; $this->phrasen['zeitwunsch/profil']='Profile'; -?> \ No newline at end of file +$this->phrasen['zeitwunsch/geteilteArbeitszeit']='Ich bin mit der Verplanung meiner Lehre in getrennten Blöcken am Tagesrand einverstanden.'; +?> From ddaa129bab09adec06e9e9715406811d34fb7343 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 4 Jul 2019 17:25:13 +0200 Subject: [PATCH 047/500] - Removed controllers api/v1/system/CallerLibrary.php and api/v1/system/CallerModel.php - Removed library libraries/CallerLib.php --- .../api/v1/system/CallerLibrary.php | 77 ---- .../controllers/api/v1/system/CallerModel.php | 77 ---- application/libraries/CallerLib.php | 361 ------------------ 3 files changed, 515 deletions(-) delete mode 100644 application/controllers/api/v1/system/CallerLibrary.php delete mode 100644 application/controllers/api/v1/system/CallerModel.php delete mode 100644 application/libraries/CallerLib.php diff --git a/application/controllers/api/v1/system/CallerLibrary.php b/application/controllers/api/v1/system/CallerLibrary.php deleted file mode 100644 index 594786384..000000000 --- a/application/controllers/api/v1/system/CallerLibrary.php +++ /dev/null @@ -1,77 +0,0 @@ - 'admin:rw')); - - // Loads the CallerLib - $this->load->library('CallerLib'); - } - - /** - * Manages a HTTP get call - */ - public function getCall() - { - // Start me up! - $result = $this->callerlib->callLibrary($this->get()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function postCall() - { - // Start me up! - $result = $this->callerlib->callLibrary($this->post()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function putCall() - { - // Start me up! - $result = $this->callerlib->callLibrary($this->put()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function deleteCall() - { - // Start me up! - $result = $this->callerlib->callLibrary($this->delete()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } -} diff --git a/application/controllers/api/v1/system/CallerModel.php b/application/controllers/api/v1/system/CallerModel.php deleted file mode 100644 index 68296aff8..000000000 --- a/application/controllers/api/v1/system/CallerModel.php +++ /dev/null @@ -1,77 +0,0 @@ - 'admin:rw')); - - // Loads the CallerLib - $this->load->library('CallerLib'); - } - - /** - * Manages a HTTP get call - */ - public function getCall() - { - // Start me up! - $result = $this->callerlib->callModel($this->get()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function postCall() - { - // Start me up! - $result = $this->callerlib->callModel($this->post()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function putCall() - { - // Start me up! - $result = $this->callerlib->callModel($this->put()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } - - /** - * @return void - */ - public function deleteCall() - { - // Start me up! - $result = $this->callerlib->callModel($this->delete()); - - // Print the result - $this->response($result, REST_Controller::HTTP_OK); - } -} diff --git a/application/libraries/CallerLib.php b/application/libraries/CallerLib.php deleted file mode 100644 index 0b46cf0c6..000000000 --- a/application/libraries/CallerLib.php +++ /dev/null @@ -1,361 +0,0 @@ -_ci =& get_instance(); // Gets CI instance - } - - /** - * Wrapper method for _call - */ - public function callLibrary($callParameters) - { - return $this->_call($callParameters); - } - - /** - * Wrapper method for _call - */ - public function callModel($callParameters) - { - return $this->_call($callParameters); - } - - /** - * Everything starts here... - */ - private function _call($callParameters) - { - $result = null; - $parameters = $this->_getParameters($callParameters); - $validation = $this->_validateCall($parameters); - - // If the validation was passed - if (isSuccess($validation)) - { - $loaded = null; - // If the given resource is a model - if (strpos($parameters->resourceName, CallerLib::MODEL_PREFIX) !== false) - { - // Try to load the model - $result = $this->_loadModel($parameters->resourcePath, $parameters->resourceName); - if (isSuccess($result)) - { - $loaded = $result->retval; - } - } - // If the given resource is a library - elseif (strpos($parameters->resourceName, CallerLib::LIB_PREFIX) !== false) - { - // Check if the resource is already loaded, it works only with libraries and drivers - $isLoaded = $this->_ci->load->is_loaded($parameters->resourceName); - // If not loaded then load it - if ($isLoaded === false) - { - // Try to load the library - $result = $this->_loadLibrary($parameters->resourcePath, $parameters->resourceName); - if (isSuccess($result)) - { - $loaded = $result->retval; - } - } - // If it is already loaded $isLoaded contains the instance of the library - else - { - $loaded = $isLoaded; - } - } - // Wrong selection! - else - { - $result = error('Neither a lib nor model: '.$parameters->resourcePath.$parameters->resourceName); - } - - // If the resource was found and loaded - if (!is_null($loaded)) - { - $result = $this->_callThis($parameters->resourceName, $parameters->function, $parameters->parameters); - } - else - { - // Resource not loaded - } - } - else - { - $result = $validation; - } - - return $result; - } - - /** - * Gets the parameters from the http call - * Search for parameters and - * is the name of the model or of the library - * is the name of the method present in the model/library - * All the others parameters will be given to the method in the same order that - * they are present in the HTTP call - * EX: - * URL: ../system/CallerLibrary/Call?resource=&function=&=&=&= - * will call .(par1, par2, par3) - */ - private function _getParameters($parametersArray) - { - $parameters = new stdClass(); - $parameters->parameters = array(); - $count = 0; - - foreach ($parametersArray as $parameterName => $parameterValue) - { - // The name of the resource, path included - if ($parameterName == CallerLib::RESOURCE_PARAMETER) - { - // Separates the resource path from the resource name - $splittedResource = preg_split(CallerLib::REG_SPLIT_EXPR, $parameterValue); - $parameters->resourceName = $splittedResource[count($splittedResource) - 1]; - $parameters->resourcePath = str_replace($parameters->resourceName, '', $parameterValue); - } - // The name of the function - elseif ($parameterName == CallerLib::FUNCTION_PARAMETER) - { - $parameters->function = $parameterValue; - } - // It is assumed that all other parameters are the parameters to be passed to the function - // They will be passed to the function in the same order in which they are passed to - // this controller - else - { - $parameters->parameters[$count++] = $parameterValue; - } - } - - return $parameters; - } - - /** - * Validate the given parameters - */ - private function _validateCall($parameters) - { - if (!is_object($parameters)) - { - return error('Parameter is not an object'); - } - if (!isset($parameters->resourcePath)) - { - return error('Resource path is not specified'); - } - if (!isset($parameters->resourceName)) - { - return error('Resource name is not specified'); - } - if (!isset($parameters->function)) - { - return error('Function is not specified'); - } - if (!is_array($parameters->parameters)) - { - return error('Parameters are not specified'); - } - if (in_array($parameters->resourceName, CallerLib::$RESOURCES_BLACK_LIST)) - { - return error('You are trying to access to unauthorized resources'); - } - - return success('Input data are valid'); - } - - /** - * Loads a model using the given path and name - * - * NOTE: the models automatically handle the permissions - */ - private function _loadModel($resourcePath, $resourceName) - { - $loaded = null; - $result = null; - - try - { - $loaded = $this->_ci->load->model($resourcePath.$resourceName); - } - catch (Exception $e) - { - // Errors while loading the model - $result = error('Errors while loading the model: '.$e->getMessage()); - } - - if (!is_null($loaded)) - { - $result = success($loaded); - } - - return $result; - } - - /** - * Loads a library using the given path and name - * - * The method 'library' of the class CI_Loader provided by CI has some limitations, - * so to be able to check errors was used a workaround. - * It consists in: - * - Checking if the file (identified by parameters $resourcePath and $resourceName) exists - * - If exists it will be loaded using the method 'file' from CI_Loader - * - Checks if the loaded file contains a class identified by parameter $resourceName - * - * If one of the previous tests fails, it will be returned a null value - */ - private function _loadLibrary($resourcePath, $resourceName) - { - $loaded = null; - - try - { - // Gets all the configured resources paths - $packagePaths = $this->_ci->load->get_package_paths(); - // Looking for a file in every paths with the same name of the resource - $found = null; - for ($i = 0; $i < count($packagePaths) && is_null($found); $i++) - { - $file = $packagePaths[$i].CallerLib::LIBS_PATH.DIRECTORY_SEPARATOR. - $resourcePath.$resourceName.CallerLib::LIB_FILE_EXTENSION; - if (file_exists($file)) - { - $found = $file; - } - } - - // If the file was found - if (!is_null($found)) - { - // Load the file - $loaded = $this->_ci->load->file($found); - // If the resource is not present inside the file - if (!class_exists($resourceName)) - { - $loaded = null; - // Same phrase error as load->model() provided by CI - $result = error($found.' exists, but doesn\'t declare class '.$resourceName); - } - } - else - { - $loaded = null; - // Same phrase error as load->model() provided by CI - $result = error('Unable to load the requested class: '.$resourceName); - } - } - catch (Exception $e) - { - // Errors while loading the library - $result = error('Errors while loading the library: '.$e->getMessage()); - } - - if (!is_null($loaded)) - { - $result = success($loaded); - } - - return $result; - } - - /** - * Calls a method of a class with the given parameters and returns its result - * - * @param string $resourceName identifies the class name - * @param string $function identifies the method name - * @param array $parameters contains the parameters to be passed to the method - */ - private function _callThis($resourceName, $function, $parameters) - { - $result = null; - - try - { - // Get informations about the function - $reflectionMethod = new ReflectionMethod($resourceName, $function); - // If the number of given parameters is greater or equal to the number of - // parameters required by the function - if (count($parameters) >= $reflectionMethod->getNumberOfRequiredParameters()) - { - // If the function is static - if ($reflectionMethod->isStatic() === true) - { - $classMethod = $resourceName.'::'.$function; - } - // If the function is not static - else - { - $classMethod = array(new $resourceName(), $function); - } - - // If the resource's function is callable - if (is_callable($classMethod)) - { - // Call resource->function() - // @ was applied to prevent really ugly and unmanageable errors - $resultCall = @call_user_func_array($classMethod, $parameters); - // If errors occurred while running it - // NOTE: if the called function via call_user_func_array returns a boolean set as false, - // it will be recognized like a running error. A little bit tricky ;) - if ($resultCall === false) - { - $result = error('Error running '.$resourceName.'->'.$function.'()'); - } - // Returns the result of resource->function() - else - { - $result = success($resultCall); - } - } - else - { - $result = error($resourceName.'->'.$function.'() is not callable!'); - } - } - else - { - $result = error( - 'Number of required parameters: '.$reflectionMethod->getNumberOfRequiredParameters().'. Given: '.count($parameters) - ); - } - } - catch (Exception $e) - { - $result = error($e->getMessage()); - } - - return $result; - } -} From 638a0a90a46203bd99e22c87eb8d5c856a1f30cb Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 4 Jul 2019 17:25:24 +0200 Subject: [PATCH 048/500] - Berechtigungscheck for reservation deletion on "meine Reservierungen anzeigen"-page corrected - removed "Alle Reservierungen anzeigen" Link --- cis/private/lvplan/stpl_reserve_list.php | 67 ++---------------------- locale/de-AT/lvplan.php | 1 - locale/en-US/lvplan.php | 1 - locale/it-IT/lvplan.php | 1 - 4 files changed, 3 insertions(+), 67 deletions(-) diff --git a/cis/private/lvplan/stpl_reserve_list.php b/cis/private/lvplan/stpl_reserve_list.php index a882b8344..82f70b612 100644 --- a/cis/private/lvplan/stpl_reserve_list.php +++ b/cis/private/lvplan/stpl_reserve_list.php @@ -67,7 +67,7 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) $reservierung = new reservierung(); if($reservierung->load($id)) { - if($reservierung->uid==$uid || $reservierung->insertvon==$uid || $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) + if(($reservierung->uid==$uid || $reservierung->insertvon==$uid) && $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) { if($reservierung->delete($id)) echo ''.$p->t('lvplan/reservierungWurdeGeloescht').'
    '; @@ -135,8 +135,8 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo '

    '.$db->convert_html_chars($pers_uid).''.$db->convert_html_chars($beschreibung).' DeleteDelete
    '; @@ -146,67 +146,6 @@ if(!$rechte->isBerechtigt('lehre/reservierung:begrenzt', null, 'suid')) echo '

    '; flush(); - if(isset($_GET['alle'])) - { - - //ALLE - $sql_query="SELECT * FROM campus.vw_reservierung - WHERE datum>=".$db->db_add_param($datum)." - ORDER BY datum, titel, ort_kurzbz, stunde"; - if (!$erg_res=$db->db_query($sql_query)) - die($db->db_last_error()); - - $num_rows_res=$db->db_num_rows($erg_res); - if ($num_rows_res>0) - { - echo $p->t('lvplan/alleReservierungen').':
    '; - echo ''; - echo ' - - - - - - - - - '; - - for ($i=0; $i<$num_rows_res; $i++) - { - $zeile=$i % 2; - $id=$db->db_result($erg_res,$i,"reservierung_id"); - $datum=$db->db_result($erg_res,$i,"datum"); - $titel=$db->db_result($erg_res,$i,"titel"); - $stunde=$db->db_result($erg_res,$i,"stunde"); - $ort_kurzbz=$db->db_result($erg_res,$i,"ort_kurzbz"); - $pers_uid=$db->db_result($erg_res,$i,"uid"); - $beschreibung=$db->db_result($erg_res,$i,"beschreibung"); - $insertamum=$db->db_result($erg_res,$i,"insertamum"); - $insertvon=$db->db_result($erg_res,$i,"insertvon"); - - $datum = $datum_obj->formatDatum($datum, 'd.m.Y'); - if($insertamum!='') - $insertamum = $datum_obj->formatDatum($insertamum, 'd.m.Y H:i:s'); - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - $z=$i-1; - if (($pers_uid==$uid) || ($insertvon==$uid) || $rechte->isBerechtigt('lehre/reservierung', null, 'suid')) - echo ''; - echo ''; - } - echo '
    '.$p->t('global/datum').''.$p->t('global/titel').''.$p->t('global/stunde').''.$p->t('lvplan/raum').''.$p->t('global/person').''.$p->t('global/beschreibung').''.$p->t('global/aktion').'
    '.$db->convert_html_chars($datum).''.$db->convert_html_chars($titel).''.$db->convert_html_chars($stunde).''.$db->convert_html_chars($ort_kurzbz).''.$db->convert_html_chars($pers_uid).''.$db->convert_html_chars($beschreibung).' Delete
    '; - flush(); - } - } - else - echo ''.$p->t('lvplan/alleReservierungenAnzeigen').''; - ?> diff --git a/locale/de-AT/lvplan.php b/locale/de-AT/lvplan.php index 6f7d3b58c..d7510d341 100644 --- a/locale/de-AT/lvplan.php +++ b/locale/de-AT/lvplan.php @@ -23,7 +23,6 @@ $this->phrasen['lvplan/fehlerUndFeedback']='Feedback geben'; $this->phrasen['lvplan/lvKoordinationsstelle']='LV-Koordinationsstelle'; $this->phrasen['lvplan/reservierungen']='Reservierungen'; $this->phrasen['lvplan/reservierungWurdeGeloescht']='Reservierung wurde geloescht'; -$this->phrasen['lvplan/alleReservierungenAnzeigen']='Alle Reservierungen anzeigen'; $this->phrasen['lvplan/alleReservierungen']='Alle Reservierungen'; $this->phrasen['lvplan/zurReservierung']='Zur Reservierung'; $this->phrasen['lvplan/raum']='Raum'; diff --git a/locale/en-US/lvplan.php b/locale/en-US/lvplan.php index e40e1f9e0..ebab1ce85 100644 --- a/locale/en-US/lvplan.php +++ b/locale/en-US/lvplan.php @@ -23,7 +23,6 @@ $this->phrasen['lvplan/fehlerUndFeedback']='Send Feedback'; $this->phrasen['lvplan/lvKoordinationsstelle']='Course-Coordination Office'; $this->phrasen['lvplan/reservierungen']='Reservations'; $this->phrasen['lvplan/reservierungWurdeGeloescht'] = 'Reservation successfully deleted'; -$this->phrasen['lvplan/alleReservierungenAnzeigen']='Show all reservations'; $this->phrasen['lvplan/alleReservierungen']='All reservations'; $this->phrasen['lvplan/zurReservierung']='Reservation'; $this->phrasen['lvplan/raum']='Room'; diff --git a/locale/it-IT/lvplan.php b/locale/it-IT/lvplan.php index 026caf68e..4434bdbdd 100644 --- a/locale/it-IT/lvplan.php +++ b/locale/it-IT/lvplan.php @@ -2,7 +2,6 @@ $this->phrasen['lvplan/aktuelleKW']='numero di settimana attuale'; $this->phrasen['lvplan/alleRaeume']='tutte le sale'; $this->phrasen['lvplan/alleReservierungen']='tutte le prenotazioni'; -$this->phrasen['lvplan/alleReservierungenAnzeigen']='mostra tutte le prenotazioni'; $this->phrasen['lvplan/anleitungLVPlanSync']=''; $this->phrasen['lvplan/anzahlPersonen']=''; $this->phrasen['lvplan/bereitsReserviert']=''; From 19425b93f0229f058513d449cfa0d5b6269d33bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 5 Jul 2019 07:29:03 +0200 Subject: [PATCH 049/500] Employees can now also be assigned directly to Courses (for Elective Courses) --- rdf/benutzer.rdf.php | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/rdf/benutzer.rdf.php b/rdf/benutzer.rdf.php index 182ce7058..3bcd2ef64 100644 --- a/rdf/benutzer.rdf.php +++ b/rdf/benutzer.rdf.php @@ -40,8 +40,8 @@ $filter = filter_input(INPUT_GET,'filter'); if (mb_strlen($filter) < 3) die('Filter muss mindestens 3 Zeichen lang sein'); -$benutzer = new student(); -$benutzer->getTab($filter, 'nachname, vorname'); +$benutzer = new benutzer(); +$benutzer->search(array($filter)); $studiengang = new studiengang(); $studiengang->getAll(null, false); @@ -49,22 +49,37 @@ $studiengang->getAll(null, false); $oRdf->sendHeader(); $db = new basis_db(); -if(count($benutzer->result) > 0) +if (count($benutzer->result) > 0) { - $i=0; - foreach($benutzer->result as $row) + $i = 0; + foreach ($benutzer->result as $row) { - if(isset($studiengang->kuerzel_arr[$row->studiengang_kz])) - $stg = $studiengang->kuerzel_arr[$row->studiengang_kz]; + $stud = new student(); + if ($stud->load($row->uid)) + { + if (isset($studiengang->kuerzel_arr[$stud->studiengang_kz])) + { + $stg = $studiengang->kuerzel_arr[$stud->studiengang_kz]; + $semester = $stud->semester; + } + else + { + $stg = ''; + $semester = ''; + } + } else + { $stg = ''; + $semester = ''; + } - $i=$oRdf->newObjekt($i); - $oRdf->obj[$i]->setAttribut('uid',$row->uid,true); - $oRdf->obj[$i]->setAttribut('vorname',$row->vorname,true); - $oRdf->obj[$i]->setAttribut('nachname',$row->nachname,true); - $oRdf->obj[$i]->setAttribut('studiengang',$stg,true); - $oRdf->obj[$i]->setAttribut('semester',$row->semester,true); + $i = $oRdf->newObjekt($i); + $oRdf->obj[$i]->setAttribut('uid', $row->uid, true); + $oRdf->obj[$i]->setAttribut('vorname', $row->vorname, true); + $oRdf->obj[$i]->setAttribut('nachname', $row->nachname, true); + $oRdf->obj[$i]->setAttribut('studiengang', $stg, true); + $oRdf->obj[$i]->setAttribut('semester', $semester, true); $oRdf->addSequence($i); $i++; } From e9e58decee0752f0e6ed1a453363901317f8fa67 Mon Sep 17 00:00:00 2001 From: Paolo Date: Fri, 5 Jul 2019 11:56:43 +0200 Subject: [PATCH 050/500] Changed file naming convention for table files --- .../dbskel/fue/{TBL-aktivitaet.php => TBL_aktivitaet.php} | 0 application/libraries/DBSkelLib.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename application/dbskel/fue/{TBL-aktivitaet.php => TBL_aktivitaet.php} (100%) diff --git a/application/dbskel/fue/TBL-aktivitaet.php b/application/dbskel/fue/TBL_aktivitaet.php similarity index 100% rename from application/dbskel/fue/TBL-aktivitaet.php rename to application/dbskel/fue/TBL_aktivitaet.php diff --git a/application/libraries/DBSkelLib.php b/application/libraries/DBSkelLib.php index df8a71a6c..4a52f44d6 100644 --- a/application/libraries/DBSkelLib.php +++ b/application/libraries/DBSkelLib.php @@ -32,7 +32,7 @@ class DBSkelLib // Configuration file names const SCHEMA_FILENAME = 'schema.sql'; // File name that contains schema creation SQL and SQL to comment a schema const SEQUENCES_FILENAME = 'sequences.php'; // PHP file that contains all the sequences - const TABLE_PREFIX = 'TBL-'; // Table file prefix + const TABLE_PREFIX = 'TBL_'; // Table file prefix const CONSTRAINTS_FILENAME = 'constraints.php'; // PHP file that contains all the constraints const VIEWS_FILENAME = 'views.php'; // PHP file that contains all the views const FUNCTIONS_FILENAME = 'functions.php'; // PHP file that contains all the functions From 96783da0139f4640458f5c5ee5f2cf3bc7a53cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 5 Jul 2019 16:12:27 +0200 Subject: [PATCH 051/500] Bugfix to get old Sabredav working with php7 --- include/sabredav/lib/Sabre/CalDAV/CalendarQueryValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sabredav/lib/Sabre/CalDAV/CalendarQueryValidator.php b/include/sabredav/lib/Sabre/CalDAV/CalendarQueryValidator.php index 494aed1a7..4b05e8ca9 100644 --- a/include/sabredav/lib/Sabre/CalDAV/CalendarQueryValidator.php +++ b/include/sabredav/lib/Sabre/CalDAV/CalendarQueryValidator.php @@ -59,7 +59,7 @@ class CalendarQueryValidator { foreach($filters as $filter) { - $isDefined = isset($parent->$filter['name']); + $isDefined = isset($parent->{$filter['name']}); if ($filter['is-not-defined']) { @@ -75,7 +75,7 @@ class CalendarQueryValidator { } if ($filter['time-range']) { - foreach($parent->$filter['name'] as $subComponent) { + foreach($parent->{$filter['name']} as $subComponent) { if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) { continue 2; } From 02693ed79088aaaae2540024c59b4a40f6d04f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 5 Jul 2019 16:28:58 +0200 Subject: [PATCH 052/500] Infotext im Tempus angepasst bei Lektoren mit Selbstverwalteter Pause (SVP) --- include/zeitaufzeichnung_gd.class.php | 1 + rdf/lehreinheit-lvplan.rdf.php | 38 ++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/zeitaufzeichnung_gd.class.php b/include/zeitaufzeichnung_gd.class.php index db678addb..b21bf0570 100644 --- a/include/zeitaufzeichnung_gd.class.php +++ b/include/zeitaufzeichnung_gd.class.php @@ -68,6 +68,7 @@ class zeitaufzeichnung_gd extends basis_db $this->updateamum = $row->updateamum; $this->updatevon = $row->updatevon; $this->selbstverwaltete_pause = $this->db_parse_bool($row->selbstverwaltete_pause); + return true; } else { diff --git a/rdf/lehreinheit-lvplan.rdf.php b/rdf/lehreinheit-lvplan.rdf.php index ece1f3128..948e2327b 100644 --- a/rdf/lehreinheit-lvplan.rdf.php +++ b/rdf/lehreinheit-lvplan.rdf.php @@ -37,6 +37,7 @@ require_once('../include/functions.inc.php'); require_once('../include/lehreinheit.class.php'); require_once('../include/notiz.class.php'); require_once('../include/mitarbeiter.class.php'); +require_once('../include/zeitaufzeichnung_gd.class.php'); $uid=get_uid(); $error_msg=''; @@ -175,6 +176,21 @@ if ($anz>0) break; } } + + $selbstverwaltete_pause = false; + foreach ($l->lektor_uid as $lktuid) + { + $gd = new zeitaufzeichnung_gd(); + if($gd->load($lktuid, $studiensemester)) + { + if ($gd->selbstverwaltete_pause) + { + $selbstverwaltete_pause = true; + break; + } + } + } + sort($l->lektor); foreach($l->lektor as $lv) $lektor.=$lv.' '; @@ -274,12 +290,26 @@ if ($anz>0) continue; } } + + $fixangestellt_info = ''; + if($fixangestellt) + { + if($selbstverwaltete_pause) + { + $fixangestellt_info = 'SVP'; + } + else + $fixangestellt_info = 'FIX'; + } + else + $fixangestellt_info = 'EXT'; + echo' - - '.$lvnr.' + + '.$lvnr.' '.$l->unr.' '.$lektor.' - '.($fixangestellt?'Fix':'Frei').' + '.$fixangestellt_info.' '.$l->lehrfach_id.' '.$l->stg_kz[0].' '.$l->fachbereich.' @@ -305,7 +335,7 @@ if ($anz>0) '.$lehrverband.' '.$anzahl_notizen.' '.$l->lehreinheit_id[0].' - + '; } } From 93a6652c5f3df9193cd5627080d020e7ad6ccf53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 5 Jul 2019 17:07:06 +0200 Subject: [PATCH 053/500] Gradelist - Max-ECTS-Sum includes ECTS of assigned Courses without Grades --- application/controllers/person/Gradelist.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/application/controllers/person/Gradelist.php b/application/controllers/person/Gradelist.php index e1ef14792..230c7f67f 100644 --- a/application/controllers/person/Gradelist.php +++ b/application/controllers/person/Gradelist.php @@ -46,6 +46,9 @@ class Gradelist extends Auth_Controller $this->_grades[$row->note]['anmerkung'] = $row->anmerkung; $this->_grades[$row->note]['notenwert'] = $row->notenwert; } + $this->_grades['']['positiv'] = false; + $this->_grades['']['anmerkung'] = ''; + $this->_grades['']['notenwert'] = 0; } /** @@ -386,6 +389,15 @@ class Gradelist extends Auth_Controller 'sws' => $row['sws'] ); } + elseif (isset($row['zugeordnet']) && $row['zugeordnet'] == true && $row['lehrtyp_kurzbz']=='lv') + { + // ECTS und SWS mitzaehlen wenn die Person zugeordnet ist auch wenn noch keine Noten vorhanden ist. + $grades[] = array( + 'note' => '', + 'ects' => $row['ects'], + 'sws' => $row['sws'] + ); + } if (isset($row['childs'])) { From 2f846796b6eb6e0c48017667d5317db1d7f7b2e3 Mon Sep 17 00:00:00 2001 From: Paolo Date: Fri, 5 Jul 2019 17:29:48 +0200 Subject: [PATCH 054/500] Work in prorgess on _manageTableColumns --- application/dbskel/fue/TBL_aktivitaet.php | 2 +- application/libraries/DBSkelLib.php | 79 +++++++++++++++-------- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/application/dbskel/fue/TBL_aktivitaet.php b/application/dbskel/fue/TBL_aktivitaet.php index 937ca3057..05027ba92 100644 --- a/application/dbskel/fue/TBL_aktivitaet.php +++ b/application/dbskel/fue/TBL_aktivitaet.php @@ -1,7 +1,7 @@ array( + 'tbl_aktivitaet' => array( 'aktivitaet_kurzbz' => array( 'comment' => 'I guess this is the PK', 'type' => 'character varying(16)', diff --git a/application/libraries/DBSkelLib.php b/application/libraries/DBSkelLib.php index 4a52f44d6..06130cf50 100644 --- a/application/libraries/DBSkelLib.php +++ b/application/libraries/DBSkelLib.php @@ -442,23 +442,10 @@ class DBSkelLib } else // if table is already present in database { - if ($this->_isNewMode()) // only if in new mode - { - $this->_printMessage('Table already present in database: '.$tableName); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then diff the already present table with the one from php file! If it fails then ends execution - if ($this->_diffTable($schema, $tableArray)) - { - $this->_printMessage('Table diff success: '.$tableName); - } - else - { - $this->_printError('Error occurred while diff table: '.$tableName); - return false; - } - } + $this->_printMessage('Table already present in database: '.$tableName); + + // Manage the differences between the table present in database and the one present in php file + return $this->_manageTableColumns($schema, $tableArray); } } else // otherwise the array present in the php table file is not well formatted @@ -1036,10 +1023,15 @@ class DBSkelLib private function _listColumns($schema, $table) { $columnsArray = array(); - $query = sprintf('SELECT * + $query = sprintf('SELECT column_name AS name, + data_type AS type, + column_default AS default, + is_nullable AS nullable, + character_maximum_length AS string_length, + numeric_precision AS number_length FROM information_schema.columns WHERE table_schema = \'%s\' - AND table_name = \'%s\'', $schema, $table); + AND table_name = \'%s\'', $schema, $table); if ($columns = @$this->_ci->db->query($query)) { @@ -1118,7 +1110,7 @@ class DBSkelLib * TODO * Changes the structure of a table using the given schema and an array that defines the table structure */ - private function _diffTable($schema, $tableArray) + private function _manageTableColumns($schema, $tableArray) { $tableName = ''; $tableComment = ''; @@ -1138,10 +1130,27 @@ class DBSkelLib } } - // Query to alter the table - $query = ''; - // Query to comment the table and its columns + // Comments the table $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); + if ($this->_isDryrunMode()) + { + $this->_printInfo('Dry run >> table .'$tableName'. would be commented with: '.$queryComment); + } + else // new and diff mode + { + if (!$this->_execQuery($queryComment)) + { + $this->_printError('Error occurred while commenting table: '.$tableName); + return false; + } + else + { + $this->_printMessage('Table successfully commented: '.$tableName); + } + } + + // Retrieves the list of columns and their attributes from database + $dbTableColumns = $this->_listColumns($schema, $tableName); // For each element of the table structure foreach ($tableStructure as $colName => $colStructure) @@ -1159,14 +1168,32 @@ class DBSkelLib } // Part of the query related to this column - $query .= sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); + $query = sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); - // If a comment is present for this column then the query is built + // Comments a column if (isset($colStructure[self::T_COMMENT])) { - $queryComment .= sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); + if ($this->_isDryrunMode()) + { + $this->_printInfo('Dry run >> column '$tableName.'.'.$colName.' would be commented with: '.$colStructure[self::T_COMMENT]); + } + else // new and diff mode + { + $queryComment = sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); + if (!$this->_execQuery($queryComment)) + { + $this->_printError('Error occurred while commenting column: '.$tableName.'.'.$colName); + return false; + } + else + { + $this->_printMessage('Column successfully commented: '.$tableName.'.'.$colName); + } + } } } + + return true; } //------------------------------------------------------------------------------------------------------------------ From 61e21d605ef62cb43bf982441f7115e72aa0184d Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 8 Jul 2019 10:47:54 +0200 Subject: [PATCH 055/500] Fixes --- application/libraries/DBSkelLib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/libraries/DBSkelLib.php b/application/libraries/DBSkelLib.php index 06130cf50..1d556d9a4 100644 --- a/application/libraries/DBSkelLib.php +++ b/application/libraries/DBSkelLib.php @@ -1134,7 +1134,7 @@ class DBSkelLib $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); if ($this->_isDryrunMode()) { - $this->_printInfo('Dry run >> table .'$tableName'. would be commented with: '.$queryComment); + $this->_printInfo('Dry run >> table '.$tableName.' would be commented with: '.$queryComment); } else // new and diff mode { @@ -1175,7 +1175,7 @@ class DBSkelLib { if ($this->_isDryrunMode()) { - $this->_printInfo('Dry run >> column '$tableName.'.'.$colName.' would be commented with: '.$colStructure[self::T_COMMENT]); + $this->_printInfo('Dry run >> column '.$tableName.'.'.$colName.' would be commented with: '.$colStructure[self::T_COMMENT]); } else // new and diff mode { From d0f40a1cf279ef683627f162086c0048a39b9b7b Mon Sep 17 00:00:00 2001 From: hainberg Date: Mon, 8 Jul 2019 15:11:23 +0200 Subject: [PATCH 056/500] Added columns vertragsstunden/vertragsstunden_studiensemester_kurzbz in tbl_vertrag --- system/dbupdate_3.3.php | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index ac5f5fdba..f6455bca8 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -2938,6 +2938,37 @@ if(!$result = @$db->db_query("SELECT bezeichnung_mehrsprachig FROM bis.tbl_orgfo } } +// Spalte vertragsstunden für tbl_vertrag +if(!$result = @$db->db_query("SELECT vertragsstunden FROM lehre.tbl_vertrag LIMIT 1")) +{ + $qry = "ALTER TABLE lehre.tbl_vertrag ADD COLUMN vertragsstunden NUMERIC(5,2);"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertrag: '.$db->db_last_error().'
    '; + else + echo '
    lehre.tbl_vertrag: Spalte vertragsstunden hinzugefuegt'; +} + +// Spalte vertragsstunden_studiensemester_kurzbz für tbl_vertrag +if(!$result = @$db->db_query("SELECT vertragsstunden_studiensemester_kurzbz FROM lehre.tbl_vertrag LIMIT 1")) +{ + $qry = " + ALTER TABLE lehre.tbl_vertrag + ADD COLUMN vertragsstunden_studiensemester_kurzbz VARCHAR(16); + + ALTER TABLE lehre.tbl_vertrag + ADD CONSTRAINT fk_vertrag_vertragsstunden_studiensemester_kurzbz + FOREIGN KEY (vertragsstunden_studiensemester_kurzbz) + REFERENCES public.tbl_studiensemester (studiensemester_kurzbz) + ON UPDATE CASCADE ON DELETE RESTRICT; + "; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertrag: '.$db->db_last_error().'
    '; + else + echo '
    lehre.tbl_vertrag: Spalte vertragsstunden_studiensemester_kurzbz hinzugefuegt'; +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; @@ -3075,7 +3106,7 @@ $tabellen=array( "lehre.tbl_stundenplan" => array("stundenplan_id","unr","mitarbeiter_uid","datum","stunde","ort_kurzbz","gruppe_kurzbz","titel","anmerkung","lehreinheit_id","studiengang_kz","semester","verband","gruppe","fix","updateamum","updatevon","insertamum","insertvon"), "lehre.tbl_stundenplandev" => array("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","ext_id"), "lehre.tbl_stundenplan_betriebsmittel" => array("stundenplan_betriebsmittel_id","betriebsmittel_id","stundenplandev_id","anmerkung","insertamum","insertvon"), - "lehre.tbl_vertrag" => array("vertrag_id","person_id","vertragstyp_kurzbz","bezeichnung","betrag","insertamum","insertvon","updateamum","updatevon","ext_id","anmerkung","vertragsdatum","lehrveranstaltung_id"), + "lehre.tbl_vertrag" => array("vertrag_id","person_id","vertragstyp_kurzbz","bezeichnung","betrag","insertamum","insertvon","updateamum","updatevon","ext_id","anmerkung","vertragsdatum","lehrveranstaltung_id", "vertragsstunden", "vertragsstunden_studiensemester_kurzbz"), "lehre.tbl_vertrag_vertragsstatus" => array("vertragsstatus_kurzbz","vertrag_id","uid","datum","ext_id","insertamum","insertvon","updateamum","updatevon"), "lehre.tbl_vertragstyp" => array("vertragstyp_kurzbz","bezeichnung"), "lehre.tbl_vertragsstatus" => array("vertragsstatus_kurzbz","bezeichnung"), From 651bbb681baf35856e1b6cf7a025c3f0c8d03b66 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Mon, 8 Jul 2019 17:03:28 +0200 Subject: [PATCH 057/500] =?UTF-8?q?=C3=84ndern=20der=20Stufe=20per=20Ajax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vilesci/stammdaten/studiengang_dokumente.php | 85 +++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/vilesci/stammdaten/studiengang_dokumente.php b/vilesci/stammdaten/studiengang_dokumente.php index fd392a928..57768558c 100644 --- a/vilesci/stammdaten/studiengang_dokumente.php +++ b/vilesci/stammdaten/studiengang_dokumente.php @@ -130,6 +130,44 @@ if($action === 'togglepflicht') } } +// Ändern der Stufe per Ajax +$changeStufe = filter_input(INPUT_POST, 'changeStufe', FILTER_VALIDATE_BOOLEAN); +if ($changeStufe && isset($_POST['stufe']) && isset($_POST['studiengang_kz'])) +{ + if (!$stufe = filter_input(INPUT_POST, 'stufe', FILTER_VALIDATE_INT)) + { + echo json_encode(array( + 'status' => 'fehler', + 'msg' => '"'.$_POST['stufe'].'" ist kein gültiger Wert für die Stufe' + )); + exit(); + } + + $studiengang_kz = filter_input(INPUT_POST, 'studiengang_kz', FILTER_VALIDATE_INT); + $dokument_kurzbz = filter_input(INPUT_POST, 'dokument_kurzbz'); + + $dokument = new dokument(); + $dokument->loadDokumentStudiengang($dokument_kurzbz, $studiengang_kz); + $dokument->stufe = $stufe; + + if (!$dokument->saveDokumentStudiengang()) + { + echo json_encode(array( + 'status' => 'fehler', + 'msg' => $p->t('global/fehlerBeiDerParameteruebergabe') + )); + exit(); + } + else + { + echo json_encode(array( + 'status' => 'ok', + 'msg' => 'Status erfolgreich aktualisiert' + )); + exit(); + } +} + if($action === 'togglenachreichbar') { if(!$rechte->isBerechtigt('assistenz', $stg_kz, 'su')) @@ -239,6 +277,45 @@ echo ' forced_root_block: "", editor_deselector: "mceNoEditor" }); + + function changeStufe(dokument_kurzbz) + { + var stufe = $("#stufe_"+dokument_kurzbz).val(); + var studiengang_kz = $("#studiengangSelect").val(); + + data = { + stufe: stufe, + studiengang_kz: studiengang_kz, + dokument_kurzbz: dokument_kurzbz, + changeStufe: true + }; + + $.ajax({ + url: "studiengang_dokumente.php", + data: data, + type: "POST", + dataType: "json", + success: function(data) + { + if(data.status!="ok") + { + $("#feedbackSpanFalse_"+dokument_kurzbz).toggle(); + $("#feedbackSpanFalse_"+dokument_kurzbz).attr("title", data["msg"]); + + } + else + { + $("#feedbackSpanFalse_"+dokument_kurzbz).hide(); + $("#feedbackSpanTrue_"+dokument_kurzbz).toggle(); + $("#feedbackSpanTrue_"+dokument_kurzbz).delay(1000).fadeOut(); + } + }, + error: function(data) + { + alert(data["msg"]); + } + }); + } Zuordnung Studiengang - Dokumente @@ -401,7 +478,7 @@ else
    - '; echo ''; foreach ($studiengang->result as $stg) { @@ -494,7 +571,11 @@ else echo' '.$dok->stufe.' + + + + '; if($rechte->isBerechtigt('assistenz', $stg_kz, 'su')) echo ''; From 68b8d018de3db21ab551c0ae6a347462beb5dee9 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Mon, 8 Jul 2019 17:05:17 +0200 Subject: [PATCH 058/500] Minor Layout Fix --- vilesci/stammdaten/cronjobverwaltung.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vilesci/stammdaten/cronjobverwaltung.php b/vilesci/stammdaten/cronjobverwaltung.php index 036f17265..a10f12f8d 100644 --- a/vilesci/stammdaten/cronjobverwaltung.php +++ b/vilesci/stammdaten/cronjobverwaltung.php @@ -202,7 +202,7 @@ if(!$cj->getAll(null, 'titel')) echo '
    Neuen Cronjob anlegen'; echo '

    - +
    From a08f450330814d2e680db7f8546ae16c6a25c156 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Mon, 8 Jul 2019 17:06:45 +0200 Subject: [PATCH 059/500] Corrected sorting order --- vilesci/stammdaten/reihungstestverwaltung.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vilesci/stammdaten/reihungstestverwaltung.php b/vilesci/stammdaten/reihungstestverwaltung.php index 244cac6d7..c367d362b 100644 --- a/vilesci/stammdaten/reihungstestverwaltung.php +++ b/vilesci/stammdaten/reihungstestverwaltung.php @@ -1000,7 +1000,7 @@ if(isset($_GET['excel'])) $("#"+v.id).tablesorter( { widgets: ["zebra", "filter", "stickyHeaders"], - sortList: [[3,0],[4,0]], + sortList: [[2,0],[3,0]], headers: {0: { sorter: false}}, widgetOptions: {filter_cssFilter: [ "filter_clm_null", From 7f7c554fd88f545c16dc338596192b9104e85dc8 Mon Sep 17 00:00:00 2001 From: hainberg Date: Mon, 8 Jul 2019 17:24:07 +0200 Subject: [PATCH 060/500] Added Vertragsstunden/VertragsstundenStudiensemester in FAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added two hidden fields . Vertragsstunden (tbl_vertrag.verstragsstunden) . VertragsstundenStudiensemester (tbl_vertrag.vertragsstunden_studiensemester_kurzbz) to FAS-tab Verträge, which can be displayed by the user. --- content/mitarbeiter/mitarbeitervertragoverlay.xul.php | 10 ++++++++++ include/vertrag.class.php | 2 ++ rdf/vertrag.rdf.php | 2 ++ 3 files changed, 14 insertions(+) diff --git a/content/mitarbeiter/mitarbeitervertragoverlay.xul.php b/content/mitarbeiter/mitarbeitervertragoverlay.xul.php index a0c9cbd94..44ee60392 100644 --- a/content/mitarbeiter/mitarbeitervertragoverlay.xul.php +++ b/content/mitarbeiter/mitarbeitervertragoverlay.xul.php @@ -117,6 +117,14 @@ echo ''; class="sortDirectionIndicator" sort="rdf:http://www.technikum-wien.at/vertrag/rdf#vertragsdatum_iso" /> +
    ID
    + + + + + + + + + + + + uid); + $studiengang = new studiengang($student->studiengang_kz); + $prfTermin = new pruefungstermin($anmeldung->pruefungstermin_id); + + if($einzeln) + { + $date = $datum->formatDatum($prfTermin->von, "Y-m-d H:i:s"); + $date = strtotime($date); + $date = $date+(60*$pruefungsintervall*($anmeldung->reihung-1)); + $date = $datum->formatDatum($prfTermin->von,"d.m.Y").' - '.date("H:i",$date); + $count++; + } + else + { + $date = $datum->formatDatum($prfTermin->von,"d.m.Y - H:i"); + $count++; + } + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } + ?> + + + + t('pruefung/keineBestaetigtenAnmeldungenVorhanden'); ?>
    + + +
    #t('pruefung/matrikelnummer'); ?>t('pruefung/studiengangAbkuerzung'); ?>t('global/datum'); ?>t('benotungstool/note'); ?>t('global/anmerkung'); ?>
    '.$count.''.$student->matr_nr.''.$studiengang->kurzbzlang.''.$date.'
    +
    + + + + + + + + + + + + + + + From 2898039b73f0203db4840d89599f193e1b684462 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 6 Aug 2019 18:58:43 +0200 Subject: [PATCH 100/500] Removed duplicated constant STATUSGRUND_ID_EINSTIEG_SOMMERSEMESTER --- config/global.config-default.inc.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/global.config-default.inc.php b/config/global.config-default.inc.php index 4a13fe2f2..d2a3801f0 100644 --- a/config/global.config-default.inc.php +++ b/config/global.config-default.inc.php @@ -259,8 +259,4 @@ define('STATUSGRUND_ID_EINSTIEG_SOMMERSEMESTER', null); // Studiengangs_kz des Studiengangs "Qualifikationskurse". Der Studiengang hat eine Sonderstellung zB für das Bewerbungstool. define('STUDIENGANG_KZ_QUALIFIKATIONKURSE', null); - -// EinsteigerInnen ins Sommersemester werden mit einem Statusgrund versehen. -// Die ID dieses Statusgrundes kann hier eingegeben werden. Es wird zB vom Infocenter-Tool gesetzt und im Bewerbungstool abgefragt -define('STATUSGRUND_ID_EINSTIEG_SOMMERSEMESTER', null); ?> From 467c8b60cc8823f68f964be800caf405745d78f0 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 7 Aug 2019 16:49:57 +0200 Subject: [PATCH 101/500] - statistik.class.php, fixed error: only non-published statistiken were loaded by default, now all are loaded --- include/statistik.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/statistik.class.php b/include/statistik.class.php index c9615d557..89ae1c752 100644 --- a/include/statistik.class.php +++ b/include/statistik.class.php @@ -164,9 +164,9 @@ class statistik extends basis_db public function getGruppe($gruppe,$publish=null) { $qry = "SELECT * FROM public.tbl_statistik WHERE gruppe=".$this->db_add_param($gruppe); - if ($publish==true) + if ($publish===true) $qry.=' AND publish '; - elseif ($publish==false) + elseif ($publish===false) $qry.=' AND NOT publish '; $qry.=' ORDER BY bezeichnung;'; From 87f4824f8a255e15be4a47d5c056d2c6d5f45770 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Fri, 9 Aug 2019 14:13:28 +0200 Subject: [PATCH 102/500] BugFix User story #3776 Fehler in Testtool-check levelgleichverteilung --- include/frage.class.php | 5 +++++ include/gebiet.class.php | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/frage.class.php b/include/frage.class.php index 8a7d4750e..cafb0c0fd 100644 --- a/include/frage.class.php +++ b/include/frage.class.php @@ -509,6 +509,11 @@ class frage extends basis_db $level[$row->level]=round(($row->anzahl/$fragengesamt)*$maxfragen); } } + // Wenn ein Level besonders viele Fragen und eines nur eine Frage (nach dem Runden) hat, + // kann es durch Rundungsfehler vorkommen, dass bei der Ausgabe ein Level ausgelassen wird. + // Deshalb wird das array hier aufsteigend sortiert. So wird ggf. vom Level mit den meisten Fragen + // die letzte ausgelassen. Hier wäre eine sauberere Lösung besser. + asort($level); // Von jedem Gebiet muss mindestens eine Frage kommen foreach ($level as $key=>$row) diff --git a/include/gebiet.class.php b/include/gebiet.class.php index 98a2535a9..2491259c4 100644 --- a/include/gebiet.class.php +++ b/include/gebiet.class.php @@ -368,12 +368,9 @@ class gebiet extends basis_db $qry = "SELECT count(*) as anzahl FROM testtool.tbl_frage WHERE gebiet_id=".$this->db_add_param($gebiet_id, FHC_INTEGER)." AND not demo AND level is not null GROUP BY level"; if($this->db_query($qry)) { - if($row = $this->db_fetch_object()) + if($this->db_num_rows() > $this->maxfragen) { - if($row->anzahl>$this->maxfragen) - { - //$this->errormsg .= "Wenn Levelgleichverteilung gesetzt ist, muss maxfragen groesser als die Anzahl der verwendeten Levels sein\n"; - } + $this->errormsg .= "Wenn Levelgleichverteilung gesetzt ist, muss maxfragen groesser als die Anzahl der verwendeten Levels sein\n"; } } } From 95c06f5d735cecea68536cf5c3dd2ae503d865ef Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 13 Aug 2019 10:44:06 +0200 Subject: [PATCH 103/500] Image-Cropper entfernt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bildupload auf die Version vor Bildzuschnitt geändert, da Cropper nicht mehr zuverlässig funktioniert --- cis/private/bildupload.php | 450 ++++++++++++------------------------- 1 file changed, 148 insertions(+), 302 deletions(-) diff --git a/cis/private/bildupload.php b/cis/private/bildupload.php index 968f67ab0..b8ce66422 100644 --- a/cis/private/bildupload.php +++ b/cis/private/bildupload.php @@ -23,8 +23,6 @@ */ // Oberflaeche zum Upload von Bildern - -//session_cache_limiter('none'); //muss gesetzt werden damit der upload in chrome und das automatische updaten des profilbildes funktioniert require_once('../../config/cis.config.inc.php'); require_once('../../include/functions.inc.php'); require_once('../../include/person.class.php'); @@ -32,67 +30,52 @@ require_once('../../include/benutzer.class.php'); require_once('../../include/akte.class.php'); require_once('../../include/phrasen.class.php'); require_once('../../include/fotostatus.class.php'); - $user = get_uid(); $sprache = getSprache(); $p = new phrasen($sprache); - echo ' + - - '. - cropCss().' - - - - - - - - - + + '.$p->t('profil/Bildupload').' +

    '.$p->t('profil/Bildupload').'

    '; - function resize($filename, $width, $height) { - $ext = explode('.',$_FILES['bild']['name']); - $ext = strtolower($ext[count($ext)-1]); + $ext = explode('.',$_FILES['bild']['name']); + $ext = strtolower($ext[count($ext)-1]); + // Hoehe und Breite neu berechnen + list($width_orig, $height_orig) = getimagesize($filename); + if ($width && ($width_orig < $height_orig)) + { + $width = ($height / $height_orig) * $width_orig; + } + else + { + $height = ($width / $width_orig) * $height_orig; + } - // Hoehe und Breite neu berechnen - list($width_orig, $height_orig) = getimagesize($filename); + $image_p = imagecreatetruecolor($width, $height); - if ($width && ($width_orig < $height_orig)) - { - $width = ($height / $height_orig) * $width_orig; - } - else - { - $height = ($width / $width_orig) * $height_orig; - } + $image = imagecreatefromjpeg($filename); - $image_p = imagecreatetruecolor($width, $height); + //Bild nur verkleinern aber nicht vergroessern + if($width_orig>$width || $height_orig>$height) + imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig); + else + $image_p = $image; - $image = imagecreatefromjpeg($filename); + imagejpeg($image_p, $filename, 80); - //Bild nur verkleinern aber nicht vergroessern - if($width_orig>$width || $height_orig>$height) - imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig); - else - $image_p = $image; - - imagejpeg($image_p, $filename, 80); - - @imagedestroy($image_p); - @imagedestroy($image); + @imagedestroy($image_p); + @imagedestroy($image); } - - if(isset($_GET['person_id'])) { $benutzer = new benutzer(); @@ -107,269 +90,132 @@ if(isset($_GET['person_id'])) } else die($p->t('global/fehlerBeiDerParameteruebergabe')); +//Bei Upload des Bildes +if(isset($_POST['submitbild'])) +{ + if(isset($_FILES['bild']['tmp_name'])) + { + //Extension herausfiltern + $ext = explode('.',$_FILES['bild']['name']); + $ext = mb_strtolower($ext[count($ext)-1]); + $width=101; + $height=130; -echo '
    '; -echo $p->t('profil/BilduploadInfotext',array($p->t('dms_link/bildRichtlinien'))).'

    '; -echo '
    - '.$p->t('profil/fotoAuswählen').' -
    - -
    - - '; + //--check that it's a jpeg + if ($ext=='jpg' || $ext=='jpeg') + { + $filename = $_FILES['bild']['tmp_name']; -if (isset($_POST['src'])) { - $src = $_POST['src']; - echo $src; + //groesse auf maximal 827x1063 begrenzen + resize($filename, 827, 1063); + + $fp = fopen($filename,'r'); + //auslesen + $content = fread($fp, filesize($filename)); + fclose($fp); + + $akte = new akte(); + + if($akte->getAkten($_GET['person_id'], 'Lichtbil')) + { + if(count($akte->result)>0) + { + $akte = $akte->result[0]; + $akte->new = false; + } + else + $akte->new = true; + } + else + { + $akte->new = true; + } + + $akte->dokument_kurzbz = 'Lichtbil'; + $akte->person_id = $_GET['person_id']; + $akte->inhalt = base64_encode($content); + $akte->mimetype = "image/jpg"; + $akte->erstelltam = date('Y-m-d H:i:s'); + $akte->gedruckt = false; + $akte->titel = "Lichtbild_".$_GET['person_id'].".jpg"; + $akte->bezeichnung = "Lichtbild gross"; + $akte->updateamum = date('Y-m-d H:i:s'); + $akte->updatevon = $user; + $akte->insertamum = date('Y-m-d H:i:s'); + $akte->insertvon = $user; + $akte->uid = ''; + + if(!$akte->save()) + { + echo '
    Fehler: '.$akte->errormsg.'
    '; + } + + //groesse auf maximal 101x130 begrenzen + resize($filename, 101, 130); + + //in DB speichern + //File oeffnen + $fp = fopen($filename,'r'); + //auslesen + $content = fread($fp, filesize($filename)); + fclose($fp); + //in base64-Werte umrechnen + $content = base64_encode($content); + $person = new person(); + if($person->load($_GET['person_id'])) + { + //base64 Wert in die Datenbank speichern + $person->foto = $content; + $person->new = false; + if($person->save()) + { + $fs = new fotostatus(); + $fs->person_id=$person->person_id; + $fs->fotostatus_kurzbz='hochgeladen'; + $fs->datum = date('Y-m-d'); + $fs->insertamum = date('Y-m-d H:i:s'); + $fs->insertvon = $user; + $fs->updateamum = date('Y-m-d H:i:s'); + $fs->updatevon = $user; + if(!$fs->save(true)) + echo '
    Fehler beim Setzen des Bildstatus
    '; + else + { + + echo "
    Bild wurde erfolgreich gespeichert
    + "; + } + } + else + echo '
    '.$person->errormsg.'
    '; + } + else + echo '
    '.$person->errormsg.'
    '; + } + else + echo '
    '.$p->t('profil/nurJPGBilder').'
    '; + } } -function cropCss() { - return ' - '; -} +//echo '
    '; +echo $p->t('profil/BilduploadInfotext',array($p->t('dms_link/bildRichtlinien'))).'

    + + '.$p->t('profil/Bild').':
    + + + '; ?> +
    From 277028e412d445c3c6f2bfab88391d43b97b895f Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Tue, 13 Aug 2019 10:44:55 +0200 Subject: [PATCH 104/500] Diplomasupplement und Bescheid aus Auswahl-Select entfernt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diplomasupplement und Bescheid haben einen Sonderstatus und sollten nur fürs archivieren verwendet werden --- content/akteupload.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/akteupload.php b/content/akteupload.php index d29be6670..f8c459845 100644 --- a/content/akteupload.php +++ b/content/akteupload.php @@ -168,7 +168,7 @@ if(isset($_POST['submitbild'])) if(isset($_GET['person_id'])) { $dokument = new dokument(); - $dokument->getAllDokumente('Zeugnis'); + $dokument->getAllDokumente('Zeugnis,DiplSupp,Bescheid'); echo " From 2e3075b8c4ef356e5bd2a0aa7df714e273b922b9 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Wed, 14 Aug 2019 11:57:12 +0200 Subject: [PATCH 105/500] Aktualisieren funktioniert nun wieder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Studiengänge in Lektorenliste werden richtig sortiert --- content/fasoverlay.js.php | 32 +++++++++++----------- content/lvplanung/stpl-week-overlay.js.php | 12 ++++---- content/tempusoverlay.js.php | 5 +++- include/mitarbeiter.class.php | 2 +- rdf/mitarbeiter.rdf.php | 2 +- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php index bf0da34ae..9d426d4dc 100644 --- a/content/fasoverlay.js.php +++ b/content/fasoverlay.js.php @@ -103,24 +103,24 @@ var LektorTreeListener = function LektorTreeSelectMitarbeiter() { var tree=document.getElementById('tree-lektor'); - var items = tree.view.rowCount; //Anzahl der Zeilen ermitteln - if(LektorTreeOpenStudiengang!=null) + if (tree.view != null) { - for(var i=0;igetStgKz('admin'); $stge=array_merge($stge, $bb->getStgKz('assistenz')); - $ma=$mitarbeiter->getMitarbeiterStg($lektor,$fixangestellt,$stge, 'lkt'); + $ma=$mitarbeiter->getMitarbeiterStg($lektor,$fixangestellt,$stge, 'lkt', 'typ, stg_kurzbz, nachname, vorname, vw_mitarbeiter.kurzbz'); $laststg=-1; if(count($ma)>0) { From 463a53a2bf6355c1c2451cb91eac6f4177e5c8f9 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Wed, 14 Aug 2019 18:27:48 +0200 Subject: [PATCH 106/500] Bugfix Gruppen-Suche --- vilesci/lehre/einheit_det.php | 4 +++- vilesci/lehre/einheit_menu.php | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/vilesci/lehre/einheit_det.php b/vilesci/lehre/einheit_det.php index 18753a0f1..12bc570e6 100644 --- a/vilesci/lehre/einheit_det.php +++ b/vilesci/lehre/einheit_det.php @@ -42,6 +42,7 @@ if(!$rechte->isBerechtigt('lehre/gruppe:begrenzt',null,'s')) die($rechte->errormsg); $kurzbz=(isset($_GET['kurzbz'])?$_GET['kurzbz']:(isset($_POST['kurzbz'])?$_POST['kurzbz']:'')); +$searchItems=(isset($_GET['searchItems'])?$_GET['searchItems']:(isset($_POST['searchItems'])?$_POST['searchItems']:'')); if(empty($kurzbz)) die('Gruppe wurde nicht übergeben Zurück'); @@ -108,7 +109,7 @@ if(!$gruppe->load($kurzbz))

    Gruppe

    studiengang_kz'>Zurück zur Übersicht

    "; +echo "Zurück zur Übersicht

    "; echo $errormsg; $generiertegruppe = $gruppe->generiert; if(!$gruppe->generiert) @@ -141,6 +142,7 @@ if(!$gruppe->generiert) $("#uid").focus(); +
    diff --git a/vilesci/lehre/einheit_menu.php b/vilesci/lehre/einheit_menu.php index 85a31f56e..bfb44e8d9 100644 --- a/vilesci/lehre/einheit_menu.php +++ b/vilesci/lehre/einheit_menu.php @@ -267,11 +267,11 @@ function doSave() function doEdit($kurzbz,$new=false) { - global $db, $rechte, $studiengang; + global $db, $rechte, $studiengang, $searchItems; if (!$new) { $e = new gruppe($kurzbz); - echo 'Zurück zur Übersicht
    '; + echo 'Zurück zur Übersicht
    '; } else { @@ -486,10 +486,10 @@ function getUebersicht() echo "
    "; // src="../../skin/images/'.($row->projektarbeit=='t'?'true.png':'false.png').'" //echo ""; Auskommentiert, da sonst die Ladezeit der Seite zu lange ist - echo ""; + echo ""; if($rechte->isBerechtigt('lehre/gruppe', $oe_studiengang, 'su')) - echo ""; + echo ""; if($rechte->isBerechtigt('lehre/gruppe', $oe_studiengang, 'suid')) echo ""; From 843be83f11ebba44a520fb0d0fe2625bbec2c414 Mon Sep 17 00:00:00 2001 From: Manfred Kindl Date: Wed, 14 Aug 2019 18:28:16 +0200 Subject: [PATCH 107/500] =?UTF-8?q?Korrektur=20Tippfehler=20Ausbildungsver?= =?UTF-8?q?trag=20Lehrg=C3=A4nge=20Deutsch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/xsl/Ausbildungsver_Lehrgaenge.xsl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/system/xsl/Ausbildungsver_Lehrgaenge.xsl b/system/xsl/Ausbildungsver_Lehrgaenge.xsl index 19108a7ba..4fd45f636 100644 --- a/system/xsl/Ausbildungsver_Lehrgaenge.xsl +++ b/system/xsl/Ausbildungsver_Lehrgaenge.xsl @@ -455,7 +455,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" --> Lehrgangs zur Weiterbildung. - Dieser Lehrgang wird in Kooperation mit der Technikum Wien GmbH organisiert und durchgeführt. Es gelten die AGB der Technikum Wien GmbH, diese sind unter https://academy.technikum-wien.at/agb jederzeit abrufbar. + Dieser Lehrgang wird von der Technikum Wien GmbH in Kooperation mit der FH Technikum Wien organisiert und durchgeführt. Es gelten die AGB der Technikum Wien GmbH, diese sind unter https://academy.technikum-wien.at/agb jederzeit abrufbar. @@ -478,7 +478,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Die Ausbildung erfolgt auf Grundlage des Fachhochschul-Studiengesetzes, BGBI. Nr. 340/1993 idgF und des Hochschul-Qualitätssicherungsgesetzes, BGBI. Nr. 74/2011 idgF, des genehmigten Lehrgangantrags durch das Fachhoschul-Kollegium und der Satzung der Fachhoschule Technikum Wien idgF. + Die Ausbildung erfolgt auf Grundlage des Fachhochschul-Studiengesetzes, BGBI. Nr. 340/1993 idgF. und des Hochschul-Qualitätssicherungsgesetzes, BGBI. Nr. 74/2011 idgF., des genehmigten Lehrgangantrags durch das Fachhoschul-Kollegium und der Satzung der Fachhoschule Technikum Wien idgF. @@ -598,8 +598,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - - . + . @@ -705,7 +704,7 @@ xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" - Ao. Studierende des Lehrgangs sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehreelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet und E-Mail) trägt der ao. Student bzw. die ao. Studentin. + Ao. Studierende des Lehrgangs sind verpflichtet, eine EDV-Ausstattung zu beschaffen und zu unterhalten, die es ermöglicht, an den Fernlehrelementen teilzunehmen. Die gesamten Kosten der Anschaffung und des Betriebs (inkl. Kosten für Internet und E-Mail) trägt der ao. Student bzw. die ao. Studentin. From 44258aef5e8bb03dec7eb43954610c7d934b753a Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 21 Aug 2019 14:37:37 +0200 Subject: [PATCH 108/500] Added 3 Vertragsstati: bestellt / erteilt / akzeptiert --- system/dbupdate_3.3.php | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 320cfdb74..5fc68e44c 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3049,6 +3049,49 @@ if(!@$db->db_query("SELECT 0 FROM campus.tbl_zeitaufzeichnung_gd WHERE 0 = 1")) echo '
    Granted privileges to vilesci on campus.tbl_zeitaufzeichnung_gd'; } + +// Insert 'bestellt' to tbl_vertragsstatus +if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragsstatus WHERE vertragsstatus_kurzbz = 'bestellt';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO lehre.tbl_vertragsstatus(vertragsstatus_kurzbz, bezeichnung) VALUES('bestellt', 'Bestellt');"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertragsstatus '.$db->db_last_error().'
    '; + else + echo 'lehre.tbl_vertragsstatus: Added value \'bestellt\'
    '; + } +} + +// Insert 'erteilt' to tbl_vertragsstatus +if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragsstatus WHERE vertragsstatus_kurzbz = 'erteilt';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO lehre.tbl_vertragsstatus(vertragsstatus_kurzbz, bezeichnung) VALUES('erteilt', 'Erteilt');"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertragsstatus '.$db->db_last_error().'
    '; + else + echo 'lehre.tbl_vertragsstatus: Added value \'erteilt\'
    '; + } +} + +// Insert 'akzeptiert' to tbl_vertragsstatus +if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragsstatus WHERE vertragsstatus_kurzbz = 'akzeptiert';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO lehre.tbl_vertragsstatus(vertragsstatus_kurzbz, bezeichnung) VALUES('akzeptiert', 'Akzeptiert');"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertragsstatus '.$db->db_last_error().'
    '; + else + echo 'lehre.tbl_vertragsstatus: Added value \'akzeptiert\'
    '; + } +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; From 99155d970cf8c1005b49b9f95b79484b075b95f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 22 Aug 2019 17:36:32 +0200 Subject: [PATCH 109/500] Fixed Notice in Testtool --- cis/testtool/menu.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cis/testtool/menu.php b/cis/testtool/menu.php index af716542a..7fcf93764 100644 --- a/cis/testtool/menu.php +++ b/cis/testtool/menu.php @@ -183,13 +183,13 @@ if (isset($_SESSION['pruefling_id'])) /* Filter out all Abgewiesene */ AND NOT EXISTS ( - SELECT - 1 + SELECT + 1 FROM tbl_prestudentstatus - WHERE - status_kurzbz = 'Abgewiesener' - AND + WHERE + status_kurzbz = 'Abgewiesener' + AND prestudent_id = ps_status.prestudent_id ) @@ -220,7 +220,7 @@ if (isset($_SESSION['pruefling_id'])) ) - SELECT DISTINCT ON + SELECT DISTINCT ON (gebiet_id, semester) semester, gebiet_id, @@ -231,7 +231,7 @@ if (isset($_SESSION['pruefling_id'])) FROM ( SELECT * - FROM ( + FROM ( (SELECT prestudent_data.semester AS ps_sem, gebiet_id, @@ -252,9 +252,9 @@ if (isset($_SESSION['pruefling_id'])) OR (prestudent_data.semester= 3 AND tbl_ablauf.semester IN (1,3)) ) - + UNION - + ( SELECT prestudent_data.semester AS ps_sem, @@ -278,7 +278,7 @@ if (isset($_SESSION['pruefling_id'])) ) ) temp ) temp2 - + GROUP BY semester, gebiet_id, @@ -425,7 +425,7 @@ else // show message to use Mozilla Firefox if ((ua.indexOf("Firefox") > -1) == false) { - let hasMathML = ""; + let hasMathML = ""; let userLang = ""; if (hasMathML == true) { @@ -442,7 +442,7 @@ else // Error massage if check_gebiet function returns false $(function() { - var invalid_gebiete = ""; + var invalid_gebiete = ""; if(invalid_gebiete == true) { $('#tr-einleitung').append('' + From f769e079894089cb22fb14a34af9070739689a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 23 Aug 2019 09:57:28 +0200 Subject: [PATCH 110/500] Added missing permission for Group Menu Entry in Vilesci --- include/tw/vilesci_menu_main.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/tw/vilesci_menu_main.inc.php b/include/tw/vilesci_menu_main.inc.php index da65a3600..c49542246 100644 --- a/include/tw/vilesci_menu_main.inc.php +++ b/include/tw/vilesci_menu_main.inc.php @@ -29,7 +29,7 @@ $menu=array ( 'name'=>'LV-Plan', 'opener'=>'true', 'hide'=>'false', 'permissions'=>array('admin','lv-plan'), 'image'=>'vilesci_lvplan.png', 'link'=>'left.php?categorie=LVPlan', 'target'=>'nav', - 'Gruppenverwaltung'=>array('name'=>'Gruppenverwaltung', 'permissions'=>array('admin','lv-plan','support'), 'link'=>'stammdaten/lvbgruppenverwaltung.php', 'target'=>'main'), + 'Gruppenverwaltung'=>array('name'=>'Gruppenverwaltung', 'permissions'=>array('admin','lv-plan','support', 'lehre/gruppe'), 'link'=>'stammdaten/lvbgruppenverwaltung.php', 'target'=>'main'), 'Lehrveranstaltung'=>array('name'=>'Lehrveranstaltung', 'link'=>'lehre/lehrveranstaltung_frameset.html', 'target'=>'main'), /* Leerzeile */'emptyrow1'=>array('name'=>'', 'link'=>'#empty', 'target'=>'main'), 'Verplanungsuebersicht'=>array('name'=>'Verplanungsübersicht', 'link'=>'lehre/check/verplanungsuebersicht.php', 'target'=>'main'), @@ -68,7 +68,7 @@ $menu=array ( 'name'=>'Lehre', 'opener'=>'true', 'hide'=>'false', 'permissions'=>array('admin','lv-plan','support', 'lehre'), 'image'=>'vilesci_lehre.png', 'link'=>'left.php?categorie=Lehre', 'target'=>'nav', - 'Gruppenverwaltung'=>array('name'=>'Gruppen', 'permissions'=>array('admin','lv-plan','support'), 'link'=>'stammdaten/lvbgruppenverwaltung.php', 'target'=>'main'), + 'Gruppenverwaltung'=>array('name'=>'Gruppen', 'permissions'=>array('admin','lv-plan','support','lehre/gruppe'), 'link'=>'stammdaten/lvbgruppenverwaltung.php', 'target'=>'main'), 'Lehrveranstaltung'=>array('name'=>'Lehrveranstaltung', 'link'=>'lehre/lehrveranstaltung_frameset.html', 'target'=>'main'), 'Studienordnung'=>array('name'=>'Studienordnung', 'link'=>'lehre/studienordnung.php', 'target'=>'_blank','permissions'=>array('lehre/studienordnung')), 'StudienplanGueltigkeit'=>array('name'=>'Studienplan Gültigkeit', 'link'=>'lehre/studienplan_gueltigkeit.php', 'target'=>'main','permissions'=>array('lehre/studienordnung')), From 7c640b6dc42a283771dc6db985ec6eefa4c66e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 23 Aug 2019 12:47:28 +0200 Subject: [PATCH 111/500] =?UTF-8?q?Wienerlinien=20Webservice=20Notice=20be?= =?UTF-8?q?hoben.=20Token=20wird=20jetzt=20Kleingeschrieben=20=C3=BCbermit?= =?UTF-8?q?elt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- soap/semesterticket.soap.php | 2 +- soap/semesterticket_client.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/soap/semesterticket.soap.php b/soap/semesterticket.soap.php index 78853a573..2d799cd54 100644 --- a/soap/semesterticket.soap.php +++ b/soap/semesterticket.soap.php @@ -52,7 +52,7 @@ function verifyData($parameters) $log = new webservicelog(); $log->request_data = file_get_contents('php://input'); $log->webservicetyp_kurzbz = 'wienerlinien'; - $log->request_id = $parameters->Token; + $log->request_id = $parameters->token; $log->beschreibung = "Semesterticketanfrage"; $log->save(true); diff --git a/soap/semesterticket_client.php b/soap/semesterticket_client.php index 4571d2e40..f9de3bec5 100644 --- a/soap/semesterticket_client.php +++ b/soap/semesterticket_client.php @@ -70,13 +70,13 @@ $db = new basis_db(); if(isset($_REQUEST['submit'])) { - $client = new SoapClient(APP_ROOT."/soap/semesterticket.wsdl.php?".microtime(true)); + $client = new SoapClient(APP_ROOT."/soap/semesterticket.wsdl.php?".microtime(true)); try { class foo {}; $obj = new foo(); - $obj->Token = $_REQUEST['token']; + $obj->token = $_REQUEST['token']; $obj->Matrikelnummer = $_REQUEST['matrikelnummer']; $obj->Name = $_REQUEST['name']; $obj->Vorname = $_REQUEST['vorname']; From 498678e726f5c9064cd5f5cf3afabf30def48591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 23 Aug 2019 13:08:18 +0200 Subject: [PATCH 112/500] =?UTF-8?q?Stipendienstelle=20Schnittstelle=20ange?= =?UTF-8?q?passt=20um=20Fehler=20zu=20vermeiden=20wenn=20Personen=20abgefr?= =?UTF-8?q?agt=20werden=20die=20im=20gew=C3=A4hlten=20Semester=20keinen=20?= =?UTF-8?q?Status=20haben?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- soap/stip.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soap/stip.class.php b/soap/stip.class.php index adabc8582..434444cc9 100644 --- a/soap/stip.class.php +++ b/soap/stip.class.php @@ -399,7 +399,7 @@ class stip extends basis_db public.tbl_prestudentstatus WHERE prestudent_id=".$this->db_add_param($prestudent_id, FHC_INTEGER)." - AND studiensemester_kurzbz=".$this->db_add_param($psem)."'"; + AND studiensemester_kurzbz=".$this->db_add_param($psem); if(!is_null($bisdatum)) $qrystatus.=" AND (tbl_prestudentstatus.datum<".$this->db_add_param($bisdatum).") "; $qrystatus.=" ORDER BY datum desc, insertamum desc, ext_id desc;"; @@ -445,6 +445,8 @@ class stip extends basis_db */ public function getSemester($prestudent_id, $studiensemester_kurzbz, $bisdatum=null) { + $sem = ''; + $qrystatus=" SELECT * From 441c9350e4e38b17f5450e2d2aeca643e7bcf7f7 Mon Sep 17 00:00:00 2001 From: hainberg Date: Wed, 28 Aug 2019 11:30:17 +0200 Subject: [PATCH 113/500] Added app 'lehrauftrag' to syystem.tbl_app --- system/dbupdate_3.3.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 5fc68e44c..f18ba7e5d 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -1366,6 +1366,21 @@ if($result = $db->db_query("SELECT 1 FROM system.tbl_app WHERE app='bewerbung'") } } +// App 'lehrauftrag' hinzufügen +if($result = $db->db_query("SELECT 1 FROM system.tbl_app WHERE app='lehrauftrag'")) +{ + if($db->db_num_rows($result)==0) + { + + $qry = "INSERT INTO system.tbl_app(app) VALUES('lehrauftrag');"; + + if(!$db->db_query($qry)) + echo 'App: '.$db->db_last_error().'
    '; + else + echo '
    Neue App lehrauftrag in system.tbl_app hinzugefügt'; + } +} + // Archiv boolean fuer public.tbl_akte if(!@$db->db_query("SELECT archiv FROM public.tbl_akte LIMIT 1")) { From 6f5ad2bbe163b5e36fb056f3c67e24b04e5225d5 Mon Sep 17 00:00:00 2001 From: hainberg Date: Wed, 28 Aug 2019 11:33:58 +0200 Subject: [PATCH 114/500] Adapted filter for Lehrauftragsstatus Added . name "Lehrauftragsstatus" and . columns "LE-ID" and "Gruppe" --- system/filtersupdate.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 6bbe25118..19ebea0f9 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -408,16 +408,21 @@ $filters = array( 'default_filter' => true, 'filter' => ' { + "name": "Lehrauftragsstatus", "columns": [ - {"name": "Lehrveranstaltung"}, + {"name": "LE-ID"}, + {"name": "Typ"}, + {"name": "Auftrag"}, {"name": "Organisationseinheit"}, + {"name": "Gruppe"}, {"name": "Lektor"}, {"name": "Stunden"}, {"name": "Betrag"}, - {"name": "Bestellung STG"}, - {"name": "Erteilung Department"}, - {"name": "Akzeptiert von Lektor"} - ] + {"name": "Bestellt"}, + {"name": "Erteilt"}, + {"name": "Akzeptiert"} + ], + "filters": [] } ', 'oe_kurzbz' => null, From 16e8bf96066721ec2464a44b2543f08e1b6cbe8f Mon Sep 17 00:00:00 2001 From: hainberg Date: Wed, 28 Aug 2019 11:57:46 +0200 Subject: [PATCH 115/500] Added lehrauftrag-permissions to tbl_berechtigung Permissios . lehrauftrag_bestellen . lehrauftrag_erteilen --- system/dbupdate_3.3.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index f18ba7e5d..a321b4b3e 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3107,6 +3107,34 @@ if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragsstatus WHERE vertra } } +// Add permission to order lehrauftrag (lehrauftrag_bestellen) +if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'lehre/lehrauftrag_bestellen';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO system.tbl_berechtigung(berechtigung_kurzbz, beschreibung) VALUES('lehre/lehrauftrag_bestellen', 'Lehrauftrag bestellen');"; + + if(!$db->db_query($qry)) + echo 'system.tbl_berechtigung '.$db->db_last_error().'
    '; + else + echo ' system.tbl_berechtigung: Added permission for lehre/lehrauftrag_bestellen
    '; + } +} + +// Add permission to approve lehrauftrag (lehrauftrag_erteilen) +if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'lehre/lehrauftrag_erteilen';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO system.tbl_berechtigung(berechtigung_kurzbz, beschreibung) VALUES('lehre/lehrauftrag_erteilen', 'Lehrauftrag erteilen');"; + + if(!$db->db_query($qry)) + echo 'system.tbl_berechtigung '.$db->db_last_error().'
    '; + else + echo ' system.tbl_berechtigung: Added permission for lehre/lehrauftrag_erteilen
    '; + } +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; From ff858a495d97b8b8af29ac2a96e05d70044e81a0 Mon Sep 17 00:00:00 2001 From: Paolo Date: Wed, 28 Aug 2019 17:26:41 +0200 Subject: [PATCH 116/500] - Added new core controller JOB_Controller - Added new webservicetyp_kurzbz "job" to table system.tbl_webservicetyp in system/dbupdate_3.3.php - Added new filter "All jobs viewer" - Added new __construct to LogLib to set properties - Added new public methods logInfoDB, logDebugDB, logWarningDB and logErrorDB to LogLib - Added new private method _logDB to LogLib - Renamed LogLib private method _format to _getPrefix - Added new private method _getDatabaseDescription to LogLib - Changed method _getCaller to use different levels of debug_backtrace - Added new properties and constants to LogLib to log to the database --- application/core/APIv1_Controller.php | 4 +- application/core/Auth_Controller.php | 7 +- application/core/CLI_Controller.php | 5 +- application/core/DB_Model.php | 5 + application/core/FHC_Controller.php | 7 +- application/core/FS_Model.php | 7 +- application/core/JOB_Controller.php | 92 ++++++++ application/libraries/LogLib.php | 210 +++++++++++++++--- .../models/system/Webservicelog_model.php | 3 +- public/css/FilterWidget.css | 16 ++ system/dbupdate_3.3.php | 14 ++ system/filtersupdate.php | 24 +- 12 files changed, 355 insertions(+), 39 deletions(-) create mode 100644 application/core/JOB_Controller.php diff --git a/application/core/APIv1_Controller.php b/application/core/APIv1_Controller.php index 6432c87db..b0c98c6e5 100644 --- a/application/core/APIv1_Controller.php +++ b/application/core/APIv1_Controller.php @@ -1,9 +1,11 @@ load->library('LogLib', array( + 'classIndex' => 5, + 'functionIndex' => 5, + 'lineIndex' => 4, + 'dbLogType' => 'job', // required + 'dbExecuteUser' => 'Cronjob system' + )); + } + + //------------------------------------------------------------------------------------------------------------------ + // Protected methods + + /** + * Writes a cronjob info log + */ + protected function logInfo($response, $parameters = null) + { + $this->_log(LogLib::INFO, 'Cronjob info', $response, $parameters); + } + + /** + * Writes a cronjob debug log + */ + protected function logDebug($response, $parameters = null) + { + $this->_log(LogLib::DEBUG, 'Cronjob debug', $response, $parameters); + } + + /** + * Writes a cronjob warning log + */ + protected function logWarning($response, $parameters = null) + { + $this->_log(LogLib::WARNING, 'Cronjob warning', $response, $parameters); + } + + /** + * Writes a cronjob error log + */ + protected function logError($response, $parameters = null) + { + $this->_log(LogLib::ERROR, 'Cronjob error', $response, $parameters); + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Writes a log to database + */ + private function _log($level, $requestId, $response, $parameters) + { + $data = new stdClass(); + + $data->response = $response; + if ($parameters != null) $data->parameters = $parameters; + + switch($level) + { + case LogLib::INFO: + $this->loglib->logInfoDB($requestId, json_encode(success($data, LogLib::INFO))); + break; + case LogLib::DEBUG: + $this->loglib->logDebugDB($requestId, json_encode(success($data, LogLib::DEBUG))); + break; + case LogLib::WARNING: + $this->loglib->logWarningDB($requestId, json_encode(error($data, LogLib::WARNING))); + break; + case LogLib::ERROR: + $this->loglib->logErrorDB($requestId, json_encode(error($data, LogLib::ERROR))); + break; + } + } +} diff --git a/application/libraries/LogLib.php b/application/libraries/LogLib.php index cb0541003..b98575150 100644 --- a/application/libraries/LogLib.php +++ b/application/libraries/LogLib.php @@ -1,102 +1,252 @@ '; const LINE_SEPARATOR = ':'; - // -------------------------------------------------------------------------------------------------------------- - // Public methods + // CodeIgniter configuration log entry name and log debug value + const CI_LOG_THRESHOLD_NAME = 'log_threshold'; + const CI_LOG_THRESHOLD_DEBUG = 2; + + // LogLib parameters names + const P_NAME_CLASS_INDEX = 'classIndex'; + const P_NAME_FUNCTION_INDEX = 'functionIndex'; + const P_NAME_LINE_INDEX = 'lineIndex'; + const P_NAME_DB_LOG_TYPE = 'dbLogType'; + const P_NAME_DB_EXECUTE_USER = 'dbExecuteUser'; + + // Properties used to retrieve caller data + private $_classIndex; + private $_functionIndex; + private $_lineIndex; + + // Properties used when logging to database + private $_dbLogType; + private $_dbExecuteUser; /** - * logDebug + * Set properties to a default value or overwrites them with the given parameters + */ + public function __construct($params = null) + { + // Properties default values + $this->_classIndex = self::CLASS_INDEX; + $this->_functionIndex = self::FUNCTION_INDEX; + $this->_lineIndex = self::LINE_INDEX; + $this->_dbLogType = null; + $this->_dbExecuteUser = self::DB_EXECUTE_USER; + + // If parameters are given then overwrite the default values + if (!isEmptyArray($params)) + { + if (isset($params[self::P_NAME_CLASS_INDEX])) $this->_classIndex = $params[self::P_NAME_CLASS_INDEX]; + if (isset($params[self::P_NAME_FUNCTION_INDEX])) $this->_functionIndex = $params[self::P_NAME_FUNCTION_INDEX]; + if (isset($params[self::P_NAME_LINE_INDEX])) $this->_lineIndex = $params[self::P_NAME_LINE_INDEX]; + if (isset($params[self::P_NAME_DB_LOG_TYPE])) $this->_dbLogType = $params[self::P_NAME_DB_LOG_TYPE]; + if (isset($params[self::P_NAME_DB_EXECUTE_USER])) $this->_dbExecuteUser = $params[self::P_NAME_DB_EXECUTE_USER]; + } + } + + // -------------------------------------------------------------------------------------------------------------- + // Public methods based on CodeIgniter log system + + /** + * Writes a debug log to CodeIgniter log */ public function logDebug($message) { - $this->_log(LogLib::DEBUG, $message); + $this->_log(self::DEBUG, $message); } /** - * logInfo + * Writes an info log to CodeIgniter log */ public function logInfo($message) { - $this->_log(LogLib::INFO, $message); + $this->_log(self::INFO, $message); } /** - * logError + * Writes an error log to CodeIgniter log */ public function logError($message) { - $this->_log(LogLib::ERROR, $message); + $this->_log(self::ERROR, $message); + } + + // -------------------------------------------------------------------------------------------------------------- + // Public methods based on database + + /** + * Writes an info log to database + */ + public function logInfoDB($requestId, $data) + { + $this->_logDB(self::INFO, $requestId, $data); + } + + /** + * Writes a debug log to database + */ + public function logDebugDB($requestId, $data) + { + $this->_logDB(self::DEBUG, $requestId, $data); + } + + /** + * Writes an warning log to database + */ + public function logWarningDB($requestId, $data) + { + $this->_logDB(self::WARNING, $requestId, $data); + } + + /** + * Writes an error log to database + */ + public function logErrorDB($requestId, $data) + { + $this->_logDB(self::ERROR, $requestId, $data); } // -------------------------------------------------------------------------------------------------------------- // Private methods /** - * log + * Writes using CodeIgniter log system (file system) */ private function _log($level, $message) { - log_message($level, $this->_getCaller().$message); + log_message($level, $this->_getPrefix($this->_getCaller()).$message); } /** - * _getCaller + * Writes logs to database + */ + private function _logDB($level, $requestId, $data) + { + // If the _dbLogType parameter was not given when this library was loaded + // NOTE: this message will be displayed only to the developer AND stops the execution + if ($this->_dbLogType == null) + { + show_error('To log to database you need to specify the "'.self::P_NAME_DB_LOG_TYPE.'" parameter when the LogLib is loaded'); + } + + $ci =& get_instance(); // get code igniter instance + + // If only debug log is enabed then is possible to write a debug log, otherwise... + if ($level == self::DEBUG && $ci->config->item(self::CI_LOG_THRESHOLD_NAME) != self::CI_LOG_THRESHOLD_DEBUG) + { + // ...do nothing + } + else + { + // Loads WebservicelogModel + $ci->load->model('system/Webservicelog_model', 'WebservicelogModel'); + + // Get caller data + $callerData = $this->_getCaller(); + + // Writes a log to database + $ci->WebservicelogModel->insert(array( + 'webservicetyp_kurzbz' => $this->_dbLogType, + 'request_id' => $requestId, + 'beschreibung' => $this->_getDatabaseDescription($callerData), + 'request_data' => $data, + 'execute_user' => $this->_dbExecuteUser, + 'execute_time' => 'NOW()' // current time + )); + } + } + + /** + * Retrieves caller's data */ private function _getCaller() { - $classIndex = 3; - $functionIndex = 3; - $lineIndex = 2; $class = ''; $function = ''; $line = ''; $backtrace_arr = debug_backtrace(); - if (isset($backtrace_arr[$classIndex]['class']) && $backtrace_arr[$classIndex]['class'] != '') + + if (isset($backtrace_arr[$this->_classIndex]['class']) && $backtrace_arr[$this->_classIndex]['class'] != '') { - $class = $backtrace_arr[$classIndex]['class']; + $class = $backtrace_arr[$this->_classIndex]['class']; } - if (isset($backtrace_arr[$functionIndex]['function']) && $backtrace_arr[$functionIndex]['function'] != '') + if (isset($backtrace_arr[$this->_functionIndex]['function']) && $backtrace_arr[$this->_functionIndex]['function'] != '') { - $function = $backtrace_arr[$functionIndex]['function']; + $function = $backtrace_arr[$this->_functionIndex]['function']; } - if (isset($backtrace_arr[$lineIndex]['line']) && $backtrace_arr[$lineIndex]['line'] != '') + if (isset($backtrace_arr[$this->_lineIndex]['line']) && $backtrace_arr[$this->_lineIndex]['line'] != '') { - $line = $backtrace_arr[$lineIndex]['line']; + $line = $backtrace_arr[$this->_lineIndex]['line']; } - return $this->_format($class, $function, $line); + return array( + self::CLASS_NAME => $class, + self::FUNCTION_NAME => $function, + self::CODE_LINE => $line + ); } /** - * format + * Formats the log message prefix (file system based) */ - private function _format($class, $function, $line) + private function _getPrefix($callerData) { - $formatted = LogLib::CALLER_PREFIX; + $formatted = self::CALLER_PREFIX; - if (!is_null($class) && $class != '') + if (!isEmptyString($callerData[self::CLASS_NAME])) { - $formatted .= $class.LogLib::CLASS_POSTFIX; + $formatted .= $callerData[self::CLASS_NAME].self::CLASS_POSTFIX; } - $formatted .= $function.LogLib::LINE_SEPARATOR.$line.LogLib::CALLER_POSTFIX.' '; + $formatted .= $callerData[self::FUNCTION_NAME].self::LINE_SEPARATOR.$callerData[self::CODE_LINE].self::CALLER_POSTFIX.' '; + + return $formatted; + } + + /** + * Formats the database description for a log + */ + private function _getDatabaseDescription($callerData) + { + $formatted = $callerData[self::FUNCTION_NAME].self::LINE_SEPARATOR.$callerData[self::CODE_LINE]; + + if (!isEmptyString($callerData[self::CLASS_NAME])) + { + $formatted = $callerData[self::CLASS_NAME].self::CLASS_POSTFIX.$formatted; + } return $formatted; } diff --git a/application/models/system/Webservicelog_model.php b/application/models/system/Webservicelog_model.php index dc45b13a7..a5b23a396 100644 --- a/application/models/system/Webservicelog_model.php +++ b/application/models/system/Webservicelog_model.php @@ -1,13 +1,14 @@ dbTable = 'system.tbl_webservicelog'; $this->pk = 'webservicelog_id'; } diff --git a/public/css/FilterWidget.css b/public/css/FilterWidget.css index 295dff8ec..5254268c7 100644 --- a/public/css/FilterWidget.css +++ b/public/css/FilterWidget.css @@ -113,3 +113,19 @@ #applyFilter, #saveCustomFilterButton { width: 100px; } + +.text-red { + color: red; +} + +.text-orange { + color: orange; +} + +.text-blue { + color: blue; +} + +.text-green { + color: green; +} diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 4e720daef..1947debdb 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3030,6 +3030,20 @@ if(!$result = @$db->db_query("SELECT stufe FROM public.tbl_dokumentstudiengang L echo '
    public.tbl_dokumentstudiengang: Spalte stufe hinzugefuegt'; } +// Add new webservice type in system.tbl_webservicetyp +if ($result = @$db->db_query("SELECT 1 FROM system.tbl_webservicetyp WHERE webservicetyp_kurzbz = 'job';")) +{ + if ($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO system.tbl_webservicetyp(webservicetyp_kurzbz, beschreibung) VALUES('job', 'Cronjob');"; + + if (!$db->db_query($qry)) + echo 'system.tbl_webservicetyp '.$db->db_last_error().'
    '; + else + echo ' system.tbl_webservicetyp: Added webservice type "job"
    '; + } +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 413b821af..2d1789774 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -353,7 +353,7 @@ $filters = array( {"name": "fakultaet"}, {"name": "datum"}, {"name": "uhrzeit"}, - {"name": "anmeldefrist"}, + {"name": "anmeldefrist"}, {"name": "oeffentlich"}, {"name": "studiengaenge"}, {"name": "freie_plaetze"}, @@ -460,6 +460,28 @@ $filters = array( } ', 'oe_kurzbz' => null, + ), + array( + 'app' => 'core', + 'dataset_name' => 'jobslogs', + 'filter_kurzbz' => 'all', + 'description' => '{All logs produced by jobs}', + 'sort' => 1, + 'default_filter' => true, + 'filter' => ' + { + "name": "All jobs viewer", + "columns": [ + {"name": "RequestId"}, + {"name": "ExecutionTime"}, + {"name": "ExecutedBy"}, + {"name": "Description"}, + {"name": "Data"} + ], + "filters": [] + } + ', + 'oe_kurzbz' => null, ) ); From f778297fb548ad35accf7deef8d62cd950277609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 29 Aug 2019 11:15:58 +0200 Subject: [PATCH 117/500] Reihenfolge der Eingabefelder angepasst --- cis/private/tools/zeitaufzeichnung.php | 250 +++++++++++++------------ 1 file changed, 128 insertions(+), 122 deletions(-) diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index aed20cd00..7461f2421 100644 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -828,90 +828,6 @@ if($projekt->getProjekteMitarbeiter($user, true)) echo ''; } - //Projekte werden nicht angezeigt wenn es keine gibt - if($anzprojekte > 0) - { - //Projekt - echo '
    - - '; - echo ''; - } - if($za_simple >= 0) - { - //OE_KURZBZ_1 - echo ' - '; - } - //Aktivitaet echo ''; echo ''; + + if($za_simple >= 0) + { + $oestyle = ''; + if($za_simple == 0) + $oestyle = 'style="width:200px;"'; + + //OE_KURZBZ_1 + echo ' + '; + } + + //Projekte werden nicht angezeigt wenn es keine gibt + if($anzprojekte > 0) + { + //Projekt + echo ' + + '; + echo ''; + } + if ($za_simple == 0) { - // Service - echo ' - - + + + echo ' + '; + + // person für Kundenvoransicht laden + $kunde_name = ''; + if($kunde_uid != '') + { + $user_kunde = new benutzer(); + + if($user_kunde->load($kunde_uid)) + $kunde_name=$user_kunde->vorname.' '.$user_kunde->nachname; + } + echo ' + + + '; - - // person für Kundenvoransicht laden - $kunde_name = ''; - if($kunde_uid != '') - { - $user_kunde = new benutzer(); - - if($user_kunde->load($kunde_uid)) - $kunde_name=$user_kunde->vorname.' '.$user_kunde->nachname; - } - echo ' - - - - '; - echo ''; + echo ''; } //Start/Ende From b910f220ac19bd84da3faf58868ab883059e3787 Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 29 Aug 2019 14:07:45 +0200 Subject: [PATCH 118/500] Added method getSTG_isEntitledFor to retrieve STG by entitlement of user --- application/libraries/PermissionLib.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/application/libraries/PermissionLib.php b/application/libraries/PermissionLib.php index b84359216..c0e3781a4 100644 --- a/application/libraries/PermissionLib.php +++ b/application/libraries/PermissionLib.php @@ -254,6 +254,26 @@ class PermissionLib return !$this->_inLAPersonIdsBlacklist($person_id) && $this->_hasLAPermissions(); } + /** + * Returns the study programs the person is entitled for. + * @param null $berechtigung_kurzbz If given, only study programs are retrieved according to organisational units + * assigned to that permission. + * @return array|bool array of studiengang_kz the person is entitled for. False on error. + */ + public function getSTG_isEntitledFor($berechtigung_kurzbz = null) + { + $studiengang_kz_arr = array(); + + if (self::$bb->getStgKz($berechtigung_kurzbz)) + { + return $studiengang_kz_arr = self::$bb->getStgKz($berechtigung_kurzbz); + } + else + { + return false; + } + } + //------------------------------------------------------------------------------------------------------------------ // Private methods From e95cc7556e034128d8c5add1f7031d51c1b02dda Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 29 Aug 2019 14:08:34 +0200 Subject: [PATCH 119/500] tablesort_bootstrap layout changes: removed background color from filter row --- public/css/sbadmin2/tablesort_bootstrap.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/sbadmin2/tablesort_bootstrap.css b/public/css/sbadmin2/tablesort_bootstrap.css index b01beccdd..3e2574241 100644 --- a/public/css/sbadmin2/tablesort_bootstrap.css +++ b/public/css/sbadmin2/tablesort_bootstrap.css @@ -42,7 +42,7 @@ table.tablesort-hover tr:hover, .tablesort-active { } /* Remove background color from filter row */ -.tablesorter-default .tablesorter-filter-row td { +.tablesorter-default .tablesorter-filter-row td, .tablesorter-default .tablesorter-filter-row:hover td { background-color: white !important; } From aad5f7bd5edc4937665601f93c3a955aea254f92 Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 29 Aug 2019 14:19:01 +0200 Subject: [PATCH 120/500] Amended Lehrauftrag Controller - GUI with Tabulator-table Amended the Lehrauftrag Controller GUI: . corrected DB query . corrected processing of GET-params . corrected filter of tabulator (LE-ID caused problems -> now LE_ID) . now stg are retrieved by permission entitlement of user . implemented Tabulator filter and other properties/functions . minor GUI adaptations . added phrase --- .../lehre/lehrauftrag/Lehrauftrag.php | 56 +++--- .../views/lehre/lehrauftrag/lehrauftrag.php | 104 ++++++----- .../lehre/lehrauftrag/lehrauftragData.php | 168 +++++++++++++----- system/filtersupdate.php | 4 +- system/phrasesupdate.php | 22 ++- 5 files changed, 230 insertions(+), 124 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php index 847bc2f3d..b214916cd 100644 --- a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php +++ b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php @@ -1,10 +1,9 @@ 'infocenter:r' + 'index' => 'lehre/lehrauftrag_bestellen:r' ) ); // Load models - $this->load->model('education/Lehreinheit_model', 'LehreinheitModel'); - $this->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); -// $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); // TODO: delete? - $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); - // TODO: check: WidgetLib notwendig? // Load libraries $this->load->library('WidgetLib'); + $this->load->library('PermissionLib'); // Load language phrases $this->loadPhrases( @@ -50,9 +45,6 @@ class Lehrauftrag extends Auth_Controller $this->_setAuthUID(); // sets property uid - //TODO: delete test user - //$this->_uid = 'testuser'; - $this->setControllerId(); // sets the controller id } @@ -63,31 +55,21 @@ class Lehrauftrag extends Auth_Controller */ public function index() { - echo '
    ', print_r($_GET, 1), '
    '; - $studiengang_kz = $this->input->get('studiengang'); - $studiensemester_kurzbz = $this->input->get('studiensemester'); + // Set studiengang selected for studiengang dropdown + $studiengang_kz = $this->input->get('studiengang'); // if provided by selected studiengang + $studiengang_kz = ($studiengang_kz == 'null' ? null : $studiengang_kz); - // Set studiengang variable - if (!isset($studiengang_kz) || !is_numeric($studiengang_kz)) + // Retrieve studiengaenge the user is entitled for to populate studiengang dropdown + if (!$studiengang_kz_arr = $this->permissionlib->getSTG_isEntitledFor(self::BERECHTIGUNG_LEHRAUFTRAG_BESTELLEN)) { - $benutzerfunktion = $this->BenutzerfunktionModel->getSTGLByUID($this->_uid); - - $studiengang_kz_arr = array(); - if (hasData($benutzerfunktion)) - { - foreach ($benutzerfunktion->retval as $benutzerfkt) - { - $studiengang_kz_arr[] = $benutzerfkt->studiengang_kz; - } - } - elseif (isError($benutzerfunktion)) - { - show_error($benutzerfunktion->error); - } + show_error('Fehler bei Berechtigungsprüfung'); } - // Set studiensemester variable - if (!isset($studiensemester_kurzbz) || !is_string($studiensemester_kurzbz)) + + // Set studiensemester selected for studiengang dropdown + $studiensemester_kurzbz = $this->input->get('studiensemester'); // if provided by selected studiensemester + + if (is_null($studiensemester_kurzbz)) // else set next studiensemester as default value { $studiensemester = $this->StudiensemesterModel->getNext(); if (hasData($studiensemester)) @@ -99,15 +81,17 @@ class Lehrauftrag extends Auth_Controller show_error($studiensemester->error); } } + $view_data = array( + 'studiengang_selected' => $studiengang_kz, 'studiengang' => $studiengang_kz_arr, - 'studiensemester' => $studiensemester_kurzbz + 'studiensemester_selected' => $studiensemester_kurzbz ); + $this->load->view('lehre/lehrauftrag/lehrauftrag.php', $view_data); } - // ----------------------------------------------------------------------------------------------------------------- // Private methods diff --git a/application/views/lehre/lehrauftrag/lehrauftrag.php b/application/views/lehre/lehrauftrag/lehrauftrag.php index 098bb448f..7742f05f8 100644 --- a/application/views/lehre/lehrauftrag/lehrauftrag.php +++ b/application/views/lehre/lehrauftrag/lehrauftrag.php @@ -16,58 +16,74 @@ $this->load->view( 'filterwidget' => true, 'navigationwidget' => true, 'phrases' => array( - 'person' => array('vorname', 'nachname'), - 'global' => array('mailAnXversandt'), - 'ui' => array('bitteEintragWaehlen') + 'global' => array('lehrauftraege'), ), 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', - 'customJSs' => array('public/js/bootstrapper.js', '') + 'customJSs' => array('public/js/bootstrapper.js') ) ); ?> +
    +
    +
    +
    +
    + +
    +
    + +
    + widgetlib->widget( + 'Studiensemester_widget', + array( + DropdownWidget::SELECTED_ELEMENT => $studiensemester_selected + ), + array( + 'name' => 'studiensemester', + 'id' => 'studiensemester' + ) + ); + ?> +
    +
    + widgetlib->widget( + 'Studiengang_widget', + array( + DropdownWidget::SELECTED_ELEMENT => $studiengang_selected, + 'studiengang' => $studiengang + ), + array( + 'name' => 'studiengang', + 'id' => 'studiengang' + ) + ); + ?> +
    + + +
    +
    -
    - -
    - - widgetlib->widget( - 'Studiengang_widget', - array( - DropdownWidget::SELECTED_ELEMENT => $studiengang[0], - 'studiengang' => $studiengang - ), - array( - 'name' => 'studiengang', - 'id' => 'studiengang', - 'class' => 'form-control' - ) - ); - ?> -
    -
    - - widgetlib->widget( - 'Studiensemester_widget', - array( - DropdownWidget::SELECTED_ELEMENT => $studiensemester - ), - array( - 'name' => 'studiensemester', - 'id' => 'studiensemester', - 'class' => 'form-control' - ) - ); - ?> -
    - -
    -
    - load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> -
    +
    + load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> +
    +
    +
    + + + +
    +
    + +
    +
    + load->view('templates/FHC-Footer'); ?> diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 8abc5dc46..f8166bf15 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -1,53 +1,122 @@ = 0 + + +UNION + +/* Projektbetreuungsaufträge and -vertragsstati */ +SELECT + pa.lehreinheit_id AS "LE_ID", + \'Betreuung\' AS "Typ", + (betreuerart_kurzbz || \' \' || + (SELECT + vorname || \' \' || nachname + FROM + public.tbl_person + JOIN public.tbl_benutzer USING (person_id) + WHERE + uid = pa.student_uid) + || \' [\' || projekttyp_kurzbz || \'arbeit\' || \' \' || lv.semester || \'.Semester]\') AS "Auftrag", + CASE + WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) + WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) + ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) + END AS "Organisationseinheit", + CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", + (vorname || \' \' || nachname) AS "Lektor", + TRUNC(pb.stunden, 1) AS "Stunden", + TRUNC((pb.stunden * pb.stundensatz), 2) AS "Betrag", + CASE + /* existing contracts for given study semester with status bestellt */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum + END AS "Bestellt", + CASE + /* existing contracts for given study semester with status erteilt */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum + END AS "Erteilt", + CASE + /* existing contracts for given study semester with status akzeptiert */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum + END AS "Akzeptiert" +FROM + lehre.tbl_projektbetreuer pb + JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id) + JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) + JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) + JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) + JOIN public.tbl_person person USING (person_id) + LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) + LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) + LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) + JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz +WHERE + /* filter studiengang */ + lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') + /* filter studiensemester */ + AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' + /* filter active lehrveranstaltungen */ + AND lv.aktiv = TRUE + +ORDER BY "Typ" DESC, "Auftrag", "Lektor" '; @@ -56,35 +125,52 @@ $filterWidgetArray = array( 'app' => Lehrauftrag::APP, 'datasetName' => 'lehrauftragOrder', 'filterKurzbz' => 'LehrauftragOrder', - //'filter_id' => $this->input->get('filter_id'), - 'requiredPermissions' => 'infocenter', // TODO: change permission + 'requiredPermissions' => 'lehre', // TODO: change permission 'datasetRepresentation' => 'tabulator', - 'reloadDataset' => ($this->input->get('reloadDataset') == 'true' ? true : false), // TODO: needed? - //'customMenu' => true, + 'customMenu' => false, 'hideOptions' => true, 'hideMenu' => true, - 'columnsAliases' => array( - ucfirst($this->p->t('person', 'vorname')) + 'columnsAliases' => array( // TODO: use phrasen + 'LE-ID', + ucfirst($this->p->t('global', 'typ')), + 'Auftrag', + 'Organisationseinheit', + 'Gruppe', + 'Lektor', + 'Stunden', + 'Betrag', + 'Bestellt', + 'Erteilt', + 'Akzeptiert' ), - 'markRow' => function($datasetRaw) { - - $mark = ''; - - if ($datasetRaw->LockDate != null) + 'formatRow' => function($datasetRaw) { + if (is_null($datasetRaw->{'Betrag'})) { - $mark = FilterWidget::DEFAULT_MARK_ROW_CLASS; + $datasetRaw->{'Betrag'} = 'Stundensatz fehlt'; } - - // Parking has priority over locking - if ($datasetRaw->ParkDate != null) - { - $mark = "text-info"; - } - - return $mark; + return $datasetRaw; }, - 'datasetRepOptions' => '{height: 300}', // tabulator properties - 'datasetRepFieldsDefs' => '{Vorname: {width: 400}}' // col properties + 'datasetRepOptions' => '{ + height: 700, + selectable: true, // allows row selection + selectableRangeMode: "click", // allows range selection using shift end click on end of range + movableColumns: true, // allows changing column + pagination: "local", // paginates the data + paginationSize: 15 // rows allowed per page + }', // tabulator properties + 'datasetRepFieldsDefs' => '{ + LE_ID: {headerFilter:"input", headerFilterPlaceholder:" "}, + Typ: {headerFilter:"input", headerFilterPlaceholder:" "}, + Auftrag: {headerFilter:"input", headerFilterPlaceholder:" "}, + Organisationseinheit: {headerFilter:"input", headerFilterPlaceholder:" "}, + Gruppe: {headerFilter:"input", headerFilterPlaceholder:" "}, + Lektor: {headerFilter:"input", headerFilterPlaceholder:" "}, + Stunden: {align:"right", headerFilter:"input", headerFilterPlaceholder:" "}, + Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc:">="}, + Bestellt: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "}, + Erteilt: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "}, + Akzeptiert: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "} + }', // col properties ); echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 19ebea0f9..a31fe702e 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -408,9 +408,9 @@ $filters = array( 'default_filter' => true, 'filter' => ' { - "name": "Lehrauftragsstatus", + "name": "", "columns": [ - {"name": "LE-ID"}, + {"name": "LE_ID"}, {"name": "Typ"}, {"name": "Auftrag"}, {"name": "Organisationseinheit"}, diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 0ee2aeda5..b39280a29 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -3450,7 +3450,27 @@ $phrases = array( 'insertvon' => 'system' ) ) - ) + ), + array( + 'app' => 'core', + 'category' => 'global', + 'phrase' => 'lehrauftraege', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehraufträge', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Lectureships', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ) ); From 6dcf97c848c81277dec7b650157e110fd1ee670a Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 29 Aug 2019 14:22:34 +0200 Subject: [PATCH 121/500] Added using of specific, limited studiengang-array in Dropdown-Widget By passing an array of studiengang_kz the dropdown-menu will only be populated with them. --- application/widgets/Studiengang_widget.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/application/widgets/Studiengang_widget.php b/application/widgets/Studiengang_widget.php index 5515b6b82..a8b98dcda 100644 --- a/application/widgets/Studiengang_widget.php +++ b/application/widgets/Studiengang_widget.php @@ -10,9 +10,8 @@ class Studiengang_widget extends DropdownWidget $this->addSelectToModel($this->StudiengangModel, 'studiengang_kz', '\'(\' || kurzbzlang || \') \' || tbl_studiengang.bezeichnung'); - - // If a specific array of studiengaenge is privided, set the condition to retrieve them - if (isset($widgetData['studiengang'])) + // If 'studiengang' (array of specific studiengaenge) is given, retrieve these studiengaenge only + if (isset($widgetData['studiengang']) && !empty($widgetData['studiengang'])) { $condition = ' studiengang_kz IN ('. implode(',', $widgetData['studiengang']) . ') AND @@ -28,7 +27,7 @@ class Studiengang_widget extends DropdownWidget $this->setElementsArray( $this->StudiengangModel->loadWhere($condition), true, - 'Select a studiengang...', + $this->p->t('ui', 'bitteEintragWaehlen'), 'No studiengaenge found' ); From d06c03f0dbef506881412846a867accb0a94f386 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 30 Aug 2019 15:52:47 +0200 Subject: [PATCH 122/500] - updated pivottable in composer to v 2.21.0 --- composer.json | 4 +- composer.lock | 175 ++++++++++++++++++++++++++++---------------------- 2 files changed, 102 insertions(+), 77 deletions(-) diff --git a/composer.json b/composer.json index d763dc5ad..631cf73c9 100644 --- a/composer.json +++ b/composer.json @@ -168,7 +168,7 @@ "name": "nicolaskruchten/pivottable", "version": "2.15.0", "dist": { - "url": "https://github.com/nicolaskruchten/pivottable/archive/v2.15.0.zip", + "url": "https://github.com/nicolaskruchten/pivottable/archive/v2.21.0.zip", "type": "zip" } } @@ -258,7 +258,7 @@ "nategood/httpful": "^0.2.20", "netcarver/textile": "^3.5", - "nicolaskruchten/pivottable": "^2.15.0", + "nicolaskruchten/pivottable": "^2.21.0", "phpseclib/phpseclib": "^2.0", diff --git a/composer.lock b/composer.lock index 8fc88ce07..28938b9f6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ddbbad487c655512e6983408339cb85f", - "content-hash": "b5902c71fe21cd14397101dba5a3080c", + "content-hash": "ad1bf16a24075268ce1cf2a033f9e7fb", "packages": [ { "name": "BlackrockDigital/startbootstrap-sb-admin-2", @@ -47,7 +46,7 @@ ], "description": "Defacto way to enable use of HTML5 sectioning elements in legacy Internet Explorer.", "homepage": "http://paulirish.com/2011/the-history-of-the-html5-shiv/", - "time": "2015-07-20 20:04:00" + "time": "2015-07-20T20:04:00+00:00" }, { "name": "alvaro-prieto/colResizable", @@ -87,7 +86,7 @@ }, "type": "library", "notification-url": "https://packagist.org/downloads/", - "time": "2016-09-02 11:31:54" + "time": "2016-09-02T11:31:54+00:00" }, { "name": "codeigniter/framework", @@ -120,7 +119,7 @@ ], "description": "The CodeIgniter framework", "homepage": "https://codeigniter.com", - "time": "2019-01-16 15:49:35" + "time": "2019-01-16T15:49:35+00:00" }, { "name": "components/angular.js", @@ -424,7 +423,7 @@ ], "description": "Shim repository for Angular.js", "homepage": "http://angularjs.org", - "time": "2015-06-07 20:10:38" + "time": "2015-06-07T20:10:38+00:00" }, { "name": "components/font-awesome", @@ -459,7 +458,7 @@ "OFL-1.1" ], "description": "The iconic font designed for use with Twitter Bootstrap.", - "time": "2016-10-25 10:56:23" + "time": "2016-10-25T10:56:23+00:00" }, { "name": "components/jquery", @@ -501,7 +500,7 @@ ], "description": "jQuery JavaScript Library", "homepage": "http://jquery.com", - "time": "2018-03-04 13:23:48" + "time": "2018-03-04T13:23:48+00:00" }, { "name": "components/jqueryui", @@ -586,7 +585,7 @@ } ], "description": "jQuery UI is a curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library. Whether you're building highly interactive web applications or you just need to add a date picker to a form control, jQuery UI is the perfect choice.", - "time": "2016-09-16 05:47:55" + "time": "2016-09-16T05:47:55+00:00" }, { "name": "easyrdf/easyrdf", @@ -648,7 +647,7 @@ "rdfa", "sparql" ], - "time": "2015-02-27 09:45:49" + "time": "2015-02-27T09:45:49+00:00" }, { "name": "fgelinas/timepicker", @@ -658,6 +657,12 @@ "url": "https://github.com/fgelinas/timepicker", "reference": "9aebe413b784696639220bc36b7c1e8a30fda129" }, + "dist": { + "type": "zip", + "url": "https://fgelinas.com/code/timepicker/releases/jquery-ui-timepicker-0.3.3.zip", + "reference": null, + "shasum": null + }, "type": "library" }, { @@ -708,7 +713,7 @@ "faker", "fixtures" ], - "time": "2018-07-12 10:23:15" + "time": "2018-07-12T10:23:15+00:00" }, { "name": "joeldbirch/superfish", @@ -850,7 +855,7 @@ "json", "schema" ], - "time": "2014-08-25 02:48:14" + "time": "2014-08-25T02:48:14+00:00" }, { "name": "kevinlebrun/colors.php", @@ -901,7 +906,7 @@ "console", "shell" ], - "time": "2018-05-30 08:34:23" + "time": "2018-05-30T08:34:23+00:00" }, { "name": "kingsquare/json-schema-form", @@ -935,17 +940,11 @@ } ], "description": "A framework-agnostic PHP Implementation for generating simple forms based on json-schema", - "time": "2014-07-10 12:27:19" + "time": "2014-07-10T12:27:19+00:00" }, { "name": "ludo/jquery-treetable", "version": "3.2.0", - "dist": { - "type": "zip", - "url": "https://github.com/ludo/jquery-treetable/archive/3.2.0.zip", - "reference": null, - "shasum": null - }, "type": "library" }, { @@ -997,7 +996,7 @@ "keywords": [ "markdown" ], - "time": "2015-03-01 12:03:08" + "time": "2015-03-01T12:03:08+00:00" }, { "name": "ml/iri", @@ -1044,7 +1043,7 @@ "uri", "url" ], - "time": "2014-01-21 13:43:39" + "time": "2014-01-21T13:43:39+00:00" }, { "name": "ml/json-ld", @@ -1093,7 +1092,7 @@ "JSON-LD", "jsonld" ], - "time": "2018-11-18 20:26:18" + "time": "2018-11-18T20:26:18+00:00" }, { "name": "mottie/tablesorter", @@ -1144,7 +1143,7 @@ "sorting", "table" ], - "time": "2018-11-20 21:54:28" + "time": "2018-11-20T21:54:28+00:00" }, { "name": "nategood/httpful", @@ -1194,7 +1193,7 @@ "rest", "restful" ], - "time": "2015-10-26 16:11:30" + "time": "2015-10-26T16:11:30+00:00" }, { "name": "netcarver/textile", @@ -1247,18 +1246,50 @@ "plaintext", "textile" ], - "time": "2019-01-26 17:03:58" + "time": "2019-01-26T17:03:58+00:00" }, { "name": "nicolaskruchten/pivottable", - "version": "2.15.0", + "version": "v2.23.0", + "source": { + "type": "git", + "url": "https://github.com/nicolaskruchten/pivottable.git", + "reference": "a9cabee5382be0aaf0984ac906d9fa2e0376d2c1" + }, "dist": { "type": "zip", - "url": "https://github.com/nicolaskruchten/pivottable/archive/v2.15.0.zip", - "reference": null, - "shasum": null + "url": "https://api.github.com/repos/nicolaskruchten/pivottable/zipball/a9cabee5382be0aaf0984ac906d9fa2e0376d2c1", + "reference": "a9cabee5382be0aaf0984ac906d9fa2e0376d2c1", + "shasum": "" }, - "type": "library" + "require": { + "components/jquery": ">=1.9" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Kruchten", + "email": "nicolas@kruchten.com" + } + ], + "description": "Javascript Pivot Table (aka Pivot Grid, Pivot Chart, Cross-Tab) implementation with drag'n'drop.", + "homepage": "https://pivottable.js.org/", + "keywords": [ + "crosstab", + "grid", + "jquery", + "jquery-plugin", + "pivot", + "pivotchart", + "pivotgrid", + "pivottable", + "table" + ], + "time": "2018-11-04T18:21:09+00:00" }, { "name": "phpseclib/phpseclib", @@ -1305,28 +1336,28 @@ "authors": [ { "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" + "role": "Lead Developer", + "email": "terrafrost@php.net" }, { "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" + "role": "Developer", + "email": "pm@datasphere.ch" }, { "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" + "role": "Developer", + "email": "bantu@phpbb.com" }, { "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" + "role": "Developer", + "email": "petrich@tronic-media.com" }, { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "role": "Developer" + "role": "Developer", + "email": "graham@alt-three.com" } ], "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", @@ -1350,7 +1381,7 @@ "x.509", "x509" ], - "time": "2019-03-10 16:53:45" + "time": "2019-03-10T16:53:45+00:00" }, { "name": "psr/log", @@ -1397,7 +1428,7 @@ "psr", "psr-3" ], - "time": "2018-11-20 15:27:04" + "time": "2018-11-20T15:27:04+00:00" }, { "name": "rdlowrey/auryn", @@ -1458,17 +1489,11 @@ "dic", "ioc" ], - "time": "2017-05-15 06:26:46" + "time": "2017-05-15T06:26:46+00:00" }, { "name": "rmariuzzo/jquery-checkboxes", "version": "1.0.7", - "dist": { - "type": "zip", - "url": "https://github.com/rmariuzzo/checkboxes.js/archive/v1.0.7.zip", - "reference": null, - "shasum": null - }, "type": "library" }, { @@ -1520,7 +1545,7 @@ "php", "template" ], - "time": "2016-02-01 16:31:13" + "time": "2016-02-01T16:31:13+00:00" }, { "name": "rougin/combustor", @@ -1585,7 +1610,7 @@ "generator", "php" ], - "time": "2016-02-14 10:36:58" + "time": "2016-02-14T10:36:58+00:00" }, { "name": "rougin/describe", @@ -1638,7 +1663,7 @@ "describe", "php" ], - "time": "2016-03-24 18:17:47" + "time": "2016-03-24T18:17:47+00:00" }, { "name": "rougin/refinery", @@ -1703,7 +1728,7 @@ "php", "refinery" ], - "time": "2016-03-04 16:55:32" + "time": "2016-03-04T16:55:32+00:00" }, { "name": "rougin/spark-plug", @@ -1762,7 +1787,7 @@ "php", "spark-plug" ], - "time": "2015-10-23 08:27:10" + "time": "2015-10-23T08:27:10+00:00" }, { "name": "scottjehl/Respond", @@ -1834,7 +1859,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-11-20 15:55:20" + "time": "2018-11-20T15:55:20+00:00" }, { "name": "symfony/debug", @@ -1891,7 +1916,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1949,7 +1974,7 @@ "polyfill", "portable" ], - "time": "2019-02-06 07:57:58" + "time": "2019-02-06T07:57:58+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2008,7 +2033,7 @@ "portable", "shim" ], - "time": "2019-02-06 07:57:58" + "time": "2019-02-06T07:57:58+00:00" }, { "name": "symfony/yaml", @@ -2058,7 +2083,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-11-11 11:18:13" + "time": "2018-11-11T11:18:13+00:00" }, { "name": "tapmodo/Jcrop", @@ -2115,7 +2140,7 @@ "tinymce", "wysiwyg" ], - "time": "2019-03-20 13:56:58" + "time": "2019-03-20T13:56:58+00:00" }, { "name": "tomazdragar/SimpleCropper", @@ -2176,7 +2201,7 @@ "responsive", "web" ], - "time": "2019-02-13 15:55:38" + "time": "2019-02-13T15:55:38+00:00" }, { "name": "twig/twig", @@ -2222,19 +2247,19 @@ "authors": [ { "name": "Fabien Potencier", + "role": "Lead Developer", "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" + "homepage": "http://fabien.potencier.org" }, { "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" + "role": "Project Founder", + "email": "armin.ronacher@active-4.com" }, { "name": "Twig Team", - "homepage": "https://twig.symfony.com/contributors", - "role": "Contributors" + "role": "Contributors", + "homepage": "https://twig.symfony.com/contributors" } ], "description": "Twig, the flexible, fast, and secure template language for PHP", @@ -2242,7 +2267,7 @@ "keywords": [ "templating" ], - "time": "2019-05-14 11:59:08" + "time": "2019-05-14T11:59:08+00:00" }, { "name": "zetacomponents/base", @@ -2306,7 +2331,7 @@ ], "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", "homepage": "https://github.com/zetacomponents", - "time": "2017-11-28 11:30:00" + "time": "2017-11-28T11:30:00+00:00" }, { "name": "zetacomponents/database", @@ -2383,7 +2408,7 @@ ], "description": "A lightweight database layer on top of PHP's PDO that allows you to utilize a database without having to take care of differences in SQL dialects.", "homepage": "https://github.com/zetacomponents", - "time": "2017-11-28 10:55:26" + "time": "2017-11-28T10:55:26+00:00" }, { "name": "zetacomponents/document", @@ -2434,7 +2459,7 @@ ], "description": "The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.", "homepage": "https://github.com/zetacomponents", - "time": "2013-12-19 11:40:00" + "time": "2013-12-19T11:40:00+00:00" }, { "name": "zetacomponents/workflow", @@ -2500,7 +2525,7 @@ ], "description": "The purpose of the Workflow component is to provide the core functionality of an activity-based workflow system including the definition and execution of workflow specifications.", "homepage": "https://github.com/zetacomponents", - "time": "2014-09-27 19:26:10" + "time": "2014-09-27T19:26:10+00:00" }, { "name": "zetacomponents/workflow-database-tiein", @@ -2567,7 +2592,7 @@ ], "description": "Contains the database backend for the Workflow component.", "homepage": "https://github.com/zetacomponents", - "time": "2014-09-27 19:26:10" + "time": "2014-09-27T19:26:10+00:00" }, { "name": "zetacomponents/workflow-event-log-tiein", @@ -2627,7 +2652,7 @@ ], "description": "Contains the EventLog listener for the Workflow component.", "homepage": "https://github.com/zetacomponents", - "time": "2007-12-17 09:04:44" + "time": "2007-12-17T09:04:44+00:00" } ], "packages-dev": [], From 6c2cc7412dee3a632df7c3e5134bc9f1ca7c70ba Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 3 Sep 2019 10:26:24 +0200 Subject: [PATCH 123/500] Enhanced tabulator selection/filtering functionality . Added buttons "select all" and "deselect all" . Now filtering will deselect previously selected rows (before: if user selected rows and filtered after, the previously selected rows were kept causing misleading Lehrauftrag orderings) . Added bottom calculations --- .../views/lehre/lehrauftrag/lehrauftrag.php | 31 +++++++---- .../lehre/lehrauftrag/lehrauftragData.php | 52 +++++++++++++------ 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/application/views/lehre/lehrauftrag/lehrauftrag.php b/application/views/lehre/lehrauftrag/lehrauftrag.php index 7742f05f8..425001070 100644 --- a/application/views/lehre/lehrauftrag/lehrauftrag.php +++ b/application/views/lehre/lehrauftrag/lehrauftrag.php @@ -27,7 +27,7 @@ $this->load->view(
    -
    +
    - +
    widgetlib->widget( @@ -66,22 +66,31 @@ $this->load->view( ?>
    - +
    -
    - load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> -
    -
    - - - + load->view('lehre/lehrauftrag/lehrauftragData.php'); ?>
    - + + + + + + + + + +
    +
    + + + +
    +
    diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index f8166bf15..c0c9493e2 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -151,28 +151,48 @@ $filterWidgetArray = array( return $datasetRaw; }, 'datasetRepOptions' => '{ - height: 700, + height: 700, + layout:"fitColumns", // fit columns to width of table + responsiveLayout:"hide", // hide columns that dont fit on the table selectable: true, // allows row selection selectableRangeMode: "click", // allows range selection using shift end click on end of range - movableColumns: true, // allows changing column - pagination: "local", // paginates the data - paginationSize: 15 // rows allowed per page + selectablePersistence:false, // deselect previously selected rows when table is filtered, sorted or paginated + movableColumns: true, // allows changing column + headerFilterPlaceholder: " " }', // tabulator properties 'datasetRepFieldsDefs' => '{ - LE_ID: {headerFilter:"input", headerFilterPlaceholder:" "}, - Typ: {headerFilter:"input", headerFilterPlaceholder:" "}, - Auftrag: {headerFilter:"input", headerFilterPlaceholder:" "}, - Organisationseinheit: {headerFilter:"input", headerFilterPlaceholder:" "}, - Gruppe: {headerFilter:"input", headerFilterPlaceholder:" "}, - Lektor: {headerFilter:"input", headerFilterPlaceholder:" "}, - Stunden: {align:"right", headerFilter:"input", headerFilterPlaceholder:" "}, - Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc:">="}, - Bestellt: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "}, - Erteilt: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "}, - Akzeptiert: {align:"center", headerFilter:"input", headerFilterPlaceholder:" "} + LE_ID: {headerFilter:"input", bottomCalc:"count"}, + Typ: {headerFilter:"input"}, + Auftrag: {headerFilter:"input"}, + Organisationseinheit: {headerFilter:"input"}, + Gruppe: {headerFilter:"input"}, + Lektor: {headerFilter:"input"}, + Stunden: {align:"right", headerFilter:"input", bottomCalc:"sum", bottomCalcParams:{precision:1}}, + Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc:">=", bottomCalc:"sum", bottomCalcParams:{precision:2}}, + Bestellt: {align:"center", headerFilter:"input"}, + Erteilt: {align:"center", headerFilter:"input"}, + Akzeptiert: {align:"center", headerFilter:"input"} }', // col properties ); echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); -?> \ No newline at end of file +?> + + + From 36942d586d65a98eba92d7b559f6e8a1c17e2b3b Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Wed, 4 Sep 2019 12:29:38 +0200 Subject: [PATCH 124/500] =?UTF-8?q?Direkte=20Gruppen=20werden=20Defaultm?= =?UTF-8?q?=C3=A4=C3=9Fig=20als=20Mailgruppen=20erstellt=20und=20als=20nic?= =?UTF-8?q?ht=20sichtbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/models/education/Lehreinheitgruppe_model.php | 4 ++-- content/lvplanung/lehrveranstaltungDBDML.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/models/education/Lehreinheitgruppe_model.php b/application/models/education/Lehreinheitgruppe_model.php index 796ae574b..2a6f9571a 100644 --- a/application/models/education/Lehreinheitgruppe_model.php +++ b/application/models/education/Lehreinheitgruppe_model.php @@ -98,8 +98,8 @@ class Lehreinheitgruppe_model extends DB_Model 'semester' => $lvadata->semester, 'bezeichnung' => $bezeichnung, 'aktiv' => true, - 'mailgrp' => false, - 'sichtbar' => true, + 'mailgrp' => true, + 'sichtbar' => false, 'generiert' => false, 'insertamum' => date('Y-m-d H:i:s'), 'insertvon' => $loggedInUser, diff --git a/content/lvplanung/lehrveranstaltungDBDML.php b/content/lvplanung/lehrveranstaltungDBDML.php index 899dc0e23..8a81ff21a 100644 --- a/content/lvplanung/lehrveranstaltungDBDML.php +++ b/content/lvplanung/lehrveranstaltungDBDML.php @@ -1550,8 +1550,8 @@ if(!$error) $gruppe->semester = $lva->semester; $gruppe->bezeichnung = $bezeichnung; $gruppe->aktiv = true; - $gruppe->mailgrp = false; - $gruppe->sichtbar = true; + $gruppe->mailgrp = true; + $gruppe->sichtbar = false; $gruppe->generiert = false; $gruppe->insertamum = date('Y-m-d H:i:s'); $gruppe->insertvon = $user; @@ -1678,7 +1678,7 @@ if(!$error) $qry = " DELETE FROM lehre.tbl_stundenplandev WHERE gruppe_kurzbz=".$db->db_add_param($gruppe_kurzbz); - + $db->db_query($qry); } else From 934d56c32c4a568078bcb7c989592689682260cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 5 Sep 2019 10:28:03 +0200 Subject: [PATCH 125/500] Changed Wiki path to wiki.fhcomplete.org --- CHANGELOG.md | 2 +- README.md | 4 +-- content/fasoverlay.js.php | 2 +- content/tempus.js.php | 44 +++++++++++++++--------------- include/tw/cis_menu_global.inc.php | 43 ----------------------------- locale/de-AT/dms_link.php | 8 +++--- locale/en-US/dms_link.php | 8 +++--- 7 files changed, 34 insertions(+), 77 deletions(-) delete mode 100644 include/tw/cis_menu_global.inc.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d712a143..fe2a855d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,7 +119,7 @@ - **[DEPRECATED]** Spalte ort_kurzbz in tbl_reihungstest wird nicht mehr verwendet und in zukünftigen Versionen entfernt Zum Update auf diese Version folgen Sie den Anweisungen auf folgender Seite: -http://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=fh-complete:codeigniter +https://wiki.fhcomplete.org/doku.php?id=fh-complete:codeigniter ## [3.1.0] - 2015-11-12 ### Added diff --git a/README.md b/README.md index c4b24c64d..d5620010a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # FH-Complete -* [FH-Complete Homepage](http://www.fhcomplete.org) -* [Wiki](http://fhcomplete.technikum-wien.at/dokuwiki/) +* [FH-Complete Homepage](https://www.fhcomplete.org) +* [Wiki](https://wiki.fhcomplete.org/) * [Changelog](CHANGELOG.md) diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php index bf0da34ae..ffc83d977 100644 --- a/content/fasoverlay.js.php +++ b/content/fasoverlay.js.php @@ -1573,7 +1573,7 @@ function OpenAboutDialog() // **** function OpenManual() { - window.open('http://fhcomplete.technikum-wien.at/dokuwiki/doku.php?','_blank'); + window.open('https://wiki.fhcomplete.org/doku.php?','_blank'); } // **** diff --git a/content/tempus.js.php b/content/tempus.js.php index 28b323be3..578785808 100644 --- a/content/tempus.js.php +++ b/content/tempus.js.php @@ -36,7 +36,7 @@ function Progressmeter(progress_id) var runningprogress=0; this.StopPM=StopPM; this.StartPM=StartPM; - + function StartPM() { // Progressmeter starten. @@ -49,7 +49,7 @@ function Progressmeter(progress_id) runningprogress--; if(runningprogress<0) runningprogress=0; - + // Progressmeter stoppen wenn alle fertig sind if(runningprogress==0) document.getElementById(id).setAttribute('mode','determined'); @@ -70,7 +70,7 @@ function closeWindow() } MitarbeiterDetailValueChanged=false; - + window.close(); } @@ -128,7 +128,7 @@ function loadURL(event) // **** function stpltableChange(db_stpl_table) { - variableChange('db_stpl_table', null, db_stpl_table); + variableChange('db_stpl_table', null, db_stpl_table); return true; } @@ -143,7 +143,7 @@ function studiensemesterChange(stsem, wert) if(typeof(stsem)=='undefined') { var items = document.getElementsByTagName('menuitem'); - + for(i in items) { if(items[i].id=='menu-properies-studiensemester-name' && items[i].getAttribute("checked")=='true') @@ -157,7 +157,7 @@ function studiensemesterChange(stsem, wert) netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); // Request absetzen - + var url = 'content/fasDBDML.php'; var req = new phpRequest(url,'',''); @@ -165,7 +165,7 @@ function studiensemesterChange(stsem, wert) req.add('type', 'variablechange'); req.add('stsem', stsem); req.add('wert', wert); - + var response = req.executePOST(); var val = new ParseReturnValue(response) @@ -184,7 +184,7 @@ function studiensemesterChange(stsem, wert) document.getElementById("statusbarpanel-semester").label = val.dbdml_data; //Menue setzen var items = document.getElementsByTagName('menuitem'); - + for(i in items) { if(items[i].label==val.dbdml_data && items[i].id=='menu-properies-studiensemester-name') @@ -201,7 +201,7 @@ function studiensemesterChange(stsem, wert) } catch(e) {} - + try { LvTreeRefresh(); @@ -209,7 +209,7 @@ function studiensemesterChange(stsem, wert) catch(e) {} } - + return true; } @@ -219,9 +219,9 @@ function studiensemesterChange(stsem, wert) function variableChangeValue(variable) { var variablevalue = getvariable(variable); - + if(variablevalue = prompt('Bitte geben Sie den neuen Wert fuer '+variable+' ein', variablevalue)) - { + { variableChange(variable, '', variablevalue); } } @@ -244,7 +244,7 @@ function variableChange(variable, id, wert) { if(id!=null) item = document.getElementById(id); - + if(typeof(wert)==='undefined') { if(item.getAttribute('checked')=='true') @@ -254,11 +254,11 @@ function variableChange(variable, id, wert) } else checked=wert; - + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); // Request absetzen - + var url = 'content/fasDBDML.php'; var req = new phpRequest(url,'',''); @@ -266,7 +266,7 @@ function variableChange(variable, id, wert) req.add('type', 'variablechange'); req.add('name', variable); req.add('wert', checked); - + var response = req.executePOST(); var val = new ParseReturnValue(response) @@ -312,7 +312,7 @@ function updateignorekollision() panel.style.backgroundColor=''; panel.style.MozAppearance = "none" document.getElementById('menu-prefs-ignore_kollision').setAttribute('checked','false'); - } + } } // **** @@ -332,7 +332,7 @@ function updatedbstpltable() { panel.style.backgroundColor=''; panel.style.MozAppearance = "none" - } + } } @@ -348,7 +348,7 @@ function getStudiensemesterVariable() document.getElementById("statusbarpanel-semester").label = stsem; //Menue setzen var items = document.getElementsByTagName('menuitem'); - + for(i in items) { if(items[i].label==stsem && items[i].id=='menu-properies-studiensemester-name') @@ -357,7 +357,7 @@ function getStudiensemesterVariable() break; } } - + //Ansichten Refreshen try { @@ -365,7 +365,7 @@ function getStudiensemesterVariable() } catch(e) {} - + try { LvTreeRefresh(); @@ -473,7 +473,7 @@ function SyncLVPlan() // **** function OpenManualTempus() { - window.open('https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=tempus:allgemeines','Manual'); + window.open('https://wiki.fhcomplete.org/doku.php?id=tempus:allgemeines','Manual'); } // **** diff --git a/include/tw/cis_menu_global.inc.php b/include/tw/cis_menu_global.inc.php deleted file mode 100644 index 274b1082d..000000000 --- a/include/tw/cis_menu_global.inc.php +++ /dev/null @@ -1,43 +0,0 @@ -, - * Andreas Oesterreicher and - * Rudolf Hangl . - */ -/** - * Menue Oben Rechts fuer CIS Seite - */ - -require_once ('../include/phrasen.class.php'); -require_once ('../include/functions.inc.php'); - -$sprache = getSprache(); -$p = new phrasen($sprache); -?> - -
    - - - - - '; - ?> - -      diff --git a/locale/de-AT/dms_link.php b/locale/de-AT/dms_link.php index a642a0d51..8c5d12d01 100644 --- a/locale/de-AT/dms_link.php +++ b/locale/de-AT/dms_link.php @@ -32,8 +32,8 @@ $this->phrasen['dms_link/lvevaluierungStudierendeCMS']=''; //Beschreibung des Ab $this->phrasen['dms_link/lvevaluierungMitarbeiterCMS']=''; //Beschreibung des Ablaufs der LVEvaluierung für Mitarbeiter //Links auf externe Seiten -$this->phrasen['dms_link/dokuwikiGesamtnote']='http://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:gesamtnote'; //Link ins Dokuwiki zur Anleitung Gesamtnote -$this->phrasen['dms_link/abgabetoolLektorHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer LektorInnen -$this->phrasen['dms_link/abgabetoolStudentHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_studierende'; //Abgabetool Handbuch fuer Studierende -$this->phrasen['dms_link/abgabetoolAssistenzHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer Assistenz +$this->phrasen['dms_link/dokuwikiGesamtnote']='https://wiki.fhcomplete.org/doku.php?id=cis:gesamtnote'; //Link ins Dokuwiki zur Anleitung Gesamtnote +$this->phrasen['dms_link/abgabetoolLektorHandbuch']='https://wiki.fhcomplete.org/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer LektorInnen +$this->phrasen['dms_link/abgabetoolStudentHandbuch']='https://wiki.fhcompleteorg/doku.php?id=cis:abgabetool_fuer_studierende'; //Abgabetool Handbuch fuer Studierende +$this->phrasen['dms_link/abgabetoolAssistenzHandbuch']='https://wiki.fhcomplete.org/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer Assistenz ?> diff --git a/locale/en-US/dms_link.php b/locale/en-US/dms_link.php index 700a38f22..297feb2b4 100644 --- a/locale/en-US/dms_link.php +++ b/locale/en-US/dms_link.php @@ -27,8 +27,8 @@ $this->phrasen['dms_link/profilhilfe']=''; //Hilfe-Link aus dem Profil $this->phrasen['dms_link/anleitungMailverteiler']='7578'; //Anleitung für die Benutzung der Mailverteiler und der Berechtigungsschlüssel //Links auf externe Seiten -$this->phrasen['dms_link/dokuwikiGesamtnote']='http://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:gesamtnote'; //Link ins Dokuwiki zur Anleitung Gesamtnote -$this->phrasen['dms_link/abgabetoolLektorHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer LektorInnen -$this->phrasen['dms_link/abgabetoolStudentHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_studierende'; //Abgabetool Handbuch fuer Studierende -$this->phrasen['dms_link/abgabetoolAssistenzHandbuch']='https://fhcomplete.technikum-wien.at/dokuwiki/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer Assistenz +$this->phrasen['dms_link/dokuwikiGesamtnote']='https://wiki.fhcomplete.org/doku.php?id=cis:gesamtnote'; //Link ins Dokuwiki zur Anleitung Gesamtnote +$this->phrasen['dms_link/abgabetoolLektorHandbuch']='https://wiki.fhcomplete.org/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer LektorInnen +$this->phrasen['dms_link/abgabetoolStudentHandbuch']='https://wiki.fhcomplete.org/doku.php?id=cis:abgabetool_fuer_studierende'; //Abgabetool Handbuch fuer Studierende +$this->phrasen['dms_link/abgabetoolAssistenzHandbuch']='https://wiki.fhcomplete.org/doku.php?id=cis:abgabetool_fuer_lektoren'; //Abgabetool Handbuch fuer Assistenz ?> From 39f63c10df1926700703f1175e5ee3bfc6c9e3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 5 Sep 2019 15:51:51 +0200 Subject: [PATCH 126/500] =?UTF-8?q?Fehler=20behoben=20beim=20Speichern=20d?= =?UTF-8?q?er=20Sortierung=20im=20Studienplan=20=C3=BCber=20Vilesci=20GUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/studienplan.class.php | 6 +++--- soap/fhcomplete.php | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/studienplan.class.php b/include/studienplan.class.php index 741cefb43..2b751b2ed 100644 --- a/include/studienplan.class.php +++ b/include/studienplan.class.php @@ -902,7 +902,7 @@ class studienplan extends basis_db * @param type $tudienplan_lehrveranstaltung_id * @param type $sort */ - function saveSortierung($studienplan_lehrveranstaltung_id, $sort) + function saveSortierung($studienplan_lehrveranstaltung_id = null, $sort = null) { if($studienplan_lehrveranstaltung_id==NULL) $studienplan_lehrveranstaltung_id = $this->studienplan_lehrveranstaltung_id; @@ -1182,10 +1182,10 @@ class studienplan extends basis_db public.tbl_studiensemester ON (tbl_studienordnung.gueltigvon = tbl_studiensemester.studiensemester_kurzbz) WHERE 1=1"; - + if ($aktiv != '' && ($aktiv == true || $aktiv == false)) $qry.=" AND tbl_studienplan.aktiv=".$this->db_add_param($aktiv, FHC_BOOLEAN); - + if ($gueltigInStudiensemester != '') $qry.=" AND tbl_studienplan_semester.studiensemester_kurzbz=".$this->db_add_param($gueltigInStudiensemester); diff --git a/soap/fhcomplete.php b/soap/fhcomplete.php index 6811d3f4a..6013b9c78 100644 --- a/soap/fhcomplete.php +++ b/soap/fhcomplete.php @@ -1,22 +1,22 @@ */ @@ -48,7 +48,7 @@ for($i=0;$i<100;$i++) $parameter[]=null; else $parameter[]=$_REQUEST['parameter_'.$i]; - } + } else break; } @@ -69,12 +69,13 @@ if(!$wsrecht->isUserAuthorized($uid, $method, $class)) $obj = new $class(); $error=false; - // Bei Save Funktionen werden alle Parameter zugewiesen if(mb_stristr($method,'save')) { - - $loaddata=json_decode($_REQUEST['loaddata'], true); + if(isset($_REQUEST['loaddata'])) + $loaddata=json_decode($_REQUEST['loaddata'], true); + else + $loaddata=null; $savedata=json_decode($_REQUEST['savedata'], true); if(isset($loaddata['method'])) @@ -114,6 +115,7 @@ if(mb_stristr($method,'save')) } } } + $return = ''; if(!$error && ($return = call_user_func_array(array($obj, $method), $parameter))) { From 3f7615daaaa923849b76c1ab3bf5abaae6399f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Fri, 6 Sep 2019 14:50:37 +0200 Subject: [PATCH 127/500] =?UTF-8?q?Fehler=20behoben=20wodurch=20in=20der?= =?UTF-8?q?=20Verbandsansicht=20Gruppen=20des=20falschen=20Verbandes=20ang?= =?UTF-8?q?ezeigt=20wurden=20wenn=20eine=20direkte=20Gruppe=20hinzugef?= =?UTF-8?q?=C3=BCgt=20wird?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/lehrstunde.class.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/include/lehrstunde.class.php b/include/lehrstunde.class.php index dd821f3d8..26043bae6 100644 --- a/include/lehrstunde.class.php +++ b/include/lehrstunde.class.php @@ -437,9 +437,9 @@ class lehrstunde extends basis_db if ($type!='idList') { if($alle_unr_mitladen) - $sql_query_stdplan='SELECT '.$stpl_id.', datum, stunde, unr FROM '.$stpl_view; + $sql_query_stdplan='SELECT '.$stpl_id.', datum, stunde, unr FROM '.$stpl_view.' stplvw'; else - $sql_query_stdplan='SELECT * FROM '.$stpl_view; + $sql_query_stdplan='SELECT * FROM '.$stpl_view.' stplvw'; $sql_query_lva=""; $sql_query=" WHERE datum>=".$this->db_add_param($datum_von)." AND datum<".$this->db_add_param($datum_bis); if ($type == 'lva') @@ -506,6 +506,20 @@ class lehrstunde extends basis_db if ($grp!='0' && $grp!=null && $grp!='') $sql_query.=" AND (gruppe=".$this->db_add_param($grp)." OR gruppe IS NULL OR gruppe='0' OR gruppe='')"; + // Direkte Gruppen werden ausgenommen da sonst Stunden von Verband A in der Ansicht für Verband B + // mit angezeigt werden weil die direkte Gruppe geladen wird. + $sql_query.=' AND + ( + gruppe_kurzbz is null + OR + EXISTS( + SELECT 1 FROM public.tbl_gruppe + WHERE + gruppe_kurzbz = stplvw.gruppe_kurzbz + AND direktinskription=false + ) + )'; + $sql_query.=' )'; for ($i=0;$i<$num_rows_einheit;$i++) @@ -547,7 +561,7 @@ class lehrstunde extends basis_db $sql_query=mb_substr($sql_query,3); $sql_query_stdplan.=' WHERE'.$sql_query; } -//echo $sql_query_stdplan; + //Datenbankabfrage if (!$this->db_query($sql_query_stdplan)) { @@ -599,7 +613,7 @@ class lehrstunde extends basis_db if ($type!='idList' && $type!='fachbereich' && $type!='lva') { // Datenbankabfrage generieren - $sql_query_reservierung='SELECT * FROM campus.vw_reservierung'; + $sql_query_reservierung='SELECT * FROM campus.vw_reservierung stplvw'; $sql_query_reservierung.=$sql_query . $sql_query_orderby; //Datenbankabfrage From eea7912e9a77ff9a637126c8cc0f8635d71be714 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 6 Sep 2019 15:09:08 +0200 Subject: [PATCH 128/500] FAS gegendert --- content/dragboard.js.php | 4 +- content/fasoverlay.js.php | 28 +- content/fasoverlay.xul.php | 8 +- content/funktionen.xul.php | 2 +- content/lvplanung/lehrveranstaltungDBDML.php | 10 +- .../lehrveranstaltungnotenoverlay.xul.php | 8 +- .../lvplanung/lehrveranstaltungoverlay.js.php | 8 +- content/lvplanung/stpl-details-dialog.xul.php | 2 +- .../lvplanung/stpl-details-overlay.xul.php | 374 ++--- content/messages.xul.php | 8 +- content/mitarbeiter/mitarbeiterbuchung.js.php | 2 +- .../mitarbeiterdetailoverlay.xul.php | 602 ++++----- content/mitarbeiter/mitarbeiteroverlay.js.php | 4 +- .../mitarbeiter/mitarbeiteroverlay.xul.php | 590 ++++---- content/notiz.xml.php | 8 +- content/pdfExport.php | 2 +- content/planner.overlay.xul.php | 392 +++--- .../projekt/projekt_ressource.window.xul.php | 96 +- content/projekt/ressource.window.xul.php | 4 +- content/projekt/ressource.xml.php | 1202 ++++++++--------- .../interessentdokumenteoverlay.xul.php | 2 +- content/student/studentDBDML.php | 4 +- .../studentabschlusspruefungoverlay.xul.php | 12 +- content/student/studentdetailoverlay.xul.php | 8 +- content/student/studentenoverlay.xul.php | 6 +- content/student/studentnotenoverlay.xul.php | 6 +- content/student/studentoverlay.js.php | 20 +- content/student/studentprojektarbeit.js.php | 2 +- .../studentprojektarbeitoverlay.xul.php | 6 +- .../student/studentpruefungoverlay.xul.php | 6 +- content/student/studentrolledialog.xul.php | 12 +- content/tempus.js.php | 2 +- content/tempusoverlay.xul.php | 2 +- content/termine.js.php | 2 +- content/termine.xul.php | 2 +- locale/de-AT/fas.dtd | 636 ++++----- 36 files changed, 2041 insertions(+), 2041 deletions(-) diff --git a/content/dragboard.js.php b/content/dragboard.js.php index 18a8d6186..2a96e0cda 100644 --- a/content/dragboard.js.php +++ b/content/dragboard.js.php @@ -116,7 +116,7 @@ var studentDDObserver= uid = tree.view.getCellText(v,col); if(uid=='') { - alert('Es koennen nur Personen mit UID (Studenten/Mitarbeiter) verschoben werden'); + alert('Es koennen nur Personen mit UID (Studierende/Mitarbeitende) verschoben werden'); return false; } paramList += ';'+uid; @@ -295,7 +295,7 @@ var LektorFunktionDDObserver= if(stg=='') { - alert('Mitarbeiter kann nur auf einen Studiengang gezogen werden'); + alert('MitarbeiterIn kann nur auf einen Studiengang gezogen werden'); return false; } diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php index 0c80221e9..eb8daabcd 100644 --- a/content/fasoverlay.js.php +++ b/content/fasoverlay.js.php @@ -147,7 +147,7 @@ function LektorFunktionDel() idx = tree.currentIndex; else { - alert('Bitte zuerst einen Mitarbeiter markieren'); + alert('Bitte zuerst eine/n MitarbeiterIn markieren'); return false; } @@ -223,7 +223,7 @@ function LektorFunktionMail() } } if(anzfault!=0) - alert(anzfault+' Mitarbeiter konnten nicht hinzugefuegt werden weil keine UID eingetragen ist!'); + alert(anzfault+' MitarbeiterInnen konnten nicht hinzugefuegt werden weil keine UID eingetragen ist!'); if(mailempfaenger!='') window.location.href=mailempfaenger; } @@ -841,7 +841,7 @@ function StatistikPrintLVPlanung() if(tree.currentIndex==-1) { - alert('Bitte zuerst einen Mitarbeiter auswaehlen'); + alert('Bitte zuerst eine/n MitarbeiterIn auswaehlen'); return; } @@ -855,7 +855,7 @@ function StatistikPrintLVPlanung() if(typeof(url)!='undefined') window.open(url,'LV-Planung'); else - alert('Bitte waehlen sie ein(en) Verband, Institut oder Lektor aus'); + alert('Bitte waehlen sie ein(e/en) Verband, Institut oder LektorIn aus'); } // **** @@ -906,7 +906,7 @@ function StatistikPrintLVPlanungExcel() if(tree.currentIndex==-1) { - alert('Bitte zuerst einen Mitarbeiter auswaehlen'); + alert('Bitte zuerst eine/n MitarbeiterIn auswaehlen'); return; } @@ -920,7 +920,7 @@ function StatistikPrintLVPlanungExcel() if(typeof(url)!='undefined') window.open(url,'LV-Planung'); else - alert('Bitte waehlen sie ein(en) Verband, Institut oder Lektor aus'); + alert('Bitte waehlen sie einen Verband, Institut oder LektorIn aus'); } // **** @@ -1084,14 +1084,14 @@ function StatistikPrintNotenspiegelStudent() //Wenn nichts markiert wurde -> alle exportieren if(tree.currentIndex==-1) { - alert("Bitte zuerst einen Studenten markieren"); + alert("Bitte zuerst eine/n Studierende/n markieren"); return; } var student_uid = getTreeCellText(tree, 'student-treecol-uid', tree.currentIndex); if (student_uid == '') { - alert('Markierte Person ist kein Student'); + alert('Markierte Person ist kein/e StudentIn'); return; } window.open('index.ci.php/person/gradelist/index/'+student_uid,'Notenspiegel'); @@ -1843,7 +1843,7 @@ function PrintStudienblatt(event) } catch(e) { - check = confirm('Achtung: Beim letzten (aktuellen) PreStudent-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); + check = confirm('Achtung: Beim letzten (aktuellen) PreStudentInnen-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); if (check == false) return false; } @@ -1856,7 +1856,7 @@ function PrintStudienblatt(event) if(studienplan_id=='') { - check = confirm('Achtung: Beim letzten (aktuellen) PreStudent-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); + check = confirm('Achtung: Beim letzten (aktuellen) PreStudentInnen-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); if (check == false) return false; } @@ -1919,7 +1919,7 @@ function PrintStudienblatt(event) } else { - alert('Bitte zuerst einen Studenten auswaehlen'); + alert('Bitte zuerst eine/n Studierende/n auswaehlen'); } } @@ -1951,7 +1951,7 @@ function PrintStudienblattEnglisch(event) } catch(e) { - check = confirm('Achtung: Beim letzten (aktuellen) PreStudent-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); + check = confirm('Achtung: Beim letzten (aktuellen) PreStudentInnen-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); if (check == false) return false; } @@ -1965,7 +1965,7 @@ function PrintStudienblattEnglisch(event) if(studienplan_id=='') { - check = confirm('Achtung: Beim letzten (aktuellen) PreStudent-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); + check = confirm('Achtung: Beim letzten (aktuellen) PreStudentInnen-Status ist KEIN STUDIENPLAN eingetragen.\nDas Studienblatt ist moeglicherweise unvollstaendig.\nMoechten Sie es dennoch erstellen?'); if (check == false) return false; } @@ -2028,7 +2028,7 @@ function PrintStudienblattEnglisch(event) } else { - alert('Bitte zuerst einen Studenten auswaehlen'); + alert('Bitte zuerst eine/n Studierende/n auswaehlen'); } } diff --git a/content/fasoverlay.xul.php b/content/fasoverlay.xul.php index f62f2a1f2..5ce6c11cc 100644 --- a/content/fasoverlay.xul.php +++ b/content/fasoverlay.xul.php @@ -225,14 +225,14 @@ echo ' - - + + - - + + diff --git a/content/funktionen.xul.php b/content/funktionen.xul.php index 0f487370a..9bbe10686 100644 --- a/content/funktionen.xul.php +++ b/content/funktionen.xul.php @@ -101,7 +101,7 @@ else class="sortDirectionIndicator" sort="rdf:http://www.technikum-wien.at/bnfunktion/rdf#uid"/> - '; echo ''; echo ''; - echo ''; + if(getSprache()=='German') + { + echo ''; + } + else + { + echo ''; + } echo ''; $lvangebot->getAllFromLvId($row->lehrveranstaltung_id, $row->studiensemester_kurzbz); @@ -276,7 +283,7 @@ require_once('../../../include/benutzerberechtigung.class.php'); echo ''; echo ''; - + echo ''; echo ''; echo ''; echo ''; @@ -286,7 +293,14 @@ require_once('../../../include/benutzerberechtigung.class.php'); echo ''; echo ''; echo ''; - echo ''; + if(getSprache()=='German') + { + echo ''; + } + else + { + echo ''; + } echo ''; echo ''; echo ''; @@ -304,7 +318,7 @@ require_once('../../../include/benutzerberechtigung.class.php'); tbl_lehrveranstaltung.bezeichnung, tbl_projektarbeit.titel, (SELECT nachname || ' ' || vorname FROM public.tbl_benutzer JOIN public.tbl_person USING(person_id) WHERE uid=student_uid) as student, tbl_lehrveranstaltung.studiengang_kz, tbl_lehrveranstaltung.semester, - tbl_studiengang.email, tbl_betreuerart.beschreibung AS beutreuerart_beschreibung + tbl_studiengang.email, tbl_betreuerart.beschreibung AS beutreuerart_beschreibung, tbl_projektbetreuer.stunden FROM lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer, public.tbl_studiengang, lehre.tbl_betreuerart WHERE @@ -318,6 +332,7 @@ require_once('../../../include/benutzerberechtigung.class.php'); $stg_obj = new studiengang(); $stg_obj->getAll(null,null); + $summe_std = 0; if($result = $db->db_query($qry)) { @@ -329,6 +344,7 @@ require_once('../../../include/benutzerberechtigung.class.php'); echo ''; echo ''; echo ''; + echo ''; echo ''; echo ''; echo ''; @@ -339,13 +355,46 @@ require_once('../../../include/benutzerberechtigung.class.php'); echo ''; echo ''; echo ''; + if(getSprache()=='German') + { + echo ''; + } + else + { + echo ''; + } echo ''; echo ''; echo ''; echo ''; - echo ''; + $summe_std+=$row->stunden; } + echo ''; + echo ''; + echo ''; + if(!defined('CIS_LVALISTE_NOTENEINGABE_ANZEIGEN') || CIS_LVALISTE_NOTENEINGABE_ANZEIGEN) + { + echo ''; + } + if($lvinfo) + + echo ''; + + if(getSprache()=='German') + { + echo ''; + } + else + { + echo ''; + } + + + echo ''; + + echo ''; + echo '
    t('pruefung/derLektor'); ?>getFullName(FALSE); ?>
    t('pruefung/dieKommission'); ?>
    ".($e->aufnahmegruppe?"true.png":"false.png")."".$gruppe->countStudenten($e->gruppe_kurzbz)."PersonenPersonengruppe_kurzbz\">Editgruppe_kurzbz&searchItems=".implode(' ',$searchItems)."\">Editgruppe_kurzbz&studiengang_kz=$e->studiengang_kz&type=delete\" onclick='return conf_del()'>Delete
    '.$p->t("zeitaufzeichnung/projekt").'
    '.$p->t("zeitaufzeichnung/organisationseinheiten").'     '; - if($za_simple == 0) - { - //OE_KURZBZ_2 - echo ''; - } - echo '
    '.$p->t("zeitaufzeichnung/aktivitaet").''; @@ -939,49 +855,139 @@ if($projekt->getProjekteMitarbeiter($user, true)) } echo '
    '.$p->t("zeitaufzeichnung/organisationseinheiten").'     '; + if($za_simple == 0) + { + //OE_KURZBZ_2 + echo ''; + } + echo '
    '.$p->t("zeitaufzeichnung/projekt").'
    '.$p->t('zeitaufzeichnung/service').'
    '.$p->t('zeitaufzeichnung/service').'
    '.$p->t("zeitaufzeichnung/kunde").' '.$p->t("zeitaufzeichnung/oderKartennummerOptional").' +
    '.$p->t("zeitaufzeichnung/kunde").' '.$p->t("zeitaufzeichnung/oderKartennummerOptional").' -
     
     
    - + @@ -362,7 +362,7 @@ echo ''; - + @@ -486,7 +486,7 @@ echo ''; - @@ -523,7 +523,7 @@ echo ''; class="sortDirectionIndicator" sort="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#orgform_kurzbz" /> - + '; - -
    '.$row->raumtypalternativ.''.$row->stundenblockung.''.$row->wochenrythmus.''.$row->semesterstunden.''.number_format($row->semesterstunden,2,$dec_point=",",$thousands_sep=".").''.number_format($row->semesterstunden,2,$dec_point=".",$thousands_sep=",").''.$row->start_kw.'        '.$p->t('lvaliste/summe').''.number_format($summe_std,2).''.number_format($summe_std,2,$dec_point=",",$thousands_sep=".").''.number_format($summe_std,2,$dec_point=".",$thousands_sep=",").' 
    '.$p->t('lvaliste/studiengang').''.$p->t('lvaliste/semester').''.$p->t('lvaliste/stunden').''.$p->t('lvaliste/lvBezeichnung').''.$p->t('lvaliste/student').''.$p->t('lvaliste/betreuungsart').'
    '.$stg_obj->kuerzel_arr[$row->studiengang_kz].''.$row->semester.''.number_format($row->stunden,2,$dec_point =",", $thousands_sep ="."). ''.number_format($row->stunden,2,$dec_point =".", $thousands_sep =","). ''.$row->bezeichnung.''.$row->student.''.$row->beutreuerart_beschreibung.''.$row->titel.'
     '.$p->t('lvaliste/summe').''.number_format($summe_std,2,$dec_point=",",$thousands_sep=".").''.number_format($summe_std,2,$dec_point=".",$thousands_sep=",").' 
    '; } } @@ -426,6 +475,7 @@ require_once('../../../include/benutzerberechtigung.class.php'); echo '
    '.$stg_obj->kuerzel_arr[$row->studiengang_kz].''.$row->semester.''.$row->stunden.''.$row->fachbereich_kurzbz.''.$row->bezeichnung.''.$lektoren.''.$db->convert_html_chars($pers_uid).''.$db->convert_html_chars($beschreibung).' Delete
    '; echo ''; - - //Wenn die Sprachwahl fuer den priorisierten Studiengang aktiviert ist, dann die Sprachen anzeigen - if($sprachwahl==true) - { - //Liste der Sprachen, die in den Gebieten vorkommen koennen - $qry = "SELECT distinct sprache - FROM - testtool.tbl_pruefling - JOIN testtool.tbl_ablauf USING(studiengang_kz) - JOIN testtool.tbl_frage USING(gebiet_id) - JOIN testtool.tbl_frage_sprache USING(frage_id) - WHERE - tbl_pruefling.pruefling_id=".$db->db_add_param($pruefling->pruefling_id)." - ORDER BY sprache DESC"; - - if($result = $db->db_query($qry)) - { - echo ' -

    '. $p->t('testtool/spracheDerTestfragen').':


    -
    - '; - - while($row = $db->db_fetch_object($result)) - { - $selected = ($_SESSION['sprache'] == $row->sprache) ? 'active' : ''; - $row_sprache = $row->sprache; - if ($sprache_user == 'German') - { - if($row->sprache == 'English') - { - $row_sprache = 'Englisch'; - } - elseif ($row->sprache == 'German') - { - $row_sprache = 'Deutsch'; - } - } - echo " - - "; - } - echo '
    '; - } - } - echo '

    '; echo '
    @@ -594,22 +545,45 @@ if (isset($prestudent_id)) if($pruefling->pruefling_id!='') { $_SESSION['pruefling_id']=$pruefling->pruefling_id; - //echo ''; } } else { echo ''.$p->t('testtool/keinPrueflingseintragVorhanden').''; } + echo '
    '; } -else +else // LOGIN Site (vor Login) { - //LOGIN FORM (Startseite vor Login) $prestudent_id_dummy_student = (defined('PRESTUDENT_ID_DUMMY_STUDENT')?PRESTUDENT_ID_DUMMY_STUDENT:''); + echo '
    '; - echo '
    - '; + echo '\n'; foreach($ps->result as $prestd) { $stg = new studiengang(); @@ -618,7 +592,8 @@ else $selected = 'selected'; else $selected=''; - echo '\n'; + echo ' + \n'; } // An der FHTW gibt es 3 Testuser für den Camus International if (CAMPUS_NAME == 'FH Technikum Wien') @@ -628,19 +603,26 @@ else echo '\n'; } echo ''; - echo '  '.$p->t('global/geburtsdatum').': '; - echo ''; - echo ''; - echo '
    '; + echo '
    '; // end col-xs + echo ''; // end form-group - echo '


    -
    - '.$p->t('testtool/willkommenstextTitel').'

    - '.$p->t('testtool/willkommenstext').' -
    '; + // Datepicker input + echo '
    '; + echo ''; + echo '
    '; + echo ''; + echo '
    '; // end col-xs + echo '
    '; // end form-group + + // Login button + echo ''; + + echo ''; // end form + + echo ''; // end row + echo ''; // end col-xs-11 } ?> - diff --git a/cis/testtool/menu.php b/cis/testtool/menu.php index 7fcf93764..d71f1e685 100644 --- a/cis/testtool/menu.php +++ b/cis/testtool/menu.php @@ -19,6 +19,7 @@ * Andreas Oesterreicher , * Rudolf Hangl , * Manfred Kindl + * Cristina Hainberger */ require_once('../../config/cis.config.inc.php'); @@ -27,56 +28,25 @@ require_once('../../include/basis_db.class.php'); require_once('../../include/sprache.class.php'); require_once '../../include/phrasen.class.php'; require_once '../../include/studiengang.class.php'; +require_once('../../include/gebiet.class.php'); if (!$db = new basis_db()) die('Fehler beim Oeffnen der Datenbankverbindung'); -require_once('../../include/gebiet.class.php'); - -function getSpracheUser() -{ - if(isset($_SESSION['sprache_user'])) - { - $sprache_user=$_SESSION['sprache_user']; - } - else - { - if(isset($_COOKIE['sprache_user'])) - { - $sprache_user=$_COOKIE['sprache_user']; - } - else - { - $sprache_user=DEFAULT_LANGUAGE; - } - setSpracheUser($sprache_user); - } - return $sprache_user; -} - -function setSpracheUser($sprache) -{ - $_SESSION['sprache_user']=$sprache; - setcookie('sprache_user',$sprache,time()+60*60*24*30,'/'); -} - -if(isset($_GET['sprache_user'])) -{ - $sprache_user = new sprache(); - if($sprache_user->load($_GET['sprache_user'])) - { - setSpracheUser($_GET['sprache_user']); - } - else - setSpracheUser(DEFAULT_LANGUAGE); -} - -$sprache_user = getSpracheUser(); -$p = new phrasen($sprache_user); -$sprache = getSprache(); - +// Start session session_start(); +// If language is changed by language select menu, reset language and session variables +if(isset($_GET['sprache_user']) && !empty($_GET['sprache_user'])) +{ + $sprache_user = $_GET['sprache_user']; + $_SESSION['sprache_user'] = $_GET['sprache_user']; +} + +// Set language variable, which impacts the navigation menu +$sprache_user = (isset($_SESSION['sprache_user']) && !empty($_SESSION['sprache_user'])) ? $_SESSION['sprache_user'] : DEFAULT_LANGUAGE; +$p = new phrasen($sprache_user); + ?> @@ -89,6 +59,9 @@ session_start(); - '.$p->t('testtool/einleitung').' + '.$p->t('testtool/einleitung').' '; } @@ -296,8 +269,6 @@ if (isset($_SESSION['pruefling_id'])) $result = $db->db_query($qry); $lastsemester = ''; $quereinsteiger_stg = ''; - $gebiet_hasMathML = false; // true, wenn irgendein Gebiet eine/n Frage/Vorschlag im MathML-Format enthält - $invalid_gebiete = false; while($row = $db->db_fetch_object($result)) { //Jedes Semester in einer eigenen Tabelle anzeigen @@ -404,7 +375,7 @@ if (isset($_SESSION['pruefling_id'])) // Link zum Logout echo ' - Logout + Logout '; echo ''; diff --git a/cis/testtool/topbar.php b/cis/testtool/topbar.php index c4ca24357..8fd10a3f0 100644 --- a/cis/testtool/topbar.php +++ b/cis/testtool/topbar.php @@ -16,57 +16,33 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Manfred Kindl . + * Cristina Hainberger */ require_once('../../config/cis.config.inc.php'); require_once('../../include/basis_db.class.php'); require_once('../../include/sprache.class.php'); require_once '../../include/phrasen.class.php'; +require_once('../../include/gebiet.class.php'); if (!$db = new basis_db()) die('Fehler beim Oeffnen der Datenbankverbindung'); - -require_once('../../include/gebiet.class.php'); - -function getSpracheUser() + +// Start session +session_start(); + +// If language is changed by language select menu, reset session- and language variable +if (isset($_GET['sprache_user']) && !empty($_GET['sprache_user'])) { - if(isset($_SESSION['sprache_user'])) - { - $sprache_user=$_SESSION['sprache_user']; - } - else - { - if(isset($_COOKIE['sprache_user'])) - { - $sprache_user=$_COOKIE['sprache_user']; - } - else - { - $sprache_user=DEFAULT_LANGUAGE; - } - setSpracheUser($sprache_user); - } - return $sprache_user; + $_SESSION['sprache_user'] = $_GET['sprache_user']; + $sprache_user = $_GET['sprache_user']; } -function setSpracheUser($sprache) -{ - $_SESSION['sprache_user']=$sprache; - setcookie('sprache_user',$sprache,time()+60*60*24*30,'/'); -} +// Set language variable, which impacts the language displayed in the language select menu +$sprache_user = (isset($_SESSION['sprache_user']) && !empty($_SESSION['sprache_user'])) ? $_SESSION['sprache_user'] : DEFAULT_LANGUAGE; -if(isset($_GET['sprache_user'])) -{ - $sprache_user = new sprache(); - if($sprache_user->load($_GET['sprache_user'])) - { - setSpracheUser($_GET['sprache_user']); - } - else - setSpracheUser(DEFAULT_LANGUAGE); -} - -$sprache_user = getSpracheUser(); +// The language select menu is only displayed if RT-Ablauf of STG allows to switch language +$display = (isset($_SESSION['sprache_auswahl']) && $_SESSION['sprache_auswahl'] == true) ? '' : 'hidden'; $p = new phrasen($sprache_user); ?> @@ -85,16 +61,15 @@ $p = new phrasen($sprache_user); @@ -104,15 +79,17 @@ echo ' -
    + + +
    - @@ -140,4 +117,3 @@ echo ' ja'; + echo 'nein'; + echo '


    '; + } + else + { + $zustimmung = ($gd->selbstverwaltete_pause) ? ' erteilt' : 'abgelehnt'; + echo '

    Zustimmung für '.$current_ss.': '.$zustimmung.' am '.$datum_obj->formatDatum($gd->insertamum,'d.m.Y H:i:s').'

    '; + } + $gd = new zeitaufzeichnung_gd(); $gd->load($uid, $next_ss); if ( ! $gd->uid ) { - echo '

    Zustimmung für '.$next_ss.': '; + echo '

    Zustimmung für '.$next_ss.': '; echo 'ja'; echo 'nein'; echo '




    '; @@ -202,7 +237,7 @@ if (isset($_GET['selbstverwaltete-pause']) && !empty($_GET['submit'])) else { $zustimmung = ($gd->selbstverwaltete_pause) ? ' erteilt' : 'abgelehnt'; - echo '

    Zustimmung für '.$next_ss.': '.$zustimmung.' am '.$datum_obj->formatDatum($gd->insertamum,'d.m.Y H:i:s').'

    '; + echo '

    Zustimmung für '.$next_ss.': '.$zustimmung.' am '.$datum_obj->formatDatum($gd->insertamum,'d.m.Y H:i:s').'

    '; } //var_dump($gd); ?> From 5150c1fc44fbdb21b2161f8f4fca0508daf2ef60 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 12 Sep 2019 10:41:40 +0200 Subject: [PATCH 145/500] Removed DBSkel changes from master branch --- application/config/dbskel.php | 27 - application/controllers/system/DBSkel.php | 26 - application/dbskel/fue/TBL_aktivitaet.php | 27 - application/dbskel/fue/constraints.php | 8 - application/dbskel/fue/extra.sql | 1 - application/dbskel/fue/functions.php | 19 - application/dbskel/fue/grants.sql | 20 - application/dbskel/fue/schema.sql | 4 - application/dbskel/fue/sequences.php | 11 - application/dbskel/fue/views.php | 50 - application/dbskel/index.html | 11 - application/libraries/DBSkelLib.php | 1251 --------------------- 12 files changed, 1455 deletions(-) delete mode 100644 application/config/dbskel.php delete mode 100644 application/controllers/system/DBSkel.php delete mode 100644 application/dbskel/fue/TBL_aktivitaet.php delete mode 100644 application/dbskel/fue/constraints.php delete mode 100644 application/dbskel/fue/extra.sql delete mode 100644 application/dbskel/fue/functions.php delete mode 100644 application/dbskel/fue/grants.sql delete mode 100644 application/dbskel/fue/schema.sql delete mode 100644 application/dbskel/fue/sequences.php delete mode 100644 application/dbskel/fue/views.php delete mode 100644 application/dbskel/index.html delete mode 100644 application/libraries/DBSkelLib.php diff --git a/application/config/dbskel.php b/application/config/dbskel.php deleted file mode 100644 index dafdc0d31..000000000 --- a/application/config/dbskel.php +++ /dev/null @@ -1,27 +0,0 @@ -load->library('DBSkelLib'); - } - - /** - * Starts the DBSkel procedure - */ - public function start($step = null, $selectedDirectories = null) - { - // If the DBSkel procedure fails then exit with an error - // In this way it's possible to undestand from console what is the exit status of the procedure - $this->dbskellib->start($step, $selectedDirectories) === true ? exit(0) : exit(1); - } -} diff --git a/application/dbskel/fue/TBL_aktivitaet.php b/application/dbskel/fue/TBL_aktivitaet.php deleted file mode 100644 index 05027ba92..000000000 --- a/application/dbskel/fue/TBL_aktivitaet.php +++ /dev/null @@ -1,27 +0,0 @@ - array( - 'aktivitaet_kurzbz' => array( - 'comment' => 'I guess this is the PK', - 'type' => 'character varying(16)', - 'null' => false - ), - 'beschreibung' => array( - 'comment' => 'none', - 'type' => 'character varying(256)', - 'null' => false, - 'default' => "'Test string'" - ), - 'sort' => array( - 'comment' => 'nope', - 'type' => 'integer', - 'default' => 1 - ), - 'oe_kurzbz' => array( - 'comment' => 'uhm', - 'type' => 'character varying(32)' - ) - ), - 'comment' => 'Timesheet SLA Activity' -); diff --git a/application/dbskel/fue/constraints.php b/application/dbskel/fue/constraints.php deleted file mode 100644 index a3e534cf1..000000000 --- a/application/dbskel/fue/constraints.php +++ /dev/null @@ -1,8 +0,0 @@ - 'ALTER TABLE fue.tbl_aktivitaet ADD CONSTRAINT pk_tbl_aktivitaet PRIMARY KEY (aktivitaet_kurzbz)', - 'fk_projekt_oe' => 'ALTER TABLE fue.tbl_aktivitaet ADD CONSTRAINT fk_test FOREIGN KEY (oe_kurzbz) REFERENCES public.tbl_organisationseinheit (oe_kurzbz)', - 'uk_beschreibung' => 'ALTER TABLE fue.tbl_aktivitaet ADD CONSTRAINT uk_beschreibung UNIQUE (beschreibung)', - 'testchk' => 'ALTER TABLE fue.tbl_aktivitaet ADD CONSTRAINT testchk CHECK (sort > 0)' -); diff --git a/application/dbskel/fue/extra.sql b/application/dbskel/fue/extra.sql deleted file mode 100644 index 3d826b40f..000000000 --- a/application/dbskel/fue/extra.sql +++ /dev/null @@ -1 +0,0 @@ -SELECT 'Extra file' AS justatest; diff --git a/application/dbskel/fue/functions.php b/application/dbskel/fue/functions.php deleted file mode 100644 index f3dab4498..000000000 --- a/application/dbskel/fue/functions.php +++ /dev/null @@ -1,19 +0,0 @@ - - 'CREATE OR REPLACE FUNCTION fue.get_highest_content_version(bigint) RETURNS smallint AS $$ - DECLARE i_content_id ALIAS FOR $1; - DECLARE rec RECORD; - BEGIN - - SELECT INTO rec version - FROM campus.tbl_contentsprache - WHERE content_id = i_content_id - ORDER BY version desc - LIMIT 1; - - RETURN rec.version; - END; - $$ LANGUAGE plpgsql;' -); diff --git a/application/dbskel/fue/grants.sql b/application/dbskel/fue/grants.sql deleted file mode 100644 index cdc8c9c95..000000000 --- a/application/dbskel/fue/grants.sql +++ /dev/null @@ -1,20 +0,0 @@ ------------------------------------------------------ --- Revokes all privileges from all granted users ------------------------------------------------------ -REVOKE ALL PRIVILEGES ON SCHEMA fue FROM vilesci; -REVOKE ALL ON ALL TABLES IN SCHEMA fue FROM vilesci; -REVOKE ALL ON ALL SEQUENCES IN SCHEMA fue FROM vilesci; -REVOKE ALL ON ALL FUNCTIONS IN SCHEMA fue FROM vilesci; - ----------------------------------------------------------------------------------------------------- --- Gives the desired privileges to the chosen users (with great power comes great responsibility!) ----------------------------------------------------------------------------------------------------- - --- Schema privileges -GRANT ALL ON SCHEMA fue TO vilesci; -GRANT USAGE ON SCHEMA fue TO web; -GRANT USAGE ON SCHEMA fue TO wawi; - --- Sequences privileges -GRANT SELECT,UPDATE ON SEQUENCE fue.seq_projekt_dokument_projekt_dokument_id TO vilesci; -GRANT SELECT,UPDATE ON SEQUENCE fue.seq_projekt_dokument_projekt_dokument_id TO web; diff --git a/application/dbskel/fue/schema.sql b/application/dbskel/fue/schema.sql deleted file mode 100644 index 1dc28d796..000000000 --- a/application/dbskel/fue/schema.sql +++ /dev/null @@ -1,4 +0,0 @@ --- Create the schema if not exists -CREATE SCHEMA IF NOT EXISTS fue; --- Comment schema -COMMENT ON SCHEMA fue IS 'Projectmanagement'; diff --git a/application/dbskel/fue/sequences.php b/application/dbskel/fue/sequences.php deleted file mode 100644 index 98a1ca60b..000000000 --- a/application/dbskel/fue/sequences.php +++ /dev/null @@ -1,11 +0,0 @@ - - 'CREATE SEQUENCE fue.seq_projekt_dokument_projekt_dokument_id - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1;' -); diff --git a/application/dbskel/fue/views.php b/application/dbskel/fue/views.php deleted file mode 100644 index 69b911714..000000000 --- a/application/dbskel/fue/views.php +++ /dev/null @@ -1,50 +0,0 @@ - - 'CREATE OR REPLACE VIEW fue.vw_projektressourcen ( - projekt_ressource_id, - projekt_kurzbz, - projektphase_id, - projektphase, - typ, - ressource_id, - ressource, - funktion_kurzbz, - start, - ende, - oe_kurzbz, - projektbudget, - aufwandstyp_kurzbz, - projektphase_fk, - phasenbudget, - personentage, - nummer, - titel, - aufwand - ) - AS - SELECT tpr.projekt_ressource_id, - COALESCE(tpr.projekt_kurzbz, tpp.projekt_kurzbz) AS projekt_kurzbz, - tpr.projektphase_id, - tpp.bezeichnung AS projektphase, - COALESCE(tpp.typ, \'Projekt\'::character varying) AS typ, - tpr.ressource_id, - tr.bezeichnung AS ressource, - tpr.funktion_kurzbz, - COALESCE(tpp.start, tp.beginn) AS start, - COALESCE(tpp.ende, tp.ende) AS ende, - tp.oe_kurzbz, - tp.budget AS projektbudget, - tp.aufwandstyp_kurzbz, - tpp.projektphase_fk, - tpp.budget AS phasenbudget, - tpp.personentage, - tp.nummer, - tp.titel, - tpr.aufwand - FROM fue.tbl_projekt_ressource tpr - JOIN fue.tbl_ressource tr USING (ressource_id) - LEFT JOIN fue.tbl_projekt tp USING (projekt_kurzbz) - LEFT JOIN fue.tbl_projektphase tpp USING (projektphase_id);' -); diff --git a/application/dbskel/index.html b/application/dbskel/index.html deleted file mode 100644 index b702fbc39..000000000 --- a/application/dbskel/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - - diff --git a/application/libraries/DBSkelLib.php b/application/libraries/DBSkelLib.php deleted file mode 100644 index 1d556d9a4..000000000 --- a/application/libraries/DBSkelLib.php +++ /dev/null @@ -1,1251 +0,0 @@ -_ci =& get_instance(); // get code igniter instance - - // Loads DB conns and confs using system settings - $this->_ci->load->database('system'); - - // Loads dbskel configs - $this->_ci->config->load('dbskel'); - - // Loads library EPrintfLib - $this->_ci->load->library('EPrintfLib'); - } - - //------------------------------------------------------------------------------------------------------------------ - // Public methods - - /** - * Starts the DBSkel procedure - * Returns false on failure and true on success - * All errors/warnings/infos are printed here using EPrintfLib - * Accept the step parameter that can be used to run only a wanted step - */ - public function start($steps, $selectedDirectories) - { - $start = false; - - // Checks if DBSkel is enabled - if ($this->_ci->config->item(self::CONF_ENABLED) === true) - { - // Checks if the given steps parameter is fine - if ($this->_checkParameterStep($steps)) - { - $this->_printSchemaSeparator(); - - $this->_printRunningMode(); - - // By default perform all steps - $stepsArray = range(1, self::MAX_STEPS); - // If steps parameter is given then use it to select the steps to be performed - if ($steps != null) $stepsArray = explode(self::SEPARATOR, $steps); - - // Gets all the directories in application/dbskel - $directories = glob(self::DBSKEL_DIR.'*', GLOB_ONLYDIR); - - // Checks if the selectedDirectories parameter is fine - if ($this->_checkParameterSelectedDirectories($selectedDirectories, $directories)) - { - $start = $this->_processDirectories($directories, $stepsArray); - - $this->_printSchemaSeparator(); - } - } - } - else - { - $this->_printInfo('DBSkel is NOT enabled'); - } - - return $start; - } - - //------------------------------------------------------------------------------------------------------------------ - // Private methods - - /** - * Process every single directory present in dbskel directory - */ - private function _processDirectories($directories, $stepsArray) - { - $processDirectories = false; // failure by default - - // For each directory - foreach ($directories as $directory) - { - $processDirectories = false; // Reset to false at the beginning of each loop - - $this->_printSchemaSeparator(); - $this->_printInfo('Found directory >>> '.basename($directory).' <<<'); - - // NOTE: the order in which these methods are called has a meaning! - // If a step fails then the loop is stopped - - // 0 - Checks file naming convention in current directory - // NOTE: no need to check a failure! NOT a blocking check!! Always performed!!! - $this->_checkFilenaming($directory); - - $this->_printFileSeparator(); - - // 1 - Process schema file - if (in_array(self::STEP_SCHEMA, $stepsArray)) - { - if (!$this->_processSchemaFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 2 - Process sequence file - if (in_array(self::STEP_SEQUENCES, $stepsArray)) - { - if (!$this->_processSequencesFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 3 - Process table files - if (in_array(self::STEP_TABLES, $stepsArray)) - { - if (!$this->_processTableFiles($directory)) break; - - $this->_printFileSeparator(); - } - - // 4 - Process constraints - if (in_array(self::STEP_CONSTRAINTS, $stepsArray)) - { - if (!$this->_processConstraintsFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 5 - Process views file - if (in_array(self::STEP_VIEWS, $stepsArray)) - { - if (!$this->_processViewsFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 6 - Process functions file - if (in_array(self::STEP_FUNCTIONS, $stepsArray)) - { - if (!$this->_processFunctionsFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 7 - Process grants file - if (in_array(self::STEP_GRANTS, $stepsArray)) - { - if (!$this->_processGrantsFile($directory)) break; - - $this->_printFileSeparator(); - } - - // 8 - Process extra file - if (in_array(self::STEP_EXTRA, $stepsArray)) - { - if (!$this->_processExtraFile($directory)) break; - } - - $processDirectories = true; // If all the steps ends successfully - - $this->_printSchemaSeparator(); - } - - return $processDirectories; - } - - /** - * Checks file names are compliant with the file naming convention - */ - private function _checkFilenaming($directory) - { - $files = array_filter(glob($directory.'/*'), 'is_file'); - - // For each file - foreach ($files as $file) - { - $fileName = basename($file); // File name - // If the file name is NOT compliant with the file naming convention - if (!$this->_isFilenameValid($fileName)) - { - $this->_printInfo('Not valid file name, it is going to be ignored: '.$fileName); - } - } - } - - /** - * Checks if the file name is compliant with the file naming convention - */ - private function _isFilenameValid($fileName) - { - return $fileName == self::SCHEMA_FILENAME // Schema file - || $fileName == self::SEQUENCES_FILENAME // Sequences file - || (substr($fileName, 0, strlen(self::TABLE_PREFIX)) == self::TABLE_PREFIX - && substr($fileName, -4, strlen(self::PHP_EXT)) == self::PHP_EXT) // Table files - || $fileName == self::CONSTRAINTS_FILENAME // Constraints file - || $fileName == self::VIEWS_FILENAME // Views file - || $fileName == self::FUNCTIONS_FILENAME // Function file - || $fileName == self::GRANTS_FILENAME // Grants file - || $fileName == self::EXTRA_FILENAME; // Extra file - } - - /** - * Process the schema file - */ - private function _processSchemaFile($directory) - { - // Looks for a schema file - $files = array_filter(glob($directory.'/'.self::SCHEMA_FILENAME), 'is_file'); - - // If a schema file is found... - if (count($files) > 0) - { - $this->_printMessage('Found schema file: '.$files[0]); - - //...process it! - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> would be executed in new and diff mode'); - } - else // new or diff mode - { - return $this->_execSQLFile($files[0]); - } - } - else - { - $this->_printMessage('No schema file found'); - } - - return true; // If no files are found then go forward -> is a success - } - - /** - * Process sequences file - * - Looks for sequences present in current schema, then sequences that are NOT present in php file are dropped (diff mode only) - * - Looks for sequences present in php files, then sequences that are NOT present in database are installed - */ - private function _processSequencesFile($directory) - { - // Looks for a sequences file - $files = array_filter(glob($directory.'/'.self::SEQUENCES_FILENAME), 'is_file'); - - // If a sequences file is found... - if (count($files) > 0) - { - $this->_printMessage('Found sequences file: '.$files[0]); - - //...process it! - require_once($files[0]); // Read sequences file - $schema = basename($directory); // retrieves schema name from directory path - $dbSequencesArray = $this->_listSequencesBySchema($schema); // get list of sequences currently present in DB schema - - // Loops through list of sequences currently present in database - foreach ($dbSequencesArray as $dbSequence) - { - // If NOT in new mode and if the sequence present in database is NOT present in the list of sequences from php file - if (!$this->_isNewMode() && !array_key_exists($dbSequence, $sequencesArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> sequence '.$dbSequence.' NOT found in sequences file >> would be removed in diff mode'); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then drop it and objects that depends on it from database! If it fails then ends execution - if (!$this->_execQuery(sprintf('DROP SEQUENCE %s.%s CASCADE', $schema, $dbSequence))) - { - $this->_printError('Error occurred while dropping sequence: '.$dbSequence); - return false; - } - else - { - $this->_printMessage('Sequence dropped successfully: '.$dbSequence); - } - } - } - } - - // Loops through list of sequences from php file - foreach ($sequencesArray as $sequenceName => $sequenceSQL) - { - // If the sequence from php file is NOT present in database - if (!in_array($sequenceName, $dbSequencesArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> sequence '.$sequenceName.' NOT found database >> would be added in new and diff mode'); - } - else - { - // Then install it! If it fails then ends execution - if (!$this->_execQuery($sequenceSQL)) - { - $this->_printError('Error occurred while adding sequence: '.$sequenceName); - return false; - } - else - { - $this->_printMessage('Sequence added successfully: '.$sequenceName); - } - } - } - else - { - $this->_printMessage('Sequence already present in database: '.$sequenceName); - } - } - } - else - { - $this->_printMessage('No sequences file found'); - } - - return true; // If ends of procedure with no failures or no files are found then is a success - } - - /** - * Process table files - */ - private function _processTableFiles($directory) - { - // Looks for table files - $files = array_filter(glob($directory.'/'.self::TABLE_PREFIX.'*'.self::PHP_EXT), 'is_file'); - - // If table files are found... - if (count($files) > 0) - { - //...process them! - $schema = basename($directory); // retrieves schema name from directory path - $dbTablesArray = $this->_listTablesBySchema($schema); // get list of tables currently present in DB schema - - // For each table file - foreach ($files as $file) - { - $this->_printMessage('Found table file: '.$file); - - require_once($file); // Read table file - - // Loops through list of tables currently present in database - foreach ($dbTablesArray as $dbTable) - { - // If NOT in new mode and if the table present in database is NOT present in the php table file - if (!$this->_isNewMode() && !array_key_exists($dbTable, $tableArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> table '.$dbTable.' NOT found in table file >> would be removed in diff mode'); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then drop it! If it fails then ends execution - if (!$this->_execQuery(sprintf('DROP TABLE %s.%s', $schema, $dbTable))) - { - $this->_printError('Error occurred while dropping table: '.$dbTable); - return false; - } - else - { - $this->_printMessage('Table dropped successfully: '.$dbTable); - } - } - } - } - - // Retrieves all the elements from the $tableArray except the element 'comment' - $tableElements = array_keys(array_diff_key($tableArray, array(self::T_COMMENT => null))); - if (is_array($tableElements) && count($tableElements) == 1) // If there is only one element left... - { - $tableName = $tableElements[0]; // ...then it is the name of the table - - // If the table from php file is NOT present in database - if (!in_array($tableName, $dbTablesArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> table '.$tableName.' would be created in new and diff mode'); - } - else // new and diff mode - { - // Then create the new table! If it fails then ends execution - if ($this->_createTable($schema, $tableArray)) - { - $this->_printMessage('Table created successfully: '.$tableName); - } - else - { - $this->_printError('Error occurred while creating a new table: '.$tableName); - return false; - } - } - } - else // if table is already present in database - { - $this->_printMessage('Table already present in database: '.$tableName); - - // Manage the differences between the table present in database and the one present in php file - return $this->_manageTableColumns($schema, $tableArray); - } - } - else // otherwise the array present in the php table file is not well formatted - { - $this->_printError('Table file with a bad format is going to be ignored: '.$file); - } - } - } - else - { - $this->_printMessage('No table files found'); - } - - return true; // If no files are found then go forward -> is a success - } - - /** - * Process constraints file - * - Looks for constraints present in current schema, then constraints that are NOT present in php file are dropped (diff mode only) - * - Looks for constraints present in php files, then constraints that are NOT present in database are installed - */ - private function _processConstraintsFile($directory) - { - // Looks for a constraints file - $files = array_filter(glob($directory.'/'.self::CONSTRAINTS_FILENAME), 'is_file'); - - // If a constraints file is found... - if (count($files) > 0) - { - $this->_printMessage('Found constraints file: '.$files[0]); - - //...process it! - require_once($files[0]); // Read constraints file - $schema = basename($directory); // retrieves schema name from directory path - $dbConstraintsArray = $this->_listConstraintsBySchema($schema); // get list of constraints currently present in DB schema - $dbConstraintsNamesArray = array(); // Contains only the names of the constraints - - // Loops through list of constraints currently present in database - foreach ($dbConstraintsArray as $dbConstraint) - { - $dbConstraintsNamesArray[] = $dbConstraint['name']; // Copy only the name of the constraint - - // If NOT in new mode and if the constraint present in database is NOT present in the list of constraints from php file - if (!$this->_isNewMode() && !array_key_exists($dbConstraint['name'], $constraintsArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> constraint '.$dbConstraint['name'].' NOT found in constraints file >> would be removed in diff mode'); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then drop it and objects that depends on it from database! If it fails then ends execution - if (!$this->_execQuery(sprintf('ALTER TABLE %s.%s DROP CONSTRAINT %s', $schema, $dbConstraint['table'], $dbConstraint['name']))) - { - $this->_printError('Error occurred while dropping constraint: '.$dbConstraint['name']); - return false; - } - else - { - $this->_printMessage('Constraint dropped successfully: '.$dbConstraint['name']); - } - } - } - } - - // Loops through list of constraints from php file - foreach ($constraintsArray as $constraintName => $constraintSQL) - { - // If the constraint from php file is NOT present in database - if (!in_array($constraintName, $dbConstraintsNamesArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> constraint '.$constraintName.' would be added in new and diff mode'); - } - else - { - // Then install it! If it fails then ends execution - if (!$this->_execQuery($constraintSQL)) - { - $this->_printError('Error occurred while adding constraint: '.$constraintName); - return false; - } - else - { - $this->_printMessage('Constraint added successfully: '.$constraintName); - } - } - } - else - { - $this->_printMessage('Constraint already present in database: '.$constraintName); - } - } - } - else - { - $this->_printMessage('No constraints file found'); - } - - return true; // If ends of procedure with no failures or no files are found then is a success - } - - /** - * Process views file - * - Looks for views present in current schema, then views that are NOT present in php file are dropped (diff mode only) - * - Looks for views present in php files and install them all - */ - private function _processViewsFile($directory) - { - // Looks for a views file - $files = array_filter(glob($directory.'/'.self::VIEWS_FILENAME), 'is_file'); - - // If a views file is found... - if (count($files) > 0) - { - $this->_printMessage('Found views file: '.$files[0]); - - //...process it! - require_once($files[0]); // Read views file - $schema = basename($directory); // retrieves schema name from directory path - $dbViewsArray = $this->_listViewsBySchema($schema); // get list of views currently present in DB schema - - // Loops through list of views currently present in database - foreach ($dbViewsArray as $dbView) - { - // If NOT in new mode and if the view present in database is NOT present in the list of views from php file - if (!$this->_isNewMode() && !array_key_exists($dbView, $viewsArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> view '.$dbView.' NOT found in views file >> would be removed in diff mode'); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then drop it and objects that depends on it from database! If it fails then ends execution - if (!$this->_execQuery(sprintf('DROP VIEW %s.%s CASCADE', $schema, $dbView))) - { - $this->_printError('Error occurred while dropping view: '.$dbView); - return false; - } - else - { - $this->_printMessage('View dropped successfully: '.$dbView); - } - } - } - } - - // Loops through list of views from php file - foreach ($viewsArray as $viewName => $viewSQL) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> view '.$viewName.' would be added in new and diff mode'); - } - else - { - // Then install it! If it fails then ends execution - if (!$this->_execQuery($viewSQL)) - { - $this->_printError('Error occurred while adding view: '.$viewName); - return false; - } - else - { - $this->_printMessage('View added successfully: '.$viewName); - } - } - } - } - else - { - $this->_printMessage('No views file found'); - } - - return true; // If ends of procedure with no failures or no files are found then is a success - } - - /** - * Process functions file - * - Looks for functions present in current schema, then functions that are NOT present in php file are dropped (diff mode only) - * - Looks for functions present in php files and install them all - */ - private function _processFunctionsFile($directory) - { - // Looks for a functions file - $files = array_filter(glob($directory.'/'.self::FUNCTIONS_FILENAME), 'is_file'); - - // If a functions file is found... - if (count($files) > 0) - { - $this->_printMessage('Found functions file: '.$files[0]); - - //...process it! - require_once($files[0]); // Read functions file - $schema = basename($directory); // retrieves schema name from directory path - $dbFunctionsArray = $this->_listFunctionsBySchema($schema); // get list of functions currently present in DB schema - - // Loops through list of functions currently present in database - foreach ($dbFunctionsArray as $dbFunction) - { - // If NOT in new mode and if the function present in database is NOT present in the list of functions from php file - if (!$this->_isNewMode() && !array_key_exists($dbFunction, $functionsArray)) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> function '.$dbFunction.' NOT found in fucntions file >> would be removed in diff mode'); - } - elseif ($this->_isDiffMode()) // only if in diff mode - { - // Then drop it and objects that depends on it from database! If it fails then ends execution - if (!$this->_execQuery(sprintf('DROP FUNCTION %s.%s CASCADE', $schema, $dbFunction))) - { - $this->_printError('Error occurred while dropping function: '.$dbFunction); - return false; - } - else - { - $this->_printMessage('Function dropped successfully: '.$dbFunction); - } - } - } - } - - // Loops through list of functions from php file - foreach ($functionsArray as $functionName => $functionSQL) - { - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> view '.$functionName.' would be added in new and diff mode'); - } - else - { - // Then install it! If it fails then ends execution - if (!$this->_execQuery($functionSQL)) - { - $this->_printError('Error occurred while adding function: '.$functionName); - return false; - } - else - { - $this->_printMessage('Function added successfully: '.$functionName); - } - } - } - } - else - { - $this->_printMessage('No functions file found'); - } - - return true; // If ends of procedure with no failures or no files are found then is a success - } - - /** - * Process grants file - */ - private function _processGrantsFile($directory) - { - // Looks for a grants file - $files = array_filter(glob($directory.'/'.self::GRANTS_FILENAME), 'is_file'); - - // If a grants file is found... - if (count($files) > 0) - { - $this->_printMessage('Found grants file: '.$files[0]); - - //...process it! - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> would be executed in new and diff mode'); - } - else // new or diff mode - { - return $this->_execSQLFile($files[0]); - } - } - else - { - $this->_printMessage('No grants file found'); - } - - return true; // If no files are found then go forward -> is a success - } - - /** - * Process extra file - */ - private function _processExtraFile($directory) - { - // Looks for an extra file - $files = array_filter(glob($directory.'/'.self::EXTRA_FILENAME), 'is_file'); - - // If an extra file is found... - if (count($files) > 0) - { - $this->_printMessage('Found extra file: '.$files[0]); - - //...process it! - if ($this->_isDryrunMode()) // If dry run mode enabled - { - $this->_printInfo('Dry run >> would be executed in new and diff mode'); - } - else // new or diff mode - { - return $this->_execSQLFile($files[0]); - } - } - else - { - $this->_printMessage('No extra file found'); - } - - return true; // If no files are found then go forward -> is a success - } - - /** - * Load SQL from a file and then execute such SQL - */ - private function _execSQLFile($file) - { - $sql = file_get_contents($file); // Read the file content - if ($sql === false) // If failed - { - $this->_printError('Error occurred while reading file: '.$file); - } - else // otherwise - { - // Exec query - if ($this->_execQuery($sql) == false) // if failed - { - $this->_printError('Error occurred while executing SQL from file: '.$file); - } - else // otherwise - { - $this->_printMessage('Successfully executed SQL from file: '.$file); - return true; - } - } - - return false; - } - - /** - * Checks if the running mode is 'dryrun' - */ - private function _isDryrunMode() - { - return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_DRYRUN; - } - - /** - * Checks if the running mode is 'diff' - */ - private function _isDiffMode() - { - return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_DIFF; - } - - /** - * Checks if the running mode is 'new' - */ - private function _isNewMode() - { - return $this->_ci->config->item(self::CONF_MODE) == self::RUN_MODE_NEW; - } - - /** - * Checks if the parameter step is correct - */ - private function _checkParameterStep($steps) - { - if ($steps != null) // if it was given - { - $stepsArray = explode(self::SEPARATOR, $steps); // split the string in an array - foreach ($stepsArray as $step) - { - if (!is_numeric($step)) // if it is not a number - { - $this->_ci->eprintflib->printError('The given parameter must be a number or a string in the following format: 1:3:5'); - return false; - } - elseif ($step > self::MAX_STEPS) // if it is a number but > MAX_STEPS - { - $this->_ci->eprintflib->printError('The maximun value fot this parameter is: '.self::MAX_STEPS); - return false; - } - elseif ($step < 1) // if it is a number but < 1 - { - $this->_ci->eprintflib->printError('The minimum value fot this parameter is 1'); - return false; - } - } - } - - return true; - } - - /** - * Checks if the parameter selectedDirectories is correct and stores the result in $directories - */ - private function _checkParameterSelectedDirectories($selectedDirectories, &$directories) - { - if ($selectedDirectories != null) - { - $selectedDirectoriesArray = explode(self::SEPARATOR, $selectedDirectories); - - $found = true; - - foreach ($selectedDirectoriesArray as $key => $value) - { - $selectedDirectoriesArray[$key] = self::DBSKEL_DIR.$value; - - if (!in_array(self::DBSKEL_DIR.$value, $directories)) - { - $found = false; - break; - } - } - - if ($found) - { - $directories = $selectedDirectoriesArray; - } - else - { - $this->_printError('One or more of the given directories does NOT exist'); - return false; - } - } - - return true; - } - - //------------------------------------------------------------------------------------------------------------------ - // Private database methods - - /** - * Executes the given query - */ - private function _execQuery($query) - { - if (!@$this->_ci->db->simple_query($query)) - { - $error = $this->_ci->db->error(); - if (is_array($error) && isset($error['message'])) - { - $this->_printError($error['message']); - } - - return false; - } - - return true; - } - - /** - * Retrieves all the sequences present in the given database schema - */ - private function _listSequencesBySchema($schema) - { - $sequencesArray = array(); - $query = sprintf('SELECT sequence_name - FROM information_schema.sequences - WHERE sequence_schema = \'%s\'', $schema); - - if ($sequences = @$this->_ci->db->query($query)) - { - foreach ($sequences->result() as $sequence) - { - $sequencesArray[] = $sequence->sequence_name; - } - } - - return $sequencesArray; - } - - /** - * Retrieves all the tables present in the given database schema - */ - private function _listTablesBySchema($schema) - { - $tablesArray = array(); - $query = sprintf('SELECT table_name - FROM information_schema.tables - WHERE table_type = \'BASE TABLE\' - AND table_schema = \'%s\'', $schema); - - if ($tables = @$this->_ci->db->query($query)) - { - foreach ($tables->result() as $table) - { - $tablesArray[] = $table->table_name; - } - } - - return $tablesArray; - } - - /** - * Retrieves all the constraints present in the given database schema - * Returns an array with all the constraints, each element of the array is an array with two elements: - * - name: the name of the constraint - * - table: the name of the table where the constraint is applied - * NOTE: does not retrieve NOT NULL constraints - */ - private function _listConstraintsBySchema($schema) - { - $constraintsArray = array(); - $query = sprintf('SELECT constraint_name, - table_name - FROM information_schema.table_constraints - WHERE table_schema = \'%s\' - AND constraint_name NOT LIKE \'%%_not_null\'', $schema); // avoid to retrieve NOT NULL constraints - - if ($constraints = @$this->_ci->db->query($query)) - { - foreach ($constraints->result() as $constraint) - { - $constraintsArray[] = array('name' => $constraint->constraint_name, 'table' => $constraint->table_name); - } - } - - return $constraintsArray; - } - - /** - * Retrieves all the views present in the given database schema - */ - private function _listViewsBySchema($schema) - { - $viewsArray = array(); - $query = sprintf('SELECT table_name - FROM information_schema.views - WHERE table_schema = \'%s\'', $schema); - - if ($views = @$this->_ci->db->query($query)) - { - foreach ($views->result() as $view) - { - $viewsArray[] = $view->table_name; - } - } - - return $viewsArray; - } - - /** - * Retrieves all the functions present in the given database schema - */ - private function _listFunctionsBySchema($schema) - { - $functionsArray = array(); - $query = sprintf('SELECT routine_name - FROM information_schema.routines - WHERE specific_schema != \'pg_catalog\' - AND specific_schema != \'information_schema\' - AND routine_schema = \'%s\'', $schema); - - if ($functions = @$this->_ci->db->query($query)) - { - foreach ($functions->result() as $function) - { - $functionsArray[] = $function->routine_name; - } - } - - return $functionsArray; - } - - /** - * Retrieves all the columns from a database table - */ - private function _listColumns($schema, $table) - { - $columnsArray = array(); - $query = sprintf('SELECT column_name AS name, - data_type AS type, - column_default AS default, - is_nullable AS nullable, - character_maximum_length AS string_length, - numeric_precision AS number_length - FROM information_schema.columns - WHERE table_schema = \'%s\' - AND table_name = \'%s\'', $schema, $table); - - if ($columns = @$this->_ci->db->query($query)) - { - foreach ($columns->result() as $column) - { - $columnsArray[] = $column->routine_name; - } - } - - return $columnsArray; - } - - /** - * Creates a new table in database using the given schema and an array that defines the table structure - */ - private function _createTable($schema, $tableArray) - { - $tableName = ''; - $tableComment = ''; - $tableStructure = null; - - // For each element of the table array from the php file - foreach ($tableArray as $key => $value) - { - if ($key == self::T_COMMENT) // If it is the comment element - { - $tableComment = $value; - } - else // otherwise is the table structure element - { - $tableName = $key; - $tableStructure = $value; - } - } - - // Query to create a table - $query = sprintf('CREATE TABLE %s.%s (', $schema, $tableName); - // Query to comment the table and its columns - $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); - - // For each element of the table structure - foreach ($tableStructure as $colName => $colStructure) - { - $notNull = ''; // by default the column could be null - if (isset($colStructure[self::T_NULL]) && $colStructure[self::T_NULL] === false) - { - $notNull = 'NOT NULL'; // set to NOT NULL - } - - $default = ''; // by default there is no default for a column - if (isset($colStructure[self::T_DEFAULT])) - { - $default = 'DEFAULT '.$colStructure[self::T_DEFAULT]; // set as given by the table structure - } - - // Part of the query related to this column - $query .= sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); - - // If a comment is present for this column then the query is built - if (isset($colStructure[self::T_COMMENT])) - { - $queryComment .= sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); - } - } - - // Removes the last comma from the query - $query = substr($query, 0, strlen($query) - 1); - - // Close the round bracket - $query .= ');'; - - return $this->_execQuery($query.$queryComment); // executes query and returns its result - } - - /** - * TODO - * Changes the structure of a table using the given schema and an array that defines the table structure - */ - private function _manageTableColumns($schema, $tableArray) - { - $tableName = ''; - $tableComment = ''; - $tableStructure = null; - - // For each element of the table array from the php file - foreach ($tableArray as $key => $value) - { - if ($key == self::T_COMMENT) // If it is the comment element - { - $tableComment = $value; - } - else // otherwise is the table structure element - { - $tableName = $key; - $tableStructure = $value; - } - } - - // Comments the table - $queryComment = sprintf('COMMENT ON TABLE %s.%s IS \'%s\';', $schema, $tableName, $tableComment); - if ($this->_isDryrunMode()) - { - $this->_printInfo('Dry run >> table '.$tableName.' would be commented with: '.$queryComment); - } - else // new and diff mode - { - if (!$this->_execQuery($queryComment)) - { - $this->_printError('Error occurred while commenting table: '.$tableName); - return false; - } - else - { - $this->_printMessage('Table successfully commented: '.$tableName); - } - } - - // Retrieves the list of columns and their attributes from database - $dbTableColumns = $this->_listColumns($schema, $tableName); - - // For each element of the table structure - foreach ($tableStructure as $colName => $colStructure) - { - $notNull = ''; // by default the column could be null - if (isset($colStructure[self::T_NULL]) && $colStructure[self::T_NULL] === false) - { - $notNull = 'NOT NULL'; // set to NOT NULL - } - - $default = ''; // by default there is no default for a column - if (isset($colStructure[self::T_DEFAULT])) - { - $default = 'DEFAULT '.$colStructure[self::T_DEFAULT]; // set as given by the table structure - } - - // Part of the query related to this column - $query = sprintf('%s %s %s %s,', $colName, $colStructure[self::T_TYPE], $notNull, $default); - - // Comments a column - if (isset($colStructure[self::T_COMMENT])) - { - if ($this->_isDryrunMode()) - { - $this->_printInfo('Dry run >> column '.$tableName.'.'.$colName.' would be commented with: '.$colStructure[self::T_COMMENT]); - } - else // new and diff mode - { - $queryComment = sprintf('COMMENT ON COLUMN %s.%s.%s IS \'%s\';', $schema, $tableName, $colName, $colStructure[self::T_COMMENT]); - if (!$this->_execQuery($queryComment)) - { - $this->_printError('Error occurred while commenting column: '.$tableName.'.'.$colName); - return false; - } - else - { - $this->_printMessage('Column successfully commented: '.$tableName.'.'.$colName); - } - } - } - } - - return true; - } - - //------------------------------------------------------------------------------------------------------------------ - // Private output methods - - /** - * - */ - private function _printInfo($string) - { - $this->_ci->eprintflib->printInfo($string); - } - - /** - * - */ - private function _printError($string) - { - $this->_ci->eprintflib->printError($string); - } - - /** - * - */ - private function _printMessage($string) - { - $this->_ci->eprintflib->printMessage($string); - } - - /** - * - */ - private function _printSchemaSeparator() - { - $this->_printInfo('--------------------------------------------------------------------------------------------'); - } - - /** - * - */ - private function _printFileSeparator() - { - $this->_printMessage('--------------------------------------------------------------------------------------------'); - } - - /** - * - */ - private function _printRunningMode() - { - if ($this->_isDryrunMode()) $this->_printInfo('>> DBSkel is running in dry run mode <<'); - elseif ($this->_isNewMode()) $this->_printInfo('>> DBSkel is running in new mode <<'); - elseif ($this->_isDiffMode()) $this->_printInfo('>> DBSkel is running in diff mode <<'); - } -} From 0703984fa627b3f7614bd80bc45f1c0c39809bcc Mon Sep 17 00:00:00 2001 From: Cris Date: Thu, 12 Sep 2019 13:26:29 +0200 Subject: [PATCH 146/500] Added Controller method orderLehrauftrag --- .../lehre/lehrauftrag/Lehrauftrag.php | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php index b214916cd..12b3f63f7 100644 --- a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php +++ b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php @@ -24,17 +24,27 @@ class Lehrauftrag extends Auth_Controller // Set required permissions parent::__construct( array( - 'index' => 'lehre/lehrauftrag_bestellen:r' + 'index' => 'lehre/lehrauftrag_bestellen:r', + 'orderLehrauftrag' => 'lehre/lehrauftrag_bestellen:rw' ) ); // Load models + $this->load->model('system/Benutzerrolle_model', 'BenutzerrolleModel'); + $this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $this->load->model('accounting/Vertrag_model', 'VertragModel'); // Load libraries $this->load->library('WidgetLib'); $this->load->library('PermissionLib'); + // Load helpers + $this->load->helper('array'); + $this->load->helper('url'); + $this->load->helper('hlp_sancho_helper'); + // Load language phrases $this->loadPhrases( array( @@ -60,15 +70,12 @@ class Lehrauftrag extends Auth_Controller $studiengang_kz = ($studiengang_kz == 'null' ? null : $studiengang_kz); // Retrieve studiengaenge the user is entitled for to populate studiengang dropdown - if (!$studiengang_kz_arr = $this->permissionlib->getSTG_isEntitledFor(self::BERECHTIGUNG_LEHRAUFTRAG_BESTELLEN)) - { + if (!$studiengang_kz_arr = $this->permissionlib->getSTG_isEntitledFor(self::BERECHTIGUNG_LEHRAUFTRAG_BESTELLEN)) { show_error('Fehler bei Berechtigungsprüfung'); } - // Set studiensemester selected for studiengang dropdown $studiensemester_kurzbz = $this->input->get('studiensemester'); // if provided by selected studiensemester - if (is_null($studiensemester_kurzbz)) // else set next studiensemester as default value { $studiensemester = $this->StudiensemesterModel->getNext(); @@ -91,6 +98,49 @@ class Lehrauftrag extends Auth_Controller $this->load->view('lehre/lehrauftrag/lehrauftrag.php', $view_data); } + public function orderLehrauftrag() + { + $result = array(); + $new_lehrvertrag_data_arr = array(); // information of new lehrvertraege to be used in mail + + foreach ($_POST as $lehrauftrag) + { + if (!isEmptyArray($lehrauftrag)) { + if ($this->VertragModel->save( + element('Person_ID', $lehrauftrag), + element('LV_ID', $lehrauftrag), + element('LE_ID', $lehrauftrag), + element('PA_ID', $lehrauftrag), + element('Stunden', $lehrauftrag), + element('Betrag', $lehrauftrag), + element('Studiensemester', $lehrauftrag) + )->retval) + { + $result []= array( + 'id' => $lehrauftrag['id'], + 'Bestellt' => date('Y-m-d') + ); + + $new_lehrvertrag_data_arr[] = array( + 'studiensemester_kurzbz' => $lehrauftrag['Studiensemester'], + 'studiengang_kz' => $lehrauftrag['studiengang_kz'], + 'lv_oe_kurzbz' => $lehrauftrag['lv_oe_kurzbz'] + ); + } + } + } + + if (!isEmptyArray($result)) + { + $this->outputJsonSuccess($result); + } + + // Send email to Mitarbeiter + // if(!$this->_sendMail($new_lehrvertrag_data_arr)) // TODO: slows down Bestell-process -> better chronjob? + { + // return error information // TODO: implement after decision regarding communication process + } + } // ----------------------------------------------------------------------------------------------------------------- // Private methods From 6b1e2259913ad666d7b2b0ecefcc5158703f959e Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 13:30:04 +0200 Subject: [PATCH 147/500] Added private methods to send mail when ordering Lehrauftraege These two methods will send email to 1. authorized Kompetenzleiter or 2. Departmentleiter with data about . study semester . study program . amount of Lehrauftraege --- .../lehre/lehrauftrag/Lehrauftrag.php | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php index 12b3f63f7..b85bf26dc 100644 --- a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php +++ b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php @@ -155,4 +155,83 @@ class Lehrauftrag extends Auth_Controller if (!$this->_uid) show_error('User authentification failed'); } + private function _sendMail($lehrvertrag_data_arr) + { + // Cluster data of new lehrvertraege as needed to send mail + $lehrvertrag_data_arr = $this->_cluster_newVertragData($lehrvertrag_data_arr); + + foreach ($lehrvertrag_data_arr as $lehrvertrag_data) + { + // Get mail recipients + $result = $this->BenutzerrolleModel->getBenutzerByBerechtigung('lehre/lehrauftrag_erteilen', $lehrvertrag_data['lv_oe_kurzbz']); + + // If given lv organisational unit has no authorized user, check if is a Kompetenzfeld. + // If so, look up for authorized user on Department level. + if (!hasData($result)) { + $result = $this->OrganisationseinheitModel->getParent($lehrvertrag_data['lv_oe_kurzbz']); + + if (hasData($result)) { + if ($result->retval[0]->organisationseinheittyp_kurzbz === 'Department') { + $result = $this->BenutzerrolleModel->getBenutzerByBerechtigung('lehre/lehrauftrag_erteilen', $result->retval[0]->oe_kurzbz); + } + } + } + + // Set mail recipients (department assistance/leader) + $to = ''; + $to_arr = array(); + foreach ($result->retval as $berechtigung) { + $to_arr []= $berechtigung->uid . '@' . DOMAIN; // TODO: als array, dann splitten mit ;? oder als array lassen? + } + $to = implode(', ', $to_arr); + + // Set link to lehrauftrag-site with preselected studiengang and studiensemester of new lehrauftraege + $url = site_url(self::LEHRAUFTRAG_URI).'?studiensemester='. $lehrvertrag_data['studiensemester_kurzbz']. '&studiengang='. $lehrvertrag_data['studiengang_kz']; + + // Prepare mail content + $content_data_arr = array( + 'anzahl' => $lehrvertrag_data['amount_new_lehrvertraege'], + 'studiengang' => $lehrvertrag_data['studiengang_kz'], + 'studiensemester' => $lehrvertrag_data['studiensemester_kurzbz'], + 'link' => anchor($url, 'Lehrverträge Übersicht') + ); + + // Send mail + sendSanchoMail( + 'LehrauftragBestellMail', + $content_data_arr, + $to, + 'Bestellung neuer Lehraufträge', + 'sancho_header_min_bw.jpg', + 'sancho_footer_min_bw.jpg' + ); + } + } + + /** + * Clusters data as needed for _sendMail. + * Makes array of new lehrvertraege unique (by studiensemester, studiengang and lv_oe_kurzbz) + * Adds the amount of lehrvertraege of each unique array element. + * @param $new_lehrvertrag_data_arr + * @return array + */ + private function _cluster_newVertragData($new_lehrvertrag_data_arr) + { + $unique_new_lehrvertrag_data_arr = array_unique($new_lehrvertrag_data_arr, SORT_REGULAR); + foreach ($unique_new_lehrvertrag_data_arr as &$new_lehrvertrag) + { + $cnt = 1; + foreach ($new_lehrvertrag_data_arr as $item) + { + if ($new_lehrvertrag['studiensemester_kurzbz'] === $item['studiensemester_kurzbz'] && + $new_lehrvertrag['studiengang_kz'] === $item['studiengang_kz'] && + $new_lehrvertrag['lv_oe_kurzbz'] === $item['lv_oe_kurzbz']) + { + $new_lehrvertrag['amount_new_lehrvertraege'] = $cnt++; + } + } + } + + return $unique_new_lehrvertrag_data_arr; + } } From 10b476c27eb00a1787be82d6040f3b85c0b86c20 Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 13:45:50 +0200 Subject: [PATCH 148/500] Added methods save() and setStatus() . save method inserts a new Vertrag, sets Vertragsstatus to 'bestellt' and assigns vertrags_id to either corresponding Lehreinheitmitarbeiter or corresponding Projektbetreuuer . setStatus inserts a new Status to a given Vertrag --- .../models/accounting/Vertrag_model.php | 152 ++++++++++++++++++ system/dbupdate_3.3.php | 14 ++ system/filtersupdate.php | 7 + 3 files changed, 173 insertions(+) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index cd4b466d6..b5158eb22 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -11,4 +11,156 @@ class Vertrag_model extends DB_Model $this->dbTable = 'lehre.tbl_vertrag'; $this->pk = 'vertrag_id'; } + + /** + * Saves Vertrag for a Lehrauftrag and sets Vertragsstatus to 'bestellt'. + * Also updates vertrag_id in tbl_lehreinheitmitarbeiter or tbl_projektbetreuer. + * @param $person_id + * @param $lehrveranstaltung_id + * @param $lehreinheit_id + * @param $projektarbeit_id + * @param $betrag Monetary amount of that Lehreinheit / Projektbetreuung. + * @param $vertragsstunden Working hours of that Lehreinheit / Projektbetreuung. + * @param $studiensemester_kurzbz + * @param $vertragstyp_kurzbz + * @return array|null On success object. On failure null. + */ + public function save($person_id, $lehrveranstaltung_id, $lehreinheit_id, $projektarbeit_id = null, $vertragsstunden, $betrag, $studiensemester_kurzbz){ + + // Cast input params + $person_id = (!isset($person_id) || empty($person_id)) ? null : intval($person_id); + $lehreinheit_id = (!isset($lehreinheit_id) || empty($lehreinheit_id)) ? null : intval($lehreinheit_id); + $lehrveranstaltung_id = (!isset($lehrveranstaltung_id) || empty($lehrveranstaltung_id)) ? null : intval($lehrveranstaltung_id); + $projektarbeit_id = (!isset($projektarbeit_id) || empty($projektarbeit_id)) ? null : intval($projektarbeit_id); + $vertragsstunden = (!isset($vertragsstunden) || empty($vertragsstunden)) ? null : floatval($vertragsstunden); + $betrag = (!isset($betrag) || empty($betrag)) ? null : floatval($betrag); + + $vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung'; + + $result = array(); + $user = getAuthUID(); + + // Retrieve mitarbeiter uid from person_id + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $benutzer = $this->BenutzerModel->getFromPersonId($person_id)->retval; + $mitarbeiter_uid = $benutzer[0]->uid; // lectors uid + + // First check if Vertrag already exists for that Lehrauftrag or for that Projektbetreuerauftrag + if ($vertragstyp_kurzbz == 'Lehrauftrag') + { + $this->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); // + if ($this->LehreinheitmitarbeiterModel->hasVertrag($mitarbeiter_uid, $lehreinheit_id)) + { + return $result = success(null); // Exit if Lehrauftrag already has Vertrag + } + } + elseif ($vertragstyp_kurzbz == 'Betreuung') + { + $this->load->model('education/Projektbetreuer_model', 'ProjektbetreuerModel'); + if ($this->ProjektbetreuerModel->hasVertrag($person_id, $projektarbeit_id)) + { + return $result = success(null); // Exit if Projektbetreuung already has Vertrag + } + } + + // If Vertrag does not exist, create now + // Start DB transaction + $this->db->trans_start(false); + + // Insert Vertragsdata + $result = $this->insert(array( + 'person_id' => $person_id, + 'lehrveranstaltung_id' => $lehrveranstaltung_id, + 'vertragstyp_kurzbz' => $vertragstyp_kurzbz, + 'betrag' => $betrag, + 'insertamum' => 'NOW()', + 'insertvon' => $user, + 'vertragsdatum' => 'NOW()', + 'vertragsstunden' => $vertragsstunden, + 'vertragsstunden_studiensemester_kurzbz' => $studiensemester_kurzbz + )); + + // Retrieve primary key + $vertrag_id = $result->retval; + + // If Vertrag was created successfully, update vertrag_id + if (isSuccess($result)) + { + // if Lehrtätigkeit, update vertrag_id in tbl_lehreinheitmitarbeiter + if ($vertragstyp_kurzbz == 'Lehrauftrag') + { + $this->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); + $result = $this->LehreinheitmitarbeiterModel->update( + array( + 'lehreinheit_id' => $lehreinheit_id, + 'mitarbeiter_uid' =>$mitarbeiter_uid + ), + array( + 'vertrag_id' => $vertrag_id + ) + ); + } + // if (Projekt-)Betreuung, update vertrag_id in tbl_projektbetreuer + elseif ($vertragstyp_kurzbz == 'Betreuung') + { + $this->load->model('education/Projektbetreuer_model', 'ProjektbetreuerModel'); + $result = $this->ProjektbetreuerModel->update( + array( + 'person_id' => $person_id, + 'projektarbeit_id' => $projektarbeit_id + ), + array( + 'vertrag_id' => $vertrag_id + ) + ); + } + } + + // If updating vertrag_id was successfully, set Status to 'bestellt' + if (isSuccess($result)) + { + $result = $this->setStatus($vertrag_id, 'bestellt', $mitarbeiter_uid); + } + + // Transaction complete! + $this->db->trans_complete(); + + // Check if everything went ok during the transaction + if ($this->db->trans_status() === false || isError($result)) + { + $this->db->trans_rollback(); + $result = error($result->msg, EXIT_ERROR); + } + else + { + $this->db->trans_commit(); + $result = success($vertrag_id); + } + + return $result; + + } + + /** + * Sets Vertragsstatus for the given Vertrag and Mitarbeiter. + * @param $vertrag_id + * @param $vertragsstatus_kurzbz + * @param $mitarbeiter_uid + * @return array|null On success object. On failure null. + */ + public function setStatus($vertrag_id, $vertragsstatus_kurzbz, $mitarbeiter_uid){ + + $query = ' + INSERT INTO lehre.tbl_vertrag_vertragsstatus( + vertragsstatus_kurzbz, + vertrag_id, + uid, + datum, + insertvon, + updatevon, + updateamum + ) VALUES (?, ?, ?, ?, ?, ?, ?);'; + + return $this->execQuery($query, array($vertragsstatus_kurzbz, $vertrag_id, $mitarbeiter_uid, 'NOW()', getAuthUID(), null, null)); + } } diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index a321b4b3e..248e52577 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3107,6 +3107,20 @@ if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragsstatus WHERE vertra } } +// Insert 'Betreuung' to tbl_vertragstyp +if($result = @$db->db_query("SELECT 1 FROM lehre.tbl_vertragstyp WHERE vertragstyp_kurzbz = 'Betreuung';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO lehre.tbl_vertragstyp(vertragstyp_kurzbz, bezeichnung) VALUES('Betreuung', 'Betreuung');"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_vertragstyp '.$db->db_last_error().'
    '; + else + echo 'lehre.tbl_vertragstyp: Added value \'Betreuung\'
    '; + } +} + // Add permission to order lehrauftrag (lehrauftrag_bestellen) if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'lehre/lehrauftrag_bestellen';")) { diff --git a/system/filtersupdate.php b/system/filtersupdate.php index a31fe702e..2140852d1 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -410,10 +410,17 @@ $filters = array( { "name": "", "columns": [ + {"name": "id"}, {"name": "LE_ID"}, + {"name": "LV_ID"}, + {"name": "PA_ID"}, + {"name": "Studiensemester"}, + {"name": "studiengang_kz"}, + {"name": "Person_ID"}, {"name": "Typ"}, {"name": "Auftrag"}, {"name": "Organisationseinheit"}, + {"name": "lv_oe_kurzbz"}, {"name": "Gruppe"}, {"name": "Lektor"}, {"name": "Stunden"}, From 237a906ecf12b90488d94aac395daa925fa8b05f Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 13:50:31 +0200 Subject: [PATCH 149/500] Added new method hasVertrag() This method checks if a Lehrauftrag has a corresponding contract. If vertrag_id is null => is still a new Lehrauftrag If vertrag_id is presendt => Lehrauftrag has been ordered and a contract has been created. --- .../Lehreinheitmitarbeiter_model.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/application/models/education/Lehreinheitmitarbeiter_model.php b/application/models/education/Lehreinheitmitarbeiter_model.php index ee11dcd01..dd5c7c858 100644 --- a/application/models/education/Lehreinheitmitarbeiter_model.php +++ b/application/models/education/Lehreinheitmitarbeiter_model.php @@ -11,4 +11,34 @@ class Lehreinheitmitarbeiter_model extends DB_Model $this->dbTable = 'lehre.tbl_lehreinheitmitarbeiter'; $this->pk = array('mitarbeiter_uid', 'lehreinheit_id'); } + + /** + * Checks if Lehrauftrag has a contract. + * @param $mitarbeiter_uid + * @param $lehreinheit_id + * @return array|bool|int Returns vertrag_id if contract exists. False if doesnt exist. On error array. + */ + public function hasVertrag($mitarbeiter_uid, $lehreinheit_id) + { + if(is_string($mitarbeiter_uid) && is_numeric($lehreinheit_id)) + { + $result = $this->load(array( + 'mitarbeiter_uid' => $mitarbeiter_uid, + 'lehreinheit_id' => $lehreinheit_id + )); + + if (hasData($result)) + { + return (is_null($result->retval[0]->vertrag_id)) ? false : intval($result->retval[0]->vertrag_id); + } + else + { + return error($result->msg, EXIT_ERROR); + } + } + else + { + return error ('Incorrect parameter type'); + } + } } From 3c98988c1c6c87d738d01310429d61aef3647109 Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 13:51:54 +0200 Subject: [PATCH 150/500] Added new method hasVertrag() This method checks if a Projektbetreuer has a corresponding contract. If vertrag_id is null => is still a new Projektauftrag If vertrag_id is present => Projektauftrag has been ordered and a contract has been created. --- .../education/Projektbetreuer_model.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/application/models/education/Projektbetreuer_model.php b/application/models/education/Projektbetreuer_model.php index 32743be82..746e4c052 100644 --- a/application/models/education/Projektbetreuer_model.php +++ b/application/models/education/Projektbetreuer_model.php @@ -11,4 +11,34 @@ class Projektbetreuer_model extends DB_Model $this->dbTable = 'lehre.tbl_projektbetreuer'; $this->pk = array('betreuerart_kurzbz', 'projektarbeit_id', 'person_id'); } + + /** + * Checks if Projektauftrag has a contract. + * @param $person_id + * @param $projektarbeit_id + * @return array|bool|int Returns vertrag_id if contract exists. False if doesnt exist. On error array. + */ + public function hasVertrag($person_id, $projektarbeit_id) + { + if (is_numeric($person_id) && is_numeric($projektarbeit_id)) + { + $result = $this->load(array( + 'person_id' => $person_id, + 'projektarbeit_id' => $projektarbeit_id + )); + + if (hasData($result)) + { + return (is_null($result->retval[0]->vertrag_id)) ? false : intval($result->retval[0]->vertrag_id); + } + else + { + return error($result->msg, EXIT_ERROR); + } + } + else + { + return error ('Incorrect parameter type'); + } + } } From b8ed622f966d6cc003c730a16ec50227f51179dc Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 13:53:39 +0200 Subject: [PATCH 151/500] Added method getParent() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method gets only one parent of given organisational unit. This ist to easily retrieve department of a studiengang or fakultät of department etc. --- .../Organisationseinheit_model.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/application/models/organisation/Organisationseinheit_model.php b/application/models/organisation/Organisationseinheit_model.php index f9353c7b3..3efc8472a 100644 --- a/application/models/organisation/Organisationseinheit_model.php +++ b/application/models/organisation/Organisationseinheit_model.php @@ -165,4 +165,27 @@ class Organisationseinheit_model extends DB_Model return $this->execQuery(sprintf($query, $aktivstring, $aktivstring), array($oe_kurzbz)); } + /** + * Get one parent only. + * Easily retrieve department of a studiengang or fakultät of department etc. + * @param $oe_kurzbz + * @return array|null + */ + public function getParent($oe_kurzbz) + { + if (is_string($oe_kurzbz)) + { + $condition = ' + oe_kurzbz = ( + SELECT + oe_parent_kurzbz + FROM + public.tbl_organisationseinheit + WHERE + oe_kurzbz = \''. $oe_kurzbz. '\' + ) + '; + } + return $this->loadWhere($condition); + } } From edd7f56481a321f31a56f6a2998f083e429a67f7 Mon Sep 17 00:00:00 2001 From: Cris Date: Thu, 12 Sep 2019 13:57:02 +0200 Subject: [PATCH 152/500] Corrected query: load uids only from *active* benutzer --- application/models/person/Benutzer_model.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/models/person/Benutzer_model.php b/application/models/person/Benutzer_model.php index 46e5bdb98..dc5b95779 100644 --- a/application/models/person/Benutzer_model.php +++ b/application/models/person/Benutzer_model.php @@ -15,8 +15,7 @@ class Benutzer_model extends DB_Model public function getFromPersonId($person_id) { - /*$this->addSelect('uid, aktiv, alias');*/ - $this->loadWhere(array('person_id' => $person_id)); + return $this->loadWhere(array('person_id' => $person_id, 'aktiv' => true)); } } From 94d13fd77a2b9053cde91dfd3a12b28947d85eda Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 14:04:48 +0200 Subject: [PATCH 153/500] Added method getBenutzerByBerechtigung This method returns user who are authorized with berechtigung and, if given, authorized for the specific organisational unit. --- .../models/system/Benutzerrolle_model.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/application/models/system/Benutzerrolle_model.php b/application/models/system/Benutzerrolle_model.php index 13ebf57b6..5ce96a622 100644 --- a/application/models/system/Benutzerrolle_model.php +++ b/application/models/system/Benutzerrolle_model.php @@ -36,4 +36,22 @@ class Benutzerrolle_model extends DB_Model return $result; } + + /** + * Get user who are authorized with berechtigung and, if given, authorized for the specific organisational unit. + * @param $berechtigung_kurzbz + * @param null $oe_kurzbz + * @return array + */ + public function getBenutzerByBerechtigung($berechtigung_kurzbz, $oe_kurzbz = null){ + + $condition = array('berechtigung_kurzbz' => $berechtigung_kurzbz); + + if (is_string($oe_kurzbz)) + { + $condition['oe_kurzbz'] = $oe_kurzbz; + } + + return $this->loadWhere($condition); + } } \ No newline at end of file From 90c257f7bb113065d31233d68e6f459f80d6f675 Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Thu, 12 Sep 2019 14:09:18 +0200 Subject: [PATCH 154/500] =?UTF-8?q?Fotoliste=20zeigt=20nun=20korrekte=20St?= =?UTF-8?q?udiengangsbezeichnung=20wenn=20Gruppen=20aus=20anderen=20Studie?= =?UTF-8?q?ng=C3=A4ngen=20zugeteilt=20sind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cis/private/lehre/fotoliste.pdf.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cis/private/lehre/fotoliste.pdf.php b/cis/private/lehre/fotoliste.pdf.php index 8054955ca..8565470c6 100644 --- a/cis/private/lehre/fotoliste.pdf.php +++ b/cis/private/lehre/fotoliste.pdf.php @@ -31,6 +31,7 @@ require_once('../../../include/lehrveranstaltung.class.php'); require_once('../../../include/lehreinheit.class.php'); require_once('../../../include/benutzerberechtigung.class.php'); require_once('../../../include/studiensemester.class.php'); +require_once('../../../include/studiengang.class.php'); require_once('../../../include/functions.inc.php'); require_once('../../../include/erhalter.class.php'); require_once('../../../include/datum.class.php'); @@ -58,6 +59,9 @@ isset($_GET['stsem']) ? $studiensemester = $_GET['stsem'] : die('Ein Studienseme $lv = new lehrveranstaltung(); $lv->load($lvid); +$stg = new studiengang(); +$stg->load($lv->studiengang_kz); + $berechtigung = new benutzerberechtigung(); $berechtigung->getBerechtigungen($user); @@ -96,17 +100,15 @@ if ($lehreinheit != '') $gruppen_string = ''; $gruppen_string_arr = array(); -$stg_typ = ''; +$stg_typ = $stg->typ; +$stg_bezeichnung = $stg->bezeichnung; //structure overall lehrveranstaltungs data if ($result = $db->db_query($qry)) { while ($row = $db->db_fetch_object($result)) { //lehrveranstaltung $lv_bezeichnung = $row->lv_bezeichnung; - //studiengang - $stg_bezeichnung = $row->stg_bez; - //studiengangstyp - $stg_typ = $row->stg_typ; + //collect all gruppenkürzel if ($row->gruppe_kurzbz == '') $gruppen_string = trim($row->kuerzel . '-' . $row->semester . $row->verband . $row->gruppe); @@ -237,8 +239,8 @@ if ($result = $db->db_query($qry)) { $row->foto_sperre = 'f'; //create foto (if not locked by student OR if fotolist is created by admin or assistenz) - $foto_url = ''; - + $foto_url = ''; + if ($row->foto_sperre == 'f' && $row->foto != '') { $foto_src = $row->foto; $foto_url = sys_get_temp_dir() . '/foto' . trim($row->matrikelnr) . '.jpg'; From 35b37179e909cb200624270419ae2f2264fc2a09 Mon Sep 17 00:00:00 2001 From: hainberg Date: Thu, 12 Sep 2019 14:09:57 +0200 Subject: [PATCH 155/500] Added Javascript button functionalities and functions for Tabulator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added buttons and functionalities for . showing all . showing new . select all . deselect all ...Lehraufträge in tabulator-table Added methods to manipulate date-data and filtering in tabulator. --- .../views/lehre/lehrauftrag/lehrauftrag.php | 199 +++++++++++++----- 1 file changed, 141 insertions(+), 58 deletions(-) diff --git a/application/views/lehre/lehrauftrag/lehrauftrag.php b/application/views/lehre/lehrauftrag/lehrauftrag.php index 425001070..6b93bb079 100644 --- a/application/views/lehre/lehrauftrag/lehrauftrag.php +++ b/application/views/lehre/lehrauftrag/lehrauftrag.php @@ -13,6 +13,7 @@ $this->load->view( 'tabulator' => true, 'momentjs' => true, 'ajaxlib' => true, + 'dialoglib' => true, 'filterwidget' => true, 'navigationwidget' => true, 'phrases' => array( @@ -27,68 +28,64 @@ $this->load->view(
    - -
    -
    - -
    -
    -
    -
    - widgetlib->widget( - 'Studiensemester_widget', - array( - DropdownWidget::SELECTED_ELEMENT => $studiensemester_selected - ), - array( - 'name' => 'studiensemester', - 'id' => 'studiensemester' - ) - ); - ?> -
    -
    - widgetlib->widget( - 'Studiengang_widget', - array( - DropdownWidget::SELECTED_ELEMENT => $studiengang_selected, - 'studiengang' => $studiengang - ), - array( - 'name' => 'studiengang', - 'id' => 'studiengang' - ) - ); - ?> -
    - - -
    -
    - -
    -
    - load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> -
    -
    - - - - - - - - -
    - + +
    +
    + +
    +
    +
    +
    + widgetlib->widget( + 'Studiensemester_widget', + array( + DropdownWidget::SELECTED_ELEMENT => $studiensemester_selected + ), + array( + 'name' => 'studiensemester', + 'id' => 'studiensemester' + ) + ); + ?> +
    +
    + widgetlib->widget( + 'Studiengang_widget', + array( + DropdownWidget::SELECTED_ELEMENT => $studiengang_selected, + 'studiengang' => $studiengang + ), + array( + 'name' => 'studiengang', + 'id' => 'studiengang' + ) + ); + ?> +
    + + +
    +
    + +
    +
    + load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> +
    +
    + +
    +
    + + +
    @@ -96,3 +93,89 @@ $this->load->view( load->view('templates/FHC-Footer'); ?> + + + From b92f3a1ee5aae051b6efe287ccaef7db26f152fa Mon Sep 17 00:00:00 2001 From: Cris Date: Thu, 12 Sep 2019 14:16:08 +0200 Subject: [PATCH 156/500] Adapted tabulator data-query (row index; some extra columns) . Added incrementing id column which provides unique number to enable tabulator to use it as row index. . Added extra colums studiengang_kz, lv_oe_kurzbz --- .../lehre/lehrauftrag/lehrauftragData.php | 263 +++++++++--------- 1 file changed, 132 insertions(+), 131 deletions(-) diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index c0c9493e2..291f9670a 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -4,120 +4,138 @@ $STUDIENSEMESTER = $studiensemester_selected; $STUDIENGANG = (isset($studiengang_selected) && !is_null($studiengang_selected)) ? array($studiengang_selected) : $studiengang; $query = ' - /* Lehraufträge and -vertragsstati */ -SELECT - lema.lehreinheit_id AS "LE_ID", - upper(lv.lehrtyp_kurzbz) AS "Typ", - (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || \']\') AS "Auftrag", - CASE - WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) - WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) - ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) - END AS "Organisationseinheit", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", - (person.vorname || \' \' || person.nachname) AS "Lektor", - TRUNC(lema.semesterstunden, 1) AS "Stunden", - TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "Betrag", - CASE - /* existing contracts for given study semester with status bestellt */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum - END AS "Bestellt", - CASE - /* existing contracts for given study semester with status erteilt */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum - END AS "Erteilt", - CASE - /* existing contracts for given study semester with status akzeptiert */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum - END AS "Akzeptiert" -FROM - lehre.tbl_lehreinheitmitarbeiter lema - JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) - JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) - JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) - JOIN public.tbl_mitarbeiter ma USING (mitarbeiter_uid) - JOIN public.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid - JOIN public.tbl_person person USING (person_id) - LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) - LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) - LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) - JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz -WHERE - /* filter studiengang */ - lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') - /* filter studiensemester */ - AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' - /* filter active lehrveranstaltungen */ - AND lv.aktiv = TRUE - /* filter dummies and invalid mitarbeiter */ - AND ma.personalnummer >= 0 - - -UNION - -/* Projektbetreuungsaufträge and -vertragsstati */ -SELECT - pa.lehreinheit_id AS "LE_ID", - \'Betreuung\' AS "Typ", - (betreuerart_kurzbz || \' \' || - (SELECT - vorname || \' \' || nachname - FROM - public.tbl_person - JOIN public.tbl_benutzer USING (person_id) - WHERE - uid = pa.student_uid) - || \' [\' || projekttyp_kurzbz || \'arbeit\' || \' \' || lv.semester || \'.Semester]\') AS "Auftrag", - CASE - WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) - WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) - ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) - END AS "Organisationseinheit", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", - (vorname || \' \' || nachname) AS "Lektor", - TRUNC(pb.stunden, 1) AS "Stunden", - TRUNC((pb.stunden * pb.stundensatz), 2) AS "Betrag", - CASE - /* existing contracts for given study semester with status bestellt */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum - END AS "Bestellt", - CASE - /* existing contracts for given study semester with status erteilt */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum - END AS "Erteilt", - CASE - /* existing contracts for given study semester with status akzeptiert */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum - END AS "Akzeptiert" -FROM - lehre.tbl_projektbetreuer pb - JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id) - JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) - JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) - JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) - JOIN public.tbl_person person USING (person_id) - LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) - LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) - LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) - JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz -WHERE - /* filter studiengang */ - lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') - /* filter studiensemester */ - AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' - /* filter active lehrveranstaltungen */ - AND lv.aktiv = TRUE - -ORDER BY "Typ" DESC, "Auftrag", "Lektor" -'; + SELECT + ROW_NUMBER() OVER () AS "id", + * + FROM + ( + /* Lehraufträge and -vertragsstati */ + SELECT + lema.lehreinheit_id AS "LE_ID", + lv.lehrveranstaltung_id AS "LV_ID", + NULL AS "PA_ID", + le.studiensemester_kurzbz AS "Studiensemester", + stg.studiengang_kz, + person.person_id AS "Person_ID", + upper(lv.lehrtyp_kurzbz) AS "Typ", + (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || \']\') AS "Auftrag", + CASE + WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) + WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) + ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) + END AS "Organisationseinheit", + lv.oe_kurzbz AS "lv_oe_kurzbz", + CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", + (person.vorname || \' \' || person.nachname) AS "Lektor", + TRUNC(lema.semesterstunden, 1) AS "Stunden", + TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "Betrag", + CASE + /* existing contracts for given study semester with status bestellt */ + WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum + END AS "Bestellt", + CASE + /* existing contracts for given study semester with status erteilt */ + WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum + END AS "Erteilt", + CASE + /* existing contracts for given study semester with status akzeptiert */ + WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum + END AS "Akzeptiert" + FROM + lehre.tbl_lehreinheitmitarbeiter lema + JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) + JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) + JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) + JOIN public.tbl_mitarbeiter ma USING (mitarbeiter_uid) + JOIN public.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid + JOIN public.tbl_person person USING (person_id) + LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) + LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) + LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) + JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz + WHERE + /* filter studiengang */ + lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') + /* filter studiensemester */ + AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' + /* filter active lehrveranstaltungen */ + AND lv.aktiv = TRUE + /* filter dummies and invalid mitarbeiter */ + AND ma.personalnummer >= 0 + + + UNION + + /* Projektbetreuungsaufträge and -vertragsstati */ + SELECT + pa.lehreinheit_id AS "LE_ID", + lv.lehrveranstaltung_id AS "LV_ID", + pa.projektarbeit_id AS "PA_ID", + le.studiensemester_kurzbz AS "Studiensemester", + stg.studiengang_kz, + person.person_id AS "Person_ID", + \'Betreuung\' AS "Typ", + (betreuerart_kurzbz || \' \' || + (SELECT + vorname || \' \' || nachname + FROM + public.tbl_person + JOIN public.tbl_benutzer USING (person_id) + WHERE + uid = pa.student_uid) + || \' [\' || projekttyp_kurzbz || \'arbeit\' || \' \' || lv.semester || \'.Semester]\') AS "Auftrag", + CASE + WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) + WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) + ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) + END AS "Organisationseinheit", + lv.oe_kurzbz AS "lv_oe_kurzbz", + CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", + (vorname || \' \' || nachname) AS "Lektor", + TRUNC(pb.stunden, 1) AS "Stunden", + TRUNC((pb.stunden * pb.stundensatz), 2) AS "Betrag", + CASE + /* existing contracts for given study semester with status bestellt */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum + END AS "Bestellt", + CASE + /* existing contracts for given study semester with status erteilt */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum + END AS "Erteilt", + CASE + /* existing contracts for given study semester with status akzeptiert */ + WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND + vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum + END AS "Akzeptiert" + FROM + lehre.tbl_projektbetreuer pb + JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id) + JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) + JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) + JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) + JOIN public.tbl_person person USING (person_id) + LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) + LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) + LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) + JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz + WHERE + /* filter studiengang */ + lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') + /* filter studiensemester */ + AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' + /* filter active lehrveranstaltungen */ + AND lv.aktiv = TRUE + + ORDER BY "Typ" DESC, "Auftrag", "Lektor" + ) auftraege + '; $filterWidgetArray = array( @@ -179,20 +197,3 @@ echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); ?> - - From c91cfcb679a2a6ca67e350cc217bcef12dbf5805 Mon Sep 17 00:00:00 2001 From: Cris Date: Thu, 12 Sep 2019 14:18:14 +0200 Subject: [PATCH 157/500] Added tabulator options and behaviour --- .../lehre/lehrauftrag/lehrauftragData.php | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 291f9670a..293b49849 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -145,14 +145,22 @@ $filterWidgetArray = array( 'filterKurzbz' => 'LehrauftragOrder', 'requiredPermissions' => 'lehre', // TODO: change permission 'datasetRepresentation' => 'tabulator', + 'reloadDataset' => true, // reload query on page refresh 'customMenu' => false, 'hideOptions' => true, 'hideMenu' => true, 'columnsAliases' => array( // TODO: use phrasen + 'id', 'LE-ID', + 'LV-ID', + 'PA-ID', + 'Studiensemester', + 'Studiengang', + 'Person-ID', ucfirst($this->p->t('global', 'typ')), 'Auftrag', 'Organisationseinheit', + 'lv_oe_kurzbz', 'Gruppe', 'Lektor', 'Stunden', @@ -175,21 +183,32 @@ $filterWidgetArray = array( selectable: true, // allows row selection selectableRangeMode: "click", // allows range selection using shift end click on end of range selectablePersistence:false, // deselect previously selected rows when table is filtered, sorted or paginated + selectableCheck: function(row){ // only allow selection if is not bestellt (as order already exists) + return row.getData().Bestellt == null; + }, movableColumns: true, // allows changing column headerFilterPlaceholder: " " }', // tabulator properties 'datasetRepFieldsDefs' => '{ + id: {visible:false}, // necessary for row indexing LE_ID: {headerFilter:"input", bottomCalc:"count"}, + LV_ID: {visible: false}, + PA_ID: {visible: false}, + Studiensemester: {visible: false}, + studiengang_kz: {visible: false}, + Person_ID: {visible: false}, Typ: {headerFilter:"input"}, Auftrag: {headerFilter:"input"}, Organisationseinheit: {headerFilter:"input"}, + lv_oe_kurzbz: {visible: false}, Gruppe: {headerFilter:"input"}, Lektor: {headerFilter:"input"}, Stunden: {align:"right", headerFilter:"input", bottomCalc:"sum", bottomCalcParams:{precision:1}}, - Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc:">=", bottomCalc:"sum", bottomCalcParams:{precision:2}}, - Bestellt: {align:"center", headerFilter:"input"}, - Erteilt: {align:"center", headerFilter:"input"}, - Akzeptiert: {align:"center", headerFilter:"input"} + Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc: hf_compareWithFloat, + bottomCalc:"sum", bottomCalcParams:{precision:2}, bottomCalcFormatter:"money", bottomCalcFormatterParams:{decimal: ",", thousand: ".", symbol:"€"}}, + Bestellt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, + Erteilt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, + Akzeptiert: {align:"center", headerFilter:"input", mutator: mut_formatStringDate} }', // col properties ); From 8efb6035c927e4dac41a5c595808e6d1293f10bc Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Thu, 12 Sep 2019 17:36:40 +0200 Subject: [PATCH 158/500] =?UTF-8?q?Mitarbeiter=20Defaultwert=20f=C3=BCr=20?= =?UTF-8?q?Fixangestellt=20und=20Aliasgenerierung=20ist=20konfiguriertbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/global.config-default.inc.php | 6 +++++ vilesci/personen/import/mitarbeiterimport.php | 26 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/config/global.config-default.inc.php b/config/global.config-default.inc.php index d2a3801f0..fa131a8aa 100644 --- a/config/global.config-default.inc.php +++ b/config/global.config-default.inc.php @@ -9,6 +9,9 @@ define('DEFAULT_LEHREINHEIT_LEHRFORM','UE'); // Defaul Trennzeichen fuer E-Mail Empfaenger wenn nicht ueber Variablen ueberschrieben define('DEFAULT_EMAILADRESSENTRENNZEICHEN',','); +// Gibt an ob neue Mitarbeiter per default fixangestellt sind oder nicht +define('DEFAULT_MITARBEITER_FIXANGESTELLT', true); + //Anzeigeoptionen für Lehrveranstaltungen im CIS define('CIS_LEHRVERANSTALTUNG_NEWSGROUPS_ANZEIGEN',true); define('CIS_LEHRVERANSTALTUNG_FEEDBACK_ANZEIGEN',true); @@ -196,6 +199,9 @@ define('SET_UID_AS_PERSONENKENNZEICHEN',false); // Legt fest ob fuer Studierende eine Alias EMail Adresse generiert wird (true|false) define('GENERATE_ALIAS_STUDENT',true); +// gibt an ob beim Anlegen von Mitarbeitern ein Alias generiert wird. +define('GENERATE_ALIAS_MITARBEITERIN',true); + // Wie viele Tage nach Semesterstart soll bei der Neuanlage von Studierenden noch das aktuelle Semester vorgeschlagen werden. define('VILESCI_PERSON_NEU_STUDIENSEMESTER_UEBERGANGSFRIST',30); diff --git a/vilesci/personen/import/mitarbeiterimport.php b/vilesci/personen/import/mitarbeiterimport.php index 561323795..7707c19f6 100644 --- a/vilesci/personen/import/mitarbeiterimport.php +++ b/vilesci/personen/import/mitarbeiterimport.php @@ -46,7 +46,7 @@ function getGemeindeDropDown($postleitzahl) $found=false; $firstentry=''; $gemeinde_x = (isset($_REQUEST['gemeinde'])?$_REQUEST['gemeinde']:''); - $qry = "SELECT distinct name FROM bis.tbl_gemeinde WHERE plz='".addslashes($postleitzahl)."'"; + $qry = "SELECT distinct name FROM bis.tbl_gemeinde WHERE plz=".$db->db_add_param($postleitzahl); echo ''; if(is_numeric($postleitzahl) && $postleitzahl<10000) { @@ -473,7 +473,10 @@ $fixangestellt = (isset($_POST['fixangestellt'])?true:false); if(!isset($_POST['svnr'])) { $lektor = true; - $fixangestellt = true; + if(defined('DEFAULT_MITARBEITER_FIXANGESTELLT') && DEFAULT_MITARBEITER_FIXANGESTELLT) + $fixangestellt = true; + else + $fixangestellt = false; } $ersatzkennzeichen = (isset($_POST['ersatzkennzeichen'])?$_POST['ersatzkennzeichen']:''); @@ -516,7 +519,7 @@ if(isset($_POST['save'])) else { $zugangscode = substr(md5(openssl_random_pseudo_bytes(20)), 0, 15); - + $person->new = true; $person->anrede = $anrede; $person->titelpre = $titel; @@ -617,7 +620,10 @@ if(isset($_POST['save'])) $benutzer->person_id = $person->person_id; $benutzer->bnaktiv = true; $benutzer->aktiv = true; - $benutzer->alias = $alias; + if (!defined('GENERATE_ALIAS_MITARBEITERIN') || GENERATE_ALIAS_MITARBEITERIN ) + { + $benutzer->alias = $alias; + } $benutzer->insertamum=date('Y-m-d H:i:s'); $benutzer->insertvon = $user; $benutzer->aktivierungscode = generateActivationKey(); @@ -949,7 +955,7 @@ if($vorname!='' && $nachname!='') { if($where!='') $where.=' OR'; - $where.=" (LOWER(vorname)=LOWER('".$vorname."') AND LOWER(nachname)=LOWER('".$nachname."'))"; + $where.=" (LOWER(vorname)=LOWER('".$db->db_escape($vorname)."') AND LOWER(nachname)=LOWER('".$db->db_escape($nachname)."'))"; } if($where!='') @@ -963,11 +969,11 @@ if($where!='') while($row = $db->db_fetch_object($result)) { $status = ''; - $qry_stati = "SELECT 'Mitarbeiter' as rolle FROM campus.vw_mitarbeiter WHERE person_id='$row->person_id' + $qry_stati = "SELECT 'Mitarbeiter' as rolle FROM campus.vw_mitarbeiter WHERE person_id=".$db->db_add_param($row->person_id)." UNION - SELECT (get_rolle_prestudent(prestudent_id, null) || ' ' || UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz)) as rolle FROM public.tbl_prestudent JOIN public.tbl_studiengang USING(studiengang_kz) WHERE person_id='$row->person_id' + SELECT (get_rolle_prestudent(prestudent_id, null) || ' ' || UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz)) as rolle FROM public.tbl_prestudent JOIN public.tbl_studiengang USING(studiengang_kz) WHERE person_id=".$db->db_add_param($row->person_id)." UNION - SELECT 'PreInteressent' as rolle FROM public.tbl_preinteressent WHERE person_id='$row->person_id'"; + SELECT 'PreInteressent' as rolle FROM public.tbl_preinteressent WHERE person_id=".$db->db_add_param($row->person_id); if($result_stati = $db->db_query($qry_stati)) { while($row_stati = $db->db_fetch_object($result_stati)) @@ -977,7 +983,7 @@ if($where!='') } $status = mb_substr($status, 0, mb_strlen($status)-2); echo '
    '; - echo ''; + echo ''; //Projektphase - echo ' - - '; - echo ''; + echo ''; } if ($za_simple == 0) From 3938000cfc1fb93693f20da1cb1eb91096165c59 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:05:22 +0200 Subject: [PATCH 215/500] =?UTF-8?q?Changed=20K=C3=BCrzel=20for=20Studienga?= =?UTF-8?q?ng-Dropdown-Widget=20to=20upper(typ||kurzbz)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/widgets/Studiengang_widget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/widgets/Studiengang_widget.php b/application/widgets/Studiengang_widget.php index a8b98dcda..360992b38 100644 --- a/application/widgets/Studiengang_widget.php +++ b/application/widgets/Studiengang_widget.php @@ -8,7 +8,7 @@ class Studiengang_widget extends DropdownWidget $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); $this->StudiengangModel->addOrder('kurzbzlang'); - $this->addSelectToModel($this->StudiengangModel, 'studiengang_kz', '\'(\' || kurzbzlang || \') \' || tbl_studiengang.bezeichnung'); + $this->addSelectToModel($this->StudiengangModel, 'studiengang_kz', '\'(\' || upper(typ||kurzbz) || \') \' || tbl_studiengang.bezeichnung'); // If 'studiengang' (array of specific studiengaenge) is given, retrieve these studiengaenge only if (isset($widgetData['studiengang']) && !empty($widgetData['studiengang'])) From fd0eaaa366d0d53ac66297c806bd1271d6a0b29f Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:11:04 +0200 Subject: [PATCH 216/500] Fixed: SQL subquery to only return one row The subquery was sometimes returning more rows causing error message. This is fixed now. --- application/views/lehre/lehrauftrag/acceptLehrauftragData.php | 3 ++- application/views/lehre/lehrauftrag/approveLehrauftragData.php | 3 ++- application/views/lehre/lehrauftrag/lehrauftragData.php | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index 716dbfa98..8f8da50a1 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -123,7 +123,8 @@ FROM public.tbl_benutzer WHERE person_id = tmp_projektbetreuung.person_id - AND aktiv = TRUE) AS "mitarbeiter_uid", + ORDER BY aktiv DESC, updateaktivam DESC -- accept inactive as some person_ids have no active, but order them last + LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index 26cb25815..c799fc99e 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -122,7 +122,8 @@ FROM public.tbl_benutzer WHERE person_id = tmp_projektbetreuung.person_id - AND aktiv = TRUE) AS "mitarbeiter_uid", + ORDER BY aktiv DESC, updateaktivam DESC -- accept inactive as some person_ids have no active, but order them last + LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 0945693f5..13f4fa251 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -122,7 +122,8 @@ FROM public.tbl_benutzer WHERE person_id = tmp_projektbetreuung.person_id - AND aktiv = TRUE) AS "mitarbeiter_uid", + ORDER BY aktiv DESC, updateaktivam DESC -- accept inactive as some person_ids have no active, but order them last + LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, From 6b29461e06054f24f8e57c86fea9cc4dffc64d19 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:16:48 +0200 Subject: [PATCH 217/500] Added empty password field --- application/views/lehre/lehrauftrag/acceptLehrauftrag.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php index cea417c65..af0b25d30 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php @@ -164,6 +164,8 @@ $(function() { var selected_data = $('#filterTabulator').tabulator('getSelectedData'); if (selected_data.length == 0) { + // Emtpy password field + $("#password").val(''); FHC_DialogLib.alertInfo('Bitte wählen Sie erst zumindest einen Lehrauftrag'); return; } @@ -207,6 +209,10 @@ $(function() { } } ); + + // Empty password field + $("#password").val(''); + }); }); From 998e906ad347a075b1123cd2fccd5de70e662ff3 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:20:05 +0200 Subject: [PATCH 218/500] Fixed: made row unselectable after updating the row Changed command to work with our actual jquery version. --- .../views/lehre/lehrauftrag/acceptLehrauftragData.php | 2 +- .../views/lehre/lehrauftrag/approveLehrauftragData.php | 2 +- application/views/lehre/lehrauftrag/lehrauftragData.php | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index 8f8da50a1..5be75964a 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -270,7 +270,7 @@ $filterWidgetArray = array( { // deselect and disable new selection of updated rows (approvement done) row.deselect(); - row.getElement().off("click"); + row.getElement().style["pointerEvents"] = "none"; }, rowFormatter:function(row) { diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index c799fc99e..b3672e9b4 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -269,7 +269,7 @@ $filterWidgetArray = array( { // deselect and disable new selection of updated rows (approvement done) row.deselect(); - row.getElement().off("click"); + row.getElement().style["pointerEvents"] = "none"; }, rowFormatter:function(row) { diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 13f4fa251..030ccd7ca 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -267,9 +267,9 @@ $filterWidgetArray = array( }, rowUpdated:function(row) { - // deselect and disable new selection of updated rows (ordering done) - row.deselect(); - row.getElement().off("click"); + // deselect and disable new selection of updated rows (ordering done) + row.deselect(); + row.getElement().style["pointerEvents"] = "none"; }, rowFormatter:function(row) { From 04ac4f55fd913c54f91bcf5bbd61674c04b11915 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:22:04 +0200 Subject: [PATCH 219/500] Removed groupBy option of tabulator This was decided for better usability. --- application/views/lehre/lehrauftrag/approveLehrauftragData.php | 1 - application/views/lehre/lehrauftrag/lehrauftragData.php | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index b3672e9b4..8b35ae235 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -254,7 +254,6 @@ $filterWidgetArray = array( layout: "fitColumns", // fit columns to width of table responsiveLayout: "hide", // hide columns that dont fit on the table movableColumns: true, // allows changing column - groupBy: "lektor", // collapsable groups headerFilterPlaceholder: " ", index: "row_index", // assign specific column as unique id (important for row indexing) selectable: true, // allow row selection diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 030ccd7ca..a43ec6b9d 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -253,8 +253,7 @@ $filterWidgetArray = array( height: 700, layout:"fitColumns", // fit columns to width of table responsiveLayout:"hide", // hide columns that dont fit on the table - movableColumns: true, // allows changing column - groupBy: "lektor", // collapsable groups + movableColumns: true, // allows changing column headerFilterPlaceholder: " ", index: "row_index", // assign specific column as unique id (important for row indexing) selectable: true, // allows row selection From df12a9aa5d410025776f37ce301cd94935b11177 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 14:25:24 +0200 Subject: [PATCH 220/500] Changed button show-accepted to show-approved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes more sense for lectures to show only approved lehraufträge by one click to be then able to accept them. --- .../views/lehre/lehrauftrag/acceptLehrauftrag.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php index af0b25d30..eb70cad99 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php @@ -68,8 +68,8 @@ $this->load->view(
    + -
    @@ -148,11 +148,11 @@ $(function() { }); // Show only rows with akzeptierte lehrauftraege - $("#show-accepted").click(function(){ + $("#show-approved").click(function(){ $('#filterTabulator').tabulator('setFilter', [ - {field: 'bestellt', type: '!=', value: null}, // filter by bestellt must be set - {field: 'erteilt', type: '!=', value: null}, // and erteilt must be set - {field: 'akzeptiert', type: '!=', value: null} // and akzeptiert must be set + {field: 'bestellt', type: '!=', value: null}, // filter when is bestellt + {field: 'erteilt', type: '!=', value: null}, // and is erteilt + {field: 'akzeptiert', type: '=', value: null} // and is not akzeptiert ] ); }); From 6ff2f19c56ace984cbb4f64d6fd03e0c49fb607f Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 15:08:33 +0200 Subject: [PATCH 221/500] =?UTF-8?q?Changed=20the=20STG-K=C3=BCrzel=20to=20?= =?UTF-8?q?'typ=20+=20kurzbz'=20in=20Lehrauftr=C3=A4ge=20+=20Vertragsmodel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the organisational unit was set, but it should be a combination of typ + kurzbz of the stg. This is changed now in . all Lehraufträge . Vertragsmodel . filtersupdate --- application/models/accounting/Vertrag_model.php | 8 ++++---- .../lehre/lehrauftrag/acceptLehrauftragData.php | 12 ++++++------ .../lehre/lehrauftrag/approveLehrauftragData.php | 12 ++++++------ ...{lehrauftragData.php => orderLehrauftragData.php} | 12 ++++++------ system/filtersupdate.php | 6 +++--- 5 files changed, 25 insertions(+), 25 deletions(-) rename application/views/lehre/lehrauftrag/{lehrauftragData.php => orderLehrauftragData.php} (96%) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index 008d3ffab..1b71e583a 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -243,13 +243,13 @@ class Vertrag_model extends DB_Model * Example: WS2017-BEE3-LIA-LAB * @param $lehrveranstaltung_id * @param $studiensemester_kurzbz Studiensemester of Lehrauftrag (= when the lector will teach the lehrveranstaltung) - * @return string + * @return string Returns e.g. WS2017-BBE5-GAP-LAB */ private function _writeVertragsbezeichung($lehrveranstaltung_id, $studiensemester_kurzbz) { $bezeichnung = ''; $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); - $this->LehrveranstaltungModel->addSelect('tbl_lehrveranstaltung.semester, tbl_lehrveranstaltung.kurzbz, lehrform_kurzbz, public.tbl_studiengang.kurzbzlang'); + $this->LehrveranstaltungModel->addSelect('tbl_lehrveranstaltung.semester, tbl_lehrveranstaltung.kurzbz AS "lv_kurzbz", lehrform_kurzbz, public.tbl_studiengang.typ, public.tbl_studiengang.kurzbz'); $this->LehrveranstaltungModel->addJoin('lehre.tbl_studienplan_lehrveranstaltung', 'lehrveranstaltung_id'); $this->LehrveranstaltungModel->addJoin('lehre.tbl_studienplan', 'studienplan_id'); $this->LehrveranstaltungModel->addJoin('lehre.tbl_studienordnung', 'studienordnung_id'); @@ -259,8 +259,8 @@ class Vertrag_model extends DB_Model if (hasData($result)) { $bezeichnung = $studiensemester_kurzbz. '-'; - $bezeichnung.= $result->retval[0]->kurzbzlang. $result->retval[0]->semester. '-'; - $bezeichnung.= $result->retval[0]->kurzbz. '-'; + $bezeichnung.= strtoupper($result->retval[0]->typ. $result->retval[0]->kurzbz). $result->retval[0]->semester. '-'; + $bezeichnung.= $result->retval[0]->lv_kurzbz. '-'; $bezeichnung.= $result->retval[0]->lehrform_kurzbz; } diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index 5be75964a..551695014 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -14,7 +14,7 @@ SELECT projektarbeit_id, studiensemester_kurzbz, studiengang_kz, - stg_oe_kurzbz, + stg_typ_kurzbz, person_id, typ, auftrag, @@ -33,7 +33,7 @@ FROM SELECT *, /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -72,7 +72,7 @@ FROM NULL AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, upper(lv.lehrtyp_kurzbz) AS "typ", (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || @@ -127,7 +127,7 @@ FROM LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -166,7 +166,7 @@ FROM pa.projektarbeit_id AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || @@ -308,7 +308,7 @@ $filterWidgetArray = array( projektarbeit_id: {visible: false}, studiensemester_kurzbz: {visible: false}, studiengang_kz: {visible: false}, - stg_oe_kurzbz: {headerFilter:"input", width: "5%"}, + stg_typ_kurzbz: {headerFilter:"input", width: "5%"}, person_id: {visible: false}, typ: {headerFilter:"input", width: "7%"}, auftrag: {headerFilter:"input", width: "23%"}, diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index 8b35ae235..aab808819 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -12,7 +12,7 @@ SELECT projektarbeit_id, studiensemester_kurzbz, studiengang_kz, - stg_oe_kurzbz, + stg_typ_kurzbz, person_id, typ, auftrag, @@ -32,7 +32,7 @@ FROM SELECT *, /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -71,7 +71,7 @@ FROM NULL AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, upper(lv.lehrtyp_kurzbz) AS "typ", (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || @@ -126,7 +126,7 @@ FROM LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -165,7 +165,7 @@ FROM pa.projektarbeit_id AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || @@ -298,7 +298,7 @@ $filterWidgetArray = array( projektarbeit_id: {visible: false}, studiensemester_kurzbz: {headerFilter:"input"}, studiengang_kz: {visible: false}, - stg_oe_kurzbz: {visible: false}, + stg_typ_kurzbz: {visible: false}, person_id: {visible: false}, typ: {headerFilter:"input"}, auftrag: {headerFilter:"input"}, diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/orderLehrauftragData.php similarity index 96% rename from application/views/lehre/lehrauftrag/lehrauftragData.php rename to application/views/lehre/lehrauftrag/orderLehrauftragData.php index a43ec6b9d..44a6a6428 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/orderLehrauftragData.php @@ -12,7 +12,7 @@ SELECT projektarbeit_id, studiensemester_kurzbz, studiengang_kz, - stg_oe_kurzbz, + stg_typ_kurzbz, person_id, typ, auftrag, @@ -32,7 +32,7 @@ FROM SELECT *, /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -71,7 +71,7 @@ FROM NULL AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, upper(lv.lehrtyp_kurzbz) AS "typ", (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || @@ -126,7 +126,7 @@ FROM LIMIT 1) AS "mitarbeiter_uid", /* concatinated and aggregated gruppen */ (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + string_agg(concat(stg_typ_kurzbz, \'-\', semester, verband, gruppe, \'\n\' || gruppe_kurzbz), \', \') FROM lehre.tbl_lehreinheitgruppe @@ -165,7 +165,7 @@ FROM pa.projektarbeit_id AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, - upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", + upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz", person.person_id, \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || @@ -298,7 +298,7 @@ $filterWidgetArray = array( projektarbeit_id: {visible: false}, studiensemester_kurzbz: {headerFilter:"input"}, studiengang_kz: {visible: false}, - stg_oe_kurzbz: {visible: false}, + stg_typ_kurzbz: {visible: false}, person_id: {visible: false}, typ: {headerFilter:"input"}, auftrag: {headerFilter:"input"}, diff --git a/system/filtersupdate.php b/system/filtersupdate.php index d5e085454..b4ab93b63 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -416,7 +416,7 @@ $filters = array( {"name": "projektarbeit_id"}, {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, - {"name": "stg_oe_kurzbz"}, + {"name": "stg_typ_kurzbz"}, {"name": "person_id"}, {"name": "typ"}, {"name": "auftrag"}, @@ -453,7 +453,7 @@ $filters = array( {"name": "projektarbeit_id"}, {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, - {"name": "stg_oe_kurzbz"}, + {"name": "stg_typ_kurzbz"}, {"name": "person_id"}, {"name": "typ"}, {"name": "auftrag"}, @@ -490,7 +490,7 @@ $filters = array( {"name": "projektarbeit_id"}, {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, - {"name": "stg_oe_kurzbz"}, + {"name": "stg_typ_kurzbz"}, {"name": "person_id"}, {"name": "typ"}, {"name": "auftrag"}, From 1c3a5c395dc7a04078c32855999954d10e2b54b5 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 15:26:47 +0200 Subject: [PATCH 222/500] Added permission lehrauftrag_akzeptieren MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This permission is for lectors to accept their lehraufträge. --- system/dbupdate_3.3.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 248e52577..01b42074b 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3149,6 +3149,20 @@ if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berecht } } +// Add permission to accept lehrauftrag (lehrauftrag_akzeptieren) +if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'lehre/lehrauftrag_akzeptieren';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO system.tbl_berechtigung(berechtigung_kurzbz, beschreibung) VALUES('lehre/lehrauftrag_akzeptieren', 'Lehrauftrag akzeptieren');"; + + if(!$db->db_query($qry)) + echo 'system.tbl_berechtigung '.$db->db_last_error().'
    '; + else + echo ' system.tbl_berechtigung: Added permission for lehre/lehrauftrag_akzeptieren
    '; + } +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; From 4ad2fe7dfbfdfc75af9a48b391219d90a8bff6b2 Mon Sep 17 00:00:00 2001 From: Cris Date: Mon, 30 Sep 2019 15:27:12 +0200 Subject: [PATCH 223/500] Changed permission check: now using lehrauftrag_akzeptieren --- .../lehre/lehrauftrag/LehrauftragAkzeptieren.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php index 2b9744cb8..59184cafd 100644 --- a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php +++ b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php @@ -10,7 +10,7 @@ class LehrauftragAkzeptieren extends Auth_Controller { const APP = 'lehrauftrag'; const LEHRAUFTRAG_URI = 'lehre/lehrauftrag/LehrauftragAkzeptieren'; // URL prefix for this controller - const BERECHTIGUNG_LEHRAUFTRAG_ERTEILEN = 'lehre/lehrauftrag_erteilen'; + const BERECHTIGUNG_LEHRAUFTRAG_AKZEPTIEREN = 'lehre/lehrauftrag_akzeptieren'; private $_uid; // uid of the logged user @@ -22,8 +22,8 @@ class LehrauftragAkzeptieren extends Auth_Controller // Set required permissions parent::__construct( array( - 'index' => 'lehre:r', - 'acceptLehrauftrag' => 'lehre:rw' // TODO: check ob eigene permission? + 'index' => 'lehre/lehrauftrag_akzeptieren:r', + 'acceptLehrauftrag' => 'lehre/lehrauftrag_akzeptieren:rw' ) ); @@ -63,13 +63,6 @@ class LehrauftragAkzeptieren extends Auth_Controller */ public function index() { - // Check if user is Mitarbeiter - $result = $this->MitarbeiterModel->isMitarbeiter($this->_uid); - if (!getData($result)) - { - show_error('Fehler bei Berechtigungsprüfung'); - } - /** * Check if lectors latest active Verwendung has inkludierte Lehre * - inkludierte_lehre is null: freelancer lector -> has NO inkludierte Lehre From 15370267c6df9c7b98d62bbceb874c27c1d0f249 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 1 Oct 2019 08:14:36 +0200 Subject: [PATCH 224/500] Minor code and GUI changes . changed file name lehrauftrag to orderLehrauftrag . changed order of buttons Both for consistecy --- application/controllers/lehre/lehrauftrag/Lehrauftrag.php | 2 +- application/views/lehre/lehrauftrag/approveLehrauftrag.php | 7 +++++-- .../lehrauftrag/{lehrauftrag.php => orderLehrauftrag.php} | 5 ++--- 3 files changed, 8 insertions(+), 6 deletions(-) rename application/views/lehre/lehrauftrag/{lehrauftrag.php => orderLehrauftrag.php} (97%) diff --git a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php index 28f6ee8ec..52fec3907 100644 --- a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php +++ b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php @@ -95,7 +95,7 @@ class Lehrauftrag extends Auth_Controller 'studiensemester_selected' => $studiensemester_kurzbz ); - $this->load->view('lehre/lehrauftrag/lehrauftrag.php', $view_data); + $this->load->view('lehre/lehrauftrag/orderLehrauftrag.php', $view_data); } public function orderLehrauftrag() diff --git a/application/views/lehre/lehrauftrag/approveLehrauftrag.php b/application/views/lehre/lehrauftrag/approveLehrauftrag.php index 5ffc2adac..2e16bec82 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftrag.php @@ -84,9 +84,8 @@ $this->load->view( - - +
    @@ -165,6 +164,10 @@ $(function() { ); }); + $("#download-cvs").click(function(){ + $('#filterTabulator').tabulator("download", "csv", "data.csv"); + }); + // Approve Lehrauftraege $("#approve-lehrauftraege").click(function(){ diff --git a/application/views/lehre/lehrauftrag/lehrauftrag.php b/application/views/lehre/lehrauftrag/orderLehrauftrag.php similarity index 97% rename from application/views/lehre/lehrauftrag/lehrauftrag.php rename to application/views/lehre/lehrauftrag/orderLehrauftrag.php index 6bccaa42b..3a33bb53a 100644 --- a/application/views/lehre/lehrauftrag/lehrauftrag.php +++ b/application/views/lehre/lehrauftrag/orderLehrauftrag.php @@ -75,7 +75,7 @@ $this->load->view(
    - load->view('lehre/lehrauftrag/lehrauftragData.php'); ?> + load->view('lehre/lehrauftrag/orderLehrauftragData.php'); ?>
    @@ -84,9 +84,8 @@ $this->load->view( - - + From ac1f31f31ffc6cbaf000ef6a97a051e8c54700c2 Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 1 Oct 2019 12:46:19 +0200 Subject: [PATCH 225/500] Added possibility to have same TableWidget in more pages --- application/libraries/TableWidgetLib.php | 12 +++++++----- application/widgets/TableWidget.php | 5 +++-- public/js/TableWidget.js | 11 +++++++++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/application/libraries/TableWidgetLib.php b/application/libraries/TableWidgetLib.php index e97e0d754..009103e68 100644 --- a/application/libraries/TableWidgetLib.php +++ b/application/libraries/TableWidgetLib.php @@ -119,8 +119,6 @@ class TableWidgetLib */ public function setSession($data) { - $data[TableWidgetLib::TABLE_UNIQUE_ID] = $this->_tableUniqueId; // the unique id of this table widget - setSessionElement(self::SESSION_NAME, $this->_tableUniqueId, $data); } @@ -190,15 +188,19 @@ class TableWidgetLib && isset($params[self::TABLE_UNIQUE_ID]) && !isEmptyString($params[self::TABLE_UNIQUE_ID])) { - $this->setTableUniqueId($params[self::TABLE_UNIQUE_ID]); + $tableUniqueId = $this->_ci->router->directory.$this->_ci->router->class.'/'. + $this->_ci->router->method.'/'. + $params[self::TABLE_UNIQUE_ID]; + + $this->setTableUniqueId($tableUniqueId); } } /** * Set the _tableUniqueId property */ - public function setTableUniqueId($filterUniqueId) + public function setTableUniqueId($tableUniqueId) { - $this->_tableUniqueId = $filterUniqueId; + $this->_tableUniqueId = $tableUniqueId; } } diff --git a/application/widgets/TableWidget.php b/application/widgets/TableWidget.php index 396ca3bb3..a0f64b291 100644 --- a/application/widgets/TableWidget.php +++ b/application/widgets/TableWidget.php @@ -59,7 +59,7 @@ class TableWidget extends Widget // NOTE: If it is NOT allowed then no data are loaded if ($this->tablewidgetlib->isAllowed($this->_requiredPermissions)) { - $this->_startTableWidget(); + $this->_startTableWidget($args[TableWidgetLib::TABLE_UNIQUE_ID]); } } @@ -244,7 +244,7 @@ class TableWidget extends Widget /** * Contains all the logic used to load all the data needed to the TableWidget */ - private function _startTableWidget() + private function _startTableWidget($tableUniqueId) { // Read the all session for this table widget $session = $this->tablewidgetlib->getSession(); @@ -297,6 +297,7 @@ class TableWidget extends Widget // Stores an array that contains all the data useful for $this->tablewidgetlib->setSession( array( + TableWidgetLib::TABLE_UNIQUE_ID => $tableUniqueId, // table unique id TableWidgetLib::SESSION_FIELDS => $this->tablewidgetlib->getExecutedQueryListFields(), // all the fields of the dataset TableWidgetLib::SESSION_COLUMNS_ALIASES => $this->_columnsAliases, // all the fields aliases TableWidgetLib::SESSION_ADDITIONAL_COLUMNS => $this->_additionalColumns, // additional columns diff --git a/public/js/TableWidget.js b/public/js/TableWidget.js index 44e66cabd..89e7cf3d5 100644 --- a/public/js/TableWidget.js +++ b/public/js/TableWidget.js @@ -42,6 +42,14 @@ var FHC_TableWidget = { //------------------------------------------------------------------------------------------------------------------ // Private methods + /** + * To retrive the page where the TableWidget is used, using the FHC_JS_DATA_STORAGE_OBJECT + */ + _getTableUniqueIdPrefix: function() { + + return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method; + }, + /** * Utility method that checks if data contains an error and print that to the console * otherwise the TableWidget GUI is refreshed @@ -109,11 +117,10 @@ var FHC_TableWidget = { for (var tableWidgetsCounter = 0; tableWidgetsCounter < tableWidgetUniqueIdArray.length; tableWidgetsCounter++) { - FHC_AjaxClient.ajaxCallGet( "widgets/Tables/getTable", { - tableUniqueId: tableWidgetUniqueIdArray[tableWidgetsCounter] + tableUniqueId: FHC_TableWidget._getTableUniqueIdPrefix() + "/" + tableWidgetUniqueIdArray[tableWidgetsCounter] }, { successCallback: function(data, textStatus, jqXHR) { From dfe4e3d82c4e34360c72be0fb62ffb3c64186bc3 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 1 Oct 2019 14:28:15 +0200 Subject: [PATCH 226/500] Embedded into FH-Complete Navigation . Added navigation items to top and left side menu for Lehrauftraege bestellen and Lehrauftraege erteilen. . Added NavigationWidget to views. --- application/config/navigation.php | 41 +++++++++++++++++++ .../lehre/lehrauftrag/approveLehrauftrag.php | 5 ++- .../lehre/lehrauftrag/orderLehrauftrag.php | 7 ++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/application/config/navigation.php b/application/config/navigation.php index d6f4b8452..306728657 100644 --- a/application/config/navigation.php +++ b/application/config/navigation.php @@ -51,6 +51,13 @@ $config['navigation_header'] = array( 'sort' => 30, 'requiredPermissions' => 'infocenter:r' ), + 'lehrauftrag' => array( + 'link' => site_url('lehre/lehrauftrag/Lehrauftrag'), + 'description' => 'Lehrauftrag', + 'expand' => true, + 'sort' => 40, + 'requiredPermissions' => 'lehre:r' + ) ) ), 'Personen' => array( @@ -118,3 +125,37 @@ $config['navigation_menu']['organisation/Reihungstest/index'] = array( 'target' => '_blank' ) ); + +$config['navigation_menu']['lehre/lehrauftrag/Lehrauftrag/index'] = array( + 'lehrauftragBestellen' => array( + 'link' => site_url('lehre/lehrauftrag/Lehrauftrag'), + 'description' => 'Lehrauftrag bestellen', + 'icon' => '', + 'sort' => 1, + 'target' => '_blank' + ), + 'lehrauftragErteilen' => array( + 'link' => site_url('lehre/lehrauftrag/LehrauftragErteilen'), + 'description' => 'Lehrauftrag erteilen', + 'icon' => '', + 'sort' => 1, + 'target' => '_blank' + ) +); + +$config['navigation_menu']['lehre/lehrauftrag/LehrauftragErteilen/index'] = array( + 'lehrauftragBestellen' => array( + 'link' => site_url('lehre/lehrauftrag/Lehrauftrag'), + 'description' => 'Lehrauftrag bestellen', + 'icon' => '', + 'sort' => 1, + 'target' => '_blank' + ), + 'lehrauftragErteilen' => array( + 'link' => site_url('lehre/lehrauftrag/LehrauftragErteilen'), + 'description' => 'Lehrauftrag erteilen', + 'icon' => '', + 'sort' => 1, + 'target' => '_blank' + ) +); diff --git a/application/views/lehre/lehrauftrag/approveLehrauftrag.php b/application/views/lehre/lehrauftrag/approveLehrauftrag.php index 2e16bec82..c23f58512 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftrag.php @@ -18,7 +18,6 @@ $this->load->view( 'phrases' => array( 'global' => array('lehrauftraege'), ), - 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', 'customJSs' => array('public/js/bootstrapper.js') ) ); @@ -26,7 +25,9 @@ $this->load->view( ?> -
    + widgetlib->widget('NavigationWidget'); ?> + +
    diff --git a/application/views/lehre/lehrauftrag/orderLehrauftrag.php b/application/views/lehre/lehrauftrag/orderLehrauftrag.php index 3a33bb53a..07332dead 100644 --- a/application/views/lehre/lehrauftrag/orderLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/orderLehrauftrag.php @@ -19,15 +19,16 @@ $this->load->view( 'phrases' => array( 'global' => array('lehrauftraege'), ), - 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', 'customJSs' => array('public/js/bootstrapper.js') ) ); ?> -
    -
    + widgetlib->widget('NavigationWidget'); ?> +
    +
    +
    '."$row->nachname$row->vorname$row->vornamen$row->gebdatum$row->svnr".($row->geschlecht=='m'?'männlich':'weiblich').""; - $qry_adr = "SELECT * FROM public.tbl_adresse WHERE person_id='$row->person_id'"; + $qry_adr = "SELECT * FROM public.tbl_adresse WHERE person_id=".$db->db_add_param($row->person_id); if($result_adr = $db->db_query($qry_adr)) while($row_adr=$db->db_fetch_object($result_adr)) echo "$row_adr->plz $row_adr->ort, $row_adr->strasse
    "; From 123fef945f01ed137a8fbbed3f2b05c73b631082 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 12 Sep 2019 18:10:36 +0200 Subject: [PATCH 159/500] - copied pivot.de.js pivottable language file from reporting addon to public folder --- public/js/pivottable/pivot.de.js | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 public/js/pivottable/pivot.de.js diff --git a/public/js/pivottable/pivot.de.js b/public/js/pivottable/pivot.de.js new file mode 100644 index 000000000..855b6e430 --- /dev/null +++ b/public/js/pivottable/pivot.de.js @@ -0,0 +1,76 @@ +(function() { + var callWithJQuery; + + callWithJQuery = function(pivotModule) { + if (typeof exports === "object" && typeof module === "object") { + return pivotModule(require("jquery")); + } else if (typeof define === "function" && define.amd) { + return define(["jquery"], pivotModule); + } else { + return pivotModule(jQuery); + } + }; + callWithJQuery(function($) { + var deFmt, deFmtInt, deFmtPct, nf, tpl; + nf = $.pivotUtilities.numberFormat; + tpl = $.pivotUtilities.aggregatorTemplates; + deFmt = nf({ + thousandsSep: ".", + decimalSep: "," + }); + deFmtInt = nf({ + digitsAfterDecimal: 0, + thousandsSep: ".", + decimalSep: "," + }); + deFmtPct = nf({ + digitsAfterDecimal: 1, + scaler: 100, + suffix: "%", + thousandsSep: ".", + decimalSep: "," + }); + return $.pivotUtilities.locales.de = { + localeStrings: { + renderError: "Bei dem Zeichnen der Pivot Ergebnisse ist ein Fehler aufgetreten.", + computeError: "Bei dem berechnen der Pivot Ergebnisse ist ein Fehler aufgetreten.", + uiRenderError: "Bei dem Zeichnen des Pivot Interfaces ist ein Fehler aufgetreten.", + selectAll: "Wähle alle", + selectNone: "Wähle keine", + tooMany: "(zu viele Ergebnisse)", + filterResults: "Ergebnisse filtern", + totals: "Total", + vs: "vs", + by: "von" + }, + aggregators: { + "Anzahl": tpl.count(deFmtInt), + "Anzahl einzigartiger Werte": tpl.countUnique(deFmtInt), + "Liste einzigartiger Werte": tpl.listUnique(", "), + "Summe": tpl.sum(deFmt), + "Summe in ganzen Zahlen": tpl.sum(deFmtInt), + "Durchschnitt": tpl.average(deFmt), + "Summe über Summe": tpl.sumOverSum(deFmt), + "80% obere Grenze": tpl.sumOverSumBound80(true, deFmt), + "80% untere Grenze": tpl.sumOverSumBound80(false, deFmt), + "Prozent": tpl.fractionOf(tpl.sum(), "total", deFmtPct), + "Prozent pro Reihe": tpl.fractionOf(tpl.sum(), "row", deFmtPct), + "Prozent pro Spalte": tpl.fractionOf(tpl.sum(), "col", deFmtPct), + "Anzahl als Teil des Ganzen": tpl.fractionOf(tpl.count(), "total", deFmtPct), + "Anzahl als Teil der Reihe": tpl.fractionOf(tpl.count(), "row", deFmtPct), + "Anzahl als Teil der Spalte": tpl.fractionOf(tpl.count(), "col", deFmtPct) + }, + renderers: { + "Tabelle": $.pivotUtilities.renderers["Table"], + "Tabelle mit Balken": $.pivotUtilities.renderers["Table Barchart"], + "Heatmap": $.pivotUtilities.renderers["Heatmap"], + "Heatmap für Reihen": $.pivotUtilities.renderers["Row Heatmap"], + "Heatmap für Spalten": $.pivotUtilities.renderers["Col Heatmap"] + } + }; + }); + +}).call(this); + + +//# sourceMappingURL=pivot.de.js.map From 4181893fdde4f0c011fab3128852bb481b85dfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 12 Sep 2019 19:19:50 +0200 Subject: [PATCH 160/500] =?UTF-8?q?Hinweistext=20hinzugef=C3=BCgt=20wenn?= =?UTF-8?q?=20bei=20der=20Kartenverwaltung=20zu=20viele=20Eintr=C3=A4ge=20?= =?UTF-8?q?gew=C3=A4hlt=20werden=20da=20es=20vorkommen=20kann=20dass=20dad?= =?UTF-8?q?urch=20die=20maximale=20Anzahl=20an=20POST=20Parametern=20?= =?UTF-8?q?=C3=BCberschritten=20wird=20und=20das=20Speichern=20der=20Daten?= =?UTF-8?q?=20nicht=20korrekt=20funktioniert.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vilesci/fhausweis/kartenverwaltung.php | 129 ++++++++++++++----------- vilesci/fhausweis/kartezuweisen.php | 40 +++++--- 2 files changed, 101 insertions(+), 68 deletions(-) diff --git a/vilesci/fhausweis/kartenverwaltung.php b/vilesci/fhausweis/kartenverwaltung.php index a1114e8b7..7a98326af 100644 --- a/vilesci/fhausweis/kartenverwaltung.php +++ b/vilesci/fhausweis/kartenverwaltung.php @@ -35,32 +35,32 @@ $uid = get_uid(); $rechte = new benutzerberechtigung(); $rechte->getBerechtigungen($uid); -define("anzahlSemester","10"); +define("anzahlSemester","10"); $buchstabenArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','Ä','Ö','Ü'); -$studiengang = new studiengang(); +$studiengang = new studiengang(); $studiengang->getAll('typ, bezeichnung', true); $studiengang_array = array(); -$fotostatus = new fotostatus(); +$fotostatus = new fotostatus(); $fotostatus->getAllStatusKurzbz(); $mails = array(); $variable = new variable(); $variable->loadVariables($uid); - + $statusStudent=(isset($_REQUEST['select_statusStudent'])?$_REQUEST['select_statusStudent']:null); $statusMitarbeiter=(isset($_REQUEST['select_statusMitarbeiter'])?$_REQUEST['select_statusMitarbeiter']:null); $typMitarbeiter =(isset($_REQUEST['select_typ_mitarbeiter'])?$_REQUEST['select_typ_mitarbeiter']:null); $studiengang_kz=(isset($_REQUEST['select_studiengang'])?$_REQUEST['select_studiengang']:null); -$semester=(isset($_REQUEST['select_semester'])?$_REQUEST['select_semester']:null); +$semester=(isset($_REQUEST['select_semester'])?$_REQUEST['select_semester']:null); $buchstabe=(isset($_REQUEST['select_buchstabe'])?$_REQUEST['select_buchstabe']:null); $studSemArray=(isset($_REQUEST['select_studiensemester'])?$_REQUEST['select_studiensemester']:array()); if (empty($studSemArray)) { $studiensemester = new studiensemester(); - + $studSemArray[]=$studiensemester->getakt(); $studSemArray[]=$studiensemester->getPrevious(); $studSemArray[]=$studiensemester->getBeforePrevious(); @@ -83,15 +83,15 @@ if (empty($studSemArray)) - + + FH-Ausweis Kartenverwaltung -isBerechtigt('basis/fhausweis', 'suid')) die('Sie haben keine Berechtigung für diese Seite'); @@ -142,7 +142,7 @@ echo ' echo'
    Semester: @@ -218,7 +218,7 @@ if(isset($_REQUEST['btn_submitStudent'])) $uids = ''; if($semester == 'alle') $semester = null; - + $studenten = new student(); $studentenArray = array(); @@ -246,8 +246,8 @@ if(isset($_REQUEST['btn_submitStudent'])) { $studenten->getStudentsStudiengang($studiengang_kz, $semester); } - $studentenArray = $studenten->result; - + $studentenArray = $studenten->result; + echo '
    Typ:
    @@ -262,16 +262,16 @@ if(isset($_REQUEST['btn_submitStudent'])) '; - + if (count($studentenArray) > 0) { foreach($studentenArray as $stud) { //if($stud->studiengang_kz>10000 && $stud->studiengang_kz !='10007' && $stud->studiengang_kz!='10004') //continue; - + // Wenn letzter Status nicht Student ist -> nicht anzeigen - $prestudent = new prestudent(); + $prestudent = new prestudent(); $prestudent->getLastStatus($stud->prestudent_id); if(($prestudent->status_kurzbz == 'Student' || ($studiengang_kz=='incoming' && $prestudent->status_kurzbz='Incoming')) && array_key_exists($stud->studiengang_kz, $studiengang_array)) { @@ -279,9 +279,9 @@ if(isset($_REQUEST['btn_submitStudent'])) { // gedruckt aber noch nicht ausgegeben $fotostatus = new fotostatus(); - $fotostatus->getLastFotoStatus($stud->person_id); - $betriebsmittel = new betriebsmittel(); - + $fotostatus->getLastFotoStatus($stud->person_id); + $betriebsmittel = new betriebsmittel(); + // status akzeptiert und noch nicht gedruckt if($fotostatus->fotostatus_kurzbz == 'akzeptiert' && $betriebsmittel->zutrittskartePrinted($stud->uid) == true && $betriebsmittel->zutrittskarteAusgegeben($stud->uid) == false) { @@ -294,9 +294,9 @@ if(isset($_REQUEST['btn_submitStudent'])) { // akzeptiert und nicht gedruckt $fotostatus = new fotostatus(); - $fotostatus->getLastFotoStatus($stud->person_id); - $betriebsmittel = new betriebsmittel(); - + $fotostatus->getLastFotoStatus($stud->person_id); + $betriebsmittel = new betriebsmittel(); + // status akzeptiert und noch nicht gedruckt if($fotostatus->fotostatus_kurzbz == 'akzeptiert' && $betriebsmittel->zutrittskartePrinted($stud->uid) == false) { @@ -309,9 +309,9 @@ if(isset($_REQUEST['btn_submitStudent'])) { // akzeptiert und nicht gedruckt $fotostatus = new fotostatus(); - $fotostatus->getLastFotoStatus($stud->person_id); - $betriebsmittel = new betriebsmittel(); - + $fotostatus->getLastFotoStatus($stud->person_id); + $betriebsmittel = new betriebsmittel(); + // noch nicht gedruckt if($betriebsmittel->zutrittskartePrinted($stud->uid) == false) { @@ -324,8 +324,8 @@ if(isset($_REQUEST['btn_submitStudent'])) { // letzten Status anzeigen $fotostatus = new fotostatus(); - $fotostatus->getLastFotoStatus($stud->person_id); - + $fotostatus->getLastFotoStatus($stud->person_id); + // überprüfen ob letzer Status der gesuchte ist if($fotostatus->fotostatus_kurzbz == $statusStudent) { @@ -342,7 +342,7 @@ if(isset($_REQUEST['btn_submitStudent'])) echo " Kartentausch - + }); + }); + +

    Zutrittskarte - Zuweisen der Karte

    '; +function printWarning() +{ + echo '
    + ACHTUNG - Es wurde eine große Datenmenge geschickt.
    + Daten wurden eventuell nicht vollständig gespeichert.
    + Bitte wähle einzelne Studiengänge aus um die Daten einzutragen.
    +
    '; + +} if(!$rechte->isBerechtigt('basis/fhausweis', 'suid')) die('Sie haben keine Berechtigung für diese Seite'); @@ -76,8 +85,13 @@ if(isset($_GET['data'])) { $users = explode(';',$_GET['data']); } +if(count($_POST)>700) +{ + printWarning(); +} if(isset($_POST['save']) && $users!='') { + var_dump($users); foreach($users as $user) { $benutzer = new benutzer(); @@ -85,7 +99,7 @@ if(isset($_POST['save']) && $users!='') { $nummer1 = $_POST['nummer1_'.$user]; $nummer2 = $_POST['nummer2_'.$user]; - + if($nummer1=='' || $nummer2=='') { echo 'Ueberspringe '.$db->convert_html_chars($user).' - keine Nummer eingetragen'; @@ -101,10 +115,10 @@ if(isset($_POST['save']) && $users!='') $bm->updateamum = date('Y-m-d H:i:s'); $bm->updatevon = $uid; $bm->reservieren=false; - + if($bm->save(true)) { - + //Zuordnung zu Benutzer anlegen $bmp = new betriebsmittelperson(); $bmp->betriebsmittel_id = $bm->betriebsmittel_id; @@ -134,10 +148,12 @@ if(isset($_POST['save']) && $users!='') } } } - if($users!='') { - + if(count($users)>500) + { + printWarning(); + } echo ' Karte gleich als Ausgegeben eintragen:
    @@ -182,4 +198,4 @@ else } echo ''; -?> \ No newline at end of file +?> From bf8b7e0ccd972f83118fc73c065c39d8456dbf0d Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 16 Sep 2019 14:00:51 +0200 Subject: [PATCH 161/500] Added JobsViewer --- application/controllers/system/JobsViewer.php | 44 +++++++++++++ application/views/system/jobs/jobsViewer.php | 47 +++++++++++++ .../views/system/jobs/jobsViewerData.php | 66 +++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 application/controllers/system/JobsViewer.php create mode 100644 application/views/system/jobs/jobsViewer.php create mode 100644 application/views/system/jobs/jobsViewerData.php diff --git a/application/controllers/system/JobsViewer.php b/application/controllers/system/JobsViewer.php new file mode 100644 index 000000000..2fdfa7181 --- /dev/null +++ b/application/controllers/system/JobsViewer.php @@ -0,0 +1,44 @@ + 'admin:r' + ) + ); + + // Loads WidgetLib + $this->load->library('WidgetLib'); + + // Loads phrases system + $this->loadPhrases( + array( + 'global', + 'ui', + 'filter' + ) + ); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Main page of the InfoCenter tool + */ + public function index() + { + $this->load->view('system/jobs/jobsViewer.php'); + } +} diff --git a/application/views/system/jobs/jobsViewer.php b/application/views/system/jobs/jobsViewer.php new file mode 100644 index 000000000..f7018a272 --- /dev/null +++ b/application/views/system/jobs/jobsViewer.php @@ -0,0 +1,47 @@ +load->view( + 'templates/FHC-Header', + array( + 'title' => 'JobsViewer', + 'jquery' => true, + 'jqueryui' => true, + 'bootstrap' => true, + 'fontawesome' => true, + 'sbadmintemplate' => true, + 'tablesorter' => true, + 'ajaxlib' => true, + 'filterwidget' => true, + 'navigationwidget' => true, + 'phrases' => array( + 'global' => array('mailAnXversandt'), + 'ui' => array('bitteEintragWaehlen') + ), + 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', + 'customJSs' => array('public/js/bootstrapper.js') + ) + ); +?> + + +
    + + widgetlib->widget('NavigationWidget'); ?> + +
    +
    +
    +
    + +
    +
    +
    + load->view('system/jobs/jobsViewerData.php'); ?> +
    +
    +
    +
    + + +load->view('templates/FHC-Footer'); ?> diff --git a/application/views/system/jobs/jobsViewerData.php b/application/views/system/jobs/jobsViewerData.php new file mode 100644 index 000000000..07815c2f3 --- /dev/null +++ b/application/views/system/jobs/jobsViewerData.php @@ -0,0 +1,66 @@ + ' + SELECT wsl.webservicelog_id AS "LogId", + wsl.request_id AS "RequestId", + wsl.execute_time AS "ExecutionTime", + wsl.execute_user AS "ExecutedBy", + wsl.beschreibung AS "Description", + wsl.request_data AS "Data" + FROM system.tbl_webservicelog wsl + WHERE wsl.webservicetyp_kurzbz = \'job\' + ORDER BY wsl.execute_time DESC + ', + 'requiredPermissions' => 'admin', + 'datasetRepresentation' => 'tablesorter', + 'reloadDataset' => ($this->input->get('reloadDataset') == 'true' ? true : false), + 'columnsAliases' => array( + 'Log id', + 'Request id', + 'Execution time', + 'Executed by', + 'Producer', + 'Data' + ), + 'formatRow' => function($datasetRaw) { + + $datasetRaw->ExecutionTime = date_format(date_create($datasetRaw->ExecutionTime), 'd.m.Y H:i:s'); + + return $datasetRaw; + }, + 'markRow' => function($datasetRaw) { + + $mark = ''; + + if ($datasetRaw->RequestId == 'Cronjob error') + { + $mark = 'text-red'; + } + + if ($datasetRaw->RequestId == 'Cronjob info') + { + $mark = 'text-green'; + } + + if ($datasetRaw->RequestId == 'Cronjob warning') + { + $mark = 'text-orange'; + } + + if ($datasetRaw->RequestId == 'Cronjob debug') + { + $mark = 'text-info'; + } + + return $mark; + } + ); + + $filterWidgetArray['app'] = 'core'; + $filterWidgetArray['datasetName'] = 'jobslogs'; + $filterWidgetArray['filterKurzbz'] = 'all'; + $filterWidgetArray['filter_id'] = $this->input->get('filter_id'); + + echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); +?> From 131d031caea7692af5f520ce9a72b6aa448c8bd7 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 17 Sep 2019 10:29:24 +0200 Subject: [PATCH 162/500] - added column projektphase_id to tbl_zeitaufzeichnung --- system/dbupdate_3.3.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 4e720daef..9df2f6eff 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3030,6 +3030,18 @@ if(!$result = @$db->db_query("SELECT stufe FROM public.tbl_dokumentstudiengang L echo '
    public.tbl_dokumentstudiengang: Spalte stufe hinzugefuegt'; } +// Add column projektphase_id to tbl_zeitaufzeichnung +if(!$result = @$db->db_query("SELECT projektphase_id FROM campus.tbl_zeitaufzeichnung LIMIT 1")) +{ + $qry = "ALTER TABLE campus.tbl_zeitaufzeichnung ADD COLUMN projektphase_id bigint; + ALTER TABLE campus.tbl_zeitaufzeichnung ADD CONSTRAINT fk_zeitaufzeichnung_projektphase FOREIGN KEY (projektphase_id) REFERENCES fue.tbl_projektphase (projektphase_id) ON DELETE RESTRICT ON UPDATE CASCADE;"; + + if(!$db->db_query($qry)) + echo 'campus.tbl_zeitaufzeichnung: '.$db->db_last_error().'
    '; + else + echo '
    campus.tbl_zeitaufzeichnung: Spalte projektphase_id hinzugefuegt'; +} + // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

    Pruefe Tabellen und Attribute!

    '; From 31cb13ec14179233c3cf226fe9f44eb86e7b9e8b Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 17 Sep 2019 10:36:53 +0200 Subject: [PATCH 163/500] - Zeitaufzeichnung: Projektphase can be selected and saved for a project --- cis/private/tools/zeitaufzeichnung.php | 78 + .../tools/zeitaufzeichnung_projektphasen.php | 28 + include/zeitaufzeichnung.class.php | 1605 +++++++++-------- locale/de-AT/zeitaufzeichnung.php | 121 +- locale/en-US/zeitaufzeichnung.php | 121 +- locale/it-IT/zeitaufzeichnung.php | 1 + 6 files changed, 1034 insertions(+), 920 deletions(-) create mode 100644 cis/private/tools/zeitaufzeichnung_projektphasen.php diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index 7461f2421..df7a2bd34 100644 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -33,6 +33,7 @@ require_once('../../../include/zeitaufzeichnung.class.php'); require_once('../../../include/zeitsperre.class.php'); require_once('../../../include/datum.class.php'); require_once('../../../include/projekt.class.php'); +require_once('../../../include/projektphase.class.php'); require_once('../../../include/phrasen.class.php'); require_once('../../../include/organisationseinheit.class.php'); require_once('../../../include/service.class.php'); @@ -117,6 +118,7 @@ $sperrdatum = date('c', strtotime($gesperrt_bis)); // Uses urlencode to avoid XSS issues $zeitaufzeichnung_id = urlencode(isset($_GET['zeitaufzeichnung_id'])?$_GET['zeitaufzeichnung_id']:''); $projekt_kurzbz = (isset($_POST['projekt'])?$_POST['projekt']:''); +$projektphase_id = (isset($_POST['projektphase'])?$_POST['projektphase']:''); $oe_kurzbz_1 = (isset($_POST['oe_kurzbz_1'])?$_POST['oe_kurzbz_1']:''); $oe_kurzbz_2 = (isset($_POST['oe_kurzbz_2'])?$_POST['oe_kurzbz_2']:''); $aktivitaet_kurzbz = (isset($_POST['aktivitaet'])?$_POST['aktivitaet']:''); @@ -251,6 +253,13 @@ echo ' $("#kunde_uid").val(ui.item.uid); } }); + + $("#projekt").change( + function() + { + getProjektphasen($(this).val()); + } + ) }); @@ -489,6 +498,40 @@ echo ' } return true; } + + function getProjektphasen(projekt_kurzbz) + { + $.ajax + ( + { + type: "GET", + url: "zeitaufzeichnung_projektphasen.php", + dataType: "json", + data: + { + "projekt_kurzbz":projekt_kurzbz + }, + success: function(json) + { + $("#projektphase").children("option").each( + function() + { + if ($(this).prop("id") !== "projektphasekeineausw") + $(this).remove(); + } + ); + + var projphasenhtml = ""; + for (var i = 0; i < json.length; i++) + { + projphasenhtml += "
    + + '; + echo ''; } if ($za_simple == 0) diff --git a/cis/private/tools/zeitaufzeichnung_projektphasen.php b/cis/private/tools/zeitaufzeichnung_projektphasen.php new file mode 100644 index 000000000..8ec421395 --- /dev/null +++ b/cis/private/tools/zeitaufzeichnung_projektphasen.php @@ -0,0 +1,28 @@ +getProjektphasen($projekt_kurzbz)) + { + $result_obj = array(); + foreach($projektphase->result as $row) + { + $item['projektphase_id']=$row->projektphase_id; + $item['bezeichnung']=$row->bezeichnung; + $result_obj[]=$item; + } + echo json_encode($result_obj); + } + exit; +} diff --git a/include/zeitaufzeichnung.class.php b/include/zeitaufzeichnung.class.php index 3c99c59a4..28a9b62ff 100644 --- a/include/zeitaufzeichnung.class.php +++ b/include/zeitaufzeichnung.class.php @@ -1,800 +1,805 @@ -, - * Andreas Oesterreicher and - * Rudolf Hangl . - */ -/** - * Klasse Zeitaufzeichnung - * @create 06-11-2007 - */ -require_once(dirname(__FILE__).'/basis_db.class.php'); - -class zeitaufzeichnung extends basis_db -{ - public $new; // boolean - public $result = array(); // zeitaufzeichnung Objekt - public $done=false; // boolean - - //Tabellenspalten - public $zeitaufzeichnung_id; // serial - public $uid; // varchar(16) - public $aktivitaet_kurzbz; // varchar(16) - public $start; // timestamp - public $ende; // timestamp - public $beschreibung; // varchar(256) - public $oe_kurzbz_1; // varchar(32) ehemals studiengangs_kz - public $oe_kurzbz_2; // varchar(32) ehemals fachbereich_kurzbz - public $insertamum; // timestamp - public $insertvon; // varchar(16) - public $updateamum; // timestamp - public $updatevon; // varchar(16) - public $projekt_kurzbz; // varchar(16) - public $ext_id; // bigint - public $service_id; // integer - public $kunde_uid; // varchar(32) - - /** - * Konstruktor - * @param $zeitaufzeichnung_id ID der Zeitaufzeichnung die geladen werden soll (Default=null) - */ - public function __construct($zeitaufzeichnung_id=null) - { - parent::__construct(); - - if($zeitaufzeichnung_id != null) - $this->load($zeitaufzeichnung_id); - } - - /** - * Laedt die Zeitaufzeichnung mit der ID $zeitaufzeichnung_id - * @param $adress_id ID der zu ladenden Adresse - * @return true wenn ok, false im Fehlerfall - */ - public function load($zeitaufzeichnung_id) - { - //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist - if(!is_numeric($zeitaufzeichnung_id) || $zeitaufzeichnung_id == '') - { - $this->errormsg = 'Zeitaufzeichnung_id muss eine Zahl sein'; - return false; - } - - //Daten aus der Datenbank lesen - $qry = "SELECT * FROM campus.tbl_zeitaufzeichnung WHERE zeitaufzeichnung_id=".$this->db_add_param($zeitaufzeichnung_id, FHC_INTEGER); - - if(!$this->db_query($qry)) - { - $this->errormsg = 'Fehler bei einer Datenbankabfrage'; - return false; - } - - if($row = $this->db_fetch_object()) - { - $this->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; - $this->uid = $row->uid; - $this->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; - $this->start = $row->start; - $this->ende = $row->ende; - $this->beschreibung = $row->beschreibung; - $this->oe_kurzbz_1 = $row->oe_kurzbz_1; - $this->oe_kurzbz_2 = $row->oe_kurzbz_2; - $this->insertamum = $row->insertamum; - $this->insertvon = $row->insertvon; - $this->updateamum = $row->updateamum; - $this->updatevon = $row->updatevon; - $this->projekt_kurzbz = $row->projekt_kurzbz; - $this->ext_id = $row->ext_id; - $this->service_id = $row->service_id; - $this->kunde_uid = $row->kunde_uid; - } - else - { - $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; - return false; - } - - return true; - } - - /** - * Prueft die Variablen auf Gueltigkeit - * @return true wenn ok, false im Fehlerfall - */ - protected function validate() - { - $this->errormsg = ''; - return true; - } - - /** - * Speichert den aktuellen Datensatz in die Datenbank - * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt - * andernfalls wird der Datensatz mit der ID in $adresse_id aktualisiert - * @return true wenn ok, false im Fehlerfall - */ - public function save() - { - //Variablen pruefen - if(!$this->validate()) - return false; - - // check ob identischer eintrag existiert - // DienstreiseMT-Einträge sind hier ausgenommen da eintägige Dienstreisen mit der identen Arbeitszeit eingetragen werden könnten - if ($this->aktivitaet_kurzbz != 'DienstreiseMT') - { - $check_qry = 'SELECT count(*) from campus.tbl_zeitaufzeichnung where uid='.$this->db_add_param($this->uid).' and aktivitaet_kurzbz != \'DienstreiseMT\' and start = '.$this->db_add_param($this->start).' and ende = '.$this->db_add_param($this->ende); - if($this->db_query($check_qry) && $this->new) - { - if($row = $this->db_fetch_object()) - { - if ($row->count) - { - $this->errormsg = 'Identischer Eintrag existiert!'; - return false; - } - } - } - } - - // ER - Checks - if ($this->aktivitaet_kurzbz == 'Ersatzruhe') - { - $check_qry = "SELECT count(*) from campus.tbl_zeitaufzeichnung where uid=".$this->db_add_param($this->uid)." and (start < ".$this->db_add_param($this->ende)." and ende > ".$this->db_add_param($this->start).")"; - if ($this->zeitaufzeichnung_id) - $check_qry .= " and zeitaufzeichnung_id != ".$this->db_add_param($this->zeitaufzeichnung_id); - if($this->db_query($check_qry)) - { - if($row = $this->db_fetch_object()) - { - if ($row->count) - { - $this->errormsg = 'Ersatzruhe darf nicht Überlappen!'; - return false; - } - } - } - } - if ($this->aktivitaet_kurzbz != 'Ersatzruhe') - { - $check_qry = "SELECT count(*) from campus.tbl_zeitaufzeichnung where uid=".$this->db_add_param($this->uid)." and aktivitaet_kurzbz = 'Ersatzruhe' and (start < ".$this->db_add_param($this->ende)." and ende > ".$this->db_add_param($this->start).")"; - if($this->db_query($check_qry)) - { - if($row = $this->db_fetch_object()) - { - if ($row->count) - { - $this->errormsg = 'Eintrag darf nicht mit Ersatzruhe Überlappen!'; - return false; - } - } - } - } - - if($this->new) - { - //Neuen Datensatz einfuegen - $qry='BEGIN;INSERT INTO campus.tbl_zeitaufzeichnung (uid, aktivitaet_kurzbz, start, ende, beschreibung, - oe_kurzbz_1, oe_kurzbz_2, insertamum, insertvon, updateamum, updatevon, projekt_kurzbz, service_id, kunde_uid) VALUES('. - $this->db_add_param($this->uid).', '. - $this->db_add_param($this->aktivitaet_kurzbz).', '. - $this->db_add_param($this->start).', '. - $this->db_add_param($this->ende).', '. - $this->db_add_param($this->beschreibung).', '. - $this->db_add_param($this->oe_kurzbz_1).', '. - $this->db_add_param($this->oe_kurzbz_2).','. - $this->db_add_param($this->insertamum).', '. - $this->db_add_param($this->insertvon).', '. - $this->db_add_param($this->updateamum).', '. - $this->db_add_param($this->updatevon).', '. - $this->db_add_param($this->projekt_kurzbz).', '. - $this->db_add_param($this->service_id).', '. - $this->db_add_param($this->kunde_uid).');'; - } - else - { - //Updaten des bestehenden Datensatzes - - //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist - if(!is_numeric($this->zeitaufzeichnung_id)) - { - $this->errormsg = 'zeitaufzeichnung_id muss eine gueltige Zahl sein'; - return false; - } - - $qry='UPDATE campus.tbl_zeitaufzeichnung SET'. - ' uid='.$this->db_add_param($this->uid).', '. - ' aktivitaet_kurzbz='.$this->db_add_param($this->aktivitaet_kurzbz).', '. - ' start='.$this->db_add_param($this->start).', '. - ' ende='.$this->db_add_param($this->ende).', '. - ' beschreibung='.$this->db_add_param($this->beschreibung).', '. - ' oe_kurzbz_1='.$this->db_add_param($this->oe_kurzbz_1).', '. - ' oe_kurzbz_2='.$this->db_add_param($this->oe_kurzbz_2).', '. - ' updateamum='.$this->db_add_param($this->updateamum).', '. - ' updatevon='.$this->db_add_param($this->updatevon).', '. - ' projekt_kurzbz='.$this->db_add_param($this->projekt_kurzbz).', '. - ' service_id='.$this->db_add_param($this->service_id).', '. - ' kunde_uid='.$this->db_add_param($this->kunde_uid).' '. - 'WHERE zeitaufzeichnung_id='.$this->db_add_param($this->zeitaufzeichnung_id, FHC_INTEGER, false); - } - - if($this->db_query($qry)) - { - if($this->new) - { - //naechste ID aus der Sequence holen - $qry="SELECT currval('campus.tbl_zeitaufzeichnung_zeitaufzeichnung_id_seq') as id;"; - if($this->db_query($qry)) - { - if($row = $this->db_fetch_object()) - { - $this->zeitaufzeichnung_id = $row->id; - $this->db_query('COMMIT'); - return true; - } - else - { - $this->db_query('ROLLBACK'); - $this->errormsg = "Fehler beim Auslesen der Sequence"; - return false; - } - } - else - { - $this->db_query('ROLLBACK'); - $this->errormsg = 'Fehler beim Auslesen der Sequence'; - return false; - } - } - } - else - { - $this->errormsg = 'Fehler beim Speichern'; - return false; - } - return true; - } - - /** - * Loescht den Datenensatz mit der ID die uebergeben wird - * @param $zeitaufzeichnnung_id ID die geloescht werden soll - * @return true wenn ok, false im Fehlerfall - */ - public function delete($zeitaufzeichnung_id) - { - //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist - if(!is_numeric($zeitaufzeichnung_id) || $zeitaufzeichnung_id == '') - { - $this->errormsg = 'zeitaufzeichnung_id muss eine gueltige Zahl sein'; - return false; - } - - //loeschen des Datensatzes - $qry="DELETE FROM campus.tbl_zeitaufzeichnung WHERE zeitaufzeichnung_id=".$this->db_add_param($zeitaufzeichnung_id, FHC_INTEGER, false); - - if($this->db_query($qry)) - { - return true; - } - else - { - $this->errormsg = 'Fehler beim Loeschen der Daten'; - return false; - } - } - - /** - * Laedt die Datensaetze eines Projektes - * @param $projekt_kurzbz - */ - public function getListeProjekt($projekt_kurzbz) - { - $where = 'projekt_kurzbz='.$this->db_add_param($projekt_kurzbz); - - $qry = "SELECT - *, to_char ((ende-start),'HH24:MI') as diff, - (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') - FROM campus.tbl_zeitaufzeichnung - WHERE $where ) as summe - FROM campus.tbl_zeitaufzeichnung WHERE $where - ORDER BY start DESC"; - - if($result = $this->db_query($qry)) - { - while($row = $this->db_fetch_object($result)) - { - $obj = new zeitaufzeichnung(); - - $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; - $obj->uid = $row->uid; - $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; - $obj->start = $row->start; - $obj->ende = $row->ende; - $obj->beschreibung = $row->beschreibung; - $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; - $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; - $obj->insertamum = $row->insertamum; - $obj->insertvon = $row->insertvon; - $obj->updateamum = $row->updateamum; - $obj->updatevon = $row->updatevon; - $obj->projekt_kurzbz = $row->projekt_kurzbz; - $obj->ext_id = $row->ext_id; - $obj->service_id = $row->service_id; - $obj->kunde_uid = $row->kunde_uid; - $obj->summe = $row->summe; - $obj->diff = $row->diff; - - $this->result[] = $obj; - } - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - - /** - * Laedt die Zeitaufzeichnungen eines Users in einer festgelegten Zeitspanne - * @param $user - * @param $from startdatum als String in Form Y-m-d - * @param $to enddatum als String in Form Y-m-d - * @param $excluded_activities zu ignorierende Aktivitätstypen - * @return bool - */ - public function getListeUserFromTo($user, $from = null, $to = null, $excluded_activities = null) - { - $where = "uid=".$this->db_add_param($user); - - //standard wenn kein Datum gegeben - letzter Monat - if(empty($from) && empty($to)) - { - $from = date('Y-m-d', strtotime('first day of previous month')); - $to = date('Y-m-d', strtotime('last day of previous month')); - } - else if(empty($to))//standard wenn ein Datum gegeben - datum +/- 40 tage - $to = date('Y-m-d', strtotime($from. ' + 40 days')); - else if(empty($from)) - $from = date('Y-m-d', strtotime($to. ' - 40 days')); - - //zusätzlicher Tag - SQL rechnet letzten Tag nicht hinein - $to = date('Y-m-d', strtotime($to. ' + 1 days')); - - $where.= " AND ((start >= ".$this->db_add_param($from)."::DATE AND start <= ".$this->db_add_param($to)."::DATE) - OR (ende >= ".$this->db_add_param($from)."::DATE AND ende <= ".$this->db_add_param($to)."::DATE))"; - - if (!empty($excluded_activities)) - { - $exactstring = is_array($excluded_activities) ? $this->db_implode4SQL($excluded_activities) : $this->db_add_param($excluded_activities); - $where .= " AND (aktivitaet_kurzbz NOT IN (" . $exactstring . ") OR aktivitaet_kurzbz IS NULL)"; - } - - $qry = "SELECT - *, to_char ((ende-start),'HH24:MI') as diff, - (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') - FROM campus.tbl_zeitaufzeichnung - WHERE $where ) as summe - FROM campus.tbl_zeitaufzeichnung WHERE $where - ORDER BY start DESC"; - - if($result = $this->db_query($qry)) - { - while($row = $this->db_fetch_object($result)) - { - $obj = new zeitaufzeichnung(); - - $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; - $obj->uid = $row->uid; - $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; - $obj->start = $row->start; - $obj->ende = $row->ende; - $obj->beschreibung = $row->beschreibung; - $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; - $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; - $obj->insertamum = $row->insertamum; - $obj->insertvon = $row->insertvon; - $obj->updateamum = $row->updateamum; - $obj->updatevon = $row->updatevon; - $obj->projekt_kurzbz = $row->projekt_kurzbz; - $obj->ext_id = $row->ext_id; - $obj->service_id = $row->service_id; - $obj->kunde_uid = $row->kunde_uid; - $obj->summe = $row->summe; - $obj->diff = $row->diff; - $obj->datum = $row->start; - - $this->result[] = $obj; - } - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Laedt die Zeitaufzeichnungen eines Users. Default: Die letzten 40 Tage - * @param string $user - * @param integer $days default: 40 Tage - */ - public function getListeUser($user, $days='40') - { - $where = "uid=".$this->db_add_param($user); - if ($days!='') - $where.= " AND ende>(now() - INTERVAL '".$days." days')"; - - $qry = "SELECT - *, to_char ((ende-start),'HH24:MI') as diff, - (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') - FROM campus.tbl_zeitaufzeichnung - WHERE $where ) as summe - FROM campus.tbl_zeitaufzeichnung WHERE $where - ORDER BY start DESC"; - - if($result = $this->db_query($qry)) - { - while($row = $this->db_fetch_object($result)) - { - $obj = new zeitaufzeichnung(); - - $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; - $obj->uid = $row->uid; - $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; - $obj->start = $row->start; - $obj->ende = $row->ende; - $obj->beschreibung = $row->beschreibung; - $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; - $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; - $obj->insertamum = $row->insertamum; - $obj->insertvon = $row->insertvon; - $obj->updateamum = $row->updateamum; - $obj->updatevon = $row->updatevon; - $obj->projekt_kurzbz = $row->projekt_kurzbz; - $obj->ext_id = $row->ext_id; - $obj->service_id = $row->service_id; - $obj->kunde_uid = $row->kunde_uid; - $obj->summe = $row->summe; - $obj->diff = $row->diff; - $obj->datum = $row->start; - - $this->result[] = $obj; - } - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Laedt die Zeitaufzeichnungen eines Users aufgefüllt mit lehren Tagen. - * Default: Die letzten 40 Tage - * @param string $user - * @param integer $days deafult: 40 Tage - */ - public function getListeUserFull($user, $days='40') - { - $where = "uid=".$this->db_add_param($user); - if ($days!='') - $where.= " AND ende>(now() - INTERVAL '".$days." days')"; - $where_join = "and (z.aktivitaet_kurzbz != 'DienstreiseMT' or z.aktivitaet_kurzbz is null) and z.uid=".$this->db_add_param($user); - if ($days!='') - $where_join.= " AND z.ende>(now() - INTERVAL '".$days." days')"; - if ($days=='') - $max_anz = 180; - else - $max_anz = $days; - $qry = "SELECT - d.dates, z.*, to_char ((z.ende-z.start),'HH24:MI') as diff, - (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') - FROM campus.tbl_zeitaufzeichnung - WHERE $where) as summe - FROM campus.tbl_zeitaufzeichnung z - right join (select current_date - s.a as dates from generate_series(0,$max_anz,1) as s(a)) d on date(z.ende) = d.dates $where_join order by d.dates desc, z.start desc - "; - - if($result = $this->db_query($qry)) - { - while($row = $this->db_fetch_object($result)) - { - $obj = new zeitaufzeichnung(); - - $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; - $obj->uid = $row->uid; - $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; - $obj->start = $row->start; - $obj->ende = $row->ende; - $obj->beschreibung = $row->beschreibung; - $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; - $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; - $obj->insertamum = $row->insertamum; - $obj->insertvon = $row->insertvon; - $obj->updateamum = $row->updateamum; - $obj->updatevon = $row->updatevon; - $obj->projekt_kurzbz = $row->projekt_kurzbz; - $obj->ext_id = $row->ext_id; - $obj->service_id = $row->service_id; - $obj->kunde_uid = $row->kunde_uid; - $obj->summe = $row->summe; - $obj->diff = $row->diff; - $obj->datum = $row->dates; - - $this->result[] = $obj; - } - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Laedt die Zeitaufzeichnungen eines Users aufgefüllt mit lehren Tagen. - * Default: Die letzten 40 Tage - * @param string $user - * @param integer $days deafult: 40 Tage - */ - public function getDienstreisenUser($user, $days='40') - { - $where = "uid=".$this->db_add_param($user); - if ($days!='') - $where.= " AND ende>(now() - INTERVAL '".$days." days')"; - $where .= " AND aktivitaet_kurzbz = 'DienstreiseMT'"; - $qry = "SELECT - zeitaufzeichnung_id, start::date as starttag, TO_CHAR(start, 'HH24:MI') as startzeit, ende::date as endtag, TO_CHAR(ende, 'HH24:MI') as endzeit - FROM campus.tbl_zeitaufzeichnung - where $where - ORDER BY ende DESC - "; - - if($result = $this->db_query($qry)) - { - $dr_arr = array(); - while($row = $this->db_fetch_object($result)) - { - if (array_key_exists($row->starttag, $dr_arr)) - { - $dr_arr[$row->starttag]['start'] = $row->startzeit; - $dr_arr[$row->starttag]['id'] = $row->zeitaufzeichnung_id; - } - else - { - $dr_arr[$row->starttag] = array(); - $dr_arr[$row->starttag]['start'] = $row->startzeit; - $dr_arr[$row->starttag]['id'] = $row->zeitaufzeichnung_id; - } - if (array_key_exists($row->endtag, $dr_arr)) - { - $dr_arr[$row->endtag]['ende'] = $row->endzeit; - $dr_arr[$row->endtag]['id'] = $row->zeitaufzeichnung_id; - } - else - { - $dr_arr[$row->endtag] = array(); - $dr_arr[$row->endtag]['ende'] = $row->endzeit; - $dr_arr[$row->endtag]['id'] = $row->zeitaufzeichnung_id; - } - - $this->result = $dr_arr; - } - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Löscht sämtliche Einträge eines Users für einen Tag - * @param string $user - * @param string $tag Y-m-d - */ - public function deleteEntriesForUser($user, $tag) - { - $where = "uid=".$this->db_add_param($user); - - $qry = "delete from campus.tbl_zeitaufzeichnung where $where and date_trunc('day', start) = '$tag'"; - if($result = $this->db_query($qry)) - { - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Löscht Pauseneinträge eines Users für einen Tag, die außerhalb der Arbeitszeit liegen - * Löscht Pauseneinträge an Tagen ohne Arbeitszeit - * @param string $user - * @param string $tag Y-m-d - */ - public function cleanPausenForUser($user, $tag) - { - $where = "uid=".$this->db_add_param($user); - - $qry = " - delete from campus.tbl_zeitaufzeichnung where aktivitaet_kurzbz = 'Pause' and start::date = '$tag' and $where and -( -start::time >= -(SELECT max(ende::time) as endzeit from campus.tbl_zeitaufzeichnung where $where and start::date = '$tag' AND (aktivitaet_kurzbz != 'LehreExtern' or aktivitaet_kurzbz is null ) and aktivitaet_kurzbz != 'Pause') -or -ende::time<= -(SELECT min(start::time) as startzeit from campus.tbl_zeitaufzeichnung where $where and start::date = '$tag' AND (aktivitaet_kurzbz != 'LehreExtern' or aktivitaet_kurzbz is null ) and aktivitaet_kurzbz != 'Pause') -or not exists -(select 1 from campus.tbl_zeitaufzeichnung where aktivitaet_kurzbz != 'LehreExtern' and aktivitaet_kurzbz != 'Pause' and start::date = '$tag' and $where ) -) - "; - - if($result = $this->db_query($qry)) - { - return true; - } - else - { - $this->errormsg = 'Fehler beim Laden der Daten'; - return false; - } - } - - /** - * Holt alle ZA-Einträge Typ LehreIntern und LehreExtern eines Users - * für das laufende Studienjahr und gibt die Summen in einem Array zurück - * @param string $user - * @return Array mit Key: LehreIntern, LehreExtern, LehreAuftraege, LehreInkludiert - */ - public function getLehreForUser($user,$sem) - { - $where = "uid=".$this->db_add_param($user); - $where_sem = "studiensemester_kurzbz=".$this->db_add_param($sem); - $lehre_arr = array("Lehre"=>0, "LehreExtern"=>0, "LehreAuftraege"=>0); - - $qry = " - select sum(extract(epoch from ende-start))/3600 as lehre, aktivitaet_kurzbz from campus.tbl_zeitaufzeichnung where $where and aktivitaet_kurzbz in ('Lehre', 'LehreExtern') and start > (select start from public.tbl_studiensemester where $where_sem) group by aktivitaet_kurzbz - "; - - if($result = $this->db_query($qry)) - { - - while($row = $this->db_fetch_object($result)) - { - $lehre_arr[$row->aktivitaet_kurzbz] = round($row->lehre,2); - } - } - else - { - return false; - } - $where = "mitarbeiter_uid=".$this->db_add_param($user); - $where_sem = "l.studiensemester_kurzbz=".$this->db_add_param($sem); - - $qry = " - SELECT sum(semstunden) AS stunden - FROM - ( - SELECT sum(m.semesterstunden) AS semstunden - FROM - lehre.tbl_lehreinheitmitarbeiter m, - lehre.tbl_lehreinheit l - JOIN - lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) - JOIN - public.tbl_studiengang s using (studiengang_kz) - WHERE - $where AND - $where_sem AND - l.lehreinheit_id = m.lehreinheit_id AND - m.stundensatz * m.semesterstunden > 0 AND - s.typ not in ('l') AND - lv.studiengang_kz > 0 - UNION - SELECT sum(pb.stunden) AS semstunden - FROM - lehre.tbl_projektarbeit pa, - lehre.tbl_projektbetreuer pb, - public.tbl_benutzer b, - lehre.tbl_lehreinheit l - JOIN - lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) - JOIN - public.tbl_studiengang s using (studiengang_kz) - - WHERE - pa.lehreinheit_id = l.lehreinheit_id AND - pb.projektarbeit_id = pa.projektarbeit_id AND - pb.person_id = b.person_id AND - b.uid = ".$this->db_add_param($user)." AND - pb.stunden * pb.stundensatz > 0 AND - s.typ not in ('l') AND - lv.studiengang_kz > 0 AND - $where_sem - ) AS semstunden - "; - - if($result = $this->db_query($qry)) - { - - while($row = $this->db_fetch_object($result)) - { - $lehre_arr["LehreAuftraege"] = round($row->stunden); - } - } - else - { - return false; - } - - return $lehre_arr; - } - - /** - * Holt das Datum bis zu dem die Eintragung für einen bestimmten User gesperrt ist - * @param string $user - * @return string $tag Y-m-d or false - */ - - public function getEintragungGesperrtBisForUser($user) - { - //check if addon casetime is installed - $qrytable = " - SELECT EXISTS( - SELECT 1 - FROM information_schema.tables - WHERE - table_schema = 'addon' AND - table_name = 'tbl_casetime_timesheet' - ); - "; - - $res = $this->db_query($qrytable); - if ($this->db_fetch_row($res)[0] == 't') - { - //check if sent timesheets for the UID exist - $where = "uid=".$this->db_add_param($user); - - $qry = "select max(datum) from addon.tbl_casetime_timesheet where ".$where." and abgeschicktamum is not null"; - - if($result = $this->db_query($qry)) - { - $datum = $this->db_fetch_object($result); - return $datum->max; - } - else - { - return false; - } - } - else - { - return false; - } - } -} -?> +, + * Andreas Oesterreicher and + * Rudolf Hangl . + */ +/** + * Klasse Zeitaufzeichnung + * @create 06-11-2007 + */ +require_once(dirname(__FILE__).'/basis_db.class.php'); + +class zeitaufzeichnung extends basis_db +{ + public $new; // boolean + public $result = array(); // zeitaufzeichnung Objekt + public $done=false; // boolean + + //Tabellenspalten + public $zeitaufzeichnung_id; // serial + public $uid; // varchar(16) + public $aktivitaet_kurzbz; // varchar(16) + public $start; // timestamp + public $ende; // timestamp + public $beschreibung; // varchar(256) + public $oe_kurzbz_1; // varchar(32) ehemals studiengangs_kz + public $oe_kurzbz_2; // varchar(32) ehemals fachbereich_kurzbz + public $insertamum; // timestamp + public $insertvon; // varchar(16) + public $updateamum; // timestamp + public $updatevon; // varchar(16) + public $projekt_kurzbz; // varchar(16) + public $projektphase_id; // bigint + public $ext_id; // bigint + public $service_id; // integer + public $kunde_uid; // varchar(32) + + /** + * Konstruktor + * @param $zeitaufzeichnung_id ID der Zeitaufzeichnung die geladen werden soll (Default=null) + */ + public function __construct($zeitaufzeichnung_id=null) + { + parent::__construct(); + + if($zeitaufzeichnung_id != null) + $this->load($zeitaufzeichnung_id); + } + + /** + * Laedt die Zeitaufzeichnung mit der ID $zeitaufzeichnung_id + * @param $adress_id ID der zu ladenden Adresse + * @return true wenn ok, false im Fehlerfall + */ + public function load($zeitaufzeichnung_id) + { + //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist + if(!is_numeric($zeitaufzeichnung_id) || $zeitaufzeichnung_id == '') + { + $this->errormsg = 'Zeitaufzeichnung_id muss eine Zahl sein'; + return false; + } + + //Daten aus der Datenbank lesen + $qry = "SELECT * FROM campus.tbl_zeitaufzeichnung WHERE zeitaufzeichnung_id=".$this->db_add_param($zeitaufzeichnung_id, FHC_INTEGER); + + if(!$this->db_query($qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = $this->db_fetch_object()) + { + $this->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; + $this->uid = $row->uid; + $this->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; + $this->start = $row->start; + $this->ende = $row->ende; + $this->beschreibung = $row->beschreibung; + $this->oe_kurzbz_1 = $row->oe_kurzbz_1; + $this->oe_kurzbz_2 = $row->oe_kurzbz_2; + $this->insertamum = $row->insertamum; + $this->insertvon = $row->insertvon; + $this->updateamum = $row->updateamum; + $this->updatevon = $row->updatevon; + $this->projekt_kurzbz = $row->projekt_kurzbz; + $this->projektphase_id = $row->projektphase_id; + $this->ext_id = $row->ext_id; + $this->service_id = $row->service_id; + $this->kunde_uid = $row->kunde_uid; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Prueft die Variablen auf Gueltigkeit + * @return true wenn ok, false im Fehlerfall + */ + protected function validate() + { + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz in die Datenbank + * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt + * andernfalls wird der Datensatz mit der ID in $adresse_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + public function save() + { + //Variablen pruefen + if(!$this->validate()) + return false; + + // check ob identischer eintrag existiert + // DienstreiseMT-Einträge sind hier ausgenommen da eintägige Dienstreisen mit der identen Arbeitszeit eingetragen werden könnten + if ($this->aktivitaet_kurzbz != 'DienstreiseMT') + { + $check_qry = 'SELECT count(*) from campus.tbl_zeitaufzeichnung where uid='.$this->db_add_param($this->uid).' and aktivitaet_kurzbz != \'DienstreiseMT\' and start = '.$this->db_add_param($this->start).' and ende = '.$this->db_add_param($this->ende); + if($this->db_query($check_qry) && $this->new) + { + if($row = $this->db_fetch_object()) + { + if ($row->count) + { + $this->errormsg = 'Identischer Eintrag existiert!'; + return false; + } + } + } + } + + // ER - Checks + if ($this->aktivitaet_kurzbz == 'Ersatzruhe') + { + $check_qry = "SELECT count(*) from campus.tbl_zeitaufzeichnung where uid=".$this->db_add_param($this->uid)." and (start < ".$this->db_add_param($this->ende)." and ende > ".$this->db_add_param($this->start).")"; + if ($this->zeitaufzeichnung_id) + $check_qry .= " and zeitaufzeichnung_id != ".$this->db_add_param($this->zeitaufzeichnung_id); + if($this->db_query($check_qry)) + { + if($row = $this->db_fetch_object()) + { + if ($row->count) + { + $this->errormsg = 'Ersatzruhe darf nicht Überlappen!'; + return false; + } + } + } + } + if ($this->aktivitaet_kurzbz != 'Ersatzruhe') + { + $check_qry = "SELECT count(*) from campus.tbl_zeitaufzeichnung where uid=".$this->db_add_param($this->uid)." and aktivitaet_kurzbz = 'Ersatzruhe' and (start < ".$this->db_add_param($this->ende)." and ende > ".$this->db_add_param($this->start).")"; + if($this->db_query($check_qry)) + { + if($row = $this->db_fetch_object()) + { + if ($row->count) + { + $this->errormsg = 'Eintrag darf nicht mit Ersatzruhe Überlappen!'; + return false; + } + } + } + } + + if($this->new) + { + //Neuen Datensatz einfuegen + $qry='BEGIN;INSERT INTO campus.tbl_zeitaufzeichnung (uid, aktivitaet_kurzbz, start, ende, beschreibung, + oe_kurzbz_1, oe_kurzbz_2, insertamum, insertvon, updateamum, updatevon, projekt_kurzbz, projektphase_id, service_id, kunde_uid) VALUES('. + $this->db_add_param($this->uid).', '. + $this->db_add_param($this->aktivitaet_kurzbz).', '. + $this->db_add_param($this->start).', '. + $this->db_add_param($this->ende).', '. + $this->db_add_param($this->beschreibung).', '. + $this->db_add_param($this->oe_kurzbz_1).', '. + $this->db_add_param($this->oe_kurzbz_2).','. + $this->db_add_param($this->insertamum).', '. + $this->db_add_param($this->insertvon).', '. + $this->db_add_param($this->updateamum).', '. + $this->db_add_param($this->updatevon).', '. + $this->db_add_param($this->projekt_kurzbz).', '. + $this->db_add_param($this->projektphase_id, FHC_INTEGER).', '. + $this->db_add_param($this->service_id).', '. + $this->db_add_param($this->kunde_uid).');'; + } + else + { + //Updaten des bestehenden Datensatzes + + //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist + if(!is_numeric($this->zeitaufzeichnung_id)) + { + $this->errormsg = 'zeitaufzeichnung_id muss eine gueltige Zahl sein'; + return false; + } + + $qry='UPDATE campus.tbl_zeitaufzeichnung SET'. + ' uid='.$this->db_add_param($this->uid).', '. + ' aktivitaet_kurzbz='.$this->db_add_param($this->aktivitaet_kurzbz).', '. + ' start='.$this->db_add_param($this->start).', '. + ' ende='.$this->db_add_param($this->ende).', '. + ' beschreibung='.$this->db_add_param($this->beschreibung).', '. + ' oe_kurzbz_1='.$this->db_add_param($this->oe_kurzbz_1).', '. + ' oe_kurzbz_2='.$this->db_add_param($this->oe_kurzbz_2).', '. + ' updateamum='.$this->db_add_param($this->updateamum).', '. + ' updatevon='.$this->db_add_param($this->updatevon).', '. + ' projekt_kurzbz='.$this->db_add_param($this->projekt_kurzbz).', '. + ' projektphase_id='.$this->db_add_param($this->projektphase_id, FHC_INTEGER).', '. + ' service_id='.$this->db_add_param($this->service_id).', '. + ' kunde_uid='.$this->db_add_param($this->kunde_uid).' '. + 'WHERE zeitaufzeichnung_id='.$this->db_add_param($this->zeitaufzeichnung_id, FHC_INTEGER, false); + } + + if($this->db_query($qry)) + { + if($this->new) + { + //naechste ID aus der Sequence holen + $qry="SELECT currval('campus.tbl_zeitaufzeichnung_zeitaufzeichnung_id_seq') as id;"; + if($this->db_query($qry)) + { + if($row = $this->db_fetch_object()) + { + $this->zeitaufzeichnung_id = $row->id; + $this->db_query('COMMIT'); + return true; + } + else + { + $this->db_query('ROLLBACK'); + $this->errormsg = "Fehler beim Auslesen der Sequence"; + return false; + } + } + else + { + $this->db_query('ROLLBACK'); + $this->errormsg = 'Fehler beim Auslesen der Sequence'; + return false; + } + } + } + else + { + $this->errormsg = 'Fehler beim Speichern'; + return false; + } + return true; + } + + /** + * Loescht den Datenensatz mit der ID die uebergeben wird + * @param $zeitaufzeichnnung_id ID die geloescht werden soll + * @return true wenn ok, false im Fehlerfall + */ + public function delete($zeitaufzeichnung_id) + { + //Pruefen ob zeitaufzeichnung_id eine gueltige Zahl ist + if(!is_numeric($zeitaufzeichnung_id) || $zeitaufzeichnung_id == '') + { + $this->errormsg = 'zeitaufzeichnung_id muss eine gueltige Zahl sein'; + return false; + } + + //loeschen des Datensatzes + $qry="DELETE FROM campus.tbl_zeitaufzeichnung WHERE zeitaufzeichnung_id=".$this->db_add_param($zeitaufzeichnung_id, FHC_INTEGER, false); + + if($this->db_query($qry)) + { + return true; + } + else + { + $this->errormsg = 'Fehler beim Loeschen der Daten'; + return false; + } + } + + /** + * Laedt die Datensaetze eines Projektes + * @param $projekt_kurzbz + */ + public function getListeProjekt($projekt_kurzbz) + { + $where = 'projekt_kurzbz='.$this->db_add_param($projekt_kurzbz); + + $qry = "SELECT + *, to_char ((ende-start),'HH24:MI') as diff, + (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') + FROM campus.tbl_zeitaufzeichnung + WHERE $where ) as summe + FROM campus.tbl_zeitaufzeichnung WHERE $where + ORDER BY start DESC"; + + if($result = $this->db_query($qry)) + { + while($row = $this->db_fetch_object($result)) + { + $obj = new zeitaufzeichnung(); + + $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; + $obj->uid = $row->uid; + $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; + $obj->start = $row->start; + $obj->ende = $row->ende; + $obj->beschreibung = $row->beschreibung; + $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; + $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; + $obj->insertamum = $row->insertamum; + $obj->insertvon = $row->insertvon; + $obj->updateamum = $row->updateamum; + $obj->updatevon = $row->updatevon; + $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->projektphase_id = $row->projektphase_id; + $obj->ext_id = $row->ext_id; + $obj->service_id = $row->service_id; + $obj->kunde_uid = $row->kunde_uid; + $obj->summe = $row->summe; + $obj->diff = $row->diff; + + $this->result[] = $obj; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + + /** + * Laedt die Zeitaufzeichnungen eines Users in einer festgelegten Zeitspanne + * @param $user + * @param $from startdatum als String in Form Y-m-d + * @param $to enddatum als String in Form Y-m-d + * @param $excluded_activities zu ignorierende Aktivitätstypen + * @return bool + */ + public function getListeUserFromTo($user, $from = null, $to = null, $excluded_activities = null) + { + $where = "uid=".$this->db_add_param($user); + + //standard wenn kein Datum gegeben - letzter Monat + if(empty($from) && empty($to)) + { + $from = date('Y-m-d', strtotime('first day of previous month')); + $to = date('Y-m-d', strtotime('last day of previous month')); + } + else if(empty($to))//standard wenn ein Datum gegeben - datum +/- 40 tage + $to = date('Y-m-d', strtotime($from. ' + 40 days')); + else if(empty($from)) + $from = date('Y-m-d', strtotime($to. ' - 40 days')); + + //zusätzlicher Tag - SQL rechnet letzten Tag nicht hinein + $to = date('Y-m-d', strtotime($to. ' + 1 days')); + + $where.= " AND ((start >= ".$this->db_add_param($from)."::DATE AND start <= ".$this->db_add_param($to)."::DATE) + OR (ende >= ".$this->db_add_param($from)."::DATE AND ende <= ".$this->db_add_param($to)."::DATE))"; + + if (!empty($excluded_activities)) + { + $exactstring = is_array($excluded_activities) ? $this->db_implode4SQL($excluded_activities) : $this->db_add_param($excluded_activities); + $where .= " AND (aktivitaet_kurzbz NOT IN (" . $exactstring . ") OR aktivitaet_kurzbz IS NULL)"; + } + + $qry = "SELECT + *, to_char ((ende-start),'HH24:MI') as diff, + (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') + FROM campus.tbl_zeitaufzeichnung + WHERE $where ) as summe + FROM campus.tbl_zeitaufzeichnung WHERE $where + ORDER BY start DESC"; + + if($result = $this->db_query($qry)) + { + while($row = $this->db_fetch_object($result)) + { + $obj = new zeitaufzeichnung(); + + $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; + $obj->uid = $row->uid; + $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; + $obj->start = $row->start; + $obj->ende = $row->ende; + $obj->beschreibung = $row->beschreibung; + $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; + $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; + $obj->insertamum = $row->insertamum; + $obj->insertvon = $row->insertvon; + $obj->updateamum = $row->updateamum; + $obj->updatevon = $row->updatevon; + $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->ext_id = $row->ext_id; + $obj->service_id = $row->service_id; + $obj->kunde_uid = $row->kunde_uid; + $obj->summe = $row->summe; + $obj->diff = $row->diff; + $obj->datum = $row->start; + + $this->result[] = $obj; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Laedt die Zeitaufzeichnungen eines Users. Default: Die letzten 40 Tage + * @param string $user + * @param integer $days default: 40 Tage + */ + public function getListeUser($user, $days='40') + { + $where = "uid=".$this->db_add_param($user); + if ($days!='') + $where.= " AND ende>(now() - INTERVAL '".$days." days')"; + + $qry = "SELECT + *, to_char ((ende-start),'HH24:MI') as diff, + (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') + FROM campus.tbl_zeitaufzeichnung + WHERE $where ) as summe + FROM campus.tbl_zeitaufzeichnung WHERE $where + ORDER BY start DESC"; + + if($result = $this->db_query($qry)) + { + while($row = $this->db_fetch_object($result)) + { + $obj = new zeitaufzeichnung(); + + $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; + $obj->uid = $row->uid; + $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; + $obj->start = $row->start; + $obj->ende = $row->ende; + $obj->beschreibung = $row->beschreibung; + $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; + $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; + $obj->insertamum = $row->insertamum; + $obj->insertvon = $row->insertvon; + $obj->updateamum = $row->updateamum; + $obj->updatevon = $row->updatevon; + $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->ext_id = $row->ext_id; + $obj->service_id = $row->service_id; + $obj->kunde_uid = $row->kunde_uid; + $obj->summe = $row->summe; + $obj->diff = $row->diff; + $obj->datum = $row->start; + + $this->result[] = $obj; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Laedt die Zeitaufzeichnungen eines Users aufgefüllt mit lehren Tagen. + * Default: Die letzten 40 Tage + * @param string $user + * @param integer $days deafult: 40 Tage + */ + public function getListeUserFull($user, $days='40') + { + $where = "uid=".$this->db_add_param($user); + if ($days!='') + $where.= " AND ende>(now() - INTERVAL '".$days." days')"; + $where_join = "and (z.aktivitaet_kurzbz != 'DienstreiseMT' or z.aktivitaet_kurzbz is null) and z.uid=".$this->db_add_param($user); + if ($days!='') + $where_join.= " AND z.ende>(now() - INTERVAL '".$days." days')"; + if ($days=='') + $max_anz = 180; + else + $max_anz = $days; + $qry = "SELECT + d.dates, z.*, to_char ((z.ende-z.start),'HH24:MI') as diff, + (SELECT (to_char(sum(ende-start),'DD')::integer)*24+to_char(sum(ende-start),'HH24')::integer || ':' || to_char(sum(ende-start),'MI') + FROM campus.tbl_zeitaufzeichnung + WHERE $where) as summe + FROM campus.tbl_zeitaufzeichnung z + right join (select current_date - s.a as dates from generate_series(0,$max_anz,1) as s(a)) d on date(z.ende) = d.dates $where_join order by d.dates desc, z.start desc + "; + + if($result = $this->db_query($qry)) + { + while($row = $this->db_fetch_object($result)) + { + $obj = new zeitaufzeichnung(); + + $obj->zeitaufzeichnung_id = $row->zeitaufzeichnung_id; + $obj->uid = $row->uid; + $obj->aktivitaet_kurzbz = $row->aktivitaet_kurzbz; + $obj->start = $row->start; + $obj->ende = $row->ende; + $obj->beschreibung = $row->beschreibung; + $obj->oe_kurzbz_1 = $row->oe_kurzbz_1; + $obj->oe_kurzbz_2 = $row->oe_kurzbz_2; + $obj->insertamum = $row->insertamum; + $obj->insertvon = $row->insertvon; + $obj->updateamum = $row->updateamum; + $obj->updatevon = $row->updatevon; + $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->ext_id = $row->ext_id; + $obj->service_id = $row->service_id; + $obj->kunde_uid = $row->kunde_uid; + $obj->summe = $row->summe; + $obj->diff = $row->diff; + $obj->datum = $row->dates; + + $this->result[] = $obj; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Laedt die Zeitaufzeichnungen eines Users aufgefüllt mit lehren Tagen. + * Default: Die letzten 40 Tage + * @param string $user + * @param integer $days deafult: 40 Tage + */ + public function getDienstreisenUser($user, $days='40') + { + $where = "uid=".$this->db_add_param($user); + if ($days!='') + $where.= " AND ende>(now() - INTERVAL '".$days." days')"; + $where .= " AND aktivitaet_kurzbz = 'DienstreiseMT'"; + $qry = "SELECT + zeitaufzeichnung_id, start::date as starttag, TO_CHAR(start, 'HH24:MI') as startzeit, ende::date as endtag, TO_CHAR(ende, 'HH24:MI') as endzeit + FROM campus.tbl_zeitaufzeichnung + where $where + ORDER BY ende DESC + "; + + if($result = $this->db_query($qry)) + { + $dr_arr = array(); + while($row = $this->db_fetch_object($result)) + { + if (array_key_exists($row->starttag, $dr_arr)) + { + $dr_arr[$row->starttag]['start'] = $row->startzeit; + $dr_arr[$row->starttag]['id'] = $row->zeitaufzeichnung_id; + } + else + { + $dr_arr[$row->starttag] = array(); + $dr_arr[$row->starttag]['start'] = $row->startzeit; + $dr_arr[$row->starttag]['id'] = $row->zeitaufzeichnung_id; + } + if (array_key_exists($row->endtag, $dr_arr)) + { + $dr_arr[$row->endtag]['ende'] = $row->endzeit; + $dr_arr[$row->endtag]['id'] = $row->zeitaufzeichnung_id; + } + else + { + $dr_arr[$row->endtag] = array(); + $dr_arr[$row->endtag]['ende'] = $row->endzeit; + $dr_arr[$row->endtag]['id'] = $row->zeitaufzeichnung_id; + } + + $this->result = $dr_arr; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Löscht sämtliche Einträge eines Users für einen Tag + * @param string $user + * @param string $tag Y-m-d + */ + public function deleteEntriesForUser($user, $tag) + { + $where = "uid=".$this->db_add_param($user); + + $qry = "delete from campus.tbl_zeitaufzeichnung where $where and date_trunc('day', start) = '$tag'"; + if($result = $this->db_query($qry)) + { + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Löscht Pauseneinträge eines Users für einen Tag, die außerhalb der Arbeitszeit liegen + * Löscht Pauseneinträge an Tagen ohne Arbeitszeit + * @param string $user + * @param string $tag Y-m-d + */ + public function cleanPausenForUser($user, $tag) + { + $where = "uid=".$this->db_add_param($user); + + $qry = " + delete from campus.tbl_zeitaufzeichnung where aktivitaet_kurzbz = 'Pause' and start::date = '$tag' and $where and +( +start::time >= +(SELECT max(ende::time) as endzeit from campus.tbl_zeitaufzeichnung where $where and start::date = '$tag' AND (aktivitaet_kurzbz != 'LehreExtern' or aktivitaet_kurzbz is null ) and aktivitaet_kurzbz != 'Pause') +or +ende::time<= +(SELECT min(start::time) as startzeit from campus.tbl_zeitaufzeichnung where $where and start::date = '$tag' AND (aktivitaet_kurzbz != 'LehreExtern' or aktivitaet_kurzbz is null ) and aktivitaet_kurzbz != 'Pause') +or not exists +(select 1 from campus.tbl_zeitaufzeichnung where aktivitaet_kurzbz != 'LehreExtern' and aktivitaet_kurzbz != 'Pause' and start::date = '$tag' and $where ) +) + "; + + if($result = $this->db_query($qry)) + { + return true; + } + else + { + $this->errormsg = 'Fehler beim Laden der Daten'; + return false; + } + } + + /** + * Holt alle ZA-Einträge Typ LehreIntern und LehreExtern eines Users + * für das laufende Studienjahr und gibt die Summen in einem Array zurück + * @param string $user + * @return Array mit Key: LehreIntern, LehreExtern, LehreAuftraege, LehreInkludiert + */ + public function getLehreForUser($user,$sem) + { + $where = "uid=".$this->db_add_param($user); + $where_sem = "studiensemester_kurzbz=".$this->db_add_param($sem); + $lehre_arr = array("Lehre"=>0, "LehreExtern"=>0, "LehreAuftraege"=>0); + + $qry = " + select sum(extract(epoch from ende-start))/3600 as lehre, aktivitaet_kurzbz from campus.tbl_zeitaufzeichnung where $where and aktivitaet_kurzbz in ('Lehre', 'LehreExtern') and start > (select start from public.tbl_studiensemester where $where_sem) group by aktivitaet_kurzbz + "; + + if($result = $this->db_query($qry)) + { + + while($row = $this->db_fetch_object($result)) + { + $lehre_arr[$row->aktivitaet_kurzbz] = round($row->lehre,2); + } + } + else + { + return false; + } + $where = "mitarbeiter_uid=".$this->db_add_param($user); + $where_sem = "l.studiensemester_kurzbz=".$this->db_add_param($sem); + + $qry = " + SELECT sum(semstunden) AS stunden + FROM + ( + SELECT sum(m.semesterstunden) AS semstunden + FROM + lehre.tbl_lehreinheitmitarbeiter m, + lehre.tbl_lehreinheit l + JOIN + lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) + JOIN + public.tbl_studiengang s using (studiengang_kz) + WHERE + $where AND + $where_sem AND + l.lehreinheit_id = m.lehreinheit_id AND + m.stundensatz * m.semesterstunden > 0 AND + s.typ not in ('l') AND + lv.studiengang_kz > 0 + UNION + SELECT sum(pb.stunden) AS semstunden + FROM + lehre.tbl_projektarbeit pa, + lehre.tbl_projektbetreuer pb, + public.tbl_benutzer b, + lehre.tbl_lehreinheit l + JOIN + lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) + JOIN + public.tbl_studiengang s using (studiengang_kz) + + WHERE + pa.lehreinheit_id = l.lehreinheit_id AND + pb.projektarbeit_id = pa.projektarbeit_id AND + pb.person_id = b.person_id AND + b.uid = ".$this->db_add_param($user)." AND + pb.stunden * pb.stundensatz > 0 AND + s.typ not in ('l') AND + lv.studiengang_kz > 0 AND + $where_sem + ) AS semstunden + "; + + if($result = $this->db_query($qry)) + { + + while($row = $this->db_fetch_object($result)) + { + $lehre_arr["LehreAuftraege"] = round($row->stunden); + } + } + else + { + return false; + } + + return $lehre_arr; + } + + /** + * Holt das Datum bis zu dem die Eintragung für einen bestimmten User gesperrt ist + * @param string $user + * @return string $tag Y-m-d or false + */ + + public function getEintragungGesperrtBisForUser($user) + { + //check if addon casetime is installed + $qrytable = " + SELECT EXISTS( + SELECT 1 + FROM information_schema.tables + WHERE + table_schema = 'addon' AND + table_name = 'tbl_casetime_timesheet' + ); + "; + + $res = $this->db_query($qrytable); + if ($this->db_fetch_row($res)[0] == 't') + { + //check if sent timesheets for the UID exist + $where = "uid=".$this->db_add_param($user); + + $qry = "select max(datum) from addon.tbl_casetime_timesheet where ".$where." and abgeschicktamum is not null"; + + if($result = $this->db_query($qry)) + { + $datum = $this->db_fetch_object($result); + return $datum->max; + } + else + { + return false; + } + } + else + { + return false; + } + } +} +?> diff --git a/locale/de-AT/zeitaufzeichnung.php b/locale/de-AT/zeitaufzeichnung.php index 4634459dd..2901ac4a7 100644 --- a/locale/de-AT/zeitaufzeichnung.php +++ b/locale/de-AT/zeitaufzeichnung.php @@ -1,60 +1,61 @@ -phrasen['zeitaufzeichnung/zeitaufzeichnung']='Zeitaufzeichnung'; -$this->phrasen['zeitaufzeichnung/benutzerWurdeNichtGefunden']='Benutzer %s wurde nicht gefunden'; -$this->phrasen['zeitaufzeichnung/zeitaufzeichnungVon']='Zeitaufzeichnung von'; -$this->phrasen['zeitaufzeichnung/neu']='NEU'; -$this->phrasen['zeitaufzeichnung/projekt']='Projekt'; -$this->phrasen['zeitaufzeichnung/keineAuswahl']='keine Auswahl'; -$this->phrasen['zeitaufzeichnung/aktivitaet']='Aktivität'; -$this->phrasen['zeitaufzeichnung/id']='ID'; -$this->phrasen['zeitaufzeichnung/user']='User'; -$this->phrasen['zeitaufzeichnung/start']='Start'; -$this->phrasen['zeitaufzeichnung/ende']='Ende'; -$this->phrasen['zeitaufzeichnung/dauer']='Dauer'; -$this->phrasen['zeitaufzeichnung/gesamtdauer']='Gesamtdauer'; -$this->phrasen['zeitaufzeichnung/sieSindDerzeitKeinenProjektenZugeordnet']='Sie sind derzeit keinen Projekten zugeordnet'; -$this->phrasen['zeitaufzeichnung/fehlerBeimErmittelnDerProjekte']='Fehler beim Ermitteln der Projekte'; -$this->phrasen['zeitaufzeichnung/organisationseinheit1']='Organisationseinheit 1'; -$this->phrasen['zeitaufzeichnung/organisationseinheit2']='Organisationseinheit 2'; -$this->phrasen['zeitaufzeichnung/organisationseinheiten']='Organisationseinheit'; -$this->phrasen['zeitaufzeichnung/oe']='OE'; -$this->phrasen['zeitaufzeichnung/service']='Service'; -$this->phrasen['zeitaufzeichnung/kunde']='Kunde'; -$this->phrasen['zeitaufzeichnung/alsNeuenEintragSpeichern']='Als neuen Eintrag speichern'; -$this->phrasen['zeitaufzeichnung/kartennummer']='Kartennummer'; -$this->phrasen['zeitaufzeichnung/oderKartennummerOptional']='oder Kartennummer (optional)'; -$this->phrasen['zeitaufzeichnung/nameEingeben']='Name eingeben'; -$this->phrasen['zeitaufzeichnung/aktuelleZeitLaden']='Aktuelle Zeit laden'; -$this->phrasen['zeitaufzeichnung/alsEndzeitUebernehmen']='Als Endzeit übernehmen'; -$this->phrasen['zeitaufzeichnung/alsStartzeitUebernehmen']='Als Startzeit übernehmen'; -$this->phrasen['zeitaufzeichnung/uebersicht']='Projektübersicht'; -$this->phrasen['zeitaufzeichnung/zeitraumAuffallendHoch']='Achtung, eingegebener Zeitraum ist auffallend hoch. \nWollen Sie die Daten dennoch speichern?'; -$this->phrasen['zeitaufzeichnung/bisDatumKleinerAlsVonDatum']='Das Bis-Datum darf nicht kleiner als das Von-Datum sein'; -$this->phrasen['zeitaufzeichnung/tagessumme']='Tagessumme:'; -$this->phrasen['zeitaufzeichnung/wochensumme']='Wochensumme:'; -$this->phrasen['zeitaufzeichnung/wochensummeEintraege']='Wochensumme Einträge'; -$this->phrasen['zeitaufzeichnung/wochensummeArbeitszeit']='Wochensumme Arbeitszeit'; -$this->phrasen['zeitaufzeichnung/xTageAnsicht']='%s Tage Ansicht'; -$this->phrasen['zeitaufzeichnung/endeXTageAnsicht']='Ende der %s Tage Ansicht'; -$this->phrasen['zeitaufzeichnung/alleAnzeigen']='Alle anzeigen'; -$this->phrasen['zeitaufzeichnung/alleEintraege']='Alle Einträge'; -$this->phrasen['zeitaufzeichnung/summeEintraege']='Summe Einträge'; -$this->phrasen['zeitaufzeichnung/arbeitszeit']='Arbeitszeit'; -$this->phrasen['zeitaufzeichnung/pause']='Pausen'; -$this->phrasen['zeitaufzeichnung/inklusivePflichtpause']='inkl. 30 min. Pflichtpause'; -$this->phrasen['zeitaufzeichnung/handbuchZeitaufzeichnung']='Arbeitszeitaufzeichnung Leitfaden'; -$this->phrasen['zeitaufzeichnung/fiktiveNormalarbeitszeit']='Vereinbarung der fiktiven Normalarbeitszeit'; -$this->phrasen['zeitaufzeichnung/projektexport']='Projektexport'; -$this->phrasen['zeitaufzeichnung/projektliste']='Projektliste'; -$this->phrasen['zeitaufzeichnung/projektlistegedruckt']='Projektliste gedruckt am:'; -$this->phrasen['zeitaufzeichnung/personalnr']='Personal-Nr.:'; -$this->phrasen['zeitaufzeichnung/jahr']='Jahr:'; -$this->phrasen['zeitaufzeichnung/monat']='Monat:'; -$this->phrasen['zeitaufzeichnung/tag']='Tag'; -$this->phrasen['zeitaufzeichnung/startdatum']='Startdatum:'; -$this->phrasen['zeitaufzeichnung/enddatum']='Enddatum:'; -$this->phrasen['zeitaufzeichnung/stunden']='Stunden'; -$this->phrasen['zeitaufzeichnung/taetigkeit']='Tätigkeit'; -$this->phrasen['zeitaufzeichnung/keineprojekte']='keine Projekte vorhanden'; -$this->phrasen['zeitaufzeichnung/summe']='Summe:'; -$this->phrasen['zeitaufzeichnung/dienstreise']='Dienstreise'; +phrasen['zeitaufzeichnung/zeitaufzeichnung']='Zeitaufzeichnung'; +$this->phrasen['zeitaufzeichnung/benutzerWurdeNichtGefunden']='Benutzer %s wurde nicht gefunden'; +$this->phrasen['zeitaufzeichnung/zeitaufzeichnungVon']='Zeitaufzeichnung von'; +$this->phrasen['zeitaufzeichnung/neu']='NEU'; +$this->phrasen['zeitaufzeichnung/projekt']='Projekt'; +$this->phrasen['zeitaufzeichnung/projektphase']='Projektphase'; +$this->phrasen['zeitaufzeichnung/keineAuswahl']='keine Auswahl'; +$this->phrasen['zeitaufzeichnung/aktivitaet']='Aktivität'; +$this->phrasen['zeitaufzeichnung/id']='ID'; +$this->phrasen['zeitaufzeichnung/user']='User'; +$this->phrasen['zeitaufzeichnung/start']='Start'; +$this->phrasen['zeitaufzeichnung/ende']='Ende'; +$this->phrasen['zeitaufzeichnung/dauer']='Dauer'; +$this->phrasen['zeitaufzeichnung/gesamtdauer']='Gesamtdauer'; +$this->phrasen['zeitaufzeichnung/sieSindDerzeitKeinenProjektenZugeordnet']='Sie sind derzeit keinen Projekten zugeordnet'; +$this->phrasen['zeitaufzeichnung/fehlerBeimErmittelnDerProjekte']='Fehler beim Ermitteln der Projekte'; +$this->phrasen['zeitaufzeichnung/organisationseinheit1']='Organisationseinheit 1'; +$this->phrasen['zeitaufzeichnung/organisationseinheit2']='Organisationseinheit 2'; +$this->phrasen['zeitaufzeichnung/organisationseinheiten']='Organisationseinheit'; +$this->phrasen['zeitaufzeichnung/oe']='OE'; +$this->phrasen['zeitaufzeichnung/service']='Service'; +$this->phrasen['zeitaufzeichnung/kunde']='Kunde'; +$this->phrasen['zeitaufzeichnung/alsNeuenEintragSpeichern']='Als neuen Eintrag speichern'; +$this->phrasen['zeitaufzeichnung/kartennummer']='Kartennummer'; +$this->phrasen['zeitaufzeichnung/oderKartennummerOptional']='oder Kartennummer (optional)'; +$this->phrasen['zeitaufzeichnung/nameEingeben']='Name eingeben'; +$this->phrasen['zeitaufzeichnung/aktuelleZeitLaden']='Aktuelle Zeit laden'; +$this->phrasen['zeitaufzeichnung/alsEndzeitUebernehmen']='Als Endzeit übernehmen'; +$this->phrasen['zeitaufzeichnung/alsStartzeitUebernehmen']='Als Startzeit übernehmen'; +$this->phrasen['zeitaufzeichnung/uebersicht']='Projektübersicht'; +$this->phrasen['zeitaufzeichnung/zeitraumAuffallendHoch']='Achtung, eingegebener Zeitraum ist auffallend hoch. \nWollen Sie die Daten dennoch speichern?'; +$this->phrasen['zeitaufzeichnung/bisDatumKleinerAlsVonDatum']='Das Bis-Datum darf nicht kleiner als das Von-Datum sein'; +$this->phrasen['zeitaufzeichnung/tagessumme']='Tagessumme:'; +$this->phrasen['zeitaufzeichnung/wochensumme']='Wochensumme:'; +$this->phrasen['zeitaufzeichnung/wochensummeEintraege']='Wochensumme Einträge'; +$this->phrasen['zeitaufzeichnung/wochensummeArbeitszeit']='Wochensumme Arbeitszeit'; +$this->phrasen['zeitaufzeichnung/xTageAnsicht']='%s Tage Ansicht'; +$this->phrasen['zeitaufzeichnung/endeXTageAnsicht']='Ende der %s Tage Ansicht'; +$this->phrasen['zeitaufzeichnung/alleAnzeigen']='Alle anzeigen'; +$this->phrasen['zeitaufzeichnung/alleEintraege']='Alle Einträge'; +$this->phrasen['zeitaufzeichnung/summeEintraege']='Summe Einträge'; +$this->phrasen['zeitaufzeichnung/arbeitszeit']='Arbeitszeit'; +$this->phrasen['zeitaufzeichnung/pause']='Pausen'; +$this->phrasen['zeitaufzeichnung/inklusivePflichtpause']='inkl. 30 min. Pflichtpause'; +$this->phrasen['zeitaufzeichnung/handbuchZeitaufzeichnung']='Arbeitszeitaufzeichnung Leitfaden'; +$this->phrasen['zeitaufzeichnung/fiktiveNormalarbeitszeit']='Vereinbarung der fiktiven Normalarbeitszeit'; +$this->phrasen['zeitaufzeichnung/projektexport']='Projektexport'; +$this->phrasen['zeitaufzeichnung/projektliste']='Projektliste'; +$this->phrasen['zeitaufzeichnung/projektlistegedruckt']='Projektliste gedruckt am:'; +$this->phrasen['zeitaufzeichnung/personalnr']='Personal-Nr.:'; +$this->phrasen['zeitaufzeichnung/jahr']='Jahr:'; +$this->phrasen['zeitaufzeichnung/monat']='Monat:'; +$this->phrasen['zeitaufzeichnung/tag']='Tag'; +$this->phrasen['zeitaufzeichnung/startdatum']='Startdatum:'; +$this->phrasen['zeitaufzeichnung/enddatum']='Enddatum:'; +$this->phrasen['zeitaufzeichnung/stunden']='Stunden'; +$this->phrasen['zeitaufzeichnung/taetigkeit']='Tätigkeit'; +$this->phrasen['zeitaufzeichnung/keineprojekte']='keine Projekte vorhanden'; +$this->phrasen['zeitaufzeichnung/summe']='Summe:'; +$this->phrasen['zeitaufzeichnung/dienstreise']='Dienstreise'; diff --git a/locale/en-US/zeitaufzeichnung.php b/locale/en-US/zeitaufzeichnung.php index bd887a5d0..936e65653 100644 --- a/locale/en-US/zeitaufzeichnung.php +++ b/locale/en-US/zeitaufzeichnung.php @@ -1,60 +1,61 @@ -phrasen['zeitaufzeichnung/zeitaufzeichnung']='Timesheet'; -$this->phrasen['zeitaufzeichnung/benutzerWurdeNichtGefunden']='User %s not found'; -$this->phrasen['zeitaufzeichnung/zeitaufzeichnungVon']='Timesheet for'; -$this->phrasen['zeitaufzeichnung/neu']='NEW'; -$this->phrasen['zeitaufzeichnung/projekt']='Project'; -$this->phrasen['zeitaufzeichnung/keineAuswahl']='no selection'; -$this->phrasen['zeitaufzeichnung/aktivitaet']='Activity'; -$this->phrasen['zeitaufzeichnung/id']='ID'; -$this->phrasen['zeitaufzeichnung/user']='User'; -$this->phrasen['zeitaufzeichnung/start']='Start'; -$this->phrasen['zeitaufzeichnung/ende']='End'; -$this->phrasen['zeitaufzeichnung/dauer']='Length'; -$this->phrasen['zeitaufzeichnung/gesamtdauer']='Total time'; -$this->phrasen['zeitaufzeichnung/sieSindDerzeitKeinenProjektenZugeordnet']='You are not currently assigned to any projects'; -$this->phrasen['zeitaufzeichnung/fehlerBeimErmittelnDerProjekte']='Error retrieving project data'; -$this->phrasen['zeitaufzeichnung/organisationseinheit1']='Organisation Unit 1'; -$this->phrasen['zeitaufzeichnung/organisationseinheit2']='Organisation Unit 2'; -$this->phrasen['zeitaufzeichnung/organisationseinheiten']='Organisation Unit'; -$this->phrasen['zeitaufzeichnung/oe']='OU'; -$this->phrasen['zeitaufzeichnung/service']='Service'; -$this->phrasen['zeitaufzeichnung/kunde']='Client'; -$this->phrasen['zeitaufzeichnung/alsNeuenEintragSpeichern']='Save as new'; -$this->phrasen['zeitaufzeichnung/kartennummer']='Number'; -$this->phrasen['zeitaufzeichnung/oderKartennummerOptional']='or number of card (optional)'; -$this->phrasen['zeitaufzeichnung/nameEingeben']='Enter name'; -$this->phrasen['zeitaufzeichnung/aktuelleZeitLaden']='Load current time'; -$this->phrasen['zeitaufzeichnung/alsEndzeitUebernehmen']='Transfer to endtime'; -$this->phrasen['zeitaufzeichnung/alsStartzeitUebernehmen']='Transfer to starttime'; -$this->phrasen['zeitaufzeichnung/uebersicht']='Projectoverview'; -$this->phrasen['zeitaufzeichnung/zeitraumAuffallendHoch']='Warning! Period entered is noticeably long. \nDo you want to save the dates anyway?'; -$this->phrasen['zeitaufzeichnung/bisDatumKleinerAlsVonDatum']='The \'To\' date may not be earlier than the \'From\' date.'; -$this->phrasen['zeitaufzeichnung/tagessumme']='Total day:'; -$this->phrasen['zeitaufzeichnung/wochensumme']='Total week:'; -$this->phrasen['zeitaufzeichnung/wochensummeEintraege']='Total week'; -$this->phrasen['zeitaufzeichnung/wochensummeArbeitszeit']='Total week working time'; -$this->phrasen['zeitaufzeichnung/xTageAnsicht']='%s days view'; -$this->phrasen['zeitaufzeichnung/endeXTageAnsicht']='End of %s days view'; -$this->phrasen['zeitaufzeichnung/alleAnzeigen']='Show all'; -$this->phrasen['zeitaufzeichnung/alleEintraege']='All entries'; -$this->phrasen['zeitaufzeichnung/summeEintraege']='Total'; -$this->phrasen['zeitaufzeichnung/arbeitszeit']='Working time'; -$this->phrasen['zeitaufzeichnung/pause']='Breaks'; -$this->phrasen['zeitaufzeichnung/inklusicePlichtpause']='incl. 30 min. lunch break'; -$this->phrasen['zeitaufzeichnung/handbuchZeitaufzeichnung']='Timesheet howto'; -$this->phrasen['zeitaufzeichnung/fiktiveNormalarbeitszeit']='Vereinbarung der fiktiven Normalarbeitszeit'; -$this->phrasen['zeitaufzeichnung/projektexport']='Projectexport'; -$this->phrasen['zeitaufzeichnung/projektliste']='Projectlist'; -$this->phrasen['zeitaufzeichnung/projektlistegedruckt']='Projectlist printed on:'; -$this->phrasen['zeitaufzeichnung/personalnr']='staff number '; -$this->phrasen['zeitaufzeichnung/jahr']='Year:'; -$this->phrasen['zeitaufzeichnung/monat']='Month:'; -$this->phrasen['zeitaufzeichnung/tag']='Day'; -$this->phrasen['zeitaufzeichnung/startdatum']='Startdate:'; -$this->phrasen['zeitaufzeichnung/enddatum']='Enddate:'; -$this->phrasen['zeitaufzeichnung/stunden']='Hours'; -$this->phrasen['zeitaufzeichnung/taetigkeit']='Activity'; -$this->phrasen['zeitaufzeichnung/keineprojekte']='no projects exist'; -$this->phrasen['zeitaufzeichnung/summe']='Sum:'; -$this->phrasen['zeitaufzeichnung/dienstreise']='Business Trip'; +phrasen['zeitaufzeichnung/zeitaufzeichnung']='Timesheet'; +$this->phrasen['zeitaufzeichnung/benutzerWurdeNichtGefunden']='User %s not found'; +$this->phrasen['zeitaufzeichnung/zeitaufzeichnungVon']='Timesheet for'; +$this->phrasen['zeitaufzeichnung/neu']='NEW'; +$this->phrasen['zeitaufzeichnung/projekt']='Project'; +$this->phrasen['zeitaufzeichnung/projektphase']='Projectphase'; +$this->phrasen['zeitaufzeichnung/keineAuswahl']='no selection'; +$this->phrasen['zeitaufzeichnung/aktivitaet']='Activity'; +$this->phrasen['zeitaufzeichnung/id']='ID'; +$this->phrasen['zeitaufzeichnung/user']='User'; +$this->phrasen['zeitaufzeichnung/start']='Start'; +$this->phrasen['zeitaufzeichnung/ende']='End'; +$this->phrasen['zeitaufzeichnung/dauer']='Length'; +$this->phrasen['zeitaufzeichnung/gesamtdauer']='Total time'; +$this->phrasen['zeitaufzeichnung/sieSindDerzeitKeinenProjektenZugeordnet']='You are not currently assigned to any projects'; +$this->phrasen['zeitaufzeichnung/fehlerBeimErmittelnDerProjekte']='Error retrieving project data'; +$this->phrasen['zeitaufzeichnung/organisationseinheit1']='Organisation Unit 1'; +$this->phrasen['zeitaufzeichnung/organisationseinheit2']='Organisation Unit 2'; +$this->phrasen['zeitaufzeichnung/organisationseinheiten']='Organisation Unit'; +$this->phrasen['zeitaufzeichnung/oe']='OU'; +$this->phrasen['zeitaufzeichnung/service']='Service'; +$this->phrasen['zeitaufzeichnung/kunde']='Client'; +$this->phrasen['zeitaufzeichnung/alsNeuenEintragSpeichern']='Save as new'; +$this->phrasen['zeitaufzeichnung/kartennummer']='Number'; +$this->phrasen['zeitaufzeichnung/oderKartennummerOptional']='or number of card (optional)'; +$this->phrasen['zeitaufzeichnung/nameEingeben']='Enter name'; +$this->phrasen['zeitaufzeichnung/aktuelleZeitLaden']='Load current time'; +$this->phrasen['zeitaufzeichnung/alsEndzeitUebernehmen']='Transfer to endtime'; +$this->phrasen['zeitaufzeichnung/alsStartzeitUebernehmen']='Transfer to starttime'; +$this->phrasen['zeitaufzeichnung/uebersicht']='Projectoverview'; +$this->phrasen['zeitaufzeichnung/zeitraumAuffallendHoch']='Warning! Period entered is noticeably long. \nDo you want to save the dates anyway?'; +$this->phrasen['zeitaufzeichnung/bisDatumKleinerAlsVonDatum']='The \'To\' date may not be earlier than the \'From\' date.'; +$this->phrasen['zeitaufzeichnung/tagessumme']='Total day:'; +$this->phrasen['zeitaufzeichnung/wochensumme']='Total week:'; +$this->phrasen['zeitaufzeichnung/wochensummeEintraege']='Total week'; +$this->phrasen['zeitaufzeichnung/wochensummeArbeitszeit']='Total week working time'; +$this->phrasen['zeitaufzeichnung/xTageAnsicht']='%s days view'; +$this->phrasen['zeitaufzeichnung/endeXTageAnsicht']='End of %s days view'; +$this->phrasen['zeitaufzeichnung/alleAnzeigen']='Show all'; +$this->phrasen['zeitaufzeichnung/alleEintraege']='All entries'; +$this->phrasen['zeitaufzeichnung/summeEintraege']='Total'; +$this->phrasen['zeitaufzeichnung/arbeitszeit']='Working time'; +$this->phrasen['zeitaufzeichnung/pause']='Breaks'; +$this->phrasen['zeitaufzeichnung/inklusicePlichtpause']='incl. 30 min. lunch break'; +$this->phrasen['zeitaufzeichnung/handbuchZeitaufzeichnung']='Timesheet howto'; +$this->phrasen['zeitaufzeichnung/fiktiveNormalarbeitszeit']='Vereinbarung der fiktiven Normalarbeitszeit'; +$this->phrasen['zeitaufzeichnung/projektexport']='Projectexport'; +$this->phrasen['zeitaufzeichnung/projektliste']='Projectlist'; +$this->phrasen['zeitaufzeichnung/projektlistegedruckt']='Projectlist printed on:'; +$this->phrasen['zeitaufzeichnung/personalnr']='staff number '; +$this->phrasen['zeitaufzeichnung/jahr']='Year:'; +$this->phrasen['zeitaufzeichnung/monat']='Month:'; +$this->phrasen['zeitaufzeichnung/tag']='Day'; +$this->phrasen['zeitaufzeichnung/startdatum']='Startdate:'; +$this->phrasen['zeitaufzeichnung/enddatum']='Enddate:'; +$this->phrasen['zeitaufzeichnung/stunden']='Hours'; +$this->phrasen['zeitaufzeichnung/taetigkeit']='Activity'; +$this->phrasen['zeitaufzeichnung/keineprojekte']='no projects exist'; +$this->phrasen['zeitaufzeichnung/summe']='Sum:'; +$this->phrasen['zeitaufzeichnung/dienstreise']='Business Trip'; diff --git a/locale/it-IT/zeitaufzeichnung.php b/locale/it-IT/zeitaufzeichnung.php index 04f222b4a..21e081de0 100644 --- a/locale/it-IT/zeitaufzeichnung.php +++ b/locale/it-IT/zeitaufzeichnung.php @@ -29,6 +29,7 @@ $this->phrasen['zeitaufzeichnung/organisationseinheit2']=''; $this->phrasen['zeitaufzeichnung/organisationseinheiten']=''; $this->phrasen['zeitaufzeichnung/pause']=''; $this->phrasen['zeitaufzeichnung/projekt']=''; +$this->phrasen['zeitaufzeichnung/projektphase']=''; $this->phrasen['zeitaufzeichnung/service']=''; $this->phrasen['zeitaufzeichnung/sieSindDerzeitKeinenProjektenZugeordnet']=''; $this->phrasen['zeitaufzeichnung/start']=''; From 14c279a03d0770776d9291994101677e98e208db Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Tue, 17 Sep 2019 15:45:48 +0200 Subject: [PATCH 164/500] =?UTF-8?q?Problem=20behoben=20wodurch=20Matrikeln?= =?UTF-8?q?ummern=20f=C3=BCr=20das=20falsche=20Semester=20angefordert=20wu?= =?UTF-8?q?rden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/dvb.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dvb.class.php b/include/dvb.class.php index 886b40eea..d3faffa9f 100644 --- a/include/dvb.class.php +++ b/include/dvb.class.php @@ -213,7 +213,7 @@ class dvb extends basis_db return ErrorHandler::error($errormsg); } - $studienjahr = substr($studiensemester_kurzbz, 4); + $studienjahr = substr($studiensemester_kurzbz, 2); $art = substr($studiensemester_kurzbz, 0, 2); if ($art == 'SS') $studienjahr = $studienjahr - 1; From ad5309e273a456c6d6a606a06dee20cf79e326f8 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 17 Sep 2019 15:54:41 +0200 Subject: [PATCH 165/500] Corrected SQL: bestellt/erteilt/akzeptiert in same row; added mitarbeiter_uid . Corrected SQL to get bestellt/erteilt/akzeptiert in same row Before it was creating new row for each stati, which was wrong. . Added mitarbeiter_uid column. . Changed column names for better maintainance and understanding. (e.g. row_index instead of id) --- .../lehre/lehrauftrag/Lehrauftrag.php | 23 +- .../views/lehre/lehrauftrag/lehrauftrag.php | 8 +- .../lehre/lehrauftrag/lehrauftragData.php | 353 ++++++++++-------- system/filtersupdate.php | 33 +- 4 files changed, 229 insertions(+), 188 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php index b85bf26dc..28f6ee8ec 100644 --- a/application/controllers/lehre/lehrauftrag/Lehrauftrag.php +++ b/application/controllers/lehre/lehrauftrag/Lehrauftrag.php @@ -25,7 +25,7 @@ class Lehrauftrag extends Auth_Controller parent::__construct( array( 'index' => 'lehre/lehrauftrag_bestellen:r', - 'orderLehrauftrag' => 'lehre/lehrauftrag_bestellen:rw' + 'orderLehrauftrag' => 'lehre/lehrauftrag_bestellen:rw', ) ); @@ -107,22 +107,23 @@ class Lehrauftrag extends Auth_Controller { if (!isEmptyArray($lehrauftrag)) { if ($this->VertragModel->save( - element('Person_ID', $lehrauftrag), - element('LV_ID', $lehrauftrag), - element('LE_ID', $lehrauftrag), - element('PA_ID', $lehrauftrag), - element('Stunden', $lehrauftrag), - element('Betrag', $lehrauftrag), - element('Studiensemester', $lehrauftrag) + element('person_id', $lehrauftrag), + element('mitarbeiter_uid', $lehrauftrag), + element('lehrveranstaltung_id', $lehrauftrag), + element('lehreinheit_id', $lehrauftrag), + element('projektarbeit_id', $lehrauftrag), + element('stunden', $lehrauftrag), + element('betrag', $lehrauftrag), + element('studiensemester_kurzbz', $lehrauftrag) )->retval) { $result []= array( - 'id' => $lehrauftrag['id'], - 'Bestellt' => date('Y-m-d') + 'row_index' => $lehrauftrag['row_index'], + 'bestellt' => date('Y-m-d') ); $new_lehrvertrag_data_arr[] = array( - 'studiensemester_kurzbz' => $lehrauftrag['Studiensemester'], + 'studiensemester_kurzbz' => $lehrauftrag['studiensemester_kurzbz'], 'studiengang_kz' => $lehrauftrag['studiengang_kz'], 'lv_oe_kurzbz' => $lehrauftrag['lv_oe_kurzbz'] ); diff --git a/application/views/lehre/lehrauftrag/lehrauftrag.php b/application/views/lehre/lehrauftrag/lehrauftrag.php index 6b93bb079..4072cdb84 100644 --- a/application/views/lehre/lehrauftrag/lehrauftrag.php +++ b/application/views/lehre/lehrauftrag/lehrauftrag.php @@ -132,7 +132,7 @@ $(function() { //$('#filterTabulator').tabulator('selectRow', true); $('#filterTabulator').tabulator('getRows') - .filter(row => row.getData().Bestellt == null) + .filter(row => row.getData().bestellt == null) .forEach((row => row.select())); }); @@ -143,12 +143,12 @@ $(function() { // Show all rows $("#show-all").click(function(){ - $('#filterTabulator').tabulator('removeFilter', 'Bestellt', '=', null); + $('#filterTabulator').tabulator('removeFilter', 'bestellt', '=', null); }); // Show only rows with new lehrauftraege $("#show-new").click(function(){ - $('#filterTabulator').tabulator('setFilter', 'Bestellt', '=', null); + $('#filterTabulator').tabulator('setFilter', 'bestellt', '=', null); }); // Order Lehrauftraege @@ -172,7 +172,7 @@ $(function() { }, errorCallback: function (jqXHR, textStatus, errorThrown) { - FHC_DialogLib.alertError("Sytemfehler
    Bestellung wurde nicht durchgeführt."); + FHC_DialogLib.alertError("Sytemfehler
    Bitte kontaktieren Sie Ihren Administrator."); } } ); diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 293b49849..d5cd01e89 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -4,139 +4,182 @@ $STUDIENSEMESTER = $studiensemester_selected; $STUDIENGANG = (isset($studiengang_selected) && !is_null($studiengang_selected)) ? array($studiengang_selected) : $studiengang; $query = ' - SELECT - ROW_NUMBER() OVER () AS "id", - * +SELECT + /* provide extra row index for tabulator, because no other column has unique ids */ + ROW_NUMBER() OVER () AS "row_index", * +FROM + ( + /* Lehraufträge and -vertragsstati */ + SELECT *, + /* existing contracts with status bestellt */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'bestellt\' + AND vertrag_id = tmp_lehrauftraege.vertrag_id) AS "bestellt", + /* existing contracts with status erteilt */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'erteilt\' + AND vertrag_id = tmp_lehrauftraege.vertrag_id) AS "erteilt", + /* existing contracts with status akzeptiert */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'akzeptiert\' + AND vertrag_id = tmp_lehrauftraege.vertrag_id) AS "akzeptiert" FROM ( - /* Lehraufträge and -vertragsstati */ SELECT - lema.lehreinheit_id AS "LE_ID", - lv.lehrveranstaltung_id AS "LV_ID", - NULL AS "PA_ID", - le.studiensemester_kurzbz AS "Studiensemester", - stg.studiengang_kz, - person.person_id AS "Person_ID", - upper(lv.lehrtyp_kurzbz) AS "Typ", - (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || \']\') AS "Auftrag", - CASE - WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) - WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) - ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) - END AS "Organisationseinheit", - lv.oe_kurzbz AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", - (person.vorname || \' \' || person.nachname) AS "Lektor", - TRUNC(lema.semesterstunden, 1) AS "Stunden", - TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "Betrag", - CASE - /* existing contracts for given study semester with status bestellt */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum - END AS "Bestellt", - CASE - /* existing contracts for given study semester with status erteilt */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum - END AS "Erteilt", - CASE - /* existing contracts for given study semester with status akzeptiert */ - WHEN lema.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum - END AS "Akzeptiert" - FROM - lehre.tbl_lehreinheitmitarbeiter lema - JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) - JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) - JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) - JOIN public.tbl_mitarbeiter ma USING (mitarbeiter_uid) - JOIN public.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid - JOIN public.tbl_person person USING (person_id) - LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) - LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) - LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) - JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz - WHERE - /* filter studiengang */ - lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') - /* filter studiensemester */ - AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' - /* filter active lehrveranstaltungen */ - AND lv.aktiv = TRUE - /* filter dummies and invalid mitarbeiter */ - AND ma.personalnummer >= 0 - - - UNION - - /* Projektbetreuungsaufträge and -vertragsstati */ - SELECT - pa.lehreinheit_id AS "LE_ID", - lv.lehrveranstaltung_id AS "LV_ID", - pa.projektarbeit_id AS "PA_ID", - le.studiensemester_kurzbz AS "Studiensemester", - stg.studiengang_kz, - person.person_id AS "Person_ID", - \'Betreuung\' AS "Typ", - (betreuerart_kurzbz || \' \' || - (SELECT - vorname || \' \' || nachname - FROM - public.tbl_person - JOIN public.tbl_benutzer USING (person_id) - WHERE - uid = pa.student_uid) - || \' [\' || projekttyp_kurzbz || \'arbeit\' || \' \' || lv.semester || \'.Semester]\') AS "Auftrag", - CASE - WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) - WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) - ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) - END AS "Organisationseinheit", - lv.oe_kurzbz AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, \'\n\' || legr.gruppe_kurzbz) AS "Gruppe", - (vorname || \' \' || nachname) AS "Lektor", - TRUNC(pb.stunden, 1) AS "Stunden", - TRUNC((pb.stunden * pb.stundensatz), 2) AS "Betrag", - CASE - /* existing contracts for given study semester with status bestellt */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'bestellt\' THEN vvs.datum - END AS "Bestellt", - CASE - /* existing contracts for given study semester with status erteilt */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'erteilt\' THEN vvs.datum - END AS "Erteilt", - CASE - /* existing contracts for given study semester with status akzeptiert */ - WHEN pb.vertrag_id NOTNULL AND vertrag.vertragsstunden_studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' AND - vvs.vertragsstatus_kurzbz = \'akzeptiert\' THEN vvs.datum - END AS "Akzeptiert" - FROM - lehre.tbl_projektbetreuer pb - JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id) - JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) - JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) - JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) - JOIN public.tbl_person person USING (person_id) - LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) - LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) - LEFT JOIN lehre.tbl_vertragsstatus status USING (vertragsstatus_kurzbz) - JOIN public.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz - WHERE - /* filter studiengang */ - lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') - /* filter studiensemester */ - AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' - /* filter active lehrveranstaltungen */ - AND lv.aktiv = TRUE - - ORDER BY "Typ" DESC, "Auftrag", "Lektor" - ) auftraege - '; + lema.lehreinheit_id, + lv.lehrveranstaltung_id, + NULL AS "projektarbeit_id", + le.studiensemester_kurzbz, + stg.studiengang_kz, + person.person_id, + upper(lv.lehrtyp_kurzbz) AS "typ", + (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || + \']\') AS "auftrag", + CASE + WHEN oe.organisationseinheittyp_kurzbz = \'Kompetenzfeld\' THEN (\'KF \' || oe.bezeichnung) + WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) + ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) + END AS "lv_oe_kurzbz", + CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, + \'\n\' || legr.gruppe_kurzbz) AS "gruppe", + (person.vorname || \' \' || person.nachname) AS "lektor", + TRUNC(lema.semesterstunden, 1) AS "stunden", + TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "betrag", + vertrag_id, + mitarbeiter_uid + FROM + lehre.tbl_lehreinheitmitarbeiter lema + JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) + JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) + JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) + JOIN PUBLIC.tbl_mitarbeiter ma USING (mitarbeiter_uid) + JOIN PUBLIC.tbl_benutzer benutzer + ON ma.mitarbeiter_uid = benutzer.uid + JOIN PUBLIC.tbl_person person USING (person_id) + LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) + JOIN PUBLIC.tbl_studiengang stg ON stg.studiengang_kz = lv.studiengang_kz + WHERE + /* filter studiengang */ + lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') + /* filter studiensemester */ + AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' + /* filter active lehrveranstaltungen */ + AND lv.aktiv = TRUE + /* filter active organisationseinheiten */ + AND oe.aktiv = TRUE + /* filter dummies and invalid mitarbeiter */ + AND ma.personalnummer >= 0 + ) tmp_lehrauftraege + UNION + + /* Projektbetreuungsaufträge and -vertragsstati */ + SELECT *, + (SELECT + uid + FROM + public.tbl_benutzer + WHERE + person_id = tmp_projektbetreuung.person_id + AND aktiv = TRUE) AS "mitarbeiter_uid", + /* existing contracts with status bestellt */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'bestellt\' + AND vertrag_id = tmp_projektbetreuung.vertrag_id) AS "bestellt", + /* existing contracts with status erteilt */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'erteilt\' + AND vertrag_id = tmp_projektbetreuung.vertrag_id) AS "erteilt", + /* existing contracts with status akzeptiert */ + (SELECT + datum + FROM + lehre.tbl_vertrag_vertragsstatus + WHERE + tbl_vertrag_vertragsstatus.vertragsstatus_kurzbz = \'akzeptiert\' + AND vertrag_id = tmp_projektbetreuung.vertrag_id) AS "akzeptiert" + FROM + ( + SELECT + pa.lehreinheit_id, + lv.lehrveranstaltung_id, + pa.projektarbeit_id AS "projektarbeit_id", + le.studiensemester_kurzbz, + stg.studiengang_kz, + person.person_id, + \'Betreuung\' AS "typ", + (betreuerart_kurzbz || \' \' || + (SELECT + vorname || \' \' || nachname + FROM + PUBLIC.tbl_person + JOIN PUBLIC.tbl_benutzer USING (person_id) + WHERE + uid = pa.student_uid + ) + || \' [\' || projekttyp_kurzbz || \'arbeit\' || \' \' || lv.semester || \'.Semester]\') AS "auftrag", + CASE + WHEN oe.organisationseinheittyp_kurzbz = + \'Kompetenzfeld\' THEN ( + \'KF \' || oe.bezeichnung) + WHEN oe.organisationseinheittyp_kurzbz = + \'Department\' THEN ( + \'DEP \' || oe.bezeichnung) + ELSE (oe.organisationseinheittyp_kurzbz || + \' \' || oe.bezeichnung) + END AS "lv_oe_kurzbz", + CONCAT(stg.kurzbzlang, + \'-\', legr.semester, legr.verband, legr.gruppe, + \'\n\' || legr.gruppe_kurzbz) AS "gruppe", + (vorname || \' \' || nachname) AS "lektor", + TRUNC(pb.stunden, 1) AS "stunden", + TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag", + vertrag_id + FROM + lehre.tbl_projektbetreuer pb + JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id) + JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) + JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) + JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) + JOIN PUBLIC.tbl_person person USING (person_id) + LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) + JOIN PUBLIC.tbl_studiengang stg + ON stg.studiengang_kz = lv.studiengang_kz + WHERE + /* filter studiengang */ + lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ') + /* filter studiensemester */ + AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\' + /* filter active lehrveranstaltungen */ + AND lv.aktiv = TRUE + /* filter active organisationseinheiten */ + AND oe.aktiv = TRUE + ) tmp_projektbetreuung + ) auftraege +ORDER BY "typ" DESC, "auftrag", "lektor" +'; $filterWidgetArray = array( 'query' => $query, @@ -150,7 +193,7 @@ $filterWidgetArray = array( 'hideOptions' => true, 'hideMenu' => true, 'columnsAliases' => array( // TODO: use phrasen - 'id', + 'row_index', 'LE-ID', 'LV-ID', 'PA-ID', @@ -160,22 +203,16 @@ $filterWidgetArray = array( ucfirst($this->p->t('global', 'typ')), 'Auftrag', 'Organisationseinheit', - 'lv_oe_kurzbz', 'Gruppe', 'Lektor', 'Stunden', 'Betrag', + 'Vertrag-ID', + 'UID', 'Bestellt', 'Erteilt', 'Akzeptiert' ), - 'formatRow' => function($datasetRaw) { - if (is_null($datasetRaw->{'Betrag'})) - { - $datasetRaw->{'Betrag'} = 'Stundensatz fehlt'; - } - return $datasetRaw; - }, 'datasetRepOptions' => '{ height: 700, layout:"fitColumns", // fit columns to width of table @@ -184,31 +221,33 @@ $filterWidgetArray = array( selectableRangeMode: "click", // allows range selection using shift end click on end of range selectablePersistence:false, // deselect previously selected rows when table is filtered, sorted or paginated selectableCheck: function(row){ // only allow selection if is not bestellt (as order already exists) - return row.getData().Bestellt == null; + return row.getData().bestellt == null; }, movableColumns: true, // allows changing column - headerFilterPlaceholder: " " + headerFilterPlaceholder: " ", + index: "row_index" // assign specific column as unique id (important for row indexing) }', // tabulator properties 'datasetRepFieldsDefs' => '{ - id: {visible:false}, // necessary for row indexing - LE_ID: {headerFilter:"input", bottomCalc:"count"}, - LV_ID: {visible: false}, - PA_ID: {visible: false}, - Studiensemester: {visible: false}, + row_index: {visible:false}, // necessary for row indexing + lehreinheit_id: {headerFilter:"input", bottomCalc:"count"}, + lehrveranstaltung_id: {headerFilter:"input"}, + projektarbeit_id: {visible: false}, + studiensemester_kurzbz: {headerFilter:"input"}, studiengang_kz: {visible: false}, - Person_ID: {visible: false}, - Typ: {headerFilter:"input"}, - Auftrag: {headerFilter:"input"}, - Organisationseinheit: {headerFilter:"input"}, - lv_oe_kurzbz: {visible: false}, - Gruppe: {headerFilter:"input"}, - Lektor: {headerFilter:"input"}, - Stunden: {align:"right", headerFilter:"input", bottomCalc:"sum", bottomCalcParams:{precision:1}}, - Betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc: hf_compareWithFloat, + person_id: {visible: false}, + typ: {headerFilter:"input"}, + auftrag: {headerFilter:"input"}, + lv_oe_kurzbz: {headerFilter:"input"}, + gruppe: {headerFilter:"input"}, + lektor: {headerFilter:"input"}, + stunden: {align:"right", headerFilter:"input", bottomCalc:"sum", bottomCalcParams:{precision:1}}, + betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc: hf_compareWithFloat, bottomCalc:"sum", bottomCalcParams:{precision:2}, bottomCalcFormatter:"money", bottomCalcFormatterParams:{decimal: ",", thousand: ".", symbol:"€"}}, - Bestellt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, - Erteilt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, - Akzeptiert: {align:"center", headerFilter:"input", mutator: mut_formatStringDate} + vertrag_id: {visible: false}, + mitarbeiter_uid: {visible: false}, + bestellt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, + erteilt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, + akzeptiert: {align:"center", headerFilter:"input", mutator: mut_formatStringDate} }', // col properties ); diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 2140852d1..e65250977 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -410,24 +410,25 @@ $filters = array( { "name": "", "columns": [ - {"name": "id"}, - {"name": "LE_ID"}, - {"name": "LV_ID"}, - {"name": "PA_ID"}, - {"name": "Studiensemester"}, + {"name": "row_index"}, + {"name": "lehreinheit_id"}, + {"name": "lehrveranstaltung_id"}, + {"name": "projektarbeit_id"}, + {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, - {"name": "Person_ID"}, - {"name": "Typ"}, - {"name": "Auftrag"}, - {"name": "Organisationseinheit"}, + {"name": "person_id"}, + {"name": "typ"}, + {"name": "auftrag"}, {"name": "lv_oe_kurzbz"}, - {"name": "Gruppe"}, - {"name": "Lektor"}, - {"name": "Stunden"}, - {"name": "Betrag"}, - {"name": "Bestellt"}, - {"name": "Erteilt"}, - {"name": "Akzeptiert"} + {"name": "gruppe"}, + {"name": "lektor"}, + {"name": "stunden"}, + {"name": "betrag"}, + {"name": "vertrag_id"}, + {"name": "mitarbeiter_uid"}, + {"name": "bestellt"}, + {"name": "erteilt"}, + {"name": "akzeptiert"} ], "filters": [] } From e39a4252eb767dd750408265cc30bce2718da245 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 17 Sep 2019 15:58:40 +0200 Subject: [PATCH 166/500] Added param mitarbeiter_uid to method save() For performance reasons. (Before the uid was retrieved by loading BenutzerModel each time when saving lots of contracts) --- application/models/accounting/Vertrag_model.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index b5158eb22..181f89ab7 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -25,7 +25,7 @@ class Vertrag_model extends DB_Model * @param $vertragstyp_kurzbz * @return array|null On success object. On failure null. */ - public function save($person_id, $lehrveranstaltung_id, $lehreinheit_id, $projektarbeit_id = null, $vertragsstunden, $betrag, $studiensemester_kurzbz){ + public function save($person_id, $mitarbeiter_uid, $lehrveranstaltung_id, $lehreinheit_id, $projektarbeit_id = null, $vertragsstunden, $betrag, $studiensemester_kurzbz){ // Cast input params $person_id = (!isset($person_id) || empty($person_id)) ? null : intval($person_id); @@ -34,17 +34,13 @@ class Vertrag_model extends DB_Model $projektarbeit_id = (!isset($projektarbeit_id) || empty($projektarbeit_id)) ? null : intval($projektarbeit_id); $vertragsstunden = (!isset($vertragsstunden) || empty($vertragsstunden)) ? null : floatval($vertragsstunden); $betrag = (!isset($betrag) || empty($betrag)) ? null : floatval($betrag); + $mitarbeiter_uid = (!isset($mitarbeiter_uid) || empty($mitarbeiter_uid)) ? null : $mitarbeiter_uid; $vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung'; $result = array(); $user = getAuthUID(); - // Retrieve mitarbeiter uid from person_id - $this->load->model('person/Benutzer_model', 'BenutzerModel'); - $benutzer = $this->BenutzerModel->getFromPersonId($person_id)->retval; - $mitarbeiter_uid = $benutzer[0]->uid; // lectors uid - // First check if Vertrag already exists for that Lehrauftrag or for that Projektbetreuerauftrag if ($vertragstyp_kurzbz == 'Lehrauftrag') { From 1da2a19d578295646d71f51195600150dcd9634f Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Wed, 18 Sep 2019 13:39:03 +0200 Subject: [PATCH 167/500] Ansprechpartner bei Account Deaktivierung korrigiert --- system/account_deaktivierung_mail.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/account_deaktivierung_mail.php b/system/account_deaktivierung_mail.php index 083295461..289846a72 100644 --- a/system/account_deaktivierung_mail.php +++ b/system/account_deaktivierung_mail.php @@ -58,7 +58,7 @@ if($result = $db->db_query($qry)) $message .= " - Ihr Home-Verzeichnis (inkl. aller Dateien) gelöscht werden.\n"; $message .= "\n"; $message .= "Falls es sich bei der Deaktivierung um einen Irrtum handelt, würden wir Sie bitten, sich umgehend mit den KollegInnen in der Personalabteilung in Verbindung zu setzen: "; - $message .= "Frau Natalie König, natalie.koenig@technikum-wien.at\n"; + $message .= "Frau Dragana Vitorovic, dragana.vitorovic@technikum-wien.at\n"; $message .= "\n"; $message .= "Mit freundlichen Grüßen\n"; $message .= "\n"; @@ -212,7 +212,7 @@ if($result = $db->db_query($qry)) $message .= " - Ihr Home-Verzeichnis (inkl. aller Dateien) gelöscht werden\n"; $message .= "\n"; $message .= "Falls es sich bei der Deaktivierung um einen Irrtum handelt, würden wir Sie bitten, sich umgehend mit den KollegInnen in der Personalabteilung in Verbindung zu setzen: "; - $message .= "Frau Natalie König, natalie.koenig@technikum-wien.at\n"; + $message .= "Frau Dragana Vitorovic, dragana.vitorovic@technikum-wien.at\n"; $message .= "\n"; $message .= "Mit freundlichen Grüßen\n"; $message .= "\n"; From 6669014ac40df14433d2e72d25f612cf523112ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Thu, 19 Sep 2019 09:19:09 +0200 Subject: [PATCH 168/500] =?UTF-8?q?Neue=20Felder=20f=C3=BCr=20UHSTAT2=20Me?= =?UTF-8?q?ldung=20zu=20IO=20Karteireiter=20hinzugef=C3=BCgt=20=20=20Mehrf?= =?UTF-8?q?achangabe=20von=20Zweck=20des=20Auslandsaufenthalts=20=20=20Meh?= =?UTF-8?q?rfachangabe=20von=20F=C3=B6rderung=20des=20Auslandsaufenthalts?= =?UTF-8?q?=20=20=20Neue=20Felder=20f=C3=BCr=20erworbene=20und=20angerechn?= =?UTF-8?q?ete=20ECTS=20hinzugef=C3=BCgt=20=20=20BIS=20Schnittstelle=20um?= =?UTF-8?q?=20die=20neuen=20Felder=20erweitert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/student/studentDBDML.php | 207 ++++- content/student/studentiooverlay.xul.php | 323 +++++--- content/student/studentoverlay.js.php | 433 ++++++++++- include/bisio.class.php | 946 +++++++++++++++-------- rdf/aufenthaltfoerderung.rdf.php | 44 ++ rdf/bisio.rdf.php | 6 +- rdf/zweck.rdf.php | 26 +- system/dbupdate_3.3.php | 110 ++- vilesci/bis/studentenmeldung.php | 36 +- 9 files changed, 1657 insertions(+), 474 deletions(-) create mode 100644 rdf/aufenthaltfoerderung.rdf.php diff --git a/content/student/studentDBDML.php b/content/student/studentDBDML.php index 6f7c310ba..447c5988f 100644 --- a/content/student/studentDBDML.php +++ b/content/student/studentDBDML.php @@ -2669,11 +2669,12 @@ if(!$error) $bisio->nation_code = $_POST['nation_code']; $bisio->von = $_POST['von']; $bisio->bis = $_POST['bis']; - $bisio->zweck_code = $_POST['zweck_code']; $bisio->student_uid = $_POST['student_uid']; $bisio->lehreinheit_id = $_POST['lehreinheit_id']; $bisio->ort = $_POST['ort']; $bisio->universitaet = $_POST['universitaet']; + $bisio->ects_erworben = $_POST['ects_erworben']; + $bisio->ects_angerechnet = $_POST['ects_angerechnet']; $bisio->updateamum = date('Y-m-d H:i:s'); $bisio->updatevon = $user; @@ -2692,6 +2693,210 @@ if(!$error) } } } + elseif(isset($_POST['type']) && $_POST['type']=='savebisiozweck') + { + $bisio = new bisio(); + if($bisio->load($_POST['bisio_id'])) + { + $student = new student(); + if($student->load($bisio->student_uid)) + { + + //Speichert einen BisIO Eintrag + if(!$rechte->isBerechtigt('assistenz',$student->studiengang_kz,'suid') && + !$rechte->isBerechtigt('admin',$student->studiengang_kz, 'suid')) + { + $error = true; + $return = false; + $errormsg = 'Sie haben keine Berechtigung'; + } + else + { + + $bisio = new bisio(); + + $bisio->bisio_id = (isset($_POST['bisio_id'])?$_POST['bisio_id']:''); + $bisio->zweck_code = $_POST['zweck_code']; + + if(!$error) + { + if($bisio->saveZweck()) + { + $return = true; + $data = $bisio->bisio_id; + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + } + } + else + { + $errormsg = $student->errormsg; + $return = false; + } + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='deletebisiozweck') + { + $bisio = new bisio(); + if($bisio->load($_POST['bisio_id'])) + { + $student = new student(); + if($student->load($bisio->student_uid)) + { + //Speichert einen BisIO Eintrag + if(!$rechte->isBerechtigt('assistenz',$student->studiengang_kz,'suid') && + !$rechte->isBerechtigt('admin',$student->studiengang_kz, 'suid')) + { + $error = true; + $return = false; + $errormsg = 'Sie haben keine Berechtigung'; + } + else + { + + $bisio = new bisio(); + + $bisio->bisio_id = (isset($_POST['bisio_id'])?$_POST['bisio_id']:''); + $bisio->zweck_code = $_POST['zweck_code']; + + if(!$error) + { + if($bisio->deleteZweck()) + { + $return = true; + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + } + } + else + { + $errormsg = $student->errormsg; + $return = false; + } + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='savebisioaufenthaltfoerderung') + { + $bisio = new bisio(); + if($bisio->load($_POST['bisio_id'])) + { + $student = new student(); + if($student->load($bisio->student_uid)) + { + + //Speichert einen BisIO Eintrag + if(!$rechte->isBerechtigt('assistenz',$student->studiengang_kz,'suid') && + !$rechte->isBerechtigt('admin',$student->studiengang_kz, 'suid')) + { + $error = true; + $return = false; + $errormsg = 'Sie haben keine Berechtigung'; + } + else + { + + $bisio = new bisio(); + + $bisio->bisio_id = (isset($_POST['bisio_id'])?$_POST['bisio_id']:''); + $bisio->aufenthaltfoerderung_code = $_POST['aufenthaltfoerderung_code']; + + if(!$error) + { + if($bisio->saveAufenthaltFoerderung()) + { + $return = true; + $data = $bisio->bisio_id; + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + } + } + else + { + $errormsg = $student->errormsg; + $return = false; + } + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='deletebisioaufenthaltfoerderung') + { + $bisio = new bisio(); + if($bisio->load($_POST['bisio_id'])) + { + $student = new student(); + if($student->load($bisio->student_uid)) + { + //Speichert einen BisIO Eintrag + if(!$rechte->isBerechtigt('assistenz',$student->studiengang_kz,'suid') && + !$rechte->isBerechtigt('admin',$student->studiengang_kz, 'suid')) + { + $error = true; + $return = false; + $errormsg = 'Sie haben keine Berechtigung'; + } + else + { + + $bisio = new bisio(); + + $bisio->bisio_id = (isset($_POST['bisio_id'])?$_POST['bisio_id']:''); + $bisio->aufenthaltfoerderung_code = $_POST['aufenthaltfoerderung_code']; + + if(!$error) + { + if($bisio->deleteAufenthaltFoerderung()) + { + $return = true; + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } + } + } + else + { + $errormsg = $student->errormsg; + $return = false; + } + } + else + { + $errormsg = $bisio->errormsg; + $return = false; + } + } elseif(isset($_POST['type']) && $_POST['type']=='getnotenotenschluessel') { if(!$rechte->isBerechtigt('admin', null, 's') && !$rechte->isBerechtigt('assistenz', null, 's') && diff --git a/content/student/studentiooverlay.xul.php b/content/student/studentiooverlay.xul.php index 4ccf78c08..9d4eb89b9 100644 --- a/content/student/studentiooverlay.xul.php +++ b/content/student/studentiooverlay.xul.php @@ -35,85 +35,92 @@ echo ''; xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > - + + + + + + + + + + + + + + - - - + + + +
    "); + $("#filterTableDataset > thead > tr").append(""); } var arrayFieldsToDisplay = FHC_FilterWidget._getFieldsToDisplay(data); @@ -922,7 +861,7 @@ var FHC_FilterWidget = { { var columnName = arrayFieldsToDisplay[i]; - filterWidgetDiv.find("#filterTableDataset > thead > tr").append(""); + $("#filterTableDataset > thead > tr").append(""); } if (data.hasOwnProperty("additionalColumns") && $.isArray(data.additionalColumns)) @@ -931,7 +870,7 @@ var FHC_FilterWidget = { { var columnName = data.additionalColumns[i]; - filterWidgetDiv.find("#filterTableDataset > thead > tr").append(""); + $("#filterTableDataset > thead > tr").append(""); } } @@ -942,8 +881,8 @@ var FHC_FilterWidget = { if (data.checkboxes != null && data.checkboxes != "") { // select checkbox range with shift key - if (typeof filterWidgetDiv.find("#filterTableDataset").checkboxes === 'function') - filterWidgetDiv.find("#filterTableDataset").checkboxes("range", true); + if (typeof $("#filterTableDataset").checkboxes === 'function') + $("#filterTableDataset").checkboxes("range", true); } for (var i = 0; i < data.dataset.length; i++) @@ -985,7 +924,7 @@ var FHC_FilterWidget = { strHtml += ""; - filterWidgetDiv.find("#filterTableDataset > tbody").append(strHtml); + $("#filterTableDataset > tbody").append(strHtml); } } } @@ -994,9 +933,9 @@ var FHC_FilterWidget = { /** * Enable the tablesorter libs to render the dataset table with sorting features */ - _enableTableSorter: function(filterWidgetDiv) { + _enableTableSorter: function() { - var filterWidgetTablesorter = filterWidgetDiv.find("#filterTableDataset"); + var filterWidgetTablesorter = $("#filterTableDataset"); // Checks if the table contains data (rows) if (filterWidgetTablesorter.find("tbody:empty").length == 0 @@ -1013,7 +952,7 @@ var FHC_FilterWidget = { // Reset filter storage if there is a filter id in url var filter_id = FHC_AjaxClient.getUrlParameter("filter_id"); - if (typeof filter_id !== "undefined") FHC_FilterWidget._cleanTablesorterLocalStorage(filterWidgetTablesorter); + if (typeof filter_id !== "undefined") FHC_FilterWidget._cleanTablesorterLocalStorage(); $.tablesorter.updateAll(filterWidgetTablesorter[0].config, true, null); } @@ -1022,24 +961,24 @@ var FHC_FilterWidget = { /** * Disable the tablesorter */ - _disableTablesorter: function(filterWidgetDiv) { + _disableTablesorter: function() { - filterWidgetDiv.find("#filterTableDataset").trigger("disable"); + $("#filterTableDataset").trigger("disable"); }, /** * Tablesorter filter local storage clean */ - _cleanTablesorterLocalStorage: function(filterWidgetTablesorter) { + _cleanTablesorterLocalStorage: function() { - filterWidgetTablesorter.trigger("filterResetSaved"); + $("#filterTableDataset").trigger("filterResetSaved"); }, /** * Renders the pivotUI for the FilterWidget * The data to be displayed are retrived from the parameter data */ - _renderDatasetPivotUI: function(filterWidgetDiv, data) { + _renderDatasetPivotUI: function(data) { // Checks if options were given and returns them var options = FHC_FilterWidget._getRepresentationOptions(data); @@ -1088,7 +1027,7 @@ var FHC_FilterWidget = { } // Renders the pivotUI - filterWidgetDiv.find("#filterPivotUI").pivotUI( + $("#filterPivotUI").pivotUI( pivotUIData, options ); @@ -1131,7 +1070,7 @@ var FHC_FilterWidget = { * Renders the tabulator for the FilterWidget * The data to be displayed are retrived from the parameter data */ - _renderDatasetTabulator: function(filterWidgetDiv, data) { + _renderDatasetTabulator: function(data) { // Checks if options were given and returns them var options = FHC_FilterWidget._getRepresentationOptions(data); @@ -1152,7 +1091,7 @@ var FHC_FilterWidget = { options.data = data.dataset; // Renders the tabulator - filterWidgetDiv.find("#filterTabulator").tabulator(options); + $("#filterTabulator").tabulator(options); } } }, @@ -1283,11 +1222,7 @@ var FHC_FilterWidget = { */ _setHideMenu: function(data) { - if (FHC_FilterWidget._filterWidgetsAttributes.length > 1) - { - FHC_FilterWidget._hideMenu = true; - } - else if (data.hasOwnProperty("hideMenu")) + if (data.hasOwnProperty("hideMenu")) { FHC_FilterWidget._hideMenu = data.hideMenu; } @@ -1302,33 +1237,6 @@ var FHC_FilterWidget = { { FHC_FilterWidget._hideOptions = data.hideOptions; } - }, - - /** - * Return true if there are more then one FilterWidget in this page, otherwise false - */ - _isMultipleFilterWidgets: function() { - - return $("div[id*='divFilterWidgetDataset']").length > 1; - }, - - /** - * - */ - _setFilterWidgetsAttributes: function() { - - FHC_FilterWidget._filterWidgetsAttributes = []; - - $("div[id*='divFilterWidgetDataset']").each(function(i, e) { - - var filterWidgetsAttributes = {}; - - filterWidgetsAttributes.app = e.attributes["app"].nodeValue; - filterWidgetsAttributes.dataset = e.attributes["dataset"].nodeValue; - filterWidgetsAttributes.filterid = e.attributes["filterid"].nodeValue; - - FHC_FilterWidget._filterWidgetsAttributes.push(filterWidgetsAttributes); - }); } }; diff --git a/public/js/infocenter/infocenterPersonDataset.js b/public/js/infocenter/infocenterPersonDataset.js index 213539f49..6c49c6a06 100644 --- a/public/js/infocenter/infocenterPersonDataset.js +++ b/public/js/infocenter/infocenterPersonDataset.js @@ -49,10 +49,7 @@ var InfocenterPersonDataset = { FHC_AjaxClient.ajaxCallGet( 'widgets/Filters/rowNumber', { - filterUniqueId: FHC_FilterWidget.getFilterUniqueIdPrefix() + "/" + - $("#divFilterWidgetDataset").attr("app") + ":" + - $("#divFilterWidgetDataset").attr("dataset") + ":" + - $("#divFilterWidgetDataset").attr("filterid") + filterUniqueId: FHC_FilterWidget.getFilterUniqueIdPrefix() }, { successCallback: function(data, textStatus, jqXHR) { From a2ecd9bdbca5d5b6eca13c3f178b0a985379bcf8 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 23 Sep 2019 17:47:11 +0200 Subject: [PATCH 183/500] - zeitaufzeichnung_projektliste.php: separate sheet for each projekt - fixed rounding sum issues for Projektphasen - subtraction of pausen from Projektphase duration - errorfree display if no projekt entered - added projektphase_id to zeitaufzeichnung.class.php in getListe methods --- .../tools/zeitaufzeichnung_projektliste.php | 629 +++++++++++------- include/zeitaufzeichnung.class.php | 3 + 2 files changed, 407 insertions(+), 225 deletions(-) diff --git a/cis/private/tools/zeitaufzeichnung_projektliste.php b/cis/private/tools/zeitaufzeichnung_projektliste.php index 17adfba97..64cf0ae9b 100644 --- a/cis/private/tools/zeitaufzeichnung_projektliste.php +++ b/cis/private/tools/zeitaufzeichnung_projektliste.php @@ -32,6 +32,7 @@ require_once('../../../include/benutzer.class.php'); require_once('../../../include/mitarbeiter.class.php'); require_once('../../../include/zeitaufzeichnung.class.php'); require_once('../../../include/projekt.class.php'); +require_once('../../../include/projektphase.class.php'); if (!isset($_GET['projexpmonat'])) die("Parameter monat fehlt"); @@ -61,17 +62,19 @@ $daysinmonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); $date = new datum(); $ztauf = new zeitaufzeichnung(); +$projektphaseclass = new projektphase(); $activitiesToIgnore = array('DienstreiseMT', 'Ersatzruhe');//aktivitaetstypen which shouldn't be added to worktime $ztauf->getListeUserFromTo($uid, $year.'-'.$month.'-01', $year.'-'.$month.'-'.$daysinmonth, $activitiesToIgnore); //objects for one projectline of list (corresponds to one day) -$projectlines = []; +$projektlines = array(); $dayStart = $dayEnd = ''; -$projectnames = $tosubtract = $allpauseranges = []; +$projektnames = $projektphasenames = $tosubtract = $allpauseranges = array(); $activitiesToSubtract = ['Pause', 'LehreExtern', 'Arztbesuch', 'Behoerde'];//aktivitaetstypen which should be subtracted fromworktime $ztaufdata = $ztauf->result; -$monthsums = [0 => 0.00]; +$totalmonthsum = 0.00; +$projektmonthsums = array(); //sort list by startdate ascending (if not already done in zeitaufzeichnung class) usort($ztaufdata, function ($ztaufa, $ztaufb) @@ -85,12 +88,13 @@ usort($ztaufdata, function ($ztaufa, $ztaufb) for ($i = 0; $i < count($ztaufdata); $i++) { $ztaufrow = $ztaufdata[$i]; + //make sure dates are in correct format $ztaufrow->start = $date->formatDatum($ztaufrow->start, $format = 'Y-m-d H:i:s'); $ztaufrow->ende = $date->formatDatum($ztaufrow->ende, $format = 'Y-m-d H:i:s'); $day = intval($date->formatDatum($ztaufrow->ende, 'd')); //first entry for a day - $isFirstEntry = !isset($projectlines[$day]); + $isFirstEntry = !isset($projektlines[$day]); //last entry for a day (next entry is different day) $isLastEntry = !array_key_exists($i + 1, $ztaufdata) || intval($date->formatDatum($ztaufdata[$i + 1]->ende, 'd')) != $day; @@ -137,18 +141,19 @@ for ($i = 0; $i < count($ztaufdata); $i++) if ($isFirstEntry) { - $projectlines[$day] = new stdClass(); - $projectlines[$day]->arbeitszeit = ''; - $projectlines[$day]->projekte = []; + $projektlines[$day] = new stdClass(); + $projektlines[$day]->arbeitszeit = ''; + $projektlines[$day]->projekte = []; } if (isset($ztaufrow->projekt_kurzbz)) { //Project already in projectline - add to worktime and description - if (array_key_exists($ztaufrow->projekt_kurzbz, $projectlines[$day]->projekte)) + if (array_key_exists($ztaufrow->projekt_kurzbz, $projektlines[$day]->projekte)) { - $laststart =& $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->laststart; - $lastende =& $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->lastende; + $currproj =& $projektlines[$day]->projekte[$ztaufrow->projekt_kurzbz]; + $laststart =& $currproj->laststart; + $lastende =& $currproj->lastende; $toadd = 0.00; //case 1: there is no overlap, just add project time difference @@ -157,56 +162,107 @@ for ($i = 0; $i < count($ztaufdata); $i++) $toadd = $date->convertTimeStringToHours($ztaufrow->diff); $laststart = $ztaufrow->start; $lastende = $ztaufrow->ende; - $newprojecttime = new stdClass(); - $newprojecttime->start = $ztaufrow->start; - $newprojecttime->ende = $ztaufrow->ende; - $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->alleZeiten[] = $newprojecttime; + $newprojekttime = new stdClass(); + $newprojekttime->start = $ztaufrow->start; + $newprojekttime->ende = $ztaufrow->ende; + $currproj->alleZeiten[] = $newprojekttime; + if (isset($ztaufrow->projektphase_id)) + $currproj->projektphasen[$ztaufrow->projektphase_id]->alleZeiten[] = $newprojekttime; } //case 2: overlap - add only part of the time elseif ($ztaufrow->start < $lastende && $ztaufrow->ende > $lastende) { $toadd = ($date->mktime_fromtimestamp($ztaufrow->ende) - $date->mktime_fromtimestamp($lastende)) / 3600; $lastende = $ztaufrow->ende; - $alleZeiten =& $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->alleZeiten; + + $alleZeiten =& $currproj->alleZeiten; $index = count($alleZeiten); $alleZeiten[$index - 1]->ende = $ztaufrow->ende; + + //check if overlap in projektphase, change ende accordingly + if (isset($ztaufrow->projektphase_id)) + { + $projektphaseAlleZeiten =& $currproj->projektphasen[$ztaufrow->projektphase_id]->alleZeiten; + $projektphaselastendeidx = count($projektphaseAlleZeiten); + $projektphaselastende =& $projektphaseAlleZeiten[$projektphaselastendeidx - 1]; + if ($ztaufrow->start < $projektphaselastende && $ztaufrow->ende > $projektphaselastende) + $projektphaselastende->ende = $ztaufrow->ende; + } + } + $currproj->stunden +=$toadd; + //add to projektphase + if (isset($ztaufrow->projektphase_id)) + { + $currproj->projektphasen[$ztaufrow->projektphase_id]->stunden += $toadd; } - $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->stunden += $toadd; //concatenate descriptions "working packages" for each project if (!empty($ztaufrow->beschreibung)) { - $packagecounter = ++$projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->arbeitspakete; + $packagecounter = ++$currproj->arbeitspakete; if ($packagecounter == 1) - $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->beschreibung = $ztaufrow->beschreibung; + $currproj->beschreibung = $ztaufrow->beschreibung; else - $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz]->beschreibung .= " | ".str_replace(array("\r\n", "\r", "\n"), " ", $ztaufrow->beschreibung); + $currproj->beschreibung .= " | ".str_replace(array("\r\n", "\r", "\n"), " ", $ztaufrow->beschreibung); } } else { //add new project to projectline - $newproject = new stdClass(); - $newproject->laststart = $ztaufrow->start; - $newproject->lastende = $ztaufrow->ende; - $newprojecttime = new stdClass(); - $newprojecttime->start = $ztaufrow->start; - $newprojecttime->ende = $ztaufrow->ende; - $newproject->alleZeiten = []; - $newproject->alleZeiten[] = $newprojecttime; - $newproject->stunden = $date->convertTimeStringToHours($ztaufrow->diff); - $newproject->arbeitspakete = 0;//counter for tracking number of descriptions (work packages) - $newproject->beschreibung = ''; + $stunden = $date->convertTimeStringToHours($ztaufrow->diff); + + $newprojekt = new stdClass(); + $newprojekt->laststart = $ztaufrow->start; + $newprojekt->lastende = $ztaufrow->ende; + $newprojekttime = new stdClass(); + $newprojekttime->start = $ztaufrow->start; + $newprojekttime->ende = $ztaufrow->ende; + $newprojekt->alleZeiten = []; + $newprojekt->alleZeiten[] = $newprojekttime; + $newprojekt->stunden = $stunden; + $newprojekt->arbeitspakete = 0;//counter for tracking number of descriptions (work packages) + $newprojekt->beschreibung = ''; if (!empty($ztaufrow->beschreibung)) { - $newproject->beschreibung = str_replace(array("\r\n", "\r", "\n"), " ", $ztaufrow->beschreibung); - $newproject->arbeitspakete++; + $newprojekt->beschreibung = str_replace(array("\r\n", "\r", "\n"), " ", $ztaufrow->beschreibung); + $newprojekt->arbeitspakete++; } - $projectlines[$day]->projekte[$ztaufrow->projekt_kurzbz] = $newproject; - //add new project to array with unique project names - if (!in_array($ztaufrow->projekt_kurzbz, $projectnames)) - $projectnames[] = $ztaufrow->projekt_kurzbz; + //add projektphasen of project + $projektphasen = array(); + + if ($projektphaseclass->getProjektphasen($ztaufrow->projekt_kurzbz)) + { + $projektphasenames[$ztaufrow->projekt_kurzbz] = array(); + + foreach ($projektphaseclass->result as $ppitem) + { + $phasetoadd = new stdClass(); + $phasetoadd->bezeichnung = $ppitem->bezeichnung; + $phasetoadd->stunden = 0; + $phasetoadd->alleZeiten = array(); + + if ($ppitem->projektphase_id == $ztaufrow->projektphase_id) + { + $phasetoadd->stunden += $stunden; + $phasetoadd->alleZeiten[] = $newprojekttime; + } + + $projektphasen[$ppitem->projektphase_id] = $phasetoadd; + + //add new projektphase to array with unique projekt phase names + if (!in_array($ppitem->bezeichnung, $projektphasenames[$ztaufrow->projekt_kurzbz])) + $projektphasenames[$ztaufrow->projekt_kurzbz][] = $ppitem->bezeichnung; + } + } + + $newprojekt->projektphasen = $projektphasen; + + $projektlines[$day]->projekte[$ztaufrow->projekt_kurzbz] = $newprojekt; + + //add new projekt to array with unique projekt names + if (!in_array($ztaufrow->projekt_kurzbz, $projektnames)) + $projektnames[] = $ztaufrow->projekt_kurzbz; } } @@ -215,7 +271,7 @@ for ($i = 0; $i < count($ztaufdata); $i++) $worktime_unix = $date->mktime_fromtimestamp($dayEnd) - $date->mktime_fromtimestamp($dayStart); $worktimehours = $worktime_unix / 3600; - $projectlines[$day]->arbeitszeit = $worktimehours; + $projektlines[$day]->arbeitszeit = $worktimehours; $pauseSubtracted = 0.00; $lehreExternExists = false; @@ -224,42 +280,71 @@ for ($i = 0; $i < count($ztaufdata); $i++) { if ($subtraction->typ == $activitiesToSubtract[0]) { - $projectlines[$day]->arbeitszeit -= $subtraction->diff; + $projektlines[$day]->arbeitszeit -= $subtraction->diff; $pauseSubtracted += $subtraction->diff; } elseif ($subtraction->typ == $activitiesToSubtract[1] && $subtraction->start >= $dayStart && $subtraction->ende <= $dayEnd) { - $projectlines[$day]->arbeitszeit -= $subtraction->diff; + $projektlines[$day]->arbeitszeit -= $subtraction->diff; $lehreExternExists = true; } elseif ($subtraction->typ == $activitiesToSubtract[2] || $subtraction->typ == $activitiesToSubtract[3]) { - $projectlines[$day]->arbeitszeit -= $subtraction->diff; + $projektlines[$day]->arbeitszeit -= $subtraction->diff; } } - //subtract pauses from project worktimes + //subtract pauses from projekt worktimes foreach ($allpauseranges as $pauserange) { - foreach ($projectlines[$day]->projekte as $name => $project) + foreach ($projektlines[$day]->projekte as $name => $projekt) { - foreach ($projectlines[$day]->projekte[$name]->alleZeiten as $zeit) + $proj =& $projektlines[$day]->projekte[$name]; + foreach ($proj->alleZeiten as $zeit) { - //pause between project start and end + $subtraction = 0.00; + + //pause between projekt start and end if ($pauserange->start >= $zeit->start && $pauserange->ende <= $zeit->ende) { - $projectlines[$day]->projekte[$name]->stunden -= ($date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($pauserange->start)) / 3600; - break; + $subtraction = $date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($pauserange->start); } - //pause and project time overlap at project time end + //pause and projekt time overlap at projekt time end elseif ($pauserange->start < $zeit->ende && $pauserange->start > $zeit->start) { - $projectlines[$day]->projekte[$name]->stunden -= ($date->mktime_fromtimestamp($zeit->ende) - $date->mktime_fromtimestamp($pauserange->start)) / 3600; + $subtraction = $date->mktime_fromtimestamp($zeit->ende) - $date->mktime_fromtimestamp($pauserange->start); + //$proj->stunden -= ($date->mktime_fromtimestamp($zeit->ende) - $date->mktime_fromtimestamp($pauserange->start)) / 3600; } - //pause and project time overlap at project time start + //pause and projekt time overlap at projekt time start elseif ($pauserange->ende > $zeit->start && $pauserange->ende < $zeit->ende) { - $projectlines[$day]->projekte[$name]->stunden -= ($date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($zeit->start)) / 3600; + $subtraction = $date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($zeit->start); + } + $proj->stunden -= $subtraction / 3600; + } + + //subtract from projektphasen + foreach ($proj->projektphasen as $phase_id => $phase) + { + foreach ($phase->alleZeiten as $zeit) + { + $subtraction = 0.00; + //pause between projektphase start and end + if ($pauserange->start >= $zeit->start && $pauserange->ende <= $zeit->ende) + { + $subtraction = ($date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($pauserange->start)); + } + //pause and projekt time overlap at projektphase time end + elseif ($pauserange->start < $zeit->ende && $pauserange->start > $zeit->start) + { + $subtraction = $date->mktime_fromtimestamp($zeit->ende) - $date->mktime_fromtimestamp($pauserange->start); + } + //pause and projekt time overlap at projektphase time start + elseif ($pauserange->ende > $zeit->start && $pauserange->ende < $zeit->ende) + { + $subtraction = $date->mktime_fromtimestamp($pauserange->ende) - $date->mktime_fromtimestamp($zeit->start); + } + $proj->projektphasen[$phase_id]->stunden -= $subtraction / 3600; } } } @@ -268,29 +353,47 @@ for ($i = 0; $i < count($ztaufdata); $i++) //worktime with no break greater 6 -> compulsory break of half an hour if ($pauseSubtracted < 0.5 && !$lehreExternExists) { - if ($projectlines[$day]->arbeitszeit >= 6.5) - $projectlines[$day]->arbeitszeit -= 0.5; + if ($projektlines[$day]->arbeitszeit >= 6.5) + $projektlines[$day]->arbeitszeit -= 0.5; //ensure that no worktime gets smaller than 6 hours because of compulsory break - elseif ($projectlines[$day]->arbeitszeit > 6) - $projectlines[$day]->arbeitszeit -= $projectlines[$day]->arbeitszeit - 6; + elseif ($projektlines[$day]->arbeitszeit > 6) + $projektlines[$day]->arbeitszeit -= $projektlines[$day]->arbeitszeit - 6; } - $projectlines[$day]->arbeitszeit = round($projectlines[$day]->arbeitszeit, 2); + $projektlines[$day]->arbeitszeit = round($projektlines[$day]->arbeitszeit, 2); - foreach ($projectlines[$day]->projekte as $name => $project) + //calculate sums + foreach ($projektlines[$day]->projekte as $name => $projekt) { - $projecthours =& $projectlines[$day]->projekte[$name]->stunden; - $projecthours = round($projecthours, 2); - if (array_key_exists($name, $monthsums)) - $monthsums[$name] += $projecthours; + $projekthours =& $projektlines[$day]->projekte[$name]->stunden; + $projekthours = round($projekthours, 2); + + if (isset($projektmonthsums[$name]->sum)) + { + $projektmonthsums[$name]->sum += $projekthours; + foreach ($projekt->projektphasen as $projektphase) + { + $projektmonthsums[$name]->projektphasen[$projektphase->bezeichnung] += round($projektphase->stunden, 2, 0); + } + } else - $monthsums[$name] = $projecthours; + { + $monthsum = new stdClass(); + $monthsum->sum = $projekthours; + $monthsum->projektphasen = array(); + + foreach ($projekt->projektphasen as $projektphase) + { + $monthsum->projektphasen[$projektphase->bezeichnung] = round($projektphase->stunden, 2, 0); + } + $projektmonthsums[$name] = $monthsum; + } } $dayStart = $dayEnd = ''; $tosubtract = $allpauseranges = []; - $monthsums[0] += $projectlines[$day]->arbeitszeit; + $totalmonthsum += $projektlines[$day]->arbeitszeit; } } @@ -301,10 +404,6 @@ $workbook->setVersion(8); // sending HTTP headers $workbook->send('Projektliste_'.$month.'_'.$year.'.xls'); -// Creating a worksheet -$worksheet =& $workbook->addWorksheet($p->t('zeitaufzeichnung/projektliste')); -$worksheet->setInputEncoding('utf-8'); - // Define formats $format_heading_left =& $workbook->addFormat(); $format_heading_left->setBold(); @@ -365,6 +464,12 @@ $format_cell_rightline->setBorder(1); $format_cell_rightline->setVAlign('vcenter'); $format_cell_rightline->setRight(2); +$format_cell_leftrightline =& $workbook->addFormat(); +$format_cell_leftrightline->setBottom(1); +$format_cell_leftrightline->setVAlign('vcenter'); +$format_cell_leftrightline->setLeft(2); +$format_cell_leftrightline->setRight(2); + $format_cell_centered =& $workbook->addFormat(); $format_cell_centered->setBorder(1); $format_cell_centered->setAlign('center'); @@ -372,7 +477,6 @@ $format_cell_centered->setVAlign('vcenter'); $format_cell_centered_leftline =& $workbook->addFormat(); $format_cell_centered_leftline->setRight(1); -$format_cell_centered_leftline->setLeft(1); $format_cell_centered_leftline->setBottom(1); $format_cell_centered_leftline->setAlign('center'); $format_cell_centered_leftline->setVAlign('vcenter'); @@ -384,6 +488,20 @@ $format_cell_centered_rightline->setAlign('center'); $format_cell_centered_rightline->setVAlign('vcenter'); $format_cell_centered_rightline->setRight(2); +$format_cell_centered_leftrightline =& $workbook->addFormat(); +$format_cell_centered_leftrightline->setBottom(1); +$format_cell_centered_leftrightline->setAlign('center'); +$format_cell_centered_leftrightline->setVAlign('vcenter'); +$format_cell_centered_leftrightline->setLeft(2); +$format_cell_centered_leftrightline->setRight(2); + +$format_cell_centered_topbottomline =& $workbook->addFormat(); +$format_cell_centered_topbottomline->setBorder(1); +$format_cell_centered_topbottomline->setAlign('center'); +$format_cell_centered_topbottomline->setVAlign('vcenter'); +$format_cell_centered_topbottomline->setBottom(2); +$format_cell_centered_topbottomline->setTop(2); + $format_cell_centered_topbottomleftline =& $workbook->addFormat(); $format_cell_centered_topbottomleftline->setBorder(1); $format_cell_centered_topbottomleftline->setAlign('center'); @@ -406,178 +524,239 @@ $format_cell_centered_alllines->setAlign('center'); $format_cell_centered_alllines->setVAlign('vcenter'); //define column widths -$nrProjects = count($projectnames); +$nrProjects = count($projektnames); +$totalwidth = 150; $daywidth = 4; $totalworktimewidth = 13; $worktimewidth = 8; -$worksheet->setColumn(0, 1, $daywidth); -$worksheet->setColumn(2, 2, $totalworktimewidth); +$timecolumnswidth = 2 * $daywidth + $totalworktimewidth + $worktimewidth; -//calculate max width for project descriptions -$maxwidthprojects = $totalworktimewidth * (12 - $nrProjects); -$projectcolumnwidths = array_fill_keys($projectnames, $worktimewidth); - -//set project column width depending on project description widths -foreach ($projectlines as $line) +if ($nrProjects < 1)//no projekts - merge all cells and write notice { - foreach ($line->projekte as $key => $project) + $projektnames[] = "Keine Projekte vorhanden"; +} + +foreach ($projektnames as $projektname) +{ + //Creating a worksheet + $worksheet =& $workbook->addWorksheet($projektname); + $worksheet->setInputEncoding('utf-8'); + + //general options + $worksheet->setLandscape(); + $worksheet->hideGridlines(); + $worksheet->hideScreenGridlines(); + $worksheet->setmargins(0.4); + + //fixed width columns + $worksheet->setColumn(0, 1, $daywidth); + $worksheet->setColumn(2, 2, $totalworktimewidth); + + //calculate number of columns of projekt with phases + $nrPhases = isset($projektphasenames[$projektname]) ? count($projektphasenames[$projektname]) : 0; + + //get taetigkeiten column width - + //minimum is wordlength, maximum restwidth after subraction of projektphase minimum width + $mintaetigkeitenwidth = strlen($p->t('zeitaufzeichnung/taetigkeit')); + $maxtaetigkeitenlimit = $totalwidth - $timecolumnswidth - $nrPhases * $worktimewidth; + + if (isset($projektlines->projekte[$projektname])) { - if ($projectcolumnwidths[$key] < strlen($project->beschreibung)) - $projectcolumnwidths[$key] = strlen($project->beschreibung); - } -} - -//distribute width remainder evenly among projects -if ($nrProjects != 0) - $remwidth = ($maxwidthprojects - array_sum($projectcolumnwidths)) / $nrProjects; - -foreach ($projectcolumnwidths as $projectname => $width) - $projectcolumnwidths[$projectname] += $remwidth; - -//calculating spaces for centering global header texts -$numberspaces = ($maxwidthprojects - 10 - strlen($username)); -$spacesstringFirst = ''; - -while ($numberspaces > 0) -{ - $spacesstringFirst .= ' '; - $numberspaces--; -} - -$numberspaces = ($maxwidthprojects - 14 - strlen($persnr)); -$spacesstringSecond = ''; -while ($numberspaces > 0) -{ - $spacesstringSecond .= ' '; - $numberspaces--; -} - -$spalte = $zeile = 0; - -//set language options -$decpoint = $sprache_index === '2' ? '.' : ','; -$thousandsep = $sprache_index === '2' ? ',' : '.'; - -//write global header -$lastspalte = ($nrProjects > 0) ? 2 + count($projectnames) * 2 : 14; -$worksheet->setMerge($zeile, $spalte, $zeile + 1, $spalte + 2); -$worksheet->write($zeile, $spalte, $monthtext.' '.$year, $format_heading_left); -$worksheet->write($zeile + 1, $spalte, $monthtext.' '.$year, $format_heading_left); -for ($i = 1; $i < 3; $i++) -{ - $worksheet->write($zeile, $spalte + $i, '', $format_heading_topline); - $worksheet->write($zeile + 1, $spalte + $i, '', $format_heading_bottomline); -} -$worksheet->setMerge($zeile, $spalte + 3, $zeile, $lastspalte); -$worksheet->setMerge($zeile + 1, $spalte + 3, $zeile + 1, $lastspalte); -$worksheet->write($zeile, $spalte + 3, $p->t('zeitaufzeichnung/projektlistegedruckt').$spacesstringFirst.$username, $format_heading_right); -for ($i = 4; $i < $lastspalte; $i++) -{ - $worksheet->write($zeile, $i, '', $format_heading_topline); - $worksheet->write($zeile + 1, $i, '', $format_heading_bottomline); -} -$worksheet->write($zeile, $lastspalte, '', $format_heading_right); -$worksheet->write($zeile + 1, $spalte + 3, date('d.m.Y H:i').$spacesstringSecond.$p->t('zeitaufzeichnung/personalnr').$persnr, $format_heading_right_bottomline); -$worksheet->write($zeile + 1, $lastspalte, '', $format_heading_right_bottomline); -$zeile += 3; - -//general options -$worksheet->setLandscape(); -$worksheet->hideGridlines(); -$worksheet->hideScreenGridlines(); - -//write table header -$worksheet->setMerge($zeile, $spalte, $zeile + 1, $spalte + 1); -$worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/tag'), $format_bold_centered_alllines); -$worksheet->write($zeile + 1, $spalte, '', $format_bold_centered_alllines); -$worksheet->write($zeile, $spalte + 1, $p->t('zeitaufzeichnung/tag'), $format_bold_centered_alllines); -$worksheet->write($zeile + 1, ++$spalte, '', $format_bold_centered_alllines); -$worksheet->setMerge($zeile, ++$spalte, $zeile + 1, $spalte); -$worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/arbeitszeit'), $format_bold_centered_alllines); -$worksheet->write($zeile + 1, $spalte, '', $format_bold_centered_alllines); -$spalte++; - -foreach ($projectnames as $project) -{ - $worksheet->setMerge($zeile, $spalte, $zeile, $spalte + 1); - $worksheet->write($zeile, $spalte, $project, $format_bold_centered_toprightline); - $worksheet->write($zeile, $spalte + 1, '', $format_bold_centered_toprightline); - $worksheet->write($zeile + 1, $spalte, $p->t('zeitaufzeichnung/stunden'), $format_bold_centered_bottomline); - $worksheet->write($zeile + 1, $spalte + 1, $p->t('zeitaufzeichnung/taetigkeit'), $format_bold_centered_bottomrightline); - $spalte += 2; -} -$zeile += 2; - -//write table body -for ($daysnmbr = 1; $daysnmbr <= $daysinmonth; $daysnmbr++) -{ - //write day and weekday - $spalte = 0; - $monthstr = ($month < 10) ? '0'.$month : $month; - $daystr = ($daysnmbr < 10) ? '0'.$daysnmbr : $daysnmbr; - $datestring = $year.'-'.$monthstr.'-'.$daystr; - $weekday = substr($tagbez[$sprache_index][$date->formatDatum($datestring, 'N')], 0, 2); - $worksheet->write($zeile, $spalte++, $weekday, $format_cell_centered_leftline); - $worksheet->write($zeile, $spalte++, $daysnmbr, $format_cell_centered_rightline); - - if (array_key_exists($daysnmbr, $projectlines)) - { - //write worktime - $worksheet->writeString($zeile, $spalte++, number_format($projectlines[$daysnmbr]->arbeitszeit, 2, $decpoint, $thousandsep), $format_cell_centered_rightline); - $spaltetemp = $spalte; - //write projects - foreach ($projectnames as $project) + foreach ($projektlines->projekte[$projektname] as $projekt) { - if (array_key_exists($project, $projectlines[$daysnmbr]->projekte)) + $projektbeschreibunglength = strlen($projekt->beschreibung); + if ($projektbeschreibunglength >= $maxtaetigkeitenlimit) { - $worksheet->setColumn($spalte, $spalte, $worktimewidth); - $worksheet->writeString($zeile, $spalte++, number_format($projectlines[$daysnmbr]->projekte[$project]->stunden, 2, $decpoint, $thousandsep), $format_cell_centered_leftline); - $worksheet->setColumn($spalte, $spalte, $projectcolumnwidths[$project]); - $worksheet->write($zeile, $spalte++, $projectlines[$daysnmbr]->projekte[$project]->beschreibung, $format_cell_rightline); - } - else - { - $worksheet->write($zeile, $spalte++, '', $format_cell_centered_leftline); - $worksheet->write($zeile, $spalte++, '', $format_cell_rightline); + $mintaetigkeitenwidth = $maxtaetigkeitenlimit; + break; } + elseif ($projektbeschreibunglength > $mintaetigkeitenwidth) + $mintaetigkeitenwidth = $projektbeschreibunglength; } } + + //get projektphase width, width depending on bezeichnung + $phasewidth = 0; + $phasewidthlimit = $nrPhases > 0 + ? ($totalwidth - $timecolumnswidth - $mintaetigkeitenwidth) / $nrPhases + : $totalwidth - 4 * $daywidth - $worktimewidth - $mintaetigkeitenwidth; + + if (isset($projektphasenames[$projektname])) + { + foreach ($projektphasenames[$projektname] as $projektphasename) + { + $projektphasewidth = strlen($projektphasename); + if ($projektphasewidth >= $phasewidthlimit) + { + $phasewidth = $phasewidthlimit; + break; + } + elseif ($projektphasewidth > $phasewidth) + $phasewidth = $projektphasewidth; + } + } + + //width remainder used for taetigkeit + $taetigkeitenwidth = $totalwidth - $timecolumnswidth - $phasewidth * $nrPhases; + + $lastspalte = 4 + $nrPhases; + + //calculating spaces for centering global header texts + $usernamelength = strlen($username) * 1.77; + $numberspacesfirstrow = $totalwidth - $daywidth * 2 - $worktimewidth - $usernamelength; + $numberspacessecondrow = $numberspacesfirstrow + $usernamelength - strlen($p->t('zeitaufzeichnung/personalnr').$persnr) - 4; + + $spacesstringfirstrow = str_repeat(' ', $numberspacesfirstrow); + $spacesstringsecondrow = str_repeat(' ', $numberspacessecondrow); + + $spalte = $zeile = 0; + + //set language options + $decpoint = $sprache_index === '2' ? '.' : ','; + $thousandsep = $sprache_index === '2' ? ',' : '.'; + + //write global header + $worksheet->setMerge($zeile, $spalte, $zeile + 1, $spalte + 2); + $worksheet->write($zeile, $spalte, $monthtext.' '.$year, $format_heading_left); + $worksheet->write($zeile + 1, $spalte, $monthtext.' '.$year, $format_heading_left); + for ($i = 1; $i < 3; $i++) + { + $worksheet->write($zeile, $spalte + $i, '', $format_heading_topline); + $worksheet->write($zeile + 1, $spalte + $i, '', $format_heading_bottomline); + } + $worksheet->setMerge($zeile, $spalte + 3, $zeile, $lastspalte); + $worksheet->setMerge($zeile + 1, $spalte + 3, $zeile + 1, $lastspalte); + $worksheet->write($zeile, $spalte + 3, $p->t('zeitaufzeichnung/projektlistegedruckt').$spacesstringfirstrow.$username, $format_heading_right); + for ($i = 4; $i < $lastspalte; $i++) + { + $worksheet->write($zeile, $i, '', $format_heading_topline); + $worksheet->write($zeile + 1, $i, '', $format_heading_bottomline); + } + $worksheet->write($zeile, $lastspalte, '', $format_heading_right); + $worksheet->write($zeile + 1, $spalte + 3, date('d.m.Y H:i').$spacesstringsecondrow.$p->t('zeitaufzeichnung/personalnr').$persnr, $format_heading_right_bottomline); + $worksheet->write($zeile + 1, $lastspalte, '', $format_heading_right_bottomline); + $zeile += 3; + + $spalte = 0; + + //write table header + $worksheet->setMerge($zeile, $spalte, $zeile + 1, $spalte + 1); + $worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/tag'), $format_bold_centered_alllines); + $worksheet->write($zeile + 1, $spalte, '', $format_bold_centered_alllines); + $worksheet->write($zeile, $spalte + 1, $p->t('zeitaufzeichnung/tag'), $format_bold_centered_alllines); + $worksheet->write($zeile + 1, ++$spalte, '', $format_bold_centered_alllines); + $worksheet->setMerge($zeile, ++$spalte, $zeile + 1, $spalte); + $worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/arbeitszeit'), $format_bold_centered_alllines); + $worksheet->write($zeile + 1, $spalte, '', $format_bold_centered_alllines); + $spalte++; + + if (isset($projektphasenames[$projektname])) + { + $phasenames = $projektphasenames[$projektname]; + $phasenameslength = count($phasenames); + } else { - //write empty cells until end of table - $worksheet->writeString($zeile, $spalte, number_format(0, 2, $decpoint, $thousandsep), $format_cell_centered_leftline); - $toskip = count($projectnames) * 2; - for ($i = 0; $i <= $toskip; $i++) - { - if ($i % 2 == 0) - $worksheet->write($zeile, $spalte, '', $format_cell_centered_rightline); - else - $worksheet->write($zeile, $spalte, '', $format_cell_centered); - $spalte++; - } + $phasenames = array(); + $phasenameslength = 0; } - $zeile++; + $worksheet->write($zeile, $spalte, $projektname, $format_bold_centered_toprightline); + $worksheet->write($zeile, $spalte + $phasenameslength + 1, '', $format_bold_centered_toprightline); + $worksheet->write($zeile + 1, $spalte, $p->t('zeitaufzeichnung/stunden'), $format_bold_centered_bottomline); + $worksheet->setMerge($zeile, $spalte, $zeile, $spalte + 1 + $phasenameslength); + for ($i = 0; $i < $phasenameslength; $i++) + { + $worksheet->write($zeile + 1, $spalte + 1 + $i, $phasenames[$i], $format_bold_centered_bottomline); + } + $worksheet->setColumn($spalte + $phasenameslength + 1, $spalte + $phasenameslength + 1, $taetigkeitenwidth); + $worksheet->write($zeile + 1, $spalte + $phasenameslength + 1, $p->t('zeitaufzeichnung/taetigkeit'), $format_bold_centered_bottomrightline); + $spalte = $spalte + 2 + $phasenameslength; + $zeile += 2; + + //write table body + for ($daysnmbr = 1; $daysnmbr <= $daysinmonth; $daysnmbr++) + { + //write day and weekday + $spalte = 0; + $monthstr = ($month < 10) ? '0'.$month : $month; + $daystr = ($daysnmbr < 10) ? '0'.$daysnmbr : $daysnmbr; + $datestring = $year.'-'.$monthstr.'-'.$daystr; + $weekday = substr($tagbez[$sprache_index][$date->formatDatum($datestring, 'N')], 0, 2); + $worksheet->write($zeile, $spalte++, $weekday, $format_cell_centered_leftline); + $worksheet->write($zeile, $spalte++, $daysnmbr, $format_cell_centered_rightline); + + if (array_key_exists($daysnmbr, $projektlines)) + { + //write worktime + $worksheet->writeString($zeile, $spalte++, number_format($projektlines[$daysnmbr]->arbeitszeit, 2, $decpoint, $thousandsep), $format_cell_centered_rightline); + $spaltetemp = $spalte; + //write projekt + if (array_key_exists($projektname, $projektlines[$daysnmbr]->projekte)) + { + $projekt = $projektlines[$daysnmbr]->projekte[$projektname]; + + $worksheet->setColumn($spalte, $spalte, $worktimewidth); + $worksheet->writeString($zeile, $spalte++, number_format($projekt->stunden, 2, $decpoint, $thousandsep), $format_cell_centered_leftrightline); + + foreach ($projekt->projektphasen as $projektphase) + { + $worksheet->setColumn($spalte, $spalte, $phasewidth); + $worksheet->writeString($zeile, $spalte++, number_format($projektphase->stunden, 2, $decpoint, $thousandsep), $format_cell_centered); + } + + $worksheet->setColumn($spalte, $spalte, $phasewidth); + $worksheet->write($zeile, $spalte++, $projekt->beschreibung, $format_cell_leftrightline); + } + } + else + { + $worksheet->writeString($zeile, $spalte++, number_format(0, 2, $decpoint, $thousandsep), $format_cell_centered_leftrightline); + } + + if (!array_key_exists($daysnmbr, $projektlines) || !array_key_exists($projektname, $projektlines[$daysnmbr]->projekte)) + { + if (isset($projektphasenames[$projektname])) + { + //write empty cells until end of table + $worksheet->write($zeile, $spalte, '', $format_cell_centered_leftrightline); + $toskip = count($projektphasenames[$projektname]); + for ($i = 0; $i <= $toskip; $i++) + { + if ($i == 0) + $format = $format_cell_centered_leftrightline; + else + $format = $format_cell_centered; + + $worksheet->write($zeile, $spalte++, '', $format); + } + $worksheet->write($zeile, $spalte, '', $format_cell_centered_leftrightline); + } + } + $zeile++; + } + + //write monthly sums + $spalte = 0; + $worksheet->setMerge($zeile, $spalte, $zeile, $spalte + 1); + $worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/summe'), $format_bold_centered_alllines); + $worksheet->write($zeile, $spalte + 1, '', $format_bold_centered_alllines); + $spalte += 2; + $worksheet->writeString($zeile, $spalte++, number_format($totalmonthsum, 2, $decpoint, $thousandsep), $format_cell_centered_alllines); + + if (isset($projektmonthsums[$projektname])) + { + $worksheet->writeString($zeile, $spalte++, number_format($projektmonthsums[$projektname]->sum, 2, $decpoint, $thousandsep), $format_cell_centered_alllines); + + foreach ($projektmonthsums[$projektname]->projektphasen as $projektphase) + { + $worksheet->writeString($zeile, $spalte++, number_format($projektphase, 2, $decpoint, $thousandsep), $format_cell_centered_topbottomline); + } + + $worksheet->write($zeile, $spalte++, '', $format_cell_centered_alllines); + } + $zeile += 2; + + $worksheet->fitToPages(1, 1); } -if ($nrProjects < 1) - //no projects - merge all cells and write notice -{ - $worksheet->setMerge(3, 3, 4 + $daysinmonth, $lastspalte); - $worksheet->write(3, 3, $p->t('zeitaufzeichnung/keineprojekte'), $format_bold_centered_alllines); - $worksheet->write(3, $lastspalte, '', $format_bold_centered_alllines); -} - -//write monthly sums -$spalte = 0; -$worksheet->setMerge($zeile, $spalte, $zeile, $spalte + 1); -$worksheet->write($zeile, $spalte, $p->t('zeitaufzeichnung/summe'), $format_bold_centered_alllines); -$worksheet->write($zeile, $spalte + 1, '', $format_bold_centered_alllines); -$spalte += 2; -$worksheet->writeString($zeile, $spalte++, number_format($monthsums[0], 2, $decpoint, $thousandsep), $format_cell_centered_alllines); -foreach ($projectnames as $project) -{ - $worksheet->writeString($zeile, $spalte++, number_format($monthsums[$project], 2, $decpoint, $thousandsep), $format_cell_centered_topbottomleftline); - $worksheet->write($zeile, $spalte++, '', $format_cell_centered_topbottomrightline); -} -$worksheet->fitToPages(1, 1); $workbook->close(); diff --git a/include/zeitaufzeichnung.class.php b/include/zeitaufzeichnung.class.php index 28a9b62ff..c7e0c47af 100644 --- a/include/zeitaufzeichnung.class.php +++ b/include/zeitaufzeichnung.class.php @@ -418,6 +418,7 @@ class zeitaufzeichnung extends basis_db $obj->updateamum = $row->updateamum; $obj->updatevon = $row->updatevon; $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->projektphase_id = $row->projektphase_id; $obj->ext_id = $row->ext_id; $obj->service_id = $row->service_id; $obj->kunde_uid = $row->kunde_uid; @@ -474,6 +475,7 @@ class zeitaufzeichnung extends basis_db $obj->updateamum = $row->updateamum; $obj->updatevon = $row->updatevon; $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->projektphase_id = $row->projektphase_id; $obj->ext_id = $row->ext_id; $obj->service_id = $row->service_id; $obj->kunde_uid = $row->kunde_uid; @@ -538,6 +540,7 @@ class zeitaufzeichnung extends basis_db $obj->updateamum = $row->updateamum; $obj->updatevon = $row->updatevon; $obj->projekt_kurzbz = $row->projekt_kurzbz; + $obj->projektphase_id = $row->projektphase_id; $obj->ext_id = $row->ext_id; $obj->service_id = $row->service_id; $obj->kunde_uid = $row->kunde_uid; From 9325edd3265f80e9c2b5e102ea4706cc6ca359d6 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:06:03 +0200 Subject: [PATCH 184/500] =?UTF-8?q?Created=20Controller=20to=20accept=20Le?= =?UTF-8?q?hrauftr=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created index- and acceptLehrauftrag methods. --- .../lehrauftrag/LehrauftragAkzeptieren.php | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php diff --git a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php new file mode 100644 index 000000000..98284b80f --- /dev/null +++ b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php @@ -0,0 +1,138 @@ + 'lehre:r', + 'acceptLehrauftrag' => 'lehre:rw' // TODO: check ob eigene permission? + ) + ); + + // Load models + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->load->model('accounting/Vertrag_model', 'VertragModel'); + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + + // Load libraries + $this->load->library('WidgetLib'); + $this->load->library('PermissionLib'); + + // Load helpers + $this->load->helper('array'); + $this->load->helper('url'); + + // Load language phrases + $this->loadPhrases( + array( + 'global', + 'ui' + ) + ); + + $this->_setAuthUID(); // sets property uid + + $this->setControllerId(); // sets the controller id + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Main page of Lehrauftrag + */ + public function index() + { + // Check if user is lector + if (!$this->MitarbeiterModel->isLektor($this->_uid)) + { + show_error('Fehler bei Berechtigungsprüfung'); + } + + // Set studiensemester selected for studiengang dropdown + $studiensemester_kurzbz = $this->input->get('studiensemester'); // if provided by selected studiensemester + if (is_null($studiensemester_kurzbz)) // else set next studiensemester as default value + { + $studiensemester = $this->StudiensemesterModel->getNext(); + if (hasData($studiensemester)) + { + $studiensemester_kurzbz = $studiensemester->retval[0]->studiensemester_kurzbz; + } + elseif (isError($studiensemester)) + { + show_error($studiensemester->error); + } + } + + $view_data = array( + 'studiensemester_selected' => $studiensemester_kurzbz + ); + + $this->load->view('lehre/lehrauftrag/acceptLehrauftrag.php', $view_data); + } + + /** + * Set the contract status of Lehrauftrag to 'akzeptiert'. + * Performed on ajax call. + */ + public function acceptLehrauftrag() + { + $lehrauftrag_arr = $this->input->post(); + + foreach($lehrauftrag_arr as $lehrauftrag) + { + if (!isEmptyArray($lehrauftrag)) + { + $mitarbeiter_uid = (!is_null($lehrauftrag['mitarbeiter_uid'])) ? $lehrauftrag['mitarbeiter_uid'] : null; + $vertrag_id = (!is_null($lehrauftrag['vertrag_id'])) ? intval($lehrauftrag['vertrag_id']) : null; + + $result = $this->VertragModel->setStatus($vertrag_id, $mitarbeiter_uid, 'akzeptiert'); + + if ($result->retval) + { + $json []= array( + 'row_index' => $lehrauftrag['row_index'], + 'akzeptiert' => date('Y-m-d') + ); + } + } + } + // output json to ajax + if (isset($json) && !isEmptyArray($json)) + { + $this->outputJsonSuccess($json); + } + } + + // ----------------------------------------------------------------------------------------------------------------- + // Private methods + + /** + * Retrieve the UID of the logged user and checks if it is valid + */ + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) show_error('User authentification failed'); + } + +} From 9829532e4f6994d8eccc536783568c58f433963d Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:08:20 +0200 Subject: [PATCH 185/500] =?UTF-8?q?Created=20View=20to=20accept=20Lehrauft?= =?UTF-8?q?r=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created view and jQuery functions to manipulate the tabulator. --- .../lehre/lehrauftrag/acceptLehrauftrag.php | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 application/views/lehre/lehrauftrag/acceptLehrauftrag.php diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php new file mode 100644 index 000000000..ba9ac43e6 --- /dev/null +++ b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php @@ -0,0 +1,178 @@ +load->view( + 'templates/FHC-Header', + array( + 'title' => 'Lehrauftrag', + 'jquery' => true, + 'jqueryui' => true, + 'jquerycheckboxes' => true, + 'bootstrap' => true, + 'fontawesome' => true, + 'sbadmintemplate' => false, + 'tabulator' => true, + 'momentjs' => true, + 'ajaxlib' => true, + 'dialoglib' => true, + 'filterwidget' => true, + 'navigationwidget' => true, + 'phrases' => array( + 'global' => array('lehrauftraege'), + ), + // 'customCSSs' => 'public/css/sbadmin2/tablesort_bootstrap.css', + 'customJSs' => array('public/js/bootstrapper.js') + ) +); + +?> + + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + widgetlib->widget( + 'Studiensemester_widget', + array( + DropdownWidget::SELECTED_ELEMENT => $studiensemester_selected + ), + array( + 'name' => 'studiensemester', + 'id' => 'studiensemester' + ) + ); + ?> +
    + + +
    +
    + +
    +
    + load->view('lehre/lehrauftrag/acceptLehrauftragData.php'); ?> +
    +
    + +
    +
    + + + + + +
    +
    +
    +
    + + +load->view('templates/FHC-Footer'); ?> + + + From 6caec74df5a54c39a860093c45ce441cb906e87c Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:10:42 +0200 Subject: [PATCH 186/500] =?UTF-8?q?Created=20SQL-query=20and=20tabulator?= =?UTF-8?q?=20to=20accept=20Lehrauftr=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lehrauftrag/acceptLehrauftragData.php | 292 ++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 application/views/lehre/lehrauftrag/acceptLehrauftragData.php diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php new file mode 100644 index 000000000..c6bd65198 --- /dev/null +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -0,0 +1,292 @@ + $query, + 'app' => LehrauftragAkzeptieren::APP, + 'datasetName' => 'lehrauftragAccept', + 'filterKurzbz' => 'LehrauftragAccept', + 'requiredPermissions' => 'lehre', // TODO: change permission + 'datasetRepresentation' => 'tabulator', + 'reloadDataset' => true, // reload query on page refresh + 'customMenu' => false, + 'hideOptions' => true, + 'hideMenu' => true, + 'columnsAliases' => array( // TODO: use phrasen + 'row_index', + 'LE-ID', + 'LV-ID', + 'PA-ID', + 'Studiensemester', + 'Studiengang-KZ', + 'Studiengang', + 'Person-ID', + 'Typ', + 'Auftrag', + 'Organisationseinheit', + 'Gruppe', + 'Stunden', + 'Betrag', + 'Vertrag-ID', + 'UID', + 'Bestellt', + 'Erteilt', + 'Akzeptiert' + ), + 'datasetRepOptions' => '{ + height: 550, + layout: "fitColumns", // fit columns to width of table + responsiveLayout: "hide", // hide columns that dont fit on the table + movableColumns: true, // allows changing column + headerFilterPlaceholder: " ", + index: "row_index", // assign specific column as unique id (important for row indexing) + selectable: true, // allow row selection + selectableRangeMode: "click", // allow range selection using shift end click on end of range + selectablePersistence:false, // deselect previously selected rows when table is filtered, sorted or paginated + selectableCheck: function(row) + { + // only allow to select bestellte Lehraufträge + return row.getData().bestellt != null && row.getData().erteilt != null; + }, + rowUpdated:function(row) + { + // deselect and disable new selection of updated rows (approvement done) + row.deselect(); + row.getElement().off("click"); + }, + rowFormatter:function(row) + { + var data = row.getData(); + + // default (white): rows to be accepted + // green: rows accepted + // grey: all other + if(row.getData().bestellt != null && row.getData().erteilt != null && row.getData().akzeptiert == null) + { + return; + } + else if(row.getData().bestellt != null && row.getData().erteilt != null && row.getData().akzeptiert != null) + { + row.getElement().style["background-color"] = "#d1f1d196"; // green + } + else + { + row.getElement().style["background-color"] = "#f5f5f5"; // grey + } + } + }', // tabulator properties + 'datasetRepFieldsDefs' => '{ + row_index: {visible:false}, // necessary for row indexing + lehreinheit_id: {headerFilter:"input", bottomCalc:"count", bottomCalcFormatter:function(cell){return "Anzahl: " + cell.getValue();}, width: "7%"}, + lehrveranstaltung_id: {headerFilter:"input", width: "5%"}, + projektarbeit_id: {visible: false}, + studiensemester_kurzbz: {visible: false}, + studiengang_kz: {visible: false}, + stg_oe_kurzbz: {headerFilter:"input", width: "5%"}, + person_id: {visible: false}, + typ: {headerFilter:"input", width: "7%"}, + auftrag: {headerFilter:"input", width: "23%"}, + lv_oe_kurzbz: {headerFilter:"input", width: "12%"}, + gruppe: {headerFilter:"input", width: "5%"}, + stunden: {align:"right", headerFilter:"input", bottomCalc:"sum", bottomCalcParams:{precision:1}, width: "5%"}, + betrag: {align:"right", headerFilter:"input", headerFilterPlaceholder:">=", headerFilterFunc: hf_compareWithFloat, + bottomCalc:"sum", bottomCalcParams:{precision:2}, bottomCalcFormatter:"money", bottomCalcFormatterParams:{decimal: ",", thousand: ".", symbol:"€"}, + width: "8%"}, + vertrag_id: {visible: false}, + mitarbeiter_uid: {visible: false}, + bestellt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, width: "auto", + erteilt: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, width: "auto", + akzeptiert: {align:"center", headerFilter:"input", mutator: mut_formatStringDate}, width: "auto" + }', // col properties +); + +echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); + +?> + From 3abfaebb1aef060711e48a380eeb053d42dd7679 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:11:07 +0200 Subject: [PATCH 187/500] =?UTF-8?q?Created=20filter=20to=20accept=20Lehrau?= =?UTF-8?q?ftr=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/filtersupdate.php | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 957b6da49..37a0c8e2f 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -470,6 +470,42 @@ $filters = array( } ', 'oe_kurzbz' => null, + ), + array( + 'app' => 'lehrauftrag', + 'dataset_name' => 'lehrauftragAccept', + 'filter_kurzbz' => 'LehrauftragAccept', + 'description' => '{Alle}', + 'sort' => 1, + 'default_filter' => true, + 'filter' => ' + { + "name": "", + "columns": [ + {"name": "row_index"}, + {"name": "lehreinheit_id"}, + {"name": "lehrveranstaltung_id"}, + {"name": "projektarbeit_id"}, + {"name": "studiensemester_kurzbz"}, + {"name": "studiengang_kz"}, + {"name": "stg_oe_kurzbz"}, + {"name": "person_id"}, + {"name": "typ"}, + {"name": "auftrag"}, + {"name": "lv_oe_kurzbz"}, + {"name": "gruppe"}, + {"name": "stunden"}, + {"name": "betrag"}, + {"name": "vertrag_id"}, + {"name": "mitarbeiter_uid"}, + {"name": "bestellt"}, + {"name": "erteilt"}, + {"name": "akzeptiert"} + ], + "filters": [] + } + ', + 'oe_kurzbz' => null, ), array( 'app' => 'budget', From a91052710992559a9974a5567a8fe48db9e72d43 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:13:08 +0200 Subject: [PATCH 188/500] Added method isLektor() This method checks if a given user is a lector (and eventually if is fix employed) --- .../models/ressource/Mitarbeiter_model.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 1e03a0ecd..2397f9c7e 100644 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -11,4 +11,33 @@ class Mitarbeiter_model extends DB_Model $this->dbTable = 'public.tbl_mitarbeiter'; $this->pk = 'mitarbeiter_uid'; } + + /** + * Checks if the user is a lector. + * @param string $uid + * @param boolean null $fixangestellt + * @return bool + */ + public function isLektor($uid, $fixangestellt = null) + { + $this->addSelect('1'); + + if (is_bool($fixangestellt)) + { + $result = $this->loadWhere(array('mitarbeiter_uid' => $uid, 'lektor' => true, 'fixangestellt' => $fixangestellt)); + } + else // Default: if lektor is true + { + $result = $this->loadWhere(array('mitarbeiter_uid' => $uid, 'lektor' => true)); + } + + if(hasData($result)) + { + return true; + } + else + { + return false; + } + } } From 812899e885810554c8d0503450a0482c0d35df2e Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:14:22 +0200 Subject: [PATCH 189/500] Added method hasStatus() This method checks if Vertrag has the given Vertragsstatus. --- .../models/accounting/Vertrag_model.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index 95bc59efc..2261af350 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -142,6 +142,26 @@ class Vertrag_model extends DB_Model } + /** + * Check if Vertrag has the given Vertragsstatus. + * @param integer $vertrag_id + * @param string $mitarbeiter_uid + * @param string $vertragsstatus_kurzbz + * @return array + */ + public function hasStatus($vertrag_id, $mitarbeiter_uid, $vertragsstatus_kurzbz) + { + $this->addSelect('1'); + $this->addJoin('lehre.tbl_vertrag_vertragsstatus', 'vertrag_id'); + $this->addLimit(1); + + return $this->loadWhere(array( + 'vertrag_id' => $vertrag_id, + 'uid' => $mitarbeiter_uid, + 'vertragsstatus_kurzbz' => $vertragsstatus_kurzbz + )); + } + /** * Sets Vertragsstatus for the given Vertrag and Mitarbeiter. * @param $vertrag_id From 1a58c977fe48d92109545abaf0588e469ddcb237 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:15:21 +0200 Subject: [PATCH 190/500] Added method getLastStatus() This method gets the latest Vertragsstatus for the given Vertrag and Mitarbeiter. --- .../models/accounting/Vertrag_model.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index 2261af350..0de9a8fc7 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -200,6 +200,29 @@ class Vertrag_model extends DB_Model return $this->execQuery($query, array($vertragsstatus_kurzbz, $vertrag_id, $mitarbeiter_uid, 'NOW()', getAuthUID(), null, null)); } + /** + * Get the latest Vertragsstatus for the given Vertrag and Mitarbeiter + * @param integer $vertrag_id + * @param string $mitarbeiter_uid + * @return array + */ + public function getLastStatus($vertrag_id, $mitarbeiter_uid) + { + $this->addSelect('vertragsstatus_kurzbz'); + $this->addJoin('lehre.tbl_vertrag_vertragsstatus', 'vertrag_id'); + $this->addOrder('datum', 'DESC'); + $this->addLimit(1); + return $this->loadWhere( + array( + 'vertrag_id' => $vertrag_id, + 'uid' => $mitarbeiter_uid + ) + ); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Private methods + /** * Generate contract description. * Example: WS2017-BEE3-LIA-LAB From 3340922a35198cdf0841905502bd4c0181810e53 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 10:21:05 +0200 Subject: [PATCH 191/500] Extended/Adapted method setStatus() Extended check: if new status is 'akzeptiert', the latest status has to be 'erteilt'. Adapted code as check for having certain status was outsourced to method hasStatus. --- .../models/accounting/Vertrag_model.php | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index 0de9a8fc7..008d3ffab 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -163,7 +163,7 @@ class Vertrag_model extends DB_Model } /** - * Sets Vertragsstatus for the given Vertrag and Mitarbeiter. + * Set Vertragsstatus for the given Vertrag and Mitarbeiter. * @param $vertrag_id * @param $vertragsstatus_kurzbz * @param $mitarbeiter_uid @@ -171,21 +171,26 @@ class Vertrag_model extends DB_Model */ public function setStatus($vertrag_id, $mitarbeiter_uid, $vertragsstatus_kurzbz){ - // First check if vertrag has already this status - $this->addJoin('lehre.tbl_vertrag_vertragsstatus', 'vertrag_id'); - - $result = $this->loadWhere(array( - 'vertrag_id' => $vertrag_id, - 'uid' => $mitarbeiter_uid, - 'vertragsstatus_kurzbz' => $vertragsstatus_kurzbz - )); - - if (!isEmptyArray($result->retval)) + // Check if vertrag has already this status + $result = $this->hasStatus($vertrag_id, $mitarbeiter_uid, $vertragsstatus_kurzbz); + if (hasData($result)) { - return success(null); // return null if status already set + return success(null); // return null if status is already set } - // Set new status + // If new status should be 'akzeptiert', the latest status has to be 'erteilt' + if ($vertragsstatus_kurzbz == 'akzeptiert') + { + $result = $this->getLastStatus($vertrag_id, $mitarbeiter_uid); + $last_status = getData($result)[0]->vertragsstatus_kurzbz; + + if ($last_status != 'erteilt') + { + return success(null); // return null if latest status is not 'erteilt' + } + } + + // Set new status if passed all checks $query = ' INSERT INTO lehre.tbl_vertrag_vertragsstatus( vertragsstatus_kurzbz, @@ -197,7 +202,17 @@ class Vertrag_model extends DB_Model updateamum ) VALUES (?, ?, ?, ?, ?, ?, ?);'; - return $this->execQuery($query, array($vertragsstatus_kurzbz, $vertrag_id, $mitarbeiter_uid, 'NOW()', getAuthUID(), null, null)); + return $this->execQuery($query, + array( + $vertragsstatus_kurzbz, + $vertrag_id, + $mitarbeiter_uid, + 'NOW()', + getAuthUID(), + null, + null + ) + ); } /** From 223f3110bdbfa4cddf4821beaf22dbf8ae069343 Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 16:06:50 +0200 Subject: [PATCH 192/500] Added method getLast() This method gets latest (active) Verwendung of the user. --- .../models/codex/Bisverwendung_model.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/application/models/codex/Bisverwendung_model.php b/application/models/codex/Bisverwendung_model.php index fa2cf84d0..20f942865 100644 --- a/application/models/codex/Bisverwendung_model.php +++ b/application/models/codex/Bisverwendung_model.php @@ -11,4 +11,34 @@ class Bisverwendung_model extends DB_Model $this->dbTable = 'bis.tbl_bisverwendung'; $this->pk = 'bisverwendung_id'; } + + /** + * Get latest (active) Verwendung of the user. + * @param string $uid + * @param bool $active If false, returns latest Verwendung no matter if actual or not (ignores ending/beginning date). + * @return array + */ + public function getLast($uid, $active = true) + { + $this->addLimit(1); + + if ($active) + { + $condition = ' + mitarbeiter_uid = '. $this->escape($uid). ' + AND ( beginn <= NOW() OR beginn IS NULL ) + AND ( ende >= NOW() OR ende IS NULL ) + ORDER BY ende DESC NULLS LAST, beginn DESC NULLS LAST + '; + } + else + { + $condition = ' + mitarbeiter_uid = '. $this->escape($uid). ' + ORDER BY ende DESC NULLS LAST, beginn DESC NULLS LAST + '; + } + + return $this->loadWhere($condition); + } } From 43452a2127b1821ae50c84479c878d0b320ebcef Mon Sep 17 00:00:00 2001 From: Cris Date: Tue, 24 Sep 2019 16:10:23 +0200 Subject: [PATCH 193/500] Hided column 'Betrag' if lector has inkludierte Lehre If the lectors actual Verwendung has inkludierte Lehre, the tabulators column betrag is hided. --- .../lehre/lehrauftrag/LehrauftragAkzeptieren.php | 12 +++++++++++- .../views/lehre/lehrauftrag/acceptLehrauftrag.php | 8 ++++++++ .../lehre/lehrauftrag/acceptLehrauftragData.php | 10 +++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php index 98284b80f..ce1018eee 100644 --- a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php +++ b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php @@ -31,6 +31,7 @@ class LehrauftragAkzeptieren extends Auth_Controller $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); $this->load->model('accounting/Vertrag_model', 'VertragModel'); $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $this->load->model('codex/Bisverwendung_model', 'BisverwendungModel'); // Load libraries $this->load->library('WidgetLib'); @@ -67,6 +68,14 @@ class LehrauftragAkzeptieren extends Auth_Controller show_error('Fehler bei Berechtigungsprüfung'); } + // Check if lectors latest active Verwendung has inkludierte Lehre + $has_inkludierteLehre = false; + $result = $this->BisverwendungModel->getLast($this->_uid); + if (hasData($result)) + { + $has_inkludierteLehre = ($result->retval[0]->inkludierte_lehre >= 0) ? true : false; + } + // Set studiensemester selected for studiengang dropdown $studiensemester_kurzbz = $this->input->get('studiensemester'); // if provided by selected studiensemester if (is_null($studiensemester_kurzbz)) // else set next studiensemester as default value @@ -83,7 +92,8 @@ class LehrauftragAkzeptieren extends Auth_Controller } $view_data = array( - 'studiensemester_selected' => $studiensemester_kurzbz + 'studiensemester_selected' => $studiensemester_kurzbz, + 'has_inkludierteLehre' => $has_inkludierteLehre ); $this->load->view('lehre/lehrauftrag/acceptLehrauftrag.php', $view_data); diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php index ba9ac43e6..a86ca537b 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftrag.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftrag.php @@ -81,6 +81,14 @@ $this->load->view( From 169ffbb5683dda61965a59a9e51d294af014dc90 Mon Sep 17 00:00:00 2001 From: hainberg Date: Wed, 25 Sep 2019 14:11:38 +0200 Subject: [PATCH 198/500] Changed method isLektor() to isMitarbeiter() Because boolean field lektor is not necessary maintained, check is now for overall mitarbeiter. --- .../models/ressource/Mitarbeiter_model.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 2397f9c7e..ccaeacd0d 100644 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -13,31 +13,31 @@ class Mitarbeiter_model extends DB_Model } /** - * Checks if the user is a lector. + * Checks if the user is a Mitarbeiter. * @param string $uid * @param boolean null $fixangestellt - * @return bool + * @return array */ - public function isLektor($uid, $fixangestellt = null) + public function isMitarbeiter($uid, $fixangestellt = null) { $this->addSelect('1'); if (is_bool($fixangestellt)) { - $result = $this->loadWhere(array('mitarbeiter_uid' => $uid, 'lektor' => true, 'fixangestellt' => $fixangestellt)); + $result = $this->loadWhere(array('mitarbeiter_uid' => $uid, 'fixangestellt' => $fixangestellt)); } - else // Default: if lektor is true + else // default { - $result = $this->loadWhere(array('mitarbeiter_uid' => $uid, 'lektor' => true)); + $result = $this->loadWhere(array('mitarbeiter_uid' => $uid)); } if(hasData($result)) { - return true; + return success(true); } else { - return false; + return success(false); } } } From 83dd828be780c532c0fbbe9f312d03c48e633805 Mon Sep 17 00:00:00 2001 From: hainberg Date: Wed, 25 Sep 2019 14:13:16 +0200 Subject: [PATCH 199/500] Minor adaptation to changed method isMitarbeiter() --- .../controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php index 8f0fdda8c..2b9744cb8 100644 --- a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php +++ b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php @@ -63,8 +63,9 @@ class LehrauftragAkzeptieren extends Auth_Controller */ public function index() { - // Check if user is lector - if (!$this->MitarbeiterModel->isLektor($this->_uid)) + // Check if user is Mitarbeiter + $result = $this->MitarbeiterModel->isMitarbeiter($this->_uid); + if (!getData($result)) { show_error('Fehler bei Berechtigungsprüfung'); } From 6f5de6a7869ec5d44548c3713d2d3e42d51079b4 Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 25 Sep 2019 15:39:42 +0200 Subject: [PATCH 200/500] Adapted SQL query: gruppen aggregated in one cell, not in seperated rows Before same lehreinheiten of same lector were shown in different rows, when they were taught in different groups. This caused incorrect contract inserts. One contract is for per lector and per lehreinheit. Gruppen are only displayed in one cell (aggregated if more) --- .../lehrauftrag/acceptLehrauftragData.php | 27 ++++++++++++----- .../lehrauftrag/approveLehrauftragData.php | 29 ++++++++++++++----- .../lehre/lehrauftrag/lehrauftragData.php | 27 ++++++++++++----- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index 713698239..fcd22b3ea 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -13,6 +13,15 @@ FROM ( /* Lehraufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_lehrauftraege.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum @@ -55,8 +64,6 @@ FROM WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", TRUNC(lema.semesterstunden, 1) AS "stunden", TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "betrag", vertrag_id, @@ -66,7 +73,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_mitarbeiter ma USING (mitarbeiter_uid) JOIN PUBLIC.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid @@ -91,6 +97,15 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", (SELECT uid FROM @@ -132,7 +147,7 @@ FROM stg.studiengang_kz, upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", person.person_id, - \'Betreuung\' AS "typ", + \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || (SELECT vorname || \' \' || nachname @@ -153,9 +168,6 @@ FROM ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, - \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", TRUNC(pb.stunden, 1) AS "stunden", TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag", vertrag_id @@ -165,7 +177,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_person person USING (person_id) LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) LEFT JOIN lehre.tbl_vertrag_vertragsstatus vvs USING (vertrag_id) diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index f27e65170..05247f7ba 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -11,6 +11,15 @@ FROM ( /* Lehraufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_lehrauftraege.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum @@ -43,6 +52,7 @@ FROM NULL AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, + upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", person.person_id, upper(lv.lehrtyp_kurzbz) AS "typ", (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || @@ -52,8 +62,6 @@ FROM WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", (person.vorname || \' \' || person.nachname) AS "lektor", TRUNC(lema.semesterstunden, 1) AS "stunden", TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "betrag", @@ -64,7 +72,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_mitarbeiter ma USING (mitarbeiter_uid) JOIN PUBLIC.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid @@ -88,6 +95,15 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", (SELECT uid FROM @@ -127,8 +143,9 @@ FROM pa.projektarbeit_id AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, + upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", person.person_id, - \'Betreuung\' AS "typ", + \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || (SELECT vorname || \' \' || nachname @@ -149,9 +166,6 @@ FROM ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, - \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", (vorname || \' \' || nachname) AS "lektor", TRUNC(pb.stunden, 1) AS "stunden", TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag", @@ -162,7 +176,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_person person USING (person_id) LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) JOIN PUBLIC.tbl_studiengang stg diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 5cf9bbb4c..b342613de 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -11,6 +11,15 @@ FROM ( /* Lehraufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_lehrauftraege.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum @@ -43,6 +52,7 @@ FROM NULL AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, + upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", person.person_id, upper(lv.lehrtyp_kurzbz) AS "typ", (lv.bezeichnung || \' [\' || le.lehrform_kurzbz || \' \' || lv.semester || \'.Semester\' || @@ -52,8 +62,6 @@ FROM WHEN oe.organisationseinheittyp_kurzbz = \'Department\' THEN (\'DEP \' || oe.bezeichnung) ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", (person.vorname || \' \' || person.nachname) AS "lektor", TRUNC(lema.semesterstunden, 1) AS "stunden", TRUNC((lema.semesterstunden * lema.stundensatz), 2) AS "betrag", @@ -64,7 +72,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_mitarbeiter ma USING (mitarbeiter_uid) JOIN PUBLIC.tbl_benutzer benutzer ON ma.mitarbeiter_uid = benutzer.uid @@ -88,6 +95,15 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", (SELECT uid FROM @@ -127,6 +143,7 @@ FROM pa.projektarbeit_id AS "projektarbeit_id", le.studiensemester_kurzbz, stg.studiengang_kz, + upper(stg.oe_kurzbz) AS "stg_oe_kurzbz", person.person_id, \'Betreuung\' AS "typ", (betreuerart_kurzbz || \' \' || @@ -149,9 +166,6 @@ FROM ELSE (oe.organisationseinheittyp_kurzbz || \' \' || oe.bezeichnung) END AS "lv_oe_kurzbz", - CONCAT(stg.kurzbzlang, - \'-\', legr.semester, legr.verband, legr.gruppe, - \'\n\' || legr.gruppe_kurzbz) AS "gruppe", (vorname || \' \' || nachname) AS "lektor", TRUNC(pb.stunden, 1) AS "stunden", TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag", @@ -162,7 +176,6 @@ FROM JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz) - JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id) JOIN PUBLIC.tbl_person person USING (person_id) LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id) JOIN PUBLIC.tbl_studiengang stg From 61a6bc7bfc5cf5c4034799c50d98af17a97bd1fb Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 25 Sep 2019 16:25:04 +0200 Subject: [PATCH 201/500] Fixed SQL query: corrected column order in subquery for Projektbetreuung --- .../lehrauftrag/acceptLehrauftragData.php | 20 ++++++++++--------- .../lehrauftrag/approveLehrauftragData.php | 20 ++++++++++--------- .../lehre/lehrauftrag/lehrauftragData.php | 20 ++++++++++--------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index fcd22b3ea..d294cd6bd 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -97,15 +97,8 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, - /* concatinated and aggregated gruppen */ - (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, - \'\n\' || gruppe_kurzbz), \', \') - FROM - lehre.tbl_lehreinheitgruppe - WHERE - lehreinheit_id = tmp_projektbetreuung.lehreinheit_id - ) AS "gruppe", + /* mitarbeiter uid retrieved by person_id */ + /* NOTE: mitarbeiter MUST come after Select * to ensure correct order with select for tmp_lehrauftraege*/ (SELECT uid FROM @@ -113,6 +106,15 @@ FROM WHERE person_id = tmp_projektbetreuung.person_id AND aktiv = TRUE) AS "mitarbeiter_uid", + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index 05247f7ba..eedffb39c 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -95,15 +95,8 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, - /* concatinated and aggregated gruppen */ - (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, - \'\n\' || gruppe_kurzbz), \', \') - FROM - lehre.tbl_lehreinheitgruppe - WHERE - lehreinheit_id = tmp_projektbetreuung.lehreinheit_id - ) AS "gruppe", + /* mitarbeiter uid retrieved by person_id */ + /* NOTE: mitarbeiter MUST come after Select * to ensure correct order with select for tmp_lehrauftraege*/ (SELECT uid FROM @@ -111,6 +104,15 @@ FROM WHERE person_id = tmp_projektbetreuung.person_id AND aktiv = TRUE) AS "mitarbeiter_uid", + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index b342613de..2f736b2d5 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -95,15 +95,8 @@ FROM /* Projektbetreuungsaufträge and -vertragsstati */ SELECT *, - /* concatinated and aggregated gruppen */ - (SELECT - string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, - \'\n\' || gruppe_kurzbz), \', \') - FROM - lehre.tbl_lehreinheitgruppe - WHERE - lehreinheit_id = tmp_projektbetreuung.lehreinheit_id - ) AS "gruppe", + /* mitarbeiter uid retrieved by person_id */ + /* NOTE: mitarbeiter MUST come after Select * to ensure correct order with select for tmp_lehrauftraege*/ (SELECT uid FROM @@ -111,6 +104,15 @@ FROM WHERE person_id = tmp_projektbetreuung.person_id AND aktiv = TRUE) AS "mitarbeiter_uid", + /* concatinated and aggregated gruppen */ + (SELECT + string_agg(concat(stg_oe_kurzbz, \'-\', semester, verband, gruppe, + \'\n\' || gruppe_kurzbz), \', \') + FROM + lehre.tbl_lehreinheitgruppe + WHERE + lehreinheit_id = tmp_projektbetreuung.lehreinheit_id + ) AS "gruppe", /* existing contracts with status bestellt */ (SELECT datum From a70507a0791b0f912ed1e7c5c3d088d4c304a8e5 Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 25 Sep 2019 16:58:33 +0200 Subject: [PATCH 202/500] Adapted tabulator to display columns in correct order after query change --- .../lehrauftrag/acceptLehrauftragData.php | 20 +++++++++++++++- .../lehrauftrag/approveLehrauftragData.php | 23 ++++++++++++++++++- .../lehre/lehrauftrag/lehrauftragData.php | 23 ++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php index d294cd6bd..716dbfa98 100644 --- a/application/views/lehre/lehrauftrag/acceptLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/acceptLehrauftragData.php @@ -8,7 +8,25 @@ $PERSON_ID = getAuthPersonId(); $query = ' SELECT /* provide extra row index for tabulator, because no other column has unique ids */ - ROW_NUMBER() OVER () AS "row_index", * + ROW_NUMBER() OVER () AS "row_index", + lehreinheit_id, + lehrveranstaltung_id, + projektarbeit_id, + studiensemester_kurzbz, + studiengang_kz, + stg_oe_kurzbz, + person_id, + typ, + auftrag, + lv_oe_kurzbz, + gruppe, + stunden, + betrag, + vertrag_id, + mitarbeiter_uid, + bestellt, + erteilt, + akzeptiert FROM ( /* Lehraufträge and -vertragsstati */ diff --git a/application/views/lehre/lehrauftrag/approveLehrauftragData.php b/application/views/lehre/lehrauftrag/approveLehrauftragData.php index eedffb39c..26cb25815 100644 --- a/application/views/lehre/lehrauftrag/approveLehrauftragData.php +++ b/application/views/lehre/lehrauftrag/approveLehrauftragData.php @@ -6,7 +6,26 @@ $ORGANISATIONSEINHEIT = (isset($organisationseinheit_selected) && !is_null($orga $query = ' SELECT /* provide extra row index for tabulator, because no other column has unique ids */ - ROW_NUMBER() OVER () AS "row_index", * + ROW_NUMBER() OVER () AS "row_index", + lehreinheit_id, + lehrveranstaltung_id, + projektarbeit_id, + studiensemester_kurzbz, + studiengang_kz, + stg_oe_kurzbz, + person_id, + typ, + auftrag, + lv_oe_kurzbz, + gruppe, + lektor, + stunden, + betrag, + vertrag_id, + mitarbeiter_uid, + bestellt, + erteilt, + akzeptiert FROM ( /* Lehraufträge and -vertragsstati */ @@ -213,6 +232,7 @@ $filterWidgetArray = array( 'LV-ID', 'PA-ID', 'Studiensemester', + 'Studiengang-KZ', 'Studiengang', 'Person-ID', 'Typ', @@ -278,6 +298,7 @@ $filterWidgetArray = array( projektarbeit_id: {visible: false}, studiensemester_kurzbz: {headerFilter:"input"}, studiengang_kz: {visible: false}, + stg_oe_kurzbz: {visible: false}, person_id: {visible: false}, typ: {headerFilter:"input"}, auftrag: {headerFilter:"input"}, diff --git a/application/views/lehre/lehrauftrag/lehrauftragData.php b/application/views/lehre/lehrauftrag/lehrauftragData.php index 2f736b2d5..0945693f5 100644 --- a/application/views/lehre/lehrauftrag/lehrauftragData.php +++ b/application/views/lehre/lehrauftrag/lehrauftragData.php @@ -6,7 +6,26 @@ $STUDIENGANG = (isset($studiengang_selected) && !is_null($studiengang_selected)) $query = ' SELECT /* provide extra row index for tabulator, because no other column has unique ids */ - ROW_NUMBER() OVER () AS "row_index", * + ROW_NUMBER() OVER () AS "row_index", + lehreinheit_id, + lehrveranstaltung_id, + projektarbeit_id, + studiensemester_kurzbz, + studiengang_kz, + stg_oe_kurzbz, + person_id, + typ, + auftrag, + lv_oe_kurzbz, + gruppe, + lektor, + stunden, + betrag, + vertrag_id, + mitarbeiter_uid, + bestellt, + erteilt, + akzeptiert FROM ( /* Lehraufträge and -vertragsstati */ @@ -213,6 +232,7 @@ $filterWidgetArray = array( 'LV-ID', 'PA-ID', 'Studiensemester', + 'Studiengang-KZ', 'Studiengang', 'Person-ID', 'Typ', @@ -278,6 +298,7 @@ $filterWidgetArray = array( projektarbeit_id: {visible: false}, studiensemester_kurzbz: {headerFilter:"input"}, studiengang_kz: {visible: false}, + stg_oe_kurzbz: {visible: false}, person_id: {visible: false}, typ: {headerFilter:"input"}, auftrag: {headerFilter:"input"}, From aefc0dfd2ccb8934d6f97fb161a46240b9dcfd6d Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 25 Sep 2019 17:01:05 +0200 Subject: [PATCH 203/500] Adapted filter for orderLehrauftraege and approveLehrauftraege Added columns stg_oe_kurzbz and gruppe. --- system/filtersupdate.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 37a0c8e2f..d5e085454 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -416,11 +416,12 @@ $filters = array( {"name": "projektarbeit_id"}, {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, + {"name": "stg_oe_kurzbz"}, {"name": "person_id"}, {"name": "typ"}, {"name": "auftrag"}, {"name": "lv_oe_kurzbz"}, - {"name": "gruppe"}, + {"name": "gruppe"}, {"name": "lektor"}, {"name": "stunden"}, {"name": "betrag"}, @@ -452,6 +453,7 @@ $filters = array( {"name": "projektarbeit_id"}, {"name": "studiensemester_kurzbz"}, {"name": "studiengang_kz"}, + {"name": "stg_oe_kurzbz"}, {"name": "person_id"}, {"name": "typ"}, {"name": "auftrag"}, From 8210c3fdc7460eb60892d8b2324b4ec05f661767 Mon Sep 17 00:00:00 2001 From: Paolo Date: Wed, 25 Sep 2019 17:15:46 +0200 Subject: [PATCH 204/500] Derived TableWidget from FilterWidget, added: - libraries/TableWidgetLib - widgets/TableWidget - controllers/widgets/Tables - public/js/TableWidget.js --- application/controllers/widgets/Tables.php | 105 ++++ application/libraries/TableWidgetLib.php | 204 +++++++ application/views/templates/FHC-Header.php | 7 + application/widgets/TableWidget.php | 414 +++++++++++++++ public/js/TableWidget.js | 587 +++++++++++++++++++++ 5 files changed, 1317 insertions(+) create mode 100644 application/controllers/widgets/Tables.php create mode 100644 application/libraries/TableWidgetLib.php create mode 100644 application/widgets/TableWidget.php create mode 100644 public/js/TableWidget.js diff --git a/application/controllers/widgets/Tables.php b/application/controllers/widgets/Tables.php new file mode 100644 index 000000000..21161ff9f --- /dev/null +++ b/application/controllers/widgets/Tables.php @@ -0,0 +1,105 @@ +load->library('AuthLib'); + + // Loads the tablewidgetlib with HTTP GET/POST parameters + $this->_loadTableWidgetLib(); + + // Checks if the caller is allow to read this data + $this->_isAllowed(); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Retrieves data about the current filter from the session and will be written on the output in JSON format + */ + public function getTable() + { + $this->outputJsonSuccess($this->tablewidgetlib->getSession()); + } + + /** + * Retrieves the number of records present in the current dataset and will be written on the output in JSON format + */ + public function rowNumber() + { + $rowNumber = 0; + $dataset = $this->tablewidgetlib->getSessionElement(TableWidgetLib::SESSION_DATASET); + + if (isset($dataset) && is_array($dataset)) + { + $rowNumber = count($dataset); + } + + $this->outputJsonSuccess($rowNumber); + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Checks if the user is allowed to use this filter + */ + private function _isAllowed() + { + if (!$this->tablewidgetlib->isAllowed()) + { + $this->terminateWithJsonError('You are not allowed to access to this content'); + } + } + + /** + * Loads the tablewidgetlib with the TABLE_UNIQUE_ID parameter + * If the parameter TABLE_UNIQUE_ID is not given then the execution of the controller is terminated and + * an error message is printed + */ + private function _loadTableWidgetLib() + { + // If the parameter TABLE_UNIQUE_ID is present in the HTTP GET or POST + if (isset($_GET[self::TABLE_UNIQUE_ID]) || isset($_POST[self::TABLE_UNIQUE_ID])) + { + // If it is present in the HTTP GET + if (isset($_GET[self::TABLE_UNIQUE_ID])) + { + $tableUniqueId = $this->input->get(self::TABLE_UNIQUE_ID); // is retrieved from the HTTP GET + } + elseif (isset($_POST[self::TABLE_UNIQUE_ID])) // Else if it is present in the HTTP POST + { + $tableUniqueId = $this->input->post(self::TABLE_UNIQUE_ID); // is retrieved from the HTTP POST + } + + // Loads the tablewidgetlib that contains all the used logic + $this->load->library('TableWidgetLib'); + + $this->tablewidgetlib->setTableUniqueId($tableUniqueId); + } + else // Otherwise an error will be written in the output + { + $this->terminateWithJsonError('Parameter "'.self::TABLE_UNIQUE_ID.'" not provided!'); + } + } +} diff --git a/application/libraries/TableWidgetLib.php b/application/libraries/TableWidgetLib.php new file mode 100644 index 000000000..e97e0d754 --- /dev/null +++ b/application/libraries/TableWidgetLib.php @@ -0,0 +1,204 @@ +_ci =& get_instance(); // get code igniter instance + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Checks if at least one of the permissions given as parameter (requiredPermissions) belongs + * to the authenticated user, if confirmed then is allowed to use this FilterWidget. + * If the parameter requiredPermissions is NOT given or is not present in the session, + * then NO one is allow to use this FilterWidget + * Wrapper method to permissionlib->hasAtLeastOne + */ + public function isAllowed($requiredPermissions = null) + { + $this->_ci->load->library('PermissionLib'); // Load permission library + + // Gets the required permissions from the session if they are not provided as parameter + $rq = $requiredPermissions; + if ($rq == null) $rq = $this->getSessionElement(self::REQUIRED_PERMISSIONS_PARAMETER); + + return $this->_ci->permissionlib->hasAtLeastOne($rq, self::PERMISSION_TABLE_METHOD, self::PERMISSION_TYPE); + } + + /** + * Wrapper method to the session helper funtions to retrieve the whole session for this filter + */ + public function getSession() + { + return getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + } + + /** + * Wrapper method to the session helper funtions to retrieve one element from the session of this filter + */ + public function getSessionElement($name) + { + $session = getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + + if (isset($session[$name])) + { + return $session[$name]; + } + + return null; + } + + /** + * Wrapper method to the session helper funtions to set the whole session for this filter + */ + public function setSession($data) + { + $data[TableWidgetLib::TABLE_UNIQUE_ID] = $this->_tableUniqueId; // the unique id of this table widget + + setSessionElement(self::SESSION_NAME, $this->_tableUniqueId, $data); + } + + /** + * Wrapper method to the session helper funtions to set one element in the session for this filter + */ + public function setSessionElement($name, $value) + { + $session = getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + + $session[$name] = $value; + + setSessionElement(self::SESSION_NAME, $this->_tableUniqueId, $session); // stores the single value + } + + /** + * Generate the query to retrieve the dataset for a filter + */ + public function generateDatasetQuery($query) + { + return 'SELECT * FROM ('.$query.') '.self::DATASET_TABLE_ALIAS; + } + + /** + * Retrieves the dataset from the DB + */ + public function getDataset($datasetQuery) + { + $dataset = null; + + if ($datasetQuery != null) + { + $this->_ci->load->model('system/Filters_model', 'FiltersModel'); + + // Execute the given SQL statement suppressing error messages + $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery); + } + + return $dataset; + } + + /** + * Retrieves metadata from the last executed query + */ + public function getExecutedQueryMetaData() + { + return $this->_ci->FiltersModel->getExecutedQueryMetaData(); + } + + /** + * Retrieves the list of fields from the last executed query + */ + public function getExecutedQueryListFields() + { + return $this->_ci->FiltersModel->getExecutedQueryListFields(); + } + + /** + * Return an unique string that identify this filter widget + * NOTE: The default value is the URI where the FilterWidget is called + * If the fhc_controller_id is present then is also used + */ + public function setTableUniqueIdByParams($params) + { + if ($params != null + && is_array($params) + && isset($params[self::TABLE_UNIQUE_ID]) + && !isEmptyString($params[self::TABLE_UNIQUE_ID])) + { + $this->setTableUniqueId($params[self::TABLE_UNIQUE_ID]); + } + } + + /** + * Set the _tableUniqueId property + */ + public function setTableUniqueId($filterUniqueId) + { + $this->_tableUniqueId = $filterUniqueId; + } +} diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index ec04ffa53..1058fa32c 100644 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -30,6 +30,7 @@ $pivotui = isset($pivotui) ? $pivotui : false; $sbadmintemplate = isset($sbadmintemplate) ? $sbadmintemplate : false; $tablesorter = isset($tablesorter) ? $tablesorter : false; + $tablewidget = isset($tablewidget) ? $tablewidget : false; $tabulator = isset($tabulator) ? $tabulator : false; $tinymce = isset($tinymce) ? $tinymce : false; ?> @@ -103,6 +104,9 @@ // NavigationWidget CSS if ($navigationwidget === true) generateCSSsInclude('public/css/NavigationWidget.css'); + // TableWidget CSS + if ($tablewidget === true) generateCSSsInclude('public/css/TableWidget.css'); + // Eventually required CSS generateCSSsInclude($customCSSs); // Eventually required CSS @@ -203,6 +207,9 @@ // PhrasesLib JS if ($phrases != null) generateJSsInclude('public/js/PhrasesLib.js'); + // TableWidget JS + if ($tablewidget === true) generateJSsInclude('public/js/TableWidget.js'); + // Load addon hooks JS // NOTE: keep it as the latest but one if ($addons === true) generateAddonsJSsInclude($calledPath.'/'.$calledMethod); diff --git a/application/widgets/TableWidget.php b/application/widgets/TableWidget.php new file mode 100644 index 000000000..396ca3bb3 --- /dev/null +++ b/application/widgets/TableWidget.php @@ -0,0 +1,414 @@ +load->library('TableWidgetLib'); // Loads the TableWidgetLib that contains all the used logic + + $this->_initTableWidget($args); // checks parameters and initialize properties + + $this->tablewidgetlib->setTableUniqueIdByParams($args); + + // Let's start if it's allowed + // NOTE: If it is NOT allowed then no data are loaded + if ($this->tablewidgetlib->isAllowed($this->_requiredPermissions)) + { + $this->_startTableWidget(); + } + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Called when echoing the table widget call + */ + public function display($widgetData) + { + $this->view(self::WIDGET_URL_TABLE, array( + 'tableUniqueId' => $widgetData[TableWidgetLib::TABLE_UNIQUE_ID] + )); // GUI starts here + } + + //------------------------------------------------------------------------------------------------------------------ + // Public static methods used to load views and to access statically to some properies of the TableWidget + + /** + * Loads the view related to the dataset, here is decided how to represent the dataset (ex: tablesorter, pivotUI, ...) + */ + public static function loadViewDataset() + { + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_TABLESORTER) + { + self::_loadView(self::WIDGET_URL_DATASET_TABLESORTER); + } + + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_PIVOTUI) + { + self::_loadView(self::WIDGET_URL_DATASET_PIVOTUI); + } + + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_TABULATOR) + { + self::_loadView(self::WIDGET_URL_DATASET_TABULATOR); + } + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Checks parameters and initialize all the properties of this TableWidget + */ + private function _initTableWidget($args) + { + $this->_checkParameters($args); + + // If here then everything is ok + + // Initialize class properties + $this->_requiredPermissions = null; + $this->_reloadDataset = null; + $this->_query = null; + $this->_additionalColumns = null; + $this->_columnsAliases = null; + $this->_formatRow = null; + $this->_markRow = null; + $this->_checkboxes = null; + $this->_datasetRepresentation = null; + $this->_datasetRepresentationOptions = null; + $this->_datasetRepFieldsDefs = null; + + // Retrieved the required permissions parameter if present + if (isset($args[TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER])) + { + $this->_requiredPermissions = $args[TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER]; + } + + // How to retrieve data for the table: SQL statement or a result from DB + if (isset($args[TableWidgetLib::QUERY_PARAMETER])) + { + $this->_query = $args[TableWidgetLib::QUERY_PARAMETER]; + } + + if (isset($args[TableWidgetLib::DATASET_RELOAD_PARAMETER])) + { + $this->_reloadDataset = $args[TableWidgetLib::DATASET_RELOAD_PARAMETER]; + } + + // Parameter is used to add extra columns to the dataset + if (isset($args[TableWidgetLib::ADDITIONAL_COLUMNS]) + && is_array($args[TableWidgetLib::ADDITIONAL_COLUMNS]) + && count($args[TableWidgetLib::ADDITIONAL_COLUMNS]) > 0) + { + $this->_additionalColumns = $args[TableWidgetLib::ADDITIONAL_COLUMNS]; + } + + // Parameter is used to add use aliases for the columns fo the dataset + if (isset($args[TableWidgetLib::COLUMNS_ALIASES]) + && is_array($args[TableWidgetLib::COLUMNS_ALIASES]) + && count($args[TableWidgetLib::COLUMNS_ALIASES]) > 0) + { + $this->_columnsAliases = $args[TableWidgetLib::COLUMNS_ALIASES]; + } + + // Parameter that contains a function to format the rows of the dataset + if (isset($args[TableWidgetLib::FORMAT_ROW]) && is_callable($args[TableWidgetLib::FORMAT_ROW])) + { + $this->_formatRow = $args[TableWidgetLib::FORMAT_ROW]; + } + + // Parameter that contains a function to mark in the GUI the rows of the dataset + if (isset($args[TableWidgetLib::MARK_ROW]) && is_callable($args[TableWidgetLib::MARK_ROW])) + { + $this->_markRow = $args[TableWidgetLib::MARK_ROW]; + } + + // Parameter used to specify the column of the dataset that will be used + // as id of the checkboxes column in the GUI + if (isset($args[TableWidgetLib::CHECKBOXES])) + { + $this->_checkboxes = $args[TableWidgetLib::CHECKBOXES]; + } + + // To specify how to represent the dataset (ex: tablesorter, pivotUI, ...) + if (isset($args[TableWidgetLib::DATASET_REPRESENTATION]) + && ($args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_TABLESORTER + || $args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_PIVOTUI + || $args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_TABULATOR)) + { + $this->_datasetRepresentation = $args[TableWidgetLib::DATASET_REPRESENTATION]; + } + + // To specify options for the dataset representation (ex: tablesorter, pivotUI, ...) + if (isset($args[TableWidgetLib::DATASET_REP_OPTIONS]) && !isEmptyString($args[TableWidgetLib::DATASET_REP_OPTIONS])) + { + $this->_datasetRepresentationOptions = $args[TableWidgetLib::DATASET_REP_OPTIONS]; + } + + // To specify how to represent each record field + if (isset($args[TableWidgetLib::DATASET_REP_FIELDS_DEFS]) && !isEmptyString($args[TableWidgetLib::DATASET_REP_FIELDS_DEFS])) + { + $this->_datasetRepFieldsDefs = $args[TableWidgetLib::DATASET_REP_FIELDS_DEFS]; + } + } + + /** + * Checks the required parameters used to call this TableWidget + */ + private function _checkParameters($args) + { + if (!is_array($args) || (is_array($args) && count($args) == 0)) + { + show_error('Second parameter of the widget call must be a NOT empty associative array'); + } + else + { + if (!isset($args[TableWidgetLib::TABLE_UNIQUE_ID])) + { + show_error('The parameter "'.TableWidgetLib::TABLE_UNIQUE_ID.'" must be specified'); + } + + if (!isset($args[TableWidgetLib::QUERY_PARAMETER])) + { + show_error('The parameters "'.TableWidgetLib::QUERY_PARAMETER.'" must be specified'); + } + + if (!isset($args[TableWidgetLib::DATASET_REPRESENTATION])) + { + show_error('The parameter "'.TableWidgetLib::DATASET_REPRESENTATION.'" must be specified'); + } + + if (isset($args[TableWidgetLib::DATASET_REPRESENTATION]) + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_TABLESORTER + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_PIVOTUI + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_TABULATOR) + { + show_error( + 'The parameter "'.TableWidgetLib::DATASET_REPRESENTATION. + '" must be IN ("' + .TableWidgetLib::DATASET_REP_TABLESORTER.'", "' + .TableWidgetLib::DATASET_REP_PIVOTUI.'", "' + .TableWidgetLib::DATASET_REP_TABULATOR.'")' + ); + } + } + } + + /** + * Contains all the logic used to load all the data needed to the TableWidget + */ + private function _startTableWidget() + { + // Read the all session for this table widget + $session = $this->tablewidgetlib->getSession(); + + // If session is NOT empty -> a table was already loaded + if ($session != null) + { + // Get SESSION_RELOAD_DATASET from the session + $sessionReloadDataset = $this->tablewidgetlib->getSessionElement(TableWidgetLib::SESSION_RELOAD_DATASET); + + // if Filter changed or reload is forced by parameter then reload the Dataset + if ($this->_reloadDataset === true || $sessionReloadDataset === true) + { + // Set as false to stop changing the dataset + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_RELOAD_DATASET, false); + + // Generate dataset query using tables from the session + $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); + + // Then retrieve dataset from DB + $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + + // Save changes into session if data are valid + if (!isError($dataset)) + { + $this->_formatDataset($dataset); // marks rows using markRow and format rowns using formatRow + + // Set the new dataset and its attributes in the session + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_METADATA, $this->tablewidgetlib->getExecutedQueryMetaData()); + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_ROW_NUMBER, count($dataset->retval)); + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_DATASET, $dataset->retval); + } + } + } + + // If the session is empty -> first time that this table is loaded + if ($session == null) + { + // Generate dataset query + $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); + + // Then retrieve dataset from DB + $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + + // Save changes into session if data are valid + if (!isError($dataset)) + { + $this->_formatDataset($dataset); // marks rows using markRow and format rowns using formatRow + + // Stores an array that contains all the data useful for + $this->tablewidgetlib->setSession( + array( + TableWidgetLib::SESSION_FIELDS => $this->tablewidgetlib->getExecutedQueryListFields(), // all the fields of the dataset + TableWidgetLib::SESSION_COLUMNS_ALIASES => $this->_columnsAliases, // all the fields aliases + TableWidgetLib::SESSION_ADDITIONAL_COLUMNS => $this->_additionalColumns, // additional columns + TableWidgetLib::SESSION_CHECKBOXES => $this->_checkboxes, // the name of the field used to build the checkboxes column + TableWidgetLib::SESSION_METADATA => $this->tablewidgetlib->getExecutedQueryMetaData(), // the metadata of the dataset + TableWidgetLib::SESSION_ROW_NUMBER => count($dataset->retval), // the number of loaded rows by this table + TableWidgetLib::SESSION_DATASET => $dataset->retval, // the entire dataset + TableWidgetLib::SESSION_RELOAD_DATASET => false, // if the dataset must be reloaded, not needed the first time + TableWidgetLib::SESSION_DATASET_REPRESENTATION => $this->_datasetRepresentation, // the choosen dataset representation + TableWidgetLib::SESSION_DATASET_REP_OPTIONS => $this->_datasetRepresentationOptions, // the choosen dataset representation options + TableWidgetLib::SESSION_DATASET_REP_FIELDS_DEFS => $this->_datasetRepFieldsDefs // the choosen dataset representation record fields definition + ) + ); + } + } + + // To be always stored in the session, otherwise is not possible to load data from Filters controller + // NOTE: must the latest operation to be performed in the session to be shure that is always present + $this->tablewidgetlib->setSessionElement(TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER, $this->_requiredPermissions); + } + + /** + * Calls the method _markRow and _formatRow to marks rows using markRow and format rowns using formatRow + * NOTE: this method operates directly on the retrieved dataset: parameter passed by reference + */ + private function _formatDataset(&$rawDataset) + { + if (hasData($rawDataset) && is_array($rawDataset->retval)) + { + // For each row of the data set + for ($rowCounter = 0; $rowCounter < count($rawDataset->retval); $rowCounter++) + { + // Calls the methods to mark and to format a row + // NOTE: keep this order! the markRow function given as parameter is supposing to work + // on a raw dataset, NOT on a formatted one + $rawDataset->retval[$rowCounter]->MARK_ROW_CLASS = $this->_markRow($rawDataset->retval[$rowCounter]); + $this->_formatRow($rawDataset->retval[$rowCounter]); + } + } + } + + /** + * Formats the columns of all the rows of the entire dataset + * - converts booleans into strings "true" and "false" + * - format dates using the format string defined in DEFAULT_DATE_FORMAT + * Calls the parameter formatRow if it was given and if it is a valid funtion + * NOTE: this method operates directly on the retrieved dataset: parameter passed by reference + */ + private function _formatRow(&$rawDatasetRow) + { + // For each column of the row + foreach ($rawDatasetRow as $columnName => $columnValue) + { + // Basic conversions + if (is_bool($columnValue)) + { + $rawDatasetRow->{$columnName} = ($columnValue === true ? 'true' : 'false'); + } + elseif (DateTime::createFromFormat('Y-m-d H:i:s', $columnValue) !== false) + { + $rawDatasetRow->{$columnName} = date(self::DEFAULT_DATE_FORMAT, strtotime($columnValue)); + } + } + + // If a valid function call the given formatRow + if ($this->_formatRow != null && is_callable($this->_formatRow)) + { + $formatRowFunction = $this->_formatRow; + $rawDatasetRow = $formatRowFunction($rawDatasetRow); + } + } + + /** + * Returns a string that contains a class name used to mark rows in the dataset table + * Calls the parameter markRow if it was given and if it is a valid funtion + */ + private function _markRow($rawDatasetRow) + { + // If a valid function call the given markRow + if ($this->_markRow != null && is_callable($this->_markRow)) + { + $markRowFunction = $this->_markRow; + $class = $markRowFunction($rawDatasetRow); + } + + return !isset($class) ? '' : $class; + } + + /** + * Utility method that retrieves the name of the columns present in a table JSON definition + */ + private function _getColumnsNames($columns) + { + $columnsNames = array(); + + foreach ($columns as $key => $obj) + { + if (isset($obj->name)) + { + $columnsNames[] = $obj->name; + } + } + + return $columnsNames; + } + + /** + * Loads a view using the given viewName and eventually other parameters + */ + private static function _loadView($viewName, $parameters = null) + { + $ci =& get_instance(); + $ci->load->view($viewName, $parameters); + } +} diff --git a/public/js/TableWidget.js b/public/js/TableWidget.js new file mode 100644 index 000000000..44e66cabd --- /dev/null +++ b/public/js/TableWidget.js @@ -0,0 +1,587 @@ +/** + * TableWidget JS magic + */ + +//-------------------------------------------------------------------------------------------------------------------- +// Constants + +// +const DATASET_REP_TABLESORTER = "tablesorter"; +const DATASET_REP_PIVOTUI = "pivotUI"; +const DATASET_REP_TABULATOR = "tabulator"; + +/** + * FHC_TableWidget this object is used to render the GUI of a table widget and to operate with it + */ +var FHC_TableWidget = { + + //------------------------------------------------------------------------------------------------------------------ + // Properties + + _datasetRepresentation: null, // contains the current data representation + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * To display the TableWidget using the loaded data prenset in the session + */ + display: function() { + + FHC_TableWidget._getTables(FHC_TableWidget._renderTableWidget); + }, + + /** + * Alias call to method display only to inprove the readability of the code + */ + refresh: function() { + + FHC_TableWidget.display(); + }, + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Utility method that checks if data contains an error and print that to the console + * otherwise the TableWidget GUI is refreshed + */ + _failOrRefresh: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.isError(data)) + { + console.log(FHC_AjaxClient.getError(data)); + } + else + { + FHC_TableWidget.refresh(); + } + }, + + /** + * Utility method that checks if data contains an error and print that to the console + * otherwise the page is reloaded + */ + _failOrReload: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.isError(data)) + { + console.log(FHC_AjaxClient.getError(data)); + } + else + { + location.reload(); + } + }, + + /** + * To reset the Table Widget GUI + */ + _resetGUI: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").html(""); + tableWidgetDiv.find("#tableWidgetTableDataset > tbody").html(""); + } + + // If the choosen dataset representation is pivotUI + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_PIVOTUI) + { + tableWidgetDiv.find("#tableWidgetPivotUI").html(""); + } + + // If the choosen dataset representation is tabulator + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABULATOR) + { + tableWidgetDiv.find("#tableWidgetTabulator").html(""); + } + }, + + /** + * To get via Ajax all the data related to the TableWidget present in the given page + * If the parameter renderFunction is a valid function, is called on success + */ + _getTables: function(renderFunction) { + + var tableWidgetUniqueIdArray = FHC_TableWidget._getTableWidgetUniqueIdArray(); + + for (var tableWidgetsCounter = 0; tableWidgetsCounter < tableWidgetUniqueIdArray.length; tableWidgetsCounter++) + { + + FHC_AjaxClient.ajaxCallGet( + "widgets/Tables/getTable", + { + tableUniqueId: tableWidgetUniqueIdArray[tableWidgetsCounter] + }, + { + successCallback: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.hasData(data)) + { + if (typeof renderFunction == "function") + { + renderFunction(FHC_AjaxClient.getData(data)); + } + } + else + { + console.log(FHC_AjaxClient.getError(data)); + } + } + } + ); + } + }, + + /** + * This method calls all the other methods needed to rendere the GUI for a TableWidget + * The parameter data contains all the data about the TableWidget and it is given as parameter + * to all the methods that here are called + * NOTE: think very carefully before changing the order of the calls + */ + _renderTableWidget: function(data) { + + FHC_TableWidget._setDatasetRepresentation(data); // set what type of dataset representation was choosen + + var tableWidgetDiv = $('div[tableUniqueId="' + data.tableUniqueId + '"]'); + + FHC_TableWidget._turnOffEvents(tableWidgetDiv); // turns all the events off + + FHC_TableWidget._resetGUI(tableWidgetDiv); // Reset the entire GUI + + FHC_TableWidget._renderDataset(tableWidgetDiv, data); + + FHC_TableWidget._turnOnEvents(tableWidgetDiv); // turns all the events off + }, + + /** + * Turns all the events off + * NOTE: must be aligned to _turnOnEvents + */ + _turnOffEvents: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._disableTablesorter(tableWidgetDiv); // disable the tablesorter + } + }, + + /** + * Turns all the events on + * NOTE: must be aligned to _turnOffEvents + */ + _turnOnEvents: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._enableTableSorter(tableWidgetDiv); // enable the tablesorter + } + }, + + _renderDataset: function(tableWidgetDiv, data) { + + // If the choosen dataset representation is tablesorter then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._renderDatasetTablesorter(tableWidgetDiv, data); // ...render the tablesorter GUI + } + + // If the choosen dataset representation is pivotUI then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_PIVOTUI) + { + FHC_TableWidget._renderDatasetPivotUI(tableWidgetDiv, data); // ...render the pivotUI GUI + } + + // If the choosen dataset representation is tabulator then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABULATOR) + { + FHC_TableWidget._renderDatasetTabulator(tableWidgetDiv, data); // ...render the tabulator GUI + } + }, + + /** + * Renders the tablesorter for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetTablesorter: function(tableWidgetDiv, data) { + + if (data.hasOwnProperty("checkboxes") && data.checkboxes != null && data.checkboxes.trim() != "") + { + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append("
    "); + } + + var arrayFieldsToDisplay = FHC_TableWidget._getFieldsToDisplay(data); + + for (var i = 0; i < arrayFieldsToDisplay.length; i++) + { + var columnName = arrayFieldsToDisplay[i]; + + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append(""); + } + + if (data.hasOwnProperty("additionalColumns") && $.isArray(data.additionalColumns)) + { + for (var i = 0; i < data.additionalColumns.length; i++) + { + var columnName = data.additionalColumns[i]; + + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append(""); + } + } + + if (arrayFieldsToDisplay.length > 0) + { + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + if (data.checkboxes != null && data.checkboxes != "") + { + // select checkbox range with shift key + if (typeof tableWidgetDiv.find("#tableWidgetTableDataset").checkboxes === 'function') + tableWidgetDiv.find("#tableWidgetTableDataset").checkboxes("range", true); + } + + for (var i = 0; i < data.dataset.length; i++) + { + var record = data.dataset[i]; + + if ($.isEmptyObject(record)) + { + continue; + } + + var strHtml = ""; + + if (data.checkboxes != null && data.checkboxes != "") + { + strHtml += ""; + } + + $.each(arrayFieldsToDisplay, function(i, fieldToDisplay) { + + if (record.hasOwnProperty(data.fields[i])) + { + strHtml += ""; + } + }); + + if (data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + $.each(data.additionalColumns, function(i, additionalColumn) { + + if (record.hasOwnProperty(additionalColumn)) + { + strHtml += ""; + } + }); + } + + strHtml += ""; + + tableWidgetDiv.find("#tableWidgetTableDataset > tbody").append(strHtml); + } + } + } + }, + + /** + * Enable the tablesorter libs to render the dataset table with sorting features + */ + _enableTableSorter: function(tableWidgetDiv) { + + var tableWidgetTablesorter = tableWidgetDiv.find("#tableWidgetTableDataset"); + + // Checks if the table contains data (rows) + if (tableWidgetTablesorter.find("tbody:empty").length == 0 + && tableWidgetTablesorter.find("tr:empty").length == 0 + && tableWidgetTablesorter.hasClass("table-condensed")) + { + tableWidgetTablesorter.tablesorter({ + dateFormat: "ddmmyyyy", + widgets: ["zebra", "filter"], + widgetOptions: { + filter_saveFilters : true + } + }); + + $.tablesorter.updateAll(tableWidgetTablesorter[0].config, true, null); + } + }, + + /** + * Disable the tablesorter + */ + _disableTablesorter: function(tableWidgetDiv) { + + tableWidgetDiv.find("#tableWidgetTableDataset").trigger("disable"); + }, + + /** + * Renders the pivotUI for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetPivotUI: function(tableWidgetDiv, data) { + + // Checks if options were given and returns them + var options = FHC_TableWidget._getRepresentationOptions(data); + + // Manipulation for the representation! + var arrayFieldsToDisplay = FHC_TableWidget._getFieldsToDisplay(data); + + // If there are fields to be displayed... + if (arrayFieldsToDisplay.length > 0) + { + // ...if there are data to be displayed... + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + // Build the array of objects used by pivotUI and store it in pivotUIData + var pivotUIData = []; + + // Loops through data + for (var i = 0; i < data.dataset.length; i++) + { + var record = data.dataset[i]; // Single record + var tmpObj = {}; // New object that represents a record + + // Loops through columns of a record + $.each(arrayFieldsToDisplay, function(i, fieldToDisplay) { + + if (record.hasOwnProperty(data.fields[i])) + { + tmpObj[fieldToDisplay] = record[data.fields[i]]; // Add data with the column alias + } + }); + + // If additional columns are present... + if (data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + // ...loops through them + $.each(data.additionalColumns, function(i, additionalColumn) { + + if (record.hasOwnProperty(additionalColumn)) + { + tmpObj[additionalColumn] = record[additionalColumn]; // Add the additional column + } + }); + } + + pivotUIData.push(tmpObj); // Add tmpObj to pivotUIData + } + + // Renders the pivotUI + tableWidgetDiv.find("#tableWidgetPivotUI").pivotUI( + pivotUIData, + options + ); + } + } + }, + + /** + * Retrives the fields to be displayed from the data parameter, if aliases are present then they are used + */ + _getFieldsToDisplay: function(data) { + + var arrayFieldsToDisplay = []; + + if (data.hasOwnProperty("fields") && $.isArray(data.fields)) + { + if (data.hasOwnProperty("columnsAliases") && $.isArray(data.columnsAliases)) + { + for (var sfc = 0; sfc < data.fields.length; sfc++) + { + for (var fc = 0; fc < data.fields.length; fc++) + { + if (data.fields[sfc] == data.fields[fc]) + { + arrayFieldsToDisplay[sfc] = data.columnsAliases[fc]; + } + } + } + } + else + { + arrayFieldsToDisplay = data.fields; + } + } + + return arrayFieldsToDisplay; + }, + + /** + * Renders the tabulator for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetTabulator: function(tableWidgetDiv, data) { + + // Checks if options were given and returns them + var options = FHC_TableWidget._getRepresentationOptions(data); + // Checks if record fields definitions were given and returns them + var recordFieldsDefinitions = FHC_TableWidget._getRepresentationFieldsDefinitions(data); + + // Manipulation for the representation! + var arrayTabulatorColumns = FHC_TableWidget._getTabulatorColumns(data, recordFieldsDefinitions); + + if (arrayTabulatorColumns.length > 0) + { + // ...if there are data to be displayed... + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + if (options == null) options = {}; + + options.columns = arrayTabulatorColumns; + options.data = data.dataset; + + // Renders the tabulator + tableWidgetDiv.find("#tableWidgetTabulator").tabulator(options); + } + } + }, + + /** + * Retrives the fields to be displayed from the data parameter, if aliases are present then they are used + */ + _getTabulatorColumns: function(data, recordFieldsDefinitions) { + + var fieldsToDisplayTabulator = []; + + if (data.hasOwnProperty("fields") && $.isArray(data.fields)) + { + for (var sfc = 0; sfc < data.fields.length; sfc++) + { + for (var fc = 0; fc < data.fields.length; fc++) + { + if (data.fields[sfc] == data.fields[fc]) + { + // Build the array of objects (columns) used by tabulator and store it in tabulatorColumns + var tmpColumnObj = {}; // New object that represents a column + + // If was given a definition for this field then use it! + if (recordFieldsDefinitions != null && recordFieldsDefinitions.hasOwnProperty(data.fields[sfc])) + { + tmpColumnObj = recordFieldsDefinitions[data.fields[sfc]]; + } + + tmpColumnObj.field = data.fields[sfc]; // Field name to be linked with dataset field name + + // If there is an alias for this field use it to give a title to this field (header) + if (data.hasOwnProperty("columnsAliases") && $.isArray(data.columnsAliases)) + { + tmpColumnObj.title = data.columnsAliases[fc]; + } + else // otherwise use the field name itself + { + tmpColumnObj.title = data.fields[sfc]; + } + + fieldsToDisplayTabulator.push(tmpColumnObj); // Add tmpColumnObj to tabulatorColumns + } + } + } + } + + // If additional columns are present... + if (data.hasOwnProperty("additionalColumns") && data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + // ...loops through them + $.each(data.additionalColumns, function(i, additionalColumn) { + + var tmpColumnObj = {}; // New object that represents a column + + // If was given a definition for this field then use it! + if (recordFieldsDefinitions != null && recordFieldsDefinitions.hasOwnProperty(additionalColumn)) + { + tmpColumnObj = recordFieldsDefinitions[additionalColumn]; + } + + tmpColumnObj.title = additionalColumn; // Give a title to this field (header) + tmpColumnObj.field = additionalColumn; // Field name to be linked with dataset field name + + fieldsToDisplayTabulator.push(tmpColumnObj); // Add tmpColumnObj to tabulatorColumns + }); + } + + return fieldsToDisplayTabulator; + }, + + /** + * Gets options for the representation + */ + _getRepresentationOptions: function(data) { + + var options = {}; // eventually contains options fot the representation + + // Checks if options were given + if (data.hasOwnProperty("datasetRepresentationOptions") && data.datasetRepresentationOptions != "") + { + var tmpOptions = eval("(" + data.datasetRepresentationOptions + ")"); // and converts them from string to javascript code + + // If it is an object then can be used + if (typeof tmpOptions == "object") + { + options = tmpOptions; + } + } + + return options; + }, + + /** + * Gets record fields definitions to represent the dataset + */ + _getRepresentationFieldsDefinitions: function(data) { + + var fieldsDefinitions = {}; // eventually contains record fields definitions + + // Checks if record fields definitions was given as parameter + if (data.hasOwnProperty("datasetRepresentationFieldsDefinitions") && data.datasetRepresentationFieldsDefinitions != "") + { + var tmpFDefs = eval("(" + data.datasetRepresentationFieldsDefinitions + ")"); // and converts them from string to javascript code + + // If it is an object then can be used + if (typeof tmpFDefs == "object") + { + fieldsDefinitions = tmpFDefs; + } + } + + return fieldsDefinitions; + }, + + /** + * Set what type of dataset representation was choosen + */ + _setDatasetRepresentation: function(data) { + + if (data.hasOwnProperty("datasetRepresentation")) + { + FHC_TableWidget._datasetRepresentation = data.datasetRepresentation; + } + }, + + _getTableWidgetUniqueIdArray: function() { + + var tableWidgetUniqueIdArray = []; + + $("div[id*='divTableWidgetDataset']").each(function(i, e) { + + tableWidgetUniqueIdArray.push(e.attributes["tableUniqueId"].nodeValue); + }); + + return tableWidgetUniqueIdArray; + } +}; + +/** + * When JQuery is up + */ +$(document).ready(function() { + + FHC_TableWidget.display(); + +}); From 0c82d4fffcfbf5e91194c88eccece4a9aa331c7f Mon Sep 17 00:00:00 2001 From: Paolo Date: Wed, 25 Sep 2019 17:19:08 +0200 Subject: [PATCH 205/500] Added new views for TableWidget --- .../views/widgets/table/pivotUIDataset.php | 1 + application/views/widgets/table/table.php | 17 +++++++++++++++++ .../views/widgets/table/tableDataset.php | 7 +++++++ .../views/widgets/table/tabulatorDataset.php | 1 + 4 files changed, 26 insertions(+) create mode 100644 application/views/widgets/table/pivotUIDataset.php create mode 100644 application/views/widgets/table/table.php create mode 100644 application/views/widgets/table/tableDataset.php create mode 100644 application/views/widgets/table/tabulatorDataset.php diff --git a/application/views/widgets/table/pivotUIDataset.php b/application/views/widgets/table/pivotUIDataset.php new file mode 100644 index 000000000..0b43fcdac --- /dev/null +++ b/application/views/widgets/table/pivotUIDataset.php @@ -0,0 +1 @@ +
    diff --git a/application/views/widgets/table/table.php b/application/views/widgets/table/table.php new file mode 100644 index 000000000..e73aec335 --- /dev/null +++ b/application/views/widgets/table/table.php @@ -0,0 +1,17 @@ + +
    +
    + + +
    + + +
    + +
    + + +
    + +
    +
    diff --git a/application/views/widgets/table/tableDataset.php b/application/views/widgets/table/tableDataset.php new file mode 100644 index 000000000..7c2f26ea5 --- /dev/null +++ b/application/views/widgets/table/tableDataset.php @@ -0,0 +1,7 @@ + +
    '.$p->t("zeitaufzeichnung/projektphase").'
    @@ -126,17 +133,16 @@ echo ''; + + + + - + @@ -194,28 +234,28 @@ echo ''; + + + +
    SelectSelect" + columnName + "" + columnName + "" + columnName + "" + columnName + "
    Select" + columnName + "" + columnName + "
    "; + strHtml += ""; + strHtml += "" + record[data.fields[i]] + "" + record[additionalColumn] + "
    + + + + +
    diff --git a/application/views/widgets/table/tabulatorDataset.php b/application/views/widgets/table/tabulatorDataset.php new file mode 100644 index 000000000..4984284bc --- /dev/null +++ b/application/views/widgets/table/tabulatorDataset.php @@ -0,0 +1 @@ +
    From 6ed669cf0247ef3dbb47e463844f38735393fc55 Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Wed, 25 Sep 2019 17:24:22 +0200 Subject: [PATCH 206/500] Fixed PHP7 Bug that break SOAP Response --- include/webservicerecht.class.php | 70 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/include/webservicerecht.class.php b/include/webservicerecht.class.php index 566a32d71..1ba1765dd 100644 --- a/include/webservicerecht.class.php +++ b/include/webservicerecht.class.php @@ -17,7 +17,7 @@ * * Authors: Karl Burkhart . */ - + require_once(dirname(__FILE__).'/basis_db.class.php'); require_once(dirname(__FILE__).'/benutzerberechtigung.class.php'); @@ -35,7 +35,7 @@ class webservicerecht extends basis_db public $new; // boolean public $result = array(); // webservicerecht object array - + /** * Konstruktor - Laedt optional einen DS * @param $webservicerecht_id @@ -47,85 +47,85 @@ class webservicerecht extends basis_db if(!is_null($webservicerecht_id)) $this->load($webservicerecht_id); } - + /** * Überprüft ob ein User die Berechtigung für eine Methode zum lesen besitzt * true wenn user lesen darf, false wenn nicht - * + * * @param $user - * @param $methode + * @param $methode * @param $klasse */ public function isUserAuthorized($user, $methode, $klasse=null) { - $berechtigung = new benutzerberechtigung(); + $berechtigung = new benutzerberechtigung(); $berechtigung->getBerechtigungen($user); - $berechtigungArray = array(); - + $berechtigungArray = array(); + foreach ($berechtigung->berechtigungen as $recht) - { + { // ist berechtigung noch gültig if(($recht->start < date('Y-m-d') || $recht->start=='') && ($recht->ende > date('Y-m-d') || $recht->ende=='')) - $berechtigungArray[] = $recht->berechtigung_kurzbz; + $berechtigungArray[] = $recht->berechtigung_kurzbz; } - - $qry = "SELECT 1 from system.tbl_webservicerecht where methode = ".$this->db_add_param($methode)." + + $qry = "SELECT 1 from system.tbl_webservicerecht where methode = ".$this->db_add_param($methode)." AND berechtigung_kurzbz IN (".$this->implode4SQL($berechtigungArray).')'; if(!is_null($klasse)) $qry.=" AND klasse=".$this->db_add_param($klasse); - + if($result = $this->db_query($qry)) { if($this->db_num_rows($result) == 0 ) { - return false; + return false; } } else - return false; - - return true; + return false; + + return true; } - + /** * Löscht alle Attribute für die ein User keine Berechtiung hat - * + * * @param $user * @param $methode * @param $objec - * + * */ public function clearResponse($user, $methode, $object) { - $berechtigung = new benutzerberechtigung(); + $berechtigung = new benutzerberechtigung(); $berechtigung->getBerechtigungen($user); - $berechtigungArray = array(); - $attributArray = array(); - + $berechtigungArray = array(); + $attributArray = array(); + foreach ($berechtigung->berechtigungen as $recht) - $berechtigungArray[] = $recht->berechtigung_kurzbz; - - $qry = "SELECT attribut from system.tbl_webservicerecht where methode = ".$this->db_add_param($methode)." + $berechtigungArray[] = $recht->berechtigung_kurzbz; + + $qry = "SELECT attribut from system.tbl_webservicerecht where methode = ".$this->db_add_param($methode)." AND berechtigung_kurzbz IN (".$this->implode4SQL($berechtigungArray).');'; - + if($result = $this->db_query($qry)) { while($row = $this->db_fetch_object($result)) { - $attributArray[] = $row->attribut; + $attributArray[] = $row->attribut; } } - - $helpObject = new stdClass(); - + + $helpObject = new stdClass(); + for($i = 0; $i$attributArray[$i])) - $helpObject->$attributArray[$i] = $object->$attributArray[$i]; + if(isset($object->{$attributArray[$i]})) + $helpObject->{$attributArray[$i]} = $object->{$attributArray[$i]}; } - return $helpObject; + return $helpObject; } } From bdb0cb7772bb4ba2e712b58a110c26e57c5c8d2e Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 26 Sep 2019 16:17:35 +0200 Subject: [PATCH 207/500] - added codex/Bisiozweck_model.php --- application/models/codex/Bisiozweck_model.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 application/models/codex/Bisiozweck_model.php diff --git a/application/models/codex/Bisiozweck_model.php b/application/models/codex/Bisiozweck_model.php new file mode 100644 index 000000000..b456f412d --- /dev/null +++ b/application/models/codex/Bisiozweck_model.php @@ -0,0 +1,15 @@ +dbTable = 'bis.tbl_bisio_zweck'; + $this->pk = array('bisio_id', 'zweck_code'); + $this->hasSequence = false; + } +} From 4cb766d2938ac97715f915a876dc8bc6eaa2ac45 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 26 Sep 2019 17:05:56 +0200 Subject: [PATCH 208/500] - added rights SELECT UPDATE INSERT DELETE for web and vilesci for tables bis.tbl_bisio_zweck and bis.tbl_aufenthaltfoerderung --- system/dbupdate_3.3.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index e6151b06f..1e60db5ab 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -2961,7 +2961,7 @@ if ($result = $db->db_query("SELECT 0 FROM pg_class WHERE relname = 'tbl_zeitauf if (!$db->db_query($qry)) echo 'campus.tbl_zeitaufzeichnung_gd_id_seq '.$db->db_last_error().'
    '; else - echo '
    Granted privileges to vilesci on campus.tbl_zeitaufzeichnung_gd_id_seq'; + echo '
    Granted privileges to web on campus.tbl_zeitaufzeichnung_gd_id_seq'; // GRANT SELECT, UPDATE ON SEQUENCE campus.tbl_zeitaufzeichnung_gd_id_seq TO vilesci; $qry = 'GRANT SELECT, UPDATE ON SEQUENCE campus.tbl_zeitaufzeichnung_gd_id_seq TO vilesci;'; @@ -3088,6 +3088,20 @@ if(!$result = @$db->db_query("SELECT 1 FROM bis.tbl_aufenthaltfoerderung LIMIT 1 echo '
    bis.tbl_aufenthaltfoerderung hinzugefügt, Tabelle bis.tbl_bisio_aufenthaltfoerderung hinzugefuegt'; } +// GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_aufenthaltfoerderung TO web; +$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_aufenthaltfoerderung TO web;'; +if (!$db->db_query($qry)) + echo 'bis.tbl_aufenthaltfoerderung ' . $db->db_last_error() . '
    '; +else + echo '
    Granted privileges to web on bis.tbl_aufenthaltfoerderung'; + +// GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_aufenthaltfoerderung TO vilesci; +$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_aufenthaltfoerderung TO vilesci;'; +if (!$db->db_query($qry)) + echo 'bis.tbl_aufenthaltfoerderung ' . $db->db_last_error() . '
    '; +else + echo '
    Granted privileges to vilesci on bis.tbl_aufenthaltfoerderung'; + // Add table bis.tbl_bisio_zweck if(!$result = @$db->db_query("SELECT 1 FROM bis.tbl_bisio_zweck LIMIT 1")) { @@ -3113,6 +3127,20 @@ if(!$result = @$db->db_query("SELECT 1 FROM bis.tbl_bisio_zweck LIMIT 1")) echo '
    bis.tbl_bisio_zweck hinzugefuegt, Spalte bis.tbl_bisio.zweck_code als DEPRECATED markiert.'; } +// GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_bisio_zweck TO web; +$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_bisio_zweck TO web;'; +if (!$db->db_query($qry)) + echo 'bis.tbl_bisio_zweck ' . $db->db_last_error() . '
    '; +else + echo '
    Granted privileges to web on bis.tbl_bisio_zweck'; + +// GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_bisio_zweck TO vilesci; +$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE bis.tbl_bisio_zweck TO vilesci;'; +if (!$db->db_query($qry)) + echo 'bis.tbl_bisio_zweck ' . $db->db_last_error() . '
    '; +else + echo '
    Granted privileges to vilesci on bis.tbl_bisio_zweck'; + // Add Column incoming and outgoing to bis.tbl_zweck // change Datatype of bis.tbl_zweck.bezeichnung from varchar(32) to varchar(64) if(!$result = @$db->db_query("SELECT incoming FROM bis.tbl_zweck LIMIT 1")) From 1273c3241967d311d10676957fd0c13ef92265d3 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 26 Sep 2019 17:40:51 +0200 Subject: [PATCH 209/500] - Renamed controller system/JobsViewer.php to system/LogsViewer.php - Renamed directory views/system/jobs to views/system/logs - Changed FilterWidget query in view system/logs/logsViewerData.php to load all logs - Added more filters in database to load different log types --- .../system/{JobsViewer.php => LogsViewer.php} | 4 +- .../jobsViewer.php => logs/logsViewer.php} | 4 +- .../logsViewerData.php} | 10 +- system/filtersupdate.php | 153 +++++++++++++++++- 4 files changed, 157 insertions(+), 14 deletions(-) rename application/controllers/system/{JobsViewer.php => LogsViewer.php} (87%) rename application/views/system/{jobs/jobsViewer.php => logs/logsViewer.php} (90%) rename application/views/system/{jobs/jobsViewerData.php => logs/logsViewerData.php} (88%) diff --git a/application/controllers/system/JobsViewer.php b/application/controllers/system/LogsViewer.php similarity index 87% rename from application/controllers/system/JobsViewer.php rename to application/controllers/system/LogsViewer.php index 2fdfa7181..55cf38d82 100644 --- a/application/controllers/system/JobsViewer.php +++ b/application/controllers/system/LogsViewer.php @@ -5,7 +5,7 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); /** * Overview on cronjob logs */ -class JobsViewer extends Auth_Controller +class LogsViewer extends Auth_Controller { /** * Constructor @@ -39,6 +39,6 @@ class JobsViewer extends Auth_Controller */ public function index() { - $this->load->view('system/jobs/jobsViewer.php'); + $this->load->view('system/logs/logsViewer.php'); } } diff --git a/application/views/system/jobs/jobsViewer.php b/application/views/system/logs/logsViewer.php similarity index 90% rename from application/views/system/jobs/jobsViewer.php rename to application/views/system/logs/logsViewer.php index f7018a272..96790b479 100644 --- a/application/views/system/jobs/jobsViewer.php +++ b/application/views/system/logs/logsViewer.php @@ -2,7 +2,7 @@ $this->load->view( 'templates/FHC-Header', array( - 'title' => 'JobsViewer', + 'title' => 'Logs viewer', 'jquery' => true, 'jqueryui' => true, 'bootstrap' => true, @@ -37,7 +37,7 @@
    - load->view('system/jobs/jobsViewerData.php'); ?> + load->view('system/logs/logsViewerData.php'); ?>
    diff --git a/application/views/system/jobs/jobsViewerData.php b/application/views/system/logs/logsViewerData.php similarity index 88% rename from application/views/system/jobs/jobsViewerData.php rename to application/views/system/logs/logsViewerData.php index 07815c2f3..2dfcfc9d0 100644 --- a/application/views/system/jobs/jobsViewerData.php +++ b/application/views/system/logs/logsViewerData.php @@ -7,9 +7,9 @@ wsl.execute_time AS "ExecutionTime", wsl.execute_user AS "ExecutedBy", wsl.beschreibung AS "Description", - wsl.request_data AS "Data" + wsl.request_data AS "Data", + wsl.webservicetyp_kurzbz AS "WebserviceType" FROM system.tbl_webservicelog wsl - WHERE wsl.webservicetyp_kurzbz = \'job\' ORDER BY wsl.execute_time DESC ', 'requiredPermissions' => 'admin', @@ -21,7 +21,8 @@ 'Execution time', 'Executed by', 'Producer', - 'Data' + 'Data', + 'Webservice type' ), 'formatRow' => function($datasetRaw) { @@ -58,8 +59,7 @@ ); $filterWidgetArray['app'] = 'core'; - $filterWidgetArray['datasetName'] = 'jobslogs'; - $filterWidgetArray['filterKurzbz'] = 'all'; + $filterWidgetArray['datasetName'] = 'logs'; $filterWidgetArray['filter_id'] = $this->input->get('filter_id'); echo $this->widgetlib->widget('FilterWidget', $filterWidgetArray); diff --git a/system/filtersupdate.php b/system/filtersupdate.php index 2d1789774..415b8d442 100644 --- a/system/filtersupdate.php +++ b/system/filtersupdate.php @@ -463,14 +463,14 @@ $filters = array( ), array( 'app' => 'core', - 'dataset_name' => 'jobslogs', - 'filter_kurzbz' => 'all', - 'description' => '{All logs produced by jobs}', + 'dataset_name' => 'logs', + 'filter_kurzbz' => 'last7days', + 'description' => '{Last 7 days logs}', 'sort' => 1, 'default_filter' => true, 'filter' => ' { - "name": "All jobs viewer", + "name": "All logs from the last 7 days", "columns": [ {"name": "RequestId"}, {"name": "ExecutionTime"}, @@ -478,7 +478,150 @@ $filters = array( {"name": "Description"}, {"name": "Data"} ], - "filters": [] + "filters": [ + { + "name": "ExecutionTime", + "operation": "lt", + "condition": "7", + "option": "days" + } + ] + } + ', + 'oe_kurzbz' => null, + ), + array( + 'app' => 'core', + 'dataset_name' => 'logs', + 'filter_kurzbz' => 'jobs14days', + 'description' => '{Last 14 days jobs logs}', + 'sort' => 2, + 'default_filter' => false, + 'filter' => ' + { + "name": "All jobs logs from the last 14 days", + "columns": [ + {"name": "RequestId"}, + {"name": "ExecutionTime"}, + {"name": "ExecutedBy"}, + {"name": "Description"}, + {"name": "Data"} + ], + "filters": [ + { + "name": "WebserviceType", + "operation": "contains", + "condition": "job" + }, + { + "name": "ExecutionTime", + "operation": "lt", + "condition": "14", + "option": "days" + } + ] + } + ', + 'oe_kurzbz' => null, + ), + array( + 'app' => 'core', + 'dataset_name' => 'logs', + 'filter_kurzbz' => 'repots14days', + 'description' => '{Last 14 days reports logs}', + 'sort' => 3, + 'default_filter' => false, + 'filter' => ' + { + "name": "All reports logs from the last 14 days", + "columns": [ + {"name": "RequestId"}, + {"name": "ExecutionTime"}, + {"name": "ExecutedBy"}, + {"name": "Description"}, + {"name": "Data"} + ], + "filters": [ + { + "name": "WebserviceType", + "operation": "contains", + "condition": "reports" + }, + { + "name": "ExecutionTime", + "operation": "lt", + "condition": "14", + "option": "days" + } + ] + } + ', + 'oe_kurzbz' => null, + ), + array( + 'app' => 'core', + 'dataset_name' => 'logs', + 'filter_kurzbz' => 'content3days', + 'description' => '{Last 3 days content logs}', + 'sort' => 4, + 'default_filter' => false, + 'filter' => ' + { + "name": "All content logs from the last 3 days", + "columns": [ + {"name": "RequestId"}, + {"name": "ExecutionTime"}, + {"name": "ExecutedBy"}, + {"name": "Description"}, + {"name": "Data"} + ], + "filters": [ + { + "name": "WebserviceType", + "operation": "contains", + "condition": "content" + }, + { + "name": "ExecutionTime", + "operation": "lt", + "condition": "3", + "option": "days" + } + ] + } + ', + 'oe_kurzbz' => null, + ), + array( + 'app' => 'core', + 'dataset_name' => 'logs', + 'filter_kurzbz' => 'wienerlinien7days', + 'description' => '{Last 7 days wiener linien logs}', + 'sort' => 5, + 'default_filter' => false, + 'filter' => ' + { + "name": "All wiener linien logs from the last 7 days", + "columns": [ + {"name": "RequestId"}, + {"name": "ExecutionTime"}, + {"name": "ExecutedBy"}, + {"name": "Description"}, + {"name": "Data"} + ], + "filters": [ + { + "name": "WebserviceType", + "operation": "contains", + "condition": "wienerlinien" + }, + { + "name": "ExecutionTime", + "operation": "lt", + "condition": "7", + "option": "days" + } + ] } ', 'oe_kurzbz' => null, From 05898bdde59e3bec01643bcac7407e0ffdd10cb2 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 26 Sep 2019 17:46:40 +0200 Subject: [PATCH 210/500] system/dbupdate_3.3.: removed UPDATE, INSERT, DELETE permissions from user web for public.tbl_variablename --- system/dbupdate_3.3.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/dbupdate_3.3.php b/system/dbupdate_3.3.php index 66504cd5a..1c95190fb 100644 --- a/system/dbupdate_3.3.php +++ b/system/dbupdate_3.3.php @@ -3069,7 +3069,7 @@ if(!@$db->db_query("SELECT 0 FROM public.tbl_variablenname WHERE 0 = 1")) { echo '
    Created public.tbl_variablenname'; // GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO web; - $qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.tbl_variablenname TO web;'; + $qry = 'GRANT SELECT ON TABLE public.tbl_variablenname TO web;'; if (!$db->db_query($qry)) echo 'public.tbl_variablenname ' . $db->db_last_error() . '
    '; else From 4a00395d08f19538f85c745b15729fc4031941cc Mon Sep 17 00:00:00 2001 From: Andreas Oesterreicher Date: Fri, 27 Sep 2019 09:49:47 +0200 Subject: [PATCH 211/500] Moved directory creation to correct position to avoid problems if the entry is not displayed --- include/tw/cis_menu_lv.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/tw/cis_menu_lv.inc.php b/include/tw/cis_menu_lv.inc.php index 3a4a8f13b..68ae8a1cb 100644 --- a/include/tw/cis_menu_lv.inc.php +++ b/include/tw/cis_menu_lv.inc.php @@ -217,12 +217,12 @@ function checkZeilenUmbruch() $link= "anwesenheitsliste.php?stg_kz=$studiengang_kz&sem=$semester&lvid=$lvid&stsem=$angezeigtes_stsem"; } - ensureDirectoryExists($DOC_ROOT, $kurzbz, $semester, $short_short_name, 'leistung','teacher'); - $dir_empty = isDirectoryEmpty($DOC_ROOT, $kurzbz, $semester, $short_short_name, 'leistung'); - $text=''; if(CIS_LEHRVERANSTALTUNG_LEISTUNGSUEBERSICHT_ANZEIGEN && ($angemeldet || $is_lector)) { + ensureDirectoryExists($DOC_ROOT, $kurzbz, $semester, $short_short_name, 'leistung','teacher'); + $dir_empty = isDirectoryEmpty($DOC_ROOT, $kurzbz, $semester, $short_short_name, 'leistung'); + if($dir_empty == false) { $dir_name=$DOC_ROOT.'/documents/'.mb_strtolower($kurzbz).'/'.$semester.'/'.mb_strtolower($short_short_name).'/leistung'; From 471c1ab9ef043502598bc017ba56014542d5e96b Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Sep 2019 11:43:55 +0200 Subject: [PATCH 212/500] top border of projekt name row is shown also in excel --- .../tools/zeitaufzeichnung_projektliste.php | 14 +++++++++----- locale/de-AT/zeitaufzeichnung.php | 2 +- locale/en-US/zeitaufzeichnung.php | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cis/private/tools/zeitaufzeichnung_projektliste.php b/cis/private/tools/zeitaufzeichnung_projektliste.php index 64cf0ae9b..b8b19a0a9 100644 --- a/cis/private/tools/zeitaufzeichnung_projektliste.php +++ b/cis/private/tools/zeitaufzeichnung_projektliste.php @@ -528,7 +528,7 @@ $nrProjects = count($projektnames); $totalwidth = 150; $daywidth = 4; $totalworktimewidth = 13; -$worktimewidth = 8; +$worktimewidth = 14; $timecolumnswidth = 2 * $daywidth + $totalworktimewidth + $worktimewidth; if ($nrProjects < 1)//no projekts - merge all cells and write notice @@ -660,14 +660,18 @@ foreach ($projektnames as $projektname) $phasenames = array(); $phasenameslength = 0; } - $worksheet->write($zeile, $spalte, $projektname, $format_bold_centered_toprightline); $worksheet->write($zeile, $spalte + $phasenameslength + 1, '', $format_bold_centered_toprightline); - $worksheet->write($zeile + 1, $spalte, $p->t('zeitaufzeichnung/stunden'), $format_bold_centered_bottomline); + $worksheet->write($zeile + 1, $spalte, $p->t('zeitaufzeichnung/projektstunden'), $format_bold_centered_bottomline); + + for($i = 0; $i < $phasenameslength; $i++) + $worksheet->write($zeile, $spalte + 1 + $i, '', $format_bold_centered_toprightline); + $worksheet->setMerge($zeile, $spalte, $zeile, $spalte + 1 + $phasenameslength); + $worksheet->write($zeile, $spalte, $projektname, $format_bold_centered_toprightline); + for ($i = 0; $i < $phasenameslength; $i++) - { $worksheet->write($zeile + 1, $spalte + 1 + $i, $phasenames[$i], $format_bold_centered_bottomline); - } + $worksheet->setColumn($spalte + $phasenameslength + 1, $spalte + $phasenameslength + 1, $taetigkeitenwidth); $worksheet->write($zeile + 1, $spalte + $phasenameslength + 1, $p->t('zeitaufzeichnung/taetigkeit'), $format_bold_centered_bottomrightline); $spalte = $spalte + 2 + $phasenameslength; diff --git a/locale/de-AT/zeitaufzeichnung.php b/locale/de-AT/zeitaufzeichnung.php index 2901ac4a7..0692a5f8b 100644 --- a/locale/de-AT/zeitaufzeichnung.php +++ b/locale/de-AT/zeitaufzeichnung.php @@ -54,7 +54,7 @@ $this->phrasen['zeitaufzeichnung/monat']='Monat:'; $this->phrasen['zeitaufzeichnung/tag']='Tag'; $this->phrasen['zeitaufzeichnung/startdatum']='Startdatum:'; $this->phrasen['zeitaufzeichnung/enddatum']='Enddatum:'; -$this->phrasen['zeitaufzeichnung/stunden']='Stunden'; +$this->phrasen['zeitaufzeichnung/projektstunden']='Projektstunden'; $this->phrasen['zeitaufzeichnung/taetigkeit']='Tätigkeit'; $this->phrasen['zeitaufzeichnung/keineprojekte']='keine Projekte vorhanden'; $this->phrasen['zeitaufzeichnung/summe']='Summe:'; diff --git a/locale/en-US/zeitaufzeichnung.php b/locale/en-US/zeitaufzeichnung.php index 936e65653..cd460dc97 100644 --- a/locale/en-US/zeitaufzeichnung.php +++ b/locale/en-US/zeitaufzeichnung.php @@ -54,7 +54,7 @@ $this->phrasen['zeitaufzeichnung/monat']='Month:'; $this->phrasen['zeitaufzeichnung/tag']='Day'; $this->phrasen['zeitaufzeichnung/startdatum']='Startdate:'; $this->phrasen['zeitaufzeichnung/enddatum']='Enddate:'; -$this->phrasen['zeitaufzeichnung/stunden']='Hours'; +$this->phrasen['zeitaufzeichnung/projektstunden']='Project hours'; $this->phrasen['zeitaufzeichnung/taetigkeit']='Activity'; $this->phrasen['zeitaufzeichnung/keineprojekte']='no projects exist'; $this->phrasen['zeitaufzeichnung/summe']='Sum:'; From 10e1539b22e1afa43fa43c42b97459f1b4b5ef40 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Sep 2019 14:36:18 +0200 Subject: [PATCH 213/500] infocenterData.php, infocenterFreigegebenData.php, infocenterReihungstestAbsolviertData.php: column data is retrieved from selected Studiensemester variable, and not from future Semesters --- .../system/infocenter/infocenterData.php | 17 +++++++++++------ .../infocenter/infocenterFreigegebenData.php | 19 ++++++++++--------- .../infocenterReihungstestAbsolviertData.php | 16 ++++++++-------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/application/views/system/infocenter/infocenterData.php b/application/views/system/infocenter/infocenterData.php index 6dd0ee957..04b99b057 100644 --- a/application/views/system/infocenter/infocenterData.php +++ b/application/views/system/infocenter/infocenterData.php @@ -99,7 +99,8 @@ FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 @@ -124,7 +125,8 @@ FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) LIMIT 1 ) AS "AnzahlAbgeschickt", @@ -148,7 +150,8 @@ FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) LIMIT 1 ) AS "StgAbgeschickt", @@ -173,7 +176,8 @@ FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) LIMIT 1 ) AS "StgNichtAbgeschickt", @@ -190,13 +194,14 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.start >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) LIMIT 1 ) AS "StgAktiv", diff --git a/application/views/system/infocenter/infocenterFreigegebenData.php b/application/views/system/infocenter/infocenterFreigegebenData.php index 20548d3f4..89ba2ec38 100644 --- a/application/views/system/infocenter/infocenterFreigegebenData.php +++ b/application/views/system/infocenter/infocenterFreigegebenData.php @@ -59,7 +59,7 @@ sg.studiengang_kz in('.$ADDITIONAL_STG.') ) AND pss.bestaetigtam is not null - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "Studiensemester", @@ -75,7 +75,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "SendDate", @@ -91,7 +91,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss @@ -113,7 +113,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' LIMIT 1 ) AS "StgAbgeschickt", ( @@ -129,13 +129,14 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' AND NOT EXISTS ( SELECT 1 FROM tbl_prestudentstatus spss WHERE spss.prestudent_id = pss.prestudent_id AND spss.status_kurzbz = '.$REJECTED_STATUS.' - AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > NOW()) + AND spss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende > + (SELECT start FROM public.tbl_studiensemester sss WHERE studiensemester_kurzbz = '.$STUDIENSEMESTER.')) ) LIMIT 1 ) AS "StgAktiv", @@ -146,7 +147,7 @@ LEFT JOIN public.tbl_status_grund sg USING(statusgrund_id) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' LIMIT 1 ) AS "Statusgrund", ( @@ -163,7 +164,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestAngetreten", @@ -180,7 +181,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.studiensemester_kurzbz = '.$STUDIENSEMESTER.') + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestApplied", diff --git a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php index 46f952ec3..22b122bb0 100644 --- a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php +++ b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php @@ -47,7 +47,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "Studiensemester", @@ -63,7 +63,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "SendDate", @@ -79,7 +79,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' LIMIT 1 ) AS "AnzahlAbgeschickt", ( @@ -94,7 +94,7 @@ OR sg.studiengang_kz in('.$ADDITIONAL_STG.') ) - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' LIMIT 1 ) AS "StgAbgeschickt", ( @@ -104,7 +104,7 @@ LEFT JOIN public.tbl_status_grund sg USING(statusgrund_id) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' LIMIT 1 ) AS "Statusgrund", ( @@ -121,7 +121,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestAngetreten", @@ -138,7 +138,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestApplied", @@ -156,7 +156,7 @@ ) rtp ON(rtp.person_id = ps.person_id AND rtp.studiensemester_kurzbz = pss.studiensemester_kurzbz) WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.' AND ps.person_id = p.person_id - AND pss.studiensemester_kurzbz IN (SELECT ss.studiensemester_kurzbz FROM public.tbl_studiensemester ss WHERE ss.ende >= NOW()) + AND pss.studiensemester_kurzbz = '.$STUDIENSEMESTER.' ORDER BY pss.datum DESC, pss.insertamum DESC, pss.ext_id DESC LIMIT 1 ) AS "ReihungstestDatum", From 484cc844edd7b6096df71c6e3eafffdb9fc4e1e1 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Sep 2019 16:44:01 +0200 Subject: [PATCH 214/500] - Zeitaufzeichnung Projektphasen dropdown is shown right from Projektdropdown - Projektphasen Dropdown is shown only if selected Projekt has Projektphasen --- cis/private/tools/zeitaufzeichnung.php | 46 +++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index df7a2bd34..94251ce12 100644 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -111,8 +111,6 @@ else if (defined('CIS_ZEITAUFZEICHNUNG_GESPERRT_BIS') && CIS_ZEITAUFZEICHNUNG_GE else $gesperrt_bis = '2015-08-31'; -//var_dump($gesperrt_bis); - $sperrdatum = date('c', strtotime($gesperrt_bis)); // Uses urlencode to avoid XSS issues @@ -513,6 +511,7 @@ echo ' }, success: function(json) { + //remove Projektphasen from html if any $("#projektphase").children("option").each( function() { @@ -520,14 +519,22 @@ echo ' $(this).remove(); } ); - - var projphasenhtml = ""; - for (var i = 0; i < json.length; i++) + //append Projektphasen if any + if (json.length > 0) { - projphasenhtml += "'; sort($projekt->result); + $projektfound = false; foreach ($projekt->result as $row_projekt) { if ($projekt_kurzbz == $row_projekt->projekt_kurzbz || $filter == $row_projekt->projekt_kurzbz) + { + $projektfound = true; $selected = 'selected'; + } else $selected = ''; echo ''; } - echo '
    '.$p->t("zeitaufzeichnung/projektphase").' '; - if (isset($projektphasen) && is_array($projektphasen)) + if ($showprojphases) { foreach ($projektphasen as $projektphase) { @@ -1018,9 +1032,9 @@ if($projekt->getProjekteMitarbeiter($user, true)) echo ''; } + echo ''; } - echo '
    t('pruefung/pruefungIntervall'); ?>: From 10963fd5c7717c156eb6045fb53bdcc5a3b852c3 Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 2 Oct 2019 09:30:41 +0200 Subject: [PATCH 229/500] Added Stunden/Studiensemester of original contract to FAS Vertragsreiter --- content/mitarbeiter/mitarbeitervertrag.js.php | 4 ++ .../mitarbeitervertragneudialog.js.php | 4 ++ .../mitarbeitervertragneudialog.xul.php | 39 ++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/content/mitarbeiter/mitarbeitervertrag.js.php b/content/mitarbeiter/mitarbeitervertrag.js.php index 00834c6d5..338b80859 100644 --- a/content/mitarbeiter/mitarbeitervertrag.js.php +++ b/content/mitarbeiter/mitarbeitervertrag.js.php @@ -208,6 +208,8 @@ function MitarbeiterVertragGenerateVertrag(windowdocument) mitarbeiter_uid = getTreeCellText(tree, "mitarbeiter-vertrag-tree-nichtzugeordnet-mitarbeiter_uid",v); lehreinheit_id = getTreeCellText(tree, "mitarbeiter-vertrag-tree-nichtzugeordnet-lehreinheit_id",v); betreuerart_kurzbz = getTreeCellText(tree, "mitarbeiter-vertrag-tree-nichtzugeordnet-betreuerart_kurzbz",v); + vertragsstunden = getTreeCellText(tree, "mitarbeiter-vertrag-tree-nichtzugeordnet-vertragsstunden",v); + vertragsstunden_studiensemester_kurzbz = getTreeCellText(tree, "mitarbeiter-vertrag-tree-nichtzugeordnet-vertragsstunden_studiensemester_kurzbz",v); req.add('type_'+anzahl, type); req.add('stsem_'+anzahl, stsem); @@ -216,6 +218,8 @@ function MitarbeiterVertragGenerateVertrag(windowdocument) req.add('mitarbeiter_uid_'+anzahl, mitarbeiter_uid); req.add('lehreinheit_id_'+anzahl, lehreinheit_id); req.add('betreuerart_kurzbz_'+anzahl, betreuerart_kurzbz); + req.add('vertragsstunden'+anzahl, vertragsstunden); + req.add('vertragsstunden_studiensemester_kurzbz'+anzahl, vertragsstunden_studiensemester_kurzbz); anzahl++; } diff --git a/content/mitarbeiter/mitarbeitervertragneudialog.js.php b/content/mitarbeiter/mitarbeitervertragneudialog.js.php index 9f488f17f..666742f22 100644 --- a/content/mitarbeiter/mitarbeitervertragneudialog.js.php +++ b/content/mitarbeiter/mitarbeitervertragneudialog.js.php @@ -85,6 +85,8 @@ function MitarbeiterVertragNeuInit(person_id, vertrag_id) bezeichnung = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#bezeichnung" )); anmerkung = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#anmerkung" )); vertragsdatum = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#vertragsdatum" )); + vertragsstunden = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#vertragsstunden" )); + vertragsstunden_studiensemester_kurzbz = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#vertragsstunden_studiensemester_kurzbz" )); MitarbeiterVertragNeuBetragOld = betrag; @@ -94,6 +96,8 @@ function MitarbeiterVertragNeuInit(person_id, vertrag_id) document.getElementById('mitarbeiter-vertrag-neu-textbox-vertrag_id').value=vertrag_id; document.getElementById('mitarbeiter-vertrag-neu-textbox-anmerkung').value=anmerkung; document.getElementById('mitarbeiter-vertrag-neu-box-vertragsdatum').value=vertragsdatum; + document.getElementById('mitarbeiter-vertrag-neu-textbox-vertragsstunden').value = vertragsstunden; + document.getElementById('mitarbeiter-vertrag-neu-textbox-vertragsstunden_studiensemester_kurzbz').value = vertragsstunden_studiensemester_kurzbz; } for(i in addon) diff --git a/content/mitarbeiter/mitarbeitervertragneudialog.xul.php b/content/mitarbeiter/mitarbeitervertragneudialog.xul.php index db8cc407f..d3d7a0bfa 100644 --- a/content/mitarbeiter/mitarbeitervertragneudialog.xul.php +++ b/content/mitarbeiter/mitarbeitervertragneudialog.xul.php @@ -110,8 +110,19 @@ foreach($addon_obj->result as $addon) sort="rdf:http://www.technikum-wien.at/vertragdetails/rdf#lehreinheit_id" />