<?php # Lifter010: TODO /** * This class displays a seminar-schedule for * users on a seminar-based view and for admins on an institute based view * * 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 Till Glöggler <tgloeggl@uos.de> * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @category Stud.IP * @since 2.0 */ // Needs to be required due to the use of constants require_once 'lib/classes/calendar/CalendarScheduleModel.php'; class Calendar_ScheduleController extends AuthenticatedController { /** * Callback function being called before an action is executed. If this * function does not return FALSE, the action will be called, otherwise * an error will be generated and processing will be aborted. If this function * already #rendered or #redirected, further processing of the action is * withheld. * * @param string Name of the action to perform. * @param array An array of arguments to the action. * */ public function before_filter(&$action, &$args) { parent::before_filter($action, $args); $zoom = Request::int('zoom'); $this->my_schedule_settings = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS; // bind zoom, show_hidden and semester_id for all actions, even preserving them after redirect if (isset($zoom)) { URLHelper::addLinkParam('zoom', Request::int('zoom')); $this->my_schedule_settings['zoom'] = Request::int('zoom'); UserConfig::get($GLOBALS['user']->id)->store('SCHEDULE_SETTINGS', $this->my_schedule_settings); } URLHelper::bindLinkParam('semester_id', $this->current_semester['semester_id']); URLHelper::bindLinkParam('show_hidden', $this->show_hidden); PageLayout::setHelpKeyword('Basis.MyStudIPStundenplan'); PageLayout::setTitle(_('Mein Stundenplan')); } /** * this action is the main action of the schedule-controller, setting the environment * for the timetable, accepting a comma-separated list of days. * * @param string $days a list of an arbitrary mix of the numbers 0-6, separated * with a comma (e.g. 1,2,3,4,5 (for Monday to Friday, the default)) */ public function index_action($days = false) { $schedule_settings = CalendarScheduleModel::getScheduleSettings(); $inst_mode = false; $institute_id = null; if ($GLOBALS['perm']->have_perm('admin')) { $inst_mode = true; } if ($inst_mode) { // try to find the correct institute-id $institute_id = Request::option('institute_id', Context::getId()); if (!$institute_id) { $institute_id = UserConfig::get($GLOBALS['user']->id)->MY_INSTITUTES_DEFAULT; } if (!$institute_id || !in_array(get_object_type($institute_id), ['fak', 'inst'])) { throw new Exception('Cannot display institute-calender. No valid ID given!'); } Navigation::activateItem('/browse/my_courses/schedule'); } else { Navigation::activateItem('/calendar/schedule'); } // check, if the hidden seminar-entries shall be shown $show_hidden = Request::int('show_hidden', 0); // load semester-data and current semester $this->semesters = array_reverse(Semester::findAllVisible(false)); $this->current_semester = Semester::findCurrent(); $semester_id = Request::option('semester_id', $schedule_settings['semester_id'] ?? null); if ($semester_id && Semester::exists($semester_id)) { $this->current_semester = Semester::find($semester_id); $schedule_settings['semester_id'] = $this->current_semester->id; User::findCurrent()->getConfiguration()->store( 'SCHEDULE_SETTINGS', $schedule_settings ); } // check type-safe if days is false otherwise sunday (0) cannot be chosen if ($days === false) { if (Request::getArray('days')) { $this->days = array_keys(Request::getArray('days')); } else { $this->days = CalendarScheduleModel::getDisplayedDays($schedule_settings['glb_days']); } } else { $this->days = explode(',', $days); } $this->controller = $this; $this->calendar_view = $inst_mode ? CalendarScheduleModel::getInstCalendarView($institute_id, $show_hidden, $this->current_semester, $this->days) : CalendarScheduleModel::getUserCalendarView($GLOBALS['user']->id, $show_hidden, $this->current_semester, $this->days);; // have we chosen an entry to display? if (!empty($this->flash['entry'])) { if ($inst_mode) { $this->show_entry = $this->flash['entry']; } else if ($this->flash['entry']['id'] == null) { $this->show_entry = $this->flash['entry']; } else { foreach ($this->calendar_view->getColumns() as $entry_days) { foreach ($entry_days->getEntries() as $entry) { if ($this->flash['entry']['cycle_id']) { if ($this->flash['entry']['id'] . '-' . $this->flash['entry']['cycle_id'] == $entry['id']) { $this->show_entry = $entry; $entry_ids = explode('-', $this->show_entry['id']); $this->show_entry['id'] = reset($entry_ids); } } else { if ($entry['id'] == $this->flash['entry']['id']) { $this->show_entry = $entry; } } } } } } $style_parameters = [ 'whole_height' => $this->calendar_view->getOverallHeight(), 'entry_height' => $this->calendar_view->getHeight() ]; $factory = new Flexi\Factory($this->dispatcher->trails_root . '/views'); PageLayout::addStyle($factory->render('calendar/schedule/stylesheet', $style_parameters), 'screen, print'); if (Request::option('printview')) { $this->calendar_view->setReadOnly(); PageLayout::addStylesheet('print.css'); // remove all stylesheets that are not used for printing to have a more reasonable printing preview PageLayout::addHeadElement('script', [], "$('head link[media=screen]').remove();"); } else { PageLayout::addStylesheet('print.css', ['media' => 'print']); } $this->show_hidden = $show_hidden; $inst = get_object_name($institute_id, 'inst'); $this->inst_mode = $inst_mode; $this->institute_name = $inst['name']; $this->institute_id = $institute_id; $this->show_settings = Request::bool('show_settings', false); } public function new_entry_action() { $this->layout = null; if (!Request::isXhr()) { $this->render_nothing(); } } /** * this action is called whenever a new entry shall be modified or added to the schedule * * @param string $id optional, if id given, the entry with this id is updated */ public function addEntry_action($id = null) { if ($id) { $data['id'] = $id; } $error = false; $data['start'] = (int)str_replace(':', '', Request::get('entry_start')); $data['end'] = (int)str_replace(':', '', Request::get('entry_end')); $data['day'] = Request::int('entry_day'); if ($data['start'] >= $data['end'] || !Request::int('entry_day') || !$this->validate_datetime(Request::get('entry_start')) || !$this->validate_datetime(Request::get('entry_end'))) { $error = true; } if ($error) { PageLayout::postError( _('Eintrag konnte nicht gespeichert werden, da die Start- und/oder Endzeit ungültig ist!') ); } else { $data['title'] = Request::get('entry_title'); $data['content'] = Request::get('entry_content'); $data['user_id'] = $GLOBALS['user']->id; if (Request::get('entry_color')) { $data['color'] = Request::get('entry_color'); } else { $data['color'] = DEFAULT_COLOR_NEW; } CalendarScheduleModel::storeEntry($data); } $this->redirect('calendar/schedule'); } /** * this action keeps the entry of the submitted_id and enables displaying of the entry-dialog. * If no id is submitted, an empty entry_dialog is displayed. * * @param string $id the id of the entry to edit (if any), false otherwise. * @param string $cycle_id an optional cycle's ID */ public function entry_action($id = null, $cycle_id = null) { if (Request::isXhr()) { $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); $this->layout = null; $this->entry = [ 'id' => $id, 'cycle_id' => $cycle_id ]; if ($cycle_id) { $seminar_ids = CalendarScheduleModel::getSeminarEntry($id, $GLOBALS['user']->id, $cycle_id); $this->show_entry = array_pop($seminar_ids); $this->show_entry['id'] = $id; $this->render_template('calendar/schedule/_entry_course'); } else if ($id) { $entry_columns = CalendarScheduleModel::getScheduleEntries($GLOBALS['user']->id, 0, 0, $id); if (count($entry_columns) > 0) { $entries = array_pop($entry_columns)->getEntries(); $this->show_entry = array_pop($entries); } else { $this->show_entry = null; } $this->render_template('calendar/schedule/_entry_schedule'); } } else { $this->flash['entry'] = [ 'id' => $id, 'cycle_id' => $cycle_id ]; $this->redirect('calendar/schedule/'); } } /** * Return an HTML fragment containing a form to edit an entry * * @param string the ID of a course * @param string an optional cycle's ID * @return void */ public function entryajax_action($id, $cycle_id = null) { $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); if ($cycle_id) { $seminar_ids = CalendarScheduleModel::getSeminarEntry($id, $GLOBALS['user']->id, $cycle_id); $this->show_entry = array_pop($seminar_ids); $this->show_entry['id'] = $id; $this->render_template('calendar/schedule/_entry_course'); } else { $entry_columns = CalendarScheduleModel::getScheduleEntries($GLOBALS['user']->id, 0, 0, $id); $entries = array_pop($entry_columns)->getEntries(); $this->show_entry = array_pop($entries); $this->render_template('calendar/schedule/_entry_schedule'); } } /** * Returns an HTML fragment of a grouped entry in the schedule of an institute. * * @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 $day numeric day to show * * @return void */ public function groupedentry_action($start, $end, $seminars, $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]); } $this->timespan = mb_substr($start, 0, 2) . ':' . mb_substr($start, 2, 2) . ' - ' . mb_substr($end, 0, 2) . ':' . mb_substr($end, 2, 2); $this->start = $start; $this->end = $end; $day_names = [ _('Montag'), _('Dienstag'), _('Mittwoch'), _('Donnerstag'), _('Freitag'), _('Samstag'), _('Sonntag') ]; $this->day = (int)$day; $this->day_name = $day_names[$this->day]; $this->render_template('calendar/schedule/_entry_inst'); } /** * delete the entry of the submitted id (only entry belonging to the current * use can be deleted) * * @param string $id the id of the entry to delete * @return void */ public function delete_action($id) { CalendarScheduleModel::deleteEntry($id); $this->redirect('calendar/schedule'); } /** * store the color-settings for the seminar * * @param string $seminar_id * @param string $cycle_id * @return void */ public function editseminar_action($seminar_id, $cycle_id) { $data = [ 'id' => $seminar_id, 'cycle_id' => $cycle_id, 'color' => Request::get('entry_color') ]; CalendarScheduleModel::storeSeminarEntry($data); $this->redirect('calendar/schedule'); } /** * Adds the appointments of a course to your schedule. * * @param string $seminar_id the ID of the course * @return void */ public function addvirtual_action($seminar_id) { $sem = Seminar::getInstance($seminar_id); foreach ($sem->getCycles() as $cycle) { $data = [ 'id' => $seminar_id, 'cycle_id' => $cycle->getMetaDateId(), 'color' => false ]; CalendarScheduleModel::storeSeminarEntry($data); } $this->redirect('calendar/schedule'); } /** * Set the visibility of the course. * * @param string $seminar_id the ID of the course * @param string $cycle_id the ID of the cycle * @param string $visible visibility; either '1' or '0' * @param string $ajax if you give this optional param, it signals an Ajax request * @return void */ public function adminbind_action($seminar_id, $cycle_id, $visible, $ajax = null) { CalendarScheduleModel::adminBind($seminar_id, $cycle_id, $visible); if (!$ajax) { $this->redirect('calendar/schedule'); } else { $this->render_nothing(); } } /** * Hide the give appointment. * * @param string $seminar_id the ID of the course * @param string $cycle_id the ID of the cycle * @param string $ajax if you give this optional param, it signals an Ajax request * @return void */ function unbind_action($seminar_id, $cycle_id = null, $ajax = null) { CalendarScheduleModel::unbind($seminar_id, $cycle_id); if (!$ajax) { $this->redirect('calendar/schedule'); } else { $this->render_nothing(); } } /** * Show the given appointment. * * @param string $seminar_id the ID of the course * @param string $cycle_id the ID of the cycle * @param string $ajax if you give this optional param, it signals an Ajax request * @return void */ public function bind_action($seminar_id, $cycle_id, $ajax = null) { CalendarScheduleModel::bind($seminar_id, $cycle_id); if (!$ajax) { $this->redirect('calendar/schedule'); } else { $this->render_nothing(); } } /** * Show the settings' form. * * @return void */ public function settings_action() { $this->settings = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS; } /** * Store the settings * * @param string the start time of the calendar to show, e.g. "1000" * @param string the end time of the calendar to show, e.g. "1200" * @param string the days to show * @param string the ID of the semester * @return void */ public function storesettings_action($start_hour = false, $end_hour = false, $days = false, $semester_id = false) { if ($start_hour === false) { $start_hour = Request::int('start_hour'); $end_hour = Request::int('end_hour'); $days = Request::getArray('days'); } if ($start_hour > $end_hour) { $end_hour = $start_hour + 1; PageLayout::postError(_('Die Endzeit darf nicht vor der Startzeit liegen!')); } $this->my_schedule_settings = [ 'glb_start_time' => $start_hour, 'glb_end_time' => $end_hour, 'glb_days' => $days, 'converted' => true ]; if ($semester_id) { $this->my_schedule_settings['semester_id'] = $semester_id; } else if ($semester = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS['semester_id']) { $this->my_schedule_settings['semester_id'] = $semester; } UserConfig::get($GLOBALS['user']->id)->store('SCHEDULE_SETTINGS', $this->my_schedule_settings); if (Context::isInstitute()) { $this->redirect('calendar/instschedule'); } else { $this->redirect('calendar/schedule'); } } }