diff --git a/application/config/lvverwaltung.php b/application/config/lvverwaltung.php index 4fe09bff3..d315c9b38 100644 --- a/application/config/lvverwaltung.php +++ b/application/config/lvverwaltung.php @@ -8,4 +8,15 @@ $config['lvverwaltung_tags'] = [ ]; */ -$config['lvverwaltung_tags'] = []; \ No newline at end of file +$config['lvverwaltung_tags'] = []; + +# Additional columns: +/* +$config["list_columns"] = [ + 'fieldname' => [ + 'js' => 'path/to/snippet.js', // tabulator config snippet (eg: return { name: 'Name', field: 'fieldname' }; ) + // NOTE: 'default' & 'joins' like in stv.php config are currently not available here + ] +]; +*/ + diff --git a/application/config/routes.php b/application/config/routes.php index 8024f449a..a58fded36 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -75,52 +75,65 @@ $route['Abgabetool/Student'] = 'Cis/Abgabetool/Student'; $route['Abgabetool/Student/(:any)'] = 'Cis/Abgabetool/Student/$1'; $route['Abgabetool/Deadlines'] = 'Cis/Abgabetool/Deadlines'; +// Studierendenverwaltung App Routes +$route['studvw'] = 'studentenverwaltung/index'; +$route['studvw/.*'] = 'studentenverwaltung/index'; +// Old routes +$route['studentenverwaltung'] = 'redirect/301/studvw'; +$route['studentenverwaltung/(:any)'] = 'redirect/301/studvw/stdsem/$1'; +$route['studentenverwaltung/(:any)/(prestudent|student|person|search)/(:any)'] = 'redirect/301/studvw/stdsem/$1/$2/$3'; +$route['studentenverwaltung/(:any)/prestudent/(:any)/tab/:any'] = 'redirect/301/studvw/stdsem/$1/prestudent/$2'; +$route['studentenverwaltung/(:any)/search/(:any)/(:any)'] = 'redirect/301/studvw/stdsem/$1/search/$2/$3'; +$route['studentenverwaltung/(:any)/(:any)'] = 'redirect/301/studvw/stdsem/$1/stg/$2'; + // Studierendenverwaltung List Routes -$route['api/frontend/v1/stv/[sS]tudents/inout'] = 'api/frontend/v1/stv/Students/index'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/index'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/incoming/1'] = 'api/frontend/v1/stv/students/getIncoming/$1'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/outgoing/1'] = 'api/frontend/v1/stv/students/getOutgoing/$1'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/shared_studies/1'] = 'api/frontend/v1/stv/students/getGemeinsamestudien/$1'; -// (studiensemester_kurzbz)/inout[/(incoming|outgoing|gemeinsamestudien)] -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout'] = 'api/frontend/v1/stv/Students/index'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/incoming'] = 'api/frontend/v1/stv/Students/getIncoming/$1'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/outgoing'] = 'api/frontend/v1/stv/Students/getOutgoing/$1'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/gemeinsamestudien'] = 'api/frontend/v1/stv/Students/getGemeinsamestudien/$1'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1'; -// (studiengang_kz)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]] -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudents/$1'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$3'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2'; -// (studiengang_kz)/(orgform)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]] -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$4'; -$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$5'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/verband/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3/$4/$5'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/verband/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2'; -// (studiensemester_kurzbz)/(studiengang_kz)/(semester)/grp/(gruppe) -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/grp/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsSpezialgruppe/$1/$2/$3/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/verband/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4/$5/$6'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/verband/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4/$5'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3'; -// (studiensemester_kurzbz)/(studiengang_kz)[/(semester)[/(verband)[/(gruppe)]]] -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/(:any)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3/$4'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3/$4/$5'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsSpezialgruppe/$1/$2/$3/$4'; -// (studiensemester_kurzbz)/(studiengang_kz)/(orgform)/(semester)/grp/(gruppe) -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/grp/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgformSpezialgruppe/$1/$2/$3/$4/$5'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgformSpezialgruppe/$1/$3/$2/$4/$5'; -// (studiensemester_kurzbz)/(studiengang_kz)/(orgform)[/(semester)[/(verband)[/(gruppe)]]] -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4/$5'; -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4/$5/$6'; +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/prestudent/(:any)'] = 'api/frontend/v1/stv/students/getPrestudent/$1/$2'; + +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/student/(:any)'] = 'api/frontend/v1/stv/students/getStudent/$1/$2'; + +$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/person/(:any)'] = 'api/frontend/v1/stv/students/getPerson/$1/$2'; + +$route['api/frontend/v1/treemenudata/stv/.*'] = 'api/frontend/v1/stv/students/index'; + +// Lvverwaltung List Routes +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3'; + +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3'; +$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3'; -// // (studiensemester_kurzbz)/uid/(uid) -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/uid/(:any)'] = 'api/frontend/v1/stv/Students/getStudent/$1/$2'; -// // (studiensemester_kurzbz)/prestudent/(prestudent_id) -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/prestudent/(:num)'] = 'api/frontend/v1/stv/Students/getPrestudent/$1/$2'; -// // (studiensemester_kurzbz)/person/(person_id) -$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/frontend/v1/stv/Students/getPerson/$1/$2'; // load routes from extensions, also look for environment-specific configs $subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions']; diff --git a/application/config/stv.php b/application/config/stv.php index 3090e3f2e..3c318ad9d 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -1,6 +1,27 @@ [ + 'js' => 'path/to/snippet.js', // tabulator config snippet (eg: return { name: 'Name', field: 'fieldname' }; ) + 'default' => "SQL SELECT statement for value", + 'joins' => [ + // additional joins needed for the SELECT statement above + [ + 'tablename', + 'join condition', // single fieldname for USING or full condition for ON + 'LEFT|RIGHT', // optional - join type + 'after_xxx|before_xxx|end' // optional - position in query + ] + // ... + ] + ] +]; +*/ + $config['tabs'] = [ 'details' => [ diff --git a/public/js/api/factory/stv/verband.js b/application/config/treemenu.php similarity index 60% rename from public/js/api/factory/stv/verband.js rename to application/config/treemenu.php index 114931e4c..72a02947b 100644 --- a/public/js/api/factory/stv/verband.js +++ b/application/config/treemenu.php @@ -1,5 +1,7 @@ +. */ -export default { - get(path) { - let url = 'api/frontend/v1/stv/verband'; - if (path) - url += '/' + path; - return { - method: 'get', - url - }; - }, - favorites: { - get() { - return { - method: 'get', - url: 'api/frontend/v1/stv/favorites' - }; - }, - set(favorites) { - return { - method: 'post', - url: 'api/frontend/v1/stv/favorites/set', - params: { favorites } - }; - } - } -}; \ No newline at end of file +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +$config['stv'] = [ + "library" => "treemenu/StudVwLib", + "permissions" => ["admin:r", "assistenz:r"] +]; +$config['lvv'] = [ + "library" => "treemenu/LvVwLib", + "permissions" => ["admin:r", "assistenz:r"] +]; diff --git a/application/config/treemenu/custom/lvvw.php b/application/config/treemenu/custom/lvvw.php new file mode 100644 index 000000000..a1f270e05 --- /dev/null +++ b/application/config/treemenu/custom/lvvw.php @@ -0,0 +1,32 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +$config['root'] = [ + 'stg' => [ + 'semester' => [ + /*'group', + 'verband' => [ + 'group' + ]*/ + ], + 'orgform' + ] +]; diff --git a/application/config/treemenu/stg_base.php b/application/config/treemenu/stg_base.php new file mode 100644 index 000000000..fcb9748b7 --- /dev/null +++ b/application/config/treemenu/stg_base.php @@ -0,0 +1,65 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +$config['root'] = [ + 'stg' => [ + 'prestudent' => [ + 'stdsem' => [ + 'interessenten' => [ + 'bewerbungnichtabgeschickt', + 'bewerbungabgeschickt', + 'zgv', + 'statusbestaetigt' => [ + 'statusbestaetigtrtnichtangemeldet', + 'statusbestaetigtrtangemeldet' + ], + 'reihungstestnichtangemeldet', + 'reihungstestangemeldet' + ], + 'bewerber' => [ + 'bewerberrtnichtangemeldet', + 'bewerberrtangemeldet' => [ + 'bewerberrtangemeldetteilgenommen', + 'bewerberrtangemeldetnichtteilgenommen' + ] + ], + 'aufgenommen', + 'warteliste', + 'absage', + 'incoming' + ] + ], + 'semester' => [ + 'group', + 'verband' => [ + 'group' + ] + ] + ], + 'inout' => [ + 'incoming', + 'outgoing', + 'shared_studies' + ] +]; + +// copy stg tree into stg/orgforms +$config['root']['stg']['orgform'] = $config['root']['stg']; diff --git a/application/controllers/Redirect.php b/application/controllers/Redirect.php new file mode 100644 index 000000000..f4a9f4cd7 --- /dev/null +++ b/application/controllers/Redirect.php @@ -0,0 +1,44 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller redirects urls to another location. This is mainly used + * with the $routes config + */ +class Redirect extends CI_Controller +{ + public function __construct() + { + parent::__construct(); + } + + /** + * Main function to handle all redirects. + * + * @param string $method - the redirect code (30x) + * @param array $params - the url to redirect to + * + * @return void + */ + public function _remap($method, $params) + { + redirect($params, 'location', $method); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/Favorites.php similarity index 78% rename from application/controllers/api/frontend/v1/stv/Favorites.php rename to application/controllers/api/frontend/v1/Favorites.php index 951eb01a4..787163abb 100644 --- a/application/controllers/api/frontend/v1/stv/Favorites.php +++ b/application/controllers/api/frontend/v1/Favorites.php @@ -20,8 +20,8 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); /** * This controller operates between (interface) the JS (GUI) and the back-end - * Provides data to the ajax get calls about favorite verbände - * Listens to ajax post calls to change the favorite verbände data + * Provides data to the ajax get calls about favorite treemenu entries + * Listens to ajax post calls to change the favorite treemenu entries * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON */ class Favorites extends FHCAPI_Controller @@ -29,7 +29,7 @@ class Favorites extends FHCAPI_Controller public function __construct() { parent::__construct([ - 'index' => self::PERM_LOGGED, + 'get' => self::PERM_LOGGED, 'set' => self::PERM_LOGGED ]); @@ -37,19 +37,19 @@ class Favorites extends FHCAPI_Controller $this->load->model('system/Variable_model', 'VariableModel'); } - public function index() + public function get($app) { - $result = $this->VariableModel->getVariables(getAuthUID(), ['stv_favorites']); + $result = $this->VariableModel->getVariables(getAuthUID(), [$app . '_favorites']); $data = $this->getDataOrTerminateWithError($result); if (!$data) $this->terminateWithSuccess(null); else - $this->terminateWithSuccess($data['stv_favorites'] ?? null); + $this->terminateWithSuccess($data[$app . '_favorites'] ?? null); } - public function set() + public function set($app) { $this->load->library('form_validation'); @@ -60,7 +60,7 @@ class Favorites extends FHCAPI_Controller $favorites = $this->input->post('favorites'); - $result = $this->VariableModel->setVariable(getAuthUID(), 'stv_favorites', $favorites); + $result = $this->VariableModel->setVariable(getAuthUID(), $app . '_favorites', $favorites); $this->getDataOrTerminateWithError($result); diff --git a/application/controllers/api/frontend/v1/Lehrveranstaltung.php b/application/controllers/api/frontend/v1/Lehrveranstaltung.php index 935602391..66bda9ebf 100644 --- a/application/controllers/api/frontend/v1/Lehrveranstaltung.php +++ b/application/controllers/api/frontend/v1/Lehrveranstaltung.php @@ -56,7 +56,9 @@ class Lehrveranstaltung extends FHCAPI_Controller $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); - $lehrveranstaltungen = $this->_ci->LehreinheitModel->getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $stg_kz); + $studiengang_kz = $this->getStudiengangKz($stg_kz); + + $lehrveranstaltungen = $this->_ci->LehreinheitModel->getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $studiengang_kz); $lehrveranstaltungen_data = $this->getDataOrTerminateWithError($lehrveranstaltungen); $tree = []; @@ -75,15 +77,17 @@ class Lehrveranstaltung extends FHCAPI_Controller $this->terminateWithSuccess($tree); } - public function getByStg($studiensemester_kurzbz = null, $studiengang_kz = null, $semester = null) + public function getByStg($studiensemester_kurzbz = null, $stg_kz = null, $semester = null) { + $studiengang_kz = $this->getStudiengangKz($stg_kz); + if (is_null($studiengang_kz) || !preg_match("/^-?[1-9][0-9]*$/", (string)$studiengang_kz)) $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); $verband = null; if (!is_null($semester) && !is_numeric($semester)) { - $verband = $semester; + $verband = $this->getOrgformKurzbz($semester); $semester = null; } @@ -260,18 +264,53 @@ class Lehrveranstaltung extends FHCAPI_Controller } } + protected function getStudiengangKz($studiengang_typ_kurzbz) + { + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $result = $this->StudiengangModel->loadWhere([ + 'LOWER(CONCAT(typ, kurzbz)) =' => strtolower($studiengang_typ_kurzbz) + ]); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + return null; + + return current($data)->studiengang_kz; + } + private function getStudiensemesterKurzbz($studiensemester_kurzbz = null) { if (!is_null($studiensemester_kurzbz)) { - $studiensemester_result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz); + $studiensemester_result = $this->_ci->StudiensemesterModel->loadWhere([ + 'LOWER(studiensemester_kurzbz)' => strtolower($studiensemester_kurzbz) + ]); if (isError($studiensemester_result) || !hasData($studiensemester_result)) - $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); return getData($studiensemester_result)[0]->studiensemester_kurzbz; } $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); } + + protected function getOrgformKurzbz($orgform_kurzbz) + { + if ($orgform_kurzbz === null) + return null; + + $this->load->model('codex/Orgform_model', 'OrgformModel'); + $result = $this->OrgformModel->loadWhere([ + 'LOWER(orgform_kurzbz) =' => strtolower($orgform_kurzbz) + ]); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + return $orgform_kurzbz; + + return current($data)->orgform_kurzbz; + } } diff --git a/application/controllers/api/frontend/v1/Treemenu.php b/application/controllers/api/frontend/v1/Treemenu.php new file mode 100644 index 000000000..e25610370 --- /dev/null +++ b/application/controllers/api/frontend/v1/Treemenu.php @@ -0,0 +1,148 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +use \ReflectionMethod as ReflectionMethod; +use \ReflectionFunction as ReflectionFunction; + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about menues + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Treemenu extends FHCAPI_Controller +{ + public function __construct() + { + // Load Router + $router = load_class('Router'); + + // Load Config + $config = load_class('Config'); + $config->load('treemenu'); + + // Get Treemenu name & config + $name = $router->method; + $conf = $config->item($name); + + // Get Permissions from config + $permissions = $conf['permissions'] ?? self::PERM_ANONYMOUS; + + // Call constructor + parent::__construct([ + $name => $permissions + ]); + + // Load Library + $libraryName = $conf['library'] ?? null; + $this->load->library($libraryName, null, 'treemenulib'); + } + + /** + * @param string $method + * @param array $params (optional) + * + * @return void + */ + public function _remap($method, $params = []) + { + if (!$this->treemenulib) + show_404(); + + $this->addMeta('ci_method', $method); + $this->addMeta('ci_params', $params); + + $params = $this->uri->uri_to_assoc(6); // 6 = start of $params + $config = $this->treemenulib->config; + + foreach (array_keys($params) as $key) { + if (!isset($config[$key]) || !$config[$key]) + show_404(); + + $config = $config[$key]; + } + + // Prepare aliases + $argumentaliases = []; + if (property_exists($this->treemenulib, 'path_to_argument')) + $argumentaliases = array_flip($this->treemenulib->path_to_argument); + $methodaliases = []; + if (property_exists($this->treemenulib, 'redirect_method')) + $methodaliases = $this->treemenulib->redirect_method; + + $items = []; + foreach ($config as $uripart => $children) { + if (!is_array($children)) { + $uripart = $children; + $children = []; + } + + $methodName = $uripart; + if (isset($methodaliases[$methodName])) { + $methodName = $methodaliases[$methodName]; + } elseif (strpbrk($methodName, ' _-') !== false) { + $methodName = lcfirst(str_replace([' ', '_', '-'], '', ucwords($methodName, " \t\r\n\f\v_-"))); + } + + // Prepare arguments + if (is_callable($methodName, false, $name)) { + if (is_string($methodName) && is_callable([$this->treemenulib, $methodName])) + $callable = [$this->treemenulib, $methodName]; + else + $callable = $methodName; + } else { + $callable = [$this->treemenulib, $methodName]; + } + + if (is_array($callable)) + $reflection = new ReflectionMethod($callable[0], $callable[1]); + elseif (is_string($callable) && strstr($callable, '::')) + $reflection = new ReflectionMethod($callable); + elseif ($name != 'Closure::__invoke' && strstr($name, '::__invoke')) + $reflection = new ReflectionMethod($callable, '__invoke'); + else + $reflection = new ReflectionFunction($callable); + + $arguments = []; + foreach ($reflection->getParameters() as $arg) { + if ($arg->name == 'path_template') { + $path = $params; + $path[$uripart] = '%s'; + $arguments[] = $this->uri->assoc_to_uri($path); + } elseif ($arg->name == 'has_children') { + $arguments[] = $children; + } elseif ($arg->name == 'original_method') { + $arguments[] = $uripart; + } elseif (isset($argumentaliases[$arg->name]) && isset($params[$argumentaliases[$arg->name]])) { + $arguments[] = $params[$argumentaliases[$arg->name]]; + } elseif (isset($params[$arg->name])) { + $arguments[] = $params[$arg->name]; + } else { + $arguments[] = null; + } + } + + // Call function from lib + $items = array_merge($items, call_user_func_array($callable, $arguments)); + } + + $this->terminateWithSuccess($items); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Favorites.php b/application/controllers/api/frontend/v1/lv/Favorites.php deleted file mode 100644 index 080a4ec6e..000000000 --- a/application/controllers/api/frontend/v1/lv/Favorites.php +++ /dev/null @@ -1,47 +0,0 @@ - self::PERM_LOGGED, - 'set' => self::PERM_LOGGED - ]); - - // Load models - $this->load->model('system/Variable_model', 'VariableModel'); - } - - public function index() - { - $result = $this->VariableModel->getVariables(getAuthUID(), ['lv_favorites']); - - $data = $this->getDataOrTerminateWithError($result); - - if (!$data) - $this->terminateWithSuccess(null); - else - $this->terminateWithSuccess(isset($data['lv_favorites']) ? $data['lv_favorites'] : null); - } - - public function set() - { - $this->load->library('form_validation'); - - $this->form_validation->set_rules('favorites', 'Favorites', 'required'); - - if (!$this->form_validation->run()) - $this->terminateWithValidationErrors($this->form_validation->error_array()); - - $favorites = $this->input->post('favorites'); - - $result = $this->VariableModel->setVariable(getAuthUID(), 'lv_favorites', $favorites); - - $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess(true); - } -} diff --git a/application/controllers/api/frontend/v1/lv/StgTree.php b/application/controllers/api/frontend/v1/lv/StgTree.php deleted file mode 100644 index 8272da978..000000000 --- a/application/controllers/api/frontend/v1/lv/StgTree.php +++ /dev/null @@ -1,117 +0,0 @@ -method] = ['admin:r', 'assistenz:r']; - parent::__construct($permissions); - - $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); - } - - public function _remap($method, $params = []) - { - if ($method == '' || $method == 'index') - return $this->getBase(); - - if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method) - && !$this->permissionlib->isBerechtigt('admin', 's', $method) - ) { - return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]); - } - - return $this->getStudiengang($method); - show_404(); - } - - protected function getBase() - { - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addDistinct(); - $this->StudiengangModel->addSelect("v.studiengang_kz AS link"); - $this->StudiengangModel->addSelect( - "CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name", - false - ); - $this->StudiengangModel->addSelect('erhalter_kz'); - $this->StudiengangModel->addSelect('typ'); - $this->StudiengangModel->addSelect('kurzbz'); - $this->StudiengangModel->addSelect('studiengang_kz'); - $this->StudiengangModel->addSelect('studiengang_kz AS stg_kz'); - - $this->StudiengangModel->addOrder('erhalter_kz'); - $this->StudiengangModel->addOrder('typ'); - $this->StudiengangModel->addOrder('kurzbz'); - - $stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: []; - $stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); - - if (!$stgs) - $this->terminateWithSuccess([]); - - $this->StudiengangModel->db->where_in('studiengang_kz', $stgs); - - $result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]); - - $list = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($list); - } - - protected function getStudiengang($studiengang_kz) - { - $link = $studiengang_kz . '/'; - - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addDistinct(); - $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false); - $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false); - $this->StudiengangModel->addSelect("TRUE AS leaf", false); - - $this->StudiengangModel->addSelect('semester'); - $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); - - $this->StudiengangModel->addOrder('semester'); - - $result = $this->StudiengangModel->loadWhere([ - 'v.studiengang_kz' => $studiengang_kz, - 'v.aktiv' => true - ]); - $list = $this->getDataOrTerminateWithError($result); - - $result = $this->StudiengangModel->load($studiengang_kz); - $result = $this->getDataOrTerminateWithError($result); - if ($result) - { - if (current($result)->mischform) - { - $this->load->model('organisation/Studienordnung_model', 'StudienordnungModel'); - - $this->StudienordnungModel->addDistinct(); - $this->StudienordnungModel->addSelect("CONCAT(studiengang_kz, '/', p.orgform_kurzbz) AS link"); - $this->StudienordnungModel->addSelect("p.orgform_kurzbz AS name"); - $this->StudienordnungModel->addSelect("TRUE as leaf", false); - - $this->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id'); - - $result = $this->StudienordnungModel->loadWhere([ - 'aktiv' => true, - 'studiengang_kz' => $studiengang_kz, - 'p.orgform_kurzbz !=' => 'DDP' - ]); - $result = $this->getDataOrTerminateWithError($result); - - $list = array_merge($list, $result); - } - } - - $this->terminateWithSuccess($list); - } -} diff --git a/application/controllers/api/frontend/v1/organisation/Studiensemester.php b/application/controllers/api/frontend/v1/organisation/Studiensemester.php index 3c6b72d2f..eaafc6ac5 100644 --- a/application/controllers/api/frontend/v1/organisation/Studiensemester.php +++ b/application/controllers/api/frontend/v1/organisation/Studiensemester.php @@ -26,7 +26,9 @@ class Studiensemester extends FHCAPI_Controller 'getAll' => self::PERM_LOGGED, 'getAktNext' => self::PERM_LOGGED, 'getStudienjahrByStudiensemester' => self::PERM_LOGGED, - 'getAllStudiensemesterAndAktOrNext' => self::PERM_LOGGED + 'getAllStudiensemesterAndAktOrNext' => self::PERM_LOGGED, + 'current' => self::PERM_LOGGED, + 'set' => self::PERM_LOGGED ) ); // Load model StudiensemesterModel @@ -166,4 +168,39 @@ class Studiensemester extends FHCAPI_Controller $this->terminateWithSuccess(array($studiensemester, $aktuell)); } + + public function current() + { + $result = $this->StudiensemesterModel->getNearest(); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + $this->terminateWithError('Kein Studiensemester aktiv'); + if (count($data) > 1) + $this->terminateWithError('Mehrere Studiensemester aktiv'); + + $this->terminateWithSuccess(current($data)->studiensemester_kurzbz); + } + + public function set() + { + $this->load->library('AuthLib'); + $this->load->library('form_validation'); + + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $stdsem = $this->input->post('studiensemester_kurzbz'); + + $this->load->model('system/Variable_model', 'VariableModel'); + + $result = $this->VariableModel->setVariable(getAuthUID(), 'semester_aktuell', $stdsem); + + $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(true); + } } diff --git a/application/controllers/api/frontend/v1/stv/Students.php b/application/controllers/api/frontend/v1/stv/Students.php index e77e20889..e97d81571 100644 --- a/application/controllers/api/frontend/v1/stv/Students.php +++ b/application/controllers/api/frontend/v1/stv/Students.php @@ -247,47 +247,54 @@ class Students extends FHCAPI_Controller } public function getPrestudents( - $studiengang_kz, + $studiengang_typ_kurzbz, $studiensemester_kurzbz = null, $filter = null ) { $this->addMeta('ci_method', __FUNCTION__); $this->addMeta('ci_params', array( - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'studiensemester_kurzbz' => $studiensemester_kurzbz, 'filter' => $filter )); - $this->fetchPrestudents($studiengang_kz, $studiensemester_kurzbz, $filter); + $this->fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz, $filter); } public function getPrestudentsOrgform( - $studiengang_kz, + $studiengang_typ_kurzbz, $orgform_kurzbz, $studiensemester_kurzbz = null, $filter = null ) { $this->addMeta('ci_method', __FUNCTION__); $this->addMeta('ci_params', array( - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'studiensemester_kurzbz' => $studiensemester_kurzbz, 'filter' => $filter, 'orgform_kurzbz' => $orgform_kurzbz )); - $this->fetchPrestudents($studiengang_kz, $studiensemester_kurzbz, $filter, $orgform_kurzbz); + $this->fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz, $filter, $orgform_kurzbz); } /** - * @param integer $studiengang_kz + * @param string $studiengang_typ_kurzbz * @param string $studiensemester_kurzbz (optional) * @param string $filter (optional) * @param string $orgform_kurzbz (optional) * * @return void */ - protected function fetchPrestudents($studiengang_kz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null) + protected function fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null) { + $studiengang_kz = $this->getStudiengangKz($studiengang_typ_kurzbz); + $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); + $orgform_kurzbz = $this->getOrgformKurzbz($orgform_kurzbz); + + if ($studiengang_kz === null) + show_404(); + $stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL'; $selectRT = " @@ -453,7 +460,7 @@ class Students extends FHCAPI_Controller public function getStudents( $studiensemester_kurzbz, - $studiengang_kz, + $studiengang_typ_kurzbz, $semester = null, $verband = null, $gruppe = null @@ -461,18 +468,18 @@ class Students extends FHCAPI_Controller $this->addMeta('ci_method', __FUNCTION__); $this->addMeta('ci_params', array( 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'semester' => $semester, 'verband' => $verband, 'gruppe' => $gruppe )); - $this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, $verband, $gruppe, null, null); + $this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, $verband, $gruppe, null, null); } public function getStudentsOrgform( $studiensemester_kurzbz, - $studiengang_kz, + $studiengang_typ_kurzbz, $orgform_kurzbz, $semester = null, $verband = null, @@ -481,37 +488,37 @@ class Students extends FHCAPI_Controller $this->addMeta('ci_method', __FUNCTION__); $this->addMeta('ci_params', array( 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'orgform_kurzbz' => $orgform_kurzbz, 'semester' => $semester, 'verband' => $verband, 'gruppe' => $gruppe )); - $this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, $verband, $gruppe, null, $orgform_kurzbz); + $this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, $verband, $gruppe, null, $orgform_kurzbz); } public function getStudentsSpezialgruppe( $studiensemester_kurzbz, - $studiengang_kz, + $studiengang_typ_kurzbz, $semester, $gruppe_kurzbz ) { $this->addMeta('ci_method', __FUNCTION__); $this->addMeta('ci_params', array( 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'semester' => $semester, 'gruppe_kurzbz' => $gruppe_kurzbz )); - $this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, null, null, $gruppe_kurzbz, null); + $this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, null, null, $gruppe_kurzbz, null); } public function getStudentsOrgformSpezialgruppe( $studiensemester_kurzbz, $orgform_kurzbz, - $studiengang_kz, + $studiengang_typ_kurzbz, $semester, $gruppe_kurzbz ) { @@ -519,17 +526,17 @@ class Students extends FHCAPI_Controller $this->addMeta('ci_params', array( 'studiensemester_kurzbz' => $studiensemester_kurzbz, 'orgform_kurzbz' => $orgform_kurzbz, - 'studiengang_kz' => $studiengang_kz, + 'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz, 'semester' => $semester, 'gruppe_kurzbz' => $gruppe_kurzbz )); - $this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, null, null, $gruppe_kurzbz, $orgform_kurzbz); + $this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, null, null, $gruppe_kurzbz, $orgform_kurzbz); } /** - * @param integer $studiengang_kz * @param string $studiensemester_kurzbz + * @param string $studiengang_typ_kurzbz * @param integer $semester (optional) * @param string $verband (optional) * @param integer $gruppe (optional) @@ -540,13 +547,20 @@ class Students extends FHCAPI_Controller */ protected function fetchStudents( $studiensemester_kurzbz, - $studiengang_kz, + $studiengang_typ_kurzbz, $semester = null, $verband = null, $gruppe = null, $gruppe_kurzbz = null, $orgform_kurzbz = null ) { + $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); + $studiengang_kz = $this->getStudiengangKz($studiengang_typ_kurzbz); + $orgform_kurzbz = $this->getOrgformKurzbz($orgform_kurzbz); + + if ($studiengang_kz === null) + show_404(); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) @@ -626,6 +640,8 @@ class Students extends FHCAPI_Controller 'prestudent_id' => $prestudent_id, )); + $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) @@ -670,6 +686,8 @@ class Students extends FHCAPI_Controller 'student_uid' => $student_uid, )); + $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) @@ -704,6 +722,8 @@ class Students extends FHCAPI_Controller 'person_id' => $person_id, )); + $studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz)) @@ -818,4 +838,55 @@ class Students extends FHCAPI_Controller } } } + + protected function getStudiengangKz($studiengang_typ_kurzbz) + { + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $result = $this->StudiengangModel->loadWhere([ + 'LOWER(CONCAT(typ, kurzbz)) =' => strtolower($studiengang_typ_kurzbz) + ]); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + return null; + + return current($data)->studiengang_kz; + } + + protected function getStudiensemesterKurzbz($studiensemester_kurzbz) + { + if ($studiensemester_kurzbz === null) + return null; + + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $result = $this->StudiensemesterModel->loadWhere([ + 'LOWER(studiensemester_kurzbz) =' => strtolower($studiensemester_kurzbz) + ]); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + return $studiensemester_kurzbz; + + return current($data)->studiensemester_kurzbz; + } + + protected function getOrgformKurzbz($orgform_kurzbz) + { + if ($orgform_kurzbz === null) + return null; + + $this->load->model('codex/Orgform_model', 'OrgformModel'); + $result = $this->OrgformModel->loadWhere([ + 'LOWER(orgform_kurzbz) =' => strtolower($orgform_kurzbz) + ]); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + return $orgform_kurzbz; + + return current($data)->orgform_kurzbz; + } } diff --git a/application/controllers/api/frontend/v1/stv/Verband.php b/application/controllers/api/frontend/v1/stv/Verband.php deleted file mode 100644 index 32ef30a45..000000000 --- a/application/controllers/api/frontend/v1/stv/Verband.php +++ /dev/null @@ -1,513 +0,0 @@ -. - */ - -if (! defined('BASEPATH')) exit('No direct script access allowed'); - -/** - * This controller operates between (interface) the JS (GUI) and the back-end - * Provides data to the ajax get calls about verbände - * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON - */ -class Verband extends FHCAPI_Controller -{ - public function __construct() - { - $permissions = []; - $router = load_class('Router'); - $permissions[$router->method] = ['admin:r', 'assistenz:r']; - parent::__construct($permissions); - - // Load Models - $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); - } - - /** - * Remap calls: - * / - * /(studiengang_kz) => getStudiengang - * /(studiengang_kz)/(semester) => getSemester - * /(studiengang_kz)/(semester)/(verband) => getVerband - * /(studiengang_kz)/(org_form) => getStudiengang - * /(studiengang_kz)/(org_form)/(semester) => getSemester - * /(studiengang_kz)/(org_form)/(semester)/(verband) => getVerband - * - * @param string $method - * @param array $params (optional) - * - * @return void - */ - public function _remap($method, $params = []) - { - if ($method == '' || $method == 'index') - return $this->getBase(); - - // NOTE(chris): Test if access is allowed ($method is the Studiengang) - if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method) - && !$this->permissionlib->isBerechtigt('admin', 's', $method) - ) { - return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]); - } - - $count = count($params); - if (!$count) - return $this->getStudiengang($method); - - if ($count == 1) { - if (is_numeric($params[0])) - return $this->getSemester($method, $params[0]); - elseif ($params[0] == 'prestudent') - return $this->terminateWithSuccess($this->getStdSem($method . '/prestudent/', $method)); - else - return $this->getStudiengang($method, $params[0]); - } - if ($count == 2) { - if (is_numeric($params[0])) - return $this->getVerband($method, $params[0], $params[1]); - elseif ($params[1] == 'prestudent') - return $this->terminateWithSuccess($this->getStdSem($method . '/' . $params[0] . '/prestudent/', $method)); - else - return $this->getSemester($method, $params[1], $params[0]); - } - if ($count == 3 && !is_numeric($params[0]) && is_numeric($params[1]) && !is_numeric($params[2])) - return $this->getVerband($method, $params[1], $params[2], $params[0]); - - show_404(); - } - - /** - * @return void - */ - protected function getBase() - { - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addDistinct(); - $this->StudiengangModel->addSelect("v.studiengang_kz AS link"); - $this->StudiengangModel->addSelect( - "CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name", - false - ); - $this->StudiengangModel->addSelect('erhalter_kz'); - $this->StudiengangModel->addSelect('typ'); - $this->StudiengangModel->addSelect('kurzbz'); - $this->StudiengangModel->addSelect('studiengang_kz'); - $this->StudiengangModel->addSelect('studiengang_kz AS stg_kz'); - - $this->StudiengangModel->addOrder('erhalter_kz'); - $this->StudiengangModel->addOrder('typ'); - $this->StudiengangModel->addOrder('kurzbz'); - - $stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: []; - $stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); - - if (!$stgs) - $this->terminateWithSuccess([]); - - $this->StudiengangModel->db->where_in('studiengang_kz', $stgs); - - $result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]); - - $list = $this->getDataOrTerminateWithError($result); - - if ($this->permissionlib->isBerechtigt('inout/uebersicht')) - $list[] = [ - 'name' => 'International', - 'link' => 'inout', - 'children' => [ - [ - 'name' => 'Incoming', - 'link' => 'inout/incoming', - 'leaf' => true - ], - [ - 'name' => 'Outgoing', - 'link' => 'inout/outgoing', - 'leaf' => true - ], - [ - 'name' => 'Gemeinsame Studien', - 'link' => 'inout/gemeinsamestudien', - 'leaf' => true - ] - ] - ]; - $this->terminateWithSuccess($list); - } - - /** - * @param integer $studiengang_kz - * @param string $orgform (optional) - * - * @return void - */ - protected function getStudiengang($studiengang_kz, $org_form = null) - { - $link = $studiengang_kz . '/'; - if ($org_form !== null) - $link .= $org_form . '/'; - - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addDistinct(); - $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false); - $this->StudiengangModel->addSelect("CONCAT( - UPPER(CONCAT(typ, kurzbz)), - '-', - semester, - ( - SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END - FROM public.tbl_lehrverband - WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester - ORDER BY verband, gruppe LIMIT 1 - ) - ) AS name", false); - - $this->StudiengangModel->addSelect('semester'); - $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); - - $this->StudiengangModel->addOrder('semester'); - - if ($org_form !== null) { - $this->StudiengangModel->addSelect("v.orgform_kurzbz"); - $this->StudiengangModel->db->group_start(); - $this->StudiengangModel->db->where('v.semester', 0); - $this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form); - $this->StudiengangModel->db->group_end(); - } - - $result = $this->StudiengangModel->loadWhere([ - 'v.studiengang_kz' => $studiengang_kz, - 'v.aktiv' => true - ]); - $list = $this->getDataOrTerminateWithError($result); - - array_unshift($list, [ - 'name' => 'PreStudent', - 'link' => $link . 'prestudent', - 'no_sem_reload' => true, - 'stg_kz' => (int)$studiengang_kz, - 'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz) - ]); - - if ($org_form === null) { - // NOTE(chris): if mischform show orgforms - $result = $this->StudiengangModel->load($studiengang_kz); - $result = $this->getDataOrTerminateWithError($result); - if ($result) { - if (current($result)->mischform) { - $this->load->model('organisation/Studienordnung_model', 'StudienordnungModel'); - - $this->StudienordnungModel->addDistinct(); - $this->StudienordnungModel->addSelect("CONCAT(studiengang_kz, '/', p.orgform_kurzbz) AS link"); - $this->StudienordnungModel->addSelect("p.orgform_kurzbz AS name"); - $this->StudienordnungModel->addSelect("studiengang_kz AS stg_kz"); - - $this->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id'); - - $result = $this->StudienordnungModel->loadWhere([ - 'aktiv' => true, - 'studiengang_kz' => $studiengang_kz, - 'p.orgform_kurzbz !=' => 'DDP' - ]); - $result = $this->getDataOrTerminateWithError($result); - - $list = array_merge($list, $result); - } - } - } - $this->terminateWithSuccess($list); - } - - /** - * @param integer $studiengang_kz - * @param integer $semester - * @param string $orgform - * - * @return void - */ - protected function getSemester($studiengang_kz, $semester, $org_form = null) - { - $link = $studiengang_kz . '/'; - if ($org_form !== null) - $link .= $org_form . '/'; - $link .= $semester . '/'; - - - $this->load->model('organisation/Gruppe_model', 'GruppeModel'); - - $this->GruppeModel->addDistinct(); - $this->GruppeModel->addSelect("CONCAT(" . $this->GruppeModel->escape($link . 'grp/') . ", gruppe_kurzbz) AS link", false); - $this->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false); - $this->GruppeModel->addSelect("TRUE AS leaf", false); - - $this->GruppeModel->addSelect('sort'); - $this->GruppeModel->addSelect('gruppe_kurzbz'); - $this->GruppeModel->addSelect($this->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false); - - $this->GruppeModel->addOrder('sort'); - $this->GruppeModel->addOrder('gruppe_kurzbz'); - - $where = [ - 'studiengang_kz' => $studiengang_kz, - 'semester' => $semester, - 'lehre' => true, - 'sichtbar' => true, - 'aktiv' => true, - 'direktinskription' => false - ]; - - if ($org_form !== null) - $where['orgform_kurzbz'] = $org_form; - - $result = $this->GruppeModel->loadWhere($where); - - $list = $this->getDataOrTerminateWithError($result); - - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", verband) AS link", false); - $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband ORDER BY gruppe LIMIT 1)) AS name", false); - $this->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf"); - - $this->StudiengangModel->addSelect($this->StudiengangModel->escape($semester) . ' AS semester'); - $this->StudiengangModel->addSelect('verband'); - $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); - - $this->StudiengangModel->addOrder('verband'); - - $this->StudiengangModel->addGroupBy('link, name, verband'); - - $where = [ - 'v.studiengang_kz' => $studiengang_kz, - 'v.semester' => $semester, - 'v.verband !=' => '', - 'v.aktiv' => true - ]; - - if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all? - $where['v.orgform_kurzbz'] = $org_form; - - $result = $this->StudiengangModel->loadWhere($where); - $result = $this->getDataOrTerminateWithError($result); - - $list = array_merge($list, $result); - - $this->terminateWithSuccess($list); - } - - /** - * @param integer $studiengang_kz - * @param integer $semester - * @param integer $verband - * @param string $orgform - * - * @return void - */ - protected function getVerband($studiengang_kz, $semester, $verband, $org_form = null) - { - $link = $studiengang_kz . '/'; - if ($org_form !== null) - $link .= $org_form . '/'; - $link .= $semester . '/'. $verband . '/'; - - - $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); - - $this->StudiengangModel->addDistinct(); - $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", gruppe) AS link", false); - $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, gruppe, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband AND gruppe=v.gruppe ORDER BY gruppe LIMIT 1)) AS name", false); - $this->StudiengangModel->addSelect("TRUE AS leaf", false); - - $this->StudiengangModel->addSelect('v.semester'); - $this->StudiengangModel->addSelect('v.verband'); - $this->StudiengangModel->addSelect('gruppe'); - $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); - - $this->StudiengangModel->addOrder('gruppe'); - - $where = [ - 'v.studiengang_kz' => $studiengang_kz, - 'v.semester' => $semester, - 'v.verband' => $verband, - 'v.gruppe !=' => '', - 'v.aktiv' => true - ]; - - if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all? - $where['v.orgform_kurzbz'] = $org_form; - - $result = $this->StudiengangModel->loadWhere($where); - - $list = $this->getDataOrTerminateWithError($result); - - $this->terminateWithSuccess($list); - } - - /** - * @param string $link - * @param integer $studiengang_kz - * - * @return array - */ - protected function getStdSem($link, $studiengang_kz) - { - $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - - $this->load->model('system/Variable_model', 'VariableModel'); - $result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']); - $data = $this->getDataOrTerminateWithError($result); - - $this->load->config('stv'); - $number_displayed_past_studiensemester_default = $this->config->item('number_displayed_past_studiensemester_default'); - - $number_displayed_past_studiensemester = $data['number_displayed_past_studiensemester'] ?? $number_displayed_past_studiensemester_default; - - $this->StudiensemesterModel->addPlusMinus(null, $number_displayed_past_studiensemester); - $this->StudiensemesterModel->addOrder('ende'); - $result = $this->StudiensemesterModel->load(); - - $studiensemester = $this->getDataOrTerminateWithError($result); - $result = []; - - $studiengang_kz = (int)$studiengang_kz; - - foreach ($studiensemester as $sem) { - $semlink = $link . $sem->studiensemester_kurzbz; - $intlink = $semlink . '/interessenten'; - $result[] = [ - 'name' => $sem->studiensemester_kurzbz, - 'link' => $semlink, - 'stg_kz' => $studiengang_kz, - 'children' => [ - [ - 'name' => 'Interessenten', - 'link' => $intlink, - 'stg_kz' => $studiengang_kz, - 'children' => [ - [ - 'name' => 'Bewerbung nicht abgeschickt', - 'link' => $intlink . '/bewerbungnichtabgeschickt', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Bewerbung abgeschickt, Status unbestätigt', - 'link' => $intlink . '/bewerbungabgeschickt', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'ZGV erfüllt', - 'link' => $intlink . '/zgv', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Status bestätigt', - 'link' => $intlink . '/statusbestaetigt', - 'stg_kz' => $studiengang_kz, - 'children' => [ - [ - 'name' => 'Nicht zum Reihungstest angemeldet', - 'link' => $intlink . '/statusbestaetigtrtnichtangemeldet', - 'leaf' => true - ], - [ - 'name' => 'Reihungstest angemeldet', - 'link' => $intlink . '/statusbestaetigtrtangemeldet', - 'leaf' => true - ] - ] - ], - [ - 'name' => 'Nicht zum Reihungstest angemeldet', - 'link' => $intlink . '/reihungstestnichtangemeldet', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Reihungstest angemeldet', - 'link' => $intlink . '/reihungstestangemeldet', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ] - ] - ], - [ - 'name' => 'Bewerber', - 'link' => $semlink . '/bewerber', - 'stg_kz' => $studiengang_kz, - 'children' => [ - [ - 'name' => 'Nicht zum Reihungstest angemeldet', - 'link' => $intlink . '/bewerberrtnichtangemeldet', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Reihungstest angemeldet', - 'link' => $intlink . '/bewerberrtangemeldet', - 'stg_kz' => $studiengang_kz, - 'children' => [ - [ - 'name' => 'Teilgenommen', - 'link' => $intlink . '/bewerberrtangemeldetteilgenommen', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Nicht teilgenommen', - 'link' => $intlink . '/bewerberrtangemeldetnichtteilgenommen', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ] - ] - ] - ] - ], - [ - 'name' => 'Aufgenommen', - 'link' => $semlink . '/aufgenommen', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Warteliste', - 'link' => $semlink . '/warteliste', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Absage', - 'link' => $semlink . '/absage', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ], - [ - 'name' => 'Incoming', - 'link' => $semlink . '/incoming', - 'stg_kz' => $studiengang_kz, - 'leaf' => true - ] - ] - ]; - } - - return $result; - } -} diff --git a/application/controllers/components/stv/Studiensemester.php b/application/controllers/components/stv/Studiensemester.php deleted file mode 100644 index c3db99686..000000000 --- a/application/controllers/components/stv/Studiensemester.php +++ /dev/null @@ -1,78 +0,0 @@ - self::PERM_LOGGED, - 'now' => self::PERM_LOGGED, - 'set' => self::PERM_LOGGED - ]); - } - - public function index() - { - $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - - $this->StudiensemesterModel->addOrder('start'); - - $result = $this->StudiensemesterModel->load(); - - if (isError($result)) { - $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); - } - $this->outputJson($result); - } - - public function now() - { - $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - - $result = $this->StudiensemesterModel->getNearest(); - - if (isError($result)) { - $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); - $this->outputJson(getError($result)); - } - $result = getData($result) ?: []; - - if (count($result) != 1) { - $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); - $this->outputJsonError(count($result) ? 'Mehrere Studiensemester aktiv' : 'Kein Studiensemester aktiv'); - } else { - $this->outputJsonSuccess(current($result)->studiensemester_kurzbz); - } - } - - public function set() - { - $this->load->library('AuthLib'); - $this->load->library('form_validation'); - - $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); - - $this->form_validation->set_rules('studiensemester', 'Studiensemester', 'required'); - - if ($this->form_validation->run() == false) { - $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); - return $this->outputJsonError($this->form_validation->error_array()); - } - - $stdsem = $this->input->post('studiensemester'); - - $this->load->model('system/Variable_model', 'VariableModel'); - - $result = $this->VariableModel->setVariable(getAuthUID(), 'semester_aktuell', $stdsem); - - if (isError($result)) { - $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); - return $this->outputJson($result); - } - - $this->outputJsonSuccess(true); - } -} diff --git a/application/controllers/js/Tabulatorcolumns.php b/application/controllers/js/Tabulatorcolumns.php new file mode 100644 index 000000000..1a4621219 --- /dev/null +++ b/application/controllers/js/Tabulatorcolumns.php @@ -0,0 +1,60 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller generates javascript from snippets for tabulator columns + */ +class Tabulatorcolumns extends Auth_Controller +{ + public function __construct() + { + parent::__construct([ + 'stv' => ['admin:r', 'assistenz:r'], + 'lvverwaltung' => ['admin:r', 'assistenz:r'] + ]); + } + + /** + * Render tabulator columns for config + * + * @param string $config + * + * @return void + */ + public function _remap($config) + { + $this->load->config($config); + $list_columns = $this->config->item('list_columns') ?: []; + + $snippets = [ + 'jssnippets/tabulatorcolumns/' . $config . '.js' + ]; + + foreach ($list_columns as $col) { + $snippets[] = $col['js']; + } + + $this->output->set_content_type('application/javascript'); + + $this->load->view('jssnippets/tabulatorcolumns.js', [ + 'snippets' => $snippets + ]); + } +} diff --git a/application/libraries/stv/StudentListLib.php b/application/libraries/stv/StudentListLib.php index 432b75bd4..a506af3d1 100644 --- a/application/libraries/stv/StudentListLib.php +++ b/application/libraries/stv/StudentListLib.php @@ -28,6 +28,7 @@ class StudentListLib private $_allowedStgs = []; private $_selects = []; private $_joins = []; + private $_wheres = []; /** * Gets the CI instance, loads model and prepares default values @@ -40,6 +41,8 @@ class StudentListLib { $this->_ci =& get_instance(); // get code igniter instance + $this->_ci->load->config('stv'); + $this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel'); if (isset($params['allowedStgs'])) @@ -116,7 +119,7 @@ class StudentListLib ) prest WHERE laststatus NOT IN ('Abbrecher', 'Abgewiesener', 'Absolvent') AND priorisierung <= tbl_prestudent.priorisierung - ) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false); // TODO(chris): overwrite in fetchStudents + ) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false); $this->addSelect('mentor'); $this->addSelect('b.aktiv AS bnaktiv'); $this->addSelect('unruly'); @@ -124,7 +127,7 @@ class StudentListLib // Add default JOINs $this->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); $this->addJoin('public.tbl_person p', 'person_id'); - $this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); // TODO(chris): overwrite in fetchStudents + $this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); $this->addJoin('public.tbl_prestudentstatus pls', ' pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) AND pls.prestudent_id=tbl_prestudent.prestudent_id @@ -134,6 +137,15 @@ class StudentListLib $this->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT'); $this->addJoin("v", "", ""); // Will be replaced later $this->addJoin("ps", "", ""); // Will be replaced later + + // Add SELECTs and JOINs from config + $config = $this->_ci->config->item('list_columns') ?: []; + foreach ($config as $conf) { + $this->addSelect($conf['default']); + if (isset($conf['joins'])) + foreach ($conf['joins'] as $join) + call_user_func_array([$this, 'addJoin'], $join); + } } //------------------------------------------------------------------------------------------------------------------ @@ -219,11 +231,7 @@ class StudentListLib */ public function addWhere($key, $value = null, $escape = true) { - if (!is_array($key) && is_array($value)) { - $this->_ci->PrestudentModel->db->where_in($key, $value, $escape); - } else { - $this->_ci->PrestudentModel->db->where($key, $value, $escape); - } + $this->_wheres[] = [$key, $value, $escape, false]; } /** @@ -237,11 +245,7 @@ class StudentListLib */ public function addOrWhere($key, $value = null, $escape = true) { - if (!is_array($key) && is_array($value)) { - $this->_ci->PrestudentModel->db->or_where_in($key, $value, $escape); - } else { - $this->_ci->PrestudentModel->db->or_where($key, $value, $escape); - } + $this->_wheres[] = [$key, $value, $escape, true]; } /** @@ -286,6 +290,20 @@ class StudentListLib foreach ($this->_selects as $select) $this->_ci->PrestudentModel->addSelect($select[0], $select[1]); + foreach ($this->_wheres as $where) { + if (!is_array($where[0]) && is_array($where[1])) { + if ($where[3]) + $this->_ci->PrestudentModel->db->or_where_in($where[0], $where[1], $where[2]); + else + $this->_ci->PrestudentModel->db->where_in($where[0], $where[1], $where[2]); + } else { + if ($where[3]) + $this->_ci->PrestudentModel->db->or_where($where[0], $where[1], $where[2]); + else + $this->_ci->PrestudentModel->db->where($where[0], $where[1], $where[2]); + } + } + $this->_ci->PrestudentModel->addOrder('nachname'); $this->_ci->PrestudentModel->addOrder('vorname'); diff --git a/application/libraries/treemenu/LvVwLib.php b/application/libraries/treemenu/LvVwLib.php new file mode 100644 index 000000000..d3c91a196 --- /dev/null +++ b/application/libraries/treemenu/LvVwLib.php @@ -0,0 +1,192 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * LvVw Menu library + */ +class LvVwLib +{ + protected $_ci = null; + + public $config = []; + + public function __construct() + { + // Get code igniter instance + $this->_ci =& get_instance(); + + // Load Tree-config + $this->_ci->load->config('treemenu/custom/lvvw'); + $this->config = $this->_ci->config->item('root'); + + // Load Libraries + $this->_ci->load->library('treemenu/base/StgLib'); + + // Load Model + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + } + + public function stg($path_template) + { + $permittedStgs = $this->getPermittedStudiengangKzs(); + + if (!$permittedStgs) + return []; + + $this->_ci->StudiengangModel->addSelect("ARRAY['link', FORMAT('{" . + '"type": "verband",' . + '"id": "lv/%1$s",' . + '"gruppe_kurzbz": null,' . + '"semester": null,' . + '"verband": null,' . + '"gruppe": null,' . + '"lehrverband": true,' . + '"stg_kz": "%1$s"' . + "}', studiengang_kz)] AS draggable", false); + + return $this->_ci->stglib->studiengang($path_template, $permittedStgs); + } + + public function semester($path_template, $has_children, $stg) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if (!$has_children) + $this->_ci->StudiengangModel->db->select('TRUE AS leaf', false); + $this->_ci->StudiengangModel->addSelect("ARRAY['link', FORMAT('{" . + '"type": "verband",' . + '"id": "lv/%1$s/%2$s",' . + '"gruppe_kurzbz": null,' . + '"semester": "%2$s",' . + '"verband": null,' . + '"gruppe": null,' . + '"lehrverband": true,' . + '"stg_kz": "%1$s"' . + "}', v.studiengang_kz, v.semester)] AS draggable", false); + + return $this->_ci->stglib->semester($path_template, $stg->studiengang_kz); + } + + public function verband($path_template, $stg, $semester) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + $this->_ci->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf"); + $this->_ci->StudiengangModel->addSelect("ARRAY['link', FORMAT('{" . + '"type": "verband",' . + '"id": "lv/%1$s/%2$s/%3$s",' . + '"gruppe_kurzbz": null,' . + '"semester": "%2$s",' . + '"verband": "%3$s",' . + '"gruppe": null,' . + '"lehrverband": true,' . + '"stg_kz": "%1$s"' . + "}', v.studiengang_kz, v.semester, v.verband)] AS draggable", false); + $this->_ci->StudiengangModel->addGroupBy('v.studiengang_kz, v.semester'); + + return $this->_ci->stglib->verband($path_template, $stg->studiengang_kz, $semester); + } + + public function group($path_template, $stg, $semester, $verband) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + $this->_ci->StudiengangModel->db->select('TRUE AS leaf', false); + + if ($verband === null) { + $this->_ci->StudiengangModel->addSelect("ARRAY['link', FORMAT('{" . + '"type": "verband",' . + '"id": "grp/%1$s/%2$s/%3$s",' . + '"gruppe_kurzbz": "%3$s",' . + '"semester": "%2$s",' . + '"verband": null,' . + '"gruppe": null,' . + '"lehrverband": false,' . + '"stg_kz": "%1$s"' . + "}', studiengang_kz, semester, gruppe_kurzbz)] AS draggable", false); + + return $this->_ci->stglib->group($path_template, $stg->studiengang_kz, $semester); + } + + $this->_ci->StudiengangModel->addSelect("ARRAY['link', FORMAT('{" . + '"type": "verband",' . + '"id": "lv/%1$s/%2$s/%3$s/%4$s",' . + '"gruppe_kurzbz": null,' . + '"semester": "%2$s",' . + '"verband": "%3$s",' . + '"gruppe": "%4$s",' . + '"lehrverband": true,' . + '"stg_kz": "%1$s"' . + "}', v.studiengang_kz, v.semester, v.verband, v.gruppe)] AS draggable", false); + + return $this->_ci->stglib->verbandsgroup($path_template, $stg->studiengang_kz, $semester, $verband); + } + + public function orgform($path_template, $stg) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if (!$stg->mischform) + return []; + + $this->_ci->StudiengangModel->db->select('TRUE AS leaf', false); + + return $this->_ci->stglib->orgform($path_template, $stg->studiengang_kz); + } + + protected function getPermittedStudiengangKzs() + { + $permittedStgs = $this->_ci->permissionlib->getSTG_isEntitledFor('admin') ?: []; + $permittedStgs = array_merge($permittedStgs, $this->_ci->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); + + return $permittedStgs; + } + + protected function getStgFromUrl($stg) + { + $permittedStgs = $this->getPermittedStudiengangKzs(); + + if (!$permittedStgs) + return null; + + $this->_ci->StudiengangModel->db->where_in('studiengang_kz', $permittedStgs); + $stg = $this->_ci->StudiengangModel->loadWhere([ + 'LOWER(CONCAT(typ, kurzbz)) =' => $stg + ]); + + if (!hasData($stg)) + return null; + + return current(getData($stg)); + } +} diff --git a/application/libraries/treemenu/StudVwLib.php b/application/libraries/treemenu/StudVwLib.php new file mode 100644 index 000000000..ee3e2cbdc --- /dev/null +++ b/application/libraries/treemenu/StudVwLib.php @@ -0,0 +1,257 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * StudVw Menu library + */ +class StudVwLib +{ + protected $_ci = null; + + public $config = []; + + public $redirect_method = [ + 'interessenten' => 'filter', + 'bewerbungnichtabgeschickt' => 'filter', + 'bewerbungabgeschickt' => 'filter', + 'zgv' => 'filter', + 'statusbestaetigt' => 'filter', + 'statusbestaetigtrtnichtangemeldet' => 'filter', + 'statusbestaetigtrtangemeldet' => 'filter', + 'reihungstestnichtangemeldet' => 'filter', + 'reihungstestangemeldet' => 'filter', + 'bewerber' => 'filter', + 'bewerberrtnichtangemeldet' => 'filter', + 'bewerberrtangemeldet' => 'filter', + 'bewerberrtangemeldetteilgenommen' => 'filter', + 'bewerberrtangemeldetnichtteilgenommen' => 'filter', + 'aufgenommen' => 'filter', + 'warteliste' => 'filter', + 'absage' => 'filter', + 'outgoing' => 'inout', + 'shared_studies' => 'inout' + ]; + + public function __construct() + { + // Get code igniter instance + $this->_ci =& get_instance(); + + // Load Tree-config + $this->_ci->load->config('treemenu/stg_base'); + $this->config = $this->_ci->config->item('root'); + + // Load Libraries + $this->_ci->load->library('treemenu/base/StgLib'); + + // Load Model + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + } + + public function stg($path_template) + { + $permittedStgs = $this->getPermittedStudiengangKzs(); + + if (!$permittedStgs) + return []; + + return $this->_ci->stglib->studiengang($path_template, $permittedStgs); + } + + public function prestudent($path_template, $stg) + { + // Check permission + if ($this->getStgFromUrl($stg) === null) + return []; + + return [ + [ + 'path' => sprintf($path_template, '1'), + 'name' => ['lehre', 'prestudent'], + 'no_sem_reload' => true + ] + ]; + } + + public function stdsem($path_template, $stg) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + return $this->_ci->stglib->studiensemester($path_template, $stg->studiengang_kz); + } + + public function semester($path_template, $stg, $orgform) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if ($orgform !== null) { + $orgform = $this->getOrgform($orgform); + if ($orgform === null) + return []; + $orgform = $orgform->orgform_kurzbz; + } + + return $this->_ci->stglib->semester($path_template, $stg->studiengang_kz, $orgform); + } + + public function verband($path_template, $stg, $semester, $orgform) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if ($orgform !== null) { + $orgform = $this->getOrgform($orgform); + if ($orgform === null) + return []; + $orgform = $orgform->orgform_kurzbz; + } + + $this->_ci->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf"); + + return $this->_ci->stglib->verband($path_template, $stg->studiengang_kz, $semester, $orgform); + } + + public function group($path_template, $stg, $semester, $verband, $orgform) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if ($orgform !== null) { + $orgform = $this->getOrgform($orgform); + if ($orgform === null) + return []; + $orgform = $orgform->orgform_kurzbz; + } + + $this->_ci->StudiengangModel->db->select('TRUE AS leaf', false); + + if ($verband === null) + return $this->_ci->stglib->group($path_template, $stg->studiengang_kz, $semester, $orgform); + + return $this->_ci->stglib->verbandsgroup($path_template, $stg->studiengang_kz, $semester, $verband, $orgform); + } + + public function orgform($path_template, $stg) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + if (!$stg->mischform) + return []; + + return $this->_ci->stglib->orgform($path_template, $stg->studiengang_kz); + } + + public function incoming($has_children, $path_template, $stg) + { + if ($stg === null) + return $this->inout('incoming', $has_children, $path_template); + + return $this->filter('incoming', $has_children, $path_template, $stg); + } + + public function filter($original_method, $has_children, $path_template, $stg) + { + $stg = $this->getStgFromUrl($stg); + + if ($stg === null) + return []; + + // TODO(chris): phrasen + $item = [ + 'path' => sprintf($path_template, '1'), + 'name' => ['treemenu', 'filter_' . $original_method] + ]; + + if (!$has_children) + $item['leaf'] = true; + + return [ $item ]; + } + + public function inout($original_method, $has_children, $path_template) + { + if (!$this->_ci->permissionlib->isBerechtigt('inout/uebersicht')) + return []; + + // TODO(chris): phrasen + $item = [ + 'path' => sprintf($path_template, '1'), + 'name' => ['treemenu', 'inout_' . $original_method] + ]; + + if (!$has_children) + $item['leaf'] = true; + + return [ $item ]; + } + + protected function getOrgform($orgform) + { + $this->_ci->load->model('codex/Orgform_model', 'OrgformModel'); + $orgform = $this->_ci->OrgformModel->loadWhere([ + 'LOWER(orgform_kurzbz) =' => $orgform + ]); + + if (!hasData($orgform)) + return null; + + return current(getData($orgform)); + } + + protected function getPermittedStudiengangKzs() + { + $permittedStgs = $this->_ci->permissionlib->getSTG_isEntitledFor('admin') ?: []; + $permittedStgs = array_merge($permittedStgs, $this->_ci->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); + + return $permittedStgs; + } + + protected function getStgFromUrl($stg) + { + $permittedStgs = $this->getPermittedStudiengangKzs(); + + if (!$permittedStgs) + return null; + + $this->_ci->StudiengangModel->db->where_in('studiengang_kz', $permittedStgs); + $stg = $this->_ci->StudiengangModel->loadWhere([ + 'LOWER(CONCAT(typ, kurzbz)) =' => $stg + ]); + + if (!hasData($stg)) + return null; + + return current(getData($stg)); + } +} diff --git a/application/libraries/treemenu/base/StgLib.php b/application/libraries/treemenu/base/StgLib.php new file mode 100644 index 000000000..84665639d --- /dev/null +++ b/application/libraries/treemenu/base/StgLib.php @@ -0,0 +1,313 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * Stg Base library + */ +class StgLib +{ + protected $_ci = null; + + public function __construct() + { + // Get code igniter instance + $this->_ci =& get_instance(); + } + + public function studiengang($path_template, $permittedStgs = []) + { + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $this->_ci->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->_ci->StudiengangModel->addDistinct(); + $this->_ci->StudiengangModel->addSelect("FORMAT(" . $this->_ci->StudiengangModel->escape($path_template) . ", LOWER(CONCAT(typ, kurzbz))) AS path"); + $this->_ci->StudiengangModel->addSelect( + "CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name", + false + ); + $this->_ci->StudiengangModel->addSelect("studiengang_kz AS title"); + $this->_ci->StudiengangModel->addSelect("studiengang_kz AS search"); + $this->_ci->StudiengangModel->addSelect('erhalter_kz'); + $this->_ci->StudiengangModel->addSelect('typ'); + $this->_ci->StudiengangModel->addSelect('kurzbz'); + $this->_ci->StudiengangModel->addSelect('studiengang_kz'); + $this->_ci->StudiengangModel->addSelect('studiengang_kz AS stg_kz'); + + $this->_ci->StudiengangModel->addOrder('erhalter_kz'); + $this->_ci->StudiengangModel->addOrder('typ'); + $this->_ci->StudiengangModel->addOrder('kurzbz'); + + if ($permittedStgs) + $this->_ci->StudiengangModel->db->where_in('studiengang_kz', $permittedStgs); + + $result = $this->_ci->StudiengangModel->loadWhere(['v.aktiv' => true]); + + return getData($result) ?: []; + } + + public function semester($path_template, $studiengang_kz, $orgform_kurzbz = null) + { + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $this->_ci->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->_ci->StudiengangModel->addDistinct(); + $this->_ci->StudiengangModel->addSelect("FORMAT(" . $this->_ci->StudiengangModel->escape($path_template) . ", semester) AS path", false); + $this->_ci->StudiengangModel->addSelect("CONCAT( + UPPER(CONCAT(typ, kurzbz)), + '-', + semester, + ( + SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END + FROM public.tbl_lehrverband + WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester + ORDER BY verband, gruppe LIMIT 1 + ) + ) AS name", false); + + $this->_ci->StudiengangModel->addSelect('semester'); + $this->_ci->StudiengangModel->addSelect('v.studiengang_kz AS stg_kz'); + $this->_ci->StudiengangModel->addSelect("ARRAY['link-strict', 'student-collection'] AS droplink"); + + $this->_ci->StudiengangModel->addOrder('semester'); + + if ($orgform_kurzbz !== null) { + $this->_ci->StudiengangModel->addSelect($this->_ci->StudiengangModel->escape($orgform_kurzbz) . " AS orgform_kurzbz", false); + $this->_ci->StudiengangModel->addDistinct(); + $this->_ci->StudiengangModel->db->group_start(); + $this->_ci->StudiengangModel->db->where('v.semester', 0); + $this->_ci->StudiengangModel->db->or_where('v.orgform_kurzbz', $orgform_kurzbz); + $this->_ci->StudiengangModel->db->group_end(); + } + + $result = $this->_ci->StudiengangModel->loadWhere([ + 'studiengang_kz' => $studiengang_kz, + 'v.aktiv' => true + ]); + + + return getData($result) ?: []; + } + + public function group($path_template, $studiengang_kz, $semester, $orgform_kurzbz = null) + { + $this->_ci->load->model('organisation/Gruppe_model', 'GruppeModel'); + + $this->_ci->GruppeModel->addDistinct(); + $this->_ci->GruppeModel->addSelect("FORMAT(" . $this->_ci->GruppeModel->escape($path_template) . ", gruppe_kurzbz) AS path", false); + $this->_ci->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false); + + $this->_ci->GruppeModel->addSelect('sort'); + $this->_ci->GruppeModel->addSelect('gruppe_kurzbz'); + $this->_ci->GruppeModel->addSelect($this->_ci->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + $this->_ci->GruppeModel->addSelect("ARRAY['link-strict', 'student-collection'] AS droplink"); + + $this->_ci->GruppeModel->addOrder('sort'); + $this->_ci->GruppeModel->addOrder('gruppe_kurzbz'); + + $where = [ + 'studiengang_kz' => $studiengang_kz, + 'semester' => $semester, + 'lehre' => true, + 'sichtbar' => true, + 'aktiv' => true, + 'direktinskription' => false + ]; + + if ($orgform_kurzbz !== null) + $where['orgform_kurzbz'] = $orgform_kurzbz; + + $result = $this->_ci->GruppeModel->loadWhere($where); + + return getData($result) ?: []; + } + + public function verband($path_template, $studiengang_kz, $semester, $orgform_kurzbz = null) + { + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $this->_ci->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->_ci->StudiengangModel->addSelect("FORMAT(" . $this->_ci->StudiengangModel->escape($path_template) . ", verband) AS path", false); + $this->_ci->StudiengangModel->addSelect("CONCAT( + UPPER(CONCAT(typ, kurzbz)), + '-', + semester, + verband, + ( + SELECT + CASE + WHEN bezeichnung IS NULL OR bezeichnung='' + THEN ''::TEXT + ELSE CONCAT(' (', bezeichnung, ')') + END + FROM public.tbl_lehrverband + WHERE studiengang_kz=v.studiengang_kz + AND semester=v.semester + AND verband=v.verband + ORDER BY gruppe + LIMIT 1 + ) + ) AS name", false); + + $this->_ci->StudiengangModel->addSelect($this->_ci->StudiengangModel->escape($semester) . ' AS semester'); + $this->_ci->StudiengangModel->addSelect('verband'); + $this->_ci->StudiengangModel->addSelect($this->_ci->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + $this->_ci->StudiengangModel->addSelect("ARRAY['link-strict', 'student-collection'] AS droplink"); + + $this->_ci->StudiengangModel->addOrder('verband'); + + $this->_ci->StudiengangModel->addGroupBy('path, name, verband'); + + $where = [ + 'v.studiengang_kz' => $studiengang_kz, + 'v.semester' => $semester, + 'v.verband !=' => '', + 'v.aktiv' => true + ]; + + if ($orgform_kurzbz !== null && $semester) // NOTE(chris): on semester 0 show all? + $where['v.orgform_kurzbz'] = $orgform_kurzbz; + + $result = $this->_ci->StudiengangModel->loadWhere($where); + + return getData($result) ?: []; + } + + public function verbandsgroup($path_template, $studiengang_kz, $semester, $verband, $orgform_kurzbz = null) + { + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $this->_ci->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->_ci->StudiengangModel->addDistinct(); + $this->_ci->StudiengangModel->addSelect("FORMAT( + " . $this->_ci->StudiengangModel->escape($path_template) . ", + gruppe + ) AS path", false); + $this->_ci->StudiengangModel->addSelect("CONCAT( + UPPER(CONCAT(typ, kurzbz)), + '-', + semester, + verband, + gruppe, + ( + SELECT + CASE + WHEN bezeichnung IS NULL OR bezeichnung='' + THEN ''::TEXT + ELSE CONCAT(' (', bezeichnung, ')') + END + FROM public.tbl_lehrverband + WHERE studiengang_kz=v.studiengang_kz + AND semester=v.semester + AND verband=v.verband + AND gruppe=v.gruppe + ORDER BY gruppe + LIMIT 1 + ) + ) AS name", false); + + $this->_ci->StudiengangModel->addSelect('v.semester'); + $this->_ci->StudiengangModel->addSelect('v.verband'); + $this->_ci->StudiengangModel->addSelect('gruppe'); + $this->_ci->StudiengangModel->addSelect($this->_ci->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + $this->_ci->StudiengangModel->addSelect("ARRAY['link-strict', 'student-collection'] AS droplink"); + + $this->_ci->StudiengangModel->addOrder('gruppe'); + + $where = [ + 'v.studiengang_kz' => $studiengang_kz, + 'v.semester' => $semester, + 'v.verband' => $verband, + 'v.gruppe !=' => '', + 'v.aktiv' => true + ]; + + if ($orgform_kurzbz !== null && $semester) // NOTE(chris): on semester 0 show all? + $where['v.orgform_kurzbz'] = $orgform_kurzbz; + + $result = $this->_ci->StudiengangModel->loadWhere($where); + + return getData($result) ?: []; + } + + public function orgform($path_template, $studiengang_kz) + { + $this->_ci->load->model('organisation/Studienordnung_model', 'StudienordnungModel'); + + $this->_ci->StudienordnungModel->addDistinct(); + $this->_ci->StudienordnungModel->addSelect("FORMAT( + " . $this->_ci->StudienordnungModel->escape($path_template) . ", + LOWER(p.orgform_kurzbz) + ) AS path"); + $this->_ci->StudienordnungModel->addSelect("p.orgform_kurzbz AS name"); + $this->_ci->StudienordnungModel->addSelect("studiengang_kz AS stg_kz"); + + $this->_ci->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id'); + + $result = $this->_ci->StudienordnungModel->loadWhere([ + 'aktiv' => true, + 'studiengang_kz' => $studiengang_kz, + 'p.orgform_kurzbz !=' => 'DDP' + ]); + + + return getData($result) ?: []; + } + + public function studiensemester($path_template, $studiengang_kz) + { + $number_displayed_past_studiensemester = null; + + $this->_ci->load->model('system/Variable_model', 'VariableModel'); + + $result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']); + if (isError($result)) + return []; + + $data = getData($result); + if ($data && isset($data['number_displayed_past_studiensemester'])) { + $number_displayed_past_studiensemester = $data['number_displayed_past_studiensemester']; + } else { + $this->_ci->load->config('stv'); + $number_displayed_past_studiensemester = $this->_ci->config->item('number_displayed_past_studiensemester_default'); + } + + $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->_ci->StudiensemesterModel->addPlusMinus(null, $number_displayed_past_studiensemester); + + $this->_ci->StudiensemesterModel->addSelect("studiensemester_kurzbz AS name"); + $this->_ci->StudiensemesterModel->addSelect("FORMAT( + " . $this->_ci->StudiensemesterModel->escape($path_template) . ", + LOWER(studiensemester_kurzbz) + ) AS path", false); + $this->_ci->StudiensemesterModel->addSelect($this->_ci->StudiensemesterModel->escape($studiengang_kz) . " AS stg_kz", false); + + $this->_ci->StudiensemesterModel->addOrder('ende'); + + $result = $this->_ci->StudiensemesterModel->load(); + + return getData($result) ?: []; + } +} diff --git a/application/views/jssnippets/tabulatorcolumns.js b/application/views/jssnippets/tabulatorcolumns.js new file mode 100644 index 000000000..44667e45b --- /dev/null +++ b/application/views/jssnippets/tabulatorcolumns.js @@ -0,0 +1,19 @@ +let result = []; +let current; + + + +current = (tabulatorcolumns => { +load->view($path); ?> +})(result); + +if (current) { + if (Array.isArray(current)) + result = result.concat(current); + else + result.push(current); +} + + + +export default result; \ No newline at end of file diff --git a/application/views/jssnippets/tabulatorcolumns/lvverwaltung.js b/application/views/jssnippets/tabulatorcolumns/lvverwaltung.js new file mode 100644 index 000000000..60d156a8a --- /dev/null +++ b/application/views/jssnippets/tabulatorcolumns/lvverwaltung.js @@ -0,0 +1,266 @@ +return [ + { + title: 'kurzbz', + titlePhrase: 'lehre/kurzbz', + field: "lv_kurzbz", + headerFilterFuncParams: { field: 'lv_kurzbz' }, + headerFilter: true, + formatter(cell, + formatterParams) { + const rowData = cell.getRow().getData(); + const iconKey = (rowData.lehrtyp_kurzbz || '').toLowerCase(); + const lvkurzbz = (cell.getValue()).toUpperCase(); + + const parentspan = document.createElement('span'); + const span = document.createElement('span'); + + span.classList.add('lv_table_icon', `icon-${iconKey}`); + span.title = iconKey || 'LV-Teil'; + + parentspan.appendChild(span); + parentspan.appendChild(document.createTextNode(` ${lvkurzbz}`)); + + return parentspan; + }, + cellClick(e, + cell) { + cell.getRow().treeToggle(); + } + }, + { + title: 'Tags', + field: 'tags', + tooltip: false, + headerFilter: "input", + headerFilterFunc: "tagHeaderFilter", + headerFilterFuncParams: { field: 'tags' }, + formatter: "tagFormatter", + width: 150, + }, + { + title: 'lehrveranstaltung_id', + titlePhrase: 'lehre/lehrveranstaltung_id', + field: "lehrveranstaltung_id", + headerFilterFuncParams: { field: 'lehrveranstaltung_id' }, + headerFilter: true, + visible: false + }, + { + title: 'bezeichnung', + titlePhrase: 'ui/bezeichnung', + field: "lv_bezeichnung", + headerFilter: true, + headerFilterFuncParams: { field: 'lv_bezeichnung' } + }, + { + title: 'bezeichnungeng', + titlePhrase: 'lehre/bezeichnungeng', + field: "lv_bezeichnung_english", + headerFilter: true, + headerFilterFuncParams: { field: 'lv_bezeichnung_english' }, + visible: false + }, + { + title: 'studiengangskennzahlLehre', + titlePhrase: 'lehre/studiengangskennzahlLehre', + field: "lv_studiengang_kz", + headerFilter: true, + headerFilterFuncParams: { field: 'lv_studiengang_kz' }, + visible: false + }, + { + title: 'studiengang', + titlePhrase: 'lehre/studiengang', + field: "studiengang", + headerFilter: true, + headerFilterFuncParams: { field: 'studiengang' }, + visible: false + }, + { + title: 'semester', + titlePhrase: 'lehre/semester', + field: "semester", + headerFilter: true, + headerFilterFuncParams: { field: 'semester' } + }, + { + title: 'sprache', + titlePhrase: 'global/sprache', + field: "sprache", + headerFilter: true, + headerFilterFuncParams: { field: 'sprache' }, + visible: false + }, + { + title: 'ects', + titlePhrase: 'lehre/ects', + field: "lv_ects", + headerFilter: true, + headerFilterFuncParams: { field: 'lv_ects' }, + visible: false + }, + { + title: 'semesterstunden', + titlePhrase: 'lehre/semesterstunden', + field: "semesterstunden", + headerFilter: true, + headerFilterFuncParams: { field: 'semesterstunden' }, + visible: false + }, + { + title: 'anmerkung', + titlePhrase: 'global/anmerkung', + field: "anmerkung", + headerFilter: true, + headerFilterFuncParams: { field: 'anmerkung' }, + visible: false + }, + { + title: 'lehre', + titlePhrase: 'lehre/lehre', + field: "lehre", + headerFilter: true, + headerFilterFuncParams: { field: 'lehre' }, + formatter: 'ja_nein', + visible: false + }, + { + title: 'aktiv', + titlePhrase: 'person/aktiv', + field: "aktiv", + headerFilter: true, + headerFilterFuncParams: { field: 'aktiv' }, + formatter: 'ja_nein', + visible: false + }, + { + title: 'organisationsform', + titlePhrase: 'lehre/organisationsform', + field: "orgform_kurzbz", + headerFilter: true, + headerFilterFuncParams: { field: 'orgform_kurzbz' } + }, + { + title: 'studienplan_id', + titlePhrase: 'ui/studienplan_id', + field: "studienplan_id", + headerFilter: true, + headerFilterFuncParams: { field: 'studienplan_id' }, + visible: false + }, + { + title: 'studienplan', + titlePhrase: 'lehre/studienplan', + field: "studienplan_bezeichnung", + headerFilter: true, + headerFilterFuncParams: { field: 'studienplan_bezeichnung' }, + visible: false + }, + { + title: 'lehrtyp', + titlePhrase: 'lehre/lehrtyp', + field: "lehrtyp_kurzbz", + headerFilter: true, + headerFilterFuncParams: { field: 'lehrtyp_kurzbz' }, + visible: false + }, + { + title: 'lehrform', + titlePhrase: 'lehre/lehrform', + field: "lehrform_kurzbz", + headerFilter: true, + headerFilterFuncParams: { field: 'lehrform_kurzbz'} }, + { + title: 'leplanstunden', + titlePhrase: 'lehre/leplanstunden', + field: "le_planstunden", + headerFilter: true, + headerFilterFuncParams: { field: 'le_planstunden' }, + visible: false + }, + { + title: 'lehreinheit_id', + titlePhrase: 'lehre/lehreinheit_id', + field: "lehreinheit_id", + headerFilter: true, + headerFilterFuncParams: { field: 'lehreinheit_id' }, + visible: false + }, + { + title: 'studiensemester', + titlePhrase: 'lehre/studiensemester', + field: "studiensemester_kurzbz", + headerFilter: true, + headerFilterFuncParams: { field: 'studiensemester_kurzbz' }, + visible: false + }, + { + title: 'unr', + titlePhrase: 'lehre/unr', + field: "unr", + headerFilter: true, + headerFilterFuncParams: { field: 'unr' }, + visible: false + }, + { + title: 'organisationseinheit', + titlePhrase: 'lehre/organisationseinheit', + field: "fachbereich", + headerFilter: true, + headerFilterFuncParams: { field: 'fachbereich' }, + visible: false + }, + { + title: 'stundenblockung', + titlePhrase: 'lehre/stundenblockung', + field: "stundenblockung", + headerFilter: true, + headerFilterFuncParams: { field: 'stundenblockung' }, + visible: false + }, + { + title: 'wochenrhythmus', + titlePhrase: 'lehre/wochenrhythmus', + field: "wochenrythmus", + headerFilter: true, + headerFilterFuncParams: { field: 'wochenrythmus' }, + visible: false + }, + { + title: 'startkw', + titlePhrase: 'lehre/startkw', + field: "start_kw", + headerFilter: true, + headerFilterFuncParams: { field: 'startkw' }, + visible: false + }, + { + title: 'raumtyp', + titlePhrase: 'lehre/raumtyp', + field: "raumtyp", + headerFilter: true, + headerFilterFuncParams: { field: 'raumtyp' }, + visible: false + }, + { + title: 'raumtypalternativ', + titlePhrase: 'lehre/raumtypalternativ', + field: "raumtypalternativ", + headerFilter: true, + headerFilterFuncParams: { field: 'raumtypalternativ' }, + visible: false + }, + { + title: 'gruppen', + titlePhrase: 'lehre/gruppen', + field: "gruppen", + headerFilter: true, + headerFilterFuncParams: { field: 'gruppen'} }, + { + title: 'lehrende', + titlePhrase: 'lehre/lehrende', + field: "lektoren", + headerFilter: true, + headerFilterFuncParams: { field: ['lektoren', 'vorname', 'nachname'] } + }, +]; diff --git a/application/views/jssnippets/tabulatorcolumns/stv.js b/application/views/jssnippets/tabulatorcolumns/stv.js new file mode 100644 index 000000000..54a370f5d --- /dev/null +++ b/application/views/jssnippets/tabulatorcolumns/stv.js @@ -0,0 +1,343 @@ +return [ + { + title: "UID", + titlePhrase: 'person/uid', + field: "uid", + headerFilter: true + }, + { + title: "TitelPre", + titlePhrase: 'person/titelpre', + field: "titelpre", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Nachname", + titlePhrase: 'person/nachname', + field: "nachname", + headerFilter: true + }, + { + title: "Vorname", + titlePhrase: 'person/vorname', + field: "vorname", + headerFilter: true + }, + { + title: "Wahlname", + titlePhrase: 'person/wahlname', + field: "wahlname", + visible: false, + headerFilter: true + }, + { + title: "Vornamen", + titlePhrase: 'person/vornamen', + field: "vornamen", + visible: false, + headerFilter: true + }, + { + title: "TitelPost", + titlePhrase: 'person/titelpost', + field: "titelpost", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Ersatzkennzeichen", + titlePhrase: 'person/ersatzkennzeichen', + field: "ersatzkennzeichen", + headerFilter: true + }, + { + title: "Geburtsdatum", + titlePhrase: 'person/geburtsdatum', + field: "gebdatum", + formatter: 'datetime', + formatterParams: { + inputFormat: "iso", + outputFormat: "dd.MM.yyyy", + invalidPlaceholder: " ", + timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone + }, + headerFilter: 'input', + headerFilterFunc: 'dateinput' + }, + { + title: "Geschlecht", + titlePhrase: 'person/geschlecht', + field: "geschlecht", + headerFilter: "list", + headerFilterParams: { + values: { + 'm': 'männlich', + 'w': 'weiblich', + 'x': 'divers', + 'u': 'unbekannt' + }, + listOnEmpty: true, + autocomplete: true + } + }, + { + title: "Sem.", + titlePhrase: 'lehre/sem', + field: "semester_berechnet", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Verb.", + titlePhrase: 'lehre/verb', + field: "verband", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Grp.", + titlePhrase: 'lehre/grp', + field: "gruppe", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Studiengang", + titlePhrase: 'lehre/studiengang', + field: "studiengang", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Studiengang_kz", + titlePhrase: 'lehre/studiengang_kz', + field: "studiengang_kz", + visible: false, + headerFilter: true + }, + { + title: "Personenkennzeichen", + titlePhrase: 'person/personenkennzeichen', + field: "matrikelnr", + headerFilter: true + }, + { + title: "PersonID", + titlePhrase: 'person/person_id', + field: "person_id", + headerFilter: true + }, + { + title: "Status", + titlePhrase: 'global/status', + field: "status", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Status Datum", + titlePhrase: 'profilUpdate/statusDate', + field: "status_datum", + visible: false, + formatter: 'datetime', + formatterParams: { + inputFormat: "iso", + outputFormat: "dd.MM.yyyy", + invalidPlaceholder: " ", + timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone + } + }, + { + title: "Status Bestaetigung", + titlePhrase: 'global/status_bestaetigung', + field: "status_bestaetigung", + visible: false, + formatter: 'datetime', + formatterParams: { + inputFormat: "iso", + outputFormat: "dd.MM.yyyy", + invalidPlaceholder: " ", + timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone + }, + headerFilter: 'input', + headerFilterFunc: 'dateinput' + }, + { + title: "EMail (Privat)", + titlePhrase: 'person/email_private', + field: "mail_privat", + visible: false, + headerFilter: true + }, + { + title: "EMail (Intern)", + titlePhrase: 'person/email_intern', + field: "mail_intern", + visible: false, + headerFilter: true + }, + { + title: "Anmerkungen", + titlePhrase: 'stv/notes_person', + field: "anmerkungen", + visible: false, + headerFilter: true + }, + { + title: "AnmerkungPre", + titlePhrase: 'stv/notes_prestudent', + field: "anmerkung", + visible: false, + headerFilter: true + }, + { + title: "OrgForm", + titlePhrase: 'lehre/orgform', + field: "orgform_kurzbz", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "Aufmerksamdurch", + titlePhrase: 'person/aufmerksamDurch', + field: "aufmerksamdurch_kurzbz", + visible: false + }, + { + title: "Gesamtpunkte", + titlePhrase: 'admission/gesamtpunkte', + field: "punkte", + visible: false + }, + { + title: "Aufnahmegruppe", + titlePhrase: 'stv/aufnahmegruppe_kurzbz', + field: "aufnahmegruppe_kurzbz", + visible: false + }, + { + title: "Dual", + titlePhrase: 'lehre/dual_short', + field: "dual", + visible: false, + formatter: 'tickCross', + formatterParams: { + tickElement: '', + crossElement: '' + }, + headerFilter: "tickCross", + headerFilterParams: { + "tristate": true, + elementAttributes: { + "value": "true" + } + }, + headerFilterEmptyCheck(value) { + return value === null + } + }, + { + title: "Matrikelnummer", + titlePhrase: 'person/matrikelnummer', + field: "matr_nr", + visible: false, + headerFilter: true + }, + { + title: "Studienplan", + titlePhrase: 'lehre/studienplan', + field: "studienplan_bezeichnung", + headerFilter: "list", + headerFilterParams: { + valuesLookup: true, + listOnEmpty: true, + autocomplete: true, + sort: "asc" + } + }, + { + title: "PreStudentInnenID", + titlePhrase: 'ui/prestudent_id', + field: "prestudent_id", + headerFilter: true + }, + { + title: "Priorität", + titlePhrase: 'lehre/prioritaet', + field: "priorisierung_relativ" + }, + { + title: "Mentor", + titlePhrase: 'stv/mentor', + field: "mentor", + visible: false + }, + { + title: "Aktiv", + titlePhrase: 'person/aktiv', + field: "bnaktiv", + visible: false, + formatter: 'tickCross', + formatterParams: { + allowEmpty: true, + tickElement: '', + crossElement: '' + }, + headerFilter: "tickCross", + headerFilterParams: { + "tristate": true, + elementAttributes: { + "value": "true" + } + }, + headerFilterEmptyCheck(value) { + return value === null + } + }, + { + title: "Unruly", + field: "unruly", + visible: false + } +]; diff --git a/public/js/api/factory/studiensemester.js b/public/js/api/factory/studiensemester.js index 7fe4a22d3..f57c10763 100644 --- a/public/js/api/factory/studiensemester.js +++ b/public/js/api/factory/studiensemester.js @@ -29,5 +29,20 @@ export default { url: 'api/frontend/v1/organisation/studiensemester/getAll', params: { order, start } }; + }, + current() { + return { + method: 'get', + url: 'api/frontend/v1/organisation/studiensemester/current' + }; + }, + set(studiensemester_kurzbz) { + return { + method: 'post', + url: 'api/frontend/v1/organisation/studiensemester/set', + params: { + studiensemester_kurzbz + } + }; } }; \ No newline at end of file diff --git a/public/js/api/factory/stv.js b/public/js/api/factory/stv.js index 95bc227f5..15ae15649 100644 --- a/public/js/api/factory/stv.js +++ b/public/js/api/factory/stv.js @@ -17,7 +17,6 @@ import app from './stv/app.js'; import lists from './stv/lists.js'; -import verband from './stv/verband.js'; import students from './stv/students.js'; import filter from './stv/filter.js'; import konto from './stv/konto.js'; @@ -34,7 +33,6 @@ import admissionDates from './stv/admissionDates.js'; export default { app, lists, - verband, students, filter, konto, diff --git a/public/js/api/lehrveranstaltung/studiengangtree.js b/public/js/api/factory/treemenu.js similarity index 68% rename from public/js/api/lehrveranstaltung/studiengangtree.js rename to public/js/api/factory/treemenu.js index fb63db729..662297d22 100644 --- a/public/js/api/lehrveranstaltung/studiengangtree.js +++ b/public/js/api/factory/treemenu.js @@ -1,5 +1,5 @@ /** - * Copyright (C) 2025 fhcomplete.org + * Copyright (C) 2026 fhcomplete.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,26 +16,29 @@ */ export default { - get(path) { - let url = 'api/frontend/v1/lv/StgTree'; - if (path) - url += '/' + path; + get(config, path = '') { return { method: 'get', - url + url: '/api/frontend/v1/treemenu/' + config + '/' + path + }; + }, + data(config, path = '') { + return { + method: 'get', + url: '/api/frontend/v1/treemenudata/' + config + '/' + path }; }, favorites: { - get() { + get(config) { return { method: 'get', - url: 'api/frontend/v1/lv/favorites' + url: 'api/frontend/v1/favorites/get/' + config }; }, - set(favorites) { + set(config, favorites) { return { method: 'post', - url: 'api/frontend/v1/lv/favorites/set', + url: 'api/frontend/v1/favorites/set/' + config, params: { favorites } }; } diff --git a/public/js/api/stv.js b/public/js/api/stv.js index 8a4e568ea..19125b1bf 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -1,4 +1,3 @@ -import verband from './stv/verband.js'; import students from './stv/students.js'; import filter from './stv/filter.js'; import konto from './stv/konto.js'; @@ -18,7 +17,6 @@ import jointstudies from "./stv/jointstudies.js"; import courselist from './stv/courselist.js'; export default { - verband, students, filter, konto, diff --git a/public/js/api/stv/verband.js b/public/js/api/stv/verband.js deleted file mode 100644 index f3479c81b..000000000 --- a/public/js/api/stv/verband.js +++ /dev/null @@ -1,15 +0,0 @@ -export default { - get() { - return this.$fhcApi.get('api/frontend/v1/stv/verband'); - }, - favorites: { - get() { - return this.$fhcApi.get('api/frontend/v1/stv/favorites'); - }, - set(favorites) { - return this.$fhcApi.post('api/frontend/v1/stv/favorites/set', { - favorites - }); - } - } -} \ No newline at end of file diff --git a/public/js/apps/LVVerwaltung.js b/public/js/apps/LVVerwaltung.js index 18f8a072f..22d3612ea 100644 --- a/public/js/apps/LVVerwaltung.js +++ b/public/js/apps/LVVerwaltung.js @@ -12,74 +12,13 @@ const router = VueRouter.createRouter({ component: LVVerwaltung }, { - name: `byEmp`, - path: `/emp/:studiensemester_kurzbz/:emp/:stg?/:semester?`, + name: 'stdsem', + path: '/stdsem/:stdsem', component: LVVerwaltung, - props: route => { - let {emp, stg, semester, studiensemester_kurzbz} = route.params; - - if (emp === '') - emp = undefined; - - if (stg === '') - stg = undefined; - - if (studiensemester_kurzbz === '') - studiensemester_kurzbz = undefined; - - return { - studiensemester_kurzbz: studiensemester_kurzbz, - emp: emp, - stg: stg, - semester: semester - }; - }, - beforeEnter: (to, from, next) => { - const { studiensemester_kurzbz } = to.params; - const isSemester = /^(SS|WS)\d{4}$/.test(studiensemester_kurzbz); - - if (!isSemester) - return next({ path: '/' }); - else - next(); - } - }, - /*{ - name: `byFachbereich`, - path: `/fachbereich/:fachbereich/:emp?`, - component: LVVerwaltung - },*/ - { - name: `byStg`, - path: '/stg/:studiensemester_kurzbz/:stg?/:semester?/', - component: LVVerwaltung, - props: route => { - let { studiensemester_kurzbz, stg, semester } = route.params; - - if (semester === '') - semester = undefined; - - if (studiensemester_kurzbz === '') - studiensemester_kurzbz = undefined; - - if (stg === '') - stg = undefined; - - return { - studiensemester_kurzbz: studiensemester_kurzbz, - stg: stg, - semester: semester, - }; - }, - beforeEnter: (to, from, next) => { - const studiensemester_kurzbz = to.params?.studiensemester_kurzbz - const isSemester = /^(SS|WS)\d{4}$/.test(studiensemester_kurzbz); - - if (!isSemester) - return next({ path: '/' }); - else - next(); - } + children: [ + { name: 'emp', path: 'emp/:emp/:treemenu(.*)*', component: LVVerwaltung }, + { name: 'treemenu', path: ':treemenu(.*)*', component: LVVerwaltung } + ] }, { path: '/:pathMatch(.*)*', diff --git a/public/js/apps/Studentenverwaltung.js b/public/js/apps/Studentenverwaltung.js index 47490bfdd..d22609fb9 100644 --- a/public/js/apps/Studentenverwaltung.js +++ b/public/js/apps/Studentenverwaltung.js @@ -24,167 +24,27 @@ import PluginsPhrasen from "../plugins/Phrasen.js"; const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; const router = VueRouter.createRouter({ - history: VueRouter.createWebHistory(), + history: VueRouter.createWebHistory('/' + ciPath), routes: [ { name: 'index', - path: `/${ciPath}/studentenverwaltung`, - component: FhcStudentenverwaltung - }, - { - name: 'studiensemester', - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz`, + path: '/studvw', component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); + children: [ + { + name: 'stdsem', + path: 'stdsem/:stdsem', + component: FhcStudentenverwaltung, + children: [ + { name: 'search', path: 'search/:query', component: FhcStudentenverwaltung }, + { name: 'searchtypes', path: 'search/:types/:query', component: FhcStudentenverwaltung }, + { name: 'prestudent', path: 'prestudent/:prestudent_id', component: FhcStudentenverwaltung }, + { name: 'student', path: 'student/:student_uid', component: FhcStudentenverwaltung }, + { name: 'person', path: 'person/:person_id', component: FhcStudentenverwaltung }, + { name: 'treemenu', path: ':treemenu(.*)*', component: FhcStudentenverwaltung }, + ] } - next(); - } - }, - { - name: 'studiengang', - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/:studiengang`, - component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_studiengang: route.params.studiengang, - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - const isStudiengang = /^[A-Z]{3}/.test(to.params.studiengang); - if (!isStudiengang) { - return next({ - name: 'studiensemester', - params: { - studiensemester_kurzbz: to.params.studiensemester_kurzbz - } - }); - } - next(); - } - }, - { - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/prestudent/:prestudent_id`, - component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'prestudent', - url_prestudent_id: route.params.prestudent_id - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } - }, - { - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/prestudent/:prestudent_id/:tab`, - component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'prestudent', - url_prestudent_id: route.params.prestudent_id, - url_tab: route.params.tab - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } - }, - { - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/student/:id`, - component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'student', - url_student_id: route.params.id - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } - }, - { - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/person/:person_id`, - component: FhcStudentenverwaltung, - props: (route) => { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'person', - url_prestudent_id: route.params.person_id - }; - }, - beforeEnter: (to, from, next) => { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } - }, - { - name: 'search', - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:searchstr`, - component: FhcStudentenverwaltung, - props(route) { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'search', - url_prestudent_id: route.params.searchstr - }; - }, - beforeEnter(to, from, next) { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } - }, - { - name: 'search_w_types', - path: `/${ciPath}/studentenverwaltung/:studiensemester_kurzbz/search/:types/:searchstr`, - component: FhcStudentenverwaltung, - props(route) { - return { - url_studiensemester_kurzbz: route.params.studiensemester_kurzbz, - url_mode: 'search', - url_prestudent_id: route.params.type + '/' + route.params.searchstr - }; - }, - beforeEnter(to, from, next) { - const isSemester = /^[WS]S\d{4}$/.test(to.params.studiensemester_kurzbz); - if (!isSemester) { - return next({name: 'index'}); - } - next(); - } + ] }, { path: '/:pathMatch(.*)*', @@ -197,11 +57,16 @@ const router = VueRouter.createRouter({ router.afterEach((to, from, failure) => { let title = 'Studierendenverwaltung FH-Complete'; - if (to.params.studiengang) { - title = to.params.studiengang + ' ' + title; + if (to.params.treemenu) { + const index = to.params.treemenu.findIndex( + (e, i) => i%2 == 0 && e == 'stg' + ); + if (index >= 0) { + title = to.params.treemenu[index + 1].toUpperCase() + ' ' + title; + } } - if (to.params.studiensemester_kurzbz) { - title = to.params.studiensemester_kurzbz + ' ' + title; + if (to.params.stdsem) { + title = to.params.stdsem.toUpperCase() + ' ' + title; } document.title = title; }); diff --git a/public/js/components/Base/Treemenu.js b/public/js/components/Base/Treemenu.js new file mode 100644 index 000000000..5fe46606c --- /dev/null +++ b/public/js/components/Base/Treemenu.js @@ -0,0 +1,363 @@ +import TreemenuEntry from './Treemenu/Entry.js'; + +import dragClick from '../../directives/dragClick.js'; + +import ApiTreemenu from '../../api/factory/treemenu.js'; + +export default { + components: { + PvTreetable: primevue.treetable, + PvColumn: primevue.column, + TreemenuEntry + }, + directives: { + dragClick + }, + emits: [ + 'selectEntry', + 'drop' + ], + props: { + config: { + type: String, + required: true, + }, + preselectedKey: { + type: Array, + default: null + } + }, + data() { + return { + loading: true, + nodes: [], + selectedKey: [], + expandedKeys: {}, + filters: {}, // TODO(chris): filter only 1st level? + favorites: {on: false, list: []} + } + }, + computed: { + filteredNodes() { + if (this.favorites.on) + return this.nodes.filter(node => this.favorites.list.includes(node.data.path)); + + return this.nodes; + } + }, + watch: { + preselectedKey(newVal, oldVal) { + if (newVal !== oldVal) { + this.setPreselection(); + } + } + }, + methods: { + reloadNodesWithProp(prop, nodes = undefined) { + if (!nodes) + nodes = this.nodes; + + nodes.forEach(node => { + if (node.data[prop]) { + // reload + delete node.children; + this.onExpandTreeNode(node); + } else if (node.children) { + this.reloadNodesWithProp(prop, node.children); + } + }); + }, + findNodeByKey(key, arr) { + if (!arr) + arr = this.nodes; + let res = arr.filter(n => n.key == key); + if (res.length) + return res.pop(); + res = arr.map(n => n.children ? this.findNodeByKey(key, n.children) : null).filter(a => a); + if (res.length) + return res.pop(); + return null; + }, + async onExpandTreeNode(node) { + if (!node.children) { + if (node.data.path) { + /** + * NOTE(chris): activeEl is for keyboard navigation to + * prevent the focus jumping down to the next parent + * instead of the current submenu entry (which is not yet + * loaded) + */ + let activeEl = null; + this.$nextTick(() => { + this.$nextTick(() => { + activeEl = document.activeElement; + }); + }); + this.loading = true; + + return this.$api + .call(ApiTreemenu.get(this.config, node.data.path)) + .then(result => { + const subNodes = result.data.map(this.mapResultToTreeData); + const realNode = this.findNodeByKey(node.key); + if (realNode) + realNode.children = subNodes; + else + node.children = subNodes; // NOTE(chris): fallback should never be the case + + this.$nextTick(() => { + if (activeEl != document.activeElement) + return; + + let treeitem = this.$refs.tree.$el.querySelector('[data-tree-item-key="' + node.key + '"]'); + if (!treeitem) + return; + + treeitem = treeitem.closest('[role="row"]'); + + if (!treeitem) + return; + + treeitem.dispatchEvent(new KeyboardEvent('keydown', { + code: 'ArrowDown', + key: 'ArrowDown' + })); + }); + + this.loading = false; + }) + .catch(this.$fhcAlert.handleSystemError); + } + } + }, + onSelectTreeNode(node) { + this.$emit('selectEntry', node.data); + }, + mapNodesToNoSemReloadNodes(result, node) { + if (node.data.no_sem_reload) + result.push(node); + if (node.children) + result = node.children.reduce(this.mapNodesToNoSemReloadNodes, result); + return result; + }, + mapResultToTreeData(el) { + const cp = { + key: ("" + el.path).replace(/\//g, '-'), + data: el, + label: el.name // TODO(chris): phrase + }; + + if (el.children) + cp.children = el.children.map(this.mapResultToTreeData); + else + cp.leaf = el.leaf || false; + + return cp; + }, + async setPreselection() + { + if (!this.preselectedKey || !this.preselectedKey.length) + { + this.selectedKey = null; + return; + } + + if (!this.preselectedKey || !Array.isArray(this.preselectedKey)) + return; + + // [1, 2, 3, 4, ...] => ['1-2', '3-4', ...] + const parts = this.preselectedKey.reduce((r, c, i, a) => (i%2 && r.push(a[i-1] + '-' + c), r), []); + let currentKey = parts[0]; + let currentNode = this.findNodeByKey(currentKey); + + if (!currentNode) + return; + + if(this.selectedKey) + { + const currentSelectedKey = Object.keys(this.selectedKey).find(Boolean); + if (currentSelectedKey) { + if (currentSelectedKey == currentKey) + return; + /** + * Do not select a new entry if the current is a child of the new one. + * This happens if a child entry of a new stg is selected and the router + * tries to select the stg root entry (because subtrees do not have + * routes yet) + */ + const isChild = this.findNodeByKey( + currentSelectedKey, + currentNode.children || [] + ); + if (isChild) + return; + } + } + + for (let i = 1; i < parts.length; i++) + { + this.expandedKeys[currentNode.key] = true; + + await this.onExpandTreeNode(currentNode); + + currentKey += '-' + parts[i]; + currentNode = this.findNodeByKey(currentKey); + + if (!currentNode) + { + return; + } + } + + this.selectedKey = {[currentNode.key]: true}; + this.onSelectTreeNode(currentNode); + }, + async toggleTreeNode(node) { + if (this.expandedKeys[node.key]) { + delete this.expandedKeys[node.key]; + } else if (!node.leaf) { + await this.onExpandTreeNode(node); + this.expandedKeys[node.key] = true; + } + }, + filterFav() { + this.favorites.on = !this.favorites.on; + this.$api + .call(ApiTreemenu.favorites.set( + this.config, + JSON.stringify(this.favorites) + )); + }, + markFav(key) { + let index = this.favorites.list.indexOf(key.data.path + ''); + + if (index != -1) { + this.favorites.list.splice(index, 1); + } else { + this.favorites.list.push(key.data.path + ''); + } + + this.$api + .call(ApiTreemenu.favorites.set( + this.config, + JSON.stringify(this.favorites) + )); + }, + unsetFavFocus(e) { + if (e.target.dataset?.linkFavAdd !== undefined) { + e.target.tabIndex = -1; + } else { + let items = e.target.querySelectorAll('[data-link-fav-add]:not([tabindex="-1"])'); + items.forEach(el => el.tabIndex = document.activeElement == el ? 0 : -1); + } + }, + setFavFocus(e) { + if (e.target.dataset?.linkFavAdd !== undefined) { + e.target.tabIndex = 0; + } else { + let items = e.target.querySelectorAll('[data-link-fav-add][tabindex="-1"]'); + items.forEach(el => el.tabIndex = 0); + } + } + }, + mounted() { + this.$api + .call(ApiTreemenu.get(this.config)) + .then(result => { + this.nodes = result.data.map(el => { + el.root = true; + return this.mapResultToTreeData(el); + }); + this.setPreselection(); + this.loading = false; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiTreemenu.favorites.get(this.config)) + .then(result => { + if (result.data) { + this.favorites = JSON.parse(result.data); + } + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: /* html */` + + + + + + + + + + + ` +}; diff --git a/public/js/components/Base/Treemenu/Entry.js b/public/js/components/Base/Treemenu/Entry.js new file mode 100644 index 000000000..c09f413ff --- /dev/null +++ b/public/js/components/Base/Treemenu/Entry.js @@ -0,0 +1,63 @@ +import drop from '../../../directives/drop.js'; +import draggable from '../../../directives/draggable.js'; + +export default { + directives: { + drop, + draggable + }, + emits: [ + 'drop' + ], + props: { + node: { + type: Object, + required: true + } + }, + computed: { + name() { + if (Array.isArray(this.node.data.name)) + return this.$p.t(this.node.data.name); + + return this.node.data.name; + }, + title() { + if (!this.node.data.title) + return this.name; + + if (Array.isArray(this.node.data.title)) + return this.$p.t(this.node.data.title); + + return this.node.data.title; + }, + dropConfig() { + if (!this.node.data?.droplink) + return null; + + const allowed = [ ...this.node.data.droplink ]; + const effect = allowed.shift(); + + return { effect, allowed }; + }, + dragConfig() { + if (!this.node.data?.draggable) + return null; + + let config = [ ...this.node.data.draggable ]; + const effect = config.shift(); + const value = JSON.parse(config.shift()); + + return { effect, value }; + } + }, + template: /* html */` + + {{ name }} + ` +}; diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 42c50bdfa..57b990e4c 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -1,15 +1,13 @@ import CoreSearchbar from "../searchbar/searchbar.js"; import VerticalSplit from "../verticalsplit/verticalsplit.js"; import AppMenu from "../AppMenu.js"; -import StvVerband from "../Stv/Studentenverwaltung/Verband.js"; +import BaseTreemenu from '../Base/Treemenu.js'; import StvStudiensemester from "../Stv/Studentenverwaltung/Studiensemester.js"; import LvTable from "./Setup/Table.js"; import LvTabs from "./Setup/Tabs.js"; import ApiDetails from "../../api/lehrveranstaltung/details.js"; import ApiLektor from "../../api/lehrveranstaltung/lektor.js"; -import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js"; -import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; import ApiSearchbar from "../../api/factory/searchbar.js"; @@ -19,7 +17,7 @@ export default { CoreSearchbar, VerticalSplit, AppMenu, - StvVerband, + BaseTreemenu, StvStudiensemester, LvTable, LvTabs, @@ -29,12 +27,7 @@ export default { lvRoot: String, permissions: Object, config: Object, - stg: { type: String, required: false }, - semester: { type: [Number, String], required: false, default: null }, - studiensemester_kurzbz: { type: String, required: false, default: null }, - emp: { type: String, required: false, default: null } }, - provide() { return { currentSemester: Vue.computed(() => this.selectedStudiensemester), @@ -50,40 +43,17 @@ export default { permissionLektorEntfernen: this.permissions['lv-plan/lektorentfernen'], } }, - mounted() { - this.updateFilter(); - }, - watch: { - stg() { - this.updateFilter(); - }, - semester() { - this.updateFilter(); - }, - selectedStudiensemester() { - this.updateFilter(); - }, - emp() { - this.updateFilter(); - }, - studiensemester_kurzbz(newVal) { - this.selectedStudiensemester = newVal ?? this.defaultSemester; - } - }, data() { return { selected: [], studiengang: "", - filter: {}, - selectedStudiensemester: this.studiensemester_kurzbz ?? this.defaultSemester, - endpoint: ApiStudiengangTree, + selectedStudiensemester: this.defaultSemester, dropdowns: { studiensemester_array: [], sprachen_array: [], lehrform_array: [], raumtyp_array: [], }, - selectedStudiengang: '', searchbaroptions: { origin: 'lvverwaltung', cssclass: "position-relative", @@ -107,28 +77,38 @@ export default { }, } }, + computed: { + filter() { + let filter = { + emp: this.$route.params.emp, + studiensemester_kurzbz: this.selectedStudiensemester + }; + let index; + if (this.$route.params.treemenu) { + index = this.$route.params.treemenu.indexOf('stg'); + if (index > -1) + filter.stg = this.$route.params.treemenu[index+1]; + index = this.$route.params.treemenu.indexOf('semester'); + if (index > -1) + filter.semester = this.$route.params.treemenu[index+1]; + } + filter.activeFilter = filter.emp ? 'employee' : filter.stg ? 'verband' : null; + return filter; + }, + emp() { + return this.filter.emp; + }, + stg() { + return this.filter.stg; + }, + semester() { + return this.filter.semester; + }, + }, methods: { updateFilter() { - const filter = { - stg: this.stg, - emp: this.emp, - semester: this.semester, - studiensemester_kurzbz: this.selectedStudiensemester, - activeFilter: this.emp ? 'employee' : this.stg ? 'verband' : null - } - - if (this.stg !== undefined) - { - this.selectedStudiengang = this.semester !== '' && this.semester - ? `${this.stg}/${this.semester}` - : this.stg; - } - else - { - this.selectedStudiengang = ''; - } - this.filter = filter; + // deprecated }, handleRowClicked(data) { @@ -136,77 +116,90 @@ export default { }, onSelectEmployee(emp) { - const { stg, semester } = this.filter; - - let studiensemester_kurzbz = this.selectedStudiensemester; - const params = { emp }; - - if (stg) - params.stg = stg; - if (semester !== null) - params.semester = semester; - if (studiensemester_kurzbz) - params.studiensemester_kurzbz = studiensemester_kurzbz; - - this.$router.push({ name: 'byEmp', params }) + this.$router.push({ + name: 'emp', + params: { + ...this.$route.params, + emp + } + }); }, - - onSelectVerband({link}) + onSelectVerband({ path: link }) { - let stg = null; - let semester = null; - let studiensemester_kurzbz = this.selectedStudiensemester; - - if (typeof link === 'number') - stg = link; - else if (typeof link === 'string') - { - [stg, semester] = link.split('/'); - } - - const routeName = this.filter.emp ? 'byEmp' : 'byStg'; - const params = { stg }; - - params.semester = ''; - if (semester !== null) - params.semester = semester; - if (studiensemester_kurzbz) - params.studiensemester_kurzbz = studiensemester_kurzbz; - if (this.filter.emp) - params.emp = this.filter.emp; - this.$router.push({ name: routeName, params }); + this.$router.push({ + name: this.$route.name == 'emp' ? 'emp' : 'treemenu', + params: { + ...this.$route.params, + treemenu: link.split('/') + } + }); this.selected = []; }, resetEmployeeFilter() { - const newParams = { ...this.filter, activeFilter: 'verband' }; - if (newParams.stg === '') - this.$router.replace({ name: 'index' }); - else - { - delete newParams.emp; - - this.$router.replace({ name: 'byStg', params: newParams }); - } + let params = { ...this.$route.params }; + + delete params.emp; + + this.$router.replace({ + name: params.treemenu ? 'treemenu' : 'stdsem', + params + }); }, resetStgFilter() { - const newParams = { ...this.filter, activeFilter: 'emp' }; - delete newParams.stg; - this.selectedStudiengang = ''; - this.$router.replace({ name: 'byEmp', params: newParams }); + let params = { ...this.$route.params }; + let index = params.treemenu.indexOf('stg'); + if (index > -1) + params.treemenu = params.treemenu.slice(0, index); + if (params.treemenu.length) { + this.$router.replace({ + params: { + treemenu: params.treemenu + } + }); + } else { + delete params.treemenu; + this.$router.replace({ + name: params.emp ? 'emp' : 'stdsem', + params + }); + } }, - searchfunction(params) { - return this.$api.call(ApiSearchbar.search(params)); + searchfunction(params, config) { + return this.$api.call(ApiSearchbar.search(params), config); }, - studiensemesterChanged(newValue) { - const routeName = this.filter.activeFilter === 'employee' ? 'byEmp' : 'byStg'; - const newParams = {...this.filter, studiensemester_kurzbz: newValue}; - this.$router.push({ name: routeName, params: newParams }); + studiensemesterChanged(stdsem) { + if (!stdsem) { + // no valid studiensemester in url + this.$router.replace({ + params: { + stdsem: this.defaultSemester.toLowerCase() + } + }); + return; + } + if (stdsem.toLowerCase() != this.selectedStudiensemester?.toLowerCase()) { + this.$router.push({ + params: { + stdsem: stdsem.toLowerCase() + } + }); + } + this.selectedStudiensemester = stdsem; this.selected = []; - }, + } }, created() { + if (!this.$route.params.stdsem) { + this.$router.replace({ + name: 'stdsem', + params: { + stdsem: this.defaultSemester.toLowerCase() + } + }); + } + this.$p.loadCategory(['lehre', 'person', 'global']) this.$api.call(ApiDetails.getStudiensemester()) @@ -239,7 +232,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, - template: /* html */`