diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index f3420767f460dc9dd32f97c81bc6500e64e261d7..f90ccb9cd4eb8c149d9d428bdc43b2d963846e88 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -74,6 +74,9 @@ - Als Ersatz für viele Methoden der Seminar-Klasse dienen die Klassen `Course`, `CourseDate` und `SeminarCycleDate`, sowie die neue `CourseDateList`-Klasse. - Die Klassen `TreeAbstract`, `TreeView` und `SemBrowse` wurden ausgebaut. ([Issue #4392](https://gitlab.studip.de/studip/studip/-/issues/4392)) - Zur Anzeige von Baumstrukturen können als Ersatz die Implementierungen des `StudipTreeNode`-Interfaces genutzt werden. +- Die Zuordnung von Veranstaltungen zu Semestern anhand von Timestamps wurde entfernt. In der Datenbank wurden die Spalten `start_time` und `duration_time` der Tabelle `seminare` entfernt. ([Issue #4391]https://gitlab.studip.de/studip/studip/-/issues/4391)) + - Plugins, die Veranstaltungen anhand von Timestamps laden oder anderweitig verwenden, müssen angepasst werden! + - Das Mapping von Veranstaltungen zu Semestern findet nun ausschließlich anhand der Semester-ID über die Verknüpfungstabelle `semester_courses` statt. ## Security related issues diff --git a/app/controllers/admin/tree.php b/app/controllers/admin/tree.php index ec35368c262516aeb57733c18c1e8edaaf76fd82..320f10efd9cd884ec567d2f36164ce6df1011f94 100644 --- a/app/controllers/admin/tree.php +++ b/app/controllers/admin/tree.php @@ -238,8 +238,8 @@ class Admin_TreeController extends AuthenticatedController $courseIds = Request::optionArray('assign_semtree'); $order = Config::get()->IMPORTANT_SEMNUMBER - ? "ORDER BY `start_time` DESC, `VeranstaltungsNummer`, `Name`" - : "ORDER BY `start_time` DESC, `Name`"; + ? "ORDER BY `VeranstaltungsNummer`, `Name`" + : "ORDER BY `Name`"; $this->courses = array_filter( Course::findMany($courseIds, $order), function (Course $course): bool { diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php index 17375d13aa844b22bdad4f38162cb3a74b4548b6..bf8b9282121954bf10fbd0fbce567ed65f000253 100644 --- a/app/controllers/admin/user.php +++ b/app/controllers/admin/user.php @@ -1634,8 +1634,8 @@ class Admin_UserController extends AuthenticatedController $courseIds = Request::optionArray('export_members'); $order = Config::get()->IMPORTANT_SEMNUMBER - ? "ORDER BY `start_time` DESC, `VeranstaltungsNummer`, `Name`" - : "ORDER BY `start_time` DESC, `Name`"; + ? "ORDER BY `VeranstaltungsNummer`, `Name`" + : "ORDER BY `Name`"; $this->courses = array_filter( Course::findMany($courseIds, $order), function (Course $course): bool { diff --git a/app/controllers/admission/restricted_courses.php b/app/controllers/admission/restricted_courses.php index aafb589e44da1701e198aaa6e50831979f04782d..371ea5de5ff749ef2e9a472604612779b6aa6f36 100644 --- a/app/controllers/admission/restricted_courses.php +++ b/app/controllers/admission/restricted_courses.php @@ -86,6 +86,7 @@ class Admission_RestrictedCoursesController extends AuthenticatedController _("Endzeitpunkt")]; $data = []; foreach ($this->courses as $course) { + $sorm_course = Course::find($course['seminare.seminar_id']); $row = []; $row[] = $course['cs_name']; $row[] = $course['course_number']; @@ -96,8 +97,8 @@ class Admission_RestrictedCoursesController extends AuthenticatedController $row[] = (int)$course['count_prelim']; $row[] = (int)$course['count_waiting']; $row[] = $course['distribution_time'] ? strftime('%x %R', $course['distribution_time']) : ''; - $row[] = isset($course['start_time']) ? strftime('%x %R', $course['start_time']) : ''; - $row[] = isset($course['end_time']) ? strftime('%x %R', $course['end_time']) : ''; + $row[] = $sorm_course?->getStartSemester()?->beginn ?? ''; + $row[] = $sorm_course?->getEndSemester()?->ende ?? ''; $data[] = $row; } diff --git a/app/controllers/contents/courseware.php b/app/controllers/contents/courseware.php index 0337e6a2fa2308d41858b5f5f0c5d8b8693907aa..00627e9400b726c4e9a7d35c2a1d52e06d9a7b99 100644 --- a/app/controllers/contents/courseware.php +++ b/app/controllers/contents/courseware.php @@ -171,46 +171,6 @@ class Contents_CoursewareController extends CoursewareController $this->sem_courses = $this->getCoursewareCourses($sem_key); } - public function pdf_export_action($element_id, $with_children): void - { - $element = \Courseware\StructuralElement::findOneById($element_id); - - $this->render_pdf($element->pdfExport($this->user, $with_children), trim($element->title).'.pdf'); - } - - /** - * To display the shared courseware - * - * @param string $entry_element_id the shared struct element id - */ - public function shared_content_courseware_action($entry_element_id): void - { - global $user; - - $navigation = new Navigation(_('Geteiltes Lernmaterial'), 'dispatch.php/contents/courseware/shared_content_courseware/' . $entry_element_id); - Navigation::addItem('/contents/courseware/shared_content_courseware', $navigation); - Navigation::activateItem('/contents/courseware/shared_content_courseware'); - - $this->entry_element_id = $entry_element_id; - - $struct = \Courseware\StructuralElement::findOneBySQL( - "id = ? AND range_type = 'user'", - [$this->entry_element_id] - ); - - if (!$struct) { - throw new Trails\Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.')); - } - - if (!$struct->canRead($user) && !$struct->canEdit($user)) { - throw new AccessDeniedException(); - } - - $this->user_id = $struct->owner_id; - - $this->setCoursewareSidebar(); - } - /** * Return list of coursewares grouped by semester_id * @@ -255,7 +215,7 @@ class Contents_CoursewareController extends CoursewareController $courses = $courses->filter(function (Course $course) use ($semester) { return $course->isInSemester($semester); }); - } + } $sem_courses = []; foreach ($courses as $course) { $units = Unit::findCoursesUnits($course); diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php index bd889327489d626beb9fe1aa30bba544b54efe6f..88a61259a1ba6d0095cc1776314b282efb06693c 100644 --- a/app/controllers/course/dates.php +++ b/app/controllers/course/dates.php @@ -102,22 +102,18 @@ class Course_DatesController extends AuthenticatedController ); $sidebar->addWidget($actions); - $course_end_time = $this->course->getEnd_Time(); - if (($course_end_time == -1) || ($course_end_time > 0)) { + if (count($this->course->semesters) !== 1) { //The course has more than one semester: $semester_widget = new SemesterSelectorWidget( $this->url_for('course/dates/index') ); - $semester_end_range = $course_end_time; - if ($semester_end_range == -1) { - //The end semester is set to unlimited. - $semester_end_range = PHP_INT_MAX; - } $semester_widget->includeAll(); - $semester_widget->setRange( - $this->course->start_time, - $semester_end_range - ); + if ($this->course->start_semester && $this->course->end_semester) { + $semester_widget->setRange( + $this->course->start_semester->beginn, + $this->course->end_semester->ende + ); + } $sidebar->addWidget($semester_widget); } diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php index 7f9c078255f96fb550b4becd87784679e6521869..707b0ed990d30387f18e89bee0c07e526e38b04e 100644 --- a/app/controllers/course/details.php +++ b/app/controllers/course/details.php @@ -98,11 +98,9 @@ class Course_DetailsController extends AuthenticatedController // Ausgabe der Modulzuordnung MVV if ($this->course->getSemClass()->offsetGet('module')) { - $course_start = $this->course->start_time; - $course_end = ($this->course->end_time < 0 || is_null($this->course->end_time)) - ? PHP_INT_MAX - : $this->course->end_time; - // set filter to show only pathes with valid semester data + $course_start = $this->course->start_semester?->beginn ?? 0; + $course_end = $this->course->end_semester?->ende ?? PHP_INT_MAX; + //Set the filter to show only paths with valid semester data: ModuleManagementModelTreeItem::setObjectFilter('Modul', function ($modul) use ($course_start, $course_end) { // check for public status diff --git a/app/controllers/lti.php b/app/controllers/lti.php index 070682ef8a12c844a3c2ea6c84297fdbcc6153ac..82d9840fb81b0f281cfd9070240661d74de0de56 100644 --- a/app/controllers/lti.php +++ b/app/controllers/lti.php @@ -69,8 +69,10 @@ class LtiController extends AuthenticatedController ]; $sql = "JOIN seminar_user USING(Seminar_id) + LEFT JOIN semester_courses sc ON seminare.seminar_id = sc.course_id + LEFT JOIN semester_data s USING (semester_id) WHERE user_id = ? AND seminar_user.status IN ('dozent', 'tutor') - ORDER BY start_time DESC, Name"; + ORDER BY s.beginn DESC, Name"; $this->courses = Course::findBySQL($sql, [$GLOBALS['user']->id]); } diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php index d21f2d508f2b0a1d249061097f8240ac79205be0..b3677aed330086d04f1d47798ee8f72f11316c92 100644 --- a/app/controllers/my_courses.php +++ b/app/controllers/my_courses.php @@ -577,7 +577,7 @@ class MyCoursesController extends AuthenticatedController LEFT JOIN archiv USING (seminar_id) WHERE user_id = :user_id GROUP BY seminar_id - ORDER BY start_time DESC, :sortby"; + ORDER BY mkdate DESC, :sortby"; $statement = DBManager::get()->prepare($query); $statement->bindValue(':user_id', $GLOBALS['user']->id); $statement->bindValue(':sortby', $sortby, StudipPDO::PARAM_COLUMN); diff --git a/app/controllers/news.php b/app/controllers/news.php index 375f48b25205352f47756bd0c93839a7fbf87893..973646e687da723587ec6a09ab6b133a5a51c61c 100644 --- a/app/controllers/news.php +++ b/app/controllers/news.php @@ -621,150 +621,6 @@ class NewsController extends StudipController return strtotime($date); } - /** - * Searchs for studip areas using given search term - * - * @param string $term search term - * @return array area data - */ - private function search_area($term) - { - global $perm; - $result = $tmp_result = []; - if (mb_strlen($term) < 3) { - PageLayout::postError(_('Der Suchbegriff muss mindestens drei Zeichen lang sein.')); - return $result; - } - - if ($term === '__THIS_SEMESTER__') { - $current_semester = Semester::findCurrent(); - $query = "SELECT seminare.Name AS sem_name, seminare.Seminar_id, seminare.visible - FROM seminar_user - LEFT JOIN seminare USING (Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = seminar_user.Seminar_id) - WHERE seminar_user.user_id = :user_id - AND seminar_user.status IN('tutor', 'dozent') - AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL) - "; - if (Config::get()->DEPUTIES_ENABLE) { - $query .= " UNION SELECT CONCAT(seminare.Name, ' ["._("Vertretung")."]') AS sem_name, seminare.Seminar_id, - seminare.visible - FROM deputies - LEFT JOIN seminare ON (deputies.range_id=seminare.Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = deputies.range_id) - WHERE deputies.user_id = :user_id - AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)"; - } - $query .= " ORDER BY sem_name ASC"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':user_id', $GLOBALS['user']->id); - $statement->bindValue(':semester_id', $current_semester->semester_id); - $statement->execute(); - $seminars = $statement->fetchAll(PDO::FETCH_ASSOC); - foreach($seminars as $sem) { - $tmp_result[$sem['Seminar_id']] = [ - 'name' => $sem['sem_name'], - 'type' => 'sem', - ]; - } - $term = ''; - } elseif ($term === '__NEXT_SEMESTER__') { - $next_semester = Semester::findNext(); - $query = "SELECT seminare.Name AS sem_name, seminare.Seminar_id, seminare.visible - FROM seminar_user - LEFT JOIN seminare USING (Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = seminar_user.Seminar_id) - WHERE seminar_user.user_id = :user_id - AND seminar_user.status IN('tutor', 'dozent') - AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)"; - if (Config::get()->DEPUTIES_ENABLE) { - $query .= " UNION SELECT CONCAT(seminare.Name, ' ["._("Vertretung")."]') AS sem_name, seminare.Seminar_id, - seminare.visible - FROM deputies - LEFT JOIN seminare ON (deputies.range_id=seminare.Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = deputies.range_id) - WHERE deputies.user_id = :user_id - AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)"; - } - $query .= " ORDER BY sem_name ASC"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':user_id', $GLOBALS['user']->id); - $statement->bindValue(':semester_id', $next_semester->semester_id); - $statement->execute(); - $seminars = $statement->fetchAll(PDO::FETCH_ASSOC); - foreach($seminars as $sem) { - $tmp_result[$sem['Seminar_id']] = [ - 'name' => $sem['sem_name'], - 'type' => 'sem', - ]; - } - $term = ''; - } elseif ($term === '__MY_INSTITUTES__') { - $term = ''; - if ($perm->have_perm('root')) { - $tmp_result['studip'] = [ - 'name' => 'Stud.IP', - 'type' => 'global' - ]; - } - $inst_list = Institute::getMyInstitutes(); - if (count($inst_list)) { - foreach($inst_list as $data) { - $tmp_result[$data['Institut_id']] = [ - 'name' => $data['Name'], - 'type' => $data['is_fak'] ? 'fak' : 'inst' - ]; - } - } - } else { - $tmp_result = search_range($term, true) ?: []; - // add users - if (mb_stripos(get_fullname(), $term) !== false) { - $tmp_result[$GLOBALS['user']->id] = [ - 'name' => get_fullname(), - 'type' => 'user' - ]; - } - if (Deputy::isEditActivated()) { - $query = "SELECT DISTINCT a.user_id - FROM deputies d - JOIN auth_user_md5 a ON (d.range_id = a.user_id) - JOIN user_info u ON (a.user_id=u.user_id) - WHERE d.user_id = ? - AND CONCAT(u.title_front, ' ', a.Vorname, ' ', a.Nachname, ', ', u.title_rear) LIKE CONCAT('%',?,'%')"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $term]); - while ($data = $statement->fetch(PDO::FETCH_ASSOC)) { - $tmp_result[$data['user_id']] = [ - 'name' => get_fullname($data['user_id']), - 'type' => 'user', - ]; - } - } - } - // workaround: apply search term (ignored by search_range below admin) - if (count($tmp_result) && !$GLOBALS['perm']->have_perm('admin') && $term) { - foreach ($tmp_result as $id => $data) { - if (mb_stripos($data['name'], $term) === false) { - unset($tmp_result[$id]); - } - } - } - // prepare result - - if (count($tmp_result)) { - foreach ($tmp_result as $id => $data) { - $index = $data['type'] === 'fak' - ? 'inst' - : $data['type']; - $result[$index][$id] = $data['name']; - } - } elseif ($term) { - PageLayout::postError(_('Zu diesem Suchbegriff wurden keine Bereiche gefunden.')); - } - return $result; - } - public function rss_config_action($range_id) { if (!Config::get()->NEWS_RSS_EXPORT_ENABLE || !StudipNews::haveRangePermission('edit', $range_id)) { diff --git a/app/views/admission/courseset/configure.php b/app/views/admission/courseset/configure.php index 773624e5bc052164bc5345b64d50aa8c4d0be10b..6380499dfcfd64ebcafe91f9c288b2854a018c36 100644 --- a/app/views/admission/courseset/configure.php +++ b/app/views/admission/courseset/configure.php @@ -158,12 +158,18 @@ if (isset($flash['error'])) { <?= sprintf(_("%s zugewiesene Veranstaltungen"), count($courseIds)) ?> <? else : ?> <? - Course::findEachMany(function($c) { - echo htmlReady($c->getFullName('number-name-semester')); - echo '<br>'; - }, - $courseIds, - 'ORDER BY start_time,VeranstaltungsNummer,Name'); + Course::findEachBySQL( + function($c) { + echo htmlReady($c->getFullName('number-name-semester')); + echo '<br>'; + }, + "JOIN `semester_courses` + ON `seminare`.`seminar_id` = `semester_courses`.`course_id` + JOIN `semester_data` USING (`semester_id`) + WHERE `seminare`.`seminar_id` IN ( :course_ids ) + 'ORDER BY `semester_data`.`beginn`, `VeranstaltungsNummer`, `Name`", + ['course_ids' => $courseIds], + ) ?> <? endif ?> <? endif ?> diff --git a/app/views/admission/restricted_courses/index.php b/app/views/admission/restricted_courses/index.php index a7b18192bb2cd357c9d9fc9b5abdee67264f141a..a7503e48c3c8e5bdbfde686a52fdeff85bbf7403 100644 --- a/app/views/admission/restricted_courses/index.php +++ b/app/views/admission/restricted_courses/index.php @@ -41,11 +41,11 @@ <td style="white-space:nowrap" data-sort-value="<?= (int) $course['distribution_time']?>"> <?= htmlReady($course['distribution_time'] ? strftime('%x %R', $course['distribution_time']) : '-') ?> </td> - <td style="white-space:nowrap" data-sort-value="<?= (int) ($course['start_time'] ?? null) ?>"> - <?= htmlReady(isset($course['start_time']) ? strftime('%x %R', $course['start_time']) : '-') ?> + <td style="white-space:nowrap" data-sort-value="<?= (int) ($course->start_semester->beginn ?? null) ?>"> + <?= htmlReady(($course->start_semester instanceof Semester) ? strftime('%x %R', $course->start_semester->beginn) : '-') ?> </td> - <td style="white-space:nowrap" data-sort-value="<?= (int) ($course['end_time'] ?? null) ?>"> - <?= htmlReady(isset($course['end_time']) ? strftime('%x %R', $course['end_time']) : '-') ?> + <td style="white-space:nowrap" data-sort-value="<?= (int) ($course->end_semester->ende ?? null) ?>"> + <?= htmlReady(($course->end_semester instanceof Semester) ? strftime('%x %R', $course->end_semester->ende) : '-') ?> </td> </tr> <? endforeach ?> diff --git a/app/views/course/wizard/steps/basicdata/index.php b/app/views/course/wizard/steps/basicdata/index.php index f19643a0731da1254126a0f51683cf25b52c8b38..372d587821d3a68e8b2922ed9bc3378c5d9415ba 100644 --- a/app/views/course/wizard/steps/basicdata/index.php +++ b/app/views/course/wizard/steps/basicdata/index.php @@ -1,3 +1,8 @@ +<?php +/** + * @var Semester[] $semesters + */ +?> <legend> <?= _('Grunddaten') ?> </legend> @@ -21,13 +26,18 @@ <label for="wizard-start-time" class="required"> <?= _('Semester') ?> </label> - <select name="start_time" id="wizard-start-time" > - <?php foreach (array_reverse($semesters) as $semester) { ?> - <? ($values['start_time'] < time()) ? (($semester->beginn <= time() && time() <= $semester->ende) ? $values['start_time'] = $semester->beginn : '' ): '' ?> - <option value="<?= $semester->beginn ?>"<?= $semester->beginn == $values['start_time'] ? ' selected="selected"' : '' ?>> + <select name="semester_id" id="wizard-start-time" > + <?php + $default_semester = Semester::findDefault(); + if ($default_semester && empty($values['start_semester'])) { + $values['start_semester'] = $default_semester; + } + ?> + <?php foreach (array_reverse($semesters) as $semester) : ?> + <option value="<?= htmlReady($semester->id) ?>" <?= $semester->id == $values['start_semester'] ? ' selected' : '' ?>> <?= htmlReady($semester->name) ?> </option> - <?php } ?> + <?php endforeach ?> </select> </section> <section> diff --git a/app/views/course/wizard/steps/basicdata/index_studygroup.php b/app/views/course/wizard/steps/basicdata/index_studygroup.php index d7417abd8b27017f572507e4d151b2bf068c2334..9f75da56436212f639eb46ea8cf9531892345e13 100644 --- a/app/views/course/wizard/steps/basicdata/index_studygroup.php +++ b/app/views/course/wizard/steps/basicdata/index_studygroup.php @@ -71,9 +71,9 @@ <?= _('Einverstanden') ?> </label> -<input type="hidden" name="institute" value="<?= htmlReady($values['institute']) ?>"> -<input type="hidden" name="start_time" value="<?= htmlReady($values['start_time']) ?>"> +<input type="hidden" name="institute" value="<?= $values['institute'] ?>"/> +<input type="hidden" name="start_semester" value="<?= htmlReady($values['start_semester']) ?>"> <input type="hidden" name="studygroup" value="1"/> <?php foreach ($values['lecturers'] as $id => $assigned) : ?> - <input type="hidden" name="lecturers[<?= htmlReady($id) ?>]" value="1"> + <input type="hidden" name="lecturers[<?= $id ?>]" value="1"/> <?php endforeach ?> diff --git a/app/views/lvgruppen/lvgruppen/details.php b/app/views/lvgruppen/lvgruppen/details.php index 6a9c3afc690da1e3d23202b1baeeb545e74f01e1..ed9dc9a854193ab4bd22e2a551f9b4da88a38b27 100644 --- a/app/views/lvgruppen/lvgruppen/details.php +++ b/app/views/lvgruppen/lvgruppen/details.php @@ -1,3 +1,8 @@ +<?php +/** + * @var Course[] $courses + */ +?> <td colspan="6"> <table class="default nohover"> <colgroup> @@ -80,7 +85,7 @@ <? foreach ($courses[$semester->id] as $course) : ?> <li> <a href="<?= URLHelper::getLink('dispatch.php/course/details', ['sem_id' => $course['seminar_id']]) ?>"> - <?= htmlReady(($course['VeranstaltungsNummer'] ? $course['VeranstaltungsNummer'] . ' - ' : '') . $course['Name']) ?> + <?= htmlReady($course->getFullName('number-name')) ?> </a> </li> <? endforeach; ?> @@ -99,7 +104,7 @@ <? foreach ($courses[$semester->id] as $course) : ?> <li> <a href="<?= URLHelper::getLink('dispatch.php/course/details', ['sem_id' => $course['seminar_id']]) ?>"> - <?= htmlReady(($course['VeranstaltungsNummer'] ? $course['VeranstaltungsNummer'] . ' - ' : '') . $course['Name']) ?> + <?= htmlReady($course->getFullName('number-name')) ?> </a> </li> <? endforeach; ?> diff --git a/db/migrations/6.0.18_remove_course_mapping_by_timestamps.php b/db/migrations/6.0.18_remove_course_mapping_by_timestamps.php new file mode 100644 index 0000000000000000000000000000000000000000..015618ca42f99ceb105987aed9aa43af84f02a39 --- /dev/null +++ b/db/migrations/6.0.18_remove_course_mapping_by_timestamps.php @@ -0,0 +1,30 @@ +<?php + + +class RemoveCourseMappingByTimestamps extends Migration +{ + public function description() + { + return 'Removes the mapping of courses to semesters by timestamps (by removing seminare.start_time and seminare.duration_time).'; + } + + public function up() + { + $db = DBManager::get(); + $db->exec( + "ALTER TABLE `seminare` + DROP COLUMN `start_time`, + DROP COLUMN `duration_time`" + ); + } + + protected function down() + { + $db = DBManager::get(); + $db->exec( + "ALTER TABLE `seminare` + ADD COLUMN start_time INT(11) UNSIGNED NULL DEFAULT 0, + ADD COLUMN duration_time INT(11) NULL DEFAULT NULL" + ); + } +} diff --git a/lib/classes/AutoInsert.php b/lib/classes/AutoInsert.php index 89d87da498dc72af6e504e2d85d53c58134be5b7..a88ec5547c0c6cd84d374a817375fb2a61024523 100644 --- a/lib/classes/AutoInsert.php +++ b/lib/classes/AutoInsert.php @@ -52,7 +52,7 @@ class AutoInsert private function loadSettings() { - $query = "SELECT a.seminar_id, GROUP_CONCAT(a.status,IF(LENGTH(a.domain_id)=0,':keine',CONCAT(':',a.domain_id))) AS domain_status, s.Name, s.Schreibzugriff, s.start_time "; + $query = "SELECT a.seminar_id, GROUP_CONCAT(a.status,IF(LENGTH(a.domain_id)=0,':keine',CONCAT(':',a.domain_id))) AS domain_status, s.Name, s.Schreibzugriff "; $query .= "FROM auto_insert_sem a "; $query .= "JOIN seminare AS s USING (Seminar_id) "; $query .= "GROUP BY s.seminar_id "; @@ -68,8 +68,7 @@ class AutoInsert $key = $array[1] . '.' . $array[0]; $this->settings[$key][$result['seminar_id']] = ['Seminar_id' => $result['seminar_id'], 'name' => $result['Name'], - 'Schreibzugriff' => $result['Schreibzugriff'], - 'start_time' => $result['start_time']]; + 'Schreibzugriff' => $result['Schreibzugriff']]; } } } @@ -78,7 +77,7 @@ class AutoInsert private function getUserSeminars($user_id, $seminare) { - $statement = DBManager::get()->prepare("SELECT Seminar_id,s.name,s.Schreibzugriff,s.start_time,su.status + $statement = DBManager::get()->prepare("SELECT Seminar_id, s.name, s.Schreibzugriff, su.status FROM seminar_user su INNER JOIN seminare s USING(Seminar_id) WHERE user_id = ? AND Seminar_id IN(?)"); @@ -256,7 +255,7 @@ class AutoInsert $statement = DBManager::get()->query($query); $results = $statement->fetchAll(PDO::FETCH_COLUMN); } else { - $query = "SELECT a.seminar_id, GROUP_CONCAT(a.status,IF(LENGTH(a.domain_id)=0,':keine',CONCAT(':',a.domain_id))) AS domain_status, s.Name, s.Schreibzugriff, s.start_time "; + $query = "SELECT a.seminar_id, GROUP_CONCAT(a.status,IF(LENGTH(a.domain_id)=0,':keine',CONCAT(':',a.domain_id))) AS domain_status, s.Name, s.Schreibzugriff "; $query .= "FROM auto_insert_sem a "; $query .= "JOIN seminare AS s USING (Seminar_id) "; diff --git a/lib/classes/CoursesetModel.php b/lib/classes/CoursesetModel.php index e12d3b9682bf76d43c1c23a6a562cc5170e3ecb8..076355d9c0717618acd2f78aca918a1e2f254b22 100644 --- a/lib/classes/CoursesetModel.php +++ b/lib/classes/CoursesetModel.php @@ -46,13 +46,11 @@ class CoursesetModel INNER JOIN `seminare` s USING (`Seminar_id`) LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) WHERE s.status NOT IN(?) - AND s.`start_time` <= ? AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?) AND su.`user_id` = ? GROUP BY su.`Seminar_id` "; $parameters = [ $excludeTypes, - $currentSemester->beginn, $currentSemester->id, $GLOBALS['user']->id ]; @@ -63,14 +61,13 @@ class CoursesetModel FROM `seminare` s INNER JOIN `deputies` d ON (s.`Seminar_id`=d.`range_id`) LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) - WHERE s.`start_time` <= ? - AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?) + WHERE (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?) AND d.`user_id` = ? GROUP BY s.`Seminar_id` "; $parameters = array_merge( $parameters, - [$currentSemester->beginn, $currentSemester->id, $GLOBALS['user']->id] + [$currentSemester->id, $GLOBALS['user']->id] ); } $courses = $db->fetchFirst($query, $parameters); @@ -88,7 +85,6 @@ class CoursesetModel LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) INNER JOIN auth_user_md5 aum USING (user_id) WHERE s.status NOT IN (:exclude_types) - AND s.start_time <= :sembegin AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) AND $sem_inst.Institut_id IN (:institutes) AND ( @@ -98,7 +94,6 @@ class CoursesetModel )"; $courses = $db->fetchFirst($query, [ 'exclude_types' => $excludeTypes, - 'sembegin' => $currentSemester->beginn, 'semester_id' => $currentSemester->id, 'institutes' => $instituteIds, 'filter' => '%' . $filter .'%', @@ -136,13 +131,15 @@ class CoursesetModel 'visible' => $course->visible, ]; - $query = "SELECT type - FROM seminar_courseset - INNER JOIN courseset_rule USING (set_id) - WHERE type IN ('LockedAdmission','PasswordAdmission') - AND seminar_id = ?"; + $query = "SELECT `type` + FROM `seminar_courseset` + JOIN `courseset_rule` USING (`set_id`) + LEFT JOIN `semester_courses` ON `seminar_courseset`.`seminar_id` = `semester_courses`.`course_id` + LEFT JOIN `semester_data` USING (`semester_id`) + WHERE `type` IN ('LockedAdmission','PasswordAdmission') + AND `seminar_id` = ?"; if ($coursesetId) { - $query .= "AND set_id <> ?"; + $query .= "AND `set_id` <> ?"; } $data[$course->id]['admission_type'] = DBManager::get()->fetchColumn( @@ -151,7 +148,7 @@ class CoursesetModel ); }; - Course::findEachMany($callable, array_unique($courses),"ORDER BY start_time DESC, VeranstaltungsNummer ASC, Name ASC"); + Course::findEachMany($callable, array_unique($courses),"ORDER BY `semester_data`.`beginn` DESC, `VeranstaltungsNummer` ASC, `Name` ASC"); return $data; } @@ -177,6 +174,7 @@ class CoursesetModel LEFT JOIN courseset_rule cr ON c.set_id = cr.set_id LEFT JOIN seminar_courseset sc ON c.set_id = sc.set_id LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id + LEFT JOIN semester_courses ON s.seminar_id = semester_courses.course_id WHERE ci.institute_id = ?"; if ($filter['course_set_name']) { $query .= " AND c.name LIKE ?"; @@ -187,8 +185,8 @@ class CoursesetModel $parameters[] = $filter['rule_types']; } if ($filter['semester_id']) { - $query .= " AND s.start_time = ?"; - $parameters[] = Semester::find($filter['semester_id'])->beginn; + $query .= " AND semester_courses.semester_id = ?"; + $parameters[] = $filter['semester_id']; } $cs_count_statement = DBManager::get()->prepare($query); $query = str_replace('ci.institute_id', '1', $query); diff --git a/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php b/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php index ba2536909c07896a471366cfb2e53ba34416b77f..9f0843aa44b855d3352839b2759d8a9a6bacf899 100644 --- a/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php +++ b/lib/classes/JsonApi/Routes/Courses/CoursesByUserIndex.php @@ -98,9 +98,14 @@ class CoursesByUserIndex extends JsonApiController */ private function findCoursesByUser(User $user, ?Semester $semester): array { - $courses = Course::findMany( - $user->course_memberships->pluck('seminar_id'), - 'ORDER BY start_time, name' + $courses = Course::findBySQL( + 'LEFT JOIN `semester_courses` + ON `seminare`.`seminar_id` = `semester_courses`.`course_id` + LEFT JOIN `semester_data` USING (`semester_id`) + WHERE + `seminare`.`seminar_id` IN ( :course_ids ) + ORDER BY `semester_data`.`beginn`, `seminare`.`name`', + ['course_ids' => $user->course_memberships->pluck('seminar_id')] ); if ($semester) { diff --git a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php index 033916cc408f7a585dce4379c1ed490a9feaac28..b96a29093c025929bf0f8c046f60e7f45f088c24 100644 --- a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php +++ b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php @@ -57,11 +57,12 @@ class UserScheduleShow extends JsonApiController { // get all virtually added seminars $stmt = \DBManager::get()->prepare( - 'SELECT c.course_id FROM schedule_courses as c - LEFT JOIN seminare ON seminare.seminar_id = c.course_id - WHERE user_id = ? AND start_time = ?' + 'SELECT c.`course_id` FROM `schedule_courses` as c + LEFT JOIN `seminare` ON `seminare`.`seminar_id` = c.`course_id` + JOIN `semester_courses` ON `seminare`.`seminar_id` = `semester_courses`.`course_id` + WHERE user_id = :user_id AND semester_id = :semester_id' ); - $stmt->execute([$user->id, $semester['beginn']]); + $stmt->execute(['user_id' => $user->id, 'semester_id' => $semester->id]); $ids = $stmt->fetchFirst(); // fetch seminar-entries @@ -71,12 +72,10 @@ class UserScheduleShow extends JsonApiController LEFT JOIN seminare as s USING (seminar_id) LEFT JOIN semester_courses ON (s.Seminar_id = semester_courses.course_id) WHERE su.user_id = :userid - AND s.start_time <= :begin AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) '); $stmt->execute([ 'userid' => $user->id, - 'begin' => $semester->beginn, 'semester_id' => $semester->id, ]); diff --git a/lib/classes/JsonApi/Schemas/Course.php b/lib/classes/JsonApi/Schemas/Course.php index b6fe04a63b49f3bc2d19058e47eef6135b9b75df..5ffb6ee878e2237ed529c364f0c63767e3c14527 100644 --- a/lib/classes/JsonApi/Schemas/Course.php +++ b/lib/classes/JsonApi/Schemas/Course.php @@ -107,29 +107,29 @@ class Course extends SchemaProvider private function getStartSemester(\Course $course) { - if (!$semester = \Semester::findByTimestamp($course->start_time)) { + if (!$course->start_semester) { return null; } return [ self::RELATIONSHIP_LINKS => [ - Link::RELATED => $this->createLinkToResource($semester), + Link::RELATED => $this->createLinkToResource($course->start_semester), ], - self::RELATIONSHIP_DATA => $semester, + self::RELATIONSHIP_DATA => $course->start_semester, ]; } private function getEndSemester(\Course $course) { - if (!$semester = \Semester::findByTimestamp($course->end_time)) { + if (!$course->end_semester) { return null; } return [ self::RELATIONSHIP_LINKS => [ - Link::RELATED => $this->createLinkToResource($semester), + Link::RELATED => $this->createLinkToResource($course->end_semester), ], - self::RELATIONSHIP_DATA => $semester, + self::RELATIONSHIP_DATA => $course->end_semester, ]; } diff --git a/lib/classes/ModulesNotification.php b/lib/classes/ModulesNotification.php index 1dc361c1f38daff33c0ac80e69febdaf3fd0cbc9..f16ea1201cb09be9fcdaf0128a59a1b5dcd84007 100644 --- a/lib/classes/ModulesNotification.php +++ b/lib/classes/ModulesNotification.php @@ -86,7 +86,7 @@ class ModulesNotification } $my_sem = []; - $query = "SELECT s.Seminar_id, s.Name, s.chdate, s.start_time, IFNULL(visitdate, :threshold) AS visitdate + $query = "SELECT s.Seminar_id, s.Name, s.chdate, IFNULL(visitdate, :threshold) AS visitdate FROM seminar_user_notifications su JOIN seminar_user USING (user_id, seminar_id) JOIN seminare s USING (Seminar_id) @@ -114,7 +114,6 @@ class ModulesNotification $my_sem[$seminar_id] = [ 'name' => $row['Name'], 'chdate' => $row['chdate'], - 'start_time' => $row['start_time'], 'tools' => new SimpleCollection($tools), 'visitdate' => $row['visitdate'], 'notification' => $notification->notification_data->getArrayCopy(), diff --git a/lib/classes/MyRealmModel.php b/lib/classes/MyRealmModel.php index 8997e780bef971c45fe3b3cbab17c12a98fdbea8..8fe3fee4d5d1cfef1aa4da66f55152aa1450d946 100644 --- a/lib/classes/MyRealmModel.php +++ b/lib/classes/MyRealmModel.php @@ -272,7 +272,7 @@ class MyRealmModel $show_semester_name = UserConfig::get($GLOBALS['user']->id)->SHOWSEM_ENABLE; $sem_courses = []; - $param_array = 'name seminar_id visible veranstaltungsnummer start_time duration_time status visible '; + $param_array = 'name seminar_id visible veranstaltungsnummer status visible '; $param_array .= 'chdate admission_binding modules admission_prelim'; // filtering courses @@ -826,7 +826,7 @@ class MyRealmModel ) ); - $data_fields = 'name seminar_id visible veranstaltungsnummer start_time duration_time status visible ' + $data_fields = 'name seminar_id visible veranstaltungsnummer status visible ' . 'chdate admission_binding admission_prelim'; $studygroup_data = []; foreach ($studygroup_memberships as $membership) { diff --git a/lib/classes/StudipLog.php b/lib/classes/StudipLog.php index 7a520c98dc37fe2819024638c5deb2600a7bc0d1..34321b14fab6ca6fe289ccbe6f972af74782e6b3 100644 --- a/lib/classes/StudipLog.php +++ b/lib/classes/StudipLog.php @@ -196,8 +196,12 @@ class StudipLog $result = []; // search for active seminars - $courses = Course::findBySQL("VeranstaltungsNummer LIKE CONCAT('%', :needle, '%') - OR seminare.Name LIKE CONCAT('%', :needle, '%') ORDER BY start_time DESC", + $courses = Course::findBySQL( + "JOIN semester_courses ON seminare.seminar_id = semester_courses.course_id + JOIN semester USING (semester_id) + WHERE + VeranstaltungsNummer LIKE CONCAT('%', :needle, '%') + OR seminare.Name LIKE CONCAT('%', :needle, '%') ORDER BY semester.beginn DESC", [':needle' => $needle]); foreach ($courses as $course) { diff --git a/lib/classes/admission/CourseSet.php b/lib/classes/admission/CourseSet.php index cf876673671a68823e1d822805307cac2b2ab963..9d9889ef1d9a20f5b399844a61a698330def8084 100644 --- a/lib/classes/admission/CourseSet.php +++ b/lib/classes/admission/CourseSet.php @@ -375,6 +375,7 @@ class CourseSet LEFT JOIN courseset_rule cr ON cr.set_id=ci.set_id LEFT JOIN seminar_courseset sc ON c.set_id = sc.set_id LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id + LEFT JOIN `semester_courses` ON s.`seminar_id` = `semester_courses`.`course_id` WHERE ci.`institute_id`=?"; $parameters = [$instituteId]; if (!$GLOBALS['perm']->have_perm('admin')) { @@ -390,8 +391,8 @@ class CourseSet $parameters[] = $filter['rule_types']; } if (!empty($filter['semester_id'])) { - $query .= " AND s.start_time = ?"; - $parameters[] = Semester::find($filter['semester_id'])->beginn; + $query .= " AND `semester_courses`.`semester_id` = ?"; + $parameters[] = $filter['semester_id']; } if (!empty($filter['course_set_chdate'])) { $query .= " AND c.chdate > ?"; @@ -415,8 +416,11 @@ class CourseSet LEFT JOIN courseset_institute ci ON ci.`set_id`=c.`set_id` LEFT JOIN courseset_rule cr ON cr.set_id=ci.set_id LEFT JOIN seminar_courseset sc ON c.set_id = sc.set_id - LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id - WHERE ci.institute_id IS NULL"; + LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id "; + if (!empty($filter['semester_id'])) { + $query .= "JOIN `semester_courses` ON s.`seminar_id` = `semester_courses`.`course_id` "; + } + $query .= "WHERE ci.institute_id IS NULL "; $parameters = []; $query .= " AND (c.`private`=0 OR c.`user_id`=?)"; $parameters[] = $GLOBALS['user']->id; @@ -429,8 +433,8 @@ class CourseSet $parameters[] = $filter['rule_types']; } if (!empty($filter['semester_id'])) { - $query .= " AND s.start_time = ?"; - $parameters[] = Semester::find($filter['semester_id'])->beginn; + $query .= " AND `semester_courses`.`semester_id` = ?"; + $parameters[] = $filter['semester_id']; } if (!empty($filter['course_set_chdate'])) { $query .= " AND c.chdate > ?"; @@ -1026,15 +1030,23 @@ class CourseSet $tpl->set_attribute('institutes', $institutes); } if (!$short || $this->hasAdmissionRule('LimitedAdmission')) { - $courses = Course::findAndMapMany(function($c) { - return [ - 'id' => $c->id, - 'name' => $c->getFullName('number-name-semester'), - 'visible' => $c->visible - ]; - }, - array_keys($this->courses), - 'ORDER BY start_time,VeranstaltungsNummer,Name'); + $courses = Course::findAndMapBySQL( + function($c) { + return [ + 'id' => $c->id, + 'name' => $c->getFullName('number-name-semester'), + 'visible' => $c->visible + ]; + }, + "LEFT JOIN `semester_courses` ON `seminare`.`seminar_id` = `semester_courses`.`course_id` + LEFT JOIN `semester_data` USING (`semester_id`) + WHERE + `seminare`.`seminar_id` IN ( :course_ids ) + 'ORDER BY `semester_data`.`beginn`, `VeranstaltungsNummer`, `Name`'", + [ + 'course_ids' => array_keys($this->courses) + ] + ); if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) { $courses = array_filter($courses, function ($c) { diff --git a/lib/classes/coursewizardsteps/BasicDataWizardStep.php b/lib/classes/coursewizardsteps/BasicDataWizardStep.php index d9e79605c6a0211bd97632ef69d92d45ef41ecc1..e6f5518b6f41df2651047d73c2c8bb7eb8a4c7b4 100644 --- a/lib/classes/coursewizardsteps/BasicDataWizardStep.php +++ b/lib/classes/coursewizardsteps/BasicDataWizardStep.php @@ -84,17 +84,17 @@ class BasicDataWizardStep implements CourseWizardStep if ($GLOBALS['perm']->have_perm("admin")) { if ( $s->id == $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE - && empty($values['start_time']) + && empty($values['start_semester']) && Request::isXhr() ) { - $values['start_time'] = $s->beginn; + $values['start_semester'] = $s->id; } } $semesters[] = $s; } } - if (empty($values['start_time'])) { - $values['start_time'] = Semester::findDefault()->beginn; + if (empty($values['start_semester'])) { + $values['start_semester'] = Semester::findDefault()->id; } if (!empty($values['studygroup']) && (!count($typestruct) || empty($values['institute'])) ) { $message = sprintf(_('Die Konfiguration der Studiengruppen ist unvollständig. ' . @@ -107,8 +107,8 @@ class BasicDataWizardStep implements CourseWizardStep if (count($semesters) > 0) { $tpl->set_attribute('semesters', array_reverse($semesters)); // If no semester is set, use current as selected default. - if (empty($values['start_time'])) { - $values['start_time'] = Semester::findCurrent()->beginn; + if (empty($values['start_semester'])) { + $values['start_semester'] = Semester::findCurrent()->id; } } else { $message = sprintf(_('Veranstaltungen können nur ' . @@ -414,7 +414,7 @@ class BasicDataWizardStep implements CourseWizardStep $course->name = new I18NString($values['name'], $values['name_i18n'] ?? []); $course->veranstaltungsnummer = $values['number'] ?? null; $course->beschreibung = new I18NString($values['description'], $values['description_i18n'] ?? []); - $course->start_semester = Semester::findByTimestamp($values['start_time']); + $course->start_semester = Semester::find($values['start_semester']); $course->institut_id = $values['institute']; $semclass = $course->getSemClass(); @@ -426,7 +426,6 @@ class BasicDataWizardStep implements CourseWizardStep // Studygroups: access and description. if (in_array($values['coursetype'], studygroup_sem_types())) { $course->visible = 1; - $course->duration_time = -1; switch ($values['access']) { case 'all': $course->admission_prelim = 0; @@ -516,7 +515,7 @@ class BasicDataWizardStep implements CourseWizardStep { $data = [ 'coursetype' => $course->status, - 'start_time' => $course->start_time, + 'start_semester' => $course->start_semester->id ?? '', 'name' => $course->name, 'name_i18n' => is_object($course->name) ? $course->name->toArray() : $course->name, 'number' => $course->veranstaltungsnummer, diff --git a/lib/classes/coursewizardsteps/LVGroupsWizardStep.php b/lib/classes/coursewizardsteps/LVGroupsWizardStep.php index c651714cf19cc516cc25412c59c28bcda65e86fc..a901b6cdec4e61730ea9e952659cf09888b85f32 100644 --- a/lib/classes/coursewizardsteps/LVGroupsWizardStep.php +++ b/lib/classes/coursewizardsteps/LVGroupsWizardStep.php @@ -33,7 +33,7 @@ class LVGroupsWizardStep implements CourseWizardStep ->classname; // store start time of semester selected in first step - $course_start_time = $values[$step_one_class]['start_time']; + $course_start_semester = $values[$step_one_class]['start_semester']; // We only need our own stored values here. $values = $values[__CLASS__] ?? []; @@ -56,8 +56,8 @@ class LVGroupsWizardStep implements CourseWizardStep $selection_details = $values['lvgruppe_selection']['area_details'] ?? null; if ( - isset($_SESSION[__CLASS__]['course_start_time']) - && $_SESSION[__CLASS__]['course_start_time'] != $course_start_time + isset($_SESSION[__CLASS__]['course_start_semester']) + && $_SESSION[__CLASS__]['course_start_semester'] != $course_start_semester ) { // don't store previously opened nodes // because we get in trouble if the semester has changed @@ -66,7 +66,7 @@ class LVGroupsWizardStep implements CourseWizardStep $open_nodes = !empty($values['open_lvg_nodes']) ? $values['open_lvg_nodes'] : []; } - $_SESSION[__CLASS__]['course_start_time'] = $course_start_time; + $_SESSION[__CLASS__]['course_start_semester'] = $course_start_semester; $tpl->open_lvg_nodes = $open_nodes; $tpl->selection = $selection; @@ -124,10 +124,10 @@ class LVGroupsWizardStep implements CourseWizardStep $course = Course::findCurrent(); if ($course) { - $course_start = $course->start_time; - $course_end = ($course->end_time < 0 || is_null($course->end_time)) ? PHP_INT_MAX : $course->end_time; + $course_start = $course->start_semester?->beginn ?? 0; + $course_end = $course->end_semester?->ende ?? PHP_INT_MAX; } else { - $semester = Semester::findByTimestamp($_SESSION[__CLASS__]['course_start_time']); + $semester = Semester::find($_SESSION[__CLASS__]['course_start_semester']); $course_start = $semester->beginn; $course_end = $semester->ende; } @@ -192,10 +192,10 @@ class LVGroupsWizardStep implements CourseWizardStep $course = Course::findCurrent(); if ($course) { - $course_start = $course->start_time; - $course_end = ($course->end_time < 0 || is_null($course->end_time)) ? PHP_INT_MAX : $course->end_time; + $course_start = $course->start_semester?->beginn ?? 0; + $course_end = $course->end_semester?->ende ?? PHP_INT_MAX; } else { - $semester = Semester::findByTimestamp($_SESSION[__CLASS__]['course_start_time']); + $semester = Semester::find($_SESSION[__CLASS__]['course_start_semester']); $course_start = $semester->beginn; $course_end = $semester->ende; } @@ -243,10 +243,10 @@ class LVGroupsWizardStep implements CourseWizardStep $course = Course::findCurrent(); if ($course) { - $course_start = $course->start_time; - $course_end = ($course->end_time < 0 || is_null($course->end_time)) ? PHP_INT_MAX : $course->end_time; + $course_start = $course->start_semester?->beginn ?? 0; + $course_end = $course->end_semester?->ende ?? PHP_INT_MAX; } else { - $semester = Semester::findByTimestamp($_SESSION[__CLASS__]['course_start_time']); + $semester = Semester::find($_SESSION[__CLASS__]['course_start_semester']); $course_start = $semester->beginn; $course_end = $semester->ende; } diff --git a/lib/classes/globalsearch/GlobalSearchCourses.php b/lib/classes/globalsearch/GlobalSearchCourses.php index 1379f1a023ee92530f7368f3c033c27cf8d2abc4..cb1fbae79adc27b2e8518ace7bb4bf1a5bc88199 100644 --- a/lib/classes/globalsearch/GlobalSearchCourses.php +++ b/lib/classes/globalsearch/GlobalSearchCourses.php @@ -100,10 +100,12 @@ class GlobalSearchCourses extends GlobalSearchModule implements GlobalSearchFull } } - $sql = "SELECT SQL_CALC_FOUND_ROWS courses.`Seminar_id`, courses.`start_time`, + $sql = "SELECT SQL_CALC_FOUND_ROWS courses.`Seminar_id`, {$language_name} AS `Name`, courses.`VeranstaltungsNummer`, courses.`status` FROM `seminare` AS courses + JOIN `semester_courses` ON courses.`seminar_id` = `semester_courses`.`course_id` + JOIN `semester` USING (`semester_id`) {$language_join} JOIN `seminar_user` u ON (u.`Seminar_id` = courses.`Seminar_id` AND u.`status` = 'dozent') JOIN `auth_user_md5` a ON (a.`user_id` = u.`user_id`) @@ -118,7 +120,7 @@ class GlobalSearchCourses extends GlobalSearchModule implements GlobalSearchFull {$seminar_type_condition} {$semester_condition} GROUP BY courses.Seminar_id - ORDER BY start_time DESC"; + ORDER BY `semester`.`beginn` DESC"; if (Config::get()->IMPORTANT_SEMNUMBER) { $sql .= ", courses.`VeranstaltungsNummer`"; diff --git a/lib/extern/ExternPageCourseDetails.php b/lib/extern/ExternPageCourseDetails.php index d9e64d9e275dce3da37729383e38adf66f88362f..05ecd24a39b1325fc991f6a367aea9a781b29a09 100644 --- a/lib/extern/ExternPageCourseDetails.php +++ b/lib/extern/ExternPageCourseDetails.php @@ -205,14 +205,16 @@ class ExternPageCourseDetails extends ExternPage if (!$GLOBALS['MVV_MODUL']['STATUS']['values'][$modul->stat]['public']) { return false; } + $course_start = $course->start_semester->beginn ?? 0; + $course_end = $course->end_semester->ende ?? PHP_INT_MAX; $modul_start = Semester::find($modul->start)->beginn ?: 0; $modul_end = Semester::find($modul->end)->beginn ?: PHP_INT_MAX; - return ($course->start_time <= $modul_end) + return ($course_start <= $modul_end) && ( - ($course->start_time >= $modul_start) + ($course_start >= $modul_start) || $course->isOpenEnded() - || $course->getEndSemester()->ende <= $modul_end - || $course->getEndSemester()->ende >= $modul_start + || $course_end <= $modul_end + || $course_end >= $modul_start ); }); ModuleManagementModelTreeItem::setObjectFilter('StgteilVersion', function ($version) { diff --git a/lib/functions.php b/lib/functions.php index 5659aa5ee625e03b8bde2b63d8d4e2b57c5c28e9..97d0e7021540dddcedaba1bdbafa99393947db63 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -652,261 +652,6 @@ function check_ticket($studipticket) return Seminar_Session::check_ticket($studipticket); } -/** - * searches - * - * @global array $perm - * @global object $user - * @global array $_fullname_sql - * - * @param string $search_str optional search-string - * @param string $search_user optional user to search for - * @param bool $show_sem if true, the seminar is added to the result - * - * @return array - */ -function search_range($search_str = false, $search_user = false, $show_sem = true) -{ - global $_fullname_sql; - - // Helper function that obtains the correct name for an entity taking - // in account whether the semesters should be displayed or not - $formatName = function ($row) use ($show_sem) { - $name = $row['Name']; - if ($show_sem) { - $name = sprintf('%s (%s%s)', - $name, - $row['startsem'], - $row['startsem'] != $row['endsem'] ? ' - ' . $row['endsem'] : ''); - } - return $name; - }; - - $search_result = []; - $show_sem_sql1 = ", s.start_time, (SELECT semester_data.name FROM semester_data WHERE s.start_time >= semester_data.`beginn` AND s.start_time <= semester_data.`ende` LIMIT 1) AS startsem, IF(semester_courses.semester_id IS NULL, '"._("unbegrenzt")."', (SELECT semester_data.name FROM semester_data LEFT JOIN semester_courses USING (semester_id) WHERE semester_courses.course_id = s.Seminar_id ORDER BY semester_data.`beginn` DESC LIMIT 1)) AS endsem "; - $show_sem_sql2 = "LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) "; - - - if ($search_str && $GLOBALS['perm']->have_perm('root')) { - if ($search_user) { - $query = "SELECT user_id, CONCAT({$_fullname_sql['full']}, ' (', username, ')') AS name - FROM auth_user_md5 AS a - LEFT JOIN user_info USING (user_id) - WHERE CONCAT(Vorname, ' ', Nachname, ' ', username) LIKE CONCAT('%', ?, '%') - ORDER BY Nachname, Vorname"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['user_id']] = [ - 'type' => 'user', - 'name' => $row['name'], - ]; - } - } - - $_hidden = _('(versteckt)'); - $query = "SELECT Seminar_id, IF(s.visible = 0, CONCAT(s.Name, ' {$_hidden}'), s.Name) AS Name %s - FROM seminare AS s %s - WHERE s.Name LIKE CONCAT('%%', ?, '%%') - GROUP BY s.Seminar_id - ORDER BY start_time DESC, Name"; - $query = $show_sem - ? sprintf($query, $show_sem_sql1, $show_sem_sql2) - : sprintf($query, '', ''); - $statement = DBManager::get()->prepare($query); - $statement->execute([$search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Seminar_id']] = [ - 'type' => 'sem', - 'name' => $formatName($row), - 'starttime' => $row['start_time'], - 'startsem' => $row['startsem'], - ]; - } - - $query = "SELECT Institut_id, Name, IF(Institut_id = fakultaets_id, 'fak', 'inst') AS type - FROM Institute - WHERE Name LIKE CONCAT('%', ?, '%') - ORDER BY Name"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Institut_id']] = [ - 'type' => $row['type'], - 'name' => $row['Name'], - ]; - } - } elseif ($search_str && $GLOBALS['perm']->have_perm('admin')) { - $_hidden = _('(versteckt)'); - $query = "SELECT s.Seminar_id, IF(s.visible = 0, CONCAT(s.Name, ' {$_hidden}'), s.Name) AS Name %s - FROM user_inst AS a - JOIN seminare AS s USING (Institut_id) %s - WHERE a.user_id = ? AND a.inst_perms = 'admin' AND s.Name LIKE CONCAT('%%', ?, '%%') - ORDER BY start_time"; - $query = $show_sem - ? sprintf($query, $show_sem_sql1, $show_sem_sql2) - : sprintf($query, '', ''); - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Seminar_id']] = [ - 'type' => 'sem', - 'name' => $formatName($row), - 'starttime' => $row['start_time'], - 'startsem' => $row['startsem'], - ]; - } - - $query = "SELECT b.Institut_id, b.Name - FROM user_inst AS a - JOIN Institute AS b USING (Institut_id) - WHERE a.user_id = ? AND a.inst_perms = 'admin' - AND a.institut_id != b.fakultaets_id AND b.Name LIKE CONCAT('%', ?, '%') - ORDER BY Name"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Institut_id']] = [ - 'type' => 'inst', - 'name' => $row['Name'], - ]; - } - if ($GLOBALS['perm']->is_fak_admin()) { - $_hidden = _('(versteckt)'); - $query = "SELECT s.Seminar_id, IF(s.visible = 0, CONCAT(s.Name, ' {$_hidden}'), s.Name) AS Name %s - FROM user_inst AS a - JOIN Institute AS b ON (a.Institut_id = b.Institut_id AND b.Institut_id = b.fakultaets_id) - JOIN Institute AS c ON (c.fakultaets_id = b.Institut_id AND c.fakultaets_id != c.Institut_id) - JOIN seminare AS s ON (s.Institut_id = c.Institut_id) %s - WHERE a.user_id = ? AND a.inst_perms = 'admin' - AND s.Name LIKE CONCAT('%%', ?, '%%') - ORDER BY start_time DESC, Name"; - $query = $show_sem - ? sprintf($query, $show_sem_sql1, $show_sem_sql2) - : sprintf($query, '', ''); - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Seminar_id']] = [ - 'type' => 'sem', - 'name' => $formatName($row), - 'starttime' => $row['start_time'], - 'startsem' => $row['startsem'], - ]; - } - - $query = "SELECT c.Institut_id, c.Name - FROM user_inst AS a - JOIN Institute AS b ON (a.Institut_id = b.Institut_id AND b.Institut_id = b.fakultaets_id) - JOIN Institute AS c ON (c.fakultaets_id = b.institut_id AND c.fakultaets_id != c.institut_id) - WHERE a.user_id = ? AND a.inst_perms = 'admin' - AND c.Name LIKE CONCAT('%', ?, '%') - ORDER BY Name"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Institut_id']] = [ - 'type' => 'inst', - 'name' => $row['Name'], - ]; - } - - $query = "SELECT b.Institut_id, b.Name - FROM user_inst AS a - JOIN Institute AS b ON (a.Institut_id = b.Institut_id AND b.Institut_id = b.fakultaets_id) - WHERE a.user_id = ? AND a.inst_perms = 'admin' - AND b.Name LIKE CONCAT('%', ?, '%') - ORDER BY Name"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id, $search_str]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Institut_id']] = [ - 'type' => 'inst', - 'name' => $row['Name'], - ]; - } - } - } elseif ($GLOBALS['perm']->have_perm('tutor') || $GLOBALS['perm']->have_perm('autor')) { - // autors my also have news in studygroups with proper rights - $_hidden = _('(versteckt)'); - $query = "SELECT s.Seminar_id, IF(s.visible = 0, CONCAT(s.Name, ' {$_hidden}'), s.Name) AS Name %s - FROM seminar_user AS a - JOIN seminare AS s USING (Seminar_id) %s - WHERE a.user_id = ? AND a.status IN ('tutor', 'dozent') - ORDER BY start_time DESC, Name"; - $query = $show_sem - ? sprintf($query, $show_sem_sql1, $show_sem_sql2) - : sprintf($query, '', ''); - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Seminar_id']] = [ - 'type' => 'sem', - 'name' => $formatName($row), - 'starttime' => $row['start_time'], - 'startsem' => $row['startsem'], - ]; - } - - $query = "SELECT Institut_id, b.Name, - IF (Institut_id = fakultaets_id, 'fak', 'inst') AS type - FROM user_inst AS a - JOIN Institute AS b USING (Institut_id) - WHERE a.user_id = ? AND a.inst_perms IN ('dozent','tutor') - ORDER BY Name"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Institut_id']] = [ - 'name' => $row['Name'], - 'type' => $row['type'], - ]; - } - } - - if (Config::get()->DEPUTIES_ENABLE) { - $_hidden = _('(versteckt)'); - $_deputy = _('Vertretung'); - $query = "SELECT s.Seminar_id, - CONCAT(IF(s.visible = 0, CONCAT(s.Name, ' {$_hidden}'), s.Name), ' [{$_deputy}]') AS Name %s - FROM seminare AS s - JOIN deputies AS d ON (s.Seminar_id = d.range_id) %s - WHERE d.user_id = ? - ORDER BY s.start_time DESC, Name"; - $query = $show_sem - ? sprintf($query, $show_sem_sql1, $show_sem_sql2) - : sprintf($query, '', ''); - $statement = DBManager::get()->prepare($query); - $statement->execute([$GLOBALS['user']->id]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['Seminar_id']] = [ - 'type' => 'sem', - 'name' => $formatName($row), - 'starttime' => $row['start_time'], - 'startsem' => $row['startsem'], - ]; - } - if (Deputy::isEditActivated()) { - $query = "SELECT a.user_id, a.username, 'user' AS type, - CONCAT({$_fullname_sql['full']}, ' (', username, ')') AS name - FROM auth_user_md5 AS a - JOIN user_info USING (user_id) - JOIN deputies AS d ON (a.user_id = d.range_id) - WHERE d.user_id = ? - ORDER BY name ASC"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $GLOBALS['user']->id - ]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $search_result[$row['user_id']] = $row; - } - } - } - - return $search_result ?: null; -} - /** * format_help_url($keyword) * returns URL for given help keyword diff --git a/lib/models/Course.php b/lib/models/Course.php index 25350dbce0b90ee38ae338fe5849312a883d1170..9607b91248d60359fe5c4be1b343697e9a842f77 100644 --- a/lib/models/Course.php +++ b/lib/models/Course.php @@ -25,8 +25,6 @@ * @property string|null $sonstiges database column * @property int $lesezugriff database column * @property int $schreibzugriff database column - * @property int|null $start_time database column - * @property int|null $duration_time database column * @property I18NString|null $art database column * @property I18NString|null $teilnehmer database column * @property I18NString|null $vorrausetzungen database column @@ -82,6 +80,16 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, FeedbackRange, Studip\Calendar\Owner { + /** + * @var Semester initial start semester. + */ + protected $initial_start_semester; + + /** + * @var Semester initial end semester. + */ + protected $initial_end_semester; + protected static function configure($config = []) { $config['db_table'] = 'seminare'; @@ -261,7 +269,6 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe $config['default_values']['lesezugriff'] = 1; $config['default_values']['schreibzugriff'] = 1; - $config['default_values']['duration_time'] = 0; $config['additional_fields']['teachers'] = [ 'get' => 'getTeachers' @@ -299,8 +306,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe $config['i18n_fields']['leistungsnachweis'] = true; $config['i18n_fields']['ort'] = true; - $config['registered_callbacks']['before_update'][] = 'logStore'; - $config['registered_callbacks']['before_store'][] = 'cbSetStartAndDurationTime'; + $config['registered_callbacks']['before_store'][] = 'logStore'; $config['registered_callbacks']['after_create'][] = 'setDefaultTools'; $config['registered_callbacks']['after_delete'][] = function ($course) { CourseAvatar::getAvatar($course->id)->reset(); @@ -367,6 +373,31 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe parent::configure($config); } + /** + * @param string $relation + */ + public function initRelation($relation): void + { + if ($relation === 'semesters' && $this->relations[$relation] === null) { + parent::initRelation($relation); + $this->initial_start_semester = $this->getStartSemester(); + $this->initial_end_semester = $this->getEndSemester(); + } + parent::initRelation($relation); + } + + /** + * Override of SimpleORMap::cbAfterInitialize for resetting the flags that indicate semester changes. + * + * @see SimpleORMap::cbAfterInitialize + */ + protected function cbAfterInitialize($cb_type): void + { + parent::cbAfterInitialize($cb_type); + //Reset the flags for the start and end semester: + $this->initial_start_semester = null; + $this->initial_end_semester = null; + } /** * Returns the currently active course or false if none is active. @@ -411,22 +442,6 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe }); } - public function getEnd_Time() - { - return $this->duration_time == -1 ? -1 : $this->start_time + $this->duration_time; - } - - public function setEnd_Time($value) - { - if ($value == -1) { - $this->duration_time = -1; - } elseif ($this->start_time > 0 && $value > $this->start_time) { - $this->duration_time = $value - $this->start_time; - } else { - $this->duration_time = 0; - } - } - public function _set_semester($field, $value) { $method = 'set' . ($field === 'start_semester' ? 'StartSemester' : 'EndSemester'); @@ -497,11 +512,11 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe */ public function getStartSemester() { - if (count($this->semesters) > 0) { - return $this->semesters->first(); - } else { - return Semester::findCurrent(); + //this is called by __get() and therefore using magic properties is not always safe + if ($this->relations['semesters'] === null) { + $this->initRelation('semesters'); } + return $this->relations['semesters']->first() ?? Semester::findCurrent(); } /** @@ -512,9 +527,11 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe */ public function getEndSemester() { - if (count($this->semesters) > 0) { - return $this->semesters->last(); + //this is called by __get() and therefore using magic properties is not always safe + if ($this->relations['semesters'] === null) { + $this->initRelation('semesters'); } + return $this->relations['semesters']->last(); } /** @@ -2133,86 +2150,66 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe */ protected function logStore() { - if ($this->isFieldDirty('start_time')) { - //Log change of start semester: - StudipLog::log('SEM_SET_STARTSEMESTER', $this->id, isset($this->start_semester) ? $this->start_semester->name : _('unbegrenzt')); - NotificationCenter::postNotification('CourseDidChangeSchedule', $this); - } - if ($this->isFieldDirty('duration_time')) { - StudipLog::log('SEM_SET_ENDSEMESTER', $this->id, $this->getTextualSemester()); - NotificationCenter::postNotification('CourseDidChangeSchedule', $this); - } - - $log = []; - if ($this->isFieldDirty('admission_prelim')) { - $log[] = $this->admission_prelim ? _('Neuer Anmeldemodus: Vorläufiger Eintrag') : _('Neuer Anmeldemodus: Direkter Eintrag'); - } + if (!$this->isNew()) { + if ($this->initial_start_semester?->id !== $this->start_semester?->id) { + //Log change of start semester: + StudipLog::log('SEM_SET_STARTSEMESTER', $this->id, isset($this->start_semester) ? $this->start_semester->name : _('unbegrenzt')); + NotificationCenter::postNotification('CourseDidChangeSchedule', $this); + } + if ($this->initial_end_semester?->id !== $this->end_semester?->id) { + StudipLog::log('SEM_SET_ENDSEMESTER', $this->id, $this->getTextualSemester()); + NotificationCenter::postNotification('CourseDidChangeSchedule', $this); + } - if ($this->isFieldDirty('admission_binding')) { - $log[] = $this->admission_binding? _('Anmeldung verbindlich') : _('Anmeldung unverbindlich'); - } + $log = []; + if ($this->isFieldDirty('admission_prelim')) { + $log[] = $this->admission_prelim ? _('Neuer Anmeldemodus: Vorläufiger Eintrag') : _('Neuer Anmeldemodus: Direkter Eintrag'); + } - if ($this->isFieldDirty('admission_turnout')) { - $log[] = sprintf(_('Neue Teilnehmerzahl: %s'), (int)$this->admission_turnout); - } + if ($this->isFieldDirty('admission_binding')) { + $log[] = $this->admission_binding ? _('Anmeldung verbindlich') : _('Anmeldung unverbindlich'); + } - if ($this->isFieldDirty('admission_disable_waitlist')) { - $log[] = $this->admission_disable_waitlist ? _('Warteliste aktiviert') : _('Warteliste deaktiviert'); - } + if ($this->isFieldDirty('admission_turnout')) { + $log[] = sprintf(_('Neue Teilnehmerzahl: %s'), (int)$this->admission_turnout); + } - if ($this->isFieldDirty('admission_waitlist_max')) { - $log[] = sprintf(_('Plätze auf der Warteliste geändert: %u'), (int)$this->admission_waitlist_max); - } + if ($this->isFieldDirty('admission_disable_waitlist')) { + $log[] = $this->admission_disable_waitlist ? _('Warteliste aktiviert') : _('Warteliste deaktiviert'); + } - if ($this->isFieldDirty('admission_disable_waitlist_move')) { - $log[] = $this->admission_disable_waitlist ? _('Nachrücken aktiviert') : _('Nachrücken deaktiviert'); - } + if ($this->isFieldDirty('admission_waitlist_max')) { + $log[] = sprintf(_('Plätze auf der Warteliste geändert: %u'), (int)$this->admission_waitlist_max); + } - if ($this->isFieldDirty('admission_prelim_txt')) { - if ($this->admission_prelim_txt) { - $log[] = sprintf(_('Neuer Hinweistext bei vorläufigen Eintragungen: %s'), strip_tags(kill_format($this->admission_prelim_txt))); - } else { - $log[] = _('Hinweistext bei vorläufigen Eintragungen wurde entfert'); + if ($this->isFieldDirty('admission_disable_waitlist_move')) { + $log[] = $this->admission_disable_waitlist ? _('Nachrücken aktiviert') : _('Nachrücken deaktiviert'); } - } - if (!empty($log)) { - StudipLog::log( - 'SEM_CHANGED_ACCESS', - $this->id, - null, - '', - implode(' - ', $log) - ); - } + if ($this->isFieldDirty('admission_prelim_txt')) { + if ($this->admission_prelim_txt) { + $log[] = sprintf(_('Neuer Hinweistext bei vorläufigen Eintragungen: %s'), strip_tags(kill_format($this->admission_prelim_txt))); + } else { + $log[] = _('Hinweistext bei vorläufigen Eintragungen wurde entfert'); + } + } - if ($this->isFieldDirty('visible')) { - StudipLog::log($this->visible ? 'SEM_VISIBLE' : 'SEM_INVISIBLE', $this->id); - } - } + if (!empty($log)) { + StudipLog::log( + 'SEM_CHANGED_ACCESS', + $this->id, + null, + '', + implode(' - ', $log) + ); + } - /** - * Called directly before storing the object to edit the columns start_time and duration_time - * which are both deprecated but are still in use for older plugins. - */ - public function cbSetStartAndDurationTime() - { - if ($this->isFieldDirty('start_time')) { - $this->setStartSemester(Semester::findByTimestamp($this->start_time)); - } - if ($this->isFieldDirty('duration_time')) { - $this->setEndSemester($this->duration_time == -1 ? null : Semester::findByTimestamp($this->start_time + $this->duration_time)); - } - if ($this->isOpenEnded()) { - $this->start_time = $this->start_time ?: Semester::findCurrent()->beginn ?? time(); - $this->duration_time = -1; - } else { - $this->start_time = $this->getStartSemester()->beginn; - $this->duration_time = $this->getEndSemester()->beginn - $this->start_time; + if ($this->isFieldDirty('visible')) { + StudipLog::log($this->visible ? 'SEM_VISIBLE' : 'SEM_INVISIBLE', $this->id); + } } } - //StudipItem interface implementation: public function getItemName($long_format = true) @@ -2342,7 +2339,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe "LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) WHERE Seminar_id IN (?) GROUP BY seminare.Seminar_id - ORDER BY semester_courses.semester_id IS NULL DESC, start_time DESC, {$name_sort}", + ORDER BY semester_courses.semester_id IS NULL DESC, {$name_sort}", [$seminar_ids] ); } diff --git a/lib/models/Lvgruppe.php b/lib/models/Lvgruppe.php index 05f3b594507d33a1a513e1a24a09406feac85977..bdd9f0b7a83eca52839f03aaecf6047dc29b018a 100644 --- a/lib/models/Lvgruppe.php +++ b/lib/models/Lvgruppe.php @@ -126,14 +126,10 @@ class Lvgruppe extends ModuleManagementModelTreeItem $semester = Semester::find($semester_id); if ($semester) { $filter_sql = trim($filter_sql) ? $filter_sql . ' AND' : $filter_sql . ' WHERE'; - $filter_sql .= ' seminare.start_time <= :beginn ' - . 'AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) ' - . 'AND (start_sem.beginn <= :ende AND ' - . 'IF(ISNULL(end_sem.ende), 1, end_sem.ende >= :beginn)) '; + $filter_sql .= ' semester_courses.semester_id = :semester_id ' + . 'AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) '; $params = [ - ':semester_id' => $semester->semester_id, - ':beginn' => $semester->beginn, - ':ende' => $semester->ende + ':semester_id' => $semester->semester_id ]; $semester_join = 'LEFT JOIN mvv_modul ON mvv_modul.modul_id = mvv_modulteil.modul_id ' . 'LEFT JOIN semester_data as start_sem ON start_sem.semester_id = mvv_modul.start ' @@ -197,14 +193,10 @@ class Lvgruppe extends ModuleManagementModelTreeItem } $filter_sql = trim($filter_sql) ? $filter_sql : ' AND'; - $filter_sql .= ' seminare.start_time <= :beginn ' - . 'AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) ' - . 'AND (start_sem.beginn <= :ende AND ' - . 'IF(ISNULL(end_sem.ende), 1, end_sem.ende >= :beginn)) '; + $filter_sql .= ' semester_courses.semester_id = :semester_id ' + . 'AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) '; $params = [ - ':semester_id' => $semester->semester_id, - ':beginn' => $semester->beginn, - ':ende' => $semester->ende + ':semester_id' => $semester->semester_id ]; $semester_join = 'LEFT JOIN mvv_modul ON mvv_modul.modul_id = mvv_modulteil.modul_id ' . 'LEFT JOIN semester_data as start_sem ON start_sem.semester_id = mvv_modul.start ' @@ -517,48 +509,61 @@ class Lvgruppe extends ModuleManagementModelTreeItem * * @param bool $only_visible Return only visible courses. * @param string $semester_id Return only this semester. - * @return array All assigned courses grouped by semesters. + * @return Course[] All assigned courses grouped by semesters. */ public function getAllAssignedCourses($only_visible = false, $semester_id = null) { - $sem_start_times = []; - + $conditions_sql = ''; + if ($only_visible) { + $conditions_sql .= " AND `seminare`.`visible` = '1'"; + } if ($semester_id) { $semester = Semester::find($semester_id); if (!$semester) { return []; } - $sem_start_times[$semester->id] = $semester->beginn; + + //Find only courses that lie in that semester. + $courses = Course::findBySQL( + 'LEFT JOIN `semester_courses` sc + ON `seminare`.`seminar_id` = sc.`course_id` + JOIN `mvv_lvgruppe_seminar` mls USING (`seminar_id`) + WHERE + mls.`lvgruppe_id` = :group_id + AND (sc.`semester_id` = :semester_id OR sc.`semester_id` IS NULL)' + . $conditions_sql . ' + ORDER BY `seminare`.`Name`', + [ + 'group_id' => $this->id, + 'semester_id' => $semester->id + ] + ); + return [$semester->id => $courses]; } else { - $sem_start_times = SimpleORMapCollection::createFromArray( - Semester::getAll())->toGroupedArray('id', 'beginn'); - $sem_start_times = array_map( - function ($sem) { return $sem['beginn']; } - , $sem_start_times); - } - $visible_sql = $only_visible ? ' AND visible = 1' : ''; - $courses = []; - $stmt = DBManager::get()->prepare('SELECT seminar_id, Name, ' - . 'VeranstaltungsNummer, visible, INTERVAL(start_time,' - . join(',', $sem_start_times) - . ') AS sem_number, ' - . 'IF(duration_time=-1,' . count($sem_start_times) - . ',INTERVAL(start_time+duration_time,' - . join(',', $sem_start_times) - . ')) AS sem_number_end FROM seminare ' - . 'INNER JOIN mvv_lvgruppe_seminar USING(seminar_id) ' - . 'WHERE lvgruppe_id = ? ' . $visible_sql - . ' AND start_time <= ' . end($sem_start_times) - . ' ORDER BY sem_number DESC, Name'); - $stmt->execute([$this->getId()]); - $sem_ids = array_keys($sem_start_times); - foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $course) { - if ($course['sem_number'] == 0) $course['sem_number'] = 1; - for ($i = $course['sem_number']; $i <= $course['sem_number_end']; $i++) { - $courses[$sem_ids[$i-1]][] = $course; + //No semester specified. Find courses from all semesters. + $courses = Course::findBySQL( + 'JOIN `mvv_lvgruppe_seminar` mls USING (`seminar_id`) + WHERE + mls.`lvgruppe_id` = :group_id ' + . $conditions_sql . ' + ORDER BY `seminare`.`Name`', + [ + 'group_id' => $this->id + ] + ); + $data = []; + foreach ($courses as $course) { + if (!$course->start_semester) { + //An invalid course that cannot be grouped by a semester. + continue; + } + if (!array_key_exists($course->start_semester->id, $data)) { + $data[$course->start_semester->id] = []; + } + $data[$course->start_semester->id][] = $course; } + return $data; } - return $courses; } /**