diff options
| author | Thomas Hackl <hackl@data-quest.de> | 2025-01-27 15:52:02 +0000 |
|---|---|---|
| committer | Thomas Hackl <hackl@data-quest.de> | 2025-01-27 15:52:02 +0000 |
| commit | 9b2411a078a279cb4e24c0cc2ca78c032ad55e94 (patch) | |
| tree | 58a7cb651133c20280d1d7253276feb8a92e2e01 | |
| parent | e4bf27a6e37efa3d7fd5decabacfd2dc94823aa6 (diff) | |
Resolve "Fehler bei der Anmeldeset-Verwaltung"
Closes #5086
Merge request studip/studip!3823
54 files changed, 253 insertions, 803 deletions
diff --git a/app/controllers/admin/courses.php b/app/controllers/admin/courses.php index 2ff2a9e..0d65e13 100644 --- a/app/controllers/admin/courses.php +++ b/app/controllers/admin/courses.php @@ -298,7 +298,6 @@ class Admin_CoursesController extends AuthenticatedController PageLayout::setHelpKeyword('Basis.Veranstaltungen'); PageLayout::setTitle(_('Verwaltung von Veranstaltungen und Einrichtungen')); // Add admission functions. - PageLayout::addScript('studip-admission.js'); $this->max_show_courses = Config::get()->MAX_SHOW_ADMIN_COURSES; } diff --git a/app/controllers/admission/courseset.php b/app/controllers/admission/courseset.php index 90ae5f5..c13791f 100644 --- a/app/controllers/admission/courseset.php +++ b/app/controllers/admission/courseset.php @@ -34,8 +34,6 @@ class Admission_CoursesetController extends AuthenticatedController throw new AccessDeniedException(); } - PageLayout::addScript('studip-admission.js'); - $views = new ActionsWidget(); $views->addLink( _('Anmeldeset anlegen'), @@ -293,7 +291,8 @@ class Admission_CoursesetController extends AuthenticatedController $this->myUserlists ) ), - 'institute-search' => (string) $this->isearch + 'institute-search' => (string) $this->isearch, + 'instant-course-set-view' => $this->instant_course_set_view ]; if ($this->courseset) { @@ -374,9 +373,9 @@ class Admission_CoursesetController extends AuthenticatedController } PageLayout::postSuccess(sprintf(_('Das Anmeldeset: %s wurde gespeichert'), htmlReady($courseset->getName()))); if ($this->instant_course_set_view) { - $this->redirect($this->url_for('course/admission')); + $this->relocate('course/admission'); } else { - $this->redirect($this->url_for('admission/courseset/configure', $courseset->getId())); + $this->relocate('admission/courseset/configure', $courseset->getId()); } } } @@ -398,7 +397,7 @@ class Admission_CoursesetController extends AuthenticatedController $this->courseset->delete(); } - $this->redirect($this->url_for('admission/courseset')); + $this->relocate('admission/courseset'); } /** @@ -607,7 +606,7 @@ class Admission_CoursesetController extends AuthenticatedController if ($ok) { PageLayout::postSuccess(_('Die zugeordneten Veranstaltungen wurden konfiguriert.')); } - $this->redirect($this->url_for('admission/courseset/configure/' . $courseset->getId())); + $this->relocate('admission/courseset/configure/' . $courseset->getId()); return; } } diff --git a/app/controllers/admission/rule.php b/app/controllers/admission/rule.php deleted file mode 100644 index 2a41db4..0000000 --- a/app/controllers/admission/rule.php +++ /dev/null @@ -1,152 +0,0 @@ -<?php - -/** - * Admission_RuleController - Admission rules - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Thomas Hackl <thomas.hackl@uni-passau.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - * @since 3.0 - */ - -class Admission_RuleController extends AuthenticatedController -{ - /** - * @see AuthenticatedController::before_filter - */ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - if ($GLOBALS['perm']->have_perm('admin') || ($GLOBALS['perm']->have_perm('dozent') && Config::get()->ALLOW_DOZENT_COURSESET_ADMIN)) { - Navigation::activateItem('/browse/coursesets'); - } - PageLayout::setTitle(_('Anmeldesets')); - - } - - /** - * Gets the template for the rule configuration form. - * - * @param String $ruleType Class name of the rule to configure. - * @param String $ruleId Optional ID of an existing rule. - */ - public function configure_action($ruleType = '', $ruleId = '') - { - $this->ruleTypes = AdmissionRule::getAvailableAdmissionRules(); - UserFilterField::getAvailableFilterFields(); - $this->ruleType = $ruleType; - // Check if rule data has been given via request. - if (Request::getArray('rules')) { - $rule_siblings = []; - foreach (Request::getManyObjects('rules', 'AdmissionRule') as $rule) { - if ($ruleType == get_class($rule) && $rule->getId() == Request::get('ruleId')) { - $this->rule = $rule; - } else { - $rule_siblings[$rule->getId()] = $rule; - } - } - if (!$this->rule && in_array($ruleType, array_keys($this->ruleTypes))) { - $this->rule = new $ruleType($ruleId); - } - $this->rule->setSiblings($rule_siblings); - } elseif (Request::get('rule')) { - $rule = Request::getObject('rule', 'AdmissionRule'); - if ($ruleType == get_class($rule)) { - $this->rule = $rule; - } - } elseif (in_array($ruleType, array_keys($this->ruleTypes))) { - $this->rule = new $ruleType($ruleId); - } - if ($this->rule) { - $this->ruleTemplate = $this->rule->getTemplate(); - } - } - - /** - * Shows a form for selecting which rule type to use. - * - * @param String $cs_id ID of a courseset the rule shall belong to. - */ - public function select_type_action($cs_id = '') - { - $this->ruleTypes = AdmissionRule::getAvailableAdmissionRules(); - $this->courseset = new CourseSet($cs_id); - $this->courseset->clearAdmissionRules(); - foreach (Request::getManyObjects('rules', 'AdmissionRule') as $rule) { - $this->courseset->addAdmissionRule($rule); - } - } - - /** - * Saves the given rule. - * - * @param String $ruleType The class name of the configured rule. - * @param String $ruleId ID of the rule to save, or empty if this is a new rule. - */ - public function save_action($ruleType, $ruleId = '') - { - CSRFProtection::verifyUnsafeRequest(); - - $this->rule = $this->loadRule($ruleType, $ruleId); - $requestData = Request::getInstance(); - // Check for start and end date and parse the String values to timestamps. - if (!empty($requestData['start_date'])) { - $parsed = date_parse($requestData['start_date']); - $timestamp = mktime($parsed['hour'], $parsed['minute'], 0, - $parsed['month'], $parsed['day'], $parsed['year']); - $requestData['start_time'] = $timestamp; - } - if (!empty($requestData['end_date'])) { - $parsed = date_parse($requestData['end_date']); - $timestamp = mktime($parsed['hour'], $parsed['minute'], 0, - $parsed['month'], $parsed['day'], $parsed['year']); - $requestData['end_time'] = $timestamp; - } - $this->rule->setAllData($requestData); - } - - /** - * Validates if the values given in the current request are sufficient to - * configure a rule of the given type. - * - * @param String $ruleType Class name of the rule to check. - * @param String $ruleId ID of the rule to save, or empty if this is a new rule. - */ - public function validate_action($ruleType, $ruleId = '') - { - $rule = $this->loadRule($ruleType, $ruleId); - $this->errors = $rule->validate(Request::getInstance()); - } - - /** - * Loads a rule by string and ensures that it is a subclass of the abstract - * admission rule. - * - * @param string $rule_type - * @param string $rule_id - * @return AdmissionRule - */ - private function loadRule(string $rule_type, string $rule_id = ''): AdmissionRule - { - static $initialized = false; - - if (!$initialized) { - // This is neccessary so that all admission rules are correctly - // loaded and known to the system - AdmissionRule::getAvailableAdmissionRules(); - $initialized = true; - } - - if (!is_a($rule_type, AdmissionRule::class, true)) { - throw new InvalidArgumentException('Rule type must be a subclass of ' . AdmissionRule::class); - } - - return new $rule_type($rule_id); - } -} diff --git a/app/controllers/admission/ruleadministration.php b/app/controllers/admission/ruleadministration.php index 1a16910..a012aeb 100644 --- a/app/controllers/admission/ruleadministration.php +++ b/app/controllers/admission/ruleadministration.php @@ -27,7 +27,6 @@ class Admission_RuleadministrationController extends AuthenticatedController $GLOBALS['perm']->check('root'); Navigation::activateItem('/admin/config/admissionrules'); - PageLayout::addScript('studip-admission.js'); $sidebar = Sidebar::Get(); diff --git a/app/controllers/admission/userlist.php b/app/controllers/admission/userlist.php index 3192a50..25ad0ec 100644 --- a/app/controllers/admission/userlist.php +++ b/app/controllers/admission/userlist.php @@ -26,7 +26,6 @@ class Admission_UserlistController extends AuthenticatedController PageLayout::setTitle(_('Personenlisten')); Navigation::activateItem('/browse/coursesets/userlists'); - PageLayout::addScript('studip-admission.js'); Sidebar::get()->addWidget(new ActionsWidget())->addLink( _('Personenliste anlegen'), diff --git a/app/controllers/course/admission.php b/app/controllers/course/admission.php index 94f8415..5b22c82 100644 --- a/app/controllers/course/admission.php +++ b/app/controllers/course/admission.php @@ -48,7 +48,6 @@ class Course_AdmissionController extends AuthenticatedController $this->is_locked['write_level'] = 'disabled readonly'; } AdmissionApplication::addMembers($this->course->id); - PageLayout::addScript('studip-admission.js'); URLHelper::addLinkParam('return_to_dialog', Request::get('return_to_dialog')); } @@ -208,7 +207,7 @@ class Course_AdmissionController extends AuthenticatedController } } if (empty($question)) { - $this->redirect($this->action_url('index')); + $this->relocate($this->action_url('index')); } else { $this->button_yes = 'change_admission_prelim_yes'; $this->button_no = 'change_admission_prelim_no'; @@ -249,7 +248,7 @@ class Course_AdmissionController extends AuthenticatedController PageLayout::postSuccess(_("Zugriff für externe Nutzer wurde geändert.")); } } - $this->redirect($this->action_url('index')); + $this->relocate($this->action_url('index')); } function change_admission_turnout_action() @@ -313,7 +312,7 @@ class Course_AdmissionController extends AuthenticatedController } } if (empty($question)) { - $this->redirect($this->action_url('index')); + $this->relocate($this->action_url('index')); } else { $this->request = $request; $this->button_yes = 'change_admission_turnout_yes'; @@ -338,7 +337,7 @@ class Course_AdmissionController extends AuthenticatedController PageLayout::postSuccess(_('Die zugelassenen Nutzerdomänen wurden geändert.')); } } - $this->redirect($this->action_url('index')); + $this->relocate($this->action_url('index')); } function change_course_set_action() @@ -402,7 +401,7 @@ class Course_AdmissionController extends AuthenticatedController } } if (empty($question)) { - $this->redirect($this->action_url('index')); + $this->relocate($this->action_url('index')); } else { $this->request = ['change_course_set_unassign' => 1]; $this->button_yes = 'change_course_set_unassign_yes'; @@ -437,66 +436,40 @@ class Course_AdmissionController extends AuthenticatedController $rule_types = AdmissionRule::getAvailableAdmissionRules(true); if (isset($rule_types[$type])) { $rule = new $type($rule_id); - $another_rule = null; - if (isset($rule_types[$another_type])) { - $another_rule = new $another_type($another_rule_id); - } - $course_set = CourseSet::getSetForRule($rule_id) ?: new CourseSet(); - if ((Request::isPost() && Request::submitted('save')) || $rule instanceof LockedAdmission) { - if ($rule instanceof LockedAdmission) { - $course_set_id = CourseSet::getGlobalLockedAdmissionSetId(); - CourseSet::addCourseToSet($course_set_id, $this->course_id); - PageLayout::postSuccess(_('Die Veranstaltung wurde gesperrt.')); - $this->redirect($this->action_url('index')); - return; - } else { - CSRFProtection::verifyUnsafeRequest(); - $errors = $rule->validate(Request::getInstance()); - if (empty($errors)) { - $rule->setAllData(Request::getInstance()); - } - if ($another_rule) { - $another_errors = $another_rule->validate(Request::getInstance()); - if (empty($another_errors)) { - $another_rule->setAllData(Request::getInstance()); - } - $errors = array_merge($errors, $another_errors); - } - if (!mb_strlen(trim(Request::get('instant_course_set_name')))) { - $errors[] = _("Bitte geben Sie einen Namen für die Anmelderegel ein!"); - } else { - $course_set->setName(trim(Request::get('instant_course_set_name'))); - } - if (count($errors)) { - PageLayout::postError(_('Speichern fehlgeschlagen'), array_map('htmlready', $errors)); - } else { - $rule->store(); - $course_set->setPrivate(true); - $course_set->addAdmissionRule($rule); - $course_set->setAlgorithm(new RandomAlgorithm());//TODO - $course_set->setCourses([$this->course_id]); - if ($another_rule) { - $course_set->addAdmissionRule($another_rule); - } - $course_set->store(); - PageLayout::postSuccess(_("Die Anmelderegel wurde erzeugt und der Veranstaltung zugewiesen.")); - $this->redirect($this->action_url('index')); - return; - } + + if ($type === 'LockedAdmission') { + + $courseset = CourseSet::getGlobalLockedAdmissionSetId(); + CourseSet::addCourseToSet($courseset, $this->course_id); + + PageLayout::postSuccess(_('Die Veranstaltung wurde gesperrt.')); + $this->relocate('course/admission'); + + } else { + + $another_rule = null; + if (isset($rule_types[$another_type])) { + $another_rule = new $another_type($another_rule_id); } + $course_set = CourseSet::getSetForRule($rule_id) ?: new CourseSet(); + $types = [$type]; + if ($another_rule) { + $types[] = $another_type; + } + $course_set_name = $rule->getName() . ': ' . $this->course->name; + + $props = [ + 'rule-types' => $types, + 'course-set-name' => $course_set_name, + 'course-id' => $this->course_id + ]; + + $this->render_vue_app( + Studip\VueApp::create('admission/InstantCourseSet') + ->withProps($props) + ); + } - if (!$course_set->getId()) { - $course_set->setName($rule->getName() . ': ' . $this->course->name); - } - $this->rule_template = $rule->getTemplate(); - $this->type = $type; - $this->rule_id = $rule_id; - if ($another_rule) { - $this->type = $this->type . '_' . $another_type; - $this->rule_id = $this->rule_id . '_' . $another_rule->getId(); - $this->rule_template = $this->rule_template . $another_rule->getTemplate(); - } - $this->course_set_name = $course_set->getName(); } else { throw new Trails\Exception(400); } @@ -510,7 +483,7 @@ class Course_AdmissionController extends AuthenticatedController $response = $this->relay('admission/courseset/configure/' . $cs->getId()); $this->body = $response->body; if (!empty($response->headers['Location'])) { - $this->redirect($response->headers['Location']); + $this->relocate($response->headers['Location']); } } else { throw new Trails\Exception(403); @@ -525,7 +498,7 @@ class Course_AdmissionController extends AuthenticatedController $response = $this->relay('admission/courseset/save/' . $cs->getId()); $this->body = $response->body; if ($response->headers['Location']) { - $this->redirect($response->headers['Location']); + $this->relocate($response->headers['Location']); } } else { throw new Trails\Exception(403); diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php index ab1c2a6..d8ac254 100644 --- a/app/controllers/course/details.php +++ b/app/controllers/course/details.php @@ -196,7 +196,6 @@ class Course_DetailsController extends AuthenticatedController } else { PageLayout::setHelpKeyword('Basis.InVeranstaltungDetails'); PageLayout::setTitle($this->title . ' - ' . _('Details')); - PageLayout::addScript('studip-admission.js'); $sidebar = Sidebar::Get(); diff --git a/app/views/admission/rule/configure.php b/app/views/admission/rule/configure.php deleted file mode 100644 index 64908ee..0000000 --- a/app/views/admission/rule/configure.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php -use Studip\Button, Studip\LinkButton; - -/** - * @var Admission_CoursesetController $controller - * @var AdmissionRule $class - * @var string $ruleTemplate - */ -?> -<div id="errormessage"></div> - <?= $ruleTemplate ?> diff --git a/app/views/admission/rule/save.php b/app/views/admission/rule/save.php deleted file mode 100644 index 0f6e8d8..0000000 --- a/app/views/admission/rule/save.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * @var AdmissionRule $rule - * @var Admission_CoursesetController $controller - */ -?> -<div class="hover_box admissionrule" id="rule_<?= $rule->getId() ?>"> - <div id="rule_data_<?= $rule->getId() ?>" class="col-3" style="margin-top: unset"> - <?= $rule->toString() ?> - <input type="hidden" name="rules[]" value="<?= htmlReady(ObjectBuilder::exportAsJson($rule)) ?>"/> - </div> - <div class="action_icons col-1" id="rule_actions_<?= $rule->getId() ?>" style="margin-top: unset"> - <a href="#" onclick="return STUDIP.Admission.configureRule('<?= get_class($rule) ?>', '<?= - $controller->url_for('admission/rule/configure', get_class($rule), $rule->getId()) ?>', '<?= - $rule->getId() ?>')"> - <?= Icon::create('edit') ?> - </a> - <a href="javascript:STUDIP.Admission.removeRule('rule_<?= $rule->getId() ?>', 'rules')" - data-confirm="<?= _('Soll die Anmelderegel wirklich gelöscht werden?') ?>"> - <?= Icon::create('trash') ?> - </a> - </div> -</div> diff --git a/app/views/admission/rule/select_type.php b/app/views/admission/rule/select_type.php deleted file mode 100644 index 1a72a75..0000000 --- a/app/views/admission/rule/select_type.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * @var AdmissionRule[] $ruleTypes - * @var CourseSet $courseset - * @var Admission_CoursesetController $controller - */ -?> -<form name="select_rule_type" class="default" action="<?= $controller->url_for('admission/rule/configure') ?>" method="post"> - <fieldset> - <legend><?= _('Anmelderegel konfigurieren') ?></legend> - <?php - use Studip\Button, Studip\LinkButton; - - foreach ($ruleTypes as $className => $classDetail) { - $disabled = $courseset && !$courseset->isAdmissionRuleAllowed($className) ? 'disabled' : ''; - ?> - <section id="<?= $className ?>"> - <label> - <input <?=$disabled ?> type="radio" name="ruletype" value="<?= $className ?>"/> - <span <?=($disabled ? 'style="text-decoration:line-through"' : '')?>><?=$classDetail['name'] ?></span> - <?= Icon::create('question-circle')->asImg(['title' => $classDetail['description']]) ?> - </label> - </section> - - <?php - } - ?> - </fieldset> - - <footer data-dialog-button> - <?= CSRFProtection::tokenTag() ?> - <?= Button::create(_('Weiter >>'), 'configure', [ - 'onclick' => "return $('input[name=ruletype]:checked').val() ? STUDIP.Admission.configureRule($('input[name=ruletype]:checked').val(), '". - $controller->url_for('admission/rule/configure')."') : false"]) ?> - <?= LinkButton::createCancel(_('Abbrechen'), $controller->url_for('admission/courseset/configure'), ['onclick' => "STUDIP.Admission.closeDialog('configurerule'); return false;"]) ?> - </footer> -</form> diff --git a/app/views/admission/rule/validate.php b/app/views/admission/rule/validate.php deleted file mode 100644 index 4311d8d..0000000 --- a/app/views/admission/rule/validate.php +++ /dev/null @@ -1,8 +0,0 @@ -<?php -/** - * @var array $errors - */ -if ($errors) { - echo MessageBox::error(_('Fehler:'), $errors); -} -?> diff --git a/app/views/course/admission/instant_course_set.php b/app/views/course/admission/instant_course_set.php index fdd9702..01409b3 100644 --- a/app/views/course/admission/instant_course_set.php +++ b/app/views/course/admission/instant_course_set.php @@ -8,8 +8,9 @@ <input type="hidden" name="rule_id" value="<?=htmlReady($rule_id)?>"> <fieldset> <legend><?= _('Neue Anmelderegel erstellen') ?></legend> - <?= $rule_template ?> - <br> + <? foreach ($types as $type) : ?> + <admission-rule-config type="<?= htmlReady($type) ?>"></admission-rule-config> + <? endforeach ?> <label class="caption"><?= _("Name für diese Anmelderegel")?></label> <input type="text" name="instant_course_set_name" size="70" value="<?= htmlReady($course_set_name) ?>"> </fieldset> diff --git a/lib/admissionrules/conditionaladmission/ConditionalAdmission.php b/lib/admissionrules/conditionaladmission/ConditionalAdmission.php index 10bcb99..55aa317 100644 --- a/lib/admissionrules/conditionaladmission/ConditionalAdmission.php +++ b/lib/admissionrules/conditionaladmission/ConditionalAdmission.php @@ -198,24 +198,6 @@ class ConditionalAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - // Open generic admission rule template. - $tpl = $GLOBALS['template_factory']->open('admission/rules/configure'); - $tpl->set_attribute('rule', $this); - $factory = new Flexi\Factory(__DIR__ . '/templates/'); - // Now open specific template for this rule and insert base template. - $tpl2 = $factory->open('configure'); - $tpl2->set_attribute('rule', $this); - $tpl2->set_attribute('tpl', $tpl->render()); - return $tpl2->render(); - } - - /** * Helper function for loading data from DB. Generic AdmissionRule data is * loaded with the parent load() method. */ @@ -371,7 +353,7 @@ class ConditionalAdmission extends AdmissionRule $obj->setValue($field['attributes']['value']); $condition->addField($obj); } - $this->addCondition($condition, $data['conditiongroup_'.$condition->getId()], $data['quota_'.$data['conditiongroup_'.$condition->getId()]] ?? 0); + $this->addCondition($condition); } foreach ($data['grouped-conditions'] as $group) { diff --git a/lib/admissionrules/conditionaladmission/templates/configure.php b/lib/admissionrules/conditionaladmission/templates/configure.php deleted file mode 100644 index d4e7a14..0000000 --- a/lib/admissionrules/conditionaladmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="ConditionalAdmission"> - <conditional-admission></conditional-admission> -</div> diff --git a/lib/admissionrules/connectedcourseadmission/ConnectedcourseAdmission.class.php b/lib/admissionrules/connectedcourseadmission/ConnectedcourseAdmission.class.php index 40f32ac..2bc8557 100644 --- a/lib/admissionrules/connectedcourseadmission/ConnectedcourseAdmission.class.php +++ b/lib/admissionrules/connectedcourseadmission/ConnectedcourseAdmission.class.php @@ -47,20 +47,6 @@ class ConnectedcourseAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - $factory = new Flexi\Factory(dirname(__FILE__).'/templates/'); - // Now open specific template for this rule and insert base template. - $tpl = $factory->open('configure'); - $tpl->set_attribute('rule', $this); - return $tpl->render(); - } - - /** * Internal helper function for loading rule definition from database. */ public function load() diff --git a/lib/admissionrules/connectedcourseadmission/templates/configure.php b/lib/admissionrules/connectedcourseadmission/templates/configure.php deleted file mode 100644 index 4a60973..0000000 --- a/lib/admissionrules/connectedcourseadmission/templates/configure.php +++ /dev/null @@ -1,5 +0,0 @@ -<h3><?= $rule->getName() ?></h3> -<label for="message" class="caption"> - <?= _('Nachricht bei fehlgeschlagener Anmeldung') ?>: -</label> -<textarea name="message" rows="4" cols="50"><?= $rule->getMessage() ?></textarea>
\ No newline at end of file diff --git a/lib/admissionrules/coursememberadmission/CourseMemberAdmission.php b/lib/admissionrules/coursememberadmission/CourseMemberAdmission.php index 00bccee..c1a4cb0 100644 --- a/lib/admissionrules/coursememberadmission/CourseMemberAdmission.php +++ b/lib/admissionrules/coursememberadmission/CourseMemberAdmission.php @@ -78,27 +78,6 @@ class CourseMemberAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - // Open generic admission rule template. - $tpl = $GLOBALS['template_factory']->open('admission/rules/configure'); - $tpl->set_attribute('rule', $this); - - $search = new StandardSearch('Seminar_id'); - - return $this->getTemplateFactory()->render('configure', [ - 'rule' => $this, - 'tpl' => $tpl->render(), - 'courses' => $this->getDecodedCourses(), - 'search' => $search - ]); - } - - /** * Helper function for loading rule definition from database. */ public function load() diff --git a/lib/admissionrules/coursememberadmission/templates/configure.php b/lib/admissionrules/coursememberadmission/templates/configure.php deleted file mode 100644 index a86150b..0000000 --- a/lib/admissionrules/coursememberadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="CourseMemberAdmission"> - <course-member-admission></course-member-admission> -</div> diff --git a/lib/admissionrules/limitedadmission/LimitedAdmission.php b/lib/admissionrules/limitedadmission/LimitedAdmission.php index c0339cc..20893d7 100644 --- a/lib/admissionrules/limitedadmission/LimitedAdmission.php +++ b/lib/admissionrules/limitedadmission/LimitedAdmission.php @@ -118,23 +118,6 @@ class LimitedAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() { - // Open generic admission rule template. - $tpl = $GLOBALS['template_factory']->open('admission/rules/configure'); - $tpl->set_attribute('rule', $this); - $factory = new Flexi\Factory(dirname(__FILE__).'/templates/'); - // Now open specific template for this rule and insert base template. - $tpl2 = $factory->open('configure'); - $tpl2->set_attribute('rule', $this); - $tpl2->set_attribute('tpl', $tpl->render()); - return $tpl2->render(); - } - - /** * Internal helper function for loading rule definition from database. */ public function load() { diff --git a/lib/admissionrules/limitedadmission/templates/configure.php b/lib/admissionrules/limitedadmission/templates/configure.php deleted file mode 100644 index 5a2e0a9..0000000 --- a/lib/admissionrules/limitedadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="LimitedAdmission"> - <limited-admission></limited-admission> -</div> diff --git a/lib/admissionrules/lockedadmission/LockedAdmission.php b/lib/admissionrules/lockedadmission/LockedAdmission.php index afef13a..4330220 100644 --- a/lib/admissionrules/lockedadmission/LockedAdmission.php +++ b/lib/admissionrules/lockedadmission/LockedAdmission.php @@ -67,19 +67,6 @@ class LockedAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() { - $factory = new Flexi\Factory(dirname(__FILE__).'/templates/'); - // Now open specific template for this rule and insert base template. - $tpl = $factory->open('configure'); - $tpl->set_attribute('rule', $this); - return $tpl->render(); - } - - /** * Internal helper function for loading rule definition from database. */ public function load() { diff --git a/lib/admissionrules/lockedadmission/templates/configure.php b/lib/admissionrules/lockedadmission/templates/configure.php deleted file mode 100644 index 5be3f66..0000000 --- a/lib/admissionrules/lockedadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="LockedAdmission"> - <locked-admission></locked-admission> -</div> diff --git a/lib/admissionrules/participantrestrictedadmission/ParticipantRestrictedAdmission.php b/lib/admissionrules/participantrestrictedadmission/ParticipantRestrictedAdmission.php index 2954602..924ce4f 100644 --- a/lib/admissionrules/participantrestrictedadmission/ParticipantRestrictedAdmission.php +++ b/lib/admissionrules/participantrestrictedadmission/ParticipantRestrictedAdmission.php @@ -101,20 +101,6 @@ class ParticipantRestrictedAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - $factory = new Flexi\Factory(dirname(__FILE__).'/templates/'); - // Open specific template for this rule and insert base template. - $tpl = $factory->open('configure'); - $tpl->set_attribute('rule', $this); - return $tpl->render(); - } - - /** * Helper function for loading rule definition from database. */ public function load() diff --git a/lib/admissionrules/participantrestrictedadmission/templates/configure.php b/lib/admissionrules/participantrestrictedadmission/templates/configure.php deleted file mode 100644 index c2b50f3..0000000 --- a/lib/admissionrules/participantrestrictedadmission/templates/configure.php +++ /dev/null @@ -1,5 +0,0 @@ -<div data-admission-rule="ParticipantRestrictedAdmission"> - <participant-restricted-admission :distribution="<?= $rule->getDistributionTime() ?>" - :fcfs="<?= $rule->isFCFSAllowed() ? 'true' : 'false'?>" - :hasPrios="false"></participant-restricted-admission> -</div> diff --git a/lib/admissionrules/passwordadmission/PasswordAdmission.php b/lib/admissionrules/passwordadmission/PasswordAdmission.php index 85c6e2d..f94f1b4 100644 --- a/lib/admissionrules/passwordadmission/PasswordAdmission.php +++ b/lib/admissionrules/passwordadmission/PasswordAdmission.php @@ -175,10 +175,11 @@ class PasswordAdmission extends AdmissionRule * @param Array $data * @return AdmissionRule This object. */ - public function setAllData($data) { + public function setAllData($data) + { parent::setAllData($data); - if ($this->new || $data['password1'] !== '') { - $this->setPassword($data['password1']); + if ($this->new || $data['password'] !== '') { + $this->setPassword($data['password']); } return $this; } @@ -189,7 +190,8 @@ class PasswordAdmission extends AdmissionRule * @param String $clearText The clear text password to be set. * @return PasswordAdmission */ - public function setPassword($clearText) { + public function setPassword($clearText) + { $this->password = $this->hasher->HashPassword($clearText); return $this; } diff --git a/lib/admissionrules/passwordadmission/templates/configure.php b/lib/admissionrules/passwordadmission/templates/configure.php deleted file mode 100644 index 5a95b85..0000000 --- a/lib/admissionrules/passwordadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="PasswordAdmission"> - <password-admission></password-admission> -</div> diff --git a/lib/admissionrules/preferentialadmission/PreferentialAdmission.php b/lib/admissionrules/preferentialadmission/PreferentialAdmission.php index 9617f2b..c92677a 100644 --- a/lib/admissionrules/preferentialadmission/PreferentialAdmission.php +++ b/lib/admissionrules/preferentialadmission/PreferentialAdmission.php @@ -329,20 +329,6 @@ class PreferentialAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - $factory = new Flexi\Factory(__DIR__.'/templates/'); - // Now open specific template for this rule and insert base template. - $tpl = $factory->open('configure'); - $tpl->set_attribute('rule', $this); - return $tpl->render(); - } - - /** * Helper function for loading data from DB. Generic AdmissionRule data is * loaded with the parent load() method. */ diff --git a/lib/admissionrules/preferentialadmission/templates/configure.php b/lib/admissionrules/preferentialadmission/templates/configure.php deleted file mode 100644 index 240e12c..0000000 --- a/lib/admissionrules/preferentialadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="PreferentialAdmission"> - <preferential-admission></preferential-admission> -</div> diff --git a/lib/admissionrules/termsadmission/TermsAdmission.php b/lib/admissionrules/termsadmission/TermsAdmission.php index 5e98513..3fda619 100644 --- a/lib/admissionrules/termsadmission/TermsAdmission.php +++ b/lib/admissionrules/termsadmission/TermsAdmission.php @@ -79,21 +79,6 @@ class TermsAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - * @throws Flexi\TemplateNotFoundException - */ - public function getTemplate() - { - $factory = new Flexi\Factory(__DIR__ . '/templates'); - $template = $factory->open('configure'); - $template->rule = $this; - - return $template->render(); - } - - /** * Does the current rule allow the given user to register as participant * in the given course? * diff --git a/lib/admissionrules/termsadmission/templates/configure.php b/lib/admissionrules/termsadmission/templates/configure.php deleted file mode 100644 index 48d4dfd..0000000 --- a/lib/admissionrules/termsadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div data-admission-rule="TermsAdmission"> - <terms-admission terms="<?= htmlReady($rule->terms) ?>" id="<?= htmlReady($rule->getId()) ?>"></terms-admission> -</div> diff --git a/lib/admissionrules/timedadmission/TimedAdmission.php b/lib/admissionrules/timedadmission/TimedAdmission.php index 69a828e..dad423f 100644 --- a/lib/admissionrules/timedadmission/TimedAdmission.php +++ b/lib/admissionrules/timedadmission/TimedAdmission.php @@ -96,19 +96,6 @@ class TimedAdmission extends AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() { - $factory = new Flexi\Factory(dirname(__FILE__).'/templates/'); - // Open specific template for this rule and insert base template. - $tpl = $factory->open('configure'); - $tpl->set_attribute('rule', $this); - return $tpl->render(); - } - - /** * Helper function for loading rule definition from database. */ public function load() { diff --git a/lib/admissionrules/timedadmission/templates/configure.php b/lib/admissionrules/timedadmission/templates/configure.php deleted file mode 100644 index d39f6ab..0000000 --- a/lib/admissionrules/timedadmission/templates/configure.php +++ /dev/null @@ -1,3 +0,0 @@ -<div id="admission-rule" data-admission-rule="TimedAdmission"> - <timed-admission :start="<?= $startTime ?: time() ?>" :end="<?= $endTime ?: (time() + 3600) ?>"></timed-admission> -</div> diff --git a/lib/classes/admission/AdmissionRule.php b/lib/classes/admission/AdmissionRule.php index 9855165..28adfec 100644 --- a/lib/classes/admission/AdmissionRule.php +++ b/lib/classes/admission/AdmissionRule.php @@ -310,16 +310,6 @@ abstract class AdmissionRule } /** - * Gets the template that provides a configuration GUI for this rule. - * - * @return String - */ - public function getTemplate() - { - return ''; - } - - /** * Internal helper function for loading rule definition from database. */ public function load() diff --git a/resources/assets/javascripts/bootstrap/admission.js b/resources/assets/javascripts/bootstrap/admission.js index c04ff24..2fff6cf 100644 --- a/resources/assets/javascripts/bootstrap/admission.js +++ b/resources/assets/javascripts/bootstrap/admission.js @@ -22,32 +22,15 @@ STUDIP.ready(function () { components[ruleType] = result.default; STUDIP.Vue.load().then(({ createApp }) => { - createApp({ - el: container, - components: components - }); + createApp({components}).mount(container); }); }); } }); - $(document).on('change', 'tr.course input', function() { - STUDIP.Admission.toggleNotSavedAlert(); - }); - $('a.userlist-delete-user').on('click', function() { $(this).closest('tr').remove(); return false; }); - - $('#courseset-form .autosave').on('click', () => { - STUDIP.Admission.autosaveCourseset(); - }); - - STUDIP.ready(() => { - $('#toggle-date-link').on('click', () => { - $('#admissionrule-valid-date').toggleClass('hidden-js'); - }); - }); }); diff --git a/resources/assets/javascripts/entry-admission.js b/resources/assets/javascripts/entry-admission.js deleted file mode 100644 index 5454d08..0000000 --- a/resources/assets/javascripts/entry-admission.js +++ /dev/null @@ -1 +0,0 @@ -import "./bootstrap/admission.js" diff --git a/resources/assets/javascripts/entry-base.js b/resources/assets/javascripts/entry-base.js index 2210471..db3d1f6 100644 --- a/resources/assets/javascripts/entry-base.js +++ b/resources/assets/javascripts/entry-base.js @@ -78,6 +78,7 @@ import "./bootstrap/oer.js" import "./bootstrap/courseware.js" import "./bootstrap/external_pages.js" import "./bootstrap/vips.js" +import "./bootstrap/admission.js" import "./mvv_course_wizard.js" import "./mvv.js" diff --git a/resources/assets/javascripts/lib/admission.js b/resources/assets/javascripts/lib/admission.js index 8c0413a..c735cb2 100644 --- a/resources/assets/javascripts/lib/admission.js +++ b/resources/assets/javascripts/lib/admission.js @@ -2,7 +2,6 @@ * Anmeldeverfahren und -sets * ------------------------------------------------------------------------ */ import { $gettext } from './gettext'; -import Dialog from './dialog.js'; const Admission = { @@ -46,143 +45,6 @@ const Admission = { return false; }, - configureRule: function(ruleType, targetUrl, ruleId) { - var urlparts = targetUrl.split('?'); - targetUrl = urlparts[0] + '/' + ruleType; - if (urlparts[1]) { - targetUrl += '?' + urlparts[1]; - } - - Dialog.fromURL(targetUrl, { - method: 'post', - size: 'auto', - title: $gettext('Anmelderegel konfigurieren'), - id: 'configurerule', - data: { ruleId: ruleId, rules: _.map($('#rules input[name="rules[]"]'), 'value') } - }); - - return false; - }, - - selectRuleType: function(source) { - Dialog.fromURL(source, { - title: $gettext('Anmelderegel konfigurieren'), - size: 'auto', - data: { rules: _.map($('#rules input[name="rules[]"]'), 'value') }, - method: 'post', - id: 'configurerule' - }); - return false; - }, - - saveRule: function(ruleId, targetId, targetUrl) { - if ($('#action').val() !== 'cancel') { - $.ajax({ - type: 'post', - url: targetUrl, - data: $('#ruleform').serialize(), - dataType: 'html', - success: function(data) { - if (data !== '') { - var result = ''; - if ($('#norules').length > 0) { - $('#norules').remove(); - $('#' + targetId).prepend('<div id="rulelist"></div>'); - } - result += data; - if ($('#rule_' + ruleId).length !== 0) { - $('#rule_' + ruleId).replaceWith(result); - } else { - $('#rulelist').append(result); - } - } - }, - error: function(jqXHR, textStatus, errorThrown) { - alert('Status: ' + textStatus + '\nError: ' + errorThrown); - } - }); - } - Admission.closeDialog('configurerule'); - Admission.toggleNotSavedAlert(); - return false; - }, - - removeRule: function(targetId, containerId) { - var parent = $('#' + targetId).parent(); - $('#' + targetId).remove(); - if (parent.children('div').length === 0) { - parent.remove(); - var norules = $gettext('Sie haben noch keine Anmelderegeln festgelegt.'); - $('#' + containerId).prepend('<span id="norules">' + '<i>' + norules + '</i></span>'); - } - Admission.toggleNotSavedAlert(); - }, - - toggleRuleDescription: function(targetId) { - $('#' + targetId).toggle(); - return false; - }, - - toggleDetails: function(arrowId, detailId) { - var oldSrc = $('#' + arrowId).attr('src'); - var newSrc = $('#' + arrowId).attr('rel'); - $('#' + arrowId).attr('src', newSrc); - $('#' + arrowId).attr('rel', oldSrc); - $('#' + detailId).slideToggle(); - return false; - }, - - /** - * - * @param String ruleId The rule to save. - * @param String errorTarget Target element ID where error messages will be - * shown. - * @param String validateUrl URL to call for validation. - * @param String savedTarget Target element ID where the saved rule will be - * displayed. - * @param String saveUrl URL to save the rule. - */ - checkAndSaveRule: function(ruleId, errorTarget, validateUrl, savedTarget, saveUrl) { - if (Admission.validateRuleConfig(errorTarget, validateUrl)) { - Admission.saveRule(ruleId, savedTarget, saveUrl); - Dialog.close({ id: 'configurerule' }); - } - return false; - }, - - validateRuleConfig: function(containerId, targetUrl) { - var valid = true; - var error = $.ajax({ - type: 'post', - async: false, - url: targetUrl, - data: $('#ruleform').serialize(), - dataType: 'html', - - error: function(jqXHR, textStatus, errorThrown) { - alert('Status: ' + textStatus + '\nError: ' + errorThrown); - } - }).responseText; - error = error.replace(/(\r\n|\n|\r)/gm, ''); - if ($.trim(error) != '') { - $('#' + containerId).html(error); - valid = false; - } - return valid; - }, - - removeUserFromUserlist: function(userId) { - var parent = $('#user_' + userId).parent(); - $('#user_' + userId).remove(); - if (parent.children('li').length === 0) { - var nousers = $gettext('Sie haben noch niemanden hinzugefügt.'); - $(parent) - .parent() - .append('<span id="nousers">' + '<i>' + nousers + '</i></span>'); - } - return false; - }, - updateInstitutes: function(elementId, instURL, courseURL, mode) { if (elementId !== '') { var query = ''; @@ -208,26 +70,6 @@ const Admission = { } }, - checkRuleActivation: function(target) { - var form = $('#' + target); - var globalActivation = form.find('input[name=enabled]'); - if (globalActivation.prop('checked')) { - $('#activation').show(); - if (form.find('input[name=activated]:checked').val() === 'studip') { - $('#institutes_activation').hide(); - } else { - $('#institutes_activation').show(); - } - } else { - $('#activation').hide(); - $('#institutes_activation').hide(); - } - }, - - closeDialog: function(elementId) { - $('#' + elementId).remove(); - }, - checkUncheckAll: function(inputName, mode) { switch (mode) { case 'check': @@ -251,20 +93,6 @@ const Admission = { toggleNotSavedAlert: function() { $('.hidden-alert').show(); - }, - - autosaveCourseset: function() { - $.post({ - url: $('#courseset-form').attr('action'), - data: $('#courseset-form').serialize() + '&submit=1', - dataType: 'html', - success: function() { - $('.hidden-alert').hide(); - }, - error: function(jqXHR, textStatus, errorThrown) { - alert('Status: ' + textStatus + '\nError: ' + errorThrown); - } - }); } }; diff --git a/resources/assets/javascripts/studip-ui.js b/resources/assets/javascripts/studip-ui.js index d6483f3..f563b31 100644 --- a/resources/assets/javascripts/studip-ui.js +++ b/resources/assets/javascripts/studip-ui.js @@ -11,7 +11,9 @@ import RestrictedDatesHelper from './lib/RestrictedDatesHelper'; $.widget( "ui.dialog", $.ui.dialog, { _allowInteraction: function( event ) { - return hasParentWhich(isCKBodyWrapper)(event.target) || this._super( event ); + return hasParentWhich(isCKBodyWrapper)(event.target) + || event.target.closest('.studip-dialog') !== null + || this._super( event ); }, }); diff --git a/resources/assets/stylesheets/scss/admission.scss b/resources/assets/stylesheets/scss/admission.scss index d9d978c..50fce65 100644 --- a/resources/assets/stylesheets/scss/admission.scss +++ b/resources/assets/stylesheets/scss/admission.scss @@ -1,17 +1,3 @@ -#rulelist div.admissionrule { - display: list-item; - list-style-type: disc; - margin-left: 25px; -} - -#toggle-date-container { - margin-top: 10px; - - img, svg { - vertical-align: text-bottom; - } -} - .hover_box { div { display: inline; @@ -88,23 +74,6 @@ form.default { } } -#userlists { - div { - margin-bottom: 10px; - - a { - &.userlist-action { - margin-left: 2px; - margin-right: 2px; - } - - img { - vertical-align: bottom; - } - } - } -} - form { fieldset { section { diff --git a/resources/vue/components/Quicksearch.vue b/resources/vue/components/Quicksearch.vue index 1a61513..9177ae5 100644 --- a/resources/vue/components/Quicksearch.vue +++ b/resources/vue/components/Quicksearch.vue @@ -32,7 +32,7 @@ <script> export default { name: 'quicksearch', - emits: ['update:modelValue'], + emits: ['update:modelValue', 'input'], props: { searchtype: { type: String, @@ -125,6 +125,7 @@ export default { this.results = []; this.$emit('update:modelValue', this.returnValue, this.inputValue); + this.$emit('input', this.returnValue, this.inputValue); if (!this.keepValue) { this.inputValue = ''; diff --git a/resources/vue/components/StudipDialog.vue b/resources/vue/components/StudipDialog.vue index ab42f48..94f95ed 100644 --- a/resources/vue/components/StudipDialog.vue +++ b/resources/vue/components/StudipDialog.vue @@ -1,7 +1,7 @@ <template> <Teleport to="body"> <focus-trap v-model="trap"> - <div class="studip-dialog" @keydown.esc="closeDialog"> + <div class="studip-dialog" @keydown.esc="closeDialog" :style="{zIndex: zIndex}"> <transition name="dialog-fade"> <div class="studip-dialog-backdrop" v-if="true"> <vue-resizeable @@ -170,6 +170,8 @@ export default { handlers: ["r", "rb", "b", "lb", "l", "lt", "t", "rt"], fit: false, footerHeight: 68, + + zIndex: null, }; }, computed: { @@ -279,6 +281,16 @@ export default { this.$refs.buttonB.focus(); }); } + }, + created() { + const maxZIndex = Array.from(document.querySelectorAll('.studip-dialog')).reduce( + (acc, el) => { + const style = getComputedStyle(el); + return Math.max(acc, Number.parseInt(style.zIndex, 10)); + }, + 1 + ); + this.zIndex = maxZIndex + 1; } }; </script> diff --git a/resources/vue/components/admission/AdmissionRuleConfig.vue b/resources/vue/components/admission/AdmissionRuleConfig.vue index 921a6c2..d6d6e65 100644 --- a/resources/vue/components/admission/AdmissionRuleConfig.vue +++ b/resources/vue/components/admission/AdmissionRuleConfig.vue @@ -1,5 +1,5 @@ <template> - <studip-dialog v-if="component !== null" + <studip-dialog v-if="useDialog && component !== null" :title="$gettext('Anmelderegel bearbeiten')" :close-text="$gettext('Abbrechen')" @close="cancel" @@ -25,6 +25,18 @@ </button> </template> </studip-dialog> + <div v-if="!useDialog && component !== null"> + <studip-message-box v-if="invalidData?.length" + type="error" + :details="invalidData" + :hide-close="true" + :hide-details="false" + :aria-description="errorText" + role="alert"> + {{ $gettext('Es sind ungültige Daten angegeben worden:') }} + </studip-message-box> + <component :is="component" v-bind="props" @submit="submit" @error="error"></component> + </div> </template> <script> @@ -32,7 +44,7 @@ import {shallowRef} from "vue"; export default { name: 'AdmissionRuleConfig', - emits: ['cancel', 'submit'], + emits: ['cancel', 'submit', 'error'], props: { type: { type: String, @@ -45,6 +57,10 @@ export default { assignedRuleTypes: { type: Array, default: () => [] + }, + useDialog: { + type: Boolean, + default: true } }, data() { diff --git a/resources/vue/components/admission/ConfigureCourseSet.vue b/resources/vue/components/admission/ConfigureCourseSet.vue index 226de37..8bd46f3 100644 --- a/resources/vue/components/admission/ConfigureCourseSet.vue +++ b/resources/vue/components/admission/ConfigureCourseSet.vue @@ -327,7 +327,7 @@ </button> <button class="button cancel" type="button" - data-dialog="close" + data-dialog-close @click.prevent="cancel" > {{ $gettext('Abbrechen') }} @@ -382,6 +382,10 @@ export default { myUserLists: { type: Array, default: () => [] + }, + instantCourseSetView: { + type: Boolean, + default: false } }, data() { @@ -413,7 +417,7 @@ export default { computed: { isStorable() { return this.name !== '' - && this.institutes.length > 0 + && (this.courseSetId !== '' || this.courseSetId === '' && this.institutes.length > 0) && this.rules.length > 0; }, hasConfigurableCourses() { @@ -498,7 +502,7 @@ export default { this.showRuleConfig = true; }, addRuleConfiguration(data) { - if (!this.ruleId) { + if (!this.ruleId || this.ruleId === data.type + '_') { STUDIP.jsonapi.withPromises().post( 'admission-rules/' + data.type, { @@ -566,7 +570,7 @@ export default { } }, addInstitute(returnValue, inputValue) { - if (!this.institutes.some(i => i.id === returnValue)) { + if (inputValue && !this.institutes.some(i => i.id === returnValue)) { this.institutes.push({ id: returnValue, name: inputValue }); } }, @@ -594,7 +598,11 @@ export default { { data: data } ).then(() => { this.$refs.courseSetForm.dataset.secure = 'false'; - window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + if (!this.instantCourseSetView) { + window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + } else { + window.location.reload(); + } }); } else { @@ -604,28 +612,31 @@ export default { { data: data} ).then(() => { this.$refs.courseSetForm.dataset.secure = 'false'; - window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + if (!this.instantCourseSetView) { + window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + } else { + window.location.reload(); + } }); } }, cancel() { - window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + if (!this.instantCourseSetView) { + window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset'); + } }, - configureCourses() - { + configureCourses() { STUDIP.Dialog.fromURL( STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/configure_courses/' + this.courseSetId) ); }, - getApplicants() - { + getApplicants() { STUDIP.Dialog.fromURL( STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/applications_list/' + this.courseSetId) ); }, - messageApplicants() - { + messageApplicants() { STUDIP.Dialog.fromURL( STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/applicants_message/' + this.courseSetId) ); diff --git a/resources/vue/components/admission/CourseMemberAdmission.vue b/resources/vue/components/admission/CourseMemberAdmission.vue index 9e689c5..3684eb3 100644 --- a/resources/vue/components/admission/CourseMemberAdmission.vue +++ b/resources/vue/components/admission/CourseMemberAdmission.vue @@ -24,8 +24,7 @@ <quicksearch v-if="courseSearch !== null" :searchtype="courseSearch" name="course" - :key="NaN" - @input="addCourse" + @update:model-value="addCourse" id="csearch" ref="courseSearch"></quicksearch> <ul v-if="courseList.length > 0"> @@ -89,7 +88,7 @@ export default { return this.invalidData.length === 0; }, }, - mounted() { + created() { // Get a new rule instance so we can use quicksearch. if (!this.id || this.id === '') { STUDIP.jsonapi.withPromises().post('admission-rules/CourseMemberAdmission', { @@ -97,7 +96,7 @@ export default { data: { attributes: { payload: { - mode: 0, + modus: 0, courses: [], message: '' } diff --git a/resources/vue/components/admission/InstantCourseSet.vue b/resources/vue/components/admission/InstantCourseSet.vue new file mode 100644 index 0000000..ec555c6 --- /dev/null +++ b/resources/vue/components/admission/InstantCourseSet.vue @@ -0,0 +1,102 @@ +<template> + <form v-if="!working" class="default"> + <section v-for="(type, index) in ruleTypes" :key="index"> + <admission-rule-config :type="type" + :use-dialog="false" + @submit="ruleData"></admission-rule-config> + </section> + <section> + <label class="caption"> + {{ $gettext("Name für diese Anmelderegel") }} + <input type="text" name="instant_course_set_name" size="70" v-model="name"> + </label> + </section> + <footer data-dialog-button> + <button class="button accept" @click.prevent="triggerRules"> + {{ $gettext('Speichern') }} + </button> + <button class="button cancel" data-dialog-close> + {{ $gettext('Abbrechen') }} + </button> + </footer> + </form> +</template> + +<script> +import AdmissionRuleConfig from './AdmissionRuleConfig'; + +export default { + name: 'InstantCourseSet', + components: { AdmissionRuleConfig }, + props: { + ruleTypes: { + type: Array, + required: true + }, + courseSetName: { + type: String, + required: true + }, + courseId: { + type: String, + required: true + } + }, + data() { + return { + name: this.courseSetName, + rules: [], + working: false + } + }, + methods: { + ruleData(data) { + this.working = true; + this.rules.push(data); + + // Check if all rultTypes have some data. If yes, the whole courseset can be stored. + let canStore = true; + for (let i = 0 ; i < this.ruleTypes.length ; i++) { + if (this.rules.filter(rule => rule.type === this.ruleTypes[i]).length === 0) { + canStore = false; + } + } + + if (canStore) { + this.store(); + } + }, + triggerRules() { + STUDIP.eventBus.emit('getRuleConfiguration'); + }, + store() { + const data = { + data: { + attributes: { + name: this.name, + private: true, + infotext: '', + institutes: [], + courses: [ this.courseId ], + rules: this.rules.map((rule) => { return { attributes: rule } } ), + userlists: [] + } + } + }; + + STUDIP.jsonapi.withPromises().post( + 'course-sets', + { data: data } + ).then(() => { + STUDIP.Report.success(this.$gettext('Die Zugangsberechtigungen wurden gespeichert.')); + window.location = STUDIP.URLHelper.getURL('dispatch.php/course/admission', {cid: this.courseId}); + }); + } + }, + created() { + for (let i = 0 ; i < this.ruleTypes.length ; i++) { + this.rules[this.ruleTypes[i]] = {}; + } + } +} +</script> diff --git a/resources/vue/components/admission/ParticipantRestrictedAdmission.vue b/resources/vue/components/admission/ParticipantRestrictedAdmission.vue index 9f75b9a..96b6cfb 100644 --- a/resources/vue/components/admission/ParticipantRestrictedAdmission.vue +++ b/resources/vue/components/admission/ParticipantRestrictedAdmission.vue @@ -1,4 +1,4 @@ -<template> + <template> <form class="default"> <section> <label> @@ -16,7 +16,7 @@ <section v-if="!fcfsAllowed || !fcfsEnabled"> <label> {{ $gettext('Zeitpunkt der automatischen Platzverteilung') }} - <datetimepicker v-if="loaded" :value="distributionTime" v-model="distributionTime"></datetimepicker> + <datetimepicker v-model="distributionTime"></datetimepicker> </label> </section> </form> @@ -24,17 +24,17 @@ <script> import { AdmissionRuleMixin } from '../../mixins/AdmissionRuleMixin'; -import Datetimepicker from '../Datetimepicker.vue'; +import datetimepicker from '../Datetimepicker.vue'; import StudipTooltipIcon from '../StudipTooltipIcon.vue'; export default { name: 'ParticipantRestrictedAdmission', - components: { StudipTooltipIcon, Datetimepicker }, + components: { StudipTooltipIcon, datetimepicker }, mixins: [AdmissionRuleMixin], props: { distribution: { type: Number, - default: Math.floor(new Date().getTime() / 1000 + 86400) + default: 0 }, fcfs: { type: Boolean, @@ -54,8 +54,7 @@ export default { messageText: this.message, fcfsAllowed: true, fcfsEnabled: this.distributionTime === 0, - distributionTime: this.distribution, - loaded: false + distributionTime: this.distribution !== 0 ? this.distribution : Math.floor(Date.now() / 1000 + 7 * 86400) } }, computed: { @@ -78,13 +77,23 @@ export default { ? data.attributes.payload['distribution-time'] : Math.floor(Date.now() / 1000 + 7 * 86400); this.fcfsEnabled = data.attributes.payload['distribution-time'] === 0; - this.loaded = true; - } - }, - created() { - if (!this.id) { - this.distributionTime = Math.floor(new Date().getTime() / 1000 + 86400); - this.loaded = true; + }, + validate() { + // Earliest possible date for seat distribution is 2 hours from now. + const earliest = new Date(); + earliest.setHours( earliest.getHours() + 2); + + if (!this.fcfsEnabled && this.distributionTime <= Math.floor(earliest.getTime() / 1000)) { + this.invalidData.push( + this.$gettext( + 'Geben Sie für die Platzverteilung ein Datum an, das weiter in der Zukunft liegt. ' + + 'Das frühestmögliche Datum ist %{earliest}.', + {earliest: earliest.toLocaleString('de-de')} + ) + ); + } + + return this.invalidData.length === 0; } } } diff --git a/resources/vue/components/admission/TimedAdmission.vue b/resources/vue/components/admission/TimedAdmission.vue index ebdc397..2437d7e 100644 --- a/resources/vue/components/admission/TimedAdmission.vue +++ b/resources/vue/components/admission/TimedAdmission.vue @@ -23,9 +23,10 @@ <script> import { AdmissionRuleMixin } from '../../mixins/AdmissionRuleMixin'; - +import datetimepicker from "../Datetimepicker.vue"; export default { name: 'TimedAdmission', + components: { datetimepicker }, mixins: [ AdmissionRuleMixin ], props: { start: { diff --git a/resources/vue/components/admission/ValidityTime.vue b/resources/vue/components/admission/ValidityTime.vue index 067567c..32efd04 100644 --- a/resources/vue/components/admission/ValidityTime.vue +++ b/resources/vue/components/admission/ValidityTime.vue @@ -16,24 +16,24 @@ <section v-if="configureTime" class="col-3"> <label> {{ $gettext('Diese Regel gilt von') }} - <datetimepicker :value="startTime"></datetimepicker> + <datetimepicker v-model="startTime"></datetimepicker> </label> </section> <section v-if="configureTime" class="col-3"> <label> {{ $gettext('bis') }} - <datetimepicker :value="endTime"></datetimepicker> + <datetimepicker v-model="endTime"></datetimepicker> </label> </section> </div> </template> <script> -import Datetimepicker from '../Datetimepicker.vue'; +import datetimepicker from '../Datetimepicker.vue'; export default { name: 'ValidityTime', - components: { Datetimepicker }, + components: { datetimepicker }, props: { start: { type: Number, diff --git a/resources/vue/mixins/AdmissionRuleMixin.js b/resources/vue/mixins/AdmissionRuleMixin.js index 0badb1a..80f6ec5 100644 --- a/resources/vue/mixins/AdmissionRuleMixin.js +++ b/resources/vue/mixins/AdmissionRuleMixin.js @@ -42,7 +42,7 @@ export const AdmissionRuleMixin = { } } }, - mounted() { + created() { if (this.id && this.id !== '' && !this.ruleData) { this.loadRuleData(); } diff --git a/templates/admission/rules/configure.php b/templates/admission/rules/configure.php deleted file mode 100644 index 4a74c1d..0000000 --- a/templates/admission/rules/configure.php +++ /dev/null @@ -1,37 +0,0 @@ -<label for="message" class="caption"> - <?= _('Nachricht bei fehlgeschlagener Anmeldung') ?>: - <?= (mb_strpos($rule->getMessage(),'%s') ? tooltipicon(_("Die Zeichen %s sind ein Platzhalter für änderbare Bedingungen")) : '')?> -</label> -<textarea name="message" rows="4" cols="50"><?= htmlReady($rule->getMessage()) ?></textarea> -<br/> -<div id="toggle-date-container"> - <a href="#" id="toggle-date-link"> - <?= Icon::create('date') ?> - <?= _('Gültigkeitszeitraum dieser Regel festlegen') ?> - </a> -</div> -<div id="admissionrule-valid-date"<?= $rule->getStartTime() || $rule->getEndTime() ? - '' : ' class="hidden-js"' ?>> - <b><?= _('Hiermit verändern Sie nur, wann die in dieser Regel getroffenen ' . - 'Einstellungen gelten sollen, und nicht den generellen Anmeldezeitraum!') ?></b> - <section class="form_group hgroup"> - <label> - <?= _('von') ?> - <input type="text" maxlength="16" name="start_date" class="size-s no-hint" - id="start_date" value="<?= $rule->getStartTime() ? - date('d.m.Y H:i', $rule->getStartTime()) : '' ?>" - placeholder="tt.mm.jjjj --:--" data-datetime-picker> - </label> - <label> - <?= _('bis') ?> - <input type="text" maxlength="16" name="end_date" class="size-s no-hint" - id="end_date" value="<?= $rule->getEndTime() ? - date('d.m.Y H:i', $rule->getEndTime()) : '' ?>" - placeholder="tt.mm.jjjj --:--" data-datetimepicker='{">":"#start_date"}'> - </label> - <script> - $('#start_date').datetimepicker(); - $('#end_date').datetimepicker(); - </script> - </section> -</div> diff --git a/templates/admission/rules/input_end.php b/templates/admission/rules/input_end.php deleted file mode 100644 index 26f0516..0000000 --- a/templates/admission/rules/input_end.php +++ /dev/null @@ -1 +0,0 @@ -</form>
\ No newline at end of file diff --git a/templates/admission/rules/input_start.php b/templates/admission/rules/input_start.php deleted file mode 100644 index 8450192..0000000 --- a/templates/admission/rules/input_start.php +++ /dev/null @@ -1 +0,0 @@ -<form action="" method="post" class="default"> diff --git a/templates/forms/quicksearch_input.php b/templates/forms/quicksearch_input.php index 46680a1..4788c69 100644 --- a/templates/forms/quicksearch_input.php +++ b/templates/forms/quicksearch_input.php @@ -10,7 +10,7 @@ <span> <quicksearch value="<?= htmlReady($value) ?>" name="<?= htmlReady($name) ?>" - @update:modelValue="(new_id, new_item_name) => { console.log(new_id); this.<?= htmlReady($name) ?> = new_id; }" + @update:modelValue="(new_id, new_item_name) => { this.<?= htmlReady($name) ?> = new_id; }" id="<?= $id ?>" <?= ($this->required ? 'required aria-required="true"' : '') ?> <?= $attributes ?>> diff --git a/webpack.common.js b/webpack.common.js index bded2cf..c18818d 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -11,7 +11,6 @@ const assetsPath = path.resolve(__dirname, "resources/assets/javascripts"); module.exports = { entry: { "studip-base": assetsPath + "/entry-base.js", - "studip-admission": assetsPath + "/entry-admission.js", "studip-statusgroups": assetsPath + "/entry-statusgroups.js", "studip-wysiwyg": assetsPath + "/entry-wysiwyg.js", "studip-installer": assetsPath + "/entry-installer.js", |
