aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRasmus Fuhse <fuhse@data-quest.de>2022-12-16 13:13:32 +0000
committerRasmus Fuhse <fuhse@data-quest.de>2022-12-16 13:13:32 +0000
commit653fcaba5a06b8098f9bdb98c051c35a567a4513 (patch)
tree4c0cb47566019bbab09401b7287ef188322239b5 /lib
parentf127f0fb49c0f687f80588e0e1008e95be37d6ce (diff)
Resolve "Evaluationen mit Fragebögen"
Closes #703 Merge request studip/studip!363
Diffstat (limited to 'lib')
-rw-r--r--lib/classes/QuestionType.interface.php39
-rw-r--r--lib/models/Freetext.php75
-rw-r--r--lib/models/LikertScale.php115
-rw-r--r--lib/models/Questionnaire.php29
-rw-r--r--lib/models/QuestionnaireAnswer.php4
-rw-r--r--lib/models/QuestionnaireInfo.php68
-rw-r--r--lib/models/QuestionnaireQuestion.php25
-rw-r--r--lib/models/RangeScale.php114
-rw-r--r--lib/models/Test.php189
-rw-r--r--lib/models/Vote.php103
-rw-r--r--lib/modules/CoreAdmin.class.php3
-rw-r--r--lib/modules/EvaluationsWidget.php4
-rw-r--r--lib/navigation/AdminNavigation.php2
-rw-r--r--lib/navigation/ContentsNavigation.php2
-rw-r--r--lib/navigation/StartNavigation.php15
15 files changed, 438 insertions, 349 deletions
diff --git a/lib/classes/QuestionType.interface.php b/lib/classes/QuestionType.interface.php
index 342a0bb..ada6005 100644
--- a/lib/classes/QuestionType.interface.php
+++ b/lib/classes/QuestionType.interface.php
@@ -14,7 +14,14 @@ interface QuestionType {
* object but called staticly.
* @return Icon the specific icon for this type of question
*/
- static public function getIcon($active = false, $add = false);
+ static public function getIcon(bool $active = false) : Icon;
+
+
+ /**
+ * Returns the shape of the icon that is used in vue.
+ * @return string
+ */
+ static public function getIconShape();
/**
* Returns the name of the type of question like "Frage" or "Test" or "Dateiablage"
@@ -26,19 +33,20 @@ interface QuestionType {
static public function getName();
/**
- * Returns a template that is used to edit or create the question. Note that
- * $this['data'] might already be filled with data, when the user is editing an
- * existing question.
- * @return Flexi_Template
+ * Returns an array with two parts: First one is the name of the component for editing the question. Second
+ * one is the import path of the component. Plugins can use this to get their component imported.
+ * @return Array
*/
- public function getEditingTemplate();
+ static public function getEditingComponent();
/**
- * Called right before the questionnaire and the question is stored or when the user
- * needs to refresh the editing-window, This method is called to store the
- * request-values into $this['data']. You get them from the Request-class as usual.
+ * Usually the $questiondata is already in the correct format. But for some question types
+ * some data have to be manipulated by for example the HTML-purifier. So this takes
+ * the questiondata and changed them before they get stored.
+ * @param $questiondata
+ * @return mixed
*/
- public function createDataFromRequest();
+ public function beforeStoringQuestiondata($questiondata);
/**
* Display the question to the user. This template will be embedded into a
@@ -64,6 +72,15 @@ interface QuestionType {
public function createAnswer();
/**
+ * In the evaluation of the questionnaire you can click on a certain answer and get the evaluation filtered
+ * by the the people that have given that answer. This method asks from the question, what user_ids have
+ * given the answer_option. Answer option could be anything that this question understands as an answer.
+ * @param $answer_option
+ * @return mixed
+ */
+ public function getUserIdsOfFilteredAnswer($answer_option);
+
+ /**
* Returns a template with the results of this question.
* @param $only_user_ids : array\null array of user_ids that the results should be restricted to.
* this is used to show only a subset of results to the user for
@@ -95,4 +112,4 @@ interface QuestionType {
* @return void
*/
public function onEnding();
-} \ No newline at end of file
+}
diff --git a/lib/models/Freetext.php b/lib/models/Freetext.php
index 0c8272b..4cc8b62 100644
--- a/lib/models/Freetext.php
+++ b/lib/models/Freetext.php
@@ -2,73 +2,50 @@
require_once 'lib/classes/QuestionType.interface.php';
-use eTask\Task;
-
class Freetext extends QuestionnaireQuestion implements QuestionType
{
/**
* Returns the Icon-object to this QuestionType.
* @param bool $active: true if Icon should be clickable, false for black info-icon.
- * @param bool $add : true if the add-appendix shoudl be added to the icon.
* @return Icon : guestbook-icon.
*/
- public static function getIcon($active = false, $add = false)
+ public static function getIcon(bool $active = false) : Icon
{
return Icon::create(
- 'guestbook',
+ static::getIconShape(),
$active ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO
);
}
/**
- * Returns the name of this QuestionType "Freitextfrage".
+ * Returns the shape of the icon of this QuestionType
* @return string
*/
- public static function getName()
+ public static function getIconShape()
{
- return _('Freitextfrage');
+ return 'guestbook';
}
/**
- * Returns the template to edit this question
- * @return Flexi_Template
- * @throws Flexi_TemplateNotFoundException if there is no template.
+ * Returns the name of this QuestionType "Freitextfrage".
+ * @return string
*/
- public function getEditingTemplate()
+ public static function getName()
{
- $factory = new Flexi_TemplateFactory(realpath(__DIR__ . '/../../app/views'));
- $template = $factory->open('questionnaire/question_types/freetext/freetext_edit.php');
- $template->vote = $this;
- return $template;
+ return _('Freitextfrage');
}
- /**
- * Processes the request and stores the given values into the etask-object.
- * Called when the question is saved by the user.
- */
- public function createDataFromRequest()
+ static public function getEditingComponent()
{
- $questions = Request::getArray('questions');
- $data = $questions[$this->getId()];
-
- if (!$this->etask) {
- $this->etask = Task::create([
- 'type' => 'freetext',
- 'user_id' => $GLOBALS['user']->id,
- ]);
- }
-
- $this->etask->description = Studip\Markup::purifyHtml($data['description']);
- $this->etask->task = [];
-
- // update mandatory option
- if (isset($data['options']['mandatory'])) {
- $options = $this->etask->options;
- $options['mandatory'] = (bool) $data['options']['mandatory'];
- $this->etask->options = $options;
- }
+ return ['freetext-edit', ''];
+ }
- $this->etask->store();
+ public function beforeStoringQuestiondata($questiondata)
+ {
+ $questiondata['description'] = \Studip\Markup::markAsHtml(
+ \Studip\Markup::purifyHtml($questiondata['description'])
+ );
+ return $questiondata;
}
/**
@@ -98,6 +75,11 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
return $answer;
}
+ public function getUserIdsOfFilteredAnswer($answer_option)
+ {
+ return [];
+ }
+
/**
* Returns the template with the answers of the question so far.
* @param null $only_user_ids : array of user_ids
@@ -106,9 +88,18 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
*/
public function getResultTemplate($only_user_ids = null)
{
+ $answers = $this->answers;
+ if ($only_user_ids !== null) {
+ foreach ($answers as $key => $answer) {
+ if (!in_array($answer['user_id'], $only_user_ids)) {
+ unset($answers[$key]);
+ }
+ }
+ }
$factory = new Flexi_TemplateFactory(realpath(__DIR__ . '/../../app/views'));
$template = $factory->open('questionnaire/question_types/freetext/freetext_evaluation.php');
$template->vote = $this;
+ $template->set_attribute('answers', $answers);
return $template;
}
@@ -121,7 +112,7 @@ class Freetext extends QuestionnaireQuestion implements QuestionType
$output = [];
$countNobodys = 0;
- $question = trim(strip_tags($this->etask->description));
+ $question = trim(strip_tags($this->questiondata['description']));
foreach ($this->answers as $answer) {
if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
$userId = $answer['user_id'];
diff --git a/lib/models/LikertScale.php b/lib/models/LikertScale.php
new file mode 100644
index 0000000..d5d2d06
--- /dev/null
+++ b/lib/models/LikertScale.php
@@ -0,0 +1,115 @@
+<?php
+require_once 'lib/classes/QuestionType.interface.php';
+
+class LikertScale extends QuestionnaireQuestion implements QuestionType
+{
+ public static function getIcon(bool $active = false) : Icon
+ {
+ return Icon::create(static::getIconShape(), $active ? 'clickable' : 'info');
+ }
+
+ /**
+ * Returns the shape of the icon of this QuestionType
+ * @return string
+ */
+ public static function getIconShape()
+ {
+ return 'likert';
+ }
+
+ public static function getName()
+ {
+ return _('Likert-Skala');
+ }
+
+ static public function getEditingComponent()
+ {
+ return ['likert-edit', ''];
+ }
+
+ public function beforeStoringQuestiondata($questiondata)
+ {
+ $questiondata['description'] = \Studip\Markup::markAsHtml(
+ \Studip\Markup::purifyHtml($questiondata['description'])
+ );
+ $questiondata['statements'] = array_filter($questiondata['statements']);
+ return $questiondata;
+ }
+
+ public function getDisplayTemplate()
+ {
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/likert/likert_answer');
+ $template->set_attribute('vote', $this);
+ return $template;
+ }
+
+ public function createAnswer()
+ {
+ $answer = $this->getMyAnswer();
+
+ $answers = Request::getArray('answers');
+ $userAnswer = (array) $answers[$this->getId()]['answerdata']['answers'];
+ $userAnswer = array_map(function ($val) { return (int) $val; }, $userAnswer);
+ $answer->setData(['answerdata' => ['answers' => $userAnswer ] ]);
+ return $answer;
+ }
+
+ public function getUserIdsOfFilteredAnswer($answer_option)
+ {
+ $user_ids = [];
+ list($statement_key, $options_key) = explode('_', $answer_option);
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+ if ($answerData['answers'][$statement_key] == $options_key) {
+ $user_ids[] = $answer['user_id'];
+ }
+ }
+ return $user_ids;
+ }
+
+ public function getResultTemplate($only_user_ids = null, $filtered = null)
+ {
+ $answers = $this->answers;
+ if ($only_user_ids !== null) {
+ foreach ($answers as $key => $answer) {
+ if (!in_array($answer['user_id'], $only_user_ids)) {
+ unset($answers[$key]);
+ }
+ }
+ }
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/likert/likert_evaluation');
+ $template->set_attribute('vote', $this);
+ $template->set_attribute('answers', $answers);
+ $template->set_attribute('filtered', $filtered);
+ return $template;
+ }
+
+ public function getResultArray()
+ {
+ $output = [];
+
+ $statements = $this['questiondata']['statements']->getArrayCopy();
+
+ foreach ($statements as $statement_key => $statement) {
+ $answerOption = [];
+ $countNobodys = 0;
+
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+
+ if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
+ $userId = $answer['user_id'];
+ } else {
+ $countNobodys++;
+ $userId = _('unbekannt').' '.$countNobodys;
+ }
+
+ $answerOption[$userId] = $this['questiondata']['options'][$answerData['answers'][$statement_key]];
+ }
+ $output[$statement] = $answerOption;
+ }
+ return $output;
+ }
+}
diff --git a/lib/models/Questionnaire.php b/lib/models/Questionnaire.php
index cd18082..f221ca1 100644
--- a/lib/models/Questionnaire.php
+++ b/lib/models/Questionnaire.php
@@ -8,6 +8,7 @@ class Questionnaire extends SimpleORMap implements PrivacyObject
$config['has_many']['questions'] = [
'class_name' => QuestionnaireQuestion::class,
+ 'order_by' => 'ORDER BY position ASC',
'on_delete' => 'delete',
'on_store' => 'store'
];
@@ -214,7 +215,8 @@ class Questionnaire extends SimpleORMap implements PrivacyObject
}
return $this['resultvisibility'] === "always"
|| $this->isEditable()
- || ($this['resultvisibility'] === "afterending" && $this->isStopped());
+ || ($this['resultvisibility'] === "afterending" && $this->isStopped())
+ || ($this['resultvisibility'] === 'afterparticipation' && $this->isAnswered());
}
/**
@@ -236,4 +238,29 @@ class Questionnaire extends SimpleORMap implements PrivacyObject
}
}
}
+
+ /**
+ * Returns all data as an array that could be stored as JSON.
+ * @return array
+ */
+ public function exportAsFile()
+ {
+ $data = [
+ 'questionnaire' => [
+ 'title' => $this['title'],
+ 'anonymous' => $this['anonymous'],
+ 'resultvisibility' => $this['resultvisibility'],
+ 'editanswers' => $this['editanswers']
+ ],
+ 'questions_data' => []
+ ];
+ foreach ($this->questions as $question) {
+ $data['questions_data'][] = [
+ 'questiontype' => $question['questiontype'],
+ 'internal_name' => $question['internal_name'],
+ 'questiondata' => $question['questiondata']->getArrayCopy()
+ ];
+ }
+ return $data;
+ }
}
diff --git a/lib/models/QuestionnaireAnswer.php b/lib/models/QuestionnaireAnswer.php
index 6e895b6..4713b7f 100644
--- a/lib/models/QuestionnaireAnswer.php
+++ b/lib/models/QuestionnaireAnswer.php
@@ -9,6 +9,10 @@ class QuestionnaireAnswer extends SimpleORMap implements PrivacyObject
$config['belongs_to']['question'] = [
'class_name' => QuestionnaireQuestion::class,
];
+ $config['belongs_to']['user'] = [
+ 'class_name' => User::class,
+ 'foreign_key' => 'user_id'
+ ];
$config['serialized_fields']['answerdata'] = "JSONArrayObject";
parent::configure($config);
diff --git a/lib/models/QuestionnaireInfo.php b/lib/models/QuestionnaireInfo.php
new file mode 100644
index 0000000..7596586
--- /dev/null
+++ b/lib/models/QuestionnaireInfo.php
@@ -0,0 +1,68 @@
+<?php
+require_once 'lib/classes/QuestionType.interface.php';
+
+class QuestionnaireInfo extends QuestionnaireQuestion implements QuestionType
+{
+ public static function getIcon(bool $active = false) : Icon
+ {
+ return Icon::create(static::getIconShape(), $active ? 'clickable' : 'info');
+ }
+
+ /**
+ * Returns the shape of the icon of this QuestionType
+ * @return string
+ */
+ public static function getIconShape()
+ {
+ return 'info-circle';
+ }
+
+ public static function getName()
+ {
+ return _('Information');
+ }
+
+ static public function getEditingComponent()
+ {
+ return ['questionnaire-info-edit', ''];
+ }
+
+ public function beforeStoringQuestiondata($questiondata)
+ {
+ $questiondata['description'] = \Studip\Markup::markAsHtml(
+ \Studip\Markup::purifyHtml($questiondata['description'])
+ );
+ return $questiondata;
+ }
+
+ public function getDisplayTemplate()
+ {
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/info/info');
+ $template->set_attribute('vote', $this);
+ return $template;
+ }
+
+ public function createAnswer()
+ {
+
+ }
+
+ public function getUserIdsOfFilteredAnswer($answer_option)
+ {
+ return [];
+ }
+
+ public function getResultTemplate($only_user_ids = null)
+ {
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/info/info');
+ $template->set_attribute('vote', $this);
+ return $template;
+ }
+
+ public function getResultArray()
+ {
+ return [];
+ }
+}
diff --git a/lib/models/QuestionnaireQuestion.php b/lib/models/QuestionnaireQuestion.php
index 93c3279..1e37340 100644
--- a/lib/models/QuestionnaireQuestion.php
+++ b/lib/models/QuestionnaireQuestion.php
@@ -17,11 +17,7 @@ class QuestionnaireQuestion extends SimpleORMap
'on_delete' => 'delete',
'on_store' => 'store'
];
- $config['belongs_to']['etask'] = [
- 'class_name' => \eTask\Task::class,
- 'foreign_key' => 'etask_task_id'
- ];
-
+ $config['serialized_fields']['questiondata'] = 'JSONArrayObject';
parent::configure($config);
}
@@ -38,24 +34,7 @@ class QuestionnaireQuestion extends SimpleORMap
$data = $statement->fetchAll();
$questions = [];
foreach ($data as $questionnaire_data) {
-
- if (!$task = Task::find($questionnaire_data['etask_task_id'])) {
- continue;
- }
-
- $class = $task->type;
-
- if ($class === 'multiple-choice') {
- $totalScore = array_reduce(
- isset($task->task['answers']) ? $task->task['answers']->getArrayCopy() : [],
- function ($totalScore, $answer) {
- return $totalScore + intval($answer['score'] ?: 0);
- },
- 0
- );
- $class = $totalScore === 0 ? 'Vote' : 'Test';
- }
-
+ $class = $questionnaire_data['questiontype'];
if (class_exists(ucfirst($class))) {
$questions[] = $class::buildExisting($questionnaire_data);
}
diff --git a/lib/models/RangeScale.php b/lib/models/RangeScale.php
new file mode 100644
index 0000000..a196462
--- /dev/null
+++ b/lib/models/RangeScale.php
@@ -0,0 +1,114 @@
+<?php
+require_once 'lib/classes/QuestionType.interface.php';
+
+class RangeScale extends QuestionnaireQuestion implements QuestionType
+{
+ public static function getIcon(bool $active = false) : Icon
+ {
+ return Icon::create(static::getIconShape(), $active ? 'clickable' : 'info');
+ }
+
+ /**
+ * Returns the shape of the icon of this QuestionType
+ * @return string
+ */
+ public static function getIconShape()
+ {
+ return 'rangescale';
+ }
+
+ public static function getName()
+ {
+ return _('Pol-Skala');
+ }
+
+ public function beforeStoringQuestiondata($questiondata)
+ {
+ $questiondata['description'] = \Studip\Markup::markAsHtml(
+ \Studip\Markup::purifyHtml($questiondata['description'])
+ );
+ $questiondata['statements'] = array_filter($questiondata['statements']);
+ return $questiondata;
+ }
+
+ static public function getEditingComponent()
+ {
+ return ['rangescale-edit', ''];
+ }
+
+ public function getDisplayTemplate()
+ {
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/rangescale/rangescale_answer');
+ $template->set_attribute('vote', $this);
+ return $template;
+ }
+
+ public function createAnswer()
+ {
+ $answer = $this->getMyAnswer();
+
+ $answers = Request::getArray('answers');
+ $userAnswer = (array) $answers[$this->getId()]['answerdata']['answers'];
+ $answer->setData(['answerdata' => ['answers' => $userAnswer ] ]);
+ return $answer;
+ }
+
+ public function getUserIdsOfFilteredAnswer($answer_option)
+ {
+ $user_ids = [];
+ list($statement_key, $options_key) = explode('_', $answer_option);
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+ if ($answerData['answers'][$statement_key] == $options_key) {
+ $user_ids[] = $answer['user_id'];
+ }
+ }
+ return $user_ids;
+ }
+
+ public function getResultTemplate($only_user_ids = null, $filtered = null)
+ {
+ $answers = $this->answers;
+ if ($only_user_ids !== null) {
+ foreach ($answers as $key => $answer) {
+ if (!in_array($answer['user_id'], $only_user_ids)) {
+ unset($answers[$key]);
+ }
+ }
+ }
+ $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
+ $template = $factory->open('questionnaire/question_types/rangescale/rangescale_evaluation');
+ $template->set_attribute('vote', $this);
+ $template->set_attribute('answers', $answers);
+ $template->set_attribute('filtered', $filtered);
+ return $template;
+ }
+
+ public function getResultArray()
+ {
+ $output = [];
+
+ $statements = $this['questiondata']['statements']->getArrayCopy();
+
+ foreach ($statements as $statement_key => $statement) {
+ $answerOption = [];
+ $countNobodys = 0;
+
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+
+ if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
+ $userId = $answer['user_id'];
+ } else {
+ $countNobodys++;
+ $userId = _('unbekannt').' '.$countNobodys;
+ }
+
+ $answerOption[$userId] = $answerData['answers'][$statement_key];
+ }
+ $output[$statement] = $answerOption;
+ }
+ return $output;
+ }
+}
diff --git a/lib/models/Test.php b/lib/models/Test.php
deleted file mode 100644
index 53e8790..0000000
--- a/lib/models/Test.php
+++ /dev/null
@@ -1,189 +0,0 @@
-<?php
-
-require_once 'lib/classes/QuestionType.interface.php';
-
-use eTask\Task;
-
-class Test extends QuestionnaireQuestion implements QuestionType
-{
- public static function getIcon($active = false, $add = false)
- {
- return Icon::create('test', $active ? 'clickable' : 'info');
- }
-
- public static function getName()
- {
- return _('Test');
- }
-
- public function getEditingTemplate()
- {
- $tf = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
- $template = $tf->open('questionnaire/question_types/test/test_edit');
- $template->set_attribute('vote', $this);
- return $template;
- }
-
- public function createDataFromRequest()
- {
- $questions = Request::getArray('questions');
- $requestData = $questions[$this->getId()];
-
- // create a new eTask if this is a new question
- if (!$this->etask) {
- $this->etask = Task::create(
- [
- 'type' => 'multiple-choice',
- 'user_id' => $GLOBALS['user']->id,
- ]
- );
- }
-
- // update description
- $this->etask->description = Studip\Markup::purifyHtml($requestData['description']);
-
- // update task's type (single|multiple)
- $task = [
- 'type' => $requestData['task']['type'] === 'multiple' ? 'multiple' : 'single',
- 'answers' => []
- ];
-
- // update task's answers
- $correct = isset($requestData['task']['correct']) ? $requestData['task']['correct'] : [];
- foreach ($requestData['task']['answers'] as $index => $text) {
- $trimmedText = trim($text);
- if ($trimmedText === '') {
- continue;
- }
-
- $task['answers'][] = [
- 'text' => $trimmedText,
- 'score' => in_array($index + 1, $correct) ? 1 : 0,
- 'feedback' => ''
- ];
- }
-
- $this->etask->task = $task;
-
- // update randomize option
- if (isset($requestData['options']['randomize'])) {
- $options = $this->etask->options;
- $options['randomize'] = (bool) $requestData['options']['randomize'];
- $this->etask->options = $options;
- }
-
- // store the eTask instance
- $this->etask->store();
- }
-
- public function getDisplayTemplate()
- {
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
- $template = $factory->open('questionnaire/question_types/vote/vote_answer');
- $template->set_attribute('vote', $this);
- return $template;
- }
-
- public function createAnswer()
- {
- $answer = $this->getMyAnswer();
-
- $answers = Request::getArray('answers');
- if (array_key_exists($this->getId(), $answers)) {
- $userAnswer = $answers[$this->getId()]['answerdata']['answers'];
- if (is_array($userAnswer)) {
- $userAnswer = array_map('intval', $userAnswer);
- }
- else {
- $userAnswer = (int) $userAnswer;
- }
- }
- $answer->setData(['answerData' => ['answers' => $userAnswer ] ]);
- return $answer;
- }
-
- public function getResultTemplate($only_user_ids = null)
- {
- $answers = $this->answers;
- if ($only_user_ids !== null) {
- foreach ($answers as $key => $answer) {
- if (!in_array($answer['user_id'], $only_user_ids)) {
- unset($answers[$key]);
- }
- }
- }
- $factory = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
- $template = $factory->open('questionnaire/question_types/test/test_evaluation');
- $template->set_attribute('vote', $this);
- $template->set_attribute('answers', $answers);
- return $template;
- }
-
- public function getResultArray()
- {
- $output = [];
-
- $taskAnswers = $this->etask->task['answers'];
-
- foreach ($taskAnswers as $key => $option) {
- $answerOption = [];
- $countNobodys = 0;
-
- foreach ($this->answers as $answer) {
- $answerData = $answer['answerdata']->getArrayCopy();
-
- if ($answer['user_id'] && $answer['user_id'] != 'nobody') {
- $userId = $answer['user_id'];
- } else {
- $countNobodys++;
- $userId = _('unbekannt').' '.$countNobodys;
- }
-
- if (in_array($key, (array) $answerData['answers'])) {
- $answerOption[$userId] = 1;
- } else {
- $answerOption[$userId] = 0;
- }
- }
- $output[$option['text']] = $answerOption;
- }
- return $output;
- }
-
- public function correctAnswered($userId = null, $answersToCheck = null)
- {
- $userId = $userId ?: $GLOBALS['user']->id;
- $correctAnswered = true;
- $task = $this->etask->task;
- $numTaskAnswers = count($task['answers']);
- $resultsUsers = array_fill(0, $numTaskAnswers, []);
- if ($answersToCheck && !is_array($answersToCheck)) {
- $answersToCheck = [$answersToCheck];
- }
- $answersToCheck = is_array($answersToCheck) ? $answersToCheck : $this->answers->findBy('user_id', $userId);
-
- foreach ($answersToCheck as $answer) {
- if ($task['type'] === 'multiple' && is_object($answer['answerdata']['answers'])) {
- foreach ($answer['answerdata']['answers'] as $a) {
- $resultsUsers[(int) $a][] = $answer['user_id'];
- }
- } else {
- $resultsUsers[(int) $answer['answerdata']['answers']][] = $answer['user_id'];
- }
- }
- foreach ($task['answers'] as $index => $option) {
- if ($option['score']) {
- if (!in_array($userId, $resultsUsers[$index])) {
- $correctAnswered = false;
- break;
- }
- } else {
- if (in_array($userId, $resultsUsers[$index])) {
- $correctAnswered = false;
- break;
- }
- }
- }
- return $correctAnswered;
- }
-}
diff --git a/lib/models/Vote.php b/lib/models/Vote.php
index 6060f0b..12c8fee 100644
--- a/lib/models/Vote.php
+++ b/lib/models/Vote.php
@@ -1,13 +1,20 @@
<?php
require_once 'lib/classes/QuestionType.interface.php';
-use eTask\Task;
-
class Vote extends QuestionnaireQuestion implements QuestionType
{
- public static function getIcon($active = false, $add = false)
+ public static function getIcon(bool $active = false) : Icon
+ {
+ return Icon::create(static::getIconShape(), $active ? 'clickable' : 'info');
+ }
+
+ /**
+ * Returns the shape of the icon of this QuestionType
+ * @return string
+ */
+ public static function getIconShape()
{
- return Icon::create('vote', $active ? 'clickable' : 'info');
+ return 'vote';
}
public static function getName()
@@ -15,69 +22,18 @@ class Vote extends QuestionnaireQuestion implements QuestionType
return _('Auswahlfrage');
}
- public function getEditingTemplate()
+ static public function getEditingComponent()
{
- $tf = new Flexi_TemplateFactory(realpath(__DIR__.'/../../app/views'));
- $template = $tf->open('questionnaire/question_types/vote/vote_edit');
- $template->set_attribute('vote', $this);
- return $template;
+ return ['vote-edit', ''];
}
- public function createDataFromRequest()
+ public function beforeStoringQuestiondata($questiondata)
{
- $questions = Request::getArray('questions');
- $data = $questions[$this->getId()];
-
- // create a new eTask if this is a new question
- if (!$this->etask) {
- $this->etask = Task::create(
- [
- 'type' => 'multiple-choice',
- 'user_id' => $GLOBALS['user']->id,
- ]
- );
- }
-
- // update description
- $this->etask->description = Studip\Markup::purifyHtml($data['description']);
-
- // update task's type (single|multiple)
- $task = [
- 'type' => $data['task']['type'] === 'multiple' ? 'multiple' : 'single',
- 'answers' => []
- ];
-
- // update task's answers
- foreach ($data['task']['answers'] as $index => $text) {
- $trimmedText = trim($text);
- if ($trimmedText === '') {
- continue;
- }
-
- $task['answers'][] = [
- 'text' => $trimmedText,
- 'score' => 0,
- 'feedback' => ''
- ];
- }
-
- $this->etask->task = $task;
-
- // update randomize option
- if (isset($data['options']['randomize'])) {
- $options = $this->etask->options;
- $options['randomize'] = (bool) $data['options']['randomize'];
- $this->etask->options = $options;
- }
- // update mandatory option
- if (isset($data['options']['mandatory'])) {
- $options = $this->etask->options;
- $options['mandatory'] = (bool) $data['options']['mandatory'];
- $this->etask->options = $options;
- }
-
- // store the eTask instance
- $this->etask->store();
+ $questiondata['description'] = \Studip\Markup::markAsHtml(
+ \Studip\Markup::purifyHtml($questiondata['description'])
+ );
+ $questiondata['options'] = array_filter($questiondata['options']);
+ return $questiondata;
}
public function getDisplayTemplate()
@@ -106,7 +62,19 @@ class Vote extends QuestionnaireQuestion implements QuestionType
return $answer;
}
- public function getResultTemplate($only_user_ids = null)
+ public function getUserIdsOfFilteredAnswer($answer_option)
+ {
+ $user_ids = [];
+ foreach ($this->answers as $answer) {
+ $answerData = $answer['answerdata']->getArrayCopy();
+ if (in_array($answer_option, (array) $answerData['answers'])) {
+ $user_ids[] = $answer['user_id'];
+ }
+ }
+ return $user_ids;
+ }
+
+ public function getResultTemplate($only_user_ids = null, $filtered = null)
{
$answers = $this->answers;
if ($only_user_ids !== null) {
@@ -120,6 +88,7 @@ class Vote extends QuestionnaireQuestion implements QuestionType
$template = $factory->open('questionnaire/question_types/vote/vote_evaluation');
$template->set_attribute('vote', $this);
$template->set_attribute('answers', $answers);
+ $template->set_attribute('filtered', $filtered);
return $template;
}
@@ -127,9 +96,9 @@ class Vote extends QuestionnaireQuestion implements QuestionType
{
$output = [];
- $taskAnswers = $this->etask->task['answers'];
+ $options = $this['questiondata']['options'] ? $this['questiondata']['options']->getArrayCopy() : [];
- foreach ($taskAnswers as $key => $option) {
+ foreach ($options as $key => $option) {
$answerOption = [];
$countNobodys = 0;
@@ -149,7 +118,7 @@ class Vote extends QuestionnaireQuestion implements QuestionType
$answerOption[$userId] = 0;
}
}
- $output[$option['text']] = $answerOption;
+ $output[$option] = $answerOption;
}
return $output;
}
diff --git a/lib/modules/CoreAdmin.class.php b/lib/modules/CoreAdmin.class.php
index b307b6f..b02cf93 100644
--- a/lib/modules/CoreAdmin.class.php
+++ b/lib/modules/CoreAdmin.class.php
@@ -88,7 +88,8 @@ class CoreAdmin extends CorePlugin implements StudipModule
$item->setImage(Icon::create('vote'));
$item->setDescription(_('Erstellen und bearbeiten von Fragebögen.'));
$navigation->addSubNavigation('questionnaires', $item);
-
+ }
+ if (Config::get()->EVAL_ENABLE) {
$item = new Navigation(_('Evaluationen'), 'admin_evaluation.php?view=eval_sem');
$item->setImage(Icon::create('evaluation'));
$item->setDescription(_('Richten Sie fragebogenbasierte Umfragen und Lehrevaluationen ein.'));
diff --git a/lib/modules/EvaluationsWidget.php b/lib/modules/EvaluationsWidget.php
index 3c5cf6f..64458d9 100644
--- a/lib/modules/EvaluationsWidget.php
+++ b/lib/modules/EvaluationsWidget.php
@@ -46,7 +46,9 @@ class EvaluationsWidget extends CorePlugin implements PortalPlugin
$controller = app(AuthenticatedController::class, ['dispatcher' => app(\Trails_Dispatcher::class)]);
$controller->suppress_empty_output = true;
- $response = $controller->relay('evaluation/display/studip')->body;
+ if (Config::get()->EVAL_ENABLE) {
+ $response = $controller->relay('evaluation/display/studip')->body;
+ }
$controller->suppress_empty_output = (bool)$response;
$response .= $controller->relay('questionnaire/widget/start')->body;
diff --git a/lib/navigation/AdminNavigation.php b/lib/navigation/AdminNavigation.php
index b45859c..de3481b 100644
--- a/lib/navigation/AdminNavigation.php
+++ b/lib/navigation/AdminNavigation.php
@@ -75,7 +75,7 @@ class AdminNavigation extends Navigation
$navigation->addSubNavigation('faculty', new Navigation(_('Mitarbeiter'), 'dispatch.php/institute/members?admin_view=1'));
$navigation->addSubNavigation('groups', new Navigation(_('Funktionen / Gruppen'), 'dispatch.php/admin/statusgroups?type=inst'));
- if (Config::get()->VOTE_ENABLE) {
+ if (Config::get()->EVAL_ENABLE) {
$navigation->addSubNavigation('evaluation', new Navigation(_('Evaluationen'), 'admin_evaluation.php?view=eval_inst'));
}
diff --git a/lib/navigation/ContentsNavigation.php b/lib/navigation/ContentsNavigation.php
index 8e814ef..965f598 100644
--- a/lib/navigation/ContentsNavigation.php
+++ b/lib/navigation/ContentsNavigation.php
@@ -126,7 +126,9 @@ class ContentsNavigation extends Navigation
);
$questionnaire->addSubNavigation('assign', $sub_nav);
}
+ }
+ if (Config::get()->EVAL_ENABLE) {
$eval = new Navigation(_('Evaluationen'), 'admin_evaluation.php', ['rangeID' => $GLOBALS['user']->username]);
$eval->setImage(Icon::create('test'));
$eval->setDescription(_('Erstellen Sie komplexe Befragungen'));
diff --git a/lib/navigation/StartNavigation.php b/lib/navigation/StartNavigation.php
index e5779a5..6f95971 100644
--- a/lib/navigation/StartNavigation.php
+++ b/lib/navigation/StartNavigation.php
@@ -55,19 +55,6 @@ class StartNavigation extends Navigation
$statement->execute(['threshold' => $threshold,
':user_id' => $GLOBALS['user']->id, ':plugin_id' => -1]);
$vote = (int) $statement->fetchColumn();
- $query = "SELECT COUNT(IF(chdate > IFNULL(b.visitdate, :threshold) AND d.author_id != :user_id, a.eval_id, NULL))
- FROM eval_range a
- INNER JOIN eval d ON (a.eval_id = d.eval_id AND d.startdate < UNIX_TIMESTAMP() AND
- (d.stopdate > UNIX_TIMESTAMP() OR d.startdate + d.timespan > UNIX_TIMESTAMP() OR (d.stopdate IS NULL AND d.timespan IS NULL)))
- LEFT JOIN object_user_visits b ON (b.object_id = d.eval_id AND b.user_id = :user_id AND b.plugin_id = :plugin_id)
- WHERE a.range_id = 'studip'
- GROUP BY a.range_id";
- $statement = DBManager::get()->prepare($query);
- $statement->bindValue(':user_id', $GLOBALS['user']->id);
- $statement->bindValue(':threshold', $threshold);
- $statement->bindValue(':plugin_id', -2);
- $statement->execute();
- $vote += (int)$statement->fetchColumn();
}
}
@@ -243,6 +230,8 @@ class StartNavigation extends Navigation
if (Config::get()->VOTE_ENABLE) {
$navigation->addSubNavigation('questionnaire', new Navigation(_('Ankündigungen'), 'dispatch.php/news/admin_news'));
+ }
+ if (Config::get()->EVAL_ENABLE) {
$navigation->addSubNavigation('evaluation', new Navigation(_('Evaluationen'), 'admin_evaluation.php', ['rangeID' => $auth->auth['uname']]));
}