aboutsummaryrefslogtreecommitdiff
path: root/app/controllers/course/dates.php
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:07:19 +0200
committerJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:19:12 +0200
commita3da1483a9e689846179159355badfec8073dbec (patch)
tree770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /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.php630
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'));
+ }
+ }
+}