diff --git a/app/controllers/admin/sem_classes.php b/app/controllers/admin/sem_classes.php index 7993c4b308d8ebfd3034fd8b6e52cf2add0cd509..3dc9f269b4653a08a0da702e5dc811fcc4cea204 100644 --- a/app/controllers/admin/sem_classes.php +++ b/app/controllers/admin/sem_classes.php @@ -126,6 +126,7 @@ class Admin_SemClassesController extends AuthenticatedController $sem_class->set('show_raumzeit', Request::int("show_raumzeit")); $sem_class->set('is_group', Request::int("is_group")); $sem_class->set('unlimited_forbidden', Request::bool('unlimited_forbidden')); + $sem_class->set('admission_turnout_mandatory', Request::bool('admission_turnout_mandatory')); $sem_class->store(); foreach (array_keys($sem_class->getModules()) as $module_name) { if ($sem_class->isModuleMandatory($module_name) && !$old_data_sem_class->isModuleMandatory($module_name)) { diff --git a/app/views/admin/sem_classes/details.php b/app/views/admin/sem_classes/details.php index 54f4f903353bfc5500bef963374757a7a71bc836..530f553a51132e2b87d4a893c81053d4a78804ed 100644 --- a/app/views/admin/sem_classes/details.php +++ b/app/views/admin/sem_classes/details.php @@ -205,11 +205,15 @@ <?= _('Unbegrenzte Laufzeit verbieten') ?> </label> + <label> + <input type="checkbox" id="admission_turnout_mandatory" value="1" <?= $sem_class['admission_turnout_mandatory'] ? 'checked' : '' ?>> + <?= _('Geplante Teilnehmendenzahl muss angegeben werden') ?> + </label> + <label> <?= _('Kurzer Beschreibungstext zum Anlegen einer Veranstaltung') ?> <textarea id="create_description" maxlength="200" style="width: 100%"><?= htmlReady($sem_class['create_description']) ?></textarea> </label> - </fieldset> <fieldset class="attribute_table"> diff --git a/app/views/course/wizard/steps/basicdata/index.php b/app/views/course/wizard/steps/basicdata/index.php index 372d587821d3a68e8b2922ed9bc3378c5d9415ba..1ec8a37888f0e68df04eb81d1137303bdb101d98 100644 --- a/app/views/course/wizard/steps/basicdata/index.php +++ b/app/views/course/wizard/steps/basicdata/index.php @@ -56,6 +56,12 @@ <input type="text" name="number" id="wizard-number" size="20" maxlength="99" value="<?= htmlReady($values['number'] ?? '') ?>" <? if ($course_number_format) : ?>pattern="<?= htmlReady($course_number_format) ?>" <? endif ?>/> </section> +<section data-mandatory="<?=htmlready(json_encode($admission_turnout_mandatory_types))?>" <?=in_array($values['coursetype'],$admission_turnout_mandatory_types) ? '' : 'style="display: none"' ?>> + <label for="wizard-maxmembers" class="required"> + <?= _('max. Teilnehmendenzahl') ?> + </label> + <input type="number" name="maxmembers" id="wizard-maxmember" min="0" value="<?= htmlReady($values['maxmembers'] ?? '') ?>"/> +</section> <section> <label for="wizard-description"> <?= _('Beschreibung') ?> diff --git a/db/migrations/6.0.23_tic3967_turnout_mandatory.php b/db/migrations/6.0.23_tic3967_turnout_mandatory.php new file mode 100644 index 0000000000000000000000000000000000000000..be1bfff551acf9285802ef97bed6b74aa9fcf2e0 --- /dev/null +++ b/db/migrations/6.0.23_tic3967_turnout_mandatory.php @@ -0,0 +1,25 @@ +<?php + +final class Tic3967TurnoutMandatory extends Migration +{ + public function description() + { + return 'adds option to make admission turnout mandatory'; + } + + public function up() + { + DBManager::get()->exec(" + ALTER TABLE `sem_classes` ADD `admission_turnout_mandatory` TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER `is_group` + "); + $cache = StudipCacheFactory::getCache(); + $cache->expire('DB_SEM_CLASSES_ARRAY'); + } + + public function down() + { + DBManager::get()->exec("ALTER TABLE `sem_classes` DROP `admission_turnout_mandatory`"); + $cache = StudipCacheFactory::getCache(); + $cache->expire('DB_SEM_CLASSES_ARRAY'); + } +} diff --git a/lib/classes/SemClass.php b/lib/classes/SemClass.php index 2a038e207874a15fee33049dd68bff4106bdb0ee..e541d8c371f2b25b3551b405c1c4d586e65ce733 100644 --- a/lib/classes/SemClass.php +++ b/lib/classes/SemClass.php @@ -386,6 +386,7 @@ class SemClass implements ArrayAccess "show_raumzeit = :show_raumzeit, " . "is_group = :is_group, " . "unlimited_forbidden = :unlimited_forbidden, " . + "admission_turnout_mandatory = :admission_turnout_mandatory," . "chdate = UNIX_TIMESTAMP() " . "WHERE id = :id ". ""); @@ -430,6 +431,7 @@ class SemClass implements ArrayAccess 'show_raumzeit' => (int) $this->data['show_raumzeit'], 'is_group' => (int) $this->data['is_group'], 'unlimited_forbidden' => (int) $this->data['unlimited_forbidden'], + 'admission_turnout_mandatory' => (int) $this->data['admission_turnout_mandatory'], ]); } diff --git a/lib/classes/coursewizardsteps/BasicDataWizardStep.php b/lib/classes/coursewizardsteps/BasicDataWizardStep.php index 53c8c5026ec378ef4591c1706821f9e0a2b4b947..022f9338488b0df6bc14b4cb1935dd93e13d021e 100644 --- a/lib/classes/coursewizardsteps/BasicDataWizardStep.php +++ b/lib/classes/coursewizardsteps/BasicDataWizardStep.php @@ -48,6 +48,7 @@ class BasicDataWizardStep implements CourseWizardStep $values = $values[__CLASS__] ?? []; // Get all available course types and their categories. $typestruct = []; + $admission_turnout_mandatory_types = []; foreach (SemType::getTypes() as $type) { $class = $type->getClass(); // Creates a studygroup. @@ -62,10 +63,14 @@ class BasicDataWizardStep implements CourseWizardStep } else { if (!$class['course_creation_forbidden'] && !$class['studygroup_mode']) { $typestruct[$class['name']][] = $type; + if ($class['admission_turnout_mandatory']) { + $admission_turnout_mandatory_types[] = $type['id']; + } } } } $tpl->set_attribute('types', $typestruct); + $tpl->set_attribute('admission_turnout_mandatory_types', $admission_turnout_mandatory_types); // Select a default type if none is given. if (empty($values['coursetype'])) { if ($GLOBALS['user']->cfg->MY_COURSES_TYPE_FILTER && Request::isXhr()) { @@ -376,6 +381,11 @@ class BasicDataWizardStep implements CourseWizardStep $errors[] = _('Sie müssen die Nutzungsbedingungen akzeptieren.'); } } + $sem_type = new SemType((int)$values['coursetype']); + $sem_class = $sem_type->getClass(); + if ($sem_class['admission_turnout_mandatory'] && !$values['maxmembers']) { + $errors[] = _('Sie müssen die maximale Teilnehmendenzahl angeben'); + } if ($errors) { $ok = false; PageLayout::postError(_('Bitte beheben Sie erst folgende Fehler, bevor Sie fortfahren:'), $errors); @@ -422,6 +432,7 @@ class BasicDataWizardStep implements CourseWizardStep $course->admission_prelim = $semclass['admission_prelim_default']; $course->lesezugriff = $semclass['default_read_level'] ?: 1; $course->schreibzugriff = $semclass['default_write_level'] ?: 1; + $course->admission_turnout = $values['maxmembers']; // Studygroups: access and description. if (in_array($values['coursetype'], studygroup_sem_types())) { @@ -523,7 +534,8 @@ class BasicDataWizardStep implements CourseWizardStep 'institute' => $course->institut_id, 'description' => $course->beschreibung, 'description_i18n' => is_object($course->beschreibung) ? - $course->beschreibung->toArray() : $course->beschreibung + $course->beschreibung->toArray() : $course->beschreibung, + 'maxmembers' => $course->getSemClass()->offsetGet('admission_turnout_mandatory') ? $course->admission_turnout : '', ]; $lecturers = $course->members->findBy('status', 'dozent')->pluck('user_id'); $data['lecturers'] = array_flip($lecturers); diff --git a/resources/assets/javascripts/bootstrap/course_wizard.js b/resources/assets/javascripts/bootstrap/course_wizard.js index ef85e96661fcee47f9c3d1348875cc109d2c8d6a..a053af50f0e4b2439562fb46ddcfc439dcec7533 100644 --- a/resources/assets/javascripts/bootstrap/course_wizard.js +++ b/resources/assets/javascripts/bootstrap/course_wizard.js @@ -11,4 +11,13 @@ STUDIP.ready(function() { $(this).closest('section,footer').css('order') ); }); + $('#wizard-coursetype').on('change', function() { + let semtype = $(this).val(); + let mandatory_types = $('#wizard-maxmember').parent('section').data('mandatory'); + if (mandatory_types.includes(semtype)) { + $('#wizard-maxmember').parent('section').show(); + } else { + $('#wizard-maxmember').parent('section').hide(); + } + }); }); diff --git a/resources/assets/javascripts/lib/admin_sem_class.js b/resources/assets/javascripts/lib/admin_sem_class.js index 5ac9532468194ee2cd2b8dae99d033bd6380fd11..10f698c636b292e26c8e16b217918a834fa377c9 100644 --- a/resources/assets/javascripts/lib/admin_sem_class.js +++ b/resources/assets/javascripts/lib/admin_sem_class.js @@ -66,7 +66,8 @@ const admin_sem_class = { admission_type_default: jQuery('#admission_type_default').val(), show_raumzeit: jQuery('#show_raumzeit').is(':checked') ? 1 : 0, is_group: jQuery('#is_group').is(':checked') ? 1 : 0, - unlimited_forbidden: jQuery('#unlimited_forbidden').is(':checked') ? 1 : 0 + unlimited_forbidden: jQuery('#unlimited_forbidden').is(':checked') ? 1 : 0, + admission_turnout_mandatory: jQuery('#admission_turnout_mandatory').is(':checked') ? 1 : 0 }, type: 'POST', dataType: 'json',