diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /lib/models/HelpTour.php | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/models/HelpTour.php')
| -rw-r--r-- | lib/models/HelpTour.php | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/lib/models/HelpTour.php b/lib/models/HelpTour.php new file mode 100644 index 0000000..978e203 --- /dev/null +++ b/lib/models/HelpTour.php @@ -0,0 +1,407 @@ +<?php +// +---------------------------------------------------------------------------+ +// This file is part of Stud.IP +// +// Copyright (C) 2014 Arne Schröder <schroeder@data-quest>, +// Suchi & Berg GmbH <info@data-quest.de> +// +---------------------------------------------------------------------------+ +// 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 the Free Software Foundation; either version 2 +// of the License, or any later version. +// +---------------------------------------------------------------------------+ +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +---------------------------------------------------------------------------+ +require_once 'lib/object.inc.php'; + +/** + * HelpTour.php - model class for Stud.IP tours + * + * + * + * + * @author Arne Schröder <schroeder@data-quest> + * @access public + * + * @property string $id alias column for tour_id + * @property string $global_tour_id database column + * @property string $tour_id database column + * @property string $name database column + * @property string $description database column + * @property string $type database column + * @property string $roles database column + * @property int $version database column + * @property string $language database column + * @property string $studip_version database column + * @property string $installation_id database column + * @property string $author_email database column + * @property int $mkdate database column + * @property int $chdate database column + * @property SimpleORMapCollection|HelpTourStep[] $steps has_many HelpTourStep + * @property SimpleORMapCollection|HelpTourAudience[] $audiences has_many HelpTourAudience + * @property HelpTourSettings $settings has_one HelpTourSettings + * @property User $author has_one User + */ +class HelpTour extends SimpleORMap +{ + protected static function configure($config = []) + { + $config['db_table'] = 'help_tours'; + + $config['has_one']['settings'] = [ + 'class_name' => HelpTourSettings::class, + 'assoc_foreign_key' => 'tour_id', + 'on_delete' => 'delete', + 'on_store' => 'store', + ]; + $config['has_many']['steps'] = [ + 'class_name' => HelpTourStep::class, + 'assoc_foreign_key' => 'tour_id', + 'on_delete' => 'delete', + 'on_store' => 'store', + ]; + $config['has_many']['audiences'] = [ + 'class_name' => HelpTourAudience::class, + 'assoc_foreign_key' => 'tour_id', + 'on_delete' => 'delete', + 'on_store' => 'store', + ]; + $config['has_one']['author'] = [ + 'class_name' => User::class, + 'foreign_key' => 'author_email', + 'assoc_func' => 'findOneByEmail', + ]; + + $config['registered_callbacks']['before_store'][] = 'cbUpdateStudipVersion'; + + parent::configure($config); + } + + + public function cbUpdateStudipVersion() + { + $this->studip_version = StudipVersion::getStudipVersion(); + } + + + /** + * get visible tours for helpbar + * + * @return array set of tours + */ + public static function GetHelpbarTourData() + { + $visible_tours = []; + $active_tour_id = null; + $active_tour_step_nr = 0; + $route = get_route(); + $tours = HelpTour::getToursByRoute($route); + foreach($tours as $index => $tour) { + if ($tour->isVisible() && ($tour->settings->access !== 'link')) { + $visible_tours[$index] = $tour; + if (in_array($tour->settings->access, ['autostart', 'autostart_once']) && !$GLOBALS['user']->cfg->TOUR_AUTOSTART_DISABLE) { + $user_visit = new HelpTourUser([$tour->tour_id, $GLOBALS['user']->user_id]); + if ($tour->settings->access === 'autostart_once' && $user_visit->isNew()) { + $active_tour_id = $tour->tour_id; + $active_tour_step_nr = 1; + } elseif ($tour->settings->access === 'autostart' && !$user_visit->completed) { + $active_tour_id = $tour->tour_id; + $active_tour_step_nr = 1; + } + } + } + } + + //if there is an active tour, initialize it + if (isset($_SESSION['active_tour']['tour_id']) + && ($_SESSION['active_tour']['last_route'] === $route + || $_SESSION['active_tour']['next_route'] === $route)) + { + $active_tour = new HelpTour($_SESSION['active_tour']['tour_id']); + $step_nr = $_SESSION['active_tour']['step_nr']; + if ($_SESSION['active_tour']['last_route'] !== $route && $_SESSION['active_tour']['next_route'] === $route) { + while ($_SESSION['active_tour']['last_route'] === $active_tour->steps[$step_nr - 1]->route) { + $step_nr += 1; + } + } + if ($route === $active_tour->steps[$step_nr - 1]->route) { + $_SESSION['active_tour']['step_nr'] = $step_nr; + $active_tour_id = $_SESSION['active_tour']['tour_id']; + $active_tour_step_nr = $step_nr; + } + } + return [ + 'tours' => $visible_tours, + 'active_tour_id' => $active_tour_id, + 'active_tour_step_nr' => $active_tour_step_nr, + ]; + } + + /** + * fetches set of tours from database for given route + * + * @param string $route route for tours to begin + * @param boolean $as_objects include HelpTour objects in result array + * @return array set of tours + */ + public static function GetToursByRoute($route = '') + { + if (!$route) { + $route = get_route(); + } + $query = "SELECT tour_id AS idx, help_tours.* + FROM help_tour_steps + INNER JOIN help_tours USING (tour_id) + WHERE route = ? AND step = 1 + ORDER BY name ASC"; + $statement = DBManager::get()->prepare($query); + $statement->execute([$route]); + $ret = $statement->fetchGrouped(PDO::FETCH_ASSOC); + + return HelpTour::GetTourObjects($ret); + } + + /** + * fetches set of tours from database filtered by parameters + * + * @param string $term search term for tour name + * @param boolean $as_objects include HelpTour objects in result array + * @return array set of tours + */ + public static function GetToursByFilter($term = '') + { + $params = []; + $condition = ''; + if (mb_strlen(trim($term)) >= 3) { + $condition = "WHERE name LIKE CONCAT('%', ?, '%')"; + $params[] = $term; + } + $query = "SELECT tour_id AS idx, help_tours.* + FROM help_tours + {$condition} + ORDER BY name ASC"; + $statement = DBManager::get()->prepare($query); + $statement->execute($params); + $ret = $statement->fetchGrouped(PDO::FETCH_ASSOC); + + return HelpTour::GetTourObjects($ret); + } + + /** + * fetches tour conflicts + * + * @return array set of tour objects + */ + public static function GetConflicts() + { + $conflicts = []; + $query = "SELECT tour_id AS idx, help_tours.* + FROM help_tours + WHERE installation_id = ? + ORDER BY name ASC"; + $statement = DBManager::get()->prepare($query); + $statement->execute([Config::get()->STUDIP_INSTALLATION_ID]); + $ret = $statement->fetchGrouped(PDO::FETCH_ASSOC); + foreach ($ret as $index => $data) { + $query = "SELECT tour_id AS idx, help_tours.* + FROM help_tours + WHERE global_tour_id = ? + AND language = ? + AND studip_version >= ? + AND installation_id <> ? + ORDER BY studip_version DESC + LIMIT 1"; + $statement = DBManager::get()->prepare($query); + $statement->execute([ + $data['global_tour_id'], + $data['language'], + $data['studip_version'], + Config::get()->STUDIP_INSTALLATION_ID, + ]); + $ret2 = $statement->fetchGrouped(PDO::FETCH_ASSOC); + if (count($ret2) > 0) { + $conflicts[] = HelpTour::GetTourObjects(array_merge([$index => $data], $ret2)); + } + } + return $conflicts; + } + + /** + * builds tour objects for given set of tour data + * + * @param array $tour_result tour set + * @return array set of tour objects + */ + public static function GetTourObjects($tour_result) + { + $objects = []; + if (is_array($tour_result)){ + foreach($tour_result as $id => $result){ + $objects[$id] = new HelpTour(); + $objects[$id]->setData($result, true); + $objects[$id]->setNew(false); + } + } + return $objects; + } + + /** + * checks if tour is visible for current user + */ + public function isVisible() + { + if (!$this->settings->active) { + return false; + } + + if (!$GLOBALS['user']->preferred_language) { + $language = mb_substr(Config::get()->DEFAULT_LANGUAGE, 0, 2); + } else { + $language = mb_substr($GLOBALS['user']->preferred_language, 0, 2); + } + if ($language !== $this->language) { + return false; + } + + $current_role = User::findCurrent() ? User::findCurrent()->perms : 'nobody'; + if (mb_strpos($this->roles, $current_role) === false) { + return false; + } + foreach ($this->audiences as $audience) { + switch ($audience->type) { + case 'inst': + $table_name = 'user_inst'; + $field_name = 'Institut_id'; + break; + case 'sem': + $table_name = 'seminar_user'; + $field_name = 'Seminar_id'; + break; + case 'studiengang': + $table_name = 'user_studiengang'; + $field_name = 'fach_id'; + break; + case 'abschluss': + $table_name = 'user_studiengang'; + $field_name = 'abschluss_id'; + break; + case 'userdomain': + $table_name = 'user_userdomains'; + $field_name = 'userdomain_id'; + break; + } + if ($audience->range_id && $table_name) { + $query = "SELECT * + FROM {$table_name} + WHERE user_id = ? + AND {$field_name} = ?"; + $items = [$GLOBALS['user']->user_id, $audience->range_id]; + $statement = DBManager::get()->prepare($query); + $statement->execute($items); + $ret = $statement->fetchOne(PDO::FETCH_ASSOC); + if (!count($ret)) { + return false; + } + } elseif ($table_name) { + $query = "SELECT * FROM {$table_name} WHERE user_id = ?"; + $items = [$GLOBALS['user']->user_id]; + $statement = DBManager::get()->prepare($query); + $statement->execute($items); + $ret = $statement->fetchOne(PDO::FETCH_ASSOC); + if (count($ret)) { + return false; + } + } + } + return true; + } + + /** + * adds step to the tour and rearranges existing steps + */ + public function addStep($data, $position = 0) + { + $step = new HelpTourStep(); + $step->setData($data, true); + if ($position) { + $step->step = $position; + } else { + $step->step = count($this->steps) + 1; + } + $step->tour_id = $this->tour_id; + if ($step->validate()) { + if ($position && $position <= count($this->steps)) { + $query = "UPDATE help_tour_steps + SET step = step + 1 + WHERE tour_id = ? AND step >= ? + ORDER BY step DESC"; + $statement = DBManager::get()->prepare($query); + $statement->execute([$this->tour_id, $position]); + } + $step->store(); + $this->restore(); + return true; + } + + return false; + } + + /** + * deletes step and rearranges existing steps + */ + public function deleteStep($position = 0) + { + if (!$position || count($this->steps) < 2) { + PageLayout::postError(_('Löschen nicht möglich. Die Tour muss mindestens einen Schritt enthalten.')); + return false; + } + $query = "DELETE FROM help_tour_steps + WHERE tour_id = ? AND step = ?"; + $statement = DBManager::get()->prepare($query); + $statement->execute([$this->tour_id, $position]); + + $query = "UPDATE help_tour_steps + SET step = step - 1 + WHERE tour_id = ? AND step > ? + ORDER BY step ASC"; + $statement = DBManager::get()->prepare($query); + $statement->execute([$this->tour_id, $position]); + $this->restore(); + return true; + } + + /** + * checks, if basic tour data is complete + * + * @return boolean true or false + */ + public function validate() + { + if (!$this->name || !$this->description) { + PageLayout::postError(_('Die Tour muss einen Namen und eine Beschreibung haben.')); + return false; + } + if (!$this->type) { + PageLayout::postError(_('Ungültige oder fehlende Angabe zur Art der Tour.')); + return false; + } + if (!$this->roles) { + PageLayout::postError(_('Angabe des Nutzendenstatus fehlt.')); + return false; + } + if (!$this->version) { + $this->version = 1; + } + if (!$this->isNew() && count($this->steps) === 0) { + PageLayout::postError(_('Die Tour muss mindestens einen Schritt enthalten.')); + return false; + } + return true; + } +} |
