1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once("./Services/UIComponent/Explorer2/classes/class.ilTreeExplorerGUI.php");
5
6/**
7 * Repository explorer GUI class
8 *
9 * @author	Alex Killing <alex.killing@gmx.de>
10 * @version	$Id$
11 *
12 * @todo: isClickable, top node id
13 *
14 * @ingroup ServicesRepository
15 */
16class ilRepositoryExplorerGUI extends ilTreeExplorerGUI
17{
18    /**
19     * @var ilSetting
20     */
21    protected $settings;
22
23    /**
24     * @var ilObjectDefinition
25     */
26    protected $obj_definition;
27
28    /**
29     * @var ilLanguage
30     */
31    protected $lng;
32
33    /**
34     * @var ilCtrl
35     */
36    protected $ctrl;
37
38    /**
39     * @var ilAccessHandler
40     */
41    protected $access;
42
43    /**
44     * @var ilRbacSystem
45     */
46    protected $rbacsystem;
47
48    /**
49     * @var ilDB
50     */
51    protected $db;
52
53    /**
54     * @var ilObjUser
55     */
56    protected $user;
57
58    protected $type_grps = array();
59    protected $session_materials = array();
60
61    protected $parent_node_id = [];
62    protected $node_data = [];
63
64    /**
65     * Constructor
66     */
67    public function __construct($a_parent_obj, $a_parent_cmd)
68    {
69        global $DIC;
70
71        $this->tree = $DIC->repositoryTree();
72        $this->settings = $DIC->settings();
73        $this->obj_definition = $DIC["objDefinition"];
74        $this->lng = $DIC->language();
75        $this->ctrl = $DIC->ctrl();
76        $this->access = $DIC->access();
77        $this->rbacsystem = $DIC->rbac()->system();
78        $this->db = $DIC->database();
79        $this->user = $DIC->user();
80        $tree = $DIC->repositoryTree();
81        $ilSetting = $DIC->settings();
82        $objDefinition = $DIC["objDefinition"];
83
84        $this->cur_ref_id = (int) $_GET["ref_id"];
85
86        $this->top_node_id = 0;
87        if ($ilSetting->get("rep_tree_limit_grp_crs") && $this->cur_ref_id > 0) {
88            $path = $tree->getPathId($this->cur_ref_id);
89            foreach ($path as $n) {
90                if ($top_node > 0) {
91                    break;
92                }
93                if (in_array(
94                    ilObject::_lookupType(ilObject::_lookupObjId($n)),
95                    array("crs", "grp")
96                )) {
97                    $this->top_node_id = $n;
98                }
99            }
100        }
101
102        parent::__construct("rep_exp", $a_parent_obj, $a_parent_cmd, $tree);
103
104        $this->setSkipRootNode(false);
105        $this->setNodeOpen($this->tree->readRootId());
106        $this->setAjax(true);
107        $this->setOrderField("title");
108        if ($ilSetting->get("repository_tree_pres") == "" ||
109            ($ilSetting->get("rep_tree_limit_grp_crs") && $this->top_node_id == 0)) {
110            $this->setTypeWhiteList($objDefinition->getExplorerContainerTypes());
111        } elseif ($ilSetting->get("repository_tree_pres") == "all_types") {
112            $white = array();
113            foreach ($objDefinition->getSubObjectsRecursively("root") as $rtype) {
114                if (/* $rtype["name"] != "itgr" && */ !$objDefinition->isSideBlock($rtype["name"])) {
115                    $white[] = $rtype["name"];
116                }
117            }
118            $this->setTypeWhiteList($white);
119        }
120        if ((int) $_GET["ref_id"] > 0) {
121            $this->setPathOpen((int) $_GET["ref_id"]);
122        }
123
124        $this->setChildLimit((int) $ilSetting->get("rep_tree_limit_number"));
125    }
126
127    /**
128     * Get root node
129     *
130     * @param
131     * @return
132     */
133    public function getRootNode()
134    {
135        if ($this->top_node_id > 0) {
136            $root_node = $this->getTree()->getNodeData($this->top_node_id);
137        } else {
138            $root_node = parent::getRootNode();
139        }
140        $this->node_data[$root_node["child"]] = $root_node;
141        return $root_node;
142    }
143
144    /**
145     * Get node content
146     *
147     * @param array
148     * @return
149     */
150    public function getNodeContent($a_node)
151    {
152        $lng = $this->lng;
153
154        $title = $a_node["title"];
155
156        if ($a_node["child"] == $this->getNodeId($this->getRootNode())) {
157            if ($title == "ILIAS") {
158                $title = $lng->txt("repository");
159            }
160        } elseif ($a_node["type"] == "sess" &&
161            !trim($title)) {
162            // #14367 - see ilObjSessionListGUI
163            include_once('./Modules/Session/classes/class.ilSessionAppointment.php');
164            $app_info = ilSessionAppointment::_lookupAppointment($a_node["obj_id"]);
165            $title = ilSessionAppointment::_appointmentToString($app_info['start'], $app_info['end'], $app_info['fullday']);
166        }
167
168        return $title;
169    }
170
171    /**
172     * Get node icon
173     *
174     * @param array
175     * @return
176     */
177    public function getNodeIcon($a_node)
178    {
179        $obj_id = ilObject::_lookupObjId($a_node["child"]);
180        return ilObject::_getIcon($obj_id, "tiny", $a_node["type"]);
181    }
182
183    /**
184     * Get node icon alt text
185     *
186     * @param array node array
187     * @return string alt text
188     */
189    public function getNodeIconAlt($a_node)
190    {
191        $lng = $this->lng;
192
193        if ($a_node["child"] == $this->getNodeId($this->getRootNode())) {
194            $title = $a_node["title"];
195            if ($title == "ILIAS") {
196                $title = $lng->txt("repository");
197            }
198            return $title;
199        }
200
201        $lng = $this->lng;
202        return $lng->txt("obj_" . $a_node["type"]) . ": " . $this->getNodeContent($a_node);
203    }
204
205    /**
206     * Is node highlighted?
207     *
208     * @param mixed $a_node node object/array
209     * @return boolean node visible true/false
210     */
211    public function isNodeHighlighted($a_node)
212    {
213        if ($a_node["child"] == $_GET["ref_id"] ||
214            ($_GET["ref_id"] == "" && $a_node["child"] == $this->getNodeId($this->getRootNode()))) {
215            return true;
216        }
217        return false;
218    }
219
220    /**
221     * Get href for node
222     *
223     * @param mixed $a_node node object/array
224     * @return string href attribute
225     */
226    public function getNodeHref($a_node)
227    {
228        $ilCtrl = $this->ctrl;
229
230        switch ($a_node["type"]) {
231            case "root":
232                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
233                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "");
234                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
235                return $link;
236
237            case "cat":
238                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
239                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "");
240                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
241                return $link;
242
243            case "catr":
244                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
245                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "redirect");
246                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
247                return $link;
248
249            case "grp":
250                $ilCtrl->setParameterByClass("ilobjgroupgui", "ref_id", $a_node["child"]);
251                $link = $ilCtrl->getLinkTargetByClass(array("ilrepositorygui", "ilobjgroupgui"), "");
252                $ilCtrl->setParameterByClass("ilobjgroupgui", "ref_id", $_GET["ref_id"]);
253                return $link;
254
255            case "grpr":
256                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
257                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "redirect");
258                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
259                return $link;
260
261            case "crs":
262                $ilCtrl->setParameterByClass("ilobjcoursegui", "ref_id", $a_node["child"]);
263                $link = $ilCtrl->getLinkTargetByClass(array("ilrepositorygui", "ilobjcoursegui"), "view");
264                $ilCtrl->setParameterByClass("ilobjcoursegui", "ref_id", $_GET["ref_id"]);
265                return $link;
266
267            case "crsr":
268                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
269                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "redirect");
270                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
271                return $link;
272
273            case 'rcrs':
274                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
275                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "infoScreen");
276                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
277                return $link;
278
279            case 'prg':
280                $ilCtrl->setParameterByClass("ilobjstudyprogrammegui", "ref_id", $a_node["child"]);
281                $link = $ilCtrl->getLinkTargetByClass(array("ilrepositorygui", "ilobjstudyprogrammegui"), "view");
282                $ilCtrl->setParameterByClass("ilobjstudyprogrammegui", "ref_id", $_GET["ref_id"]);
283                return $link;
284            case "prgr":
285                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $a_node["child"]);
286                $link = $ilCtrl->getLinkTargetByClass("ilrepositorygui", "redirect");
287                $ilCtrl->setParameterByClass("ilrepositorygui", "ref_id", $_GET["ref_id"]);
288                return $link;
289
290            default:
291                include_once('./Services/Link/classes/class.ilLink.php');
292                return ilLink::_getStaticLink($a_node["child"], $a_node["type"], true);
293
294        }
295    }
296
297    /**
298     * Is node visible
299     *
300     * @param
301     * @return
302     */
303    public function isNodeVisible($a_node)
304    {
305        $ilAccess = $this->access;
306        $tree = $this->tree;
307        $ilSetting = $this->settings;
308
309        if (!$ilAccess->checkAccess('visible', '', $a_node["child"])) {
310            return false;
311        }
312
313        if ($ilSetting->get("repository_tree_pres") == "all_types") {
314            /*$container_parent_id = $tree->checkForParentType($a_node["child"], 'grp');
315            if (!$container_parent_id) {
316                $container_parent_id = $tree->checkForParentType($a_node["child"], 'crs');
317            }*/
318            // see #21215
319            $container_parent_id = $this->getParentCourseOrGroup($a_node["child"]);
320            if ($container_parent_id > 0) {
321                // do not display session materials for container course/group
322                if ($container_parent_id != $a_node["child"]) {
323                    // get container event items only once
324                    if (!isset($this->session_materials[$container_parent_id])) {
325                        include_once './Modules/Session/classes/class.ilEventItems.php';
326                        $this->session_materials[$container_parent_id] = ilEventItems::_getItemsOfContainer($container_parent_id);
327                    }
328                    if (in_array($a_node["child"], $this->session_materials[$container_parent_id])) {
329                        return false;
330                    }
331                }
332            }
333        }
334
335        return true;
336    }
337
338    /**
339     * Get upper course or group
340     *
341     * @param int $node_id
342     * @return int
343     */
344    protected function getParentCourseOrGroup($node_id)
345    {
346        $current_node_id = $node_id;
347        while (isset($this->parent_node_id[$current_node_id])) {
348            $parent_node_id = $this->parent_node_id[$current_node_id];
349            if (isset($this->node_data[$parent_node_id]) && in_array($this->node_data[$parent_node_id]["type"], ["grp", "crs"])) {
350                return $parent_node_id;
351            }
352            $current_node_id = $parent_node_id;
353        }
354        return 0;
355    }
356
357
358    /**
359     * Sort childs
360     *
361     * @param array $a_childs array of child nodes
362     * @param mixed $a_parent_node parent node
363     *
364     * @return array array of childs nodes
365     */
366    public function sortChilds($a_childs, $a_parent_node_id)
367    {
368        $objDefinition = $this->obj_definition;
369        $ilAccess = $this->access;
370
371        $parent_obj_id = ilObject::_lookupObjId($a_parent_node_id);
372        if ($parent_obj_id > 0) {
373            $parent_type = ilObject::_lookupType($parent_obj_id);
374        } else {
375            $parent_type = "dummy";
376            $this->type_grps["dummy"] = array("root" => "dummy");
377        }
378
379        // alex: if this is not initialized, things are messed up
380        // see bug 0015978
381        $this->type_grps = array();
382
383        if (empty($this->type_grps[$parent_type])) {
384            $this->type_grps[$parent_type] =
385                $objDefinition->getGroupedRepositoryObjectTypes($parent_type);
386        }
387
388        // #14465 - item groups
389        include_once('./Services/Object/classes/class.ilObjectActivation.php');
390        $group = array();
391        $igroup = array(); // used for item groups, see bug #0015978
392        $in_any_group = array();
393        foreach ($a_childs as $child) {
394            // item group: get childs
395            if ($child["type"] == "itgr") {
396                $g = $child["child"];
397                $items = ilObjectActivation::getItemsByItemGroup($g);
398                if ($items) {
399                    // add item group ref id to item group block
400                    $this->type_grps[$parent_type]["itgr"]["ref_ids"][] = $g;
401
402                    // #16697 - check item group permissions
403                    $may_read = $ilAccess->checkAccess('read', '', $g);
404
405                    // see bug #0015978
406                    if ($may_read) {
407                        include_once("./Services/Container/classes/class.ilContainerSorting.php");
408                        $items = ilContainerSorting::_getInstance($parent_obj_id)->sortSubItems('itgr', $child["obj_id"], $items);
409                    }
410
411                    foreach ($items as $item) {
412                        $in_any_group[] = $item["child"];
413
414                        if ($may_read) {
415                            $igroup[$g][] = $item;
416                            $group[$g][] = $item;
417                        }
418                    }
419                }
420            }
421            // type group
422            else {
423                $g = $objDefinition->getGroupOfObj($child["type"]);
424                if ($g == "") {
425                    $g = $child["type"];
426                }
427                $group[$g][] = $child;
428            }
429        }
430
431        $in_any_group = array_unique($in_any_group);
432
433        // custom block sorting?
434        include_once("./Services/Container/classes/class.ilContainerSorting.php");
435        $sort = ilContainerSorting::_getInstance($parent_obj_id);
436        $block_pos = $sort->getBlockPositions();
437        if (is_array($block_pos) && count($block_pos) > 0) {
438            $tmp = $this->type_grps[$parent_type];
439
440            $this->type_grps[$parent_type] = array();
441            foreach ($block_pos as $block_type) {
442                // type group
443                if (!is_numeric($block_type) &&
444                    array_key_exists($block_type, $tmp)) {
445                    $this->type_grps[$parent_type][$block_type] = $tmp[$block_type];
446                    unset($tmp[$block_type]);
447                }
448                // item group
449                else {
450                    // using item group ref id directly
451                    $this->type_grps[$parent_type][$block_type] = array();
452                }
453            }
454
455            // append missing
456            if (sizeof($tmp)) {
457                foreach ($tmp as $block_type => $grp) {
458                    $this->type_grps[$parent_type][$block_type] = $grp;
459                }
460            }
461
462            unset($tmp);
463        }
464
465        $childs = array();
466        $done = array();
467
468        foreach ($this->type_grps[$parent_type] as $t => $g) {
469            // type group
470            if (is_array($group[$t])) {
471                // see bug #0015978
472                // custom sorted igroups
473                if (is_array($igroup[$t])) {
474                    foreach ($igroup[$t] as $k => $item) {
475                        if (!in_array($item["child"], $done)) {
476                            $childs[] = $item;
477                            $done[] = $item["child"];
478                        }
479                    }
480                } else {
481                    // do we have to sort this group??
482                    include_once("./Services/Container/classes/class.ilContainer.php");
483                    include_once("./Services/Container/classes/class.ilContainerSorting.php");
484                    $sort = ilContainerSorting::_getInstance($parent_obj_id);
485                    $group = $sort->sortItems($group);
486
487                    // need extra session sorting here
488                    if ($t == "sess") {
489                    }
490
491                    foreach ($group[$t] as $k => $item) {
492                        if (!in_array($item["child"], $done) &&
493                            !in_array($item["child"], $in_any_group)) { // #16697
494                            $childs[] = $item;
495                            $done[] = $item["child"];
496                        }
497                    }
498                }
499            }
500            // item groups (if not custom block sorting)
501            elseif ($t == "itgr" &&
502                is_array($g["ref_ids"])) {
503                foreach ($g["ref_ids"] as $ref_id) {
504                    if (isset($group[$ref_id])) {
505                        foreach ($group[$ref_id] as $k => $item) {
506                            if (!in_array($item["child"], $done)) {
507                                $childs[] = $item;
508                                $done[] = $item["child"];
509                            }
510                        }
511                    }
512                }
513            }
514        }
515
516        return $childs;
517    }
518
519    /**
520     * Get childs of node
521     *
522     * @param
523     * @return
524     */
525    public function getChildsOfNode($a_parent_node_id)
526    {
527        $rbacsystem = $this->rbacsystem;
528
529        if (!$rbacsystem->checkAccess("read", $a_parent_node_id)) {
530            return array();
531        }
532
533        $obj_id = ilObject::_lookupObjId($a_parent_node_id);
534        if (!ilConditionHandler::_checkAllConditionsOfTarget($a_parent_node_id, $obj_id)) {
535            return array();
536        }
537
538        $childs = parent::getChildsOfNode($a_parent_node_id);
539
540        foreach ($childs as $c) {
541            $this->parent_node_id[$c["child"]] = $a_parent_node_id;
542            $this->node_data[$c["child"]] = $c;
543        }
544
545        return $childs;
546    }
547
548    /**
549     * Is node clickable?
550     *
551     * @param mixed $a_node node object/array
552     * @return boolean node clickable true/false
553     */
554    public function isNodeClickable($a_node)
555    {
556        $rbacsystem = $this->rbacsystem;
557        $tree = $this->tree;
558        $ilDB = $this->db;
559        $ilUser = $this->user;
560        $ilAccess = $this->access;
561
562        $obj_id = ilObject::_lookupObjId($a_node["child"]);
563        if (!ilConditionHandler::_checkAllConditionsOfTarget($a_node["child"], $obj_id)) {
564            return false;
565        }
566
567        switch ($a_node["type"]) {
568            case 'tst':
569                if (!$rbacsystem->checkAccess("read", $a_node["child"])) {
570                    return false;
571                }
572
573                $query = sprintf("SELECT * FROM tst_tests WHERE obj_fi=%s", $obj_id);
574                $res = $ilDB->query($query);
575                while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
576                    return (bool) $row->complete;
577                }
578                return false;
579
580            case 'svy':
581                if (!$rbacsystem->checkAccess("read", $a_node["child"])) {
582                    return false;
583                }
584
585                $query = sprintf("SELECT * FROM svy_svy WHERE obj_fi=%s", $obj_id);
586                $res = $ilDB->query($query);
587                while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
588                    return (bool) $row->complete;
589                }
590                return false;
591
592            // media pools can only be edited
593            case "mep":
594                if ($rbacsystem->checkAccess("read", $a_node["child"])) {
595                    return true;
596                } else {
597                    return false;
598                }
599                break;
600            case 'grpr':
601            case 'crsr':
602            case 'catr':
603                include_once('./Services/ContainerReference/classes/class.ilContainerReferenceAccess.php');
604                return ilContainerReferenceAccess::_isAccessible($a_node["child"]);
605
606            case 'prg':
607                    return $rbacsystem->checkAccess("read", $a_node["child"]);
608
609            // all other types are only clickable, if read permission is given
610            default:
611                if ($rbacsystem->checkAccess("read", $a_node["child"])) {
612                    // check if lm is online
613                    if ($a_node["type"] == "lm") {
614                        include_once("./Modules/LearningModule/classes/class.ilObjLearningModule.php");
615                        $lm_obj = new ilObjLearningModule($a_node["child"]);
616                        if (($lm_obj->getOfflineStatus()) && (!$rbacsystem->checkAccess('write', $a_node["child"]))) {
617                            return false;
618                        }
619                    }
620                    // check if fblm is online
621                    if ($a_node["type"] == "htlm") {
622                        include_once("./Modules/HTMLLearningModule/classes/class.ilObjFileBasedLM.php");
623                        $lm_obj = new ilObjFileBasedLM($a_node["child"]);
624                        if (($lm_obj->getOfflineStatus()) && (!$rbacsystem->checkAccess('write', $a_node["child"]))) {
625                            return false;
626                        }
627                    }
628                    // check if fblm is online
629                    if ($a_node["type"] == "sahs") {
630                        include_once("./Modules/ScormAicc/classes/class.ilObjSAHSLearningModule.php");
631                        $lm_obj = new ilObjSAHSLearningModule($a_node["child"]);
632                        if (($lm_obj->getOfflineStatus()) && (!$rbacsystem->checkAccess('write', $a_node["child"]))) {
633                            return false;
634                        }
635                    }
636                    // check if glossary is online
637                    if ($a_node["type"] == "glo") {
638                        $obj_id = ilObject::_lookupObjectId($a_node["child"]);
639                        if ((!ilObjGlossary::_lookupOnline($obj_id)) &&
640                            (!$rbacsystem->checkAccess('write', $a_node["child"]))) {
641                            return false;
642                        }
643                    }
644
645                    return true;
646                } else {
647                    return false;
648                }
649                break;
650        }
651    }
652}
653