Skip to content
Snippets Groups Projects
Commit 55966778 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

TIC #9569

parent 9dcac1b5
No related branches found
No related tags found
No related merge requests found
<?php
class CourseMemberAdmissionCourseIdType extends Migration
{
public function description()
{
return "Save course ids as JSON instead of plain text.";
}
public function up()
{
DBManager::get()->exec("
ALTER TABLE `coursememberadmissions`
ADD COLUMN `courses` JSON default NULL AFTER `course_id`
");
DBManager::get()->exec("UPDATE `coursememberadmissions`
SET `courses` = JSON_ARRAY_APPEND('[]', '$', `course_id`)
WHERE `course_id` != ''
");
DBManager::get()->exec("ALTER TABLE `coursememberadmissions`
DROP COLUMN `course_id`");
}
public function down()
{
$query = "ALTER TABLE `coursememberadmissions`
ADD COLUMN `course_id` CHAR(32) CHARACTER SET `latin1` COLLATE `latin1_bin` NOT NULL DEFAULT ''";
DBManager::get()->exec($query);
$query = "UPDATE `coursememberadmissions`
SET `course_id` = IFNULL(JSON_EXTRACT(`courses`, '$[0]'), '')";
DBManager::get()->exec($query);
$query = "ALTER TABLE `coursememberadmissions`
DROP COLUMN `courses`";
DBManager::get()->exec($query);
}
}
......@@ -17,14 +17,15 @@
class CourseMemberAdmission extends AdmissionRule
{
const MODE_MUST_BE_IN_COURSES = 0;
const MODE_MAY_NOT_BE_IN_COURSES = 1;
// --- ATTRIBUTES ---
/**
* End of course admission.
*/
public $mandatory_course_id = '';
public $courses_to_add = '[]';
public $modus = '';
public $default_message1 = '';
// --- OPERATIONS ---
......@@ -33,11 +34,10 @@ class CourseMemberAdmission extends AdmissionRule
*
* @param String ruleId
*/
public function __construct($ruleId='', $courseSetId = '')
public function __construct($ruleId = '', $courseSetId = '')
{
parent::__construct($ruleId, $courseSetId);
$this->default_message = _('Sie sind nicht in der Veranstaltung "%s" eingetragen.');
$this->default_message1 = _('Sie dürfen nicht in der Veranstaltung "%s" eingetragen sein.');
if ($ruleId) {
$this->load();
} else {
......@@ -48,26 +48,31 @@ class CourseMemberAdmission extends AdmissionRule
/**
* Deletes the admission rule and all associated data.
*/
public function delete() {
public function delete()
{
parent::delete();
// Delete rule data.
$stmt = DBManager::get()->prepare("DELETE FROM `coursememberadmissions`
WHERE `rule_id`=?");
$stmt->execute([$this->id]);
DBManager::get()->execute(
"DELETE FROM `coursememberadmissions` WHERE `rule_id` = ?",
[$this->id]
);
}
/**
* Gets some text that describes what this AdmissionRule (or respective
* subclass) does.
*/
public static function getDescription() {
public static function getDescription()
{
return _("Anmelderegeln dieses Typs legen eine Veranstaltung fest, in der die Nutzer bereits eingetragen sein müssen, oder in der sie nicht eingetragen sein dürfen, um sich zu Veranstaltungen des Anmeldesets anmelden zu können.");
}
/**
* Return this rule's name.
*/
public static function getName() {
public static function getName()
{
return _("Veranstaltungsbezogene Anmeldung");
}
......@@ -76,24 +81,24 @@ class CourseMemberAdmission extends AdmissionRule
*
* @return String
*/
public function getTemplate() {
public function getTemplate()
{
// Open generic admission rule template.
$tpl = $GLOBALS['template_factory']->open('admission/rules/configure');
$tpl->set_attribute('rule', $this);
$factory = new Flexi_TemplateFactory(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('mandatory_course', Course::find($this->mandatory_course_id));
$tpl2->set_attribute('tpl', $tpl->render());
return $tpl2->render();
return $this->getTemplateFactory()->render('configure', [
'rule' => $this,
'tpl' => $tpl->render(),
'courses' => $this->getDecodedCourses(),
]);
}
/**
* Helper function for loading rule definition from database.
*/
public function load() {
public function load()
{
// Load data.
$stmt = DBManager::get()->prepare("SELECT *
FROM `coursememberadmissions` WHERE `rule_id`=? LIMIT 1");
......@@ -102,8 +107,8 @@ class CourseMemberAdmission extends AdmissionRule
$this->message = $current['message'];
$this->startTime = $current['start_time'];
$this->endTime = $current['end_time'];
$this->mandatory_course_id = $current['course_id'];
$this->modus = $current['modus'];
$this->courses_to_add = $current['courses'];
$this->modus = (int) $current['modus'];
}
}
......@@ -114,15 +119,27 @@ class CourseMemberAdmission extends AdmissionRule
* @param String courseId
* @return Array
*/
public function ruleApplies($userId, $courseId) {
public function ruleApplies($userId, $courseId)
{
$errors = [];
if ($this->checkTimeFrame()) {
$user = User::find($userId);
$is_member = $user->course_memberships->findOneBy('seminar_id', $this->mandatory_course_id);
if ((!$this->modus && !$is_member) || ($this->modus && $is_member)) {
$errors[] = $this->getMessage(Course::find($this->mandatory_course_id));
$courses = $this->getDecodedCourses();
foreach ($courses as $course) {
$is_member = CourseMember::exists([$course->id, $userId]);
if (($this->modus == self::MODE_MUST_BE_IN_COURSES && !$is_member)
|| ($this->modus == self::MODE_MAY_NOT_BE_IN_COURSES && $is_member)
) {
$errors[] = $this->getMessage($course);
}
}
// mode: "Mitgliedschaft ist in mindestens einer dieser Veranstaltungen notwendig"
if ($this->modus == self::MODE_MUST_BE_IN_COURSES && count($errors) < count($courses)) {
$errors = [];
}
}
return $errors;
}
......@@ -134,24 +151,27 @@ class CourseMemberAdmission extends AdmissionRule
* @param Array $data
* @return AdmissionRule This object.
*/
public function setAllData($data) {
public function setAllData($data)
{
parent::setAllData($data);
$this->mandatory_course_id = $data['mandatory_course_id'] ?: $data['mandatory_course_id_old'];
$this->modus = $data['modus'];
$this->modus = (int) $data['modus'];
$this->courses_to_add = json_encode(array_keys($data['courses_to_add']));
return $this;
}
}
/**
* Store rule definition to database.
*/
public function store() {
public function store()
{
// Store data.
$stmt = DBManager::get()->prepare("INSERT INTO `coursememberadmissions`
(`rule_id`, `message`, `course_id`, `modus`, `start_time`,
(`rule_id`, `message`, `courses`, `modus`, `start_time`,
`end_time`, `mkdate`, `chdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `start_time`=VALUES(`start_time`),
`end_time`=VALUES(`end_time`),message=VALUES(message),course_id=VALUES(course_id),modus=VALUES(modus), `chdate`=VALUES(`chdate`)");
$stmt->execute([$this->id, $this->message,$this->mandatory_course_id, (int)$this->modus, (int)$this->startTime,
`end_time`=VALUES(`end_time`),message=VALUES(message),courses=VALUES(courses),modus=VALUES(modus), `chdate`=VALUES(`chdate`)");
$stmt->execute([$this->id, $this->message, $this->courses_to_add, (int)$this->modus, (int)$this->startTime,
(int)$this->endTime, time(), time()]);
}
......@@ -162,10 +182,11 @@ class CourseMemberAdmission extends AdmissionRule
*/
public function toString()
{
$factory = new Flexi_TemplateFactory(dirname(__FILE__).'/templates/');
$tpl = $factory->open('info');
$tpl->set_attribute('rule', $this);
return $tpl->render();
return $this->getTemplateFactory()->render('info', [
'courses' => $this->getDecodedCourses(),
'rule' => $this,
'modus' => $this->modus,
]);
}
/**
......@@ -178,7 +199,7 @@ class CourseMemberAdmission extends AdmissionRule
public function validate($data)
{
$errors = parent::validate($data);
if (!($data['mandatory_course_id'] || $data['mandatory_course_id_old'])) {
if (!$data['courses_to_add']) {
$errors[] = _('Bitte wählen Sie eine Veranstaltung aus.');
}
return $errors;
......@@ -187,6 +208,7 @@ class CourseMemberAdmission extends AdmissionRule
public function getMessage($course = null)
{
$message = parent::getMessage();
if ($course) {
return sprintf($message, $course->getFullname('number-name'));
} else {
......@@ -194,4 +216,44 @@ class CourseMemberAdmission extends AdmissionRule
}
}
private function getDecodedCourses()
{
$decoded_courses = json_decode($this->courses_to_add, true);
if (!$decoded_courses) {
return [];
}
return Course::findMany($decoded_courses);
}
public function getValidityPeriod(): string
{
if ($this->getStartTime() && $this->getEndTime()) {
return sprintf(
_('Diese Regel gilt von %s bis %s.'),
strftime('%d.%m.%Y %H:%M', $this->getStartTime()),
strftime('%d.%m.%Y %H:%M', $this->getEndTime())
);
}
if ($this->getStartTime() && !$this->getEndTime()) {
return sprintf(
_('Diese Regel gilt ab %s.'),
strftime('%d.%m.%Y %H:%M', $this->getStartTime())
);
}
if (!$this->getStartTime() && $this->getEndTime()) {
return sprintf(
_('Diese Regel gilt bis %s.'),
strftime('%d.%m.%Y %H:%M', $this->getEndTime())
);
}
return '';
}
private function getTemplateFactory(): Flexi_TemplateFactory
{
return new Flexi_TemplateFactory(__DIR__ . '/templates/');
}
}
<h3><?= $rule->getName() ?></h3>
<h3><?= htmlReady($rule->getName()) ?></h3>
<?= $tpl ?>
<input type="hidden" name="search_sem_qs_choose" value="title_lecturer_number">
<? if ($mandatory_course) : ?>
<input type="hidden" name="mandatory_course_id_old" value="<?=$mandatory_course->id?>">
<? foreach ($courses as $course) : ?>
<input type="hidden" name="mandatory_course_id_old[]" value="<?= htmlReady($course->id) ?>">
<label class="caption">
<?= _('Mitgliedschaft in folgender Veranstaltung überprüfen') ?>:
</label>
<p>
<?=htmlReady($mandatory_course->getFullName('number-name-semester'));?>
<a href="<?=URLHelper::getScriptLink('dispatch.php/course/details/index/' . $mandatory_course->id) ?>" data-dialog>
<?= Icon::create(
'info-circle',
Icon::ROLE_INACTIVE,
['title' =>_('Veranstaltungsdetails aufrufen')]
)?>
<?=htmlReady($course->getFullName('number-name-semester'));?>
<a href="<?=URLHelper::getLink('dispatch.php/course/details/index/' . $course->id) ?>" data-dialog>
<?= Icon::create('info-circle')->asImg([
'title' =>_('Veranstaltungsdetails aufrufen')
]) ?>
</a>
</p>
<? endif ?>
<? endforeach ?>
<label class="caption">
<?= _('Modus') ?>:
</label>
<div>
<label>
<input type="radio" name="modus" value="0" <?=(!$rule->modus ? 'checked' : '')?>>
<?=_("Mitgliedschaft ist notwendig")?>
<label>
<input type="radio" name="modus" value="0" <? if ($rule->modus == CourseMemberAdmission::MODE_MUST_BE_IN_COURSES) echo 'checked'; ?>>
<?=_("Mitgliedschaft ist in mindestens einer dieser Veranstaltungen notwendig")?>
</label>
<label>
<input type="radio" name="modus" value="1" <?=($rule->modus ? 'checked' : '')?>>
<?=_("Mitgliedschaft ist verboten")?>
<input type="radio" name="modus" value="1" <? if ($rule->modus == CourseMemberAdmission::MODE_MAY_NOT_BE_IN_COURSES) echo 'checked'; ?>>
<?=_("Mitgliedschaft ist in keiner dieser Veranstaltungen erlaubt")?>
</label>
</div>
......@@ -39,27 +40,84 @@
<div style="display:inline-block">
<?=
QuickSearch::get("mandatory_course_id", new SeminarSearch('number-name-lecturer'))
->render();
?>
<?= Semester::getSemesterSelector(
['name' => 'search_sem_sem'],
Semester::getIndexById($_SESSION['_default_sem'], false, !$GLOBALS['perm']->have_perm('admin')),
'key',
false
)?>
<?=
QuickSearch::get("mandatory_course_id", new SeminarSearch('number-name-lecturer'))
->fireJSFunctionOnSelect('addcourse')
->render();
?>
<?= Semester::getSemesterSelector(
['name' => 'search_sem_sem'],
Semester::getIndexById($_SESSION['_default_sem'], false, !$GLOBALS['perm']->have_perm('admin')),
'key',
false
)?>
<br><br>
<ul>
<? foreach ($courses as $course) : ?>
<li>
<input type="hidden" id="<?= htmlReady($course->id) ?>"
name="courses_to_add[<?= htmlReady($course->id) ?>]"
value="<?= htmlReady($course->name) ?>">
<span><?= htmlReady($course->name) ?></span>
<a href="#" onclick="return removecourse('<?= htmlReady($course->id) ?>')">
<?= Icon::create('trash') ?>
</a>
</li>
<? endforeach ?>
</ul>
</div>
<br><br>
<script>
$('#ruleform input[name="modus"]').on('change',
function () {
var message = [
"<?=jsReady($rule->default_message, 'script-double')?>",
"<?=jsReady($rule->default_message1, 'script-double')?>"
];
$('#ruleform textarea').text(message[this.value]);
});
$('#ruleform input[name="modus"]').on('change', function () {
const message = <?= json_encode([
_('Sie sind nicht in der Veranstaltung "%s" eingetragen.'),
_('Sie dürfen nicht in der Veranstaltung "%s" eingetragen sein.'),
]) ?>;
console.log(this, this.value);
$('#ruleform textarea').text(message[this.value]);
}).filter(':checked').change();
function addcourse(id, title) {
if ($('input[name="courses_to_add[' + id + ']"]').length === 0) {
var wrapper = $('<li>');
var input = $('<input>')
.attr('id', id)
.attr('type', 'hidden')
.attr('name', 'courses_to_add['+ id + ']')
.attr('value', title);
wrapper.append(input);
var trash = $('<input>')
.attr('type', 'image')
.attr('src', STUDIP.ASSETS_URL + 'images/icons/blue/trash.svg')
.attr('name', 'remove_[' + id + ']')
.attr('value', '1')
.attr('onclick', "return removecourse('" + id + "')");
var icon = $('<a>')
.attr('onclick', "return removecourse('" + id + "')")
.attr('href', '#');
var img = $('<img>')
.attr('src', STUDIP.ASSETS_URL + 'images/icons/blue/trash.svg')
.attr('width', '16px')
.attr('height', '16px');
icon.append(img);
var nametext = $('<span>')
.html(title)
.text();
wrapper.append(nametext);
wrapper.append(icon);
$('input[name=mandatory_course_id_parameter]').parent().find('ul').append(wrapper);
}
}
function removecourse(id) {
$('input#' + id).parent().remove();
return false;
}
</script>
<?php
if ($rule->getStartTime() && $rule->getEndTime()) {
echo sprintf(_('Diese Regel gilt von %s bis %s.'), strftime('%d.%m.%Y %H:%M',
$rule->getStartTime()), strftime('%d.%m.%Y %H:%M', $rule->getEndTime())).'<br/>';
} else if ($rule->getStartTime() && !$rule->getEndTime()) {
echo sprintf(_('Diese Regel gilt ab %s.'), strftime('%d.%m.%Y %H:%M', $rule->getStartTime())).'<br/>';
} else if (!$rule->getStartTime() && $rule->getEndTime()) {
echo sprintf(_('Diese Regel gilt bis %s.'), strftime('%d.%m.%Y %H:%M', $rule->getEndTime())).'<br/>';
}
$course = Course::find($rule->mandatory_course_id);
if ($course) {
echo sprintf(!$rule->modus ?
_('Die Anmeldung ist nur Teilnehmenden der Veranstaltung: <b>%s</b> %s erlaubt.') :
_('Die Anmeldung ist für Teilnehmende der Veranstaltung: <b>%s</b> %s verboten.'),
$course->getFullname('number-name-semester'), '<a href="'.URLHelper::getScriptLink('dispatch.php/course/details/index/' . $course->id).'" data-dialog>'.
Icon::create(
'info-circle',
Icon::ROLE_INACTIVE,
['title' =>_('Veranstaltungsdetails aufrufen')]
).'</a>');
}
<? if ($rule->getValidityPeriod()): ?>
<?= $rule->getValidityPeriod() ?><br>
<? endif; ?>
<? if ($modus == CourseMemberAdmission::MODE_MAY_NOT_BE_IN_COURSES): ?>
<?= _('Die Anmeldung ist für Teilnehmende einer der folgenden Veranstaltungen nicht erlaubt:') ?>
<? elseif ($modus == CourseMemberAdmission::MODE_MUST_BE_IN_COURSES): ?>
<?= _('Die Anmeldung ist nur für Teilnehmende mindestens einer der folgenden Veranstaltungen erlaubt:') ?>
<? endif; ?>
<br>
<ul>
<? foreach ($courses as $course): ?>
<li>
<strong><?= htmlReady($course->getFullname('number-name-semester')) ?></strong>
<a href="<?= URLHelper::getLink('dispatch.php/course/details/index/' . $course->id) ?>" data-dialog>
<?= Icon::create('info-circle')->asImg([
'title' => _('Veranstaltungsdetails aufrufen')
]) ?>
</a>
</li>
<? endforeach; ?>
</ul>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment