aboutsummaryrefslogtreecommitdiff
path: root/lib/models/Course.class.php
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/models/Course.class.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/models/Course.class.php')
-rw-r--r--lib/models/Course.class.php1173
1 files changed, 0 insertions, 1173 deletions
diff --git a/lib/models/Course.class.php b/lib/models/Course.class.php
deleted file mode 100644
index 59f9b82..0000000
--- a/lib/models/Course.class.php
+++ /dev/null
@@ -1,1173 +0,0 @@
-<?php
-/**
- * Course.class.php
- * model class for table seminare
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * @author André Noack <noack@data-quest.de>
- * @copyright 2012 Stud.IP Core-Group
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- *
- * @property string $id alias column for seminar_id
- * @property string $seminar_id database column
- * @property string|null $veranstaltungsnummer database column
- * @property string $institut_id database column
- * @property I18NString $name database column
- * @property I18NString|null $untertitel database column
- * @property int $status database column
- * @property I18NString $beschreibung database column
- * @property I18NString|null $ort database column
- * @property string|null $sonstiges database column
- * @property int $lesezugriff database column
- * @property int $schreibzugriff database column
- * @property int|null $start_time database column
- * @property int|null $duration_time database column
- * @property I18NString|null $art database column
- * @property I18NString|null $teilnehmer database column
- * @property I18NString|null $vorrausetzungen database column
- * @property I18NString|null $lernorga database column
- * @property I18NString|null $leistungsnachweis database column
- * @property int $mkdate database column
- * @property int $chdate database column
- * @property string|null $ects database column
- * @property int|null $admission_turnout database column
- * @property int|null $admission_binding database column
- * @property int $admission_prelim database column
- * @property string|null $admission_prelim_txt database column
- * @property int $admission_disable_waitlist database column
- * @property int $visible database column
- * @property int|null $showscore database column
- * @property string|null $aux_lock_rule database column
- * @property int $aux_lock_rule_forced database column
- * @property string|null $lock_rule database column
- * @property int $admission_waitlist_max database column
- * @property int $admission_disable_waitlist_move database column
- * @property int $completion database column
- * @property string|null $parent_course database column
- * @property SimpleORMapCollection|CourseTopic[] $topics has_many CourseTopic
- * @property SimpleORMapCollection|CourseDate[] $dates has_many CourseDate
- * @property SimpleORMapCollection|CourseExDate[] $ex_dates has_many CourseExDate
- * @property SimpleORMapCollection|CourseMember[] $members has_many CourseMember
- * @property SimpleORMapCollection|Deputy[] $deputies has_many Deputy
- * @property SimpleORMapCollection|Statusgruppen[] $statusgruppen has_many Statusgruppen
- * @property SimpleORMapCollection|AdmissionApplication[] $admission_applicants has_many AdmissionApplication
- * @property SimpleORMapCollection|DatafieldEntryModel[] $datafields has_many DatafieldEntryModel
- * @property SimpleORMapCollection|SeminarCycleDate[] $cycles has_many SeminarCycleDate
- * @property SimpleORMapCollection|BlubberThread[] $blubberthreads has_many BlubberThread
- * @property SimpleORMapCollection|ConsultationBlock[] $consultation_blocks has_many ConsultationBlock
- * @property SimpleORMapCollection|RoomRequest[] $room_requests has_many RoomRequest
- * @property SimpleORMapCollection|Course[] $children has_many Course
- * @property SimpleORMapCollection|ToolActivation[] $tools has_many ToolActivation
- * @property SimpleORMapCollection|CourseMemberNotification[] $member_notifications has_many CourseMemberNotification
- * @property SimpleORMapCollection|Courseware\Unit[] $courseware_units has_many Courseware\Unit
- * @property Institute $home_institut belongs_to Institute
- * @property AuxLockRule|null $aux belongs_to AuxLockRule
- * @property Course|null $parent belongs_to Course
- * @property SimpleORMapCollection|Semester[] $semesters has_and_belongs_to_many Semester
- * @property SimpleORMapCollection|StudipStudyArea[] $study_areas has_and_belongs_to_many StudipStudyArea
- * @property SimpleORMapCollection|Institute[] $institutes has_and_belongs_to_many Institute
- * @property SimpleORMapCollection|UserDomain[] $domains has_and_belongs_to_many UserDomain
- * @property-read mixed $teachers additional field
- * @property mixed $end_time additional field
- * @property mixed $start_semester additional field
- * @property mixed $end_semester additional field
- * @property-read mixed $semester_text additional field
- * @property-read mixed $config additional field
- */
-
-class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, FeedbackRange, Studip\Calendar\Owner
-{
- protected static function configure($config = [])
- {
- $config['db_table'] = 'seminare';
- $config['has_many']['topics'] = [
- 'class_name' => CourseTopic::class,
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['dates'] = [
- 'class_name' => CourseDate::class,
- 'assoc_foreign_key' => 'range_id',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- 'order_by' => 'ORDER BY date'
- ];
- $config['has_many']['ex_dates'] = [
- 'class_name' => CourseExDate::class,
- 'assoc_foreign_key' => 'range_id',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['members'] = [
- 'class_name' => CourseMember::class,
- 'assoc_func' => 'findByCourse',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['deputies'] = [
- 'class_name' => Deputy::class,
- 'assoc_func' => 'findByRange_id',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['statusgruppen'] = [
- 'class_name' => Statusgruppen::class,
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['admission_applicants'] = [
- 'class_name' => AdmissionApplication::class,
- 'assoc_func' => 'findByCourse',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['datafields'] = [
- 'class_name' => DatafieldEntryModel::class,
- 'assoc_func' => 'findByModel',
- 'assoc_foreign_key' => function ($model, $params) {
- $model->setValue('range_id', $params[0]->id);
- },
- 'foreign_key' => function ($course) {
- return [$course];
- },
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['cycles'] = [
- 'class_name' => SeminarCycleDate::class,
- 'assoc_func' => 'findBySeminar',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['blubberthreads'] = [
- 'class_name' => BlubberThread::class,
- 'assoc_func' => 'findBySeminar',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_many']['consultation_blocks'] = [
- 'class_name' => ConsultationBlock::class,
- 'assoc_foreign_key' => 'range_id',
- 'on_delete' => 'delete',
- ];
-
- $config['has_and_belongs_to_many']['semesters'] = [
- 'class_name' => Semester::class,
- 'thru_table' => 'semester_courses',
- 'thru_key' => 'course_id',
- 'thru_assoc_key' => 'semester_id',
- 'order_by' => 'ORDER BY beginn ASC',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
-
- $config['belongs_to']['home_institut'] = [
- 'class_name' => Institute::class,
- 'foreign_key' => 'institut_id',
- 'assoc_func' => 'find',
- ];
- $config['belongs_to']['aux'] = [
- 'class_name' => AuxLockRule::class,
- 'foreign_key' => 'aux_lock_rule',
- ];
- $config['has_and_belongs_to_many']['study_areas'] = [
- 'class_name' => StudipStudyArea::class,
- 'thru_table' => 'seminar_sem_tree',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
- $config['has_and_belongs_to_many']['institutes'] = [
- 'class_name' => Institute::class,
- 'thru_table' => 'seminar_inst',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- ];
-
- $config['has_and_belongs_to_many']['domains'] = [
- 'class_name' => UserDomain::class,
- 'thru_table' => 'seminar_userdomains',
- 'on_delete' => 'delete',
- 'on_store' => 'store',
- 'order_by' => 'ORDER BY name',
- ];
-
- $config['has_many']['room_requests'] = [
- 'class_name' => RoomRequest::class,
- 'assoc_foreign_key' => 'course_id',
- 'on_delete' => 'delete',
- ];
- $config['belongs_to']['parent'] = [
- 'class_name' => Course::class,
- 'foreign_key' => 'parent_course'
- ];
- $config['has_many']['children'] = [
- 'class_name' => Course::class,
- 'assoc_foreign_key' => 'parent_course',
- 'order_by' => 'GROUP BY seminar_id ORDER BY VeranstaltungsNummer, Name'
- ];
- $config['has_many']['tools'] = [
- 'class_name' => ToolActivation::class,
- 'assoc_foreign_key' => 'range_id',
- 'order_by' => 'ORDER BY position',
- 'on_delete' => 'delete',
- ];
- $config['has_many']['member_notifications'] = [
- 'class_name' => CourseMemberNotification::class,
- 'on_delete' => 'delete',
- ];
-
- $config['has_many']['courseware_units'] = [
- 'class_name' => \Courseware\Unit::class,
- 'assoc_foreign_key' => 'range_id',
- 'on_delete' => 'delete',
- ];
-
- $config['default_values']['lesezugriff'] = 1;
- $config['default_values']['schreibzugriff'] = 1;
- $config['default_values']['duration_time'] = 0;
-
- $config['additional_fields']['teachers'] = [
- 'get' => 'getTeachers'
- ];
- $config['additional_fields']['end_time'] = true;
-
- $config['additional_fields']['start_semester'] = [
- 'get' => 'getStartSemester',
- 'set' => '_set_semester'
- ];
- $config['additional_fields']['end_semester'] = [
- 'get' => 'getEndSemester',
- 'set' => '_set_semester'
- ];
- $config['additional_fields']['semester_text'] = [
- 'get' => 'getTextualSemester'
- ];
-
- $config['additional_fields']['config'] = [
- 'get' => function (Course $course) {
- return $course->getConfiguration();
- }
- ];
-
- $config['notification_map']['after_create'] = 'CourseDidCreateOrUpdate';
- $config['notification_map']['after_store'] = 'CourseDidCreateOrUpdate';
-
- $config['i18n_fields']['name'] = true;
- $config['i18n_fields']['untertitel'] = true;
- $config['i18n_fields']['beschreibung'] = true;
- $config['i18n_fields']['art'] = true;
- $config['i18n_fields']['teilnehmer'] = true;
- $config['i18n_fields']['vorrausetzungen'] = true;
- $config['i18n_fields']['lernorga'] = true;
- $config['i18n_fields']['leistungsnachweis'] = true;
- $config['i18n_fields']['ort'] = true;
-
- $config['registered_callbacks']['before_update'][] = 'logStore';
- $config['registered_callbacks']['before_store'][] = 'cbSetStartAndDurationTime';
- $config['registered_callbacks']['after_create'][] = 'setDefaultTools';
- $config['registered_callbacks']['after_delete'][] = function ($course) {
- CourseAvatar::getAvatar($course->id)->reset();
- FeedbackElement::deleteBySQL('course_id = ?', [$course->id]);
- // Remove subcourse relations, leaving subcourses intact.
- DBManager::get()->execute(
- "UPDATE `seminare` SET `parent_course` = NULL WHERE `parent_course` = :course",
- ['course' => $course->id]
- );
- DBManager::get()->execute(
- "DELETE FROM `forum_visits` WHERE `seminar_id` = ?",
- [$course->id]
- );
- };
-
- parent::configure($config);
- }
-
-
- /**
- * Returns the currently active course or false if none is active.
- *
- * @return Course object of currently active course, null otherwise
- * @since 3.0
- */
- public static function findCurrent()
- {
- if (Context::isCourse()) {
- return Context::get();
- }
-
- return null;
- }
-
- /**
- * Returns the associated mvv modules for a given course id.
- *
- * @param string $course_id
- * @return Modul[]
- */
- public static function getMVVModulesForCourseId(string $course_id): array
- {
- $query = "SELECT mvv_modul.*
- FROM mvv_lvgruppe_seminar
- JOIN `mvv_lvgruppe` on(`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe`.`lvgruppe_id`)
- JOIN `mvv_lvgruppe_modulteil` on(`mvv_lvgruppe_seminar`.`lvgruppe_id` = `mvv_lvgruppe_modulteil`.`lvgruppe_id`)
- JOIN `mvv_modulteil` on(`mvv_lvgruppe_modulteil`.`modulteil_id` = `mvv_modulteil`.`modulteil_id`)
- JOIN `mvv_modul` on(`mvv_modulteil`.`modul_id` = `mvv_modul`.`modul_id`)
- WHERE seminar_id = ?";
- return DBManager::get()->fetchAll($query, [$course_id], function ($row) {
- return Modul::buildExisting($row);
- });
- }
-
- public function getEnd_Time()
- {
- return $this->duration_time == -1 ? -1 : $this->start_time + $this->duration_time;
- }
-
- public function setEnd_Time($value)
- {
- if ($value == -1) {
- $this->duration_time = -1;
- } elseif ($this->start_time > 0 && $value > $this->start_time) {
- $this->duration_time = $value - $this->start_time;
- } else {
- $this->duration_time = 0;
- }
- }
-
- public function _set_semester($field, $value)
- {
- $method = 'set' . ($field === 'start_semester' ? 'StartSemester' : 'EndSemester');
- $this->$method($value);
- }
-
- /**
- * @param Semester $semester
- */
- public function setStartSemester(Semester $semester)
- {
- $end_semester = $this->semesters->last();
- $start_semester = $this->semesters->first();
- if ($start_semester && $start_semester->id === $semester->id) {
- return;
- }
- if ($end_semester) {
- if (count($this->semesters) > 1 && $end_semester->beginn < $semester->beginn) {
- throw new InvalidArgumentException('start-semester must start before end-semester');
- }
- foreach ($this->semesters as $key => $one_semester) {
- if ($one_semester->beginn < $semester->beginn) {
- $this->semesters->offsetUnset($key);
- }
- }
- }
- $this->semesters[] = $semester;
- $this->semesters->orderBy('beginn asc');
- //add possibly missing semesters between start_semester and end_semester
- if (count($this->semesters) > 1 && $semester->beginn < $start_semester->beginn) {
- $this->setEndSemester($end_semester);
- }
- }
-
- /**
- * @param Semester|null $semester
- */
- public function setEndSemester(?Semester $semester)
- {
- $end_semester = $this->semesters->last();
- $start_semester = $this->semesters->first();
- if (
- (is_null($end_semester) && is_null($semester))
- || ($end_semester && $semester && $end_semester->id === $semester->id)) {
- return;
- }
- if ($start_semester) {
- if ($semester && $start_semester->beginn > $semester->beginn) {
- throw new InvalidArgumentException('end-semester must start after start-semester');
- }
- $this->semesters = [];
- if ($semester) {
- $all_semester = SimpleCollection::createFromArray(Semester::getAll());
- $this->semesters = $all_semester->findBy('beginn', [$start_semester->beginn, $semester->beginn], '>=<=');
- }
- } else {
- if ($semester) {
- $this->semesters[] = $semester;
- }
- }
- }
-
- /**
- * Retrieves the first semester of a course, if applicable.
- *
- * @returns Semester|null Either the first semester of the course
- * or null, if no semester could be found.
- */
- public function getStartSemester()
- {
- if (count($this->semesters) > 0) {
- return $this->semesters->first();
- } else {
- return Semester::findCurrent();
- }
- }
-
- /**
- * Retrieves the last semester of a course, if applicable.
- *
- * @returns Semester|null Either the last semester of the course
- * or null, if no semester could be found.
- */
- public function getEndSemester()
- {
- if (count($this->semesters) > 0) {
- return $this->semesters->last();
- }
- }
-
- /**
- * Returns the readable semester duration as as string
- * @return string : readable semester
- */
- public function getTextualSemester()
- {
- if (count($this->semesters) > 1) {
- return $this->start_semester->short_name . ' - ' . $this->end_semester->short_name;
- } elseif (count($this->semesters) === 1) {
- return $this->start_semester->short_name;
- } else {
- return _('unbegrenzt');
- }
- }
-
- /**
- * Returns true if this course has no end-semester. Else false.
- * @return bool : true if there is no end-semester
- */
- public function isOpenEnded()
- {
- return count($this->semesters) === 0;
- }
-
- /**
- * Returns if this course is in the given semester
- * @param Semester $semester : instance of the given semester
- * @return bool : true if this course is part of this semester
- */
- public function isInSemester(Semester $semester)
- {
- if (count($this->semesters) > 0) {
- foreach ($this->semesters as $s) {
- if ($s->id === $semester->id) {
- return true;
- }
- }
- return false;
- } else {
- return true;
- }
- }
-
- public function getTeachers()
- {
- return $this->members->filter(function ($m) {
- return $m['status'] === 'dozent';
- });
- }
-
- public function getFreeSeats()
- {
- $free_seats = $this->admission_turnout - $this->getNumParticipants();
- return max($free_seats, 0);
- }
-
- public function isWaitlistAvailable()
- {
- if ($this->admission_disable_waitlist) {
- return false;
- }
-
- if ($this->admission_waitlist_max) {
- return $this->admission_waitlist_max - $this->getNumWaiting() > 0;
- }
-
- return true;
- }
-
- /**
- * Retrieves all members of a status
- *
- * @param String|Array $status the status to filter with
- * @param bool $as_collection return collection instead of array?
- * @return Array|SimpleCollection an array of all those members.
- */
- public function getMembersWithStatus($status, $as_collection = false)
- {
- $result = CourseMember::findByCourseAndStatus($this->id, $status);
- return $as_collection
- ? SimpleCollection::createFromArray($result)
- : $result;
- }
-
- /**
- * Retrieves the number of all members of a status
- *
- * @param String|Array $status the status to filter with
- *
- * @return int the number of all those members.
- */
- public function countMembersWithStatus($status)
- {
- return CourseMember::countByCourseAndStatus($this->id, $status);
- }
-
- public function getNumParticipants()
- {
- return $this->countMembersWithStatus('user autor') + $this->getNumPrelimParticipants();
- }
-
- public function getNumPrelimParticipants()
- {
- return AdmissionApplication::countBySql(
- "seminar_id = ? AND status = 'accepted'",
- [$this->id]
- );
- }
-
- public function getNumWaiting()
- {
- return AdmissionApplication::countBySql(
- "seminar_id = ? AND status = 'awaiting'",
- [$this->id]
- );
- }
-
- public function getParticipantStatus($user_id)
- {
- $p_status = $this->members->findBy('user_id', $user_id)->val('status');
- if (!$p_status) {
- $p_status = $this->admission_applicants->findBy('user_id', $user_id)->val('status');
- }
- return $p_status;
- }
-
- /**
- * Returns the semType object that is defined for the course
- *
- * @return SemType The semTypeObject for the course
- */
- public function getSemType()
- {
- $semTypes = SemType::getTypes();
- if (isset($semTypes[$this->status])) {
- return $semTypes[$this->status];
- }
-
- Log::error(sprintf('SemType not found id:%s status:%s', $this->id, $this->status));
- return new SemType(['name' => 'Fehlerhafter Veranstaltungstyp']);
- }
-
- /**
- * Returns the SemClass object that is defined for the course
- *
- * @return SemClass The SemClassObject for the course
- */
- public function getSemClass()
- {
- return $this->getSemType()->getClass();
- }
-
- /**
- * Returns the full name of a course. If the important course numbers
- * (IMPORTANT_SEMNUMBER) is set in global configs it will also display
- * the coursenumber
- *
- * @param string formatting template name
- * @return string Fullname
- */
- public function getFullName($format = 'default')
- {
- $template = [
- 'name' => '%1$s',
- 'name-semester' => '%1$s (%4$s)',
- 'number-name' => '%3$s %1$s',
- 'number-name-semester' => '%3$s %1$s (%4$s)',
- 'number-type-name' => '%3$s %2$s: %1$s',
- 'sem-duration-name' => '%4$s',
- 'type-name' => '%2$s: %1$s',
- 'type-number-name' => '%2$s: %3$s %1$s',
- ];
-
- if ($format === 'default' || !isset($template[$format])) {
- $format = Config::get()->IMPORTANT_SEMNUMBER ? 'type-number-name' : 'type-name';
- }
- $sem_type = $this->getSemType();
- $data[0] = $this->name;
- $data[1] = $sem_type['name'];
- $data[2] = $this->veranstaltungsnummer;
- $data[3] = $this->getTextualSemester();
- return trim(vsprintf($template[$format], array_map('trim', $data)));
- }
-
-
- /**
- * Retrieves the course dates including cancelled dates ("ex-dates").
- * The dates can be filtered by an optional time range. By default,
- * all dates are retrieved.
- *
- * @param int $range_begin The begin timestamp of the time range.
- *
- * @param int $range_end The end timestamp of the time range.
- *
- * @returns SimpleCollection A collection of all retrieved dates and
- * cancelled dates.
- */
- public function getDatesWithExdates($range_begin = 0, $range_end = 0)
- {
- $dates = [];
- if (($range_begin > 0) && ($range_end > 0) && ($range_end > $range_begin)) {
- $ex_dates = $this->ex_dates->findBy('content', '', '<>')
- ->findBy('date', $range_begin, '>=')
- ->findBy('end_time', $range_end, '<=');
- $dates = $this->dates->findBy('date', $range_begin, '>=')
- ->findBy('end_time', $range_end, '<=');
- $dates->merge($ex_dates);
- } else {
- $dates = $this->ex_dates->findBy('content', '', '<>');
- $dates->merge($this->dates);
- }
- $dates->uasort(function($a, $b) {
- return $a->date - $b->date
- ?: strnatcasecmp($a->getRoomName(), $b->getRoomName());
- });
- return $dates;
- }
-
- /**
- * Sets this courses study areas to the given values.
- *
- * @param array $ids the new study areas
- * @return bool Changes successfully saved?
- */
- public function setStudyAreas($ids)
- {
- $old = $this->study_areas->pluck('sem_tree_id');
- $added = array_diff($ids, $old);
- $removed = array_diff($old, $ids);
- $success = false;
- if ($added || $removed) {
-
- $this->study_areas = SimpleCollection::createFromArray(StudipStudyArea::findMany($ids));
-
- if ($this->store()) {
- NotificationCenter::postNotification('CourseDidChangeStudyArea', $this);
- $success = true;
-
- foreach ($added as $one) {
- StudipLog::log('SEM_ADD_STUDYAREA', $this->id, $one);
-
- $area = $this->study_areas->find($one);
- if ($area->isModule()) {
- NotificationCenter::postNotification(
- 'CourseAddedToModule',
- $area,
- ['module_id' => $one, 'course_id' => $this->id]
- );
- }
- }
-
- foreach ($removed as $one) {
- StudipLog::log('SEM_DELETE_STUDYAREA', $this->id, $one);
-
- $area = StudipStudyArea::find($one);
- if ($area->isModule()) {
- NotificationCenter::postNotification(
- 'CourseRemovedFromModule',
- $area,
- ['module_id' => $one, 'course_id' => $this->id]
- );
- }
- }
- }
- }
-
- return $success;
- }
-
- /**
- * Is the current course visible for the current user?
- * @param string $user_id
- * @return bool Visible?
- */
- public function isVisibleForUser($user_id = null)
- {
- return $this->visible
- || $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM, $user_id)
- || $GLOBALS['perm']->have_studip_perm('user', $this->id, $user_id);
- }
-
- /**
- * Returns a descriptive text for the range type.
- *
- * @return string
- */
- public function describeRange()
- {
- return _('Veranstaltung');
- }
-
- /**
- * Returns a unique identificator for the range type.
- *
- * @return string
- */
- public function getRangeType()
- {
- return 'course';
- }
-
- /**
- * Returns the id of the current range
- *
- * @return string
- */
- public function getRangeId()
- {
- return $this->id;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getConfiguration()
- {
- return CourseConfig::get($this);
- }
-
- /**
- * Decides whether the user may access the range.
- *
- * @param string|null $user_id Optional id of a user, defaults to current user
- * @return bool
- * @todo Check permissions
- */
- public function isAccessibleToUser($user_id = null)
- {
- if ($user_id === null) {
- $user_id = $GLOBALS['user']->id;
- }
- return $GLOBALS['perm']->have_studip_perm('user', $this->id, $user_id);
- }
-
- /**
- * Decides whether the user may edit/alter the range.
- *
- * @param string|null $user_id Optional id of a user, defaults to current user
- * @return bool
- * @todo Check permissions
- */
- public function isEditableByUser($user_id = null)
- {
- if ($user_id === null) {
- $user_id = $GLOBALS['user']->id;
- }
- return $GLOBALS['perm']->have_studip_perm('tutor', $this->id, $user_id);
- }
-
- /**
- * Returns the appropriate icon for the completion status.
- *
- * Mapping (completion -> icon role):
- * - 0 => status-red
- * - 1 => status-yellow
- * - 2 => status-green
- *
- * @return Icon class
- */
- public function getCompletionIcon()
- {
- $role = Icon::ROLE_STATUS_RED;
- if ($this->completion == 1) {
- $role = Icon::ROLE_STATUS_YELLOW;
- } elseif ($this->completion == 2) {
- $role = Icon::ROLE_STATUS_GREEN;
- }
- return Icon::create('radiobutton-checked', $role);
- }
-
- /**
- * Returns the appropriate label for the completion status.
- *
- * @return string
- */
- public function getCompetionLabel(): string
- {
- return [
- 0 => _('unvollständig'),
- 1 => _('in Bearbeitung'),
- 2 => _('fertig'),
- ][$this->completion] ?? _('undefiniert');
- }
-
- /**
- * Generates a general log entry if the course were changed.
- * Furthermore, this method emits notifications when the
- * start and/or the end semester has/have changed.
- */
- protected function logStore()
- {
- if ($this->isFieldDirty('start_time')) {
- //Log change of start semester:
- StudipLog::log('SEM_SET_STARTSEMESTER', $this->id, isset($this->start_semester) ? $this->start_semester->name : _('unbegrenzt'));
- NotificationCenter::postNotification('CourseDidChangeSchedule', $this);
- }
- if ($this->isFieldDirty('duration_time')) {
- StudipLog::log('SEM_SET_ENDSEMESTER', $this->id, $this->getTextualSemester());
- NotificationCenter::postNotification('CourseDidChangeSchedule', $this);
- }
-
- $log = [];
- if ($this->isFieldDirty('admission_prelim')) {
- $log[] = $this->admission_prelim ? _('Neuer Anmeldemodus: Vorläufiger Eintrag') : _('Neuer Anmeldemodus: Direkter Eintrag');
- }
-
- if ($this->isFieldDirty('admission_binding')) {
- $log[] = $this->admission_binding? _('Anmeldung verbindlich') : _('Anmeldung unverbindlich');
- }
-
- if ($this->isFieldDirty('admission_turnout')) {
- $log[] = sprintf(_('Neue Teilnehmerzahl: %s'), (int)$this->admission_turnout);
- }
-
- if ($this->isFieldDirty('admission_disable_waitlist')) {
- $log[] = $this->admission_disable_waitlist ? _('Warteliste aktiviert') : _('Warteliste deaktiviert');
- }
-
- if ($this->isFieldDirty('admission_waitlist_max')) {
- $log[] = sprintf(_('Plätze auf der Warteliste geändert: %u'), (int)$this->admission_waitlist_max);
- }
-
- if ($this->isFieldDirty('admission_disable_waitlist_move')) {
- $log[] = $this->admission_disable_waitlist ? _('Nachrücken aktiviert') : _('Nachrücken deaktiviert');
- }
-
- if ($this->isFieldDirty('admission_prelim_txt')) {
- if ($this->admission_prelim_txt) {
- $log[] = sprintf(_('Neuer Hinweistext bei vorläufigen Eintragungen: %s'), strip_tags(kill_format($this->admission_prelim_txt)));
- } else {
- $log[] = _('Hinweistext bei vorläufigen Eintragungen wurde entfert');
- }
- }
-
- if (!empty($log)) {
- StudipLog::log(
- 'SEM_CHANGED_ACCESS',
- $this->id,
- null,
- '',
- implode(' - ', $log)
- );
- }
-
- if ($this->isFieldDirty('visible')) {
- StudipLog::log($this->visible ? 'SEM_VISIBLE' : 'SEM_INVISIBLE', $this->id);
- }
- }
-
- /**
- * Called directly before storing the object to edit the columns start_time and duration_time
- * which are both deprecated but are still in use for older plugins.
- */
- public function cbSetStartAndDurationTime()
- {
- if ($this->isFieldDirty('start_time')) {
- $this->setStartSemester(Semester::findByTimestamp($this->start_time));
- }
- if ($this->isFieldDirty('duration_time')) {
- $this->setEndSemester($this->duration_time == -1 ? null : Semester::findByTimestamp($this->start_time + $this->duration_time));
- }
- if ($this->isOpenEnded()) {
- $this->start_time = $this->start_time ?: Semester::findCurrent()->beginn ?? time();
- $this->duration_time = -1;
- } else {
- $this->start_time = $this->getStartSemester()->beginn;
- $this->duration_time = $this->getEndSemester()->beginn - $this->start_time;
- }
- }
-
-
- //StudipItem interface implementation:
-
- public function getItemName($long_format = true)
- {
- if ($long_format) {
- return $this->getFullName();
- } else {
- return $this->name;
- }
- }
-
- public function getItemURL()
- {
- return URLHelper::getURL(
- 'dispatch.php/course/details/index',
- [
- 'cid' => $this->id
- ]
- );
- }
-
- public function getItemAvatarURL()
- {
- $avatar = CourseAvatar::getAvatar($this->id);
- if ($avatar) {
- return $avatar->getURL(Avatar::NORMAL);
- }
- return '';
- }
-
-
- /**
- * Export available data of a given user into a storage object
- * (an instance of the StoredUserData class) for that user.
- *
- * @param StoredUserData $storage object to store data into
- */
- public static function exportUserData(StoredUserData $storage)
- {
- $sorm = self::findThru($storage->user_id, [
- 'thru_table' => 'seminar_user',
- 'thru_key' => 'user_id',
- 'thru_assoc_key' => 'Seminar_id',
- 'assoc_foreign_key' => 'Seminar_id',
- ]);
- if ($sorm) {
- $field_data = [];
- foreach ($sorm as $row) {
- $field_data[] = $row->toRawArray();
- }
- if ($field_data) {
- $storage->addTabularData(_('Seminare'), 'seminare', $field_data);
- }
- }
- }
- public function getRangeName()
- {
- return $this->name;
- }
-
- public function getRangeIcon($role)
- {
- return Icon::create('seminar', $role);
- }
-
- public function getRangeUrl()
- {
- return 'course/overview';
- }
-
- public function getRangeCourseId()
- {
- return $this->Seminar_id;
- }
-
- public function isRangeAccessible(string $user_id = null): bool
- {
- $user_id = $user_id ?? $GLOBALS['user']->id;
- return $GLOBALS['perm']->have_studip_perm('autor', $this->Seminar_id, $user_id);
- }
-
-
- public function getLink() : StudipLink
- {
- return new StudipLink($this->getItemURL(), $this->name, Icon::create('seminar'));
- }
-
-
- /**
- * Returns a list of courses for the specified user.
- * Permission levels may be supplied to limit the course list.
- *
- * @param string $user_id The ID of the user whose courses shall be retrieved.
- *
- * @param string[] $perms The permission levels of the user that shall be
- * regarded when retrieving courses.
- *
- * @param bool $with_deputies Whether to include courses where the user is
- * a deputy (true) or not (false). Defaults to true.
- *
- * @return Course[] A list of courses.
- */
- public static function findByUser($user_id, $perms = [], $with_deputies = true)
- {
- if (!$user_id) {
- return [];
- }
-
- $db = DBManager::get();
- $sql = "SELECT `seminar_id`
- FROM `seminar_user`
- WHERE `user_id` = :user_id";
- $sql_params = ['user_id' => $user_id];
- if (is_array($perms) && count($perms)) {
- $sql .= ' AND `status` IN (:perms)';
- $sql_params['perms'] = $perms;
- }
- $seminar_ids = $db->fetchFirst($sql, $sql_params);
- if (Config::get()->DEPUTIES_ENABLE && $with_deputies) {
- $sql = 'SELECT range_id FROM `deputies` WHERE `deputies`.`user_id` = :user_id';
- $seminar_ids = array_merge($seminar_ids, $db->fetchFirst($sql, $sql_params));
- }
-
- $name_sort = Config::get()->IMPORTANT_SEMNUMBER ? 'VeranstaltungsNummer, Name' : 'Name';
-
- return Course::findBySQL(
- "LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
- WHERE Seminar_id IN (?)
- GROUP BY seminare.Seminar_id
- ORDER BY semester_courses.semester_id IS NULL DESC, start_time DESC, {$name_sort}",
- [$seminar_ids]
- );
- }
-
- /**
- * Returns whether this course is a studygroup
- * @return bool
- */
- public function isStudygroup()
- {
- return in_array($this->status, studygroup_sem_types());
- }
-
- /**
- *
- */
- public function setDefaultTools()
- {
- $this->tools = [];
- foreach (array_values($this->getSemClass()->getActivatedModuleObjects()) as $module) {
- PluginManager::getInstance()->setPluginActivated($module->getPluginId(), $this->id, true);
- $this->tools[] = ToolActivation::find([$this->id, $module->getPluginId()]);
- }
- }
-
- /**
- * @param $name string name of tool / plugin
- * @return bool
- */
- public function isToolActive($name)
- {
- $plugin = PluginEngine::getPlugin($name);
- return $plugin && $this->tools->findOneby('plugin_id', $plugin->getPluginId());
- }
-
- /**
- * returns all activated plugins/modules for this course
- * @return StudipModule[]
- */
- public function getActivatedTools()
- {
- return array_filter($this->tools->getStudipModule());
- }
-
- /**
- * @see Range::__toString()
- */
- public function __toString() : string
- {
- return $this->getFullName();
- }
-
- /**
- * @inheritDoc
- */
- public static function getCalendarOwner(string $owner_id): ?\Studip\Calendar\Owner
- {
- return self::find($owner_id);
- }
-
- /**
- * @inheritDoc
- */
- public function isCalendarReadable(?string $user_id = null): bool
- {
- if ($user_id === null) {
- $user_id = User::findCurrent()->id;
- }
-
- //Calendar read permissions are granted for all participants
- //that have at least user permissions.
- return $GLOBALS['perm']->have_studip_perm('user', $this->id, $user_id);
- }
-
- /**
- * @inheritDoc
- */
- public function isCalendarWritable(string $user_id = null): bool
- {
- if ($user_id === null) {
- $user_id = User::findCurrent()->id;
- }
-
- //Calendar write permissions are granted for all participants
- //that have autor permissions or higher.
- return $GLOBALS['perm']->have_studip_perm('autor', $this->id, $user_id);
- }
-
- /**
- * Get user information for all users in this course
- *
- */
- public function getMembersData(?string $status = ''): array
- {
- $result = [];
-
- if (!$status) {
- foreach ($this->members->orderBy('position, nachname') as $member) {
- $result[$member->user_id] = $member->getExportData();
- }
- foreach ($this->admission_applicants->findBy('status', 'accepted')->orderBy('position') as $member) {
- $result[$member->user_id] = $member->getExportData();
- }
- } elseif ($status === 'awaiting') {
- foreach ($this->admission_applicants->findBy('status', $status)->orderBy('position') as $member) {
- $result[$member->user_id] = $member->getExportData();
- }
- } elseif ($status === 'claiming') {
- $cs = CourseSet::getSetForCourse($this->id);
- if (is_object($cs) && !$cs->hasAlgorithmRun()) {
- $claiming_users = User::findFullMany(array_keys(AdmissionPriority::getPrioritiesByCourse($cs->getId(), $this->id)), 'ORDER BY nachname');
- foreach ($claiming_users as $claiming_user) {
- $studycourse = [];
- $claiming_user->studycourses->map(function($sc) use (&$studycourse) {
- $studycourse[]= $sc->studycourse->name . ',' . $sc->degree->name . ',' . $sc->semester;
- });
- $export_data = [
- 'status' => $status,
- 'salutation' => $claiming_user->salutation,
- 'Titel' => $claiming_user->title_front,
- 'Vorname' => $claiming_user->vorname,
- 'Nachname' => $claiming_user->nachname,
- 'Titel2' => $claiming_user->title_rear,
- 'username' => $claiming_user->username,
- 'privadr' => $claiming_user->privadr,
- 'privatnr' => $claiming_user->privatnr,
- 'Email' => $claiming_user->email,
- 'Anmeldedatum' => '',
- 'Matrikelnummer' => $claiming_user->matriculation_number,
- 'studiengaenge' => implode(';', $studycourse),
- 'position' => 0,
- ];
- $result[$claiming_user->user_id] = $export_data;
- }
- }
- }
-
- return $result;
- }
-
-}