diff options
| author | Jan-Hendrik Willms <tleilax+github@gmail.com> | 2021-07-22 16:07:19 +0200 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+github@gmail.com> | 2021-07-22 16:19:12 +0200 |
| commit | a3da1483a9e689846179159355badfec8073dbec (patch) | |
| tree | 770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /app/controllers/course/dates.php | |
current code from svn, revision 62608
Diffstat (limited to 'app/controllers/course/dates.php')
| -rw-r--r-- | app/controllers/course/dates.php | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php new file mode 100644 index 0000000..be7b387 --- /dev/null +++ b/app/controllers/course/dates.php @@ -0,0 +1,630 @@ +<?php +require_once 'lib/raumzeit/raumzeit_functions.inc.php'; + +class Course_DatesController extends AuthenticatedController +{ + protected $allow_nobody = true; + + public function before_filter(&$action, &$args) + { + PageLayout::setHelpKeyword('Basis/InVeranstaltungAblauf'); + + parent::before_filter($action, $args); + checkObject(); + $this->studip_module = checkObjectModule('schedule'); + + $this->course = Context::get(); + if ($this->course) { + PageLayout::setTitle($this->course->getFullname() . ' ' . _('Termine')); + } else { + PageLayout::setTitle(_('Termine')); + } + + $this->show_raumzeit = $this->course->getSemClass()->offsetGet('show_raumzeit'); + $this->has_access = $this->hasAccess(); + } + + public function index_action() + { + if ($this->hasAccess() && Request::isPost() && Request::option('termin_id') && Request::get('topic_title')) { + $date = new CourseDate(Request::option('termin_id')); + $seminar_id = $date['range_id']; + $title = Request::get('topic_title'); + $topic = CourseTopic::findByTitle($seminar_id, $title); + if (!$topic) { + $topic = new CourseTopic(); + $topic['title'] = $title; + $topic['seminar_id'] = $seminar_id; + $topic['author_id'] = $GLOBALS['user']->id; + $topic['description'] = ''; + $topic->store(); + } + $success = $date->addTopic($topic); + if ($success) { + PageLayout::postSuccess(_('Thema wurde hinzugefügt.')); + } else { + PageLayout::postInfo(_('Thema war schon mit dem Termin verknüpft.')); + } + } + Navigation::activateItem('/course/schedule/dates'); + + object_set_visit_module($this->studip_module->getPluginId()); + $this->assignLockRulesToTemplate(); + + $this->last_visitdate = object_get_visit($this->course->id, $this->studip_module->getPluginId()); + $semester_id = Request::get('semester_id'); + $semester = null; + if ($semester_id != 'all') { + $semester = Semester::find($semester_id); + } + if (!$semester || ($semester_id == 'all')) { + $this->dates = $this->course->getDatesWithExdates(); + } else { + $this->dates = $this->course->getDatesWithExdates($semester->beginn, $semester->ende); + } + + + // set up sidebar + $sidebar = Sidebar::get(); + + $actions = new ActionsWidget(); + + if (!$this->show_raumzeit && $this->hasAccess()) { + $actions->addLink( + _('Neuer Einzeltermin'), + $this->url_for('course/dates/singledate'), + Icon::create('add') + )->asDialog(); + } + + if (Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent()->id)) { + $actions->addLink( + _('Sitzungsordner anlegen'), + $this->url_for('course/dates/create_folders'), + Icon::create('folder-topic-empty') + )->asDialog('size=auto'); + } + $actions->addLink( + _('Als Doc-Datei runterladen'), + $this->url_for('course/dates/export'), + Icon::create('file-word') + ); + + $actions->addLink( + _('Als CSV-Datei exportieren'), + $this->url_for('course/dates/export_csv'), + Icon::create('file-excel') + ); + $sidebar->addWidget($actions); + + $course_end_time = $this->course->getEnd_Time(); + if (($course_end_time == -1) || ($course_end_time > 0)) { + //The course has more than one semester: + $semester_widget = new SemesterSelectorWidget( + $this->url_for('course/dates/index') + ); + $semester_end_range = $course_end_time; + if ($semester_end_range == -1) { + //The end semester is set to unlimited. + $semester_end_range = PHP_INT_MAX; + } + $semester_widget->includeAll(); + $semester_widget->setRange( + $this->course->start_time, + $semester_end_range + ); + $sidebar->addWidget($semester_widget); + } + + if ($this->show_raumzeit && $this->hasAccess()) { + $actions = new LinksWidget(); + $actions->setTitle(_('Links')); + $actions->addLink(_('Zeiten und Räume bearbeiten'), + $this->url_for('course/timesrooms'), + Icon::create('link-intern')); + $sidebar->addWidget($actions); + } + } + + + /** + * This method is called to show the dialog to edit a date for a course. + * + * @param String $termin_id The id of the date + * @return void + */ + public function details_action($termin_id) + { + $this->date = new CourseDate($termin_id); + + Navigation::activateItem('/course/schedule/dates'); + PageLayout::setTitle( + $this->date->getTypeName() . ': ' . + $this->date->getFullname(CourseDate::FORMAT_VERBOSE) + ); + + if ($this->hasAccess()) { + $this->assignLockRulesToTemplate(); + + $this->teachers = array_map(function (CourseMember $member) { + return $member->user; + }, $this->date->course->getMembersWithStatus('dozent')); + $this->assigned_teachers = $this->date->dozenten; + + $this->groups = $this->date->course->statusgruppen; + $this->assigned_groups = $this->date->statusgruppen; + + $this->render_action('details-edit'); + } + } + + public function details_files_action($termin_id) + { + $this->date = new CourseDate($termin_id); + + Navigation::activateItem('/course/schedule/dates'); + PageLayout::setTitle( + $this->date->getTypeName() . ': ' . + $this->date->getFullname(CourseDate::FORMAT_VERBOSE) + ); + $this->render_action('details'); + } + + /** + * This method is called to show the dialog to edit a singledate for a studygroup. + * + * @param String $termin_id The id of the date + * @return void + */ + public function singledate_action($termin_id = null) + { + $this->checkAccess(); + $this->assignLockRulesToTemplate(); + + Navigation::activateItem('/course/schedule/dates'); + + if (Request::isPost()) { + CSRFProtection::verifyUnsafeRequest(); + + $start_date = strtotime(Request::get('startDate')); + + $errors = []; + if (!$start_date) { + $errors[] = _('Bitte geben Sie ein korretes Datum an!'); + } else { + $start_time = strtotime((Request::get('start_stunde') ?: '0') . ':' . (Request::get('start_minute') ?: '0'), $start_date); + $end_time = strtotime((Request::get('end_stunde') ?: '0') . ':' . (Request::get('end_minute') ?: '0'), $start_date); + if (!($start_time && $end_time && $start_time < $end_time)) { + $errors[] = _('Bitte geben Sie korrekte Werte für Start- und Endzeit an!'); + } + } + $termin = CourseDate::find(Request::option('singleDateID')); + if ($termin == null) { + $termin = new CourseDate(); + } + $termin->raum = Request::get('freeRoomText_sd'); + $termin->autor_id = $GLOBALS['user']->id; + $termin->range_id = $this->course->id; + $termin->date = $start_time; + $termin->end_time = $end_time; + $termin->date_typ = Request::int('dateType'); + if (!count($errors)) { + if ($termin->store()) { + PageLayout::postSuccess(_('Der Termin wurde geändert.')); + } + return $this->relocate('course/dates'); + } else { + PageLayout::postError(_('Bitte korrigieren Sie Ihre Eingaben:'), $errors); + $this->date = $termin; + } + } elseif ($termin_id) { + $this->date = new CourseDate($termin_id); + $xtitle = $this->date->getTypeName() . ': ' . $this->date->getFullname(); + + } else { + $this->date = new CourseDate(); + $xtitle = _('Einzeltermin anlegen'); + } + + PageLayout::setTitle($xtitle); + } + + /** + * This method is called to save a singledate for a studygroup. + * + * @return void + */ + public function save_details_action($date_id) + { + $this->checkAccess(); + + CSRFProtection::verifyUnsafeRequest(); + + $termin = CourseDate::find($date_id); + if ($termin) { + $termin->date_typ = Request::get('dateType'); + + // Assign teachers + $assigned_teachers = Request::optionArray('assigned_teachers'); + $current_count = CourseMember::countByCourseAndStatus( + $termin->course->id, + 'dozent' + ); + $termin->dozenten = count($assigned_teachers) !== $current_count + ? User::findMany($assigned_teachers) + : []; + + // Assign groups + $assigned_groups = Request::optionArray('assigned_groups'); + $termin->statusgruppen = Statusgruppen::findMany($assigned_groups); + + if ($termin->store()) { + PageLayout::postSuccess(_('Der Termin wurde geändert.')); + } + } + $this->relocate('course/dates'); + } + + public function new_topic_action() + { + Navigation::activateItem('/course/schedule/dates'); + if (Request::isAjax()) { + PageLayout::setTitle(_("Thema hinzufügen")); + } + + $this->date = new CourseDate(Request::option('termin_id')); + $this->course = Course::findCurrent(); + } + + public function add_topic_action() + { + $this->checkAccess(); + + if (!Request::get('title')) { + $this->set_status(400); + $this->render_json(['message' => _('Geben Sie einen Titel an.')]); + return; + } + + $date = new CourseDate(Request::option('termin_id')); + $seminar_id = $date->range_id; + $title = Request::get('title'); + $topic = CourseTopic::findByTitle($seminar_id, $title); + if (!$topic) { + $topic = new CourseTopic(); + $topic->title = $title; + $topic->seminar_id = $seminar_id; + $topic->author_id = $GLOBALS['user']->id; + $topic->description = ''; + $topic->store(); + } + $output = ['topic_id' => $topic->id]; + if ($date->addTopic($topic)) { + $factory = $this->get_template_factory(); + $template = $factory->open($this->get_default_template('_topic_li')); + $template->topic = $topic; + $template->date = $date; + $template->has_access = $this->hasAccess(); + $template->controller = $this; + $output['li'] = $template->render(); + } + + $this->render_json($output); + } + + /** + * Moves a topic from one date to another. + * This action will be called from an ajax request and will return only + * the neccessary output for a single topic element. + * + * @param String $topic_id The id of the topic + * @param String $old_date_id The id of the original date of the topic + * @param String $new_date_id The id of the new date of the topic + * @throws MethodNotAllowedException if request method is not post + * @throws AccessDeniedException if the user is not allowed to execute the + * action (at least tutor of the course) + */ + public function move_topic_action($topic_id, $old_date_id, $new_date_id) + { + $this->checkAccess(); + + if (!Request::isPost()) { + throw new MethodNotAllowedException(); + } + + $this->topic = CourseTopic::find($topic_id); + $this->date = new CourseDate($new_date_id); + + $this->topic->dates->unsetByPK($old_date_id); + if (!$this->topic->dates->findOneBy('termin_id', $new_date_id)) { + $this->topic->dates[] = CourseDate::find($new_date_id); + } + $this->topic->store(); + + $this->set_content_type('text/html;charset=utf-8'); + $this->render_template('course/dates/_topic_li.php'); + } + + public function remove_topic_action() + { + $this->checkAccess(); + + $topic = new CourseTopic(Request::option('issue_id')); + $date = new CourseDate(Request::option('termin_id')); + $date->removeTopic($topic); + + $output = []; + $this->render_json($output); + } + + public function export_action() + { + $sem = new Seminar($this->course); + $themen =& $sem->getIssues(); + + $termine = getAllSortedSingleDates($sem); + + $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'] + ]; + } + } + } + + $factory = $this->get_template_factory(); + $template = $factory->open($this->get_default_template('export')); + + $template->set_attribute('dates', $dates); + $template->lecturer_count = $this->course->countMembersWithStatus('dozent'); + $template->group_count = count($this->course->statusgruppen); + $content = $template->render(); + + $content = mb_encode_numericentity($content, [0x80, 0xffff, 0, 0xffff], 'utf-8'); + $filename = FileManager::cleanFileName($this->course['name'] . '-' . _('Ablaufplan') . '.doc'); + + $this->set_content_type(get_mime_type($filename)); + $this->response->add_header('Content-Length', strlen($content)); + $this->response->add_header('Content-Disposition', 'attachment; ' . encode_header_parameter('filename', $filename)); + $this->response->add_header('Expires', 0); + $this->response->add_header('Cache-Control', 'private'); + $this->response->add_header('Pragma', 'cache'); + $this->render_text($content); + } + + /** + * Export list of course dates into CSV format. + */ + public function export_csv_action() + { + $sem = new Seminar($this->course); + $dates = getAllSortedSingleDates($sem); + $issues = $sem->getIssues(); + + $columns = [ + _('Wochentag'), + _('Termin'), + _('Beginn'), + _('Ende'), + _('Typ'), + _('Thema'), + _('Beschreibung'), + _('Lehrende'), + _('Gruppen'), + _('Raum'), + _('Raumbeschreibung'), + _('Sitzplätze') + ]; + + $data = [$columns]; + + foreach ($dates as $date) { + // FIXME this should not be necessary, see https://develop.studip.de/trac/ticket/8101 + if ($date->isExTermin() && $date->getComment() == '') { + continue; + } + + $row = []; + $row[] = strftime('%A', $date->date); + $row[] = strftime('%x', $date->date); + $row[] = strftime('%H:%M', $date->date); + $row[] = strftime('%H:%M', $date->end_time); + $row[] = $date->getTypeName(); + + if ($date->isExTermin()) { + $row[] = $date->getComment(); + $row[] = ''; + } else { + $issue = $descr = ''; + + foreach ((array) $date->getIssueIDs() as $id) { + $issue .= $issues[$id]->getTitle() . "\n"; + $descr .= kill_format($issues[$id]->getDescription()) . "\n"; + } + + $row[] = trim($issue); + $row[] = trim($descr); + } + + $related_persons = ''; + + if ($date->related_persons) { + foreach ($date->related_persons as $user_id) { + $related_persons .= User::find($user_id)->getFullname() . "\n"; + } + } + + $row[] = trim($related_persons); + + $related_groups = ''; + + if ($date->related_groups) { + foreach ($date->related_groups as $group_id) { + $related_groups .= Statusgruppen::find($group_id)->name . "\n"; + } + } + + $row[] = trim($related_groups); + + $room = null; + if ($date->resource_id) { + $resource_object = Resource::find($date->resource_id); + if ($resource_object) { + $room = $resource_object->getDerivedClassInstance(); + } + } + if ($room instanceof Room) { + $row[] = $room->name; + $row[] = $room->description; + $row[] = $room->seats; + } else { + $row[] = $date->raum; + $row[] = ''; + $row[] = ''; + } + + $data[] = $row; + } + + $filename = $sem->name . '-' . _('Ablaufplan') . '.csv'; + $this->render_csv($data, $filename); + } + + private function hasAccess() + { + return $GLOBALS['perm']->have_studip_perm('tutor', $this->course->id); + } + + private function checkAccess() + { + if (!$this->hasAccess()) { + throw new AccessDeniedException(); + } + } + + private function assignLockRulesToTemplate() + { + $this->cancelled_dates_locked = LockRules::Check( + $this->course->id, + 'cancelled_dates' + ); + $this->metadata_locked = LockRules::Check( + $this->course->id, + 'edit_dates_in_schedule' + ); + $this->dates_locked = LockRules::Check( + $this->course->id, + 'room_time' + ); + } + + public function create_folders_action() + { + $this->checkAccess(); + $this->dates = CourseDate::findByRange_id($this->course->id); + $this->show_confirmation_button = false; + $this->course_date_folders = []; + $this->previously_selected_dates = []; + $confirmed = false; + if (Request::submitted('go') || Request::submitted('force_go')) { + CSRFProtection::verifyUnsafeRequest(); + $confirmed = Request::submitted('force_go'); + $this->course_date_folders = Request::optionArray('course_date_folders'); + $this->previously_selected_dates = Request::getArray('previously_selected_dates'); + $count = 0; + $root_folder_id = Folder::findTopFolder($this->course->id)->getId(); + $new_folders = []; + $dates_with_folders = []; + foreach ($this->course_date_folders as $termin_id) { + // Check if there are already course date folders + // for the course date: + $course_date = CourseDate::find($termin_id); + if ($course_date && count($course_date->folders) > 0) { + $dates_with_folders[] = $course_date; + } + $folder = Folder::build([ + 'range_id' => $this->course->id, + 'parent_id' => $root_folder_id, + 'range_type' => 'course', + 'folder_type' => 'CourseTopicFolder', + 'user_id' => $GLOBALS['user']->id + ]); + $date_folder = new CourseDateFolder($folder); + $ok = $date_folder->setDataFromEditTemplate([ + 'course_date_folder_termin_id' => $termin_id, + 'course_date_folder_perm_write' => Request::get('course_date_folder_perm_write') + ]); + $new_folders[] = $ok; + } + // Check if the course_date_folders array + // and the previously_selected_dates array are equal. + // If not, then someone has changed the date selection in the + // confirmation step and the confirmation has to be done again. + if ($this->previously_selected_dates) { + //We are definetly confirming the creation of folders. + if ($this->previously_selected_dates != $this->course_date_folders) { + //Confirm again. + $confirmed = false; + } + } + if ($dates_with_folders && !$confirmed) { + $this->previously_selected_dates = $this->course_date_folders; + if (count($dates_with_folders) === 1) { + PageLayout::postWarning(sprintf( + _('Für den Termin am %s existiert bereits ein Sitzungs-Ordner. Möchten Sie trotzdem einen weiteren Sitzungs-Ordner erstellen?'), + htmlReady($dates_with_folders[0]->getFullname()) + )); + } else { + $dates_string = []; + foreach ($dates_with_folders as $date) { + $dates_string[] = $date->getFullname(); + } + PageLayout::postWarning( + _('Für die folgenden Termine gibt es bereits Sitzungs-Ordner. Möchten Sie trotzdem weitere Sitzungs-Ordner erstellen?'), + array_map('htmlReady', $dates_string) + ); + } + $this->show_confirmation_button = true; + return; + } + + foreach ($new_folders as $new_folder) { + if ($new_folder instanceof CourseDateFolder) { + $count += $new_folder->store(); + } + } + PageLayout::postSuccess(sprintf(_('Es wurden %u Ordner erstellt.'), $count)); + $this->response->add_header('X-Dialog-Close', '1'); + $this->relocate($this->url_for('/index')); + } + } +} |
