diff --git a/app/controllers/questionnaire.php b/app/controllers/questionnaire.php index c1361786f84f5faa0f6c362afe594720beac9aa4..9f16442cfcd85d6306b3a96bcbb1ab7b2055187f 100644 --- a/app/controllers/questionnaire.php +++ b/app/controllers/questionnaire.php @@ -18,6 +18,7 @@ class QuestionnaireController extends AuthenticatedController class_exists('LikertScale'); class_exists('RangeScale'); class_exists('QuestionnaireInfo'); + class_exists('QuestionnaireAutomatedData'); PageLayout::setHelpKeyword('Basis/Votings'); } diff --git a/app/views/questionnaire/edit.php b/app/views/questionnaire/edit.php index e5ef007b62e06576ba403ac5e202a81b67ca188c..cd73fbc282a24978b4d6423e62d818286284355a 100644 --- a/app/views/questionnaire/edit.php +++ b/app/views/questionnaire/edit.php @@ -13,6 +13,7 @@ foreach (get_declared_classes() as $class) { if ( is_subclass_of($class, QuestionType::class) && !isset($questiontypes[$class]) + && isset($class::getEditingComponent()[0]) ) { $questiontypes[$class] = [ 'name' => $class::getName(), diff --git a/app/views/questionnaire/question_types/automated_data/_evaluation_part.php b/app/views/questionnaire/question_types/automated_data/_evaluation_part.php new file mode 100644 index 0000000000000000000000000000000000000000..d2b7bacd945a0b02e99aeb29a2480f2432367177 --- /dev/null +++ b/app/views/questionnaire/question_types/automated_data/_evaluation_part.php @@ -0,0 +1,81 @@ +<? +/** + * @var QuestionnaireQuestion $question + * @var QuestionnaireAnswer[] $answers + * @var $filtered string + * @var $description string + * @var $answerdata array + * @var $options array + */ + +?> + +<div class="description_container"> + <div class="icon_container"> + <?= Icon::create('tan2', Icon::ROLE_INFO) ?> + </div> + <div class="description"> + <?= formatReady($description) ?> + </div> +</div> + + +<table class="default nohover"> + <tbody> + <? $countAnswers = $question->questionnaire->countAnswers() ?> + <? foreach ($options as $key => $answer) : ?> + <tr> + <? $percentage = $countAnswers && isset($answerdata[$key]) ? round(count((array) $answerdata[$key]) / $countAnswers * 100) : 0 ?> + + <td style="text-align: right; background-size: <?= $percentage ?>% 100%; background-position: right center; background-image: url('<?= Assets::image_path("vote_lightgrey.png") ?>'); background-repeat: no-repeat;" width="50%"> + <strong><?= htmlReady($answer) ?></strong> + </td> + + <td style="white-space: nowrap;"> + <? if (!empty($filtered) && $filtered == $key) : ?> + <a href="" + title="<?= _('Zeige wieder alle Ergebnisse ohne Filterung an.') ?>" + onclick="STUDIP.Questionnaire.removeFilter('<?= htmlReady($question['questionnaire_id']) ?>'); return false;"> + <?= Icon::create('filter2')->asImg(['class' => 'text-bottom']) ?> + (<?= $percentage ?>% | <?= (int) count((array) $answerdata[$key]) ?>/<?= $countAnswers ?>) + </a> + <? else : ?> + <a href="" + onclick="STUDIP.Questionnaire.addFilter('<?= htmlReady($question['questionnaire_id']) ?>', '<?= htmlReady($question->getId()) ?>', '<?= $key ?>'); return false;" + title="<?= _('Zeige nur Ergebnisse von Personen an, die diese Option gewählt haben.') ?>"> + (<?= $percentage ?>% | <?= isset($answerdata[$key]) ? count((array) $answerdata[$key]) : 0 ?>/<?= $countAnswers ?>) + </a> + <? endif ?> + </td> + + <td width="50%"> + <? if (!$question->questionnaire['anonymous'] && isset($answerdata[$key]) && $answerdata[$key]) : ?> + + <? $users = SimpleCollection::createFromArray( + User::findMany($answerdata[$key])); ?> + + <? foreach ($answerdata[$key] as $index => $user_id) : ?> + + <? $user = $users->findOneBy('user_id', $user_id); ?> + + <? if ($user) : ?> + <a href="<?= URLHelper::getLink( + 'dispatch.php/profile', + ['username' => $user->username] + ) ?>"> + <?= Avatar::getAvatar($user_id, $user->username)->getImageTag( + Avatar::SMALL, + ['title' => $user->getFullname('no_title')] + ) ?> + <? if (count($answerdata[$key]) < 4) : ?> + <?= htmlReady($user->getFullname('no_title')) ?> + <? endif ?> + </a> + <? endif ?> + <? endforeach ?> + <? endif ?> + </td> + </tr> + <? endforeach ?> + </tbody> +</table> diff --git a/app/views/questionnaire/question_types/automated_data/answer.php b/app/views/questionnaire/question_types/automated_data/answer.php new file mode 100644 index 0000000000000000000000000000000000000000..53ee2224197f121de2bafebe785e71b9e84da68c --- /dev/null +++ b/app/views/questionnaire/question_types/automated_data/answer.php @@ -0,0 +1,54 @@ +<? +/** + * @var QuestionnaireQuestion $question + */ +$data = []; +$user = User::findCurrent(); +if ($question['questiondata']['geschlecht']) { + $map = [ + 0 => _('unbekannt'), + 1 => _('männlich'), + 2 => _('weiblich'), + 3 => _('divers') + ]; + $data[] = _('Geschlecht:') . ' ' . $map[$user['geschlecht']]; +} +if ($question['questiondata']['studienfach']) { + $studienfach = []; + foreach ($user->studycourses as $studycourse) { + $studienfach[] = $studycourse->studycourse_name; + } + $data[] = _('Studienfach:') . ' ' . (implode(', ', $studienfach) ?: _('Kein Eintrag')); +} +if ($question['questiondata']['studiengang']) { + $studiengang = []; + foreach ($user->studycourses as $studycourse) { + $studiengang[] = $studycourse->studycourse_name . ' ' . $studycourse->degree_name; + } + $data[] = _('Studiengang:') . ' ' . (implode(', ', $studiengang) ?: _('Kein Eintrag')); +} +if ($question['questiondata']['studiengangfachsemester']) { + $studiengang = []; + foreach ($user->studycourses as $studycourse) { + $studiengang[] = $studycourse->studycourse_name . ' ' . $studycourse->degree_name . ' ' . $studycourse->semester; + } + $data[] = _('Studiengang und Fachsemester:') . ' ' . (implode(', ', $studiengang) ?: _('Kein Eintrag')); +} +if (isset($question['questiondata']['datafields'])) { + foreach ($question['questiondata']['datafields'] as $datafield_id) { + $datafield = DataField::find($datafield_id); + if ($datafield) { + $entry = DatafieldEntryModel::findOneBySQL('range_id = :user_id AND datafield_id = :datafield_id', [ + 'user_id' => $user->getId(), + 'datafield_id' => $datafield_id + ]); + $data[] = $datafield['name'] . ': ' . ($entry ? $entry['content'] : _('Kein Eintrag')); + } + } +} +?> +<? if ($question->questionnaire['anonymous']) : ?> + <?= MessageBox::info(_('Die folgenden Daten werden in diesem Fragebogen automatisch erfasst. Die Teilnahme an diesem Fragebogen erfolgt grundsätzlich anonym, aber eventuell können die automatisch erfassten Daten zu einer Deanonymisierung führen.'), array_map('htmlReady', $data)) ?> +<? else : ?> + <?= MessageBox::info(_('Die folgenden Daten werden in diesem Fragebogen automatisch erfasst:'), array_map('htmlReady', $data)) ?> +<? endif ?> diff --git a/app/views/questionnaire/question_types/automated_data/evaluation.php b/app/views/questionnaire/question_types/automated_data/evaluation.php new file mode 100644 index 0000000000000000000000000000000000000000..16b8f46d76fdab11d7e0455f58d90af8bec6956b --- /dev/null +++ b/app/views/questionnaire/question_types/automated_data/evaluation.php @@ -0,0 +1,110 @@ +<? +/** + * @var QuestionnaireQuestion $question + * @var QuestionnaireAnswer[] $answers + * @var $filtered string + */ +?> + +<? if ($question['questiondata']['geschlecht']) : ?> + <? $options = [ + 0 => _('unbekannt'), + 1 => _('männlich'), + 2 => _('weiblich'), + 3 => _('divers') + ]; + $answerdata = []; + foreach ($answers as $answer) { + if (isset($answer['answerdata']['geschlecht'])) { + $answerdata[$answer['answerdata']['geschlecht']][] = $answer['user_id']; + } + } + ?> + <?= $this->render_partial('questionnaire/question_types/automated_data/_evaluation_part.php', [ + 'options' => $options, + 'description' => _('Geschlecht'), + 'answerdata' => $answerdata, + ]) ?> +<? endif ?> + +<? if ($question['questiondata']['studienfach']) : ?> + <? $options = []; + $answerdata = []; + foreach ($answers as $answer) { + if (isset($answer['answerdata']['studienfach'])) { + foreach ($answer['answerdata']['studienfach'] as $studienfach) { + if (!in_array($studienfach, $options)) { + $options[$studienfach] = $studienfach; + } + $answerdata[$studienfach][] = $answer['user_id']; + } + } + } + ?> + <?= $this->render_partial('questionnaire/question_types/automated_data/_evaluation_part.php', [ + 'options' => $options, + 'description' => _('Studiengang'), + 'answerdata' => $answerdata, + ]) ?> +<? endif ?> + +<? if ($question['questiondata']['studiengang']) : ?> + <? $options = []; + $answerdata = []; + foreach ($answers as $answer) { + if (isset($answer['answerdata']['studiengang'])) { + foreach ($answer['answerdata']['studiengang'] as $studiengang) { + if (!in_array($studiengang, $options)) { + $options[$studiengang] = $studiengang; + } + $answerdata[$studiengang][] = $answer['user_id']; + } + } + } + ?> + <?= $this->render_partial('questionnaire/question_types/automated_data/_evaluation_part.php', ['options' => $options, 'description' => _('Studiengang'), 'answerdata' => $answerdata]) ?> +<? endif ?> + +<? if ($question['questiondata']['studiengangfachsemester']) : ?> + <? $options = []; + $answerdata = []; + foreach ($answers as $answer) { + if (isset($answer['answerdata']['studiengangfachsemester'])) { + foreach ($answer['answerdata']['studiengangfachsemester'] as $studiengangfachsemester) { + if (!in_array($studiengangfachsemester, $options)) { + $options[$studiengangfachsemester] = $studiengangfachsemester; + } + $answerdata[$studiengangfachsemester][] = $answer['user_id']; + } + } + } + ?> + <?= $this->render_partial('questionnaire/question_types/automated_data/_evaluation_part.php', [ + 'options' => $options, 'description' => _('Studiengang und Fachsemester'), + 'answerdata' => $answerdata, + ]) ?> +<? endif ?> + +<? if (isset($question['questiondata']['datafields'])) : + foreach ($question['questiondata']['datafields'] as $datafield_id) : + $datafield = DataField::find($datafield_id); + if ($datafield) : ?> + <? $options = []; + $answerdata = []; + foreach ($answers as $answer) { + if (isset($answer['answerdata']['datafields'][$datafield_id])) { + if (!in_array($answer['answerdata']['datafields'][$datafield_id], $options)) { + $options[$answer['answerdata']['datafields'][$datafield_id]] = $answer['answerdata']['datafields'][$datafield_id]; + } + $answerdata[$answer['answerdata']['datafields'][$datafield_id]][] = $answer['user_id']; + } + } + ?> + <?= $this->render_partial('questionnaire/question_types/automated_data/_evaluation_part.php', [ + 'options' => $options, + 'description' => $datafield['name'], + 'answerdata' => $answerdata, + ]) ?> + <? endif ?> + <? endforeach ?> +<? endif ?> diff --git a/db/migrations/6.0.33_add_automated_data_questiontype.php b/db/migrations/6.0.33_add_automated_data_questiontype.php new file mode 100644 index 0000000000000000000000000000000000000000..7a318fe269f6eb6ace74017d7ce4629dd2df8465 --- /dev/null +++ b/db/migrations/6.0.33_add_automated_data_questiontype.php @@ -0,0 +1,36 @@ +<?php + +class AddAutomatedDataQuestionType extends Migration +{ + + public function description() + { + return 'Adds a new question type Automated Data. You can disable this question type by changing the config QUESTIONNAIRE_AUTOMATED_DATA_PERM.'; + } + + public function up() + { + $query = "INSERT IGNORE INTO `config` (`field`, `value`, `type`, `range`, `section`, `mkdate`, `chdate`, `description`) + VALUES (:name, :value, :type, :range, :section, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), :description)"; + + $statement = DBManager::get()->prepare($query); + $statement->execute([ + ':name' => 'QUESTIONNAIRE_AUTOMATED_DATA_PERM', + ':description' => 'Ab welchem Status (autor, tutor, dozent, admin, root) darf man den Fragetyp Automatik in Fragebögen einbauen?', + ':range' => 'global', + ':type' => 'string', + ':section' => 'global', + ':value' => 'autor' + ]); + } + + public function down() + { + $query = "DELETE FROM `config` + WHERE `field` = 'QUESTIONNAIRE_AUTOMATED_DATA_PERM' "; + DBManager::get()->exec($query); + $query = "DELETE FROM `config_values` + WHERE `field` = 'QUESTIONNAIRE_AUTOMATED_DATA_PERM' "; + DBManager::get()->exec($query); + } +} diff --git a/lib/classes/JsonApi/RouteMap.php b/lib/classes/JsonApi/RouteMap.php index ec3668d1b2cd2f63287591915c4e0272a17fa541..c7a6c898a7f1f79f1dfb695f00b46bc4c8ac1834 100644 --- a/lib/classes/JsonApi/RouteMap.php +++ b/lib/classes/JsonApi/RouteMap.php @@ -158,6 +158,8 @@ class RouteMap $group->get('/studip/properties', Routes\Studip\PropertiesIndex::class); + $group->get('/datafields', Routes\DatafieldsIndex::class); + if (\PluginManager::getInstance()->getPlugin(\CoursewareModule::class)) { $group->get('/public/courseware/{link_id}/courseware-structural-elements/{id}', Routes\Courseware\PublicStructuralElementsShow::class); $group->get('/public/courseware/{link_id}/courseware-structural-elements', Routes\Courseware\PublicStructuralElementsIndex::class); diff --git a/lib/classes/JsonApi/Routes/DatafieldsIndex.php b/lib/classes/JsonApi/Routes/DatafieldsIndex.php new file mode 100644 index 0000000000000000000000000000000000000000..b966c71ae2e5088d73198acdfba8be6d8129710e --- /dev/null +++ b/lib/classes/JsonApi/Routes/DatafieldsIndex.php @@ -0,0 +1,38 @@ +<?php + +namespace JsonApi\Routes; + +use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; +use JsonApi\JsonApiController; + +/** + * List all the semesters. + */ +class DatafieldsIndex extends JsonApiController +{ + protected $allowedFilteringParameters = ['object_type']; + protected $allowedPagingParameters = ['offset', 'limit']; + + public function __invoke(Request $request, Response $response, $args) + { + [$offset, $limit] = $this->getOffsetAndLimit(); + + $params = $this->getQueryParameters(); + $filtering = $params->getFilteringParameters(); + if (isset($filtering['object_type'])) { + $datafields = \DataField::getDataFields($filtering['object_type']); + } else { + $datafields = \DataField::getDataFields(); + } + $datafields = array_filter( + $datafields, + fn($field) => $field->accessAllowed() + ); + + return $this->getPaginatedContentResponse( + array_slice($datafields, $offset, $limit), + count($datafields) + ); + } +} diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php index 50d67606f003ffb32467274b335a53a2fb8ff716..c651b8774dce590d4f422f08b34b3be7a04aee99 100644 --- a/lib/classes/JsonApi/SchemaMap.php +++ b/lib/classes/JsonApi/SchemaMap.php @@ -35,6 +35,7 @@ class SchemaMap \CourseMember::class => Schemas\CourseMember::class, \CourseDate::class => Schemas\CourseEvent::class, \CourseExDate::class => Schemas\CourseEvent::class, + \DataField::class => Schemas\Datafield::class, \Degree::class => Schemas\Degree::class, \FeedbackElement::class => Schemas\FeedbackElement::class, \FeedbackEntry::class => Schemas\FeedbackEntry::class, diff --git a/lib/classes/JsonApi/Schemas/Datafield.php b/lib/classes/JsonApi/Schemas/Datafield.php new file mode 100644 index 0000000000000000000000000000000000000000..74b3b9c84a19185ada1579c1fcf878dd115d6375 --- /dev/null +++ b/lib/classes/JsonApi/Schemas/Datafield.php @@ -0,0 +1,42 @@ +<?php + +namespace JsonApi\Schemas; + +use Neomerx\JsonApi\Contracts\Schema\ContextInterface; +use JsonApi\Schemas\SchemaProvider; + +class Datafield extends SchemaProvider +{ + const TYPE = 'datafield'; + + public function getId($datafield): ?string + { + return $datafield->getId(); + } + + public function getAttributes($datafield, ContextInterface $context): iterable + { + return [ + 'name' => (string) $datafield->name, + 'object_type' => $datafield->object_type, + 'object_class' => $datafield->object_class, + 'institut_id' => $datafield->institut_id, + 'priority' => $datafield->priority, + 'type' => $datafield->type, + 'typeparam' => $datafield->typeparam, + 'is_required' => (bool) $datafield->is_required, + 'default_value' => $datafield->default_value, + 'is_userfilter' => (bool) $datafield->is_userfilter, + 'mkdate' => date('c', $datafield->mkdate), + 'chdate' => date('c', $datafield->chdate) + ]; + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getRelationships($datafield, ContextInterface $context): iterable + { + return []; + } +} diff --git a/lib/models/QuestionnaireAutomatedData.php b/lib/models/QuestionnaireAutomatedData.php new file mode 100644 index 0000000000000000000000000000000000000000..5b483920d332be2e1c334e7f214c782efe935f02 --- /dev/null +++ b/lib/models/QuestionnaireAutomatedData.php @@ -0,0 +1,182 @@ +<?php + +class QuestionnaireAutomatedData extends QuestionnaireQuestion implements QuestionType +{ + public static function getIcon(bool $active = false) : Icon + { + return Icon::create(static::getIconShape(), $active ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO); + } + + /** + * Returns the shape of the icon of this QuestionType + */ + public static function getIconShape(): string + { + return 'question-automation'; + } + + public static function getName(): string + { + return _('Automatik'); + } + + public static function getEditingComponent(): array + { + if ($GLOBALS['perm']->have_perm(Config::get()->QUESTIONNAIRE_AUTOMATED_DATA_PERM)) { + return ['AutomatedDataEdit', '']; + } else { + //in this case the question_type is not allowed: + return []; + } + } + + public function beforeStoringQuestiondata($questiondata) + { + return $questiondata; + } + + public function getDisplayTemplate(): ?Flexi\Template + { + if ($GLOBALS['user']->id !== 'nobody') { + $factory = new Flexi\Factory(realpath(__DIR__.'/../../app/views')); + $template = $factory->open('questionnaire/question_types/automated_data/answer'); + $template->set_attribute('question', $this); + return $template; + } else { + return null; + } + } + + public function createAnswer(): QuestionnaireAnswer + { + $answer = $this->getMyAnswer(); + $answerdata = []; + if ($GLOBALS['user']->id !== 'nobody') { + $user = User::findCurrent(); + if ($this['questiondata']['geschlecht']) { + $answerdata['geschlecht'] = $user->geschlecht; + } + if ($this['questiondata']['studienfach']) { + $answerdata['studienfach'] = []; + foreach ($user->studycourses as $studycourse) { + $answerdata['studienfach'][] = $studycourse->studycourse_name; + } + } + if ($this['questiondata']['studiengang']) { + $answerdata['studiengang'] = []; + foreach ($user->studycourses as $studycourse) { + $answerdata['studiengang'][] = $studycourse->studycourse_name . ' ' . $studycourse->degree_name; + } + } + if ($this['questiondata']['studiengangfachsemester']) { + $answerdata['studiengangfachsemester'] = []; + foreach ($user->studycourses as $studycourse) { + $answerdata['studiengangfachsemester'][] = $studycourse->studycourse_name . ' ' . $studycourse->degree_name . ' ' . $studycourse['semester']; + } + } + foreach ($this['questiondata']['datafields'] as $datafield_id) { + $datafieldentry = DatafieldEntryModel::findOneBySQL('range_id = :user_id AND datafield_id = :datafield_id', [ + 'datafield_id' => $datafield_id, + 'user_id' => $user->getId() + ]); + $answerdata['datafields'][$datafield_id] = $datafieldentry['content']; + } + } + + $answer->answerdata = $answerdata; + return $answer; + } + + public function getUserIdsOfFilteredAnswer($answer_option): array + { + $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): Flexi\Template + { + $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\Factory(realpath(__DIR__.'/../../app/views')); + $template = $factory->open('questionnaire/question_types/automated_data/evaluation'); + $template->set_attribute('question', $this); + $template->set_attribute('answers', $answers); + return $template; + } + + public function getResultArray(): array + { + $output = []; + + $options = []; + if ($this['questiondata']['geschlecht']) { + $options['geschlecht'] = _('Geschlecht'); + } + if ($this['questiondata']['studienfach']) { + $options['studienfach'] = _('Studienfach'); + } + if ($this['questiondata']['studiengang']) { + $options['studiengang'] = _('Studiengang'); + } + if ($this['questiondata']['studiengangfachsemester']) { + $options['studiengangfachsemester'] = _('Studiengang und Fachsemester'); + } + foreach ($this['questiondata']['datafields'] as $datafield_id) { + $datafield = DataField::find($datafield_id); + if ($datafield) { + $options[$datafield_id] = (string) $datafield['name']; + } + } + + $map = [ + 0 => _('unbekannt'), + 1 => _('männlich'), + 2 => _('weiblich'), + 3 => _('divers') + ]; + + foreach ($options 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 (isset($answerData[$key])) { + if (is_array($answerData[$key])) { + $answerOption[$userId] = implode('|', $answerData[$key]); + } else { + $answerOption[$userId] = $map[$answerData[$key]]; + } + } elseif(strlen($key) === 32 && isset($answerData['datafields']) && isset($answerData['datafields'][$key])) { + $answerOption[$userId] = $answerData['datafields'][$key]; + } else { + $answerOption[$userId] = ''; + } + } + + $output[$option] = $answerOption; + } + + return $output; + } +} diff --git a/public/assets/images/icons/blue/question-automation.svg b/public/assets/images/icons/blue/question-automation.svg new file mode 100644 index 0000000000000000000000000000000000000000..de55c00dd68e020ef9bdc819fbfef5226ff2e525 --- /dev/null +++ b/public/assets/images/icons/blue/question-automation.svg @@ -0,0 +1 @@ +<svg data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path fill="none" d="M0 0h64v64H0z" data-name="Viewbox 64x64"/><path d="M26.65 13H4v38h56V13zM8 17h11.48c.33 1.28.52 2.62.52 4 0 7.45-5.1 13.7-12 15.48zm0 30v-6.43c.36-.07.73-.16 1.08-.25l1.84 2.95c.24.38.72.54 1.13.36l2.25-.93c.42-.17.65-.62.55-1.06l-.78-3.39c.7-.41 1.37-.86 2.02-1.35l2.83 2.02c.37.26.87.22 1.19-.1l1.72-1.72c.32-.32.36-.82.1-1.19l-2.02-2.83c.49-.64.94-1.32 1.35-2.02l3.39.78c.44.1.89-.13 1.06-.55l.93-2.25c.17-.42.02-.9-.36-1.13l-2.95-1.84c.2-.78.36-1.57.47-2.38l3.43-.57c.44-.07.77-.46.77-.91v-2.44c0-.45-.33-.84-.77-.91l-3.43-.57c-.06-.44-.14-.87-.22-1.3h32.43v16.03s-.05.02-.08.04l-2.83 2.02c-.64-.49-1.31-.94-2.02-1.35l.78-3.39c.1-.44-.13-.89-.55-1.06l-2.25-.93a.915.915 0 0 0-1.13.36l-1.84 2.95c-.78-.2-1.57-.36-2.38-.47l-.57-3.43a.924.924 0 0 0-.91-.77h-2.44c-.45 0-.84.33-.91.77l-.57 3.43c-.81.11-1.6.27-2.38.47l-1.84-2.95a.91.91 0 0 0-1.13-.36l-2.25.93c-.42.17-.65.62-.55 1.06l.78 3.39c-.7.41-1.37.86-2.02 1.35l-2.83-2.02a.926.926 0 0 0-1.19.1l-1.72 1.72c-.32.32-.36.82-.1 1.19l2.02 2.83c-.49.64-.94 1.32-1.35 2.02l-3.39-.78c-.44-.1-.89.13-1.06.55l-.93 2.25c-.17.42-.02.9.36 1.13l2.95 1.84c-.09.36-.18.72-.25 1.08H8Zm48 0H25.52C27.3 40.1 33.54 35 41 35c6.89 0 12.75 4.37 15 10.48z" fill="#28497c" fill-rule="evenodd"/></svg> \ No newline at end of file diff --git a/public/assets/images/icons/blue/question-automation2.svg b/public/assets/images/icons/blue/question-automation2.svg new file mode 100644 index 0000000000000000000000000000000000000000..ae65a05520057506ced24017c2d7f402f506c8a1 --- /dev/null +++ b/public/assets/images/icons/blue/question-automation2.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path fill="none" d="M0 0h64v64H0z"/><path d="M7 47h22.346l.077 1.53-.074 1.47H4V37.635l1.936-1.597L7 35.46zm53-9.145-1.884-2.122-1.116.366V47H36.4l.058.526-3.303 1.529-.096.945H60zM18.8 14H4v16.992l1.413.996L7 31.274V17h16.771l-.261-1.246-4.672-.96zM60 29.058l-1.41.857-1.59.766V17H28.976l-.254-.987L28.415 14H60z" fill="#28497C"/><path d="M28.977 17c2.253 8.85 10.288 15.392 19.84 15.392 2.909 0 5.677-.607 8.183-1.71v5.417a22.3 22.3 0 0 1-4.311 1.089l-.96 4.67a30 30 0 0 1-5.826 0l-.96-4.67a25.7 25.7 0 0 1-5.426-1.454l-3.167 3.565a30 30 0 0 1-5.045-2.913l1.504-4.525a25.6 25.6 0 0 1-3.973-3.973l-4.525 1.505a30 30 0 0 1-2.913-5.046l3.566-3.166A22 22 0 0 1 23.772 17zM60 29.058v8.797l-1.884-2.121-1.116.365v-5.418l1.59-.766zM28.722 16.013 28.415 14H18.8l.039.794 4.67.96.263 1.246h5.205z" fill="#28497C"/><path d="M7 31.274a15.8 15.8 0 0 1 3.576-1.166l.931-3.518a22 22 0 0 1 5.7 0l.931 3.518a18.8 18.8 0 0 1 5.163 1.88l2.976-2.096a22 22 0 0 1 4.365 3.663l-1.548 3.294a18.8 18.8 0 0 1 2.748 4.758l3.626.307c.518 1.652.84 3.359.932 5.086h-7.054c-.767-7.598-7.19-13.537-14.989-13.537-2.685 0-5.207.704-7.357 1.997zM36.4 47h-7.054l.078 1.53-.075 1.47h3.71l.096-.945 3.303-1.529zM5.413 31.988 7 31.274v4.186l-1.065.578L4 37.636v-6.644z" fill="#28497C"/></svg> \ No newline at end of file diff --git a/resources/assets/stylesheets/scss/questionnaire.scss b/resources/assets/stylesheets/scss/questionnaire.scss index fde7d32a2bf1c40ae29adb115cd941046ffec05f..f4d28e3219b3dd05f40a61de7dd47ee0d268c2d9 100644 --- a/resources/assets/stylesheets/scss/questionnaire.scss +++ b/resources/assets/stylesheets/scss/questionnaire.scss @@ -138,6 +138,10 @@ $width: 270px; text-align: center; } } + + .automated-data-checkbox-list { + margin-top: 20px; + } } .questionnaire_results { diff --git a/resources/vue/components/questionnaires/AutomatedDataEdit.vue b/resources/vue/components/questionnaires/AutomatedDataEdit.vue new file mode 100644 index 0000000000000000000000000000000000000000..f37bba909f9feda76b945ee730da8ff0f61f3320 --- /dev/null +++ b/resources/vue/components/questionnaires/AutomatedDataEdit.vue @@ -0,0 +1,61 @@ +<template> + <div> + <studip-message-box type="info" :hideClose="false"> + {{ $gettext('Die folgenden Daten können automatisch erfasst werden. Achtung: Diese Daten können zu einer Deanonymisierung der Teilnehmenden führen. Die Teilnehmenden sehen einen Hinweis, dass und welche Daten von ihnen erfasst werden.') }} + </studip-message-box> + <div class="automated-data-checkbox-list"> + <label> + <input v-autofocus type="checkbox" v-model="val_clone.geschlecht" true-value="1" false-value="0"> + {{ $gettext('Geschlecht') }} + </label> + <label> + <input type="checkbox" true-value="1" v-model="val_clone.studienfach" false-value="0"> + {{$gettext('Studienfach')}} + </label> + <label> + <input type="checkbox" true-value="1" v-model="val_clone.studiengang" false-value="0"> + {{$gettext('Studiengang')}} + </label> + <label> + <input type="checkbox" true-value="1" v-model="val_clone.studiengangfachsemester" false-value="0"> + {{$gettext('Studiengang-Fachsemester')}} + </label> + <label v-for="datafield in datafields" :key="datafield.datafield_id"> + <input type="checkbox" v-model="val_clone.datafields" :value="datafield.datafield_id"> + {{ datafield.name }} + </label> + </div> + </div> +</template> + +<script> +import axios from 'axios'; +import { QuestionnaireComponent } from '../../mixins/QuestionnaireComponent'; + +export default { + name: 'automated-data-edit', + mixins: [ QuestionnaireComponent ], + data() { + return { + datafields: [] + } + }, + created() { + this.setDefaultValues({ + geschlecht: 0, + studienfach: 0, + studiengang: 0, + studiengangfachsemester: 0, + datafields: [] + }); + axios.get(STUDIP.URLHelper.getURL(`jsonapi.php/v1/datafields?filter[object_type]=user`)).then((response) => { + for (let studiengang of response.data.data) { + this.datafields.push({ + datafield_id: studiengang.id, + name: studiengang.attributes.name + }); + } + }); + } +} +</script>