diff --git a/classes/class.ilHSLUUIDefaultsAccessChecker.php b/classes/class.ilHSLUUIDefaultsAccessChecker.php new file mode 100644 index 0000000..0b1a80b --- /dev/null +++ b/classes/class.ilHSLUUIDefaultsAccessChecker.php @@ -0,0 +1,30 @@ +rbac_review = $rbac_review; + + // Check if the admin role is set and if the given ID is indeed the object ID of a role + if (SYSTEM_ROLE_ID !== null + && \ilObject::_lookupType(SYSTEM_ROLE_ID) == 'role' + ) { + $this->admin_role_is_defiend = true; + $this->admin_role_id = (int) SYSTEM_ROLE_ID; + } else { + $this->admin_role_is_defiend = false; + $this->admin_role_id = null; + } + } + + public function checkIfAdminRoleIsDefinedAndUserIsAdmin(\ilObjUser $user) : bool + { + return $this->admin_role_is_defiend + && $this->rbac_review->isAssigned($user->getId(), $this->admin_role_id) ; + } +} \ No newline at end of file diff --git a/classes/class.ilHSLUUIDefaultsCtrlRoutingGUI.php b/classes/class.ilHSLUUIDefaultsCtrlRoutingGUI.php new file mode 100644 index 0000000..77bfd20 --- /dev/null +++ b/classes/class.ilHSLUUIDefaultsCtrlRoutingGUI.php @@ -0,0 +1,198 @@ +getLinkByTargetClass(...) + public const CTRL_UI_ROUTE = [\ilUIPluginRouterGUI::class, \ilHSLUUIDefaultsCtrlRoutingGUI::class]; + + // Commands which are used for ilCtrl. Public = accessible for other GUI-Classes, Private = only accessible from here + public const CMD_DASHBOARD_PAGE = 'show_dashboard'; + + // TAB-IDs + private const TAB_DASHBOARD = 'dashboard'; + + private ilHSLUUIDefaultsPlugin $plugin_object; + private ilGlobalPageTemplate $tpl; + private Factory $ui_factory; + private Renderer $ui_renderer; + private ilCtrl $ctrl; + private ilTabsGUI $tabs; + private ilDBInterface $db; + private ServerRequestInterface $request; + private ilTree $tree; + private ilObjUser $user; + private ilErrorHandling $error; + private ilHSLUUIDefaultsAccessChecker $access_checker; + private $filtered_queries = array(); + + public function __construct() + { + global $DIC; + + // Here I set a lot of useful objects which might be used later in the GUI class + $this->plugin_object = new ilHSLUUIDefaultsPlugin(); + $this->tpl = $DIC->ui()->mainTemplate(); + $this->ui_factory = $DIC->ui()->factory(); + $this->ui_renderer = $DIC->ui()->renderer(); + $this->ctrl = $DIC->ctrl(); + $this->tabs = $DIC->tabs(); + $this->db = $DIC->database(); + $this->request = $DIC->http()->request(); + $this->tree = $DIC->repositoryTree(); + $this->user = $DIC->user(); + $this->error = $DIC["ilErr"]; + $this->filtered_queries = array(); + + $this->access_checker = new ilHSLUUIDefaultsAccessChecker($DIC->rbac()->review()); + + // add the filtered queries + $this->addFilteredQueries(); + + } + + public function executeCommand() + { + // This method is for access checking. We only want admins on this page. Otherwise redirect with an error + $this->checkAccessAndRedirectOnFailure(); + + // This method renders the title, tabs and all the stuff you want to show on each page + $this->initHeaderGUI(); + + // Here is the check for the ilCtrl-Command. I prefer to use class-constants instead of strings to avoid typos + $cmd = $this->ctrl->getCmd(); + switch($cmd) { + case self::CMD_DASHBOARD_PAGE: + $this->tabs->activateTab(self::TAB_DASHBOARD); + $this->showDashboardPage(); + break; + default: + // execute the relevant filtered query + $this->tabs->activateTab($this->filtered_queries[$cmd]->getId()); + $this->showFilteredQueryPage($this->filtered_queries[$cmd]); + break; + } + + // Add the end, we let the Global-Template send its content to the client + $this->tpl->printToStdout(); + } + + private function initHeaderGUI() + { + // Set title which is shown above the tabs + $this->tpl->setTitle("HSLU UI Defaults"); + + // Add tab for dashboard + $link = $this->ctrl->getLinkTargetByClass(self::CTRL_UI_ROUTE, self::CMD_DASHBOARD_PAGE); + $this->tabs->addTab(self::TAB_DASHBOARD, $this->plugin_object->txt('tab_dashboard'), $link); + + // add tabs for filtered queries + $this->addFilteredQueryTabs(); + + } + private function addFilteredQueries() + { + // + // event log + // + $columns = [ + ["text" => $this->plugin_object->txt("evento_id"),"sort_field" => "evento_id", "width" => "7%"], + ["text" => $this->plugin_object->txt("last_import_data"), "sort_field" => "last_import_data", "width" => "83%"], + ["text" => $this->plugin_object->txt("last_import_date"), "sort_field" => "last_import_date", "width" => "10%"] + ]; + + $filter_fields = [ + ["type" => "text", "id" => "evento_id", "label" => $this->plugin_object->txt("evento_id"), "sql_expr" => "evento_id", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE], + ["type" => "text", "id" => "last_import_data", "label" => $this->plugin_object->txt("last_import_data"), "sql_expr" => "last_import_data", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE], + ["type" => "text", "id" => "last_import_date", "label" => $this->plugin_object->txt("last_import_date"), "sql_expr" => "last_import_date", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE] + ]; + + $sql = [ + "select" => "*", + "from" => "crevento_log_events", + "where" => "", + "order_by" => "last_import_date" + ]; + + $filtered_query = new ilHSLUUIDefaultsFilteredQueryGUI($this, "show_evento_log", $this->plugin_object, $this->plugin_object->txt("evento_log"), "hsluevento", "tpl.table_row_single_column.html", $this->ctrl->getFormAction($this), $filter_fields, $columns, $sql, "last_import_date"); + + $this->filtered_queries[$filtered_query->getParentCmd()] = $filtered_query; + + // + // objects + // + $columns = [ + ["text" => $this->plugin_object->txt("obj_id"),"sort_field" => "obj_id", "width" => "7%"], + ["text" => $this->plugin_object->txt("title"), "sort_field" => "title", "width" => "40%"], + ["text" => $this->plugin_object->txt("type"), "sort_field" => "type", "width" => "6%"], + ["text" => $this->plugin_object->txt("ref_id"), "sort_field" => "ref_id", "width" => "7%"], + ["text" => $this->plugin_object->txt("path"), "sort_field" => "path", "width" => "40%"] + ]; + + $filter_fields = [ + ["type" => "text", "id" => "obj_id", "label" => $this->plugin_object->txt("obj_id"), "sql_expr" => "ref.obj_id", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE], + ["type" => "text", "id" => "ref_id", "label" => $this->plugin_object->txt("ref_id"), "sql_expr" => "ref.ref_id", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE], + ["type" => "text", "id" => "title", "label" => $this->plugin_object->txt("title"), "sql_expr" => "obj.title", "operator" => ilHSLUUIDefaultsFilteredQueryGUI::OPR_LIKE] + ]; + + $sql = [ + "select" => "obj.obj_id AS obj_id, CASE WHEN obj.type in ('cat','crs','grp','crsr','file') THEN concat('',obj.title,'') ELSE obj.title END as title, obj.type AS type, ref.ref_id AS ref_id, t.path AS path ", + "from" => "object_reference AS ref JOIN object_data obj ON ref.obj_id = obj.obj_id JOIN tree as t ON ref.ref_id = t.child", + "where" => "", + "order_by" => "obj.obj_id" + ]; + + $filtered_query = new ilHSLUUIDefaultsFilteredQueryGUI($this, "show_objects", $this->plugin_object, $this->plugin_object->txt("objects"), "hsluobjects", "tpl.table_row_single_column.html", $this->ctrl->getFormAction($this), $filter_fields, $columns, $sql, "obj_id"); + + $this->filtered_queries[$filtered_query->getParentCmd()] = $filtered_query; + } + private function addFilteredQueryTabs() + { + foreach($this->filtered_queries as $key=> $query){ + $link = $this->ctrl->getLinkTargetByClass(self::CTRL_UI_ROUTE, $query->getParentCmd()); + $this->tabs->addTab($query->getId(), $query->title, $link); + } + } + private function checkAccessAndRedirectOnFailure() + { + if (!$this->access_checker->checkIfAdminRoleIsDefinedAndUserIsAdmin($this->user)) { + $this->error->raiseError('Permission denied'); + exit; + } + } + + private function showDashboardPage() + { + // Array for UI-Components. See UI-Kitchensink documentation for more + $ui_components = []; + + // Build modal from UI-Factory and add to UI-Components + $modal = $this->ui_factory->modal()->lightbox( + $this->ui_factory->modal()->lightboxTextPage('This is a lightbox modal', 'And here is some text') + ); + $ui_components[] = $modal; + + // Build panel with a button from UI-Factory. Let the modal open itself if the button is clicked + $ui_components[] = $this->ui_factory->panel()->standard( + 'This is a panel for something', + $this->ui_factory->button()->standard('Klick here to show a modal', $modal->getShowSignal()) + ); + + // Render kitchensink-components to HTML and add them to the globale template + $content_html = $this->ui_renderer->render($ui_components); + $this->tpl->setContent($content_html); + } + + private function showFilteredQueryPage(ilHSLUUIDefaultsFilteredQueryGUI $filtered_query) + { + $this->tpl->setContent($filtered_query->getHTML()); + } +} diff --git a/classes/class.ilHSLUUIDefaultsFilteredQueryGUI.php b/classes/class.ilHSLUUIDefaultsFilteredQueryGUI.php new file mode 100644 index 0000000..fd6840a --- /dev/null +++ b/classes/class.ilHSLUUIDefaultsFilteredQueryGUI.php @@ -0,0 +1,296 @@ + + */ +class ilHSLUUIDefaultsFilteredQueryGUI extends ilTable2GUI +{ + /** + * @var operators + */ + public const OPR_EQUALS = '='; + public const OPR_NOT_EQUALS = '!='; + public const OPR_LIKE = 'LIKE'; + public const OPR_NOT_LIKE = 'NOT LIKE'; + public const OPR_GREATER_THAN = '>'; + public const OPR_LESS_THAN = '<'; + protected $parent; + protected $plugin; + protected $form_action; + protected $filter_fields; + protected $columns; + + /** + * @var \ILIAS\UI\Renderer + */ + protected $renderer; + + /** + * @var Standard + */ + protected $filter; + + /** + * @var ilUIFilterService + */ + protected $filter_service; + /** + * @var sql + */ + protected $sql; + + public function __construct( + ilHSLUUIDefaultsCtrlRoutingGUI $parent, + string $parent_cmd, + $plugin, + string $title, + string $id, + string $template, + $form_action, + array $filter_fields, + array $columns, + array $sql, + string $default_order_field, + bool $enable_header = true, + int $limit = 1000 + ) { + global $DIC; + + parent::__construct($parent, $parent_cmd); + + $this->parent = $parent; + $this->plugin = $plugin; + $this->setTitle($title); + $this->setId($id); + $this->setRowTemplate($template, $this->plugin->getDirectory()); + $this->form_action = $form_action; + $this->setFormAction($form_action); + $this->filter_fields = array_column($filter_fields, null, 'id'); + $this->columns = $columns; + $this->setDefaultOrderField($default_order_field); + $this->setEnableHeader($enable_header); + $this->lng = $DIC->language(); + $this->ctrl = $DIC->ctrl(); + $this->renderer = $DIC->ui()->renderer(); + $this->filter_service = $DIC->uiService()->filter(); + $this->sql = $sql; + + foreach ($columns as $column) { + $this->addColumn( + $column["text"], + $column["sort_field"], + $column["width"], + $column["is_checkbox_action_column"], + $column["class"], + $column["tooltip"], + $column["tooltip_html"]); + } + $this->setLimit($limit); + } + + protected function getFilterInputFields($filter_fields) : array + { + + global $DIC; + + $input_fields = []; + $field_factory = $DIC->ui()->factory()->input()->field(); + + foreach ($filter_fields as $filter_field) { + $field = null; + switch ($filter_field["type"]) { + case "text": + $field = $field_factory->text($filter_field["label"], $filter_field["byline"]); + break; + case "numeric": + $field = $field_factory->numeric($filter_field["label"], $filter_field["byline"]); + break; + case "multiSelect": + $field = $field_factory->multiSelect($filter_field["label"], $filter_field["options"], + $filter_field["byline"]); + break; + default: + $field = $field_factory->text($filter_field["label"], $filter_field["byline"]); + } + $input_fields[$filter_field["id"]] = $field; + } + + return $input_fields; + } + + protected function setFilter(ilHSLUUIDefaultsCtrlRoutingGUI $parent, string $parent_cmd, string $id, $filter_fields) + { + + global $DIC; + $filter_service = $DIC->uiService()->filter(); + + $this->filter = $filter_service->standard( + $id, + $DIC->ctrl()->getLinkTarget($parent, $parent_cmd), + $filter_fields, + array_fill(0, count($filter_fields), true), + true, + true); + } + + private function getFilterData() : array + { + try { + return $this->filter_service->getData($this->filter) ?? []; + } catch (InvalidArgumentException $e) { + return []; + } + } + + protected function fetchData() : array + { + global $DIC; + + $ilDB = $DIC->database(); + $where_sql = $this->sql["where"]; + + // apply only set filters + $active_filters = $this->getActiveFilters(); + + $params = array(); + + // build where sql + foreach ($active_filters as $id => $filter) { + $filter_field = $this->filter_fields[$id]; + if (strlen($filter_field["sql_expr"]) != 0) { + $sql_expr = $filter_field["sql_expr"]; + $operator = (strlen($filter_field["operator"]) > 0) ? $filter_field["operator"] : "="; + $value = $filter; + $where_sql = $where_sql . ((strlen($where_sql) > 0) ? " AND " . $sql_expr : $sql_expr); + $where_sql = $where_sql . " " . $operator; + switch ($operator) { + case $this::OPR_LIKE: + case $this::OPR_NOT_LIKE: + $value = "%" . $value . "%"; + break; + default: + } + $where_sql = $where_sql . " ? "; + $params[] = $value; + } + } + + $sql_str = "SELECT " . $this->sql["select"] . " FROM " . $this->sql["from"]; + if (strlen($where_sql) > 0) { + $sql_str .= " WHERE " . $where_sql; + } + if (strlen($this->sql["order_by"]) > 0) { + $sql_str .= " ORDER BY " . $this->sql["order_by"]; + } + + // run prepared query if any params + if (count($params) > 0) { + $stmt = $ilDB->prepare($sql_str); + $r = $stmt->execute($params); + } else { + $r = $ilDB->query($sql_str); + } + + $arr = array(); + if ($ilDB->numRows($r) > 0) { + while ($row = $ilDB->fetchAssoc($r)) { + $arr[] = $row; + } + } + + return $arr; + } + + protected function getActiveFilters() + { + // apply only set filters + $active_filters = array_filter($this->getFilterData(), static function ($value) : bool { + return !empty($value); + }); + return $active_filters; + } + + private function applyFilter(array $arr, array $filter_fields) : array + { + + // apply only set filters + $active_filters = $this->getActiveFilters(); + $filter_fields = $this->filter_fields; + $self = $this; + + // apply filters + $arr = array_filter($arr, + static function (array $arr_data) use ($active_filters, $filter_fields, $self) : bool { + + $matches_filter = true; + + foreach ($active_filters as $id => $filter) { + $filter_field = $filter_fields[$id]; + $sql_expr = $filter_field["sql_expr"]; + if (strlen($filter_field["sql_expr"]) == 0) { + $operator = (strlen($filter_field["operator"]) > 0) ? $filter_field["operator"] : "="; + $value = $filter; + switch ($operator) { + case $self::OPR_EQUALS: + $matches_filter = $matches_filter && ($arr_data[$id] == $value); + break; + case $self::OPR_NOT_EQUALS: + $matches_filter = $matches_filter && ($arr_data[$id] != $value); + break; + case $self::OPR_LESS_THAN: + $matches_filter = $matches_filter && ($arr_data[$id] < $value); + break; + case $self::OPR_GREATER_THAN: + $matches_filter = $matches_filter && ($arr_data[$id] > $value); + break; + case $self::OPR_LIKE: + $matches_filter = $matches_filter && (strpos($arr_data[$id], $value) !== false); + break; + case $self::OPR_NOT_LIKE: + $matches_filter = $matches_filter && (strpos($arr_data[$id], $value) === false); + break; + default: + } + } + + if (!$matches_filter) { + break; + } + } + return $matches_filter; + }); + + return $arr; + } + + private function getFilterHTML() : string + { + return $this->renderer->render($this->filter); + } + + public function getHTML() + { + $this->setFilter($this->parent, $this->parent_cmd, $this->getId(), + $this->getFilterInputFields($this->filter_fields)); + + // get data and apply filters + $arr = $this->fetchData(); + $arr = $this->applyFilter($arr, $this->filter_fields); + $this->setData($arr); + + // return filter and table html + return $this->getFilterHTML() . parent::getHTML(); + } + + protected function fillRow($a_set) + { + foreach ($this->columns as $column) { + $this->tpl->setVariable("VAL_COLUMN", $a_set[$column["sort_field"]]); + $this->tpl->setCurrentBlock("column"); + $this->tpl->parseCurrentBlock(); + } + } +} \ No newline at end of file diff --git a/classes/class.ilHSLUUIDefaultsGlobalScreenMenuProvider.php b/classes/class.ilHSLUUIDefaultsGlobalScreenMenuProvider.php new file mode 100644 index 0000000..59a1bac --- /dev/null +++ b/classes/class.ilHSLUUIDefaultsGlobalScreenMenuProvider.php @@ -0,0 +1,43 @@ +dic->globalScreen()->mainBar(); + $id_provider_factory = $this->dic->globalScreen()->identification()->plugin($this->getPluginID(), $this); + + // Some needed classes from the Dependency Injection Container (DIC) + $ctrl = $this->dic->ctrl(); + $user = $this->dic->user(); + $access_checker = new ilHSLUUIDefaultsAccessChecker($this->dic->rbac()->review()); + + // Menu items we want to provide + $menu_items = []; + + // Build URL for the dashboard page in 'ilHSLUUIDefaultsCtrlRoutingGUI' + $link = $ctrl->getLinkTargetByClass(ilHSLUUIDefaultsCtrlRoutingGUI::CTRL_UI_ROUTE, ilHSLUUIDefaultsCtrlRoutingGUI::CMD_DASHBOARD_PAGE); + + // Build and add menu item + $dashboard_identification = $id_provider_factory->identifier('hslu_dashboard'); + $menu_items[] = $menu_item_factory->link( + $dashboard_identification + ) + ->withTitle($this->plugin->txt('hslu_dashboard')) + ->withAction($link) + ->withVisibilityCallable( + function() use ($access_checker, $user){ + return $access_checker->checkIfAdminRoleIsDefinedAndUserIsAdmin($user); + } + ); + + return $menu_items; + } +} \ No newline at end of file diff --git a/classes/class.ilHSLUUIDefaultsPlugin.php b/classes/class.ilHSLUUIDefaultsPlugin.php index 658b33d..d5bed3a 100644 --- a/classes/class.ilHSLUUIDefaultsPlugin.php +++ b/classes/class.ilHSLUUIDefaultsPlugin.php @@ -26,6 +26,9 @@ public function __construct() $this->provider_collection ->setModificationProvider(new ilHSLUUIDefaultsGlobalScreenModificationProvider($DIC, $this)); + + $this->provider_collection + ->setMainBarProvider(new ilHSLUUIDefaultsGlobalScreenMenuProvider($DIC, $this)); } public function getPluginName() diff --git a/lang/ilias_de.lang b/lang/ilias_de.lang index 94ea733..724c8f4 100644 --- a/lang/ilias_de.lang +++ b/lang/ilias_de.lang @@ -5,5 +5,19 @@ back_link#:#Ebene hoch categories_with_fav_link#:#Kategorien mit Link zu Favoriten categories_with_fav_link_desc#:#Diese Kategorien zeigen einen Link zu den Favoriten statt einen "Ebene hoch"-Link. +evento_id#:#Evento ID +evento_log#:#Evento Log favorite_link#:#Zu Favoriten +hslu_dashboard#:#HSLU Dashboard +last_import_data#:#Last Import Data +last_import_date#:#Last Import Date +obj_id#:#Obj Id +objects#:#Objects +path#:#Path +ref_id#:#Ref Id +tab_blank#:#Leerer Tab +tab_dashboard#:#Dashboard +tab_table#:#Tabelle +title#:#Titel +type#:#Type xcwi_back_link#:#Kursvorlagen Übersicht \ No newline at end of file diff --git a/lang/ilias_en.lang b/lang/ilias_en.lang index c08d10b..6c02995 100644 --- a/lang/ilias_en.lang +++ b/lang/ilias_en.lang @@ -5,5 +5,12 @@ back_link#:#Up categories_with_fav_link#:#Categories with Link to Favourites categories_with_fav_link_desc#:#These categories will show a link back to favourites instead of a up-link. +evento_id#:#Evento ID favorite_link#:#To Favorites +hslu_dashboard#:#HSLU Dashboard +last_import_data#:#Last Import Data +last_import_date#:#Last Import Date +tab_blank#:#Blank Tab +tab_dashboard#:#Dashboard +tab_table#:#Table xcwi_back_link#:#Course Template Overview \ No newline at end of file diff --git a/plugin.php b/plugin.php index 6431638..555ea0a 100644 --- a/plugin.php +++ b/plugin.php @@ -4,7 +4,7 @@ $id = "hsluuidef"; // code version; must be changed for all code changes -$version = "1.0.2"; +$version = "1.0.3"; // ilias min and max version; must always reflect the versions that should // run with the plugin diff --git a/templates/default/tpl.table_row.html b/templates/default/tpl.table_row.html new file mode 100644 index 0000000..be9fd93 --- /dev/null +++ b/templates/default/tpl.table_row.html @@ -0,0 +1,11 @@ + + + {VAL_EVENTO_ID} + + + {VAL_LAST_IMPORT_DATA} + + + {VAL_LAST_IMPORT_DATE} + + diff --git a/templates/default/tpl.table_row_single_column.html b/templates/default/tpl.table_row_single_column.html new file mode 100644 index 0000000..11b1cb3 --- /dev/null +++ b/templates/default/tpl.table_row_single_column.html @@ -0,0 +1,3 @@ + + {VAL_COLUMN} +