Skip to content
Snippets Groups Projects
Forked from Stud.IP / Stud.IP
3721 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
questionnaire.php 44.50 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('Test');
        class_exists('Freetext');
    }

    public function overview_action()
    {
        if (Navigation::hasItem('/contents/questionnaire/overview')) {
            Navigation::activateItem('/contents/questionnaire/overview');
        }

        if (!$GLOBALS['perm']->have_perm('autor')) {
            throw new AccessDeniedException('Only for logged in users.');
        }
        $this->questionnaires = Questionnaire::findBySQL("user_id = ? ORDER BY mkdate 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_type = Course::findCurrent() ? 'course' : 'institute';
        if (($this->range_type === "institute") && $GLOBALS['perm']->have_perm('admin')) {
            if (!Context::get()->id) {
                Navigation::activateItem('/admin/institute/questionnaires');
            }
            require_once 'lib/admin_search.inc.php';
        }
        if (!$GLOBALS['perm']->have_studip_perm("tutor", Context::get()->id)) {
            throw new AccessDeniedException("Only for logged in users.");
        }
        Navigation::activateItem("/course/admin/questionnaires");
        $this->statusgruppen = Statusgruppen::findByRange_id(Context::get()->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.mkdate DESC",
            [Context::get()->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->render_action("overview");
    }

    public function thank_you_action()
    {

    }

    public function add_to_context_action()
    {
        $this->statusgruppen = Statusgruppen::findByRange_id(Context::get()->id);
        if (!count($this->statusgruppen)) {
            $this->redirect(
                $this->url_for("questionnaire/edit", [
                'range_type' => Context::getType(),
                'range_id' => Context::get()->id
            ]));
            return;
        }
        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;
        }
        if (Request::isPost()) {
            $neworder = array_flip(Request::getArray("neworder"));
            $order = array_flip(json_decode(Request::get("order"), true));
            $questionnaire_data = Request::getArray("questionnaire");
            $questionnaire_data['startdate'] = $questionnaire_data['startdate']
                ? (strtotime($questionnaire_data['startdate']) ?: time())
                : null;
            $questionnaire_data['stopdate'] = strtotime($questionnaire_data['stopdate']) ?: null;
            $questionnaire_data['copyable'] = (int) $questionnaire_data['copyable'];
            $questionnaire_data['anonymous'] = (int) $questionnaire_data['anonymous'];
            $questionnaire_data['editanswers'] = $questionnaire_data['anonymous'] ? 0 : (int) $questionnaire_data['editanswers'];
            if ($this->questionnaire->isNew()) {
                $questionnaire_data['visible'] = ($questionnaire_data['startdate'] <= time() && (!$questionnaire_data['stopdate'] || $questionnaire_data['stopdate'] >= time())) ? 1 : 0;
            }
            $this->questionnaire->setData($questionnaire_data);
            $question_types_data = Request::getArray("question_types");
            foreach ($question_types_data as $question_id => $question_type) {
                $question = null;
                foreach ($this->questionnaire->questions as $index => $q) {
                    if ($q->getId() === $question_id) {
                        $question = $q;
                        break;
                    }
                }
                if (!$question) {
                    $question = new $question_type($question_id);
                    $this->questionnaire->questions[] = $question;
                }
                $question['position'] = $neworder[$question_id] + 1;
                $question->createDataFromRequest();
            }
            foreach ($this->questionnaire->questions as $q) {
                if (!in_array($q->getId(), array_keys($question_types_data))) {
                    $q->delete();
                }
            }
            if (Request::submitted("questionnaire_store")) {
                //save everything
                $is_new = $this->questionnaire->isNew();
                if ($is_new) {
                    $this->questionnaire['user_id'] = $GLOBALS['user']->id;
                }
                $this->questionnaire->store();

                if ($is_new && Request::get("range_id") && Request::get("range_type")) {
                    if (Request::get("range_id") === "start" && !$GLOBALS['perm']->have_perm("root")) {
                        throw new Exception(_("Der Fragebogen darf nicht von Ihnen auf die Startseite eingehängt werden, sondern nur von einem Admin."));
                    }
                    if (Request::get("range_type") === "course" && !$GLOBALS['perm']->have_studip_perm("tutor", Request::get("range_id"))) {
                        throw new Exception(_("Der Fragebogen darf nicht in die ausgewählte Veranstaltung eingebunden werden."));
                    }
                    if (Request::get("range_type") === "user" && Request::get("range_id") !== $GLOBALS['user']->id) {
                        throw new Exception(_("Der Fragebogen darf nicht in diesen Bereich eingebunden werden."));
                    }
                    $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();
                }
                if ($is_new) {
                    $message = MessageBox::success(_("Der Fragebogen wurde erfolgreich erstellt."));
                } else {
                    $message = MessageBox::success(_("Der Fragebogen wurde gespeichert."));
                }
                if (Request::isAjax()) {
                    $this->questionnaire->restore();
                    $this->questionnaire->resetRelation("assignments");
                    $output = [
                            'questionnaire_id' => $this->questionnaire->getId(),
                            'overview_html' => $this->render_template_as_string("questionnaire/_overview_questionnaire.php"),
                            'widget_html' => $this->questionnaire->isStarted()
                                ? $this->render_template_as_string("questionnaire/_widget_questionnaire.php")
                                : "",
                            'message' => $message->__toString()
                    ];
                    $this->response->add_header("X-Dialog-Close", 1);
                    $this->response->add_header("X-Dialog-Execute", "STUDIP.Questionnaire.updateOverviewQuestionnaire");
                    $this->render_json($output);
                } else {
                    PageLayout::postMessage($message);
                    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");
                    }
                }
            }
            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 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->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['mkdate'] = time();

            $etask = new \eTask\Task();
            $etask->setData($question->etask->toRawArray());
            $etask->setId(null); //to get a new integer id
            $etask->store();
            $new_question['etask_task_id'] = $etask->getId();

            $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 add_question_action()
    {
        if (!$GLOBALS['perm']->have_perm("autor")) {
            throw new AccessDeniedException(_('Der Fragebogen ist nicht einsehbar.'));
        }
        $class = Request::get("questiontype");
        $this->question = new $class();
        $this->question->setId($this->question->getNewId());

        $template = $this->get_template_factory()->open("questionnaire/_question.php");
        $template->set_attribute("question", $this->question);

        $output = [
            'html' => $template->render(),
            'question_id' => $this->question->getId()
        ];
        $this->render_json($output);
    }

    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));

        if (Request::isAjax() && !$_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 context_action($questionnaire_id)
    {
        $this->questionnaire = new Questionnaire($questionnaire_id);
        if (!$this->questionnaire->isEditable()) {
            throw new AccessDeniedException(_('Der Fragebogen ist nicht bearbeitbar.'));
        }
        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");
            $output = [
                'func' => "STUDIP.Questionnaire.updateOverviewQuestionnaire",
                'payload' => [
                    'questionnaire_id' => $this->questionnaire->getId(),
                    'overview_html' => $this->render_template_as_string("questionnaire/_overview_questionnaire.php")
                ]
            ];
            $this->response->add_header("X-Dialog-Execute", json_encode($output));
        }
        PageLayout::setTitle(sprintf(_("Bereiche für Fragebogen: %s"), $this->questionnaire->title));
        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";
        }
        $statusgruppen_ids = [];
        if (in_array($this->range_type, ["course", "institute"])) {
            if ($GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) {
                $statusgruppen = Statusgruppen::findByRange_id(Context::get()->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
                ]);
            }
            $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' => $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"])
                && !$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 = 'start_time = :semester_begin ';
                $sql_array = [
                    'semester_begin' => $this->semester->beginn
                ];

                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, $user_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, $user_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()) {
            foreach ($this->questionnaire->questions as $question) {
                $answer = $question->createAnswer();
                if (!$answer['question_id']) {
                    $answer['question_id'] = $question->getId();
                }
                $answer['user_id'] = $GLOBALS['user']->id;
                if (!$answer['answerdata']) {
                    $answer['answerdata'] = [];
                }
                if ($this->questionnaire['anonymous']) {
                    $answer['user_id'] = 'anonymous';
                    $answer['chdate'] = 1;
                    $answer['mkdate'] = 1;
                    $this->anonAnswers[] = $answer->toArray();
                    $answer['user_id'] = null;
                }
                $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)) {
                $url = URLHelper::getURL("dispatch.php/questionnaire/evaluate/" . $this->questionnaire->getId(), [], true);
                PersonalNotifications::add(
                    $this->questionnaire['user_id'],
                    $url,
                    sprintf(_("%s hat an der Befragung '%s' teilgenommen."), $GLOBALS['user']->getFullName(), $this->questionnaire['title']),
                    "questionnaire_" . $this->questionnaire->getId(),
                    Icon::create('vote'),
                    true
                );
            }
        }

        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");
            }
        }
    }
}