From f00164f6f8b823872d0934830a466aeb2af7114b Mon Sep 17 00:00:00 2001 From: Moritz Strohm Date: Mon, 2 Sep 2024 07:50:49 +0000 Subject: StEP 3209, re #3209 Merge request studip/studip!2179 --- app/controllers/admin/autoinsert.php | 14 +- app/controllers/admin/banner.php | 8 +- app/controllers/admin/courses.php | 15 +- app/controllers/admin/user.php | 11 +- app/controllers/avatar.php | 19 +- app/controllers/calendar/calendar.php | 13 + app/controllers/calendar/schedule.php | 18 +- app/controllers/course/admission.php | 26 +- app/controllers/course/archive.php | 5 +- app/controllers/course/basicdata.php | 472 ++-- app/controllers/course/block_appointments.php | 4 +- app/controllers/course/cancel_dates.php | 24 +- app/controllers/course/dates.php | 83 +- app/controllers/course/details.php | 20 +- app/controllers/course/enrolment.php | 105 +- app/controllers/course/grouping.php | 79 +- app/controllers/course/members.php | 696 +++--- app/controllers/course/overview.php | 37 +- app/controllers/course/statusgroups.php | 53 +- app/controllers/course/studygroup.php | 25 +- app/controllers/course/timesrooms.php | 443 ++-- app/controllers/course/topics.php | 6 +- app/controllers/my_courses.php | 47 +- app/controllers/tree.php | 3 +- app/views/calendar/schedule/_entry_course.php | 20 +- app/views/calendar/schedule/_entry_inst.php | 24 +- app/views/course/cancel_dates/index.php | 6 +- app/views/course/details/index.php | 20 +- app/views/course/overview/index.php | 18 +- app/views/course/studygroup/edit.php | 30 +- app/views/course/timesrooms/_regularEvents.php | 29 +- app/views/course/timesrooms/createSingleDate.php | 4 +- app/views/course/timesrooms/editStack.php | 4 +- composer.json | 6 +- .../1.6_step_25_raumzeit_db_conversion.php | 6 - lib/classes/Context.php | 2 - lib/classes/CourseAvatar.php | 4 +- lib/classes/CourseDateList.php | 323 +++ lib/classes/DateFormatter.php | 176 -- lib/classes/EnrolmentInformation.php | 64 + lib/classes/ForumPerm.php | 6 +- lib/classes/Information.php | 157 ++ lib/classes/JsonApi/Routes/Blubber/Authority.php | 1 - .../Routes/Tree/DetailsOfTreeNodeCourse.php | 7 +- lib/classes/JsonApi/Schemas/SeminarCycleDate.php | 10 +- lib/classes/SemBrowse.php | 41 +- lib/classes/Seminar.php | 2439 -------------------- lib/classes/SeminarCategories.php | 2 +- lib/classes/StudipSemTreeViewAdmin.php | 6 +- lib/classes/StudygroupModel.php | 49 +- lib/classes/UserManagement.php | 13 +- lib/classes/admission/RandomAlgorithm.php | 35 +- lib/classes/calendar/CalendarScheduleModel.php | 73 +- .../coursewizardsteps/BasicDataWizardStep.php | 162 +- lib/classes/globalsearch/GlobalSearchCourses.php | 6 +- lib/classes/globalsearch/GlobalSearchMyCourses.php | 0 lib/dates.inc.php | 51 +- lib/elearning/Ilias4ConnectedCMS.php | 25 +- lib/exceptions/Exception.php | 58 + lib/exceptions/InvalidValuesException.php | 12 +- lib/exceptions/StudipException.php | 36 - lib/exceptions/course/EnrolmentException.php | 60 + lib/exceptions/course/MembershipException.php | 42 + lib/exceptions/tools/ToolException.php | 29 + lib/extern/ExternPageCourseDetails.php | 5 +- lib/extern/ExternPageCourses.php | 2 +- lib/ilias_interface/ConnectedIlias.php | 50 +- lib/models/AdmissionApplication.php | 40 +- lib/models/ContentTermsOfUse.php | 10 +- lib/models/Course.php | 1358 ++++++++++- lib/models/CourseDate.php | 75 +- lib/models/CourseMember.php | 70 +- lib/models/CourseTopic.php | 28 +- lib/models/LogEvent.php | 4 +- lib/models/SeminarCycleDate.php | 347 ++- lib/models/StudipNews.php | 2 +- lib/models/resources/ResourceRequest.php | 9 +- lib/raumzeit/CycleData.php | 434 ---- lib/raumzeit/CycleDataDB.php | 271 --- lib/raumzeit/Issue.php | 268 --- lib/raumzeit/IssueDB.php | 153 -- lib/raumzeit/MetaDate.php | 697 ------ lib/raumzeit/MetaDateDB.php | 55 - lib/raumzeit/SeminarDB.php | 264 --- lib/raumzeit/SingleDate.php | 978 -------- lib/raumzeit/SingleDateDB.php | 299 --- lib/raumzeit/raumzeit_functions.inc.php | 70 - lib/showNews.inc.php | 6 +- lib/webservices/api/studip_seminar.php | 2 +- .../services/lecture_tree_webservice.php | 13 +- templates/dates/course_date_list.php | 26 + templates/dates/room_grouped_course_date_list.php | 24 + templates/dates/seminar_export_location.php | 48 - tests/jsonapi/_bootstrap.php | 4 +- 94 files changed, 4029 insertions(+), 7865 deletions(-) create mode 100644 lib/classes/CourseDateList.php delete mode 100644 lib/classes/DateFormatter.php create mode 100644 lib/classes/EnrolmentInformation.php create mode 100644 lib/classes/Information.php delete mode 100644 lib/classes/Seminar.php create mode 100644 lib/classes/globalsearch/GlobalSearchMyCourses.php create mode 100644 lib/exceptions/Exception.php delete mode 100644 lib/exceptions/StudipException.php create mode 100644 lib/exceptions/course/EnrolmentException.php create mode 100644 lib/exceptions/course/MembershipException.php create mode 100644 lib/exceptions/tools/ToolException.php delete mode 100644 lib/raumzeit/CycleData.php delete mode 100644 lib/raumzeit/CycleDataDB.php delete mode 100644 lib/raumzeit/Issue.php delete mode 100644 lib/raumzeit/IssueDB.php delete mode 100644 lib/raumzeit/MetaDate.php delete mode 100644 lib/raumzeit/MetaDateDB.php delete mode 100644 lib/raumzeit/SeminarDB.php delete mode 100644 lib/raumzeit/SingleDate.php delete mode 100644 lib/raumzeit/SingleDateDB.php delete mode 100644 lib/raumzeit/raumzeit_functions.inc.php create mode 100644 templates/dates/course_date_list.php create mode 100644 templates/dates/room_grouped_course_date_list.php delete mode 100644 templates/dates/seminar_export_location.php diff --git a/app/controllers/admin/autoinsert.php b/app/controllers/admin/autoinsert.php index f899795..003586e 100644 --- a/app/controllers/admin/autoinsert.php +++ b/app/controllers/admin/autoinsert.php @@ -159,7 +159,7 @@ class Admin_AutoinsertController extends AuthenticatedController } elseif (!count($filters)) { PageLayout::postError(_('Keine Filterkriterien gewählt')); } else { - $seminar = Seminar::GetInstance($seminar_id); + $course = Course::find($seminar_id); $userlookup = new UserLookup(); foreach ($filters as $type => $values) { @@ -170,8 +170,11 @@ class Admin_AutoinsertController extends AuthenticatedController foreach ($user_ids as $user_id) { if ($force || !AutoInsert::checkAutoInsertUser($seminar_id, $user_id)) { - $real_users += $seminar->addMember($user_id) ? 1 : 0; - AutoInsert::saveAutoInsertUser($seminar_id, $user_id); + $user = User::find($user_id); + if ($user) { + $real_users += $course->addMember($user) ? 1 : 0; + AutoInsert::saveAutoInsertUser($seminar_id, $user_id); + } } } @@ -182,9 +185,8 @@ class Admin_AutoinsertController extends AuthenticatedController count($user_ids), sprintf( '%s', - URLHelper::getLink('dispatch.php/course/details/', ['cid' => $seminar->getId()]), - htmlReady($seminar->getName() - ) + URLHelper::getLink('dispatch.php/course/details/', ['cid' => $course->id]), + htmlReady($course->name) ) ); $details = [_('Etwaige Abweichungen der Personenzahlen enstehen durch bereits vorhandene bzw. wieder ausgetragene Personen.')]; diff --git a/app/controllers/admin/banner.php b/app/controllers/admin/banner.php index 5199bbc..abc88ba 100644 --- a/app/controllers/admin/banner.php +++ b/app/controllers/admin/banner.php @@ -156,9 +156,7 @@ class Admin_BannerController extends AuthenticatedController } break; case 'seminar': - try { - Seminar::getInstance($target); - } catch (Exception $e) { + if (!Course::exists($target)) { $errors[] = _('Die angegebene Veranstaltung existiert nicht. ' .'Bitte geben Sie eine gültige Veranstaltungs-ID ein.'); } @@ -199,14 +197,14 @@ class Admin_BannerController extends AuthenticatedController ->defaultValue($banner->target,$seminar_name['name']) ->render(); } - + if ($banner->target_type == 'user') { $this->user = QuickSearch::get('user', new StandardSearch('username')) ->setInputStyle('width: 240px') ->defaultValue($banner->target, $banner->target) ->render(); } - + if ($banner->target_type == 'inst') { $institut_name = get_object_name($banner->target, 'inst'); $this->institut = QuickSearch::get('institut', new StandardSearch('Institut_id')) diff --git a/app/controllers/admin/courses.php b/app/controllers/admin/courses.php index 5f16d21..562a14b 100644 --- a/app/controllers/admin/courses.php +++ b/app/controllers/admin/courses.php @@ -641,10 +641,8 @@ class Admin_CoursesController extends AuthenticatedController $d['type'] = $semtype['name']; } if (in_array('room_time', $activated_fields)) { - $seminar = new Seminar($course); - $d['room_time'] = $seminar->getDatesHTML([ - 'show_room' => true, - ]) ?: _('nicht angegeben'); + $strings = $course->getAllDatesInSemester()->toStringArray(); + $d['room_time'] = implode('
', $strings) ?: _('nicht angegeben'); } if (in_array('semester', $activated_fields)) { $d['semester'] = $course->semester_text; @@ -968,7 +966,6 @@ class Admin_CoursesController extends AuthenticatedController $data = []; foreach ($courses as $course) { - $sem = new Seminar($course); $row = []; if (in_array('number', $filter_config)) { @@ -988,11 +985,9 @@ class Admin_CoursesController extends AuthenticatedController } if (in_array('room_time', $filter_config)) { - $_room = $sem->getDatesExport([ - 'semester_id' => $this->semester->id, - 'show_room' => true - ]); - $row['room_time'] = $_room ?: _('nicht angegeben'); + $dates = $course->getAllDatesInSemester($this->semester); + $date_strings = $dates->toStringArray(true); + $row['room_time'] = implode("\n", $date_strings) ?: _('nicht angegeben'); } if (in_array('requests', $filter_config)) { diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php index d1dcf1e..45802bc 100644 --- a/app/controllers/admin/user.php +++ b/app/controllers/admin/user.php @@ -1569,21 +1569,22 @@ class Admin_UserController extends AuthenticatedController { CSRFProtection::verifyUnsafeRequest(); + $course_ids = []; if (Request::get('course_id')) { - $courses = [Request::get('course_id')]; + $course_ids = [Request::option('course_id')]; } else { - $courses = Request::getArray('courses'); + $course_ids = Request::optionArray('courses'); } - if (empty($courses)) { + if (empty($course_ids)) { PageLayout::postError(_('Sie haben keine Veranstaltungen ausgewählt.')); } else { - $courses = array_map('Seminar::GetInstance', $courses); + $courses = Course::findMany($course_ids); $successes = 0; $fails = 0; foreach ($courses as $course) { - if ($course->deleteMember($user->id)) { + if ($course->deleteMember($user)) { $successes++; } else { $fails++; diff --git a/app/controllers/avatar.php b/app/controllers/avatar.php index aafbb98..5111078 100644 --- a/app/controllers/avatar.php +++ b/app/controllers/avatar.php @@ -41,10 +41,9 @@ class AvatarController extends AuthenticatedController PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Veranstaltungsbild ändern')); $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { - $class = StudygroupAvatar::class; + $course = Course::find($id); + if ($course->isStudygroup()) { + $class = 'StudygroupAvatar'; $this->cancel_link = $this->url_for('course/studygroup/edit?cid=' . $id); } else { $class = CourseAvatar::class; @@ -99,10 +98,9 @@ class AvatarController extends AuthenticatedController $redirect = 'institute/basicdata/index'; } else { $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { - $class = StudygroupAvatar::class; + $course = Course::find($id); + if ($course->isStudygroup()) { + $class = 'StudygroupAvatar'; $redirect = 'course/studygroup/edit/?cid=' . $id; } else { $class = CourseAvatar::class; @@ -180,9 +178,8 @@ class AvatarController extends AuthenticatedController $redirect = 'institute/basicdata/index'; } else { $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { + $course = Course::find($id); + if ($course->isStudygroup()) { $class = 'StudygroupAvatar'; $redirect = 'course/studygroup/edit/?cid=' . $id; } else { diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php index 6923f8f..dfc6706 100644 --- a/app/controllers/calendar/calendar.php +++ b/app/controllers/calendar/calendar.php @@ -1,4 +1,17 @@ + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since + */ class Calendar_CalendarController extends AuthenticatedController { diff --git a/app/controllers/calendar/schedule.php b/app/controllers/calendar/schedule.php index cf70dd3..668ed77 100644 --- a/app/controllers/calendar/schedule.php +++ b/app/controllers/calendar/schedule.php @@ -292,18 +292,18 @@ class Calendar_ScheduleController extends AuthenticatedController * * @param string $start the start time of the group, e.g. "1000" * @param string $end the end time of the group, e.g. "1200" - * @param string $seminars the IDs of the courses + * @param string $course_ids the IDs of the courses * @param string $day numeric day to show * * @return void */ - public function groupedentry_action($start, $end, $seminars, $day) + public function groupedentry_action($start, $end, $course_ids, $day) { $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); - $seminars = explode(',', $seminars); - foreach ($seminars as $seminar) { - $zw = explode('-', $seminar); - $this->seminars[$zw[0]] = Seminar::getInstance($zw[0]); + $course_ids = explode(',', $course_ids); + foreach ($course_ids as $course_id) { + $zw = explode('-', $course_id); + $this->courses[$zw[0]] = Course::find($zw[0]); } $this->timespan = mb_substr($start, 0, 2) . ':' . mb_substr($start, 2, 2) @@ -369,11 +369,11 @@ class Calendar_ScheduleController extends AuthenticatedController */ public function addvirtual_action($seminar_id) { - $sem = Seminar::getInstance($seminar_id); - foreach ($sem->getCycles() as $cycle) { + $regular_dates = SeminarCycleDate::findBySeminar($seminar_id); + foreach ($regular_dates as $cycle) { $data = [ 'id' => $seminar_id, - 'cycle_id' => $cycle->getMetaDateId(), + 'cycle_id' => $cycle->id, 'color' => false ]; diff --git a/app/controllers/course/admission.php b/app/controllers/course/admission.php index 14a9b20..0b3755a 100644 --- a/app/controllers/course/admission.php +++ b/app/controllers/course/admission.php @@ -138,14 +138,18 @@ class Course_AdmissionController extends AuthenticatedController if (Request::submittedSome('change_admission_prelim_no', 'change_admission_prelim_yes') || !$question) { if ($this->course->admission_prelim == 1 && $this->course->getNumParticipants() && Request::submitted('change_admission_prelim_yes')) { $num_moved = 0; - $seminar = new Seminar($this->course_id); - foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user_id') as $user_id) { - $seminar->addPreliminaryMember($user_id); - $num_moved += ($seminar->deleteMember($user_id) !== false); - setTempLanguage($user_id); + foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user') as $user) { + $this->course->addPreliminaryMember($user); + try { + $this->course->deleteMember($user); + } catch (\Studip\Exception $e) { + continue; + } + $num_moved++; + setTempLanguage($user->id); $message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **vorläufig akzeptiert** befördert, da das Anmeldeverfahren geändert wurde.'), $this->course->name); $message_title = sprintf(_("Statusänderung %s"), $this->course->name); - messaging::sendSystemMessage($user_id, $message_title, $message_body); + messaging::sendSystemMessage($user->id, $message_title, $message_body); restoreLanguage(); } if ($num_moved) { @@ -158,9 +162,13 @@ class Course_AdmissionController extends AuthenticatedController if ($this->course->admission_prelim == 0 && $this->course->getNumPrelimParticipants()) { if (Request::submitted('change_admission_prelim_yes')) { $num_moved = 0; - $seminar = new Seminar($this->course_id); - foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user_id') as $user_id) { - $num_moved += ($seminar->addMember($user_id, 'autor') !== false); + foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user') as $user) { + try { + $this->course->addMember($user, 'autor'); + } catch (\Studip\Exception $e) { + continue; + } + $num_moved++; setTempLanguage($user_id); $message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **Autor** versetzt, da das Anmeldeverfahren geändert wurde.'), $this->course->name); $message_title = sprintf(_("Statusänderung %s"), $this->course->name); diff --git a/app/controllers/course/archive.php b/app/controllers/course/archive.php index f181cca..1c6fc25 100644 --- a/app/controllers/course/archive.php +++ b/app/controllers/course/archive.php @@ -165,9 +165,8 @@ class Course_ArchiveController extends AuthenticatedController $course = Course::find($courseId); if ($course) { - $seminar = new Seminar($course); - $coursename = $course->getFullName(); - if ($seminar->delete()) { + $coursename = $course->getFullname(); + if ($course->delete()) { $this->deletedCourses[] = $courseId; PageLayout::postSuccess(sprintf( _('Die Veranstaltung %s wurde erfolgreich gelöscht.'), diff --git a/app/controllers/course/basicdata.php b/app/controllers/course/basicdata.php index 59130c4..eab5f36 100644 --- a/app/controllers/course/basicdata.php +++ b/app/controllers/course/basicdata.php @@ -21,17 +21,14 @@ class Course_BasicdataController extends AuthenticatedController /** * Set up the list of input fields. Some fields may be locked for - * some reasons (lock rules, insufficient permissions etc.). This + * some reason (lock rules, insufficient permissions etc.). This * method does not return anything, it just sets up $this->attributes * and $this->descriptions. * - * @param Seminar $sem + * @param Course $course */ - private function setupInputFields($sem) + protected function setupInputFields(Course $course) { - $course_id = $sem->getId(); - $data = $sem->getData(); - $this->attributes = []; $this->attributes[] = [ 'title' => _("Name der Veranstaltung"), @@ -39,16 +36,16 @@ class Course_BasicdataController extends AuthenticatedController 'must' => true, 'type' => 'text', 'i18n' => true, - 'value' => $data['name'], - 'locked' => LockRules::Check($course_id, 'Name') + 'value' => $course->name, + 'locked' => LockRules::Check($course->id, 'Name') ]; $this->attributes[] = [ - 'title' => _("Untertitel der Veranstaltung"), - 'name' => "course_subtitle", + 'title' => _('Untertitel der Veranstaltung'), + 'name' => 'course_untertitel', 'type' => 'text', 'i18n' => true, - 'value' => $data['subtitle'], - 'locked' => LockRules::Check($course_id, 'Untertitel') + 'value' => $course->untertitel, + 'locked' => LockRules::Check($course->id, 'Untertitel') ]; $changable = true; $this->attributes[] = [ @@ -56,60 +53,60 @@ class Course_BasicdataController extends AuthenticatedController 'name' => 'course_status', 'must' => true, 'type' => 'select', - 'value' => $data['status'], - 'locked' => LockRules::Check($course_id, 'status'), - 'choices' => $this->_getTypes($sem, $data, $changable), + 'value' => $course->status, + 'locked' => LockRules::Check($course->id, 'status'), + 'choices' => $this->_getTypes($course, $changable), 'changable' => $changable, ]; $this->attributes[] = [ 'title' => _("Art der Veranstaltung"), - 'name' => "course_form", + 'name' => 'course_art', 'type' => 'text', 'i18n' => true, - 'value' => $data['form'], - 'locked' => LockRules::Check($course_id, 'art') + 'value' => $course->art, + 'locked' => LockRules::Check($course->id, 'art') ]; $course_number_format_config = Config::get()->getMetadata('COURSE_NUMBER_FORMAT'); $this->attributes[] = [ - 'title' => _("Veranstaltungsnummer"), - 'name' => "course_seminar_number", + 'title' => _('Veranstaltungsnummer'), + 'name' => 'course_veranstaltungsnummer', 'type' => 'text', - 'value' => $data['seminar_number'], - 'locked' => LockRules::Check($course_id, 'VeranstaltungsNummer'), + 'value' => $course->veranstaltungsnummer, + 'locked' => LockRules::Check($course->id, 'VeranstaltungsNummer'), 'description' => $course_number_format_config['comment'], 'pattern' => Config::get()->COURSE_NUMBER_FORMAT ]; $this->attributes[] = [ - 'title' => _("ECTS-Punkte"), - 'name' => "course_ects", + 'title' => _('ECTS-Punkte'), + 'name' => 'course_ects', 'type' => 'text', - 'value' => $data['ects'], - 'locked' => LockRules::Check($course_id, 'ects') + 'value' => $course->ects, + 'locked' => LockRules::Check($course->id, 'ects') ]; $this->attributes[] = [ - 'title' => _("max. Teilnehmendenzahl"), - 'name' => "course_admission_turnout", + 'title' => _('max. Teilnehmendenzahl'), + 'name' => 'course_admission_turnout', 'must' => false, 'type' => 'number', - 'value' => $data['admission_turnout'], - 'locked' => LockRules::Check($course_id, 'admission_turnout'), + 'value' => $course->admission_turnout, + 'locked' => LockRules::Check($course->id, 'admission_turnout'), 'min' => '0' ]; $this->attributes[] = [ - 'title' => _("Beschreibung"), - 'name' => "course_description", + 'title' => _('Beschreibung'), + 'name' => 'course_beschreibung', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['description'], - 'locked' => LockRules::Check($course_id, 'Beschreibung') + 'value' => $course->beschreibung, + 'locked' => LockRules::Check($course->id, 'Beschreibung') ]; $this->institutional = []; $my_institutes = Institute::getMyInstitutes(); $institutes = Institute::getInstitutes(); foreach ($institutes as $institute) { - if ($institute['Institut_id'] === $data['institut_id']) { + if ($institute['Institut_id'] === $course->institut_id) { $found = false; foreach ($my_institutes as $inst) { if ($inst['Institut_id'] === $institute['Institut_id']) { @@ -128,54 +125,54 @@ class Course_BasicdataController extends AuthenticatedController 'name' => 'course_institut_id', 'must' => true, 'type' => 'nested-select', - 'value' => $data['institut_id'], + 'value' => $course->institut_id, 'choices' => $this->instituteChoices($my_institutes), - 'locked' => LockRules::Check($course_id, 'Institut_id') + 'locked' => LockRules::Check($course->id, 'Institut_id') ]; - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); $this->institutional[] = [ 'title' => _('beteiligte Einrichtungen'), 'name' => 'related_institutes[]', 'type' => 'nested-select', - 'value' => array_diff($sem_institutes, [$sem->institut_id]), + 'value' => $institute_ids, 'choices' => $this->instituteChoices($institutes), - 'locked' => LockRules::Check($course_id, 'seminar_inst'), + 'locked' => LockRules::Check($course->id, 'seminar_inst'), 'multiple' => true, ]; $this->descriptions = []; $this->descriptions[] = [ - 'title' => _("Teilnehmende"), - 'name' => "course_participants", + 'title' => _('Teilnehmende'), + 'name' => 'course_teilnehmer', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['participants'], - 'locked' => LockRules::Check($course_id, 'teilnehmer') + 'value' => $course->teilnehmer, + 'locked' => LockRules::Check($course->id, 'teilnehmer') ]; $this->descriptions[] = [ - 'title' => _("Voraussetzungen"), - 'name' => "course_requirements", + 'title' => _('Voraussetzungen'), + 'name' => 'course_vorrausetzungen', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['vorrausetzungen'], - 'locked' => LockRules::Check($course_id, 'voraussetzungen') + 'value' => $course->vorrausetzungen, + 'locked' => LockRules::Check($course->id, 'voraussetzungen') ]; $this->descriptions[] = [ - 'title' => _("Lernorganisation"), - 'name' => "course_orga", + 'title' => _('Lernorganisation'), + 'name' => 'course_lernorga', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['orga'], - 'locked' => LockRules::Check($course_id, 'lernorga') + 'value' => $course->lernorga, + 'locked' => LockRules::Check($course->id, 'lernorga') ]; $this->descriptions[] = [ - 'title' => _("Leistungsnachweis"), - 'name' => "course_leistungsnachweis", + 'title' => _('Leistungsnachweis'), + 'name' => 'course_leistungsnachweis', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['leistungsnachweis'], - 'locked' => LockRules::Check($course_id, 'leistungsnachweis') + 'value' => $course->leistungsnachweis, + 'locked' => LockRules::Check($course->id, 'leistungsnachweis') ]; $this->descriptions[] = [ 'title' => _("Ort") . @@ -186,18 +183,18 @@ class Course_BasicdataController extends AuthenticatedController "Angaben aus Zeiten oder Sitzungsterminen gemacht werden können.") . "", 'i18n' => true, - 'name' => "course_location", + 'name' => 'course_ort', 'type' => 'textarea', - 'value' => $data['ort'], - 'locked' => LockRules::Check($course_id, 'Ort') + 'value' => $course->ort, + 'locked' => LockRules::Check($course->id, 'Ort') ]; - $datenfelder = DataFieldEntry::getDataFieldEntries($course_id, 'sem', $data["status"]); + $datenfelder = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status); if ($datenfelder) { foreach($datenfelder as $datenfeld) { if ($datenfeld->isVisible()) { $locked = !$datenfeld->isEditable() - || LockRules::Check($course_id, $datenfeld->getID()); + || LockRules::Check($course->id, $datenfeld->getID()); $desc = $locked ? _('Diese Felder werden zentral durch die zuständigen Administratoren erfasst.') : $datenfeld->getDescription(); $this->descriptions[] = [ 'title' => $datenfeld->getName(), @@ -215,11 +212,11 @@ class Course_BasicdataController extends AuthenticatedController } } $this->descriptions[] = [ - 'title' => _("Sonstiges"), - 'name' => "course_misc", + 'title' => _('Sonstiges'), + 'name' => 'course_sonstiges', 'type' => 'textarea', - 'value' => $data['misc'], - 'locked' => LockRules::Check($course_id, 'Sonstiges') + 'value' => $course->sonstiges, + 'locked' => LockRules::Check($course->id, 'Sonstiges') ]; } @@ -291,22 +288,21 @@ class Course_BasicdataController extends AuthenticatedController //Daten sammeln: $course = Course::find($this->course_id); - $sem = new Seminar($course); - $data = $sem->getData(); + $data = $course->toRawArray(); //Erster, zweiter und vierter Reiter des Akkordions: Grundeinstellungen - $this->setupInputFields($sem); + $this->setupInputFields($course); - $sem_institutes = $sem->getInstitutes(); + $sem_institutes = $course->institutes->pluck('id'); $this->dozent_is_locked = LockRules::Check($this->course_id, 'dozent'); $this->tutor_is_locked = LockRules::Check($this->course_id, 'tutor'); //Dritter Reiter: Personal - $this->dozenten = $sem->getMembers('dozent'); - $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'dozent')); + $this->dozenten = $course->getMembersWithStatus('dozent'); + $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'dozent')); $this->lecturersOfInstitute = $instUsers->pluck('user_id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = "user_inst_not_already_in_sem"; } else { $search_template = "user_not_already_in_sem"; @@ -314,7 +310,7 @@ class Course_BasicdataController extends AuthenticatedController $this->dozentUserSearch = new PermissionSearch( $search_template, - sprintf(_("%s suchen"), get_title_for_status('dozent', 1, $sem->status)), + sprintf(_('%s suchen'), get_title_for_status('dozent', 1, $course->status)), "user_id", [ 'permission' => 'dozent', @@ -323,25 +319,25 @@ class Course_BasicdataController extends AuthenticatedController 'institute' => $sem_institutes ] ); - $this->dozenten_title = get_title_for_status('dozent', 1, $sem->status); + $this->dozenten_title = get_title_for_status('dozent', 1, $course->status); $this->deputies_enabled = $deputies_enabled; if ($this->deputies_enabled) { $this->deputies = Deputy::findDeputies($this->course_id); $this->deputySearch = new PermissionSearch( "user_not_already_in_sem_or_deputy", - sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $sem->status)), + sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $course->status)), "user_id", ['permission' => Deputy::getValidPerms(), 'seminar_id' => $this->course_id] ); - $this->deputy_title = get_title_for_status('deputy', 1, $sem->status); + $this->deputy_title = get_title_for_status('deputy', 1, $course->status); } - $this->tutoren = $sem->getMembers('tutor'); + $this->tutoren = $course->getMembersWithStatus('tutor'); $this->tutorUserSearch = new PermissionSearch( $search_template, - sprintf(_("%s suchen"), get_title_for_status('tutor', 1, $sem->status)), + sprintf(_('%s suchen'), get_title_for_status('tutor', 1, $course->status)), "user_id", ['permission' => ['dozent','tutor'], 'seminar_id' => $this->course_id, @@ -349,8 +345,8 @@ class Course_BasicdataController extends AuthenticatedController 'institute' => $sem_institutes ] ); - $this->tutor_title = get_title_for_status('tutor', 1, $sem->status); - $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'tutor')); + $this->tutor_title = get_title_for_status('tutor', 1, $course->status); + $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'tutor')); $this->tutorsOfInstitute = $instUsers->pluck('user_id'); unset($instUsers); @@ -464,15 +460,19 @@ class Course_BasicdataController extends AuthenticatedController CSRFProtection::verifyUnsafeRequest(); $course_number_format = Config::get()->COURSE_NUMBER_FORMAT; - $sem = Seminar::getInstance($course_id); - $this->msg = []; - $old_settings = $sem->getSettings(); + $course = Course::find($course_id); + $this->msg = [ + 'success' => '', + 'errors' => [] + ]; + $old_settings = $course->toRawArray(); + unset($old_settings['config']); //Seminar-Daten: - if ($perm->have_studip_perm("tutor", $sem->getId())) { - $this->setupInputFields($sem); + if ($perm->have_studip_perm('tutor', $course_id)) { + $this->setupInputFields($course); $changemade = false; $invalid_datafields = []; - $all_fields_types = DataFieldEntry::getDataFieldEntries($sem->id, 'sem', $sem->status); + $all_fields_types = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status); $datafield_values = Request::getArray('datafields'); foreach (array_merge($this->attributes, $this->institutional, $this->descriptions) as $field) { @@ -490,8 +490,17 @@ class Course_BasicdataController extends AuthenticatedController } } else if ($field['name'] == 'related_institutes[]') { // only related_institutes supported for now - if ($sem->setInstitutes(Request::optionArray('related_institutes'))) { - $changemade = true; + $related_institute_ids = Request::optionArray('related_institutes'); + if (is_array($related_institute_ids)) { + $institutes = Institute::findMany($related_institute_ids); + if ($institutes) { + $course->institutes = $institutes; + $changemade = $course->store(); + } else { + $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); + } + } else { + $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); } } else { // format of input element name is "course_xxx" @@ -503,14 +512,14 @@ class Course_BasicdataController extends AuthenticatedController } if ($varname === "name" && !$req_value) { - $this->msg[] = ["error", _("Name der Veranstaltung darf nicht leer sein.")]; + $this->msg['error'][] = _('Name der Veranstaltung darf nicht leer sein.'); } elseif ($varname === "seminar_number" && $req_value && $course_number_format && !preg_match('/^' . $course_number_format . '$/', $req_value)) { - $this->msg[] = ['error', _('Die Veranstaltungsnummer hat ein ungültiges Format.')]; + $this->msg['error'][] = _('Die Veranstaltungsnummer hat ein ungültiges Format.'); } else if ($field['type'] == 'select' && !in_array($req_value, array_flatten(array_values(array_map('array_keys', $field['choices']))))) { // illegal value - just ignore this - } else if ($sem->{$varname} != $req_value) { - $sem->{$varname} = $req_value; + } else if ($course->getValue($varname) != $req_value) { + $course->setValue($varname, $req_value); $changemade = true; } } @@ -524,23 +533,25 @@ class Course_BasicdataController extends AuthenticatedController count($invalid_datafields) ); $message = sprintf($message, join(', ', array_map('htmlReady', $invalid_datafields))); - $this->msg[] = ['error', $message]; + $this->msg['error'][] = $message; } - $sem->store(); + $course->store(); // Logging - $before = array_diff_assoc($old_settings, $sem->getSettings()); - $after = array_diff_assoc($sem->getSettings(), $old_settings); + $current_settings = $course->toRawArray(); + unset($current_settings['config']); + $before = array_diff_assoc($old_settings, $current_settings); + $after = array_diff_assoc($current_settings, $old_settings); //update admission, if turnout was raised if ( !empty($after['admission_turnout']) && !empty($before['admission_turnout']) && $after['admission_turnout'] > $before['admission_turnout'] - && $sem->isAdmissionEnabled() + && $course->isAdmissionEnabled() ) { - AdmissionApplication::addMembers($sem->getId()); + AdmissionApplication::addMembers($course_id); } if (sizeof($before) && sizeof($after)) { @@ -548,30 +559,30 @@ class Course_BasicdataController extends AuthenticatedController foreach ($before as $k => $v) { $log_message .= "$k: $v => " . $after[$k] . " \n"; } - StudipLog::log('CHANGE_BASIC_DATA', $sem->getId(), " ", $log_message); - NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $sem->id , $GLOBALS['user']->id); + StudipLog::log('CHANGE_BASIC_DATA', $course_id, ' ', $log_message); + NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $course->id , $GLOBALS['user']->id); } // end of logging if ($changemade) { - $this->msg[] = ["msg", _("Die Grunddaten der Veranstaltung wurden verändert.")]; + $this->msg['success'] = _('Die Grunddaten der Veranstaltung wurden verändert.'); } } else { - $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; + $this->msg['error'][] = _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.'); } //Labels/Funktionen für Dozenten und Tutoren - if ($perm->have_studip_perm('dozent', $sem->getId())) { + if ($perm->have_studip_perm('dozent', $course_id)) { foreach (Request::getArray('label') as $user_id => $label) { - if ($GLOBALS['perm']->have_studip_perm('tutor', $sem->getId(), $user_id)) { - $mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $sem->getId()]); + if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id, $user_id)) { + $mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $course_id]); if ($mb) { $mb->label = $label; if ($mb->store()) { NotificationCenter::postNotification( 'CourseDidChangeMemberLabel', - $sem, + $course, $mb ); } @@ -580,21 +591,23 @@ class Course_BasicdataController extends AuthenticatedController } } - foreach($sem->getStackedMessages() as $key => $messages) { - foreach($messages['details'] as $message) { - $this->msg[] = [($key !== "success" ? $key : "msg"), $message]; - } + if (!empty($this->msg['error'])) { + PageLayout::postError( + _('Die folgenden Fehler traten auf:'), + $this->msg['error'] + ); + } elseif ($this->msg['success']) { + PageLayout::postSuccess($this->msg['success']); } - $this->flash['msg'] = $this->msg; + $this->flash['open'] = Request::get("open"); if (Request::isDialog()) { $this->response->add_header('X-Dialog-Close', 1); $this->response->add_header('X-Dialog-Execute', 'STUDIP.AdminCourses.App.loadCourse'); $this->render_text($course_id); } else { - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course_id)); } - } public function add_member_action($course_id, $status = 'dozent') @@ -627,8 +640,8 @@ class Course_BasicdataController extends AuthenticatedController } // Only show the success messagebox once if ($succeeded) { - $sem = Seminar::GetInstance($course_id); - $status_title = get_title_for_status($status, count($succeeded), $sem->status); + $course = Course::find($course_id); + $status_title = get_title_for_status($status, count($succeeded), $course->status); if (count($succeeded) > 1) { $messagetext = sprintf( _("%u %s wurden hinzugefügt."), @@ -661,72 +674,28 @@ class Course_BasicdataController extends AuthenticatedController $this->redirect($this->url_for($redirect)); } - private function addTutor($tutor, $course_id) - { - //Tutoren hinzufügen: - if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) { - $sem = Seminar::GetInstance($course_id); - if ($sem->addMember($tutor, 'tutor')) { - // Check if we need to add user to course parent as well. - if ($sem->parent_course) { - $this->addTutor($tutor, $sem->parent_course); - } - - return true; - } - } - return false; - } - - private function addDeputy($user_id, $course_id) - { - //Vertretung hinzufügen: - if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { - $sem = Seminar::GetInstance($course_id); - if (Deputy::addDeputy($user_id, $sem->getId())) { - return true; - } - } - return false; - } - - private function addTeacher($dozent, $course_id) + /** + * A helper method since the steps for removing someone are all the same in this controller. + * Only the actions differ. + * + * @param Course $course The course from which to remove a user. + * @param User $user The user to be removed. + * @return void + */ + protected function deleteUserFromCourse(Course $course, User $user) { - $deputies_enabled = Config::get()->DEPUTIES_ENABLE; - $sem = Seminar::GetInstance($course_id); - if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { - if ($sem->addMember($dozent, 'dozent')) { - // Check if we need to add user to course parent as well. - if ($sem->parent_course) { - $this->addTeacher($dozent, $sem->parent_course); - } - - // Only applicable when globally enabled and user deputies enabled too - if ($deputies_enabled) { - // Check whether chosen person is set as deputy - // -> delete deputy entry. - $deputy = Deputy::find([$course_id, $dozent]); - if ($deputy) { - $deputy->delete(); - } - - // Add default deputies of the chosen lecturer... - if (Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - $deputies = Deputy::findDeputies($dozent)->pluck('user_id'); - $lecturers = $sem->getMembers(); - foreach ($deputies as $deputy) { - // ..but only if not already set as lecturer or deputy. - if (!isset($lecturers[$deputy])) { - Deputy::addDeputy($deputy, $course_id); - } - } - } - } - - return true; - } - } - return false; + try { + $course->deleteMember($user); + } catch (\Studip\Exception $e) { + PageLayout::postError(_('Ein Fehler ist aufgetreten.'), $e->getMessage()); + return; + } + PageLayout::postSuccess( + studip_interpolate( + _('%{name} wurde aus der Veranstaltung ausgetragen.'), + ['name' => $user->getFullName()] + ) + ); } /** @@ -745,24 +714,10 @@ class Course_BasicdataController extends AuthenticatedController } elseif ($teacher_id === $GLOBALS['user']->id) { PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.')); } else { - $sem = Seminar::getInstance($course_id); - $sem->deleteMember($teacher_id); - - // Remove user from subcourses as well. - foreach ($sem->children as $child) { - $child->deleteMember($teacher_id); - } - - $this->msg = []; - foreach ($sem->getStackedMessages() as $key => $messages) { - foreach ($messages['details'] as $message) { - $this->msg[] = [ - $key !== 'success' ? $key : 'msg', - $message - ]; - } - } - $this->flash['msg'] = $this->msg; + $this->deleteUserFromCourse( + Course::find($course_id), + User::find($teacher_id) + ); } $this->flash['open'] = 'bd_personal'; @@ -785,23 +740,23 @@ class Course_BasicdataController extends AuthenticatedController } elseif ($deputy_id === $GLOBALS['user']->id) { PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.')); } else { - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); $deputy = Deputy::find([$course_id, $deputy_id]); if ($deputy && $deputy->delete()) { // Remove user from subcourses as well. - if (count($sem->children)) { - $children_ids = $sem->children->pluck('seminar_id'); + if (count($course->children) > 0) { + $children_ids = $course->children->pluck('seminar_id'); Deputy::deleteBySQL('user_id = ? AND range_id IN (?)', [$deputy_id, $children_ids]); } PageLayout::postSuccess(sprintf( _('%s wurde entfernt.'), - htmlReady(get_title_for_status('deputy', 1, $sem->status)) + htmlReady(get_title_for_status('deputy', 1, $course->status)) )); } else { PageLayout::postError(sprintf( _('%s konnte nicht entfernt werden.'), - htmlReady(get_title_for_status('deputy', 1, $sem->status)) + htmlReady(get_title_for_status('deputy', 1, $course->status)) )); } } @@ -824,24 +779,10 @@ class Course_BasicdataController extends AuthenticatedController if (!$GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { PageLayout::postError( _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.')); } else { - $sem = Seminar::getInstance($course_id); - - $sem->deleteMember($tutor_id); - // Remove user from subcourses as well. - foreach ($sem->children as $child) { - $child->deleteMember($tutor_id); - } - - $this->msg = []; - foreach ($sem->getStackedMessages() as $key => $messages) { - foreach ($messages['details'] as $message) { - $this->msg[] = [ - $key !== 'success' ? $key : 'msg', - $message - ]; - } - } - $this->flash['msg'] = $this->msg; + $this->deleteUserFromCourse( + Course::find($course_id), + User::find($teacher_id) + ); } $this->flash['open'] = 'bd_personal'; @@ -849,77 +790,63 @@ class Course_BasicdataController extends AuthenticatedController } /** - * Falls eine Person in der >>Reihenfolge<< hochgestuft werden soll. - * Leitet danach weiter auf View und öffnet den Reiter Personal. + * Moves a course member up one position in the position list for the + * corresponding permission level in the course. + * + * @param string $course_id The course where to increase the priority. + * + * @param string $user_id The user for whom to increase the priority. * - * @param md5 $user_id - * @param string $status + * @param string $status The permission level. This is an unused parameter that is only kept + * for compatibility reasons. */ - public function priorityupfor_action($course_id, $user_id, $status = "dozent") + public function priorityupfor_action(string $course_id, string $user_id, string $status = 'dozent') { - global $perm; - CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); + $user = User::find($user_id); $this->msg = []; - if ($perm->have_studip_perm("dozent", $sem->getId())) { - $teilnehmer = $sem->getMembers($status); - $members = []; - foreach($teilnehmer as $key => $member) { - $members[] = $member["user_id"]; - } - foreach($members as $key => $member) { - if ($key > 0 && $member == $user_id) { - $temp_member = $members[$key-1]; - $members[$key-1] = $member; - $members[$key] = $temp_member; - } + if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) { + if ($course->moveMemberUp($user) < 0) { + $this->msg[] = ['error', _('Die Person konnte nicht nach oben verschoben werden.')]; } - $sem->setMemberPriority($members); } else { $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; } $this->flash['msg'] = $this->msg; $this->flash['open'] = "bd_personal"; - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course->id)); } /** - * Falls eine Person in der >>Reihenfolge<< runtergestuft werden soll. - * Leitet danach weiter auf View und öffnet den Reiter Personal. + * Moves a course member down one position in the position list for the + * corresponding permission level in the course. + * + * @param string $course_id The course where to decrease the priority. + * + * @param string $user_id The user for whom to decrease the priority. * - * @param md5 $user_id - * @param string $status + * @param string $status The permission level. This is an unused parameter that is only kept + * for compatibility reasons. */ - public function prioritydownfor_action($course_id, $user_id, $status = "dozent") + public function prioritydownfor_action($course_id, $user_id, $status = 'dozent') { - global $perm; - CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); + $user = User::find($user_id); $this->msg = []; - if ($perm->have_studip_perm("dozent", $sem->getId())) { - $teilnehmer = $sem->getMembers($status); - $members = []; - foreach($teilnehmer as $key => $member) { - $members[] = $member["user_id"]; + if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) { + if ($course->moveMemberDown($user) < 0) { + $this->msg[] = ['error', _('Die Person konnte nicht nach unten verschoben werden.')]; } - foreach($members as $key => $member) { - if ($key < count($members)-1 && $member == $user_id) { - $temp_member = $members[$key+1]; - $members[$key+1] = $member; - $members[$key] = $temp_member; - } - } - $sem->setMemberPriority($members); } else { - $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; + $this->msg[] = ['error', _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.')]; } $this->flash['msg'] = $this->msg; $this->flash['open'] = "bd_personal"; - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course->id)); } public function switchdeputy_action($course_id, $newstatus) @@ -959,7 +886,7 @@ class Course_BasicdataController extends AuthenticatedController $this->redirect($this->url_for('course/basicdata/view/'.$course_id)); } - private function _getTypes($sem, $data, &$changable = true) + private function _getTypes(Course $course, &$changable = true) { $sem_types = []; @@ -971,10 +898,10 @@ class Course_BasicdataController extends AuthenticatedController } } } else { - $sem_classes[] = $sem->getSemClass(); + $sem_classes[] = $course->getSemClass(); } - if (!$sem->isStudyGroup()) { + if (!$course->isStudyGroup()) { $sem_classes = array_filter($sem_classes, function (SemClass $sc) { return !$sc['studygroup_mode']; }); @@ -985,13 +912,12 @@ class Course_BasicdataController extends AuthenticatedController return $st['name']; }, $sc->getSemTypes()); } - - if (!in_array($data['status'], array_flatten(array_values(array_map('array_keys', $sem_types))))) { - $class_name = $sem->getSemClass()->offsetGet('name'); + if (!in_array($course->status, array_flatten(array_values(array_map('array_keys', $sem_types))))) { + $class_name = $course->getSemClass()->offsetGet('name'); if (!isset($sem_types[$class_name])) { $sem_types[$class_name] = []; } - $sem_types[$class_name][] = $sem->getSemType()->offsetGet('name'); + $sem_types[$class_name][] = $course->getSemType()->offsetGet('name'); $changable = false; } diff --git a/app/controllers/course/block_appointments.php b/app/controllers/course/block_appointments.php index ad28b1e..1628e94 100644 --- a/app/controllers/course/block_appointments.php +++ b/app/controllers/course/block_appointments.php @@ -242,8 +242,8 @@ class Course_BlockAppointmentsController extends AuthenticatedController $result = $d->store(); } else { $result = $d->store(); - $singledate = new SingleDate($d); - $singledate->bookRoom(Request::option('room_id')); + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + $d->bookRoom($room); } return $result ? $d->getFullName() : null; }, $dates)); diff --git a/app/controllers/course/cancel_dates.php b/app/controllers/course/cancel_dates.php index 8da0d09..692c170 100644 --- a/app/controllers/course/cancel_dates.php +++ b/app/controllers/course/cancel_dates.php @@ -25,17 +25,17 @@ class Course_CancelDatesController extends AuthenticatedController parent::before_filter($action, $args); if (Request::get('termin_id')) { - $this->dates[0] = new SingleDate(Request::option('termin_id')); + $this->dates[0] = CourseDate::find(Request::option('termin_id')); $this->course_id = $this->dates[0]->range_id; } if (Request::get('issue_id')) { $this->issue_id = Request::option('issue_id'); - $this->dates = array_values(array_map(function ($data) { - $d = new SingleDate(); - $d->fillValuesFromArray($data); - return $d; - }, IssueDB::getDatesforIssue(Request::option('issue_id')))); + $this->dates = CourseDate::findBySQL( + "JOIN `themen_termine` USING (`termin_id`) + WHERE `issue_id` = :issue_id ORDER BY `date`", + ['issue_id' => Request::option('issue_id')] + ); $this->course_id = $this->dates[0]->range_id; } if (!get_object_type($this->course_id, ['sem']) || !$perm->have_studip_perm("tutor", $this->course_id)) { @@ -52,13 +52,13 @@ class Course_CancelDatesController extends AuthenticatedController public function store_action() { CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($this->course_id); $msg = ''; foreach ($this->dates as $date) { - $sem->cancelSingleDate($date->getTerminId(), $date->getMetadateId()); - $date->setComment(Request::get('cancel_dates_comment')); - $date->setExTermin(true); - $date->store(); + $ex_date = $date->cancelDate(); + if ($ex_date) { + $ex_date->content = Request::get('cancel_dates_comment'); + $ex_date->store(); + } } if (Request::int('cancel_dates_snd_message') && count($this->dates) > 0) { $snd_messages = raumzeit_send_cancel_message(Request::get('cancel_dates_comment'), $this->dates); @@ -67,7 +67,7 @@ class Course_CancelDatesController extends AuthenticatedController } } PageLayout::postSuccess(_('Folgende Termine wurden abgesagt') . ($msg ? ' (' . $msg . '):' : ':'), array_map(function ($d) { - return $d->toString(); + return $d->getFullName(); }, $this->dates)); $this->redirect($this->url_for('course/dates')); diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php index f64d66b..bd88932 100644 --- a/app/controllers/course/dates.php +++ b/app/controllers/course/dates.php @@ -1,5 +1,4 @@ asDialog(); } - if ( - Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') - && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent() ? User::findCurrent()->id : null) + Course::exists(Context::getId()) + && $this->course->isToolActive(CoreDocuments::class) + && CourseDateFolder::availableInRange($this->course, User::findCurrent()->id) ) { $actions->addLink( _('Sitzungsordner anlegen'), @@ -367,45 +366,42 @@ class Course_DatesController extends AuthenticatedController public function export_action() { - $sem = new Seminar($this->course); - $themen =& $sem->getIssues(); + $themen = CourseTopic::findBySeminar_id($this->course->id); - $termine = getAllSortedSingleDates($sem); + $termine = $this->course->getAllDatesInSemester()->getSingleDates(true, true, true); $dates = []; - if (is_array($termine) && sizeof($termine) > 0) { - foreach ($termine as $singledate_id => $singledate) { - if (!$singledate->isExTermin()) { - $tmp_ids = $singledate->getIssueIDs(); - $title = $description = ''; - if (is_array($tmp_ids)) { - $title = trim(join("\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getTitle();}, $tmp_ids))); - $description = trim(join("\n\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getDescription();}, $tmp_ids))); - } - - $dates[] = [ - 'date' => $singledate->toString(), - 'title' => $title, - 'description' => $description, - 'start' => $singledate->getStartTime(), - 'related_persons' => $singledate->getRelatedPersons(), - 'groups' => $singledate->getRelatedGroups(), - 'room' => $singledate->getRoom() ?: $singledate->raum, - 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] - ]; - } elseif ($singledate->getComment()) { - $dates[] = [ - 'date' => $singledate->toString(), - 'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->getComment() . ')', - 'description' => '', - 'start' => $singledate->getStartTime(), - 'related_persons' => [], - 'groups' => [], - 'room' => '', - 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] - ]; + foreach ($termine as $singledate) { + if ($singledate instanceof CourseDate) { + $tmp_ids = $singledate->getIssueIDs(); + $title = $description = ''; + if (is_array($tmp_ids)) { + $title = trim(join("\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getTitle();}, $tmp_ids))); + $description = trim(join("\n\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getDescription();}, $tmp_ids))); } + + $dates[] = [ + 'date' => $singledate->toString(), + 'title' => $title, + 'description' => $description, + 'start' => $singledate->getStartTime(), + 'related_persons' => $singledate->getRelatedPersons(), + 'groups' => $singledate->getRelatedGroups(), + 'room' => $singledate->getRoom() ?: $singledate->raum, + 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] + ]; + } elseif ($singledate->getComment()) { + $dates[] = [ + 'date' => $singledate->toString(), + 'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->getComment() . ')', + 'description' => '', + 'start' => $singledate->getStartTime(), + 'related_persons' => [], + 'groups' => [], + 'room' => '', + 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] + ]; } } @@ -434,9 +430,12 @@ class Course_DatesController extends AuthenticatedController */ public function export_csv_action() { - $sem = new Seminar($this->course); - $dates = getAllSortedSingleDates($sem); - $issues = $sem->getIssues(); + $dates = $this->course->getAllDatesInSemester(true, true, true); + $raw_issues = CourseTopic::findBySeminar_id($this->course->id); + $issues = []; + foreach ($raw_issues as $issue) { + $issues[$issue->id] = $issue; + } $columns = [ _('Wochentag'), @@ -523,7 +522,7 @@ class Course_DatesController extends AuthenticatedController $data[] = $row; } - $filename = $sem->name . '-' . _('Ablaufplan') . '.csv'; + $filename = $this->course->name . '-' . _('Ablaufplan') . '.csv'; $this->render_csv($data, $filename); } diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php index e1c9493..10f3f57 100644 --- a/app/controllers/course/details.php +++ b/app/controllers/course/details.php @@ -70,7 +70,6 @@ class Course_DetailsController extends AuthenticatedController $this->prelim_discussion = vorbesprechung($this->course->id); $this->title = $this->course->getFullName(); $this->course_domains = UserDomain::getUserDomainsForSeminar($this->course->id); - $this->sem = new Seminar($this->course); $this->links = []; //public folders @@ -203,11 +202,12 @@ class Course_DetailsController extends AuthenticatedController $sidebar = Sidebar::Get(); + $enrolment_info = null; + if ($GLOBALS['SessionSeminar'] === $this->course->id) { Navigation::activateItem('/course/main/details'); } else { - $sidebarlink = true; - $enrolment_info = $this->sem->getEnrolmentInfo($GLOBALS['user']->id); + $enrolment_info = $this->course->getEnrolmentInformation($GLOBALS['user']->id); } $links = new ActionsWidget(); @@ -217,12 +217,12 @@ class Course_DetailsController extends AuthenticatedController Icon::create('print'), ['class' => 'print_action', 'target' => '_blank'] ); - if (isset($enrolment_info) && $enrolment_info['enrolment_allowed'] && $sidebarlink) { - if (in_array($enrolment_info['cause'], ['member', 'root', 'courseadmin'])) { - $abo_msg = _('direkt zur Veranstaltung'); + if ($enrolment_info && $enrolment_info->isEnrolmentAllowed()) { + if (in_array($enrolment_info->getCodeword(), ['already_member', 'root', 'course_admin'])) { + $abo_msg = _('Direkt zur Veranstaltung'); } else { $abo_msg = _('Zugang zur Veranstaltung'); - if ($this->sem->admission_binding) { + if ($this->course->admission_binding) { PageLayout::postInfo(_('Die Anmeldung ist verbindlich, Teilnehmende können sich nicht selbst austragen.')); } } @@ -244,7 +244,7 @@ class Course_DetailsController extends AuthenticatedController if (Config::get()->SCHEDULE_ENABLE && !$GLOBALS['perm']->have_studip_perm('user', $this->course->id) && !$GLOBALS['perm']->have_perm('admin') - && $this->sem->getMetaDateCount() + && count($this->course->cycles) ) { $query = "SELECT 1 FROM `schedule_seminare` @@ -303,8 +303,8 @@ class Course_DetailsController extends AuthenticatedController ); $sidebar->addWidget($share); - if (isset($enrolment_info) && $enrolment_info['description']) { - PageLayout::postInfo($enrolment_info['description']); + if ($enrolment_info) { + PageLayout::postMessage($enrolment_info->toMessageBox()); } } } diff --git a/app/controllers/course/enrolment.php b/app/controllers/course/enrolment.php index 420b5ca..8724ff2 100644 --- a/app/controllers/course/enrolment.php +++ b/app/controllers/course/enrolment.php @@ -39,12 +39,15 @@ class Course_EnrolmentController extends AuthenticatedController if (!get_object_type($this->course_id, ['sem'])) { throw new Trails\Exception(400); } - $course = Seminar::GetInstance($this->course_id); - $enrolment_info = $course->getEnrolmentInfo($GLOBALS['user']->id); + $course = Course::find($this->course_id); + $enrolment_info = $course->getEnrolmentInformation($GLOBALS['user']->id); //Ist bereits Teilnehmer/Admin/freier Zugriff -> gleich weiter - if ($enrolment_info['enrolment_allowed'] && - (in_array($enrolment_info['cause'], words('root courseadmin member')) - || ($enrolment_info['cause'] == 'free_access' && $GLOBALS['user']->id == 'nobody')) + if ( + $enrolment_info->isEnrolmentAllowed() + && ( + in_array($enrolment_info->getCodeword(), ['root', 'course_admin', 'already_member']) + || ($enrolment_info->getCodeword() === 'free_access' && !User::findCurrent()) + ) ) { $redirect_url = URLHelper::getUrl('seminar_main.php', ['auswahl' => $this->course_id]); if (Request::isXhr()) { @@ -56,10 +59,10 @@ class Course_EnrolmentController extends AuthenticatedController return false; } //Grundsätzlich verboten - if (!$enrolment_info['enrolment_allowed']) { - throw new AccessDeniedException($enrolment_info['description']); + if (!$enrolment_info->isEnrolmentAllowed()) { + throw new AccessDeniedException($enrolment_info->getMessage()); } - PageLayout::setTitle($course->getFullName() . " - " . _("Veranstaltungsanmeldung")); + PageLayout::setTitle($course->getFullName() . ' - ' . _('Veranstaltungsanmeldung')); if (Request::submitted('cancel')) { $this->redirect(URLHelper::getURL('dispatch.php/course/details/', ['sem_id' => $this->course_id])); } @@ -109,13 +112,14 @@ class Course_EnrolmentController extends AuthenticatedController } if (StudipLock::get('enrolment' . $this->course_id)) { $course = Course::find($this->course_id); + $user = User::find($user_id); if ($course->getFreeSeats() && !$course->getNumWaiting()) { $enrol_user = true; - } elseif ($course->isWaitlistAvailable()) { - $seminar = new Seminar($course); - if ($maxpos = $seminar->addToWaitlist($user_id, 'last')) { - $msg = _("Diese Veranstaltung ist teilnahmebeschränkt."); - $msg_details[] = sprintf(_("Alle Plätze sind belegt, Sie wurden daher auf Platz %s der Warteliste gesetzt."), $maxpos); + } elseif ($user && $course->isWaitlistAvailable()) { + $application = $course->addMemberToWaitlist($user, 'last'); + if ($application) { + $msg = _('Diese Veranstaltung ist teilnahmebeschränkt.'); + $msg_details[] = sprintf(_('Alle Plätze sind belegt, Sie wurden daher auf Platz %s der Warteliste gesetzt.'), $application->position); } } elseif ($course->admission_disable_waitlist) { $this->admission_error = MessageBox::error(_("Die Anmeldung war nicht erfolgreich. Alle Plätze sind belegt und es steht keine Warteliste zur Verfügung.")); @@ -176,55 +180,62 @@ class Course_EnrolmentController extends AuthenticatedController } if ($enrol_user && $this->confirmed) { - $course = Seminar::GetInstance($this->course_id); + $course = Course::find($this->course_id); if ($course->admission_prelim) { if (Request::get('admission_comment')) { $admission_comment = get_fullname() . ': ' . Request::get('admission_comment'); } else { $admission_comment = ''; } - if ($course->addPreliminaryMember($user_id, $admission_comment)) { - if ($course->isStudygroup()) { - if (StudygroupModel::isInvited($user_id, $this->course_id)) { - // an invitation exists, so accept the join request automatically - $status = 'autor'; - StudygroupModel::accept_user(get_username($user_id), $this->course_id); - StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); - $success = sprintf( - _("Sie wurden in die Veranstaltung %s als %s eingetragen."), - htmlReady($course->getName()), - htmlReady(get_title_for_status($status, 1, $course->status)) - ); - PageLayout::postSuccess($success); - } else { - $success = sprintf( - _("Sie wurden auf die Anmeldeliste der Studiengruppe %s eingetragen. Die Moderatoren der Studiengruppe können Sie jetzt freischalten."), - htmlReady($course->getName()) - ); - PageLayout::postSuccess($success); - } + try { + $course->addPreliminaryMember($user_id, $admission_comment); + } catch (Exception $e) { + PageLayout::postError($e->getMessage()); + return; + } + if ($course->isStudygroup()) { + if (StudygroupModel::isInvited($user_id, $this->course_id)) { + // an invitation exists, so accept the join request automatically + $status = 'autor'; + StudygroupModel::accept_user(get_username($user_id), $this->course_id); + StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); + $success = sprintf( + _('Sie wurden in die Veranstaltung %1$s als %2$s eingetragen.'), + htmlReady($course->getFullName()), + htmlReady(get_title_for_status($status, 1, $course->status)) + ); + PageLayout::postSuccess($success); } else { $success = sprintf( - _("Sie wurden in die Veranstaltung %s vorläufig eingetragen."), - htmlReady($course->getName()) + _('Sie wurden auf die Anmeldeliste der Studiengruppe %s eingetragen. Die Personen, die die Studiengruppe moderieren, können Sie jetzt freischalten.'), + htmlReady($course->name) ); PageLayout::postSuccess($success); } - } - } else { - $status = 'autor'; - if ($course->addMember($user_id, $status)) { + } else { $success = sprintf( - _("Sie wurden in die Veranstaltung %s als %s eingetragen."), - htmlReady($course->getName()), - htmlReady(get_title_for_status($status, 1, $course->status)) + _('Sie wurden in die Veranstaltung %s vorläufig eingetragen.'), + htmlReady($course->getFullName()) ); PageLayout::postSuccess($success); + } + } else { + $status = 'autor'; + try { + $course->addMember($user_id, $status); + } catch (Exception $e) { + PageLayout::postError($e->getMessage()); + } + $success = sprintf( + _('Sie wurden in die Veranstaltung %1$s als %2$s eingetragen.'), + htmlReady($course->getFullName()), + htmlReady(get_title_for_status($status, 1, $course->status)) + ); + PageLayout::postSuccess($success); - if (StudygroupModel::isInvited($user_id, $this->course_id)) { - // delete an existing invitation - StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); - } + if (StudygroupModel::isInvited($user_id, $this->course_id)) { + // delete an existing invitation + StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); } } unset($this->courseset_message); diff --git a/app/controllers/course/grouping.php b/app/controllers/course/grouping.php index 588872b..aec9264 100644 --- a/app/controllers/course/grouping.php +++ b/app/controllers/course/grouping.php @@ -302,15 +302,16 @@ class Course_GroupingController extends AuthenticatedController { CSRFProtection::verifyUnsafeRequest(); - $source = Seminar::getInstance($source_id); - $target = Seminar::getInstance(Request::option('target')); + $source = Course::find($source_id); + $target = Course::find(Request::option('target')); $success = 0; $fail = 0; - foreach (Request::getArray('users') as $user) { - $m = CourseMember::find([$source_id, $user]); + foreach (Request::getArray('users') as $user_id) { + $m = CourseMember::find([$source_id, $user_id]); $status = $m->status; + $user = User::find($user_id); if ($source->deleteMember($user)) { $target->addMember($user, $status); $success += 1; @@ -336,20 +337,24 @@ class Course_GroupingController extends AuthenticatedController */ public function remove_members_action($course_id, $user_id = null) { - $s = Seminar::getInstance($course_id); + $course = Course::find($course_id); $success = 0; $fail = 0; $users = $user_id ? [$user_id] : $this->flash['users']; - foreach ($users as $user) { - if ($s->deleteMember($user)) { - $success += 1; - } else { - $fail += 1; - } - } + User::findEachMany( + function (User $user) use ($course, &$fail, &$success) { + try { + $course->deleteMember($user); + $success += 1; + } catch (\Studip\MembershipException $e) { + $fail += 1; + } + }, + $users + ); if ($success > 0) { PageLayout::postSuccess(sprintf(_('%u Personen wurden entfernt.'), $success)); @@ -511,10 +516,11 @@ class Course_GroupingController extends AuthenticatedController $fail = []; // Iterate over selected courses... foreach (Request::optionArray('courses') as $course) { - $sem = Seminar::getInstance($course); + $course_obj = Course::find($course); // ... and selected users. foreach (Request::optionArray('users') as $user) { + $user_obj = User::find($user); // Try to add deputies. if (Request::option('permission') == 'deputy') { // If not already deputy, create new entry. @@ -524,20 +530,24 @@ class Course_GroupingController extends AuthenticatedController $d->user_id = $user; // Error on storing. if (!$d->store()) { - $fail[$sem->getFullName()][] = $user; + $fail[$course_obj->getFullname()][] = $user; // Check if new deputy was regular member before, remove entry. } else { $m = CourseMember::find([$course, $user]); // Could not delete old course membership, remove deputy entry. if ($m && !$m->delete()) { $d->delete(); - $fail[$sem->getFullName()][] = $user; + $fail[$course_obj->getFullname()][] = $user; } } } // Add member with given permission. - } elseif (!$sem->addMember($user, Request::option('permission'))) { - $fail[$sem->getFullName()][] = $user; + } else { + try { + $course_obj->addMember($user_obj, Request::option('permission')); + } catch (\Studip\EnrolmentException $e) { + $fail[$course_obj->getFullname()][] = $user; + } } } } @@ -565,8 +575,9 @@ class Course_GroupingController extends AuthenticatedController */ private function sync_users($parent_id, $child_id) { - $sem = Seminar::getInstance($parent_id); - $csem = Seminar::getInstance($child_id); + $parent_course = Course::find($parent_id); + $child_course = Course::find($child_id); + /* * Find users that are in current course but not in parent. */ @@ -582,11 +593,19 @@ class Course_GroupingController extends AuthenticatedController )"; $diff = DBManager::get()->prepare($query); - /* - * Before synchronizing the lecturers, we add all institutes - * from child course. - */ - $sem->setInstitutes(array_merge($sem->getInstitutes(), $csem->getInstitutes())); + //Before synchronizing the lecturers, we add all institutes from the child course: + $parent_institute_ids = [$parent_course->institut_id]; + foreach ($parent_course->institutes as $institute) { + $parent_institute_ids[] = $institute->id; + } + + foreach ($child_course->institutes as $institute) { + if (!in_array($institute->id, $parent_institute_ids)) { + //Add the institute to the parent course: + $parent_course->institutes->append($institute); + } + } + $parent_course->store(); /* * Synchronize all members (including lecturers, tutors @@ -598,20 +617,24 @@ class Course_GroupingController extends AuthenticatedController 'status' => $permission, 'parent' => $parent_id ]); - foreach ($diff->fetchFirst() as $user) { - $sem->addMember($user, $permission); + foreach ($diff->fetchFirst() as $user_id) { + $user = User::find($user_id); + if (!$user) { + continue; + } + $parent_course->addMember($user, $permission); // Add default deputies of current user if applicable. if ($permission === 'dozent' && Config::get()->DEPUTIES_ENABLE && Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - foreach (Deputy::findByRange_id($user) as $deputy) { + foreach (Deputy::findByRange_id($user_id) as $deputy) { if (!Deputy::exists([$parent_id, $deputy->user_id]) && !CourseMember::exists([$parent_id, $deputy->user_id])) { $d = new Deputy(); $d->range_id = $parent_id; - $d->user_id = $user; + $d->user_id = $user_id; $d->store(); } } diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php index 0ab18f8..fd65077 100644 --- a/app/controllers/course/members.php +++ b/app/controllers/course/members.php @@ -97,7 +97,7 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $sem = Seminar::getInstance($this->course_id); + $course = Course::find($this->course_id); $this->sort_by = Request::option('sortby', 'nachname'); $this->order = Request::option('order', 'desc'); $this->sort_status = Request::get('sort_status', ''); @@ -154,12 +154,12 @@ class Course_MembersController extends AuthenticatedController // Check Seminar $this->waitingTitle = _('Warteliste (nicht aktiv)'); $this->waiting_type = 'awaiting'; - if ($this->is_tutor && $sem->isAdmissionEnabled()) { - $this->course = $sem; - $distribution_time = $sem->getCourseSet()->getSeatDistributionTime(); - if ($sem->getCourseSet()->hasAlgorithmRun()) { + if ($this->is_tutor && $course->isAdmissionEnabled()) { + $this->course = $course; + $distribution_time = $course->getCourseSet()->getSeatDistributionTime(); + if ($course->getCourseSet()->hasAlgorithmRun()) { $this->waitingTitle = _("Warteliste"); - if (!$sem->admission_disable_waitlist_move) { + if (!$course->admission_disable_waitlist_move) { $this->waitingTitle .= ' (' . _("automatisches Nachrücken ist eingeschaltet") . ')'; } else { $this->waitingTitle .= ' (' . _("automatisches Nachrücken ist ausgeschaltet") . ')'; @@ -185,8 +185,12 @@ class Course_MembersController extends AuthenticatedController $this->to_waitlist_actions = false; // Check for waitlist availability (influences available actions) // People can be moved to waitlist if waitlist available and no automatic moving up. - if (!$sem->admission_disable_waitlist && $sem->admission_disable_waitlist_move - && $sem->isAdmissionEnabled() && $sem->getCourseSet()->hasAlgorithmRun()) { + if ( + !$course->admission_disable_waitlist + && $course->admission_disable_waitlist_move + && $course->isAdmissionEnabled() + && $course->getCourseSet()->hasAlgorithmRun() + ) { $this->to_waitlist_actions = true; } } @@ -290,21 +294,44 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_autor" . $this->course_id); - - $countAdded = 0; - $msg = []; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addMember($a, true, Request::bool('consider_contingent', false), $msg)) { - $countAdded++; - } + $course = Course::find($this->course_id); + if (!$course) { + PageLayout::postError(_('Die ausgewählte Veranstaltung wurde nicht gefunden!')); + $this->redirect($this->indexURL()); + return; } - if ($countAdded == 1) { - $text = _('Es wurde eine neue Person hinzugefügt.'); - } else { - $text = sprintf(_('Es wurden %s neue Personen hinzugefügt.'), $countAdded); + $added_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$added_c, &$errors) { + try { + $course->addMember($user); + $added_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $mp->getAddedUsers() + ); + if ($added_c > 0) { + PageLayout::postSuccess( + sprintf( + ngettext( + 'Es wurde eine neue Person hinzugefügt.', + 'Es wurden %u neue Personen hinzugefügt.', + $added_c + ), + $added_c + ) + ); + } + if ($errors) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Eintragen von Personen auf:'), + $errors + ); } - PageLayout::postSuccess($text, $msg['success']); $this->redirect($this->indexURL()); } @@ -321,22 +348,33 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_dozent" . $this->course_id); - $sem = Seminar::GetInstance($this->course_id); - $countAdded = 0; - foreach ($mp->getAddedUsers() as $a) { - if($this->addDozent($a)) { - $countAdded++; - } - } - if($countAdded > 0) { - $status = get_title_for_status('dozent', $countAdded, $sem->status); - if ($countAdded == 1) { - PageLayout::postSuccess(sprintf(_('Ein %s wurde hinzugefügt.'), htmlReady($status))); - } else { - PageLayout::postSuccess(sprintf(_("Es wurden %s %s Personen hinzugefügt."), $countAdded, htmlReady($status))); - } + $course = Course::find($this->course_id); + $added_c = 0; + User::findEachMany( + function (User $user) use ($course, &$added_c) { + try { + $course->addMember($user, 'dozent'); + $added_c++; + } catch (\Studip\Exception $e) { + //Nothing here. + } + }, + $mp->getAddedUsers() + ); + if ($added_c > 0) { + $status = get_title_for_status('dozent', $added_c, $course->status); + PageLayout::postSuccess( + sprintf( + ngettext( + '%1$u %2$s wurde hinzugefügt.', + '%1$u %2$s wurden hinzugefügt.', + $added_c + ), + $added_c, + htmlReady($status) + ) + ); } - $this->redirect('course/members/index'); } @@ -353,62 +391,50 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load('add_waitlist' . $this->course_id); - $countAdded = 0; - $countFailed = 0; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addToWaitlist($a)) { - $countAdded++; - } else { - $countFailed++; - } - } + $course = Course::find($this->course_id); + $added_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$added_c, &$errors) { + try { + $course->addMemberTowaitlist($user); + $added_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $mp->getAddedUsers() + ); - if ($countAdded) { - PageLayout::postSuccess(sprintf(ngettext('Es wurde %u neue Person auf der Warteliste hinzugefügt.', - 'Es wurden %u neue Personen auf der Warteliste hinzugefügt.', $countAdded), $countAdded)); + if ($added_c) { + PageLayout::postSuccess( + sprintf( + ngettext( + 'Eine Person wurde zur Warteliste hinzugefügt.', + '%u Personen wurden zur Warteliste hinzugefügt.', + $added_c + ), + $added_c + ) + ); } - if ($countFailed) { - PageLayout::postError(sprintf(ngettext('%u Person konnte nicht auf die Warteliste eingetragen werden.', - '%u neue Personen konnten nicht auf die Warteliste eingetragen werden.', $countFailed), - $countFailed)); + if ($errors) { + PageLayout::postError( + sprintf( + ngettext( + 'Eine Person konnte nicht zur Warteliste hinzugefügt werden:', + '%u Personen konnten nicht zur Warteliste hinzugefügt werden:', + count($errors) + ), + count($errors) + ), + $errors + ); } $this->redirect('course/members/index'); } /** - * Helper function to add dozents to a seminar. - */ - private function addDozent($dozent) - { - $sem = Seminar::GetInstance($this->course_id); - if ($sem->addMember($dozent, "dozent")) { - // Only applicable when globally enabled and user deputies enabled too - if (Config::get()->DEPUTIES_ENABLE) { - // Check whether chosen person is set as deputy - // -> delete deputy entry. - $deputy = Deputy::find([$this->course_id, $dozent]); - if ($deputy) { - $deputy->delete(); - } - // Add default deputies of the chosen lecturer... - if (Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - $deputies = Deputy::findDeputies($dozent)->pluck('user_id'); - $lecturers = $sem->getMembers(); - foreach ($deputies as $deputy) { - // ..but only if not already set as lecturer or deputy. - if (!isset($lecturers[$deputy])) { - Deputy::addDeputy($deputy, $this->course_id); - } - } - } - } - return true; - } else { - return false; - } - } - - /** * Add tutors to a seminar. * @throws AccessDeniedException */ @@ -421,28 +447,36 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_tutor" . $this->course_id); - $sem = Seminar::GetInstance($this->course_id); - $countAdded = 0; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addTutor($a)) { - $countAdded++; - } - } - if($countAdded) { - PageLayout::postSuccess(sprintf(_('%s wurde hinzugefügt.'), htmlReady(get_title_for_status('tutor', $countAdded, $sem->status)))); + $course = Course::find($this->course_id); + $added_c = 0; + User::findEachMany( + function (User $user) use ($course, &$added_c) { + try { + $course->addMember($user, 'tutor'); + $added_c++; + } catch (\Studip\Exception $e) { + //Nothing here. + } + }, + $mp->getAddedUsers() + ); + if($added_c > 0) { + $status = get_title_for_status('tutor', $added_c, $course->status); + PageLayout::postSuccess( + sprintf( + ngettext( + '%1$u %2$s wurde hinzugefügt.', + '%1$u %2$s wurden hinzugefügt.', + $added_c + ), + $added_c, + $status + ) + ); } $this->redirect('course/members/index'); } - private function addTutor($tutor) { - $sem = Seminar::GetInstance($this->course_id); - if ($sem->addMember($tutor, "tutor")) { - return true; - } else { - return false; - } - } - /** * Provides a dialog to move or copy selected users to another course. */ @@ -634,6 +668,7 @@ class Course_MembersController extends AuthenticatedController if (Request::get('csv_import')) { // remove duplicate users from csv-import $csv_lines = array_unique($csv_request); + $course = Course::find($this->course_id); foreach ($csv_lines as $csv_line) { $csv_name = preg_split('/[,\t]/', mb_substr($csv_line, 0, 100), -1, PREG_SPLIT_NO_EMPTY); $csv_nachname = trim($csv_name[0]); @@ -671,16 +706,19 @@ class Course_MembersController extends AuthenticatedController $row = reset($csv_users); if (!$row['is_present']) { $consider_contingent = Request::option('consider_contingent_csv'); - - if (CourseMember::insertCourseMember($this->course_id, $row['user_id'], 'autor', isset($consider_contingent), $consider_contingent)) { - $csv_count_insert++; - setTempLanguage($this->user_id); - - $message = sprintf(_('Sie wurden in die Veranstaltung **%s** eingetragen.'), $this->course_title); - - restoreLanguage(); - $messaging->insert_message($message, $row['username'], '____%system%____', FALSE, FALSE, '1', FALSE, sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), TRUE); - } elseif (isset($consider_contingent)) { + $user = User::find($row['user_id']); + $failure = false; + if ($user) { + try { + $course->addMember($user, 'autor', $consider_contingent); + $csv_count_insert++; + } catch (\Studip\Exception $e) { + $failure = true; + } + } else { + $failure = true; + } + if ($failure && isset($consider_contingent)) { $csv_count_contingent_full++; } } else { @@ -695,19 +733,17 @@ class Course_MembersController extends AuthenticatedController $selected_users = Request::getArray('selected_users'); if (!empty($selected_users) && count($selected_users) > 0) { + $course = Course::find($this->course_id); foreach ($selected_users as $selected_user) { - if ($selected_user) { - if (CourseMember::insertCourseMember($this->course_id, get_userid($selected_user), 'autor', isset($consider_contingent), $consider_contingent)) { + $user = User::findByUsername($selected_user); + if ($user) { + try { + $course->addMember($user, 'autor', $consider_contingent); $csv_count_insert++; - setTempLanguage($this->user_id); - $message = sprintf(_('Sie wurden manu - - ell in die Veranstaltung **%s** eingetragen.'), $this->course_title); - - restoreLanguage(); - $messaging->insert_message($message, $selected_user, '____%system%____', FALSE, FALSE, '1', FALSE, sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), TRUE); - } elseif (isset($consider_contingent)) { - $csv_count_contingent_full++; + } catch (\Studip\Exception $e) { + if (isset($consider_contingent)) { + $csv_count_contingent_full++; + } } } } @@ -998,11 +1034,8 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - if ( - !$this->is_dozent - && in_array($target_status, ['tutor', 'dozent']) - ) { - throw new AccessDeniedException(_('Sie dürfen keine Lehrenden oder Tutor/-innen in diese Veranstaltung eintragen.')); + if (!$this->is_dozent && in_array($target_status, ['tutor', 'dozent'])) { + throw new AccessDeniedException(_('Sie dürfen keine lehrenden Personen oder Hilfspersonen in diese Veranstaltung eintragen.')); } if (isset($this->flash['consider_contingent'])) { @@ -1018,29 +1051,64 @@ class Course_MembersController extends AuthenticatedController } if ($users) { - $msgs = $this->insertAdmissionMember( - $users, - $target_status, - Request::bool('consider_contingent', false), - $status === 'accepted' - ); - if ($msgs) { - if ($cmd === 'add_user') { - $message = sprintf(_('%s wurde in die Veranstaltung mit dem Status %s eingetragen.'), htmlReady(join(',', $msgs)), $this->decoratedStatusGroups['autor']); - } else { - if ($status === 'awaiting') { - $message = sprintf(_('%s wurde aus der Anmelde bzw. Warteliste mit dem Status - %s in die Veranstaltung eingetragen.'), htmlReady(join(', ', $msgs)), $this->decoratedStatusGroups[$target_status]); - } else { - $message = sprintf(_('%s wurde mit dem Status %s endgültig akzeptiert - und damit in die Veranstaltung aufgenommen.'), htmlReady(join(', ', $msgs)), $this->decoratedStatusGroups[$target_status]); + $enrolled_user_names = []; + $errors = []; + $course = Course::find($this->course_id); + foreach ($users as $user_id => $value) { + if ($value) { + $user = User::find($user_id); + if ($user) { + try { + //Add the user but do not renumber the admission list. This is done manually + //to avoid a mass of mails being sent. + $course->addMember( + $user, + $target_status, + Request::bool('consider_contingent', false), + true, + false + ); + $enrolled_user_names[] = $user->getFullName(); + } catch (\Studip\Exception $e) { + $errors[] = sprintf( + '%1$s: %2$s', + $user->getFullName(), + $e->getMessage() + ); + } } } + } - PageLayout::postSuccess($message); + //Renumber the admission list: + AdmissionApplication::renumberAdmission($this->course_id); + + if ($enrolled_user_names) { + $message = sprintf( + _('%1$s wurde in die Veranstaltung mit dem Status „%2$s“ eingetragen.'), + htmlReady(join(',', $enrolled_user_names)), + $this->decoratedStatusGroups['autor'] + ); } else { - $message = _("Es stehen keine weiteren Plätze mehr im Teilnehmendenkontingent zur Verfügung."); - PageLayout::postError($message); + if ($status === 'awaiting') { + $message = sprintf( + _('%1$s wurde aus der Anmelde- bzw. Warteliste mit dem Status "%2$s" in die Veranstaltung eingetragen.'), + htmlReady(implode(', ', $enrolled_user_names)), + $this->decoratedStatusGroups[$target_status] + ); + } else { + $message = sprintf(_('%1$s wurde mit dem Status "%2$s" endgültig akzeptiert und damit in die Veranstaltung eingetragen.'), + htmlReady(implode(', ', $enrolled_user_names)), + $this->decoratedStatusGroups[$target_status] + ); + } + PageLayout::postSuccess($message); + } + if ($errors) { + PageLayout::postError( + _('Es traten Fehler beim Hochstufen von Personen auf:'), + $errors + ); } } else { PageLayout::postError(_('Sie haben niemanden zum Hochstufen ausgewählt.')); @@ -1062,7 +1130,7 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $course = Seminar::GetInstance($this->course_id); + $course = Course::find($this->course_id); if (!Request::submitted('no')) { if (Request::submitted('yes')) { CSRFProtection::verifyUnsafeRequest(); @@ -1072,10 +1140,39 @@ class Course_MembersController extends AuthenticatedController $this->validateTutorPermission($users, $this->course_id); } if (!empty($users)) { + $removed_users = []; + $errors = []; if (in_array($status, words('accepted awaiting claiming'))) { - $msgs = $course->cancelAdmissionSubscription($users, $status); + foreach ($users as $user) { + $course->removePreliminaryMember($user); + } } else { - $msgs = $course->cancelSubscription($users); + foreach ($users as $user) { + try { + $course->cancelSubscription($user); + $removed_users[] = $user->getFullName(); + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + } + } + + if (!empty($errors)) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Austragen von Personen auf:'), + $errors + ); + } + if (count($removed_users) > 5) { + PageLayout::postSuccess( + _('%u Personen wurden ausgetragen.'), + count($removed_users) + ); + } elseif (count($removed_users) > 0) { + PageLayout::postSuccess( + _('Die folgenden Personen wurden ausgetragen:'), + $removed_users + ); } // deleted authors @@ -1236,22 +1333,50 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $users = []; + $user_ids = []; if (!empty($this->flash['users'])) { - $users = array_keys(array_filter($this->flash['users'])); - } - - if (!empty($users)) { - $msg = $this->moveToWaitlist($users, $which_end); - if (count($msg['success'])) { - PageLayout::postSuccess(sprintf(_('%s Person(en) wurden auf die Warteliste verschoben.'), - count($msg['success'])), - count($msg['success']) <= 5 ? $msg['success'] : []); + $user_ids = array_keys(array_filter($this->flash['users'])); + } + + if (!empty($user_ids)) { + $course = Course::find($this->course_id); + $success_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$success_c, &$errors) { + try { + $course->moveMemberToWaitlist($user, true); + $success_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $user_ids + ); + if ($success_c > 0) { + PageLayout::postSuccess( + studip_interpolate( + ngettext( + 'Eine Person wurden auf die Warteliste verschoben.', + '%{number} Personen wurden auf die Warteliste verschoben.', + $success_c + ), + ['number' => $success_c] + ) + ); } - if (count($msg['error'])) { - PageLayout::postError(sprintf(_('%s Person(en) konnten nicht auf die Warteliste verschoben werden.'), - count($msg['error'])), - count($msg['error']) <= 5 ? $msg['error'] : []); + if (count($errors)) { + PageLayout::postError( + studip_interpolate( + ngettext( + 'Eine Person konnten nicht auf die Warteliste verschoben werden:', + '%{number} Personen konnten nicht auf die Warteliste verschoben werden:', + count($errors) + ), + count($errors) + ), + $errors + ); } } else { PageLayout::postError(_('Sie haben keine Personen zum Verschieben auf die Warteliste ausgewählt')); @@ -1402,7 +1527,7 @@ class Course_MembersController extends AuthenticatedController */ private function getSubject() { - $result = Seminar::GetInstance($this->course_id)->getNumber(); + $result = Course::find($this->course_id)->veranstaltungsnummer; return ($result == '') ? sprintf('[%s]', $this->course_title) : sprintf(_('[%s: %s]'), $result, $this->course_title); @@ -1410,7 +1535,6 @@ class Course_MembersController extends AuthenticatedController private function createSidebar($filtered_members) { - $sem = Seminar::GetInstance($this->course_id); $course = Course::find($this->course_id); $sidebar = Sidebar::get(); @@ -1441,9 +1565,9 @@ class Course_MembersController extends AuthenticatedController } if ($this->is_dozent) { if (!$this->dozent_is_locked) { - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = 'user_inst_not_already_in_sem'; } else { $search_template = 'user_not_already_in_sem'; @@ -1454,12 +1578,12 @@ class Course_MembersController extends AuthenticatedController $search_template, sprintf( _('%s suchen'), - get_title_for_status('dozent', 1, $sem->status) + get_title_for_status('dozent', 1, $course->status) ), 'user_id', [ 'permission' => 'dozent', - 'institute' => $sem_institutes, + 'institute' => $institute_ids, 'seminar_id' => $course->id, ] ); @@ -1476,10 +1600,10 @@ class Course_MembersController extends AuthenticatedController // add "add dozent" to infobox $mp = MultiPersonSearch::get("add_dozent{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['dozent']->pluck('user_id')) ->setLinkIconPath("") - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_dozent')) ->setSearchObject($searchtype) ->addQuickfilter( @@ -1498,9 +1622,9 @@ class Course_MembersController extends AuthenticatedController $widget->addElement($element); } if (!$this->tutor_is_locked) { - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = 'user_inst_not_already_in_sem'; } else { $search_template = 'user_not_already_in_sem'; @@ -1511,12 +1635,12 @@ class Course_MembersController extends AuthenticatedController $search_template, sprintf( _('%s suchen'), - get_title_for_status('tutor', 1, $sem->status) + get_title_for_status('tutor', 1, $course->status) ), 'user_id', [ 'permission' => ['dozent', 'tutor'], - 'institute' => $sem_institutes, + 'institute' => $institute_ids, 'seminar_id' => $course->id, ] ); @@ -1533,10 +1657,10 @@ class Course_MembersController extends AuthenticatedController // add "add tutor" to infobox $mp = MultiPersonSearch::get("add_tutor{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['tutor']->pluck('user_id')) ->setLinkIconPath('') - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_tutor')) ->setSearchObject($searchType) ->addQuickfilter( @@ -1571,7 +1695,7 @@ class Course_MembersController extends AuthenticatedController 'user_not_already_in_sem', sprintf( _('%s suchen'), - get_title_for_status('autor', 1, $sem->status) + get_title_for_status('autor', 1, $course->status) ), 'user_id', [ @@ -1593,10 +1717,10 @@ class Course_MembersController extends AuthenticatedController // add "add autor" to infobox $mp = MultiPersonSearch::get("add_autor{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['autor']->pluck('user_id')) ->setLinkIconPath('') - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_autor')) ->setSearchObject($searchType) ->addQuickfilter( @@ -1619,10 +1743,10 @@ class Course_MembersController extends AuthenticatedController // add "add person to waitlist" to sidebar if ( - $sem->isAdmissionEnabled() - && $sem->getCourseSet()->hasAlgorithmRun() - && !$sem->admission_disable_waitlist - && (!$sem->getFreeSeats() || $sem->admission_disable_waitlist_move) + $course->isAdmissionEnabled() + && $course->getCourseSet()->hasAlgorithmRun() + && !$course->admission_disable_waitlist + && (!$course->getFreeSeats() || $course->admission_disable_waitlist_move) ) { $ignore = array_merge( $filtered_members['dozent']->pluck('user_id'), @@ -1815,11 +1939,11 @@ class Course_MembersController extends AuthenticatedController $this->dozent_count = CourseMember::countBySql("seminar_id=? AND status=?" . $visibility_constraint, [$this->course_id, 'dozent']); //Use the correct names for thte four status groups: - $sem = Seminar::GetInstance($this->course_id); - $this->user_name = get_title_for_status('user', 0, $sem->status); - $this->autor_name = get_title_for_status('autor', 0, $sem->status); - $this->tutor_name = get_title_for_status('tutor', 0, $sem->status); - $this->dozent_name = get_title_for_status('dozent', 0, $sem->status); + $course = Course::find($this->course_id); + $this->user_name = get_title_for_status('user', 0, $course->status); + $this->autor_name = get_title_for_status('autor', 0, $course->status); + $this->tutor_name = get_title_for_status('tutor', 0, $course->status); + $this->dozent_name = get_title_for_status('dozent', 0, $course->status); $this->default_subject = Request::get('default_subject'); @@ -2000,78 +2124,6 @@ class Course_MembersController extends AuthenticatedController return $msgs; } - public function addMember(string $user_id, bool $accepted = false, bool $consider_contingent = null, &$msg = []): bool - { - $user = User::find($user_id); - $messaging = new messaging; - - $status = 'autor'; - // insert - $copy_course = $accepted || $consider_contingent; - $admission_user = CourseMember::insertCourseMember($this->course_id, $user_id, $status, $copy_course, $consider_contingent, true); - - if ($admission_user) { - setTempLanguage($user_id); - $message = sprintf( - _('Sie wurden in die Veranstaltung **%s** eingetragen.'), - $this->course_title - ); - restoreLanguage(); - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), - true - ); - $msg['success'][] = sprintf( - _('%1$s wurde in die Veranstaltung mit dem Status %2$s eingetragen.'), - $user->getFullName(), - $status - ); - } else if ($consider_contingent) { - PageLayout::postError(_('Es stehen keine weiteren Plätze mehr im Teilnehmendenkontingent zur Verfügung.')); - return false; - } else { - PageLayout::postError( - _('Beim Eintragen ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut oder wenden Sie sich an die Administrierenden') - ); - return false; - } - //Warteliste neu sortieren - AdmissionApplication::renumberAdmission($this->course_id); - return true; - } - - /** - * Adds the given user to the waitlist of the current course and sends a - * corresponding message. - * - * @param String $user_id The user to add - * @return bool Successful operation? - */ - private function addToWaitlist(string $user_id): bool - { - $course = Seminar::getInstance($this->course_id); - // Insert user in waitlist at current position. - if ($course->addToWaitlist($user_id, 'last')) { - setTempLanguage($user_id); - $message = sprintf(_('Sie wurden von einem/einer Veranstaltungsleiter/-in (%1$s) ' . - 'oder einem/einer Administrator/-in auf die Warteliste der Veranstaltung **%2$s** gesetzt.'), - get_title_for_status('dozent', 1), $this->course_title); - restoreLanguage(); - messaging::sendSystemMessage($user_id, sprintf('%s %s', _('Systemnachricht:'), - _('Auf Warteliste gesetzt')), $message); - - return true; - } - return false; - } - /** * Adds the given users to the target course. * @param array $users users to add @@ -2082,127 +2134,29 @@ class Course_MembersController extends AuthenticatedController private function sendToCourse(array $users, string $target_course_id, bool $move = false): array { $msg = []; - foreach ($users as $user) { - if (!CourseMember::exists([$target_course_id, $user])) { - $target_course = Seminar::GetInstance($target_course_id); + foreach ($users as $user_id) { + if (!CourseMember::exists([$target_course_id, $user_id])) { + $user = User::find($user_id); + if (!$user) { + continue; + } + $target_course = Course::find($target_course_id); if ($target_course->addMember($user)) { if ($move) { - $remove_from = Seminar::getInstance($this->course_id); + $remove_from = Course::find($this->course_id); $remove_from->deleteMember($user); } - $msg['success'][] = $user; + $msg['success'][] = $user_id; } else { - $msg['failed'][] = $user; + $msg['failed'][] = $user_id; } } else { - $msg['existing'][] = $user; + $msg['existing'][] = $user_id; } } return $msg; } - private function insertAdmissionMember(array $users, string $next_status, bool $consider_contingent, bool $accepted = false, string $cmd = 'add_user'): array - { - $messaging = new messaging; - $msgs = []; - foreach ($users as $user_id => $value) { - if ($value) { - $user = User::find($user_id); - if ($user) { - $admission_user = CourseMember::insertCourseMember( - $this->course_id, - $user_id, - $next_status, - $accepted || $consider_contingent, - $consider_contingent - ); - - // only if user was on the waiting list - if ($admission_user) { - setTempLanguage($user_id); - restoreLanguage(); - - if ($cmd === 'add_user') { - $message = sprintf( - _('Sie wurden in die Veranstaltung **%s** eingetragen.'), - $this->course_title - ); - } else { - if (!$accepted) { - $message = sprintf( - _('Sie wurden aus der Warteliste in die Veranstaltung **%s** aufgenommen und sind damit zugelassen.'), - $this->course_title - ); - } else { - $message = sprintf( - _('Sie wurden vom Status **vorläufig akzeptiert** auf **teilnehmend** in der Veranstaltung **%s** hochgestuft und sind damit zugelassen.'), - $this->course_title - ); - } - } - - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), - true - ); - $msgs[] = $user->getFullName(); - } - } - } - } - - // resort admissionlist - AdmissionApplication::renumberAdmission($this->course_id); - - return $msgs; - } - - /** - * Adds given users to the course waitlist, either at list beginning or end. - * System messages are sent to affected users. - * - * @param array $users array of user ids to add - * @param String $which_end 'last' or 'first': which list end to append to - * @return array Array of messages (stating success and/or errors) - */ - public function moveToWaitlist($users, $which_end) - { - $course = Seminar::getInstance($this->course_id); - $msgs = [ - 'success' => [], - 'error' => [], - ]; - foreach ($users as $user_id) { - // Delete member from seminar - $temp_user = User::find($user_id); - if ($course->deleteMember($user_id)) { - setTempLanguage($user_id); - $message = sprintf(_('Sie wurden aus der Veranstaltung **%s** abgemeldet. '. - 'Sie wurden auf die Warteliste dieser Veranstaltung gesetzt.'), - $this->course_title); - restoreLanguage(); - messaging::sendSystemMessage($user_id, sprintf('%s %s', _('Systemnachricht:'), - _('Anmeldung aufgehoben, auf Warteliste gesetzt')), $message); - if ($course->addToWaitlist($user_id, $which_end)) { - $msgs['success'][] = $temp_user->getFullName('no_title'); - } else { - $msgs['error'][] = $temp_user->getFullName('no_title'); - } - // Something went wrong on inserting the user in waitlist. - } else { - $msgs['error'][] = $temp_user->getFullName('no_title'); - } - } - return $msgs; - } - /** * Get the position out of the database * @param String $user_id diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php index 876de5a..e1da00e 100644 --- a/app/controllers/course/overview.php +++ b/app/controllers/course/overview.php @@ -29,10 +29,6 @@ class Course_OverviewController extends AuthenticatedController PageLayout::setHelpKeyword('Basis.InVeranstaltungKurzinfo'); PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Kurzinfo')); Navigation::activateItem('/course/main/info'); - - $this->sem = Seminar::getInstance($this->course_id); - $sem_class = $this->sem->getSemClass(); - $this->studygroup_mode = $sem_class['studygroup_mode']; } /** @@ -63,26 +59,27 @@ class Course_OverviewController extends AuthenticatedController } - if (!$this->studygroup_mode) { + if (!$this->course->isStudygroup()) { $this->avatar = CourseAvatar::getAvatar($this->course_id); // Fetch dates $response = $this->relay("calendar/contentbox/display/{$this->course_id}/1210000"); $this->dates = $response->body; - $this->next_date = $this->sem->getNextDate(); - $this->first_date = $this->sem->getFirstDate(); + $this->next_date = $this->course->getNextDate(); + $this->first_date = $this->course->getFirstDate(); $show_link = $GLOBALS["perm"]->have_studip_perm('autor', $this->course_id) && $this->course->isToolActive('schedule'); - $this->times_rooms = $this->sem->getDatesTemplate('dates/seminar_html', ['link_to_dates' => $show_link, 'show_room' => true]); - - // Fettch teachers - $dozenten = $this->sem->getMembers('dozent'); - $this->num_dozenten = count($dozenten); - $show_dozenten = []; - foreach ($dozenten as $dozent) { - $show_dozenten[] = '' - . htmlready($this->num_dozenten > 10 ? get_fullname($dozent['user_id'], 'no_title_short') : $dozent['fullname']) - . ''; + $this->times_rooms = implode('
', $this->course->getAllDatesInSemester()->toStringArray()); + + //Load lecturers: + $lecturers = $this->course->getMembersWithStatus('dozent'); + $this->num_lecturers = count($lecturers); + $this->lecturer_html = []; + foreach ($lecturers as $lecturer) { + $this->lecturer_html[] = sprintf( + '%s', + URLHelper::getLink('dispatch.php/profile', ['username' => $lecturer->user->username], true), + htmlReady($lecturer->user->getFullName($this->num_lecturers > 10 ? 'no_title_short' : 'default')) + ); } - $this->show_dozenten = $show_dozenten; // Check lock rules if (!$GLOBALS['perm']->have_studip_perm('dozent', $this->course_id)) { @@ -107,7 +104,7 @@ class Course_OverviewController extends AuthenticatedController } } } else { - $this->all_mods = $this->sem->getMembers('dozent') + $this->sem->getMembers('tutor'); + $this->all_mods = $this->course->getMembersWithStatus(['dozent', 'tutor']); $this->avatar = StudygroupAvatar::getAvatar($this->course_id); } @@ -129,7 +126,7 @@ class Course_OverviewController extends AuthenticatedController } $share = new ShareWidget(); - if ($this->studygroup_mode) { + if ($this->course->isStudygroup()) { $share->addCopyableLink( _('Link zu dieser Studiengruppe kopieren'), $this->url_for('course/studygroup/details/' . $this->course->id, [ diff --git a/app/controllers/course/statusgroups.php b/app/controllers/course/statusgroups.php index 9a13738..dc282ff 100644 --- a/app/controllers/course/statusgroups.php +++ b/app/controllers/course/statusgroups.php @@ -890,8 +890,6 @@ class Course_StatusgroupsController extends AuthenticatedController SeminarCycleDate::findBySeminar_id($this->course_id)); foreach ($cycles as $c) { - $cd = new CycleData($c); - $name = $c->toString(); // Append description to group title if applicable. @@ -900,15 +898,10 @@ class Course_StatusgroupsController extends AuthenticatedController } // Get name of most used room and append to group title. - if ($rooms = $cd->getPredominantRoom()) { - $room_keys = array_keys($rooms); - $room_name = DBManager::get()->fetchOne( - "SELECT `name` FROM `resources` WHERE `id` = ?", - [array_pop($room_keys)]); - $name .= ' (' . $room_name['name'] . ')'; + if ($room = $c->getMostBookedRoom()) { + $name .= ' (' . $room->name . ')'; } else { - $free_text_predominant_rooms = array_keys($cd->getFreeTextPredominantRoom()); - $room = trim(array_pop($free_text_predominant_rooms)); + $room = $c->getMostBookedFreetextRoom(); if ($room) { $name .= ' (' . $room . ')'; } @@ -1439,14 +1432,42 @@ class Course_StatusgroupsController extends AuthenticatedController CSRFProtection::verifyUnsafeRequest(); $members = Request::getArray('members'); - $course = Seminar::GetInstance($this->course_id); - $removed_names = $course->cancelSubscription($members); - - PageLayout::postSuccess( - _('Die folgenden Personen wurden aus der Veranstaltung ausgetragen'), - $removed_names + $course = Course::find($this->course_id); + $removed_users = []; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$errors, &$removed_users) { + try { + $course->deleteMember($user, true); + $removed_users = $user->getFullName(); + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + + }, + array_column($members, 'user_id') ); + if (!empty($errors)) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Austragen von Personen auf:'), + $errors + ); + } + if (!empty($removed_users)) { + if (count($removed_users) <= 5) { + PageLayout::postSuccess( + _('Die folgenden Personen wurden ausgetragen:'), + $removed_users + ); + } else { + PageLayout::postSuccess( + _('%u Personen wurden ausgetragen.'), + count($removed_users) + ); + } + } + $this->relocate('course/statusgroups'); } diff --git a/app/controllers/course/studygroup.php b/app/controllers/course/studygroup.php index 1f9c4a4..f164b57 100644 --- a/app/controllers/course/studygroup.php +++ b/app/controllers/course/studygroup.php @@ -75,7 +75,7 @@ class Course_StudygroupController extends AuthenticatedController $id = Context::getId(); } - $studygroup = new Seminar($id); + $studygroup = Course::find($id); $this->sidebarActions = []; if (Request::isXhr()) { PageLayout::setTitle(_('Studiengruppendetails')); @@ -365,15 +365,14 @@ class Course_StudygroupController extends AuthenticatedController // if we are permitted to edit the studygroup get some data... if ($id && $perm->have_studip_perm('dozent', $id)) { - $sem = Seminar::getInstance($id); + $this->course = Course::find($id); PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Studiengruppe bearbeiten')); Navigation::activateItem('/course/admin/main'); - $this->sem_id = $id; - $this->sem = $sem; - $this->sem_class = $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$sem->status]['class']]; - $this->tutors = $sem->getMembers('tutor'); + $this->course_id = $id; + $this->sem_class = $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$this->course->status]['class']]; + $this->tutors = CourseMember::findByCourseAndStatus($this->course->id, 'tutor'); $this->founders = StudygroupModel::getFounders($id); $actions = new ActionsWidget(); @@ -775,8 +774,8 @@ class Course_StudygroupController extends AuthenticatedController // save invite in database StudygroupModel::inviteMember($receiver, $id); // send invite message to user - $msg = new messaging(); - $sem = new Seminar($id); + $msg = new messaging(); + $sem = Course::find($id); $message = sprintf(_("%s möchte Sie auf die Studiengruppe %s aufmerksam machen. Klicken Sie auf den folgenden Link, um direkt zur Studiengruppe zu gelangen.\n\n %s"), get_fullname(), $sem->name, URLHelper::getlink("dispatch.php/course/studygroup/details/" . $id, ['cid' => null])); $subject = _("Sie wurden in eine Studiengruppe eingeladen"); @@ -823,14 +822,10 @@ class Course_StudygroupController extends AuthenticatedController if ($perm->have_studip_perm('dozent', $id)) { if ($approveDelete && check_ticket(Request::get('studip_ticket'))) { - $messages = []; - $sem = new Seminar($id); - $sem->delete(); - if ($messages = $sem->getStackedMessages()) { - $this->flash['messages'] = $messages; + $course = Course::find($id); + if (!$course->delete()) { + PageLayout::postError(_('Die Studiengruppe konnte nicht gelöscht werden.')); } - unset($sem); - $this->redirect(URLHelper::getURL('dispatch.php/studygroup/browse', [], true)); return; } elseif (!$approveDelete) { diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php index bbc7196..5eab38a 100644 --- a/app/controllers/course/timesrooms.php +++ b/app/controllers/course/timesrooms.php @@ -31,7 +31,7 @@ class Course_TimesroomsController extends AuthenticatedController } // Get seminar instance - $this->course = new Seminar(Course::findCurrent()); + $this->course = Course::findCurrent(); if (Navigation::hasItem('course/admin/dates')) { Navigation::activateItem('course/admin/dates'); @@ -60,29 +60,41 @@ class Course_TimesroomsController extends AuthenticatedController PageLayout::setTitle($title); + $dates_in_time_range = CourseDate::countBySql( + "`range_id` = :course_id AND `date` BETWEEN :beginning AND :end", + [ + 'course_id' => $this->course->id, + 'beginning' => $this->course->start_semester->beginn, + 'end' => $this->course->end_semester->vorles_ende + ] + ) > 0; URLHelper::bindLinkParam('semester_filter', $this->semester_filter); if (empty($this->semester_filter)) { - if (!$this->course->hasDatesOutOfDuration() && count($this->course->semesters) == 1) { + if ($dates_in_time_range && count($this->course->semesters) == 1) { $this->semester_filter = $this->course->start_semester->id; } else { $this->semester_filter = 'all'; } } - if ($this->semester_filter == 'all') { - $this->course->applyTimeFilter(0, 0); - } else { - $semester = Semester::find($this->semester_filter); - $this->course->applyTimeFilter($semester['beginn'], $semester['ende']); - } if ($this->course->isOpenEnded()) { $selectable_semesters = Semester::getAll(); } else { $selectable_semesters = $this->course->semesters->toArray(); } - if (count($selectable_semesters) > 1 || (count($selectable_semesters) == 1 && $this->course->hasDatesOutOfDuration())) { + + $dates_outside_of_time_range = CourseDate::countBySql( + "`range_id` = :course_id AND `date` NOT BETWEEN :beginning AND :end", + [ + 'course_id' => $this->course->id, + 'beginning' => $this->course->start_semester->beginn, + 'end' => $this->course->end_semester->vorles_ende + ] + ) > 0; + + if (count($selectable_semesters) > 1 || (count($selectable_semesters) == 1 && $dates_outside_of_time_range)) { $selectable_semesters[] = ['name' => _('Alle Semester'), 'semester_id' => 'all']; } $this->selectable_semesters = array_reverse($selectable_semesters); @@ -91,14 +103,20 @@ class Course_TimesroomsController extends AuthenticatedController $this->setSidebar(); } elseif (Request::isXhr() && $this->flash['update-times']) { $semester_id = $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE ?? ''; + $semester = null; + if ($this->semester_filter !== 'all') { + $semester = Semester::find($this->semester_filter); + if (!$semester && $semester_id) { + $semester = Semester::find($this->semester_id); + } + } + + $dates = $this->course->getAllDatesInSemester($semester, $semester); $this->response->add_header( 'X-Raumzeit-Update-Times', json_encode([ 'course_id' => $this->course->id, - 'html' => $this->course->getDatesHTML([ - 'semester_id' => $semester_id, - 'show_room' => true, - ]) ?: _('nicht angegeben'), + 'html' => $dates->toHtml(false, true), ]) ); } @@ -243,7 +261,7 @@ class Course_TimesroomsController extends AuthenticatedController unset($_SESSION['_checked_dates']); } if (Request::isDialog()) { - $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "'.$this->course->getId().'"}'); + $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "' . $this->course->id . '"}'); } } @@ -291,15 +309,16 @@ class Course_TimesroomsController extends AuthenticatedController $course->semesters = $selected_semesters; } - // set the semester-chooser to the first semester - $this->course->setFilter($course->getStartSemester()); + //Set the semester selector to the first semester: $this->semester_filter = $start_semester->semester_id; $course->store(); if (!$course->isOpenEnded()) { $new_start_weeks = $course->start_semester->getStartWeeks($course->end_semester); - SeminarCycleDate::removeOutRangedSingleDates($this->course->getStartSemester(), $this->course->getEndSemesterVorlesEnde(), $course->id); + $start = $this->course->start_semester->beginn; + $end = $this->course->end_semester->vorles_ende; + SeminarCycleDate::removeOutRangedSingleDates($start, $end, $course->id); $cycles = SeminarCycleDate::findBySeminar_id($course->id); foreach ($cycles as $cycle) { $cycle->end_offset = $this->getNewEndOffset($cycle, $old_start_weeks, $new_start_weeks); @@ -308,14 +327,10 @@ class Course_TimesroomsController extends AuthenticatedController } } - $messages = $this->course->getStackedMessages(); - foreach ($messages as $type => $msg) { - PageLayout::postMessage(MessageBox::$type($msg['title'], $msg['details'])); - } $this->relocate(str_replace('_', '/', Request::option('origin'))); } if (Request::isDialog()) { - $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "'.$this->course->getId().'"}'); + $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "' . $this->course->id . '"}'); } } } @@ -331,6 +346,12 @@ class Course_TimesroomsController extends AuthenticatedController $this->date = CourseDate::find($termin_id) ?: CourseExDate::find($termin_id); $this->attributes = []; + $request = RoomRequest::findByDate($this->date->id); + if ($request) { + $this->params = ['request_id' => $request->id]; + } else { + $this->params = ['new_room_request_type' => 'date_' . $this->date->id]; + } $this->only_bookable_rooms = Request::submitted('only_bookable_rooms'); if (Config::get()->RESOURCES_ENABLE) { @@ -427,29 +448,37 @@ class Course_TimesroomsController extends AuthenticatedController } $time_changed = ($date != $termin->date || $end_time != $termin->end_time); - //time changed for regular date. create normal singledate and cancel the regular date - if ($termin->metadate_id != '' && $time_changed) { - $termin_values = $termin->toArray(); - $termin_info = $termin->getFullName(); - - $termin->cancelDate(); - PageLayout::postInfo(sprintf( - _('Der Termin %s wurde aus der Liste der regelmäßigen Termine' - . ' gelöscht und als unregelmäßiger Termin eingetragen, da Sie die Zeiten des Termins verändert haben,' - . ' so dass dieser Termin nun nicht mehr regelmäßig ist.'), - htmlReady($termin_info) - )); + if ($time_changed) { + if ($termin->metadate_id != '') { + //time changed for regular date. create normal singledate and cancel the regular date + $termin_values = $termin->toArray(); + $termin_info = $termin->getFullName(); + + $termin->cancelDate(); + PageLayout::postInfo(sprintf( + _('Der Termin %s wurde aus der Liste der regelmäßigen Termine' + . ' gelöscht und als unregelmäßiger Termin eingetragen, da Sie die Zeiten des Termins verändert haben,' + . ' sodass dieser Termin nun nicht mehr regelmäßig ist.'), + htmlReady($termin_info) + )); - $termin = new CourseDate(); - unset($termin_values['metadate_id']); - $termin->setData($termin_values); - $termin->setId($termin->getNewId()); + $termin = new CourseDate(); + unset($termin_values['metadate_id']); + $termin->setData($termin_values); + $termin->date = $date; + $termin->end_time = $end_time; + $termin->setId($termin->getNewId()); + } else { + //Time changed for single date. + $termin->date = $date; + $termin->end_time = $end_time; + } } $termin->date_typ = Request::get('course_type'); // Set assigned teachers $assigned_teachers = Request::optionArray('assigned_teachers'); - $dozenten = $this->course->getMembers(); + $dozenten = $this->course->getMembersWithStatus('dozent'); if (count($assigned_teachers) === count($dozenten) || empty($assigned_teachers)) { //The amount of lecturers of the course date is the same as the amount of lecturers of the course //or no lecturers are assigned to the course date. @@ -471,15 +500,7 @@ class Course_TimesroomsController extends AuthenticatedController } // Set Room - if ($termin->room_booking) { - $old_room_id = $termin->room_booking->resource_id; - } else { - $old_room_id = null; - } - $singledate = new SingleDate($termin); - if ($singledate->setTime($date, $end_time)) { - $singledate->store(); - } + $old_room_id = $termin->room_booking->resource_id ?? ''; if ((Request::option('room') == 'room') || Request::option('room') == 'nochange') { //Storing the SingleDate above has deleted the room booking @@ -500,57 +521,61 @@ class Course_TimesroomsController extends AuthenticatedController } } if ($room_id) { - if ($room_id != $singledate->resource_id) { - if ($singledate->bookRoom($room_id, $preparation_time ?: 0)) { - $messages = $singledate->getMessages(); - $this->course->appendMessages($messages); - } else if (!$singledate->ex_termin) { - $this->course->createError( - sprintf( - _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), - '' . htmlReady($singledate->toString()) . '' - ) - ); + $room = Resource::find($room_id)?->getDerivedClassInstance(); + if ($room_id !== $old_room_id) { + $failure = false; + if ($room instanceof Room) { + try { + $failure = !$termin->bookRoom($room, $preparation_time ?: 0); + } catch (ResourceBookingException|ResourceBookingOverlapException $e) { + PageLayout::postError(sprintf( + _('Der angegebene Raum konnte für den Termin %1$s nicht gebucht werden: %2$s'), + '' . htmlReady($termin->getFullName()) . '', + $e->getMessage() + )); + } } - } elseif ($termin->room_booking->preparation_time != ($preparation_time * 60)) { - $singledate->bookRoom($room_id, $preparation_time ?: 0); + if ($failure) { + PageLayout::postError(sprintf( + _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), + '' . htmlReady($termin->getFullName()) . '' + )); + } + } elseif ($room instanceof Room && $termin->room_booking->preparation_time != ($preparation_time * 60)) { + $termin->bookRoom($room, $preparation_time ?: 0); } - } else if ($old_room_id && !$singledate->resource_id) { - $this->course->createInfo( + } else if ($old_room_id && empty($termin->room_booking->resource_id)) { + PageLayout::postInfo( sprintf( _('Die Raumbuchung für den Termin %s wurde aufgehoben, da die neuen Zeiten außerhalb der alten liegen!'), - ''.htmlReady( $singledate->toString()) .'' + ''.htmlReady($termin->getFullName()) .'' )); } else if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( _('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } } elseif (Request::option('room') == 'freetext') { - $singledate->setFreeRoomText(Request::get('freeRoomText_sd')); - $singledate->killAssign(); - $singledate->store(); - $this->course->createMessage(sprintf( - _('Der Termin %s wurde geändert, etwaige Raumbuchungen wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), - '' . htmlReady($singledate->toString()) . '' + $termin->raum = Request::get('freeRoomText_sd'); + if ($termin->room_booking) { + $termin->room_booking->delete(); + } + $termin->store(); + PageLayout::postSuccess(sprintf( + _('Der Termin %s wurde geändert, Raumbuchungen zu diesem Termin wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), + '' . htmlReady($termin->getFullName()) . '' )); } elseif (Request::option('room') == 'noroom') { - $singledate->setFreeRoomText(''); - $singledate->killAssign(); - $singledate->store(); - $this->course->createMessage(sprintf( - _('Der Termin %s wurde geändert, etwaige freie Ortsangaben und Raumbuchungen wurden entfernt.'), - '' . htmlReady($singledate->toString()) . '' + $termin->raum = ''; + if ($termin->room_booking) { + $termin->room_booking->delete(); + } + $termin->store(); + PageLayout::postSuccess(sprintf( + _('Der Termin %s wurde geändert, freie Ortsangaben und Raumbuchungen an diesem Termin wurden entfernt.'), + '' . htmlReady($termin) . '' )); } - if (!empty($singledate->messages['error'])) { - PageLayout::postError( - _('Die folgenden Fehler traten beim Bearbeiten des Termins auf:'), - htmlReady($singledate->messages['error']) - ); - } - - $this->displayMessages(); $this->redirect('course/timesrooms/index', ['contentbox_open' => $termin->metadate_id]); } @@ -569,7 +594,7 @@ class Course_TimesroomsController extends AuthenticatedController if (Config::get()->RESOURCES_ENABLE) { $this->setAvailableRooms(null); } - $this->teachers = $this->course->getMembers('dozent'); + $this->teachers = $this->course->getMembersWithStatus('dozent'); $this->groups = Statusgruppen::findBySeminar_id($this->course->id); } @@ -633,12 +658,13 @@ class Course_TimesroomsController extends AuthenticatedController $termin->store(); } else { $termin->store(); - $singledate = new SingleDate($termin); - $singledate->bookRoom(Request::option('room_id')); - $this->course->appendMessages($singledate->getMessages()); + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + if ($room instanceof Room) { + $termin->bookRoom($room); + } } if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( _('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } @@ -646,13 +672,8 @@ class Course_TimesroomsController extends AuthenticatedController // store last created date in session $_SESSION['last_single_date'] = Request::getInstance(); - if ($start_time < $this->course->filterStart || $end_time > $this->course->filterEnd) { - $this->course->setFilter('all'); - } - - $this->course->createMessage(sprintf(_('Der Termin %s wurde hinzugefügt!'), htmlReady($termin->getFullName()))); + PageLayout::postSuccess(sprintf(_('Der Termin %s wurde hinzugefügt!'), htmlReady($termin->getFullname()))); $this->course->store(); - $this->displayMessages(); $this->relocate('course/timesrooms/index'); } @@ -667,11 +688,10 @@ class Course_TimesroomsController extends AuthenticatedController $ex_termin = CourseExDate::find($termin_id); $termin = $ex_termin->unCancelDate(); if ($termin) { - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde wiederhergestellt!'), htmlReady($termin->getFullName()) )); - $this->displayMessages(); } if ($from_dates) { @@ -733,7 +753,7 @@ class Course_TimesroomsController extends AuthenticatedController private function editStack($cycle_id) { $this->cycle_id = $cycle_id; - $this->teachers = $this->course->getMembers(); + $this->teachers = $this->course->getMembersWithStatus('dozent'); $this->gruppen = Statusgruppen::findBySeminar_id($this->course->id); $checked_course_dates = CourseDate::findMany($_SESSION['_checked_dates']); $this->only_bookable_rooms = Request::submitted('only_bookable_rooms'); @@ -876,13 +896,12 @@ class Course_TimesroomsController extends AuthenticatedController $ex_termin->content = ''; $termin = $ex_termin->unCancelDate(); if ($termin !== null) { - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde wiederhergestellt!'), htmlReady($termin->getFullName()) )); } } - $this->displayMessages(); $this->relocate('course/timesrooms/index', ['contentbox_open' => $cycle_id]); } @@ -911,8 +930,6 @@ class Course_TimesroomsController extends AuthenticatedController $this->saveRequestStack(); } - $this->displayMessages(); - $this->relocate('course/timesrooms/index', ['contentbox_open' => $cycle_id]); } @@ -937,7 +954,7 @@ class Course_TimesroomsController extends AuthenticatedController if ($cancel_send_message && $cancel_comment != '' && count($deleted_dates) > 0) { $snd_messages = raumzeit_send_cancel_message($cancel_comment, $deleted_dates); if ($snd_messages > 0) { - $this->course->createMessage(_('Alle Teilnehmenden wurden benachrichtigt.')); + PageLayout::postSuccess(_('Alle Teilnehmenden wurden benachrichtigt.')); } } } @@ -969,7 +986,7 @@ class Course_TimesroomsController extends AuthenticatedController // Update related persons if (in_array($action, words('add delete'))) { - $course_lectures = $this->course->getMembers(); + $course_lectures = $this->course->getMembersWithStatus('dozent'); $persons = User::findMany($persons); foreach ($singledates as $singledate) { if ($action === 'add') { @@ -1000,7 +1017,7 @@ class Course_TimesroomsController extends AuthenticatedController } if ($lecture_changed) { - $this->course->createMessage(_('Zuständige Personen für die Termine wurden geändert.')); + PageLayout::postSuccess(_('Die zuständigen Personen für die Termine wurden geändert.')); } if (in_array($group_action, words('add delete'))) { @@ -1034,72 +1051,95 @@ class Course_TimesroomsController extends AuthenticatedController } if ($groups_changed) { - $this->course->createMessage(_('Zugewiesene Gruppen für die Termine wurden geändert.')); + PageLayout::postSuccess(_('Zugewiesene Gruppen für die Termine wurden geändert.')); } if (in_array(Request::get('action'), ['room', 'freetext', 'noroom']) || Request::get('course_type')) { - foreach ($singledates as $key => $singledate) { - $date = new SingleDate($singledate); + $errors = []; + foreach ($singledates as $singledate) { + if ($singledate instanceof CourseExDate) { + continue; + } if (Request::option('action') == 'room') { $preparation_time = Request::get('preparation_time'); $max_preparation_time = Config::get()->RESOURCES_MAX_PREPARATION_TIME; if ($preparation_time > $max_preparation_time) { - $this->course->createError( - sprintf( - _('Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'), - $max_preparation_time - ) + $errors[] = sprintf( + studip_interpolate( + _('%{date}: Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'), + ['date' => $singledate->getFullName()] + ), + $max_preparation_time ); continue; } if (Request::option('room_id')) { - if (Request::option('room_id') != $singledate->room_booking->resource_id) { - if ($date->bookRoom(Request::option('room_id'), $preparation_time)) { - $messages = $date->getMessages(); - $this->course->appendMessages($messages); - } else if (!$date->ex_termin) { - $this->course->createError(sprintf( + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + if ($room instanceof Room) { + $failure = false; + try { + $failure = !$singledate->bookRoom($room, intval($preparation_time)); + } catch (ResourceBookingException|ResourceBookingOverlapException $e) { + $errors[] = sprintf( + _('Der angegebene Raum konnte für den Termin %1$s nicht gebucht werden: %2$s'), + '' . htmlReady($singledate->getFullName()) . '', + $e->getMessage() + ); + } + if ($failure) { + $errors[] = sprintf( _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), - '' . htmlReady($date->toString() ) . '') + '' . htmlReady($singledate->getFullName()) . '' ); + } else { + PageLayout::postSuccess(sprintf( + _('Die Änderungen am Termin %s wurden gespeichert.'), + $singledate->getFullName() + )); } - } elseif (($preparation_time * 60) != $singledate->room_booking->preparation_time) { - $date->bookRoom(Request::option('room_id'), $preparation_time); - $messages = $date->getMessages(); - $this->course->appendMessages($messages); } } else if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( ('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } } elseif (Request::option('action') == 'freetext') { - $date->setFreeRoomText(Request::get('freeRoomText')); - $date->store(); - $date->killAssign(); - $this->course->createMessage(sprintf( + $singledate->raum = Request::get('freeRoomText'); + $singledate->store(); + if ($singledate->room_booking instanceof ResourceBooking) { + $singledate->room_booking->delete(); + } + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde geändert, etwaige Raumbuchungen wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), - '' . htmlReady($date->toString()) . '' + '' . htmlReady($singledate->getFullName()) . '' )); } elseif (Request::option('action') == 'noroom') { - $date->setFreeRoomText(''); - $date->store(); - $date->killAssign(); - $this->course->createMessage(sprintf( + $singledate->raum = ''; + $singledate->store(); + if ($singledate->room_booking instanceof ResourceBooking) { + $singledate->room_booking->delete(); + } + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde geändert, etwaige freie Ortsangaben und Raumbuchungen wurden entfernt.'), - '' . htmlReady($date->toString()) . '' + '' . htmlReady($singledate) . '' )); } if (Request::get('course_type') != '') { - $date->setDateType(Request::get('course_type')); - $date->store(); - $this->course->createMessage(sprintf( + $singledate->date_typ = Request::get('course_type'); + $singledate->store(); + PageLayout::postSuccess(sprintf( _('Die Art des Termins %s wurde geändert.'), - '' . htmlReady($date->toString()) . '' + '' . htmlReady($singledate) . '' )); } } + if ($errors) { + PageLayout::postError( + _('Die folgenden Fehler traten auf:'), + $errors + ); + } } } @@ -1134,21 +1174,17 @@ class Course_TimesroomsController extends AuthenticatedController } if (!$appointments) { - $this->course->createError( - _('Es wurden keine gültigen Termin-IDs übergeben!') - ); + PageLayout::postError(_('Es wurden keine gültigen Termine übergeben!')); return; } $request = new RoomRequest(); - $request->course_id = $this->course->getId(); + $request->course_id = $this->course->id; $request->user_id = $GLOBALS['user']->id; $request->comment = Request::get('comment'); $request->closed = '0'; if (!$request->store()) { - $this->course->createError( - _('Fehler beim Speichern der Anfrage!') - ); + PageLayout::postError(_('Fehler beim Speichern der Anfrage!')); return; } @@ -1162,9 +1198,7 @@ class Course_TimesroomsController extends AuthenticatedController } if ($set_properties && $successfully_stored < count($set_properties)) { - $this->course->createError( - _('Es wurden nicht alle zur Anfrage gehörenden Eigenschaften gespeichert!') - ); + PageLayout::postError(_('Es wurden nicht alle zur Anfrage gehörenden Eigenschaften gespeichert!')); } //Finally we can create ResourceRequestAppointment @@ -1181,15 +1215,11 @@ class Course_TimesroomsController extends AuthenticatedController } if (($successfully_stored < count($appointments)) && count($appointments)) { - $this->course->createError( - _('Es wurden nicht alle zur Anfrage gehörenden Terminzuordnungen gespeichert!') - ); + PageLayout::postError(_('Es wurden nicht alle zur Anfrage gehörenden Terminzuordnungen gespeichert!')); return; } - $this->course->createMessage( - _('Die Raumanfrage wurde gespeichert!') - ); + PageLayout::postSuccess(_('Die Raumanfrage wurde gespeichert!')); } @@ -1200,7 +1230,7 @@ class Course_TimesroomsController extends AuthenticatedController */ public function createCycle_action($cycle_id = null) { - PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Regelmäßige Termine anlegen')); + PageLayout::setTitle(Course::findCurrent()->getFullname() . " - " . _('Regelmäßige Termine anlegen')); $this->restoreRequest( words('day start_time end_time description cycle startWeek teacher_sws fromDialog course_type') ); @@ -1327,18 +1357,16 @@ class Course_TimesroomsController extends AuthenticatedController $cycle_info = $cycle->toString(); NotificationCenter::postNotification('CourseDidChangeSchedule', $this->course); - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Die regelmäßige Veranstaltungszeit %s wurde hinzugefügt!'), htmlReady($cycle_info)) ); - $this->displayMessages(); $this->relocate('course/timesrooms/index'); } else { $this->storeRequest(); - $this->course->createError( + PageLayout::postError( _('Die regelmäßige Veranstaltungszeit konnte nicht hinzugefügt werden! Bitte überprüfen Sie Ihre Eingabe.') ); - $this->displayMessages(); $this->redirect('course/timesrooms/createCycle'); } } @@ -1466,29 +1494,28 @@ class Course_TimesroomsController extends AuthenticatedController if (Request::get('cancel_comment') != $termin->content) { $termin->content = Request::get('cancel_comment'); if ($termin->store()) { - $this->course->createMessage(sprintf( - _('Der Kommtentar des gelöschten Termins %s wurde geändert.'), - htmlReady($termin->getFullName()) + PageLayout::postSuccess(sprintf( + _('Der Kommentar des gelöschten Termins %s wurde geändert.'), + htmlReady($termin->getFullname()) )); } else { - $this->course->createInfo(sprintf( + PageLayout::postInfo(sprintf( _('Der gelöschte Termin %s wurde nicht verändert.'), - htmlReady($termin->getFullName()) + htmlReady($termin->getFullname()) )); } } else { - $this->course->createInfo(sprintf( + PageLayout::postInfo(sprintf( _('Der gelöschte Termin %s wurde nicht verändert.'), - htmlReady($termin->getFullName()) + htmlReady($termin->getFullname()) )); } if (Request::int('cancel_send_message')) { $snd_messages = raumzeit_send_cancel_message(Request::get('cancel_comment'), $termin); if ($snd_messages > 0) { - $this->course->createInfo(_('Alle Teilnehmenden wurden benachrichtigt.')); + PageLayout::postInfo(_('Alle Teilnehmenden wurden benachrichtigt.')); } } - $this->displayMessages(); $this->redirect('course/timesrooms/index', ['contentbox_open' => $termin->metadate_id]); } @@ -1521,10 +1548,23 @@ class Course_TimesroomsController extends AuthenticatedController } Sidebar::Get()->addWidget($widget); + if ($GLOBALS['perm']->have_perm('admin')) { + $list = new SelectWidget( + _('Veranstaltungen'), + $this->indexURL(), + 'cid' + ); - if ($GLOBALS['perm']->have_studip_perm('admin', $this->course->id)) { - $widget = new CourseManagementSelectWidget(); - Sidebar::get()->addWidget($widget); + foreach (AdminCourseFilter::get()->getCoursesForAdminWidget() as $seminar) { + $list->addElement(new SelectElement( + $seminar['Seminar_id'], + $seminar['Name'], + $seminar['Seminar_id'] === Context::getId(), + $seminar['VeranstaltungsNummer'] . ' ' . $seminar['Name'] + )); + } + $list->size = 8; + Sidebar::Get()->addWidget($list); } } @@ -1559,20 +1599,6 @@ class Course_TimesroomsController extends AuthenticatedController } /** - * Displays messages. - * - * @param Array $messages Messages to display (optional, defaults to - * potential stored messages on course object) - */ - private function displayMessages(array $messages = []) - { - $messages = $messages ?: $this->course->getStackedMessages(); - foreach ((array)$messages as $type => $msg) { - PageLayout::postMessage(MessageBox::$type($msg['title'], $msg['details'])); - } - } - - /** * Deletes a date. * * @param CourseDate $termin CourseDate of the date @@ -1602,23 +1628,32 @@ class Course_TimesroomsController extends AuthenticatedController } if ($has_topics) { - $this->course->createMessage(sprintf( - _('Dem Termin %s war ein Thema zugeordnet. Sie können das Thema im %sAblaufplan%s einem anderen Termin (z.B. einem Ausweichtermin) zuordnen.'), - htmlReady($termin_date), - '', '' - )); + PageLayout::postSuccess( + sprintf( + _('Dem Termin %s war ein Thema zugeordnet. Sie können das Thema im Ablaufplan einem anderen Termin (z.B. einem Ausweichtermin) zuordnen.'), + htmlReady($termin_date) + ), + [ + sprintf( + '%s', + URLHelper::getLink('dispatch.php/course/topics'), + _('Zum Ablaufplan') + ) + ] + ); } if ($termin_room) { - $this->course->createMessage(sprintf( - _('Der Termin %s wurde gelöscht! Die Buchung für den Raum %s wurde gelöscht.'), - htmlReady($termin_date), - htmlReady($termin_room) - )); + PageLayout::postSuccess( + studip_interpolate( + _('Der Termin %{date} wurde gelöscht! Die Buchung für den Raum %{room} wurde gelöscht.'), + [ + 'date' => htmlReady($termin_date), + 'room' => htmlReady($termin_room) + ] + ) + ); } else { - $this->course->createMessage(sprintf( - _('Der Termin %s wurde gelöscht!'), - htmlReady($termin_date) - )); + PageLayout::postSuccess(_('Der Termin %s wurde gelöscht!'), htmlReady($termin_date)); } return $termin; @@ -1657,9 +1692,9 @@ class Course_TimesroomsController extends AuthenticatedController /** * Restores a previously stored request from trails' flash object */ - private function restoreRequest(array $fields, $request = null) + private function restoreRequest(array $fields) { - $request = $this->flash['request'] ?? $request; + $request = $this->flash['request']; if ($request) { foreach ($fields as $field) { @@ -1719,7 +1754,7 @@ class Course_TimesroomsController extends AuthenticatedController } else { $user_rooms = RoomManager::getUserRooms($current_user); foreach ($user_rooms as $room) { - if ($room->userHasBookingRights($current_user, $begin ?? null, $end ?? null)) { + if ($room->userHasBookingRights($current_user, $begin, $end)) { $rooms_with_booking_permissions++; if ($only_bookable_rooms) { foreach ($all_time_intervals as $interval) { diff --git a/app/controllers/course/topics.php b/app/controllers/course/topics.php index 2d97490..36e25ec 100644 --- a/app/controllers/course/topics.php +++ b/app/controllers/course/topics.php @@ -17,9 +17,9 @@ class Course_TopicsController extends AuthenticatedController Navigation::activateItem('/course/schedule/topics'); PageLayout::setTitle(sprintf('%s - %s', Course::findCurrent()->getFullName(), _("Themen"))); - $seminar = new Seminar(Course::findCurrent()); - $this->forum_activated = $seminar->getSlotModule('forum'); - $this->documents_activated = $seminar->getSlotModule('documents'); + $course = Course::findCurrent(); + $this->forum_activated = $course->isToolActive(CoreForum::class); + $this->documents_activated = $course->isToolActive(CoreDocuments::class); if ($action !== 'index' && !$GLOBALS['perm']->have_studip_perm('tutor', Context::getId())) { throw new AccessDeniedException(); diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php index e17fc91..d21f2d5 100644 --- a/app/controllers/my_courses.php +++ b/app/controllers/my_courses.php @@ -377,13 +377,13 @@ class MyCoursesController extends AuthenticatedController */ public function decline_action($course_id, $waiting = null) { - $current_seminar = Seminar::getInstance($course_id); + $course = Course::find($course_id); $ticket_check = Seminar_Session::check_ticket(Request::option('studipticket')); if (LockRules::Check($course_id, 'participants')) { $lockdata = LockRules::getObjectRule($course_id); PageLayout::postError(sprintf( _('Sie können sich nicht von der Veranstaltung %s abmelden.'), - htmlReady($current_seminar->name) + htmlReady($course->name) )); if ($lockdata['description']) { PageLayout::postInfo(formatLinks($lockdata['description'])); @@ -393,7 +393,6 @@ class MyCoursesController extends AuthenticatedController } // Ensure last teacher cannot leave course - $course = Course::find($course_id); $teacher = $course->members->findOneBy('user_id', User::findCurrent()->id); if ( $teacher @@ -402,7 +401,7 @@ class MyCoursesController extends AuthenticatedController ) { PageLayout::postError(sprintf( _('Sie können sich nicht von der Veranstaltung %s abmelden.'), - htmlReady($current_seminar->name) + htmlReady($course->name) )); $this->redirect('my_courses/index'); return; @@ -414,45 +413,49 @@ class MyCoursesController extends AuthenticatedController } if (Request::option('cmd') != 'kill' && Request::option('cmd') != 'kill_admission') { - if ($current_seminar->admission_binding && Request::get('cmd') != 'suppose_to_kill_admission' && !LockRules::Check($current_seminar->getId(), 'participants')) { + if ( + $course->admission_binding + && Request::get('cmd') != 'suppose_to_kill_admission' + && !LockRules::Check($course->id, 'participants') + ) { PageLayout::postError(sprintf(_("Die Veranstaltung %s ist als bindend angelegt. Wenn Sie sich abmelden wollen, müssen Sie sich an die Lehrende der Veranstaltung wenden."), - htmlReady($current_seminar->name))); + htmlReady($course->name))); $this->redirect('my_courses/index'); return; } if (Request::get('cmd') == 'suppose_to_kill') { // check course admission - list(,$admission_end_time) = @array_values($current_seminar->getAdmissionTimeFrame()); + list(,$admission_end_time) = @array_values($course->getAdmissionTimeFrame()); - $admission_enabled = $current_seminar->isAdmissionEnabled(); - $admission_locked = $current_seminar->isAdmissionLocked(); + $admission_enabled = $course->isAdmissionEnabled(); + $admission_locked = $course->isAdmissionLocked(); - if ($admission_enabled || $admission_locked || (int)$current_seminar->admission_prelim == 1) { + if ($admission_enabled || $admission_locked || (int) $course->admission_prelim === 1) { $message = sprintf( _('Wollen Sie sich von der teilnahmebeschränkten Veranstaltung "%s" wirklich abmelden? Sie verlieren damit die Berechtigung für die Veranstaltung und müssen sich ggf. neu anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else if (isset($admission_end_time) && $admission_end_time < time()) { $message = sprintf( _('Wollen Sie sich von der teilnahmebeschränkten Veranstaltung "%s" wirklich abmelden? Der Anmeldezeitraum ist abgelaufen und Sie können sich nicht wieder anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else { - $message = sprintf(_('Wollen Sie sich von der Veranstaltung "%s" wirklich abmelden?'), htmlReady($current_seminar->name)); + $message = sprintf(_('Wollen Sie sich von der Veranstaltung "%s" wirklich abmelden?'), htmlReady($course->name)); } $cmd = 'kill'; } else { if (AdmissionApplication::checkMemberPosition($GLOBALS['user']->id, $course_id) === false) { $message = sprintf( _('Wollen Sie sich von der Anmeldeliste der Veranstaltung "%s" wirklich abmelden?'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else { $message = sprintf( _('Wollen Sie sich von der Warteliste der Veranstaltung "%s" wirklich abmelden? Sie verlieren damit die bereits erreichte Position und müssen sich ggf. neu anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } $cmd = 'kill_admission'; @@ -489,13 +492,13 @@ class MyCoursesController extends AuthenticatedController AdmissionApplication::addMembers($course_id); // If this course is a child of another course... - if ($current_seminar->parent_course) { + if ($course->parent) { // ... check if user is member in another sibling ... $other = CourseMember::findBySQL( "`user_id` = :user AND `Seminar_id` IN (:courses) AND `Seminar_id` != :this", [ 'user' => $GLOBALS['user']->id, - 'courses' => $current_seminar->parent->children->pluck('seminar_id'), + 'courses' => $course->parent->children->pluck('seminar_id'), 'this' => $course_id ] ); @@ -503,7 +506,7 @@ class MyCoursesController extends AuthenticatedController // ... and delete from parent course if this was the only // course membership in this family. if (count($other) == 0) { - $m = CourseMember::find([$current_seminar->parent_course, $GLOBALS['user']->id]); + $m = CourseMember::find([$course->parent_course, $GLOBALS['user']->id]); if ($m) { $m->delete(); } @@ -512,14 +515,14 @@ class MyCoursesController extends AuthenticatedController PageLayout::postSuccess(sprintf( _("Erfolgreich von Veranstaltung %s abgemeldet."), - htmlReady($current_seminar->name) + htmlReady($course->name) )); } } else { // LOGGING StudipLog::log('SEM_USER_DEL', $course_id, $GLOBALS['user']->id, 'Hat sich selbst aus der Warteliste ausgetragen'); - if ($current_seminar->isAdmissionEnabled()) { - $prio_delete = AdmissionPriority::unsetPriority($current_seminar->getCourseSet()->getId(), $GLOBALS['user']->id, $course_id); + if ($course->isAdmissionEnabled()) { + $prio_delete = AdmissionPriority::unsetPriority($course->getCourseSet()->getId(), $GLOBALS['user']->id, $course_id); } NotificationCenter::postNotification('UserDidLeaveWaitingList', $course_id, $GLOBALS['user']->id); $deleted = AdmissionApplication::deleteBySQL( @@ -533,7 +536,7 @@ class MyCoursesController extends AuthenticatedController AdmissionApplication::addMembers($course_id); PageLayout::postSuccess(sprintf( _("Der Eintrag in der Anmelde- bzw. Warteliste der Veranstaltung %s wurde aufgehoben. Wenn Sie an der Veranstaltung teilnehmen wollen, müssen Sie sich erneut bewerben."), - htmlReady($current_seminar->name) + htmlReady($course->name) )); } } diff --git a/app/controllers/tree.php b/app/controllers/tree.php index 655e717..e87f134 100644 --- a/app/controllers/tree.php +++ b/app/controllers/tree.php @@ -21,7 +21,6 @@ class TreeController extends AuthenticatedController $data = []; foreach ($courses as $course) { - $sem = Seminar::getInstance($course->id); $lecturers = SimpleCollection::createFromArray( CourseMember::findByCourseAndStatus($course->id, 'dozent') )->orderBy('position, nachname, vorname'); @@ -37,7 +36,7 @@ class TreeController extends AuthenticatedController $course->veranstaltungsnummer, $course->getFullName('type-number-name'), $course->getTextualSemester(), - $sem->getDatesExport(), + implode("\n", $course->getAllDatesInSemester()->toStringArray()), implode(', ', $lecturersSorted) ]; } diff --git a/app/views/calendar/schedule/_entry_course.php b/app/views/calendar/schedule/_entry_course.php index ece5392..f600218 100644 --- a/app/views/calendar/schedule/_entry_course.php +++ b/app/views/calendar/schedule/_entry_course.php @@ -1,5 +1,5 @@

- getNumber()) ?> + veranstaltungsnummer) ?>

- getName()) ?> + name) ?>

- getMembers('dozent') as $dozent) :?> - 0) echo ', '; ?> - - + id, 'dozent'); + foreach ($lecturers as $lecturer) :?> + 0 ? ', ' : '' ?> + + user->getFullName()) ?> @@ -45,7 +47,7 @@ $sem = Seminar::getInstance($show_entry['id']);

- getDatesHTML(['show_room' => true]) ?>
+ getAllDatesInSemester()->toHtml(true) ?>
diff --git a/app/views/calendar/schedule/_entry_inst.php b/app/views/calendar/schedule/_entry_inst.php index fb9435b..228751f 100644 --- a/app/views/calendar/schedule/_entry_inst.php +++ b/app/views/calendar/schedule/_entry_inst.php @@ -15,38 +15,38 @@ - + - getNumber()) ?> + veranstaltungsnummer) ?> - + - getName()) ?> + name) ?> - + id, $start, $end, $day) ?> toString() ?> - getId(), $cycle->getMetadateId()) ?> + id, $cycle->getMetadateId()) ?> url_for('calendar/schedule/adminbind/' . $seminar->getId() . '/' . $cycle->getMetadateId() . '/0'), + $controller->url_for('calendar/schedule/adminbind/' . $course->id . '/' . $cycle->getMetadateId() . '/0'), [ - 'id' => $seminar->getId() . '_' . $cycle->getMetadateId() . '_hide', - 'onclick' => "STUDIP.Schedule.instSemUnbind('" . $seminar->getId() . "','" . $cycle->getMetadateId() . "'); return false;", + 'id' => $course->id . '_' . $cycle->getMetadateId() . '_hide', + 'onclick' => "STUDIP.Schedule.instSemUnbind('" . $course->id . "','" . $cycle->getMetadateId() . "'); return false;", 'style' => ($visible ? '' : 'display: none') ]) ?> url_for('calendar/schedule/adminbind/' . $seminar->getId() . '/' . $cycle->getMetadateId() . '/1'), + $controller->url_for('calendar/schedule/adminbind/' . $course->id . '/' . $cycle->getMetadateId() . '/1'), [ - 'id' => $seminar->getId() . '_' . $cycle->getMetadateId() . '_show', - 'onclick' => "STUDIP.Schedule.instSemBind('" . $seminar->getId() . "','" . $cycle->getMetadateId() . "'); return false;", + 'id' => $course->id . '_' . $cycle->getMetadateId() . '_show', + 'onclick' => "STUDIP.Schedule.instSemBind('" . $course->id . "','" . $cycle->getMetadateId() . "'); return false;", 'style' => ($visible ? 'display: none' : '') ]) ?>
diff --git a/app/views/course/cancel_dates/index.php b/app/views/course/cancel_dates/index.php index 4f3e297..0bb1138 100644 --- a/app/views/course/cancel_dates/index.php +++ b/app/views/course/cancel_dates/index.php @@ -6,7 +6,7 @@
toString(); + return $d->getFullName(); }, $dates)); ?>
@@ -21,9 +21,9 @@ - + - +