Skip to content
Snippets Groups Projects
Select Git revision
  • 89ac333749acd0d646259a22b1f22a6dfdd63697
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

log_event.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    questionnaire.php 45.01 KiB
    <?php
    
    require_once 'lib/classes/QuestionType.interface.php';
    
    class QuestionnaireController extends AuthenticatedController
    {
        protected $allow_nobody = true; //nobody is allowed
    
        public function before_filter(&$action, &$args)
        {
            parent::before_filter($action, $args);
            if ($action !== 'courseoverview' && Navigation::hasItem('/contents/questionnaire')) {
                Navigation::activateItem('/contents/questionnaire');
            }
            PageLayout::setTitle(_('Fragebögen'));
    
            //trigger autoloading:
            class_exists('Vote');
            class_exists('Freetext');
            class_exists('LikertScale');
            class_exists('RangeScale');
            class_exists('QuestionnaireInfo');
            PageLayout::setHelpKeyword('Basis/Votings');
        }
    
        public function overview_action()
        {
            if (Navigation::hasItem('/contents/questionnaire/overview')) {
                Navigation::activateItem('/contents/questionnaire/overview');
            }
            $this->params = [];
            $this->range_id = null;
            $this->range_type = null;
            if (!$GLOBALS['perm']->have_perm('autor')) {
                throw new AccessDeniedException('Only for logged in users.');
            }
            $this->questionnaires = Questionnaire::findBySQL("user_id = ? ORDER BY chdate DESC", [$GLOBALS['user']->id]);
            foreach ($this->questionnaires as $questionnaire) {
                if (!$questionnaire['visible'] && $questionnaire->isRunning()) {
                    $questionnaire->start();
                }
                if ($questionnaire['visible'] && $questionnaire->isStopped()) {
                    $questionnaire->stop();
                }
            }
        }
    
        public function courseoverview_action()
        {
            $this->range_id = Context::getId();
    
            if (!$this->range_id) {
                throw new CheckObjectException(_('Sie haben kein Objekt gewählt.'));
            }
            $this->range_type = Context::getType();
            if (!$GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) {
                throw new AccessDeniedException("Only for logged in users.");
            }
    
            Navigation::activateItem("/course/admin/questionnaires");
            if ($GLOBALS['perm']->have_studip_perm('admin', $this->range_id)) {
                // Ensure the select widget is added last
                NotificationCenter::on('SidebarWillRender', function () {
                    $widget = new CourseManagementSelectWidget();
                    Sidebar::get()->addWidget($widget);
                });
            }
    
            $this->statusgruppen = Statusgruppen::findByRange_id($this->range_id);
            $this->questionnaires = Questionnaire::findBySQL(
                "INNER JOIN questionnaire_assignments USING (questionnaire_id) WHERE (questionnaire_assignments.range_id = ? AND questionnaire_assignments.range_type = ?) OR (questionnaire_assignments.range_id IN (?) AND questionnaire_assignments.range_type = 'statusgruppe') ORDER BY questionnaires.chdate DESC",
                [$this->range_id, $this->range_type, array_map(function ($g) { return $g->getId(); }, $this->statusgruppen)]
            );
            foreach ($this->questionnaires as $questionnaire) {
                if (!$questionnaire['visible'] && $questionnaire->isRunning()) {
                    $questionnaire->start();
                }
                if ($questionnaire['visible'] && $questionnaire->isStopped()) {
                    $questionnaire->stop();
                }
            }
            $this->params = ['redirect' => 'questionnaire/courseoverview'];
            $this->render_action("overview");
        }
    
        public function thank_you_action()
        {
    
        }
    
        public function add_to_context_action()
        {
            $this->statusgruppen = Statusgruppen::findByRange_id(Context::get()->id);
            PageLayout::setTitle(_("Kontext auswählen"));
        }
    
        public function edit_action($questionnaire_id = null)
        {
            if (!$GLOBALS['perm']->have_perm("autor")) {
                throw new AccessDeniedException("Only for authors.");
            }
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if ($this->questionnaire->isNew()) {
                PageLayout::setTitle(_("Neuer Fragebogen"));
            } else {
                PageLayout::setTitle(_("Fragebogen bearbeiten: ").$this->questionnaire['title']);
            }
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Fragebogen ist nicht bearbeitbar.'));
            }
            if ($this->questionnaire->isRunning() && $this->questionnaire->countAnswers() > 0) {
                $this->render_text(
                    MessageBox::error(_("Fragebogen ist gestartet worden und kann jetzt nicht mehr bearbeitet werden. Stoppen oder löschen Sie den Fragebogen stattdessen."))
                );
                return;
            }
    
            $statement = DBManager::get()->prepare("
                SELECT question_id
                FROM questionnaire_questions
                WHERE questionnaire_questions.questionnaire_id = ?
                ORDER BY position ASC
            ");
            $statement->execute(array($this->questionnaire->getId()));
            $this->order = $statement->fetchAll(PDO::FETCH_COLUMN, 0);
        }
    
        public function store_action($questionnaire_id = null)
        {
            if ($questionnaire_id) {
                $this->questionnaire = Questionnaire::find($questionnaire_id);
            } else {
                $this->questionnaire = new Questionnaire();
            }
            if (!$this->questionnaire || !$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
            }
            if ($this->questionnaire->isRunning() && $this->questionnaire->countAnswers() > 0) {
                $this->response->set_status('409', 'Conflict');
                $this->render_json([
                    'error' => 'alreadystarted',
                    'message' => _("Der Fragebogen ist gestartet worden und kann jetzt nicht mehr bearbeitet werden. Stoppen oder löschen Sie den Fragebogen stattdessen.")
                ]);
                return;
            }
            if (!Request::isPost()) {
                throw new MethodNotAllowedException();
            }
            $questionnaire_data = Request::getArray("questionnaire");
            $this->questionnaire['title'] = $questionnaire_data['title'] ?? '';
            $this->questionnaire['visible'] = $questionnaire_data['visible'] ?? 1;
            $this->questionnaire['anonymous'] = $questionnaire_data['anonymous'] ?? 0;
            $this->questionnaire['resultvisibility'] = $questionnaire_data['resultvisibility'] ?? 'always';
            $this->questionnaire['editanswers'] = $questionnaire_data['editanswers'] ?? 1;
            $this->questionnaire['copyable'] = $questionnaire_data['copyable'] ?? 1;
            $this->questionnaire['startdate'] = is_numeric($questionnaire_data['startdate'])
                ? $questionnaire_data['startdate']
                : ($questionnaire_data['startdate'] ? time() : null);
            $this->questionnaire['stopdate'] = is_numeric($questionnaire_data['stopdate'])
                ? $questionnaire_data['stopdate']
                : null;
    
            $this->questionnaire['user_id'] = User::findCurrent()->id;
            $questions_data = json_decode(Request::get('questions_data'), true);
            $questions = [];
            foreach ($questions_data as $index => $question_data) {
                $class = $question_data['questiontype'];
                if (!class_exists($class) || !is_subclass_of($class, 'QuestionType')) {
                    continue;
                }
                $question = $class::find($question_data['id']);
                if (!$question) {
                    $question = new $class();
                    $question->setId($question_data['id']);
                } elseif ($question['questionnaire_id'] !== $this->questionnaire->getId()) {
                    $question = new $class();
                    $question->setId($question->getNewId());
                }
                $question_data['questiondata'] = $question->beforeStoringQuestiondata($question_data['questiondata']);
                unset($question_data['id']);
                $question->setData($question_data);
                $question['position'] = $index;
                $questions[] = $question;
            }
            $this->questionnaire->questions = $questions;
            $this->questionnaire->store();
    
            //assignments:
            if (Request::get("range_id") && Request::get("range_type")) {
                if (Request::get("range_id") === "start" && !$GLOBALS['perm']->have_perm("root")) {
                    throw new AccessDeniedException();
                }
                if (Request::get("range_type") === "course" && !$GLOBALS['perm']->have_studip_perm("tutor", Request::get("range_id"))) {
                    throw new AccessDeniedException();
                }
                if (Request::get("range_type") === "user" && Request::get("range_id") !== $GLOBALS['user']->id) {
                    throw new AccessDeniedException();
                }
                $assignment = new QuestionnaireAssignment();
                $assignment['questionnaire_id'] = $this->questionnaire->getId();
                $assignment['range_id'] = Request::option("range_id");
                $assignment['range_type'] = Request::get("range_type");
                $assignment['user_id'] = $GLOBALS['user']->id;
                $assignment->store();
            }
    
            PageLayout::postSuccess(_('Die Daten wurden erfolgreich gespeichert.'));
            $this->render_nothing();
        }
    
    
        public function copy_action($from)
        {
            $this->old_questionnaire = Questionnaire::find($from);
            if (!$this->old_questionnaire->isCopyable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht kopierbar.'));
            }
            $this->questionnaire = new Questionnaire();
            $this->questionnaire->setData($this->old_questionnaire->toArray());
            $this->questionnaire->title .= sprintf(' [%s]', _('Kopie'));
            $this->questionnaire->setId($this->questionnaire->getNewId());
            $this->questionnaire['user_id'] = $GLOBALS['user']->id;
            $this->questionnaire['startdate'] = null;
            $this->questionnaire['stopdate'] = null;
            $this->questionnaire['mkdate'] = time();
            $this->questionnaire['chdate'] = time();
            $this->questionnaire->store();
            foreach ($this->old_questionnaire->questions as $question) {
                $new_question = QuestionnaireQuestion::build($question->toArray());
                $new_question->setId($new_question->getNewId());
                $new_question['questionnaire_id'] = $this->questionnaire->getid();
                $new_question['questiondata'] = $question['questiondata'];
                $new_question['mkdate'] = time();
                $new_question->store();
            }
            PageLayout::postSuccess(_('Der Fragebogen wurde kopiert. Wo soll er angezeigt werden?'));
            $this->redirect("questionnaire/context/".$this->questionnaire->getId());
        }
    
        public function delete_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
            }
            $this->questionnaire->delete();
            PageLayout::postSuccess(_('Der Fragebogen wurde gelöscht.'));
            if (Request::get("redirect")) {
                $this->redirect(Request::get("redirect"));
            } else {
                $this->redirect("questionnaire/overview");
            }
        }
    
        public function bulkdelete_action()
        {
            if (!Request::isPost()) {
                throw new MethodNotAllowedException();
            }
            foreach (Request::getArray("q") as $questionnaire_id) {
                $questionnaire = new Questionnaire($questionnaire_id);
                if ($questionnaire->isEditable()) {
                    $questionnaire->delete();
                }
            }
            PageLayout::postSuccess(_('Fragebögen wurden gelöscht.'));
            if (Request::get("range_type") === "user") {
                $this->redirect("questionnaire/overview");
            } elseif (Request::get("range_type") === "course") {
                $this->redirect("questionnaire/courseoverview");
            } elseif (Request::get("range_id") === "start") {
                $this->redirect("start");
            } else {
                $this->redirect("questionnaire/overview");
            }
        }
    
        public function answer_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isViewable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht einsehbar.'));
            }
            object_set_visit($questionnaire_id, 'vote');
            $this->range_type = Request::get("range_type");
            $this->range_id = Request::get("range_id");
            PageLayout::setTitle(sprintf(_("Fragebogen beantworten: %s"), $this->questionnaire->title));
        }
    
        public function evaluate_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isViewable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht einsehbar.'));
            }
            object_set_visit($questionnaire_id, 'vote');
            PageLayout::setTitle(sprintf(_("Fragebogen: %s"), $this->questionnaire->title));
    
            $this->filtered = [];
            if (Request::submitted('filtered')) {
                $this->filtered[$questionnaire_id] = Request::getArray('filtered');
            }
    
            if (Request::isAjax() && empty($_SERVER['HTTP_X_DIALOG'])) {
                PageLayout::clearMessages();
            }
        }
    
        public function stop_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
            }
            $this->questionnaire->stop();
    
            PageLayout::postSuccess(_('Die Befragung wurde beendet.'));
            if (Request::get("redirect")) {
                $this->redirect(Request::get("redirect"));
            } else {
                $this->redirect("questionnaire/overview");
            }
        }
    
        public function start_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
            }
            $this->questionnaire->start();
    
            PageLayout::postSuccess(_("Die Befragung wurde gestartet."));
            if (Request::get("redirect")) {
                $this->redirect(Request::get("redirect"));
            } else {
                $this->redirect("questionnaire/overview");
            }
        }
    
        public function export_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht exportierbar.'));
            }
            $csv = [[_("Nummer"), _("Benutzername"), _("Nachname"), _("Vorname"), _("E-Mail")]];
    
            $results = [];
            $user_ids = [];
    
            foreach ($this->questionnaire->questions as $question) {
                $result = (array) $question->getResultArray();
                foreach ($result as $frage => $r) {
                    $csv[0][] = $frage;
                    $user_ids = array_merge($user_ids, array_keys($r));
                    $user_ids = array_unique($user_ids);
                }
                $results[] = $result;
            }
    
            foreach ($user_ids as $key => $user_id) {
                $user = User::find($user_id);
                if ($user) {
                    $csv_line = [$key + 1, $user['username'], $user['Nachname'], $user['Vorname'], $user['Email']];
                } else {
                    $csv_line = [$key + 1, $user_id, '', '', ''];
                }
    
                foreach ($results as $result) {
                    foreach ($result as $frage => $value) {
                        $csv_line[] = $value[$user_id];
                    }
                }
                $csv[] = $csv_line;
            }
            $this->response->add_header('Content-Type', "text/csv");
            $this->response->add_header('Content-Disposition', "attachment; " . encode_header_parameter('filename', $this->questionnaire['title'].'.csv'));
            $this->render_text(array_to_csv($csv));
        }
    
        public function reset_action(Questionnaire $questionnaire)
        {
            if (!Request::isPost() || !$questionnaire->isEditable() || !CSRFProtection::verifyRequest()) {
                throw new AccessDeniedException();
            }
            foreach ($questionnaire->anonymousanswers as $anonymous) {
                $anonymous->delete();
            }
            foreach ($questionnaire->questions as $question) {
                foreach ($question->answers as $answer) {
                    $answer->delete();
                }
            }
            PageLayout::postSuccess(_('Antworten wurden zurückgesetzt.'));
            if (Request::get("range_type") === "user") {
                $this->redirect("profile");
            } elseif (Request::get("range_type") === "course") {
                $this->redirect("course/overview");
            } elseif (Request::get("range_id") === "start") {
                $this->redirect("start");
            } else {
                $this->redirect("questionnaire/overview");
            }
        }
    
        public function context_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isEditable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
            }
            $this->profile = null;
            $this->public = null;
            $this->start = null;
            foreach ($this->questionnaire->assignments as $relation) {
                if ($relation['range_type'] === "user") {
                    $this->profile = $relation;
                }
                if ($relation['range_id'] === "public") {
                    $this->public = $relation;
                }
                if ($relation['range_id'] === "start") {
                    $this->start = $relation;
                }
            }
            if (Request::isPost()) {
                if (Request::get("user")) {
                    if (!$this->profile) {
                        $this->profile = new QuestionnaireAssignment();
                        $this->profile['questionnaire_id'] = $this->questionnaire->getId();
                        $this->profile['range_id'] = $GLOBALS['user']->id;
                        $this->profile['range_type'] = "user";
                        $this->profile['user_id'] = $GLOBALS['user']->id;
                        $this->profile->store();
                    }
                } else {
                    if ($this->profile) {
                        $this->profile->delete();
                    }
                }
                if (Request::get("public")) {
                    if (!$this->public) {
                        $this->public = new QuestionnaireAssignment();
                        $this->public['questionnaire_id'] = $this->questionnaire->getId();
                        $this->public['range_id'] = "public";
                        $this->public['range_type'] = "static";
                        $this->public['user_id'] = $GLOBALS['user']->id;
                        $this->public->store();
                    }
                } else {
                    if ($this->public) {
                        $this->public->delete();
                    }
                }
                if ($GLOBALS['perm']->have_perm("root")) {
                    if (Request::get("start")) {
                        if (!$this->start) {
                            $this->start = new QuestionnaireAssignment();
                            $this->start['questionnaire_id'] = $this->questionnaire->getId();
                            $this->start['range_id'] = "start";
                            $this->start['range_type'] = "static";
                            $this->start['user_id'] = $GLOBALS['user']->id;
                            $this->start->store();
                        }
                    } else {
                        if ($this->start) {
                            $this->start->delete();
                        }
                    }
                }
                if (Request::option("add_seminar_id") && $GLOBALS['perm']->have_studip_perm("tutor", Request::option("add_seminar_id"))) {
                    $course_assignment = new QuestionnaireAssignment();
                    $course_assignment['questionnaire_id'] = $this->questionnaire->getId();
                    $course_assignment['range_id'] = Request::option("add_seminar_id");
                    $course_assignment['range_type'] = "course";
                    $course_assignment['user_id'] = $GLOBALS['user']->id;
                    $course_assignment->store();
                }
                if (Request::option("add_institut_id") && $GLOBALS['perm']->have_studip_perm("admin", Request::option("add_institut_id"))) {
                    $course_assignment = new QuestionnaireAssignment();
                    $course_assignment['questionnaire_id'] = $this->questionnaire->getId();
                    $course_assignment['range_id'] = Request::option("add_institut_id");
                    $course_assignment['range_type'] = "institute";
                    $course_assignment['user_id'] = $GLOBALS['user']->id;
                    $course_assignment->store();
                }
                if (Request::option("add_statusgruppe_id") && $GLOBALS['perm']->have_studip_perm("tutor", Statusgruppen::find(Request::option("add_statusgruppe_id"))->range_id)) {
                    $course_assignment = new QuestionnaireAssignment();
                    $course_assignment['questionnaire_id'] = $this->questionnaire->getId();
                    $course_assignment['range_id'] = Request::option("add_statusgruppe_id");
                    $course_assignment['range_type'] = "statusgruppe";
                    $course_assignment['user_id'] = $GLOBALS['user']->id;
                    $course_assignment->store();
                }
                foreach (PluginManager::getInstance()->getPlugins("QuestionnaireAssignmentPlugin") as $plugin) {
                    $plugin->storeQuestionnaireAssignments($this->questionnaire);
                }
    
                foreach (Request::getArray('remove_sem') as $seminar_id) {
                    if ($GLOBALS['perm']->have_studip_perm('tutor', $seminar_id)) {
                        $course_assignment = QuestionnaireAssignment::findBySeminarAndQuestionnaire($seminar_id, $this->questionnaire->getId());
                        if ($course_assignment) {
                            $course_assignment->delete();
                        }
                    }
                }
    
                foreach (Request::optionArray('remove_inst') as $institute_id) {
                    if ($GLOBALS['perm']->have_studip_perm('admin', $institute_id)) {
                        $inst_assignment = QuestionnaireAssignment::findByInstituteAndQuestionnaire($institute_id, $this->questionnaire->id);
                        if ($inst_assignment) {
                            $inst_assignment->delete();
                        }
                    }
                }
    
                foreach (Request::optionArray('remove_statusgruppe') as $statusgruppe_id) {
                    if ($GLOBALS['perm']->have_studip_perm("tutor", Statusgruppen::find($statusgruppe_id)->range_id)) {
                        $inst_assignment = QuestionnaireAssignment::findByStatusgruppeAndQuestionnaire($statusgruppe_id, $this->questionnaire->id);
                        if ($inst_assignment) {
                            $inst_assignment->delete();
                        }
                    }
                }
    
                PageLayout::postSuccess(_('Die Bereichszuweisungen wurden gespeichert.'));
                $this->questionnaire->restore();
                $this->questionnaire->resetRelation("assignments");
                $this->response->add_header("X-Dialog-Close", 1);
            }
            PageLayout::setTitle(sprintf(_("Bereiche für Fragebogen: %s"), $this->questionnaire->title));
            // Prepare context for MyCoursesSearch...
            if ($GLOBALS['perm']->have_perm('root')) {
                $parameters = [
                    'exclude'   => ['']
                ];
            } elseif ($GLOBALS['perm']->have_perm('admin')) {
                $parameters = [
                    'institutes' => array_map(function ($i) {
                        return $i['Institut_id'];
                    }, Institute::getMyInstitutes()),
                    'exclude'    => ['']
                ];
            } else {
                $parameters = [
                    'userid'    => $GLOBALS['user']->id,
                    'exclude'   => ['']
                ];
            }
            $this->seminarsearch = MyCoursesSearch::get('Seminar_id', $GLOBALS['perm']->get_perm(), $parameters);
    
            if ($GLOBALS['perm']->have_perm("root")) {
                $this->statusgruppesearch = new SQLSearch(
                    "SELECT statusgruppen.statusgruppe_id, CONCAT(seminare.name, ': ', statusgruppen.name) AS search_name
                        FROM statusgruppen
                            INNER JOIN seminare ON (seminare.Seminar_id = statusgruppen.range_id)
                        WHERE CONCAT(seminare.name, ': ', statusgruppen.name) LIKE :input
                        ORDER BY statusgruppen.name ASC ",
                    _("Teilnehmergruppe suchen")
                );
            } elseif ($GLOBALS['perm']->have_perm("admin")) {
                $this->statusgruppesearch = new SQLSearch(
                    "SELECT statusgruppen.statusgruppe_id, CONCAT(seminare.name, ': ', statusgruppen.name) AS search_name
                    FROM statusgruppen
                        INNER JOIN seminare ON (seminare.Seminar_id = statusgruppen.range_id)
                        INNER JOIN seminar_inst ON (seminar_inst.seminar_id = seminare.Seminar_id)
                        INNER JOIN user_inst ON (seminar_inst.institut_id = user_inst.Institut_id AND inst_perms = 'admin')
                    WHERE CONCAT(seminare.name, ': ', statusgruppen.name) LIKE :input
                        AND user_inst.user_id = " . DBManager::get()->quote($GLOBALS['user']->id) . "
                    ORDER BY statusgruppen.name ASC ",
                    _("Teilnehmergruppe suchen")
                );
            } else {
                $this->statusgruppesearch = new SQLSearch(
                    "SELECT statusgruppen.statusgruppe_id, CONCAT(seminare.name, ': ', statusgruppen.name) AS search_name
                        FROM statusgruppen
                            LEFT JOIN seminar_user ON (statusgruppen.range_id = seminar_user.Seminar_id AND seminar_user.status IN ('tutor', 'dozent'))
                            LEFT JOIN seminare ON (seminare.Seminar_id = statusgruppen.range_id)
                        WHERE seminar_user.user_id = " . DBManager::get()->quote($GLOBALS['user']->id) . "
                            AND CONCAT(seminare.name, ': ', statusgruppen.name) LIKE :input
                        ORDER BY statusgruppen.name ASC ",
                    _("Teilnehmergruppe suchen")
                );
            }
        }
    
        public function widget_action($range_id, $range_type = "course")
        {
            if (get_class($this->parent_controller) === __CLASS__) {
                throw new RuntimeException('widget_action must be relayed');
            }
            $this->range_id = $range_id;
            $this->range_type = $range_type;
            if (in_array($this->range_id, ["public", "start"])) {
                $this->range_type = "static";
            }
            $this->statusgruppen_ids = [];
            if (in_array($this->range_type, ["course", "institute"])) {
                if ($this->range_id && $GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) {
                    $statusgruppen = Statusgruppen::findByRange_id($this->range_id);
                } else {
                    $statusgruppen = Statusgruppen::findBySQL("INNER JOIN statusgruppe_user USING (statusgruppe_id) WHERE statusgruppen.range_id = ? AND statusgruppe_user.user_id = ? ", [
                        Context::get()->id,
                        $GLOBALS['user']->id
                    ]);
                }
                $this->statusgruppen_ids = array_map(function ($g) { return $g->getId(); }, $statusgruppen);
            }
            $statement = DBManager::get()->prepare("
                SELECT questionnaires.*
                FROM questionnaires
                    INNER JOIN questionnaire_assignments ON (questionnaires.questionnaire_id = questionnaire_assignments.questionnaire_id)
                WHERE (
                        questionnaire_assignments.range_id = :range_id
                        AND questionnaire_assignments.range_type = :range_type
                    ) OR (
                        questionnaire_assignments.range_id IN (:statusgruppe_id)
                        AND questionnaire_assignments.range_type = 'statusgruppe'
                    )
                    AND startdate <= UNIX_TIMESTAMP()
                ORDER BY questionnaires.mkdate DESC
            ");
            $statement->execute([
                'range_id' => $this->range_id,
                'range_type' => $this->range_type,
                'statusgruppe_id' => $this->statusgruppen_ids
            ]);
            $this->questionnaire_data = $statement->fetchAll(PDO::FETCH_ASSOC);
            $stopped_visible = 0;
            foreach ($this->questionnaire_data as $i => $questionnaire) {
                $one = Questionnaire::buildExisting($questionnaire);
                if (!$questionnaire['visible'] && $one->isRunning()) {
                    $one->start();
                }
                if ($questionnaire['visible'] && $one->isStopped()) {
                    $one->stop();
                }
                if ($one->isStopped() && $one->resultsVisible()) {
                    $stopped_visible++;
                }
                if (($one->isStopped() || !$one->isViewable()) && (!$one->resultsVisible() || !Request::get("questionnaire_showall"))) {
                    unset($this->questionnaire_data[$i]);
                    continue;
                }
    
                object_set_visit($questionnaire['questionnaire_id'], 'vote');
            }
            if (in_array($this->range_type, ["course", "institute"])
                    && $this->range_id
                    && !$GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)
                    && !($stopped_visible || count($this->questionnaire_data))) {
                $this->render_nothing();
            }
        }
    
    
        /**
         * The assign action allows assigning multiple questionnaires
         * to multiple courses.
         */
        public function assign_action()
        {
            PageLayout::setTitle(_('Fragebögen zuordnen'));
    
            if (Navigation::hasItem('/contents/questionnaire/assign')) {
                Navigation::activateItem('/contents/questionnaire/assign');
            }
    
            if (!$GLOBALS['perm']->have_perm('admin')) {
                throw new AccessDeniedException();
            }
    
            $user = User::findCurrent();
    
            $this->available_semesters = Semester::findBySql(
                'TRUE ORDER BY beginn DESC'
            );
            $this->available_institutes = Institute::getMyInstitutes($user->id);
            $this->available_course_types = SemType::getTypes();
            $this->selected_questionnaires = [];
    
            $this->step = 0;
    
            //We accept only forms which have been sent via POST!
            if (Request::isPost()) {
                CSRFProtection::verifyUnsafeRequest();
    
                if (Request::submitted('search_courses')) {
                    $this->step = 1;
                } elseif (Request::submitted('select_courses')) {
                    $this->step = 2;
                } elseif (Request::submitted('copy') || Request::submitted('assign')) {
                    $this->step = 3;
                }
    
                if ($this->step >= 1) {
                    //Step 1: Search for courses.
                    $this->semester_id = Request::get('semester_id');
                    $this->institute_id = Request::get('institute_id');
                    $this->course_type_id = Request::get('course_type_id');
    
                    if ($this->institute_id) {
                        //Check if the user has at least admin permissions on the selected
                        //institute. If not, then don't process the submitted data
                        //any further:
                        if (!$GLOBALS['perm']->have_studip_perm('admin', $this->institute_id, $user->id)) {
                            PageLayout::postError(
                                _('Sie haben unzureichende Berechtigungen an der gewählten Einrichtung! Bitte wählen Sie eine andere Einrichtung!')
                            );
                            $this->step = 0;
                            return;
                        }
                    }
    
                    $this->semester = Semester::find($this->semester_id);
                    if ($this->institute_id) {
                        $this->institute = Institute::find($this->institute_id);
                    }
    
                    $this->error_message = '';
    
                    if (!$this->semester) {
                        PageLayout::postError(_('Es wurde kein gültiges Semester ausgewählt!'));
                        $this->step = 0;
                        return;
                    }
    
                    //Search courses matching the search criteria:
    
                    $sql = 'LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) WHERE (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL) ';
                    $sql_array = [
                        'semester_id' => $this->semester->id
                    ];
    
                    if ($this->institute) {
                        $sql .= 'AND institut_id = :institute_id ';
                        $sql_array['institute_id'] = $this->institute->id;
                    }
                    if ($this->course_type_id) {
                        $sql .= 'AND status = :course_type_id ';
                        $sql_array['course_type_id'] = $this->course_type_id;
                    }
    
                    $sql .= 'ORDER BY name ASC';
    
                    $courses = Course::findBySql($sql, $sql_array);
    
                    $this->found_courses = [];
    
                    //We can only add those courses where the current user
                    //has at least admin permissions:
                    foreach ($courses as $course) {
                        if ($GLOBALS['perm']->have_studip_perm('admin', $course->id)) {
                            $this->found_courses[] = $course;
                        }
                    }
                }
    
                if ($this->step >= 2) {
                    //Step 2: Courses have been selected. Search for questionnaires.
                    $this->course_id_list = Request::getArray('course_id_list');
                    $this->selected_courses = Course::findMany($this->course_id_list);
                    if (!$this->selected_courses) {
                        PageLayout::postError(
                            _('Es wurde keine Veranstaltung ausgewählt! Bitte mindestens eine Veranstaltung auswählen!')
                        );
                        $this->step = 1;
                        return;
                    }
                    $courses_without_perms = [];
                    foreach ($this->selected_courses as $course) {
                        if (!$GLOBALS['perm']->have_studip_perm('admin', $course->id)) {
                            $courses_without_perms[] = $course->getFullName();
                        }
                    }
    
                    if ($courses_without_perms) {
                        PageLayout::postError(
                            ngettext(
                                'Ihre Berechtigungen reichen nicht, um Fragebögen zu der folgenden Veranstaltung zuweisen zu können:',
                                'Ihre Berechtigungen reichen nicht, um Fragebögen zu den folgenden Veranstaltungen zuweisen zu können:',
                                count($courses_without_perms)
                            ),
                            $courses_without_perms
                        );
                        $this->step = 1;
                        return;
                    }
    
                    //Get only the questionnaires of the current user:
                    $this->questionnaires = Questionnaire::findBySql(
                        'user_id = :user_id ORDER BY mkdate DESC',
                        [
                            'user_id' => $user->id
                        ]
                    );
                }
    
                if ($this->step >= 3) {
                    //Step 3: Questionnaires have been selected. Assign them
                    //to the found courses.
                    $this->selected_questionnaire_ids = Request::getArray('selected_questionnaire_ids');
                    $this->delete_dates = Request::get('delete_dates');
                    $this->copy_questionnaires = Request::submitted('copy');
    
                    //Get only the questionnaires of the current user:
                    $this->selected_questionnaires = Questionnaire::findBySql(
                        'user_id = :user_id AND questionnaire_id IN ( :questionnaire_ids )',
                        [
                            'user_id' => $user->id,
                            'questionnaire_ids' => $this->selected_questionnaire_ids
                        ]
                    );
                    if (!$this->selected_questionnaires) {
                        PageLayout::postError(
                            _('Es wurde kein Fragebogen ausgewählt! Bitte mindestens einen Fragebogen auswählen!')
                        );
                        $this->step = 2;
                        return;
                    }
    
                    $errors = [];
                    foreach ($this->selected_courses as $course) {
                        foreach ($this->selected_questionnaires as $questionnaire) {
                            if ($this->copy_questionnaires) {
                                //The questionnaire shall be copied and only the copy
                                //shall be placed inside the course.
    
                                //The following code to copy a questionnaire was copied
                                //from the questionnaire controller's copy_action method.
                                //If that method changes please keep this code "in sync"
                                //with the code from the questionnaire controller to avoid
                                //misbehavior of this plugin.
                                $new_questionnaire = new Questionnaire();
                                $new_questionnaire->setData($questionnaire->toArray());
                                $new_questionnaire->setId($new_questionnaire->getNewId());
                                $new_questionnaire->user_id = $user->id;
                                //Contrary to the original code, copied questionnaires
                                //may still contain the start date and end date of the
                                //original questionnaire.
                                if ($this->delete_dates) {
                                    $new_questionnaire->startdate = null;
                                    $new_questionnaire->stopdate = null;
                                }
    
                                $new_questionnaire->mkdate = time();
                                $new_questionnaire->chdate = time();
                                $new_questionnaire->store();
                                foreach ($questionnaire->questions as $question) {
                                    $new_question = QuestionnaireQuestion::build($question->toArray());
                                    $new_question->setId($new_question->getNewId());
                                    $new_question->questionnaire_id = $new_questionnaire->id;
                                    $new_question->mkdate = time();
                                    $new_question->store();
                                }
    
                                $assignment = new QuestionnaireAssignment();
                                $assignment->questionnaire_id = $new_questionnaire->id;
                                $assignment->range_id = $course->id;
                                $assignment->range_type = 'course';
                                $assignment->user_id = $user->id;
                                if (!$assignment->store()) {
                                    $errors[] = sprintf(
                                        _('Fragebogen "%1$s" konnte nicht in Veranstaltung "%2$s" kopiert werden!'),
                                        $new_questionnaire->title,
                                        $course->name
                                    );
                                }
                            } else {
                                //The questionnaire shall be assigned to the course.
                                //We must check if the association already exists.
                                $assignment = QuestionnaireAssignment::findBySeminarAndQuestionnaire(
                                    $course->id,
                                    $questionnaire->id
                                );
    
                                if (!$assignment) {
                                    //The assignment doesn't exist: create it:
                                    $assignment = new QuestionnaireAssignment();
                                    $assignment->questionnaire_id = $questionnaire->id;
                                    $assignment->range_id = $course->id;
                                    $assignment->range_type = 'course';
                                    $assignment->user_id = $user->id;
                                    if (!$assignment->store()) {
                                        $errors[] = sprintf(
                                            _('Fragebogen "%1$s" konnte nicht zu Veranstaltung "%2$s" zugeordnet werden!'),
                                            htmlReady($questionnaire->title),
                                            htmlReady($course->name)
                                        );
                                    }
                                }
                            }
                        }
                    }
    
                    if ($errors) {
                        PageLayout::postError(
                            _('Beim Zuordnen traten Fehler auf:'),
                            $errors
                        );
                    } else {
                        PageLayout::postSuccess(
                            _('Alle gewählten Fragebögen wurden den gewählten Veranstaltungen zugeordnet!')
                        );
                    }
                }
            }
        }
    
        public function submit_action($questionnaire_id)
        {
            $this->questionnaire = new Questionnaire($questionnaire_id);
            if (!$this->questionnaire->isViewable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht einsehbar.'));
            }
            $answered_before = $this->questionnaire->isAnswered();
            if ($this->questionnaire->isAnswerable()) {
                $pseudonomous_id = 'q'.substr(md5(uniqid()), 1);
                foreach ($this->questionnaire->questions as $question) {
                    $answer = $question->createAnswer();
                    if (!$answer['question_id']) {
                        $answer['question_id'] = $question->getId();
                    }
                    $answer['user_id'] = $GLOBALS['user']->id !== "nobody" ? $GLOBALS['user']->id : $pseudonomous_id;
                    if (!$answer['answerdata']) {
                        $answer['answerdata'] = [];
                    }
                    if ($this->questionnaire['anonymous']) {
                        $answer['user_id'] = $pseudonomous_id;
                        $answer['chdate'] = 1;
                        $answer['mkdate'] = 1;
                        $this->anonAnswers[] = $answer->toArray();
                    }
                    $answer->store();
                }
                if ($this->questionnaire['anonymous'] && ($GLOBALS['user']->id !== "nobody")) {
                    $anonymous_answer = new QuestionnaireAnonymousAnswer();
                    $anonymous_answer['questionnaire_id'] = $this->questionnaire->getId();
                    $anonymous_answer['user_id'] = $GLOBALS['user']->id;
                    $anonymous_answer->store();
                }
                if (!$answered_before && !$this->questionnaire['anonymous'] && ($this->questionnaire['user_id'] !== $GLOBALS['user']->id)) {
                    setTempLanguage($this->questionnaire->user_id);
    
                    PersonalNotifications::add(
                        $this->questionnaire->user_id,
                        URLHelper::getURL('dispatch.php/questionnaire/evaluate/' . $this->questionnaire->id, [], true),
                        sprintf(_("%s hat an der Befragung '%s' teilgenommen."), $GLOBALS['user']->getFullName(), $this->questionnaire->title),
                        "questionnaire_" . $this->questionnaire->id,
                        Icon::create('vote'),
                        true
                    );
    
                    restoreLanguage();
                }
            }
    
            if (Request::isAjax()) {
                $this->response->add_header("X-Dialog-Close", "1");
                $this->response->add_header("X-Dialog-Execute", "STUDIP.Questionnaire.updateWidgetQuestionnaire");
                $this->render_template("questionnaire/evaluate");
            } elseif (Request::get("range_type") === "user") {
                PageLayout::postMessage(MessageBox::success(_("Danke für die Teilnahme!")));
                $this->redirect("profile?username=".get_username(Request::option("range_id")));
            } elseif (Request::get("range_type") === "course") {
                PageLayout::postMessage(MessageBox::success(_("Danke für die Teilnahme!")));
                $this->redirect("course/overview?cid=".Request::option("range_id"));
            } elseif (Request::get("range_id") === "start") {
                PageLayout::postMessage(MessageBox::success(_("Danke für die Teilnahme!")));
                $this->redirect("start");
            } else {
                PageLayout::postMessage(MessageBox::success(_("Danke für die Teilnahme!")));
                if ($GLOBALS['perm']->have_perm("autor")) {
                    $this->redirect("questionnaire/overview");
                } else {
                    $this->redirect("questionnaire/thank_you");
                }
            }
        }
    
        public function export_file_action(Questionnaire $questionnaire)
        {
            if (!$questionnaire->isCopyable()) {
                throw new AccessDeniedException(_('Der Fragebogen ist nicht kopierbar.'));
            }
            $this->response->add_header('Content-Disposition', 'attachment; ' . encode_header_parameter('filename', $questionnaire['title'].".json"));
    
            $rawdata = $questionnaire->exportAsFile();
            $file_data = json_encode($rawdata);
            $this->response->add_header('Content-Length', strlen($file_data));
            $this->render_json($rawdata);
        }
    }