aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/calendar/calendar.php9
-rw-r--r--app/controllers/calendar/schedule.php854
-rw-r--r--app/controllers/course/details.php12
-rw-r--r--app/views/calendar/calendar/add_courses.php8
-rw-r--r--app/views/calendar/schedule/_colorpicker.php15
-rw-r--r--app/views/calendar/schedule/_dialog.php12
-rw-r--r--app/views/calendar/schedule/_entry_course.php92
-rw-r--r--app/views/calendar/schedule/_entry_inst.php59
-rw-r--r--app/views/calendar/schedule/_entry_schedule.php73
-rw-r--r--app/views/calendar/schedule/_semester_chooser.php23
-rw-r--r--app/views/calendar/schedule/course_info.php77
-rw-r--r--app/views/calendar/schedule/entry.php86
-rw-r--r--app/views/calendar/schedule/index.php86
-rw-r--r--app/views/calendar/schedule/settings.php44
-rw-r--r--app/views/calendar/schedule/stylesheet.php13
-rw-r--r--app/views/my_courses/group_selector.php20
-rw-r--r--app/views/my_courses/groups.php21
-rw-r--r--db/migrations/6.0.13_alter_schedule_table.php65
-rw-r--r--lib/calendar/CalendarColumn.php371
-rw-r--r--lib/calendar/CalendarView.php344
-rw-r--r--lib/calendar/CalendarWeekView.php124
-rw-r--r--lib/calendar/CalendarWidgetView.php54
-rw-r--r--lib/classes/JsonApi/Models/ScheduleEntry.php18
-rw-r--r--lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php2
-rw-r--r--lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php1
-rw-r--r--lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php6
-rw-r--r--lib/classes/JsonApi/SchemaMap.php2
-rw-r--r--lib/classes/JsonApi/Schemas/ScheduleEntry.php10
-rw-r--r--lib/classes/UserManagement.php2
-rw-r--r--lib/classes/calendar/CalendarScheduleModel.php813
-rw-r--r--lib/classes/calendar/Helper.php61
-rw-r--r--lib/models/Course.php10
-rw-r--r--lib/models/CourseDate.php2
-rw-r--r--lib/models/CourseExDate.php2
-rw-r--r--lib/models/SeminarCycleDate.php2
-rw-r--r--lib/models/calendar/CalendarCourseDate.php2
-rw-r--r--lib/models/calendar/CalendarCourseExDate.php2
-rw-r--r--lib/models/calendar/ScheduleCourseDate.php42
-rw-r--r--lib/models/calendar/ScheduleEntry.php341
-rw-r--r--lib/modules/ScheduleWidget.php12
-rw-r--r--lib/navigation/CalendarNavigation.php8
-rw-r--r--resources/assets/stylesheets/scss/calendar.scss16
-rw-r--r--resources/assets/stylesheets/scss/my_courses.scss11
-rw-r--r--templates/start/schedule_widget.php1
-rw-r--r--tests/jsonapi/ScheduleEntriesShowTest.php17
-rw-r--r--tests/jsonapi/UserScheduleShowTest.php7
-rw-r--r--tests/unit/lib/CalendarcolumnClassTest.php103
-rw-r--r--tests/unit/lib/CalendarviewClassTest.php103
48 files changed, 1244 insertions, 2814 deletions
diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php
index dfc6706..468c35d 100644
--- a/app/controllers/calendar/calendar.php
+++ b/app/controllers/calendar/calendar.php
@@ -35,6 +35,13 @@ class Calendar_CalendarController extends AuthenticatedController
$actions = new ActionsWidget();
if ($schedule) {
+ //Add the semester selector widget first:
+ $semester_widget = new SemesterSelectorWidget(
+ $this->url_for('calendar/calendar/schedule')
+ );
+ $sidebar->addWidget($semester_widget);
+
+ //Then add the actions for the action widget:
$actions->addLink(
_('Neuer Eintrag'),
$this->url_for('calendar/calendar/add_schedule_entry'),
@@ -762,7 +769,7 @@ class Calendar_CalendarController extends AuthenticatedController
}
}
PageLayout::postSuccess(_('Die Zuordnung von Veranstaltungen zum Kalender wurde aktualisiert.'));
- $this->redirect('calendar/calendar');
+ $this->redirect('calendar/schedule/index');
}
}
diff --git a/app/controllers/calendar/schedule.php b/app/controllers/calendar/schedule.php
index 668ed77..33c9f6d 100644
--- a/app/controllers/calendar/schedule.php
+++ b/app/controllers/calendar/schedule.php
@@ -1,498 +1,568 @@
<?php
-# Lifter010: TODO
/**
- * This class displays a seminar-schedule for
- * users on a seminar-based view and for admins on an institute based view
+ * schedule.php - Calender schedule controller
*
* 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>
+ * @author Moritz Strohm <strohm@data-quest.de>
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
- * @since 2.0
+ * @package calender
+ * @since 6.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'));
+ if (!Context::isCourse() && Navigation::hasItem('/calendar')) {
+ Navigation::activateItem('/calendar');
+ }
}
- /**
- * 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)
+ public function index_action()
{
- $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 {
+ PageLayout::setTitle(_('Stundenplan'));
+
+ if (Navigation::hasItem('/calendar/schedule')) {
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
+ $show_hidden = Request::bool('show_hidden', false);
+
+ //Build the sidebar:
+
+ $sidebar = Sidebar::get();
+
+ //Add the semester selector widget first:
+ $semester_widget = new SemesterSelectorWidget(
+ $this->indexURL(['show_hidden' => $show_hidden ?: null])
+ );
+ $sidebar->addWidget($semester_widget);
+
+ //Then add the actions for the action widget:
+ $actions = new ActionsWidget();
+ $actions->addLink(
+ _('Neuer Termin'),
+ $this->url_for('calendar/schedule/entry/add'),
+ Icon::create('add'),
+ ['data-dialog' => '']
+ );
+ if ($show_hidden) {
+ $actions->addLink(
+ _('Ausgeblendete Veranstaltungen verstecken'),
+ $this->indexURL(['semester_id' => Request::get('semester_id')]),
+ Icon::create('visibility-invisible')
);
- }
-
- // 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);
+ $actions->addLink(
+ _('Ausgeblendete Veranstaltungen anzeigen'),
+ $this->indexURL([
+ 'show_hidden' => true,
+ 'semester_id' => Request::get('semester_id'),
+ ]),
+ Icon::create('visibility-visible')
+ );
}
- $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;
- }
- }
- }
- }
- }
+ $actions->addLink(
+ _('Drucken'),
+ '#',
+ Icon::create('print'),
+ ['onclick' => 'window.print(); return false;']
+ );
+ $actions->addLink(
+ _('Einstellungen'),
+ $this->url_for('settings/calendar'),
+ Icon::create('settings'),
+ ['data-dialog' => 'size=auto;reload-on-close']
+ );
+ $sidebar->addWidget($actions);
+
+ //Handle the selected semester and create a Fullcalendar instance.
+
+ $semester = null;
+ if (Request::submitted('semester_id')) {
+ $semester = Semester::find(Request::option('semester_id'));
}
-
- $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']);
+ if (!$semester) {
+ $semester = Semester::findCurrent();
}
- $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);
+ $fullcalendar = \Studip\Calendar\Helper::getScheduleFullcalendar(
+ $semester->id ?? '',
+ Request::bool('show_hidden', false)
+ );
+ $this->fullcalendar = $fullcalendar->render();
}
- public function new_entry_action()
+ public function data_action()
{
- $this->layout = null;
-
- if (!Request::isXhr()) {
- $this->render_nothing();
+ //Fullcalendar sets the week time range in which to put the course dates
+ //of the semester. Therefore, start and end are handled in here.
+ $begin = Request::getDateTime('start', \DateTime::RFC3339);
+ $end = Request::getDateTime('end', \DateTime::RFC3339);
+ if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) {
+ //No time range specified.
+ throw new InvalidArgumentException('Invalid parameters!');
}
- }
- /**
- * 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;
- }
+ $result = [];
+
+ $semester_id = Request::option('semester_id');
+ $semester = Semester::find($semester_id);
+ $show_hidden = Request::bool('show_hidden', false);
+
+ if ($semester) {
+ //Get all regular course dates for that semester:
+ $cycle_dates = SeminarCycleDate::findBySql(
+ 'JOIN `termine` USING (`metadate_id`)
+ JOIN `seminare` USING (`seminar_id`)
+ WHERE
+ `seminar_id` IN (
+ SELECT `seminar_id` FROM `seminar_user`
+ WHERE `user_id` = :user_id
+ UNION
+ SELECT `course_id` FROM `schedule_courses`
+ WHERE `user_id` = :user_id
+ )
+ AND
+ (
+ `termine`.`date` BETWEEN :begin AND :end
+ OR `termine`.`end_time` BETWEEN :begin AND :end
+ )
+ GROUP BY `metadate_id`',
+ [
+ 'user_id' => $GLOBALS['user']->id,
+ 'begin' => $semester->beginn,
+ 'end' => $semester->ende
+ ]
+ );
- $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');
+ foreach ($cycle_dates as $cycle_date) {
+ //Calculate a fake begin and end that lies in the week
+ //fullcalendar has specified.
+ $fake_begin = clone $begin;
+ $fake_end = clone $begin;
+ if ($cycle_date->weekday > 1) {
+ $fake_begin = $fake_begin->add(new DateInterval('P' . ($cycle_date->weekday - 1) . 'D'));
+ $fake_end = $fake_end->add(new DateInterval('P' . ($cycle_date->weekday - 1) . 'D'));
+ }
+ $start_time_parts = explode(':', $cycle_date->start_time);
+ $end_time_parts = explode(':', $cycle_date->end_time);
+ $fake_begin->setTime(
+ $start_time_parts[0],
+ $start_time_parts[1],
+ $start_time_parts[2]
+ );
+ $fake_end->setTime(
+ $end_time_parts[0],
+ $end_time_parts[1],
+ $end_time_parts[2]
+ );
+
+ $schedule_course = ScheduleCourseDate::findOneBySQL(
+ '`course_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $cycle_date->seminar_id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+ $is_hidden = $schedule_course && !$schedule_course->visible;
+ if (!$show_hidden && $is_hidden) {
+ //The regular date belongs to a course that has been hidden in the schedule.
+ //The flag to include hidden courses is not set which means that the regular
+ //date shall not be included.
+ continue;
+ }
- 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;
- }
+ //Get the course colour:
+ $course_membership = CourseMember::findOneBySQL(
+ '`seminar_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $cycle_date->seminar_id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+
+ $event_classes = [];
+ $event_title = $cycle_date->course->getFullName();
+ if ($course_membership) {
+ $event_classes[] = sprintf('course-color-%u', $course_membership->gruppe);
+ } elseif ($schedule_course) {
+ $event_classes[] = 'marked-course';
+ $event_title = studip_interpolate(
+ _('%{course_name} (vorgemerkt)'),
+ ['course_name' => $cycle_date->course->getFullName()]
+ );
+ }
- 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;
+ $event_icon = '';
+ if ($schedule_course && !$course_membership) {
+ $event_icon = 'tag';
+ } elseif ($show_hidden && $is_hidden) {
+ $event_icon = 'visibility-invisible';
+ $event_classes[] = 'hidden-course';
+ }
+
+ $event = new \Studip\Calendar\EventData(
+ $fake_begin,
+ $fake_end,
+ $event_title,
+ $event_classes,
+ '',
+ '',
+ false,
+ 'SeminarCycleDate',
+ $cycle_date->id,
+ '',
+ '',
+ 'course',
+ $cycle_date->seminar_id,
+ [
+ 'show' => $this->url_for('calendar/schedule/course_info/' . $cycle_date->seminar_id)
+ ],
+ [],
+ $event_icon ?: ''
+ );
+
+ $result[] = $event->toFullcalendarEvent();
}
+ }
- CalendarScheduleModel::storeEntry($data);
+ //Add all schedule entries to the result set:
+ $weekly_dates = ScheduleEntry::findByUser_id($GLOBALS['user']->id);
+ foreach ($weekly_dates as $date) {
+ $event_data = $date->toEventData($GLOBALS['user']->id);
+ //Disable fullcalendar drag & drop actions:
+ $event_data->editable = false;
+ $result[] = $event_data->toFullcalendarEvent();
}
- $this->redirect('calendar/schedule');
+ $this->render_json($result);
}
-
/**
- * 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.
+ * This action handles adding and editing schedule entries.
*
- * @param string $id the id of the entry to edit (if any), false otherwise.
- * @param string $cycle_id an optional cycle's ID
+ * @param string $entry_id The ID of the entry to be modified. In case the ID is set to "add", a new entry
+ * will be created. In all other cases, an existing entry will be loaded.
*/
- public function entry_action($id = null, $cycle_id = null)
+ public function entry_action(string $entry_id)
{
- 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');
+ $this->entry = null;
+ if ($entry_id === 'add') {
+ //Add mode
+ $this->entry = new ScheduleEntry();
+ $this->entry->user_id = $GLOBALS['user']->id;
+ if (!Request::submitted('save')) {
+ //Provide good default values:
+ $this->entry->dow = Request::int('dow', date('N'));
+ $this->entry->setFormattedStart(Request::get('start', date('H:00', strtotime('+1 hour'))));
+ $this->entry->setFormattedEnd(Request::get('end', date('H:00', strtotime('+2 hours'))));
}
+ PageLayout::setTitle(_('Neuer Termin'));
} else {
- $this->flash['entry'] = [
- 'id' => $id,
- 'cycle_id' => $cycle_id
- ];
-
- $this->redirect('calendar/schedule/');
+ //Edit mode
+ $this->entry = ScheduleEntry::find($entry_id);
+ if (!$this->entry) {
+ PageLayout::postError(_('Der Termin wurde nicht gefunden.'));
+ }
+ if (!$this->entry->isWritable($GLOBALS['user']->id)) {
+ throw new AccessDeniedException(_('Sie dĂĽrfen diesen Termin nicht bearbeiten!'));
+ }
+ PageLayout::setTitle($this->entry->toString());
}
- }
- /**
- * 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');
+ if (Request::submitted('save')) {
+ CSRFProtection::verifyUnsafeRequest();
+ $this->saveEntry($entry_id);
+ } elseif (Request::submitted('delete')) {
+ CSRFProtection::verifyUnsafeRequest();
+ $this->deleteEntry();
}
}
/**
- * 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 $course_ids the IDs of the courses
- * @param string $day numeric day to show
- *
- * @return void
+ * Handles storing a schedule entry.
*/
- public function groupedentry_action($start, $end, $course_ids, $day)
+ public function save_entry_action(string $entry_id)
{
- $this->response->add_header('Content-Type', 'text/html; charset=utf-8');
- $course_ids = explode(',', $course_ids);
- foreach ($course_ids as $course_id) {
- $zw = explode('-', $course_id);
- $this->courses[$zw[0]] = Course::find($zw[0]);
+ $this->entry = null;
+ if ($entry_id === 'add') {
+ //Add mode
+ $this->entry = new ScheduleEntry();
+ $this->entry->user_id = $GLOBALS['user']->id;
+ PageLayout::setTitle(_('Neuer Termin'));
+ } else {
+ //Edit mode
+ $this->entry = ScheduleEntry::find($entry_id);
+ if (!$this->entry) {
+ PageLayout::postError(_('Der Termin wurde nicht gefunden.'));
+ }
+ if (!$this->entry->isWritable($GLOBALS['user']->id)) {
+ throw new AccessDeniedException(_('Sie dĂĽrfen diesen Termin nicht bearbeiten!'));
+ }
+ PageLayout::setTitle($this->entry->toString());
}
- $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->entry->dow = Request::int('dow', date('N'));
+ $this->entry->setFormattedStart(Request::get('start'));
+ $this->entry->setFormattedEnd(Request::get('end'));
+ $this->entry->label = Request::get('label', '');
+ $this->entry->content = Request::get('content', '');
- $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)
- {
- $regular_dates = SeminarCycleDate::findBySeminar($seminar_id);
- foreach ($regular_dates as $cycle) {
- $data = [
- 'id' => $seminar_id,
- 'cycle_id' => $cycle->id,
- 'color' => false
- ];
-
- CalendarScheduleModel::storeSeminarEntry($data);
+ if ($this->entry->start_time >= $this->entry->end_time) {
+ PageLayout::postError(_('Der Startzeitpunkt darf nicht nach dem Endzeitpunkt liegen!'));
+ $this->redirect('calendar/schedule/entry/' . $entry_id);
+ return;
}
- $this->redirect('calendar/schedule');
+ if ($this->entry->store() !== false) {
+ if ($entry_id === 'add') {
+ PageLayout::postSuccess(_('Der Termin wurde hinzugefĂĽgt.'));
+ } else {
+ PageLayout::postSuccess(_('Der Termin wurde bearbeitet.'));
+ }
+ if (Request::isDialog()) {
+ $this->response->add_header('X-Dialog-Close', '1');
+ } else {
+ $this->redirect('calendar/schedule/index');
+ }
+ } else {
+ if ($entry_id === 'add') {
+ PageLayout::postError(_('Der Termin konnte nicht hinzugefĂĽgt werden.'));
+ } else {
+ PageLayout::postError(_('Der Termin konnte nicht bearbeitet werden.'));
+ }
+ $this->redirect('calendar/schedule/entry/' . $entry_id);
+ }
+ $this->render_nothing();
}
-
/**
- * 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
+ * Handles deleting a schedule entry.
*/
- public function adminbind_action($seminar_id, $cycle_id, $visible, $ajax = null)
+ public function delete_entry_action(string $entry_id)
{
- CalendarScheduleModel::adminBind($seminar_id, $cycle_id, $visible);
-
- if (!$ajax) {
- $this->redirect('calendar/schedule');
+ CSRFProtection::verifyUnsafeRequest();
+ $this->entry = ScheduleEntry::find($entry_id);
+ if (!$this->entry) {
+ PageLayout::postError(_('Der Termin wurde nicht gefunden.'));
+ }
+ if (!$this->entry->isWritable($GLOBALS['user']->id)) {
+ throw new AccessDeniedException(_('Sie dĂĽrfen diesen Termin nicht bearbeiten!'));
+ }
+ if ($this->entry->delete()) {
+ PageLayout::postSuccess(_('Der Termin wurde gelöscht.'));
} else {
- $this->render_nothing();
+ PageLayout::postError(_('Der Termin konnte nicht gelöscht werden.'));
}
+ if (Request::isDialog()) {
+ $this->response->add_header('X-Dialog-Close', '1');
+ } else {
+ $this->redirect('calendar/schedule/index');
+ }
+ $this->render_nothing();
}
/**
- * Hide the give appointment.
+ * Displays information about a course in the schedule.
*
- * @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
+ * @param string $course_id The ID of the course.
*/
- function unbind_action($seminar_id, $cycle_id = null, $ajax = null)
+ public function course_info_action(string $course_id)
{
- CalendarScheduleModel::unbind($seminar_id, $cycle_id);
-
- if (!$ajax) {
- $this->redirect('calendar/schedule');
- } else {
- $this->render_nothing();
+ $this->course = Course::find($course_id);
+ if (!$this->course) {
+ PageLayout::postError(_('Die Veranstaltung wurde nicht gefunden.'));
+ return;
}
+ $this->membership = CourseMember::findOneBySQL(
+ '`seminar_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $this->course->id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+ $this->schedule_course_entry = ScheduleCourseDate::findOneBySQL(
+ '`course_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $this->course->id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+
+ PageLayout::setTitle($this->course->getFullName());
}
/**
- * Show the given appointment.
+ * Hides a course in the schedule.
*
- * @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
+ * @param string $course_id The ID of the course.
*/
- public function bind_action($seminar_id, $cycle_id, $ajax = null)
+ public function hide_course_action(string $course_id)
{
- CalendarScheduleModel::bind($seminar_id, $cycle_id);
+ CSRFProtection::verifyUnsafeRequest();
+ $success = false;
+
+ $course = Course::find($course_id);
+ if ($course) {
+ $this->membership = CourseMember::findOneBySQL(
+ '`seminar_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $course->id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
- if (!$ajax) {
- $this->redirect('calendar/schedule');
- } else {
- $this->render_nothing();
+ //Hide the course.
+ if ($this->membership) {
+ //Hide the course in the schedule by creating a new schedule course entry
+ //with the visibility set to 0:
+ $entry = ScheduleCourseDate::findOneBySQL(
+ '`user_id` = :user_id AND `course_id` = :course_id',
+ ['user_id' => $GLOBALS['user']->id, 'course_id' => $course->id]
+ );
+ if (!$entry) {
+ $entry = new ScheduleCourseDate();
+ $entry->user_id = $GLOBALS['user']->id;
+ $entry->course_id = $course->id;
+ $entry->metadate_id = '';
+ }
+ $entry->visible = false;
+ $success = $entry->store() !== false;
+ } else {
+ //Remove the entry of the marked course from the schedule.
+ $success = ScheduleCourseDate::deleteBySQL(
+ '`user_id` = :user_id AND `course_id` = :course_id',
+ ['user_id' => $GLOBALS['user']->id, 'course_id' => $course->id]
+ ) > 0;
+ }
+ }
+ if ($success) {
+ if (Request::isDialog()) {
+ $this->response->add_header('X-Dialog-Close', '1');
+ } else {
+ $this->redirect('calendar/schedule/index');
+ }
}
+ $this->render_nothing();
}
/**
- * Show the settings' form.
+ * Makes a hidden course visible again in the schedule.
*
- * @return void
+ * @param string $course_id The ID of the course.
*/
- public function settings_action()
+ public function show_course_action(string $course_id)
{
- $this->settings = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS;
+ CSRFProtection::verifyUnsafeRequest();
+ $success = false;
+
+ $course = Course::find($course_id);
+ if ($course) {
+ //Make a hidden course visible again.
+ $entry = ScheduleCourseDate::findOneBySQL(
+ '`user_id` = :user_id AND `course_id` = :course_id',
+ ['user_id' => $GLOBALS['user']->id, 'course_id' => $course_id]
+ );
+ if ($entry) {
+ $entry->visible = true;
+ $success = $entry->store() !== false;
+ } else {
+ $success = true;
+ }
+ //In case no entry exists, the course is not hidden since an entry in schedule_courses
+ //must exist with its visible set to zero to make a course disappear from the schedule.
+ }
+ if ($success) {
+ if (Request::isDialog()) {
+ $this->response->add_header('X-Dialog-Close', '1');
+ } else {
+ $this->redirect('calendar/schedule/index');
+ }
+ }
+ $this->render_nothing();
}
/**
- * Store the settings
+ * Saves the data that are specific to displaying a course in the schedule.
+ * Currently, this means saving only the colour of the course.
*
- * @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
+ * @param string $course_id The ID of the course.
*/
- public function storesettings_action($start_hour = false, $end_hour = false, $days = false, $semester_id = false)
+ public function save_course_info_action(string $course_id)
{
- if ($start_hour === false) {
- $start_hour = Request::int('start_hour');
- $end_hour = Request::int('end_hour');
- $days = Request::getArray('days');
+ CSRFProtection::verifyUnsafeRequest();
+ $success = false;
+
+ $course = Course::find($course_id);
+ if ($course) {
+ $this->membership = CourseMember::findOneBySQL(
+ '`seminar_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $course->id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+ if (!$this->membership) {
+ throw new AccessDeniedException();
+ }
+ //Save the selected group.
+ $selected_groups = Request::getArray('gruppe');
+ if (array_key_exists($course->id, $selected_groups)) {
+ $this->membership->gruppe = $selected_groups[$course->id] ?? '0';
+ }
+ $success = $this->membership->store() !== false;
}
-
- if ($start_hour > $end_hour) {
- $end_hour = $start_hour + 1;
- PageLayout::postError(_('Die Endzeit darf nicht vor der Startzeit liegen!'));
+ if ($success) {
+ PageLayout::postSuccess(_('Die Farbe der Veranstaltung wurde geändert.'));
+ } else {
+ PageLayout::postError(_('Die Farbe der Veranstaltung konnte nicht geändert werden.'));
}
-
- $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;
+ if ($success) {
+ if (Request::isDialog()) {
+ $this->response->add_header('X-Dialog-Close', '1');
+ } else {
+ $this->redirect('calendar/schedule/index');
+ }
}
+ $this->render_nothing();
+ }
- UserConfig::get($GLOBALS['user']->id)->store('SCHEDULE_SETTINGS', $this->my_schedule_settings);
-
- if (Context::isInstitute()) {
- $this->redirect('calendar/instschedule');
+ public function mark_course_action(string $course_id)
+ {
+ $course = Course::find($course_id);
+ if ($course->isStudygroup()) {
+ throw new AccessDeniedException();
+ }
+ $entry = ScheduleCourseDate::findOneBySQL(
+ '`course_id` = :course_id AND `user_id` = :user_id',
+ [
+ 'course_id' => $course_id,
+ 'user_id' => $GLOBALS['user']->id
+ ]
+ );
+ if ($entry) {
+ PageLayout::postInfo(_('Die Veranstaltung wurde bereits zum Stundenplan hinzugefĂĽgt.'));
} else {
- $this->redirect('calendar/schedule');
+ $entry = new ScheduleCourseDate();
+ $entry->course_id = $course->id;
+ $entry->user_id = $GLOBALS['user']->id;
+ $entry->metadate_id = '';
+ $entry->visible = true;
+ if ($entry->store() !== false) {
+ PageLayout::postSuccess(_('Die Veranstaltung wurde zum Stundenplan hinzugefĂĽgt.'));
+ } else {
+ PageLayout::postError(_('Die Veranstaltung konnte nicht zum Stundenplan hinzugefĂĽgt werden.'));
+ }
}
+ $this->redirect('calendar/schedule/index');
}
}
diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php
index 10f3f57..7f9c078 100644
--- a/app/controllers/course/details.php
+++ b/app/controllers/course/details.php
@@ -247,22 +247,22 @@ class Course_DetailsController extends AuthenticatedController
&& count($this->course->cycles)
) {
$query = "SELECT 1
- FROM `schedule_seminare`
- WHERE `seminar_id` = ? AND `user_id` = ?";
+ FROM `schedule_courses`
+ WHERE `course_id` = ? AND `user_id` = ?";
$penciled = DBManager::Get()->fetchColumn($query, [
$this->course->id,
$GLOBALS['user']->id,
]);
if (!$penciled) {
$links->addLink(
- _('Nur im Stundenplan vormerken'),
- $this->url_for("calendar/schedule/addvirtual/{$this->course->id}"),
+ _('Zum Stundenplan hinzufĂĽgen'),
+ $this->url_for('calendar/schedule/mark_course', $this->course),
Icon::create('info')
);
$this->links[] = [
- 'label' => _('Nur im Stundenplan vormerken'),
- 'url' => $this->url_for("calendar/schedule/addvirtual/{$this->course->id}"),
+ 'label' => _('Zum Stundenplan hinzufĂĽgen'),
+ 'url' => $this->url_for('calendar/schedule/mark_course', $this->course),
'attributes' => [],
];
}
diff --git a/app/views/calendar/calendar/add_courses.php b/app/views/calendar/calendar/add_courses.php
index cf3d282..85d4cd0 100644
--- a/app/views/calendar/calendar/add_courses.php
+++ b/app/views/calendar/calendar/add_courses.php
@@ -1,3 +1,11 @@
+<?php
+/**
+ * @var Trails_Controller $controller The controller.
+ * @var array $selected_course_ids The IDs of the selected courses.
+ * @var string $selected_semester_id The ID of the selected semester.
+ * @var array $available_semester_data The data of all available semesters.
+ */
+?>
<form class="default" method="post" action="<?= $controller->link_for('calendar/calendar/add_courses') ?>">
<?= CSRFProtection::tokenTag() ?>
<fieldset class="simplevue">
diff --git a/app/views/calendar/schedule/_colorpicker.php b/app/views/calendar/schedule/_colorpicker.php
deleted file mode 100644
index e1f1266..0000000
--- a/app/views/calendar/schedule/_colorpicker.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<section id="color_picker">
- <?= _('Farbe des Termins') ?>
- <div>
- <? foreach ($GLOBALS['PERS_TERMIN_KAT'] as $index => $data): ?>
- <span>
- <input type="radio" name="entry_color" value="<?= $index ?>" id="color-<?= $index ?>"
- <?= $index === $selected ? 'checked' : '' ?>>
- <label class="undecorated schedule-category<?= $index ?> enter-accessible"
- for="color-<?= $index ?>"
- aria-label="<?= sprintf(_('Farbe %u zuordnen'), $index) ?>"
- title="<?= sprintf(_('Farbe %u zuordnen'), $index) ?>"></label>
- </span>
- <? endforeach; ?>
- </div>
-</section>
diff --git a/app/views/calendar/schedule/_dialog.php b/app/views/calendar/schedule/_dialog.php
deleted file mode 100644
index 0b64f9d..0000000
--- a/app/views/calendar/schedule/_dialog.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-draggable ui-resizable ui-dialog-buttons <?= $class ?: 'schedule-dialog' ?>" tabindex="-1" role="dialog" aria-labelledby="ui-id-2" id="schedule_new_entry" style="width: 600px; height: auto; z-index: 1002;">
- <div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" style="z-index: 1001">
- <span id="ui-id-2" class="ui-dialog-title"><?= $title ?></span>
- <a class="ui-dialog-titlebar-close ui-corner-all" href="<?= $controller->link_for('calendar/schedule') ?>" role="button">
- <span class="ui-icon ui-icon-closethick">close</span>
- </a>
- </div>
-
- <div class="ui-widget-content" style="display: block; width: auto; min-height: 0px; height: 100%;" scrolltop="0" scrollleft="0">
- <?= $content_for_layout ?>
- </div>
-</div>
diff --git a/app/views/calendar/schedule/_entry_course.php b/app/views/calendar/schedule/_entry_course.php
deleted file mode 100644
index f600218..0000000
--- a/app/views/calendar/schedule/_entry_course.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-$course = Course::find($show_entry['id']);
-?>
-<form class="default"
- action="<?= $controller->link_for('calendar/schedule/editseminar/' . $show_entry['id'] . '/' . $show_entry['cycle_id']) ?>"
- method="post" name="edit_entry">
- <?= CSRFProtection::tokenTag() ?>
- <fieldset>
- <legend>
- <?= _('Stundenplaneintrag') ?>
- </legend>
-
- <?= $this->render_partial('calendar/schedule/_colorpicker.php', [
- 'selected' => $show_entry['color'],
- ]) ?>
-
- <? if ($show_entry['type'] == 'virtual') : ?>
- <section>
- <span
- style="color: red; font-weight: bold"><?= _('Dies ist lediglich eine vorgemerkte Veranstaltung') ?></span><br><br>
- </section>
- <? endif ?>
-
- <section>
- <strong><?= _('Veranstaltungsnummer') ?></strong><br>
- <?= htmlReady($course->veranstaltungsnummer) ?>
- </section>
-
- <section>
- <strong><?= _('Name') ?></strong><br>
- <?= htmlReady($course->name) ?>
- </section>
-
- <section>
- <strong><?= _('Lehrende') ?></strong><br>
- <?
- $pos = 0;
- $lecturers = CourseMember::findByCourseAndStatus($course->id, 'dozent');
- foreach ($lecturers as $lecturer) :?>
- <?= $pos > 0 ? ', ' : '' ?>
- <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $lecturer->user->username]) ?>">
- <?= htmlReady($lecturer->user->getFullName()) ?>
- </a>
- <? $pos++ ?>
- <? endforeach ?>
- </section>
-
- <section>
- <strong><?= _('Veranstaltungszeiten') ?></strong><br>
- <?= $course->getAllDatesInSemester()->toHtml(true) ?><br>
- </section>
-
- <section>
- <?= Icon::create('link-intern') ?>
- <? if ($show_entry['type'] == 'virtual') : ?>
- <a href="<?= URLHelper::getLink('dispatch.php/course/details', ['sem_id' => $show_entry['id']]) ?>">
- <?= _('Zur Veranstaltung') ?>
- </a>
- <br>
- <? else : ?>
- <a href="<?= URLHelper::getLink('seminar_main.php', ['auswahl' => $show_entry['id']]) ?>">
- <?= _('Zur Veranstaltung') ?>
- </a>
- <br>
- <? endif ?>
- </section>
- </fieldset>
-
- <footer data-dialog-button>
- <?= Studip\Button::createAccept(_('Speichern'), ['style' => 'margin-right: 20px']) ?>
-
- <? if (!$show_entry['visible']) : ?>
- <?= Studip\LinkButton::create(
- _('Einblenden'),
- $controller->url_for(
- 'calendar/schedule/bind/' . $show_entry['id'] . '/' . $show_entry['cycle_id'] . '/',
- ['show_hidden' => '1']
- ),
- ['style' => 'margin-right: 20px']) ?>
- <? else : ?>
- <?= Studip\LinkButton::create(
- $show_entry['type'] == 'virtual' ? _('Löschen') : _('Ausblenden'),
- $controller->url_for('calendar/schedule/unbind/' . $show_entry['id'] . '/' . $show_entry['cycle_id']),
- ['style' => 'margin-right: 20px']) ?>
- <? endif ?>
-
- <?= Studip\LinkButton::createCancel(
- _('Abbrechen'),
- $controller->url_for('calendar/schedule'),
- ['onclick' => "jQuery('#edit_sem_entry').fadeOut('fast'); STUDIP.Calendar.click_in_progress = false; return false"]) ?>
- </footer>
-</form>
diff --git a/app/views/calendar/schedule/_entry_inst.php b/app/views/calendar/schedule/_entry_inst.php
deleted file mode 100644
index 228751f..0000000
--- a/app/views/calendar/schedule/_entry_inst.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<table class="default">
- <colgroup>
- <col style="width: 15%">
- <col style="width: 45%">
- <col>
- </colgroup>
- <caption>
- <?= sprintf(_('Veranstaltungen mit regelmäßigen Zeiten am %s, %s Uhr'), htmlReady($day), htmlReady($timespan)) ?>
- </caption>
- <thead>
- <tr>
- <th><?= _('Nummer') ?></th>
- <th><?= _('Name') ?></th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <? foreach ($courses as $course) : ?>
- <tr>
- <td><?= htmlReady($course->veranstaltungsnummer) ?></td>
- <td>
- <a href="<?= URLHelper::getLink('dispatch.php/course/details/', ['sem_id' => $course->id]) ?>">
- <?= Icon::create('link-intern') ?>
- <?= htmlReady($course->name) ?>
- </a>
- </td>
- <td class="schedule-adminbind">
- <? $cycles = CalendarScheduleModel::getSeminarCycleId($course->id, $start, $end, $day) ?>
-
- <? foreach ($cycles as $cycle) : ?>
- <span><?= $cycle->toString() ?></span>
-
- <? $visible = CalendarScheduleModel::isSeminarVisible($course->id, $cycle->getMetadateId()) ?>
-
- <?= Studip\LinkButton::create(
- _('Ausblenden'),
- $controller->url_for('calendar/schedule/adminbind/' . $course->id . '/' . $cycle->getMetadateId() . '/0'),
- [
- 'id' => $course->id . '_' . $cycle->getMetadateId() . '_hide',
- 'onclick' => "STUDIP.Schedule.instSemUnbind('" . $course->id . "','" . $cycle->getMetadateId() . "'); return false;",
- 'style' => ($visible ? '' : 'display: none')
- ]) ?>
-
- <?= Studip\LinkButton::create(
- _('Einblenden'),
- $controller->url_for('calendar/schedule/adminbind/' . $course->id . '/' . $cycle->getMetadateId() . '/1'),
- [
- 'id' => $course->id . '_' . $cycle->getMetadateId() . '_show',
- 'onclick' => "STUDIP.Schedule.instSemBind('" . $course->id . "','" . $cycle->getMetadateId() . "'); return false;",
- 'style' => ($visible ? 'display: none' : '')
- ]) ?>
- <br>
- <? endforeach ?>
- </td>
- </tr>
- <? endforeach ?>
- </tbody>
-</table>
-<br>
diff --git a/app/views/calendar/schedule/_entry_schedule.php b/app/views/calendar/schedule/_entry_schedule.php
deleted file mode 100644
index ad5bbcd..0000000
--- a/app/views/calendar/schedule/_entry_schedule.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<form class="default"
- action="<?= $controller->link_for('calendar/schedule/addentry', $show_entry['id'] ?? null) ?>"
- method="post" name="edit_entry" onSubmit="return STUDIP.Schedule.checkFormFields()">
- <?= CSRFProtection::tokenTag() ?>
- <fieldset>
- <legend>
- <?= _('Stundenplaneintrag') ?>
- </legend>
-
- <label class="col-2">
- <?= _('Tag') ?>
- <select name="entry_day" class="size-s">
- <? foreach ([1, 2, 3, 4, 5, 6, 7] as $index) : ?>
- <option
- value="<?= $index ?>" <?= (isset($show_entry['day']) && $show_entry['day'] == $index) ? 'selected="selected"' : '' ?>>
- <?= getWeekDay($index % 7, false) ?>
- </option>
- <? endforeach ?>
- </select>
- </label>
-
- <label class="col-2">
- <?= _('von') ?>
- <input class="size-s studip-timepicker" placeholder="HH:mm" type="text" size="2" name="entry_start"
- value="<?= !empty($show_entry['start']) ? $show_entry['start_formatted'] : '' ?>"
- id="entry-start" data-time-picker>
- </label>
-
- <label class="col-2">
- <?= _('bis') ?>
- <input class="size-s studip-timepicker" placeholder="HH:mm" type="text" size="2" name="entry_end"
- value="<?= !empty($show_entry['end']) ? $show_entry['end_formatted'] : '' ?>"
- id="entry-end" data-time-picker>
- </label>
-
- <span class="invalid_message"><?= _('Die Endzeit liegt vor der Startzeit!') ?></span>
-
- <?= $this->render_partial('calendar/schedule/_colorpicker.php', [
- 'selected' => $show_entry['color'] ?? null,
- ]) ?>
-
- <label>
- <?= _('Titel') ?>
- <input type="text" name="entry_title" value="<?= htmlReady($show_entry['title'] ?? '') ?>">
- </label>
-
- <label>
- <?= _('Beschreibung') ?>
- <textarea name="entry_content"
- rows="7"><?= htmlReady($show_entry['content'] ?? '') ?></textarea>
- </label>
- </fieldset>
-
- <footer data-dialog-button>
- <?= Studip\Button::createAccept(_('Speichern'), ['style' => 'margin-right: 20px']) ?>
- <? if (isset($show_entry['id'])) : ?>
- <?= Studip\LinkButton::create(
- _('Löschen'),
- $controller->url_for('calendar/schedule/delete/'. $show_entry['id']),
- ['style' => 'margin-right: 20px']
- ) ?>
- <? endif ?>
-
- <? if (!empty($show_entry)) : ?>
- <?= Studip\LinkButton::createCancel(
- _('Abbrechen'),
- $controller->url_for('calendar/schedule'),
- ['onclick' => 'STUDIP.Schedule.cancelNewEntry(); STUDIP.Calendar.click_in_progress = false;return false;']) ?>
- <? else: ?>
- <?= Studip\LinkButton::createCancel(_('Abbrechen'), 'javascript:STUDIP.Schedule.cancelNewEntry()') ?>
- <? endif ?>
- </footer>
-</form>
diff --git a/app/views/calendar/schedule/_semester_chooser.php b/app/views/calendar/schedule/_semester_chooser.php
deleted file mode 100644
index a8a783e..0000000
--- a/app/views/calendar/schedule/_semester_chooser.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<form method="post" class="default" action="<?= $controller->link_for(
- isset($inst_mode) && $inst_mode == true ? 'calendar/instschedule/index' : 'calendar/schedule/index'
-) ?>">
- <label for="semester_id" class="sr-only"><?= _('Angezeigtes Semester') ?></label>
- <select name="semester_id" class="submit-upon-select" id="semester_id">
- <? foreach ($semesters as $semester) : ?>
- <? if ($semester['ende'] > time() - strtotime('1year 1day')) : ?>
- <option
- value="<?= $semester['semester_id'] ?>" <?= $current_semester['semester_id'] == $semester['semester_id'] ? 'selected="selected"' : '' ?>>
- <?= htmlReady($semester['name']) ?>
- <?= $semester['beginn'] < time() && $semester['ende'] > time() ? _('*') : '' ?>
- </option>
- <? endif ?>
- <? endforeach ?>
- </select>
- <noscript>
- <?= Icon::create(
- 'accept',
- Icon::ROLE_ACCEPT,
- ['title' => _('auswählen')]
- )->asInput(['type' => 'image', 'class' => 'middle']) ?>
- </noscript>
-</form>
diff --git a/app/views/calendar/schedule/course_info.php b/app/views/calendar/schedule/course_info.php
new file mode 100644
index 0000000..b813592
--- /dev/null
+++ b/app/views/calendar/schedule/course_info.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * @var AuthenticatedController $controller
+ * @var Course $course
+ * @var CourseMember $membership
+ * @var ScheduleCourseDate $schedule_course_entry
+ */
+?>
+<? if ($course) : ?>
+ <h2><?= htmlReady($course->getFullName()) ?></h2>
+ <form class="default" method="post" data-dialog="reload-on-close"
+ action="<?= $controller->link_for('calendar/schedule/course_info/' . $course->id) ?>">
+ <?= CSRFProtection::tokenTag() ?>
+ <? if ($membership) : ?>
+ <fieldset>
+ <legend><?= _('Farbe') ?></legend>
+ <table class="default mycourses-group-selector">
+ <tr>
+ <?= $this->render_partial(
+ 'my_courses/group_selector',
+ [
+ 'course_id' => $course->id,
+ 'selected_group_id' => $membership->gruppe
+ ]
+ ) ?>
+ </tr>
+ </table>
+ </fieldset>
+ <? endif ?>
+ <fieldset>
+ <legend><?= _('Informationen') ?></legend>
+ <section>
+ <h3><?= _('Veranstaltungsnummer') ?></h3>
+ <p><?= htmlReady($course->veranstaltungsnummer) ?></p>
+ <h3><?= _('Lehrende') ?></h3>
+ <ul class="default">
+ <?
+ $lecturers = CourseMember::findByCourseAndStatus($course->id, 'dozent');
+ ?>
+ <? foreach ($lecturers as $lecturer) : ?>
+ <li>
+ <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $lecturer->username]) ?>">
+ <?= htmlReady($lecturer->user->getFullName()) ?>
+ </a>
+ </li>
+ <? endforeach ?>
+ </ul>
+ <h3><?= _('Veranstaltungszeiten') ?></h3>
+ <?= $course->getAllDatesInSemester()->toHtml() ?>
+ </section>
+ </fieldset>
+ <div data-dialog-button>
+ <?= \Studip\Button::create(
+ _('Speichern'),
+ 'save',
+ ['formaction' => $controller->url_for('calendar/schedule/save_course_info/' . $course->id)]
+ ) ?>
+ <? if ($schedule_course_entry && !$schedule_course_entry->visible) : ?>
+ <?= \Studip\Button::create(
+ _('Veranstaltung einblenden'),
+ 'show',
+ ['formaction' => $controller->url_for('calendar/schedule/show_course/' . $course->id)]
+ ) ?>
+ <? else : ?>
+ <?= \Studip\Button::create(
+ _('Veranstaltung ausblenden'),
+ 'hide',
+ ['formaction' => $controller->url_for('calendar/schedule/hide_course/' . $course->id)]
+ ) ?>
+ <? endif ?>
+ <?= \Studip\LinkButton::create(
+ _('Direkt zur Veranstaltung'),
+ URLHelper::getURL('dispatch.php/course/overview', ['cid' => $course->id])
+ ) ?>
+ </div>
+ </form>
+<? endif ?>
diff --git a/app/views/calendar/schedule/entry.php b/app/views/calendar/schedule/entry.php
index 54d44e9..676f073 100644
--- a/app/views/calendar/schedule/entry.php
+++ b/app/views/calendar/schedule/entry.php
@@ -1,9 +1,77 @@
-<? if (!empty($show_entry) && in_array($show_entry['type'], ['sem', 'virtual'])): ?>
- <?= $this->render_partial('calendar/schedule/_entry_course.php') ?>
- <? unset($show_entry) ?>
-<? elseif (!empty($show_entry) && $show_entry['type'] === 'inst'): ?>
- <?= $this->render_partial('calendar/schedule/_entry_inst.php') ?>
- <? unset($show_entry) ?>
-<? else : ?>
- <?= $this->render_partial('calendar/schedule/_entry_schedule.php') ?>
-<? endif ?>
+<?php
+/**
+ * @var AuthenticatedController $controller
+ * @var ScheduleEntry $entry The schedule entry to be created/modified.
+ */
+?>
+<form class="default" method="post" action="<?= $controller->link_for('calendar/schedule/entry/' . ($entry->isNew() ? 'add' : $entry->id)) ?>"
+ data-dialog="reload-on-close">
+ <?= CSRFProtection::tokenTag() ?>
+ <fieldset>
+ <legend><?= _('Zeit') ?></legend>
+ <section class="flex-row">
+ <label>
+ <?= _('Wochentag') ?>
+ <select name="dow">
+ <option value="1" <?= $entry->dow === 1 ? 'selected' : '' ?>>
+ <?= _('Montag') ?>
+ </option>
+ <option value="2" <?= $entry->dow === 2 ? 'selected' : '' ?>>
+ <?= _('Dienstag') ?>
+ </option>
+ <option value="3" <?= $entry->dow === 3 ? 'selected' : '' ?>>
+ <?= _('Mittwoch') ?>
+ </option>
+ <option value="4" <?= $entry->dow === 4 ? 'selected' : '' ?>>
+ <?= _('Donnerstag') ?>
+ </option>
+ <option value="5" <?= $entry->dow === 5 ? 'selected' : '' ?>>
+ <?= _('Freitag') ?>
+ </option>
+ <option value="6" <?= $entry->dow === 6 ? 'selected' : '' ?>>
+ <?= _('Samstag') ?>
+ </option>
+ <option value="7" <?= $entry->dow === 7 ? 'selected' : '' ?>>
+ <?= _('Sonntag') ?>
+ </option>
+ </select>
+ </label>
+ <label>
+ <?= _('Startuhrzeit') ?>
+ <input type="text" class="has-time-picker" name="start"
+ value="<?= htmlReady($entry->getFormattedStart()) ?>">
+ </label>
+ <label>
+ <?= _('Enduhrzeit') ?>
+ <input type="text" class="has-time-picker" name="end"
+ value="<?= htmlReady($entry->getFormattedEnd()) ?>">
+ </label>
+ </section>
+ </fieldset>
+ <fieldset>
+ <legend><?= _('Inhalt') ?></legend>
+ <label>
+ <?= _('Titel') ?>
+ <input type="text" name="label" value="<?= htmlReady($entry->label) ?>">
+ </label>
+ <label>
+ <?= _('Beschreibung') ?>
+ <textarea name="content"><?= htmlReady($entry->content) ?></textarea>
+ </label>
+ </fieldset>
+ <div data-dialog-button>
+ <?= \Studip\Button::create(
+ _('Speichern'),
+ 'save',
+ ['formaction' => $controller->url_for('calendar/schedule/save_entry/' . ($entry->isNew() ? 'add' : $entry->id))]
+ ) ?>
+ <? if (!$entry->isNew()) : ?>
+ <?= \Studip\Button::create(
+ _('Löschen'),
+ 'delete',
+ ['formaction' => $controller->url_for('calendar/schedule/delete_entry/' . $entry->id)]
+ ) ?>
+ <? endif ?>
+ <?= \Studip\Button::createCancel(_('Abbrechen')) ?>
+ </div>
+</form>
diff --git a/app/views/calendar/schedule/index.php b/app/views/calendar/schedule/index.php
index fe022a2..390a016 100644
--- a/app/views/calendar/schedule/index.php
+++ b/app/views/calendar/schedule/index.php
@@ -1,84 +1,6 @@
<?php
-# Lifter010: TODO
-$zoom = $my_schedule_settings['zoom'] ?? 0;
-
-$sidebar = Sidebar::get();
-
-$semester_widget = new SidebarWidget();
-$semester_widget->setTitle(_('Angezeigtes Semester'));
-$semester_widget->addElement(
- new WidgetElement($this->render_partial('calendar/schedule/_semester_chooser')),
- 'semester'
-);
-$sidebar->addWidget($semester_widget, 'calendar/schedule/semester');
-
-$actions = new ActionsWidget();
-if (!$inst_mode) {
- $actions->addLink(
- _('Neuer Eintrag'),
- $controller->url_for('calendar/schedule/entry'),
- Icon::create('add'),
- ['data-dialog' => 'size=auto']
- );
-}
-$actions->addLink(
- _('Darstellung ändern'),
- $controller->url_for('calendar/schedule/settings'),
- Icon::create('admin'),
- ['data-dialog' => 'size=auto']
-);
-if (!$show_hidden) {
- $actions->addLink(
- _('Ausgeblendete Veranstaltungen anzeigen'),
- $controller->url_for('calendar/schedule', ['show_hidden' => '1']),
- Icon::create('visibility-invisible')
- );
-} else {
- $actions->addLink(
- _('Ausgeblendete Veranstaltungen verbergen'),
- $controller->url_for('calendar/schedule', ['show_hidden' => '0']),
- Icon::create('visibility-visible')
- );
-}
-$sidebar->addWidget($actions, 'calendar/schedule/actions');
-
-$widget = new ExportWidget();
-$widget->addLink(_('Druckansicht'),
- $controller->url_for(
- 'calendar/schedule/index/' . implode(',', $days),
- [
- 'printview' => 'true',
- 'semester_id' => $current_semester['semester_id'],
- ]
- ),
- Icon::create('print'),
- ['target' => '_blank']);
-$sidebar->addWidget($widget, 'calendar/schedule/print');
-
-$options = new OptionsWidget();
-$options->setTitle(_('Darstellungsgröße'));
-$options->addRadioButton(_('klein'), URLHelper::getURL('', ['zoom' => 0]), $zoom == 0);
-$options->addRadioButton(_('mittel'), URLHelper::getURL('', ['zoom' => 1]), $zoom == 1);
-$options->addRadioButton(_('groĂź'), URLHelper::getURL('', ['zoom' => 2]), $zoom == 2);
-$sidebar->addWidget($options, 'calendar/schedule/options');
-
+/**
+ * @var \Studip\Fullcalendar $fullcalendar The fullcalendar instance to be rendered.
+ */
?>
-<div style="text-align: center; font-weight: bold; font-size: 1.2em">
- <? if ($inst_mode) : ?>
- <?= htmlReady($institute_name) ?>: <?= _('Stundenplan im') ?>
- <? else : ?>
- <?= _('Mein Stundenplan im') ?>
- <? endif ?>
- <?= htmlReady($current_semester['name']) ?>
-</div>
-
-<? if (!empty($show_entry)) : ?>
- <div class="ui-widget-overlay" style="width: 100%; height: 100%; z-index: 1001;"></div>
- <?= $this->render_partial('calendar/schedule/_dialog', [
- 'content_for_layout' => $this->render_partial('calendar/schedule/entry', [
- 'show_entry' => $show_entry]),
- 'title' => _('Termindetails')
- ]) ?>
-<? endif ?>
-
-<?= $calendar_view->render(['show_hidden' => $show_hidden]) ?>
+<?= $fullcalendar ?>
diff --git a/app/views/calendar/schedule/settings.php b/app/views/calendar/schedule/settings.php
deleted file mode 100644
index 0e2674e..0000000
--- a/app/views/calendar/schedule/settings.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<form class="default" method="post" action="<?= $controller->link_for('calendar/schedule/storesettings') ?>">
- <?= CSRFProtection::tokenTag() ?>
- <fieldset>
- <legend>
- <?= _('Angezeigter Zeitraum') ?>
- </legend>
- <section>
- <section class="hgroup">
- <label>
- <?= _('von') ?>
- <input type="text" name="start_hour" id="start-hour" class="size-s"
- value="<?= sprintf('%02u:00', $settings['glb_start_time']) ?>"
- data-time-picker>
- </label>
- <label>
- <?= _('bis') ?>
- <input type="text" name="end_hour" id="end-hour" class="size-s"
- value="<?= sprintf('%02u:00', $settings['glb_end_time']) ?>"
- data-time-picker>
- </label>
- <?= _('Uhr') ?><br>
- </section>
- </section>
- </fieldset>
- <fieldset>
- <legend>
- <?= _('Angezeigte Wochentage') ?>
- </legend>
- <section class='settings'>
- <? foreach ([1, 2, 3, 4, 5, 6, 0] as $day) : ?>
- <label>
- <input type="checkbox" name="days[]" value="<?= $day ?>"
- <?= in_array($day, $settings['glb_days']) !== false ? 'checked' : '' ?>>
- <?= getWeekDay($day, false) ?>
- </label>
- <? endforeach ?>
- <span class="invalid_message"><?= _('Bitte mindestens einen Wochentag auswählen.') ?></span><br>
- </section>
- </fieldset>
- <footer data-dialog-button>
- <?= Studip\Button::createSuccess(_('Speichern'), ['onclick' => "return STUDIP.Calendar.validateNumberOfDays();"]) ?>
- <?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->url_for('calendar/schedule/#')) ?>
- </footer>
-</form>
diff --git a/app/views/calendar/schedule/stylesheet.php b/app/views/calendar/schedule/stylesheet.php
deleted file mode 100644
index aaf7334..0000000
--- a/app/views/calendar/schedule/stylesheet.php
+++ /dev/null
@@ -1,13 +0,0 @@
-div.schedule_day {
- height: <?= $whole_height ?>px;
-}
-
-div.schedule_marker {
- height: <?= floor($entry_height / 2) ?>px;
- line-height: <?= floor($entry_height / 2) ?>px;
- margin-bottom: <?= floor($entry_height / 2) ?>px;
-}
-
-div.schedule_hours {
- height: <?= $entry_height ?>px;
-}
diff --git a/app/views/my_courses/group_selector.php b/app/views/my_courses/group_selector.php
new file mode 100644
index 0000000..8d99a64
--- /dev/null
+++ b/app/views/my_courses/group_selector.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * @var string $course_id
+ * @var string $selected_group_id
+ */
+?>
+<? for ($i = 0; $i < 9; $i++) : ?>
+ <td class="gruppe<?= $i ?> mycourses-group-selector" onclick="this.querySelector('input').checked = true;">
+ <input type="radio" name="gruppe[<?= htmlReady($course_id) ?>]" value="<?= $i ?>"
+ aria-label="<?= sprintf(_('Gruppe %u zuordnen'), $i + 1) ?>"
+ id="course-group-<?= htmlReady($course_id) ?>-<?= $i ?>"
+ <?= $selected_group_id == $i ? 'checked' : '' ?>>
+ <label for="course-group-<?= htmlReady($course_id) ?>-<?= $i ?>">
+ <span class="group-number"><?= $i + 1 ?></span>
+ <span class="checked-icon">
+ <?= Icon::create('accept', Icon::ROLE_INFO)->asImg(20) ?>
+ </span>
+ </label>
+ </td>
+<? endfor ?>
diff --git a/app/views/my_courses/groups.php b/app/views/my_courses/groups.php
index 4476aeb..fff9d63 100644
--- a/app/views/my_courses/groups.php
+++ b/app/views/my_courses/groups.php
@@ -55,20 +55,13 @@
<?= _('(versteckt)') ?>
<? endif; ?>
</td>
- <? for ($i = 0; $i < 9; $i++): ?>
- <td class="gruppe<?= $i ?> mycourses-group-selector" onclick="this.querySelector('input').checked = true;">
- <input type="radio" name="gruppe[<?= $member['seminar_id'] ?>]" value="<?= $i ?>"
- aria-label="<?= sprintf(_('Gruppe %u zuordnen'), $i + 1) ?>"
- id="course-group-<?= htmlReady($member['seminar_id']) ?>-<?= $i ?>"
- <? if ($my_sem[$member['seminar_id']]['gruppe'] == $i) echo 'checked'; ?>>
- <label for="course-group-<?= htmlReady($member['seminar_id']) ?>-<?= $i ?>">
- <span class="group-number"><?= $i + 1 ?></span>
- <span class="checked-icon">
- <?= Icon::create('accept', Icon::ROLE_INFO)->asImg(20) ?>
- </span>
- </label>
- </td>
- <? endfor; ?>
+ <?= $this->render_partial(
+ 'my_courses/group_selector',
+ [
+ 'course_id' => $member['seminar_id'],
+ 'selected_group_id' => $my_sem[$member['seminar_id']]['gruppe']
+ ]
+ ) ?>
</tr>
<? endforeach; ?>
</tbody>
diff --git a/db/migrations/6.0.13_alter_schedule_table.php b/db/migrations/6.0.13_alter_schedule_table.php
new file mode 100644
index 0000000..d27bf81
--- /dev/null
+++ b/db/migrations/6.0.13_alter_schedule_table.php
@@ -0,0 +1,65 @@
+<?php
+
+
+class AlterScheduleTable extends Migration
+{
+ public function description()
+ {
+ return 'Renames and alters the schedule table';
+ }
+
+ protected function up()
+ {
+ $db = DBManager::get();
+
+ $db->exec("RENAME TABLE `schedule` TO `schedule_entries`");
+
+ $db->exec(
+ "ALTER TABLE `schedule_entries`
+ DROP COLUMN color,
+ CHANGE COLUMN start start_time SMALLINT(6) NOT NULL,
+ CHANGE COLUMN end end_time SMALLINT(6) NOT NULL,
+ CHANGE COLUMN day dow TINYINT(1) NOT NULL,
+ CHANGE COLUMN title label VARCHAR(255) NOT NULL DEFAULT '',
+ CHANGE COLUMN content content TEXT,
+ ADD COLUMN mkdate BIGINT(10) NOT NULL DEFAULT 0,
+ ADD COLUMN chdate BIGINT(10) NOT NULL DEFAULT 0"
+ );
+
+ $db->exec("RENAME TABLE `schedule_seminare` TO `schedule_courses`");
+ $db->exec(
+ "ALTER TABLE `schedule_courses`
+ DROP COLUMN color,
+ CHANGE COLUMN seminar_id course_id CHAR(32) NOT NULL,
+ ADD COLUMN mkdate BIGINT(10) NOT NULL DEFAULT 0,
+ ADD COLUMN chdate BIGINT(10) NOT NULL DEFAULT 0"
+ );
+ }
+
+ protected function down()
+ {
+ $db = DBManager::get();
+
+ $db->exec(
+ "ALTER TABLE `schedule_courses`
+ ADD COLUMN color TINYINT(4) NULL DEFAULT NULL,
+ CHANGE COLUMN course_id seminar_id CHAR(32) NOT NULL,
+ DROP COLUMN mkdate,
+ DROP COLUMN chdate"
+ );
+ $db->exec("RENAME TABLE `schedule_courses` TO `schedule_seminare`");
+
+ $db->exec(
+ "ALTER TABLE `schedule_entries`
+ ADD COLUMN color TINYINT(4) NULL DEFAULT NULL,
+ CHANGE COLUMN start_time start SMALLINT(6) NOT NULL,
+ CHANGE COLUMN end_time end SMALLINT(6) NOT NULL,
+ CHANGE COLUMN dow day TINYINT(1) NOT NULL,
+ CHANGE COLUMN label title VARCHAR(255) NOT NULL,
+ CHANGE COLUMN content content VARCHAR(255) NOT NULL,
+ DROP COLUMN mkdate,
+ DROP COLUMN chdate"
+ );
+ $db->exec("RENAME TABLE `schedule_entries` TO `schedule`");
+ }
+}
diff --git a/lib/calendar/CalendarColumn.php b/lib/calendar/CalendarColumn.php
deleted file mode 100644
index 78a3809..0000000
--- a/lib/calendar/CalendarColumn.php
+++ /dev/null
@@ -1,371 +0,0 @@
-<?php
-# Lifter010: TODO
-/**
- * CalendarColumn.php - a column for a CalendarView
- *
- * This class represents an entry-column like "monday" in the calendar
- *
- * 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 Rasmus Fuhse <fuhse@data-quest.de>
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- *
- * @deprecated since Stud.IP 5.5
- */
-
-class CalendarColumn
-{
- protected static $number = 0;
- protected $title = "";
- protected $id = "";
- public $entries = [];
- protected $url = "";
- protected $grouped = false;
- protected $sorted_entries = null;
-
- /**
- * creates instance of type CalendarColumn
- *
- * @param string $id necessary if you want JavaScript enabled for this calendar
- * @return CalendarColumn
- */
- static public function create($id = null) {
- $column = new CalendarColumn($id);
- return $column;
- }
-
- /**
- * constructor
- *
- * @param string $id necessary if you want JavaScript enabled for this column
- */
- public function __construct($id = null) {
- $id !== null || $id = md5(uniqid("CalendarColumn_".self::$number++));
- $this->setId($id);
- }
-
- /**
- * returns the id of the column
- *
- * @return string
- */
- public function getId() {
- return $this->id;
- }
-
- /**
- * sets the id for this column, which is only necessary if you want
- * Javascript to be enabled for this calendar
- *
- * @param string $id new id for this column
- * @return CalendarColumn
- */
- public function setId($id) {
- $this->id = $id;
- return $this;
- }
-
- /**
- * sets a title like "monday" for this column, which will be displayed in the calendar
- *
- * @param string $new_title new title
- * @return CalendarColumn
- */
- public function setTitle($new_title) {
- $this->title = $new_title;
- return $this;
- }
-
- /**
- * returns the title of this column like "monday"
- *
- * @return string title of column
- */
- public function getTitle() {
- return $this->title;
- }
-
- /**
- * sets the url to be directed to when clicking on the title of the column.
- * Usually this is a single-day-view of the calendar.
- *
- * @param string $new_url an url
- * @return CalendarColumn
- */
- public function setURL($new_url) {
- $this->url = $new_url;
- return $this;
- }
-
- /**
- * returns the URL of the column (see setURL)
- *
- * @return string an url
- */
- public function getURL() {
- return $this->url;
- }
-
- /**
- * adds a new entry in the column. The entry needs to be an associative array
- * with parameters as follows:
- *
- * @param array $entry_array associative array for an entry in the column like
- * array (
- * 'color' => the color in hex (css-like, without the #)
- * 'start' => the (start hour * 100) + (start minute)
- * 'end' => the (end hour * 100) + (end minute)
- * 'title' => the entry`s title
- * 'content' => whatever shall be the content of the entry as a string
- * )
- */
- public function addEntry($entry_array) {
- if (!isset($entry_array['start']) || !isset($entry_array['end'])
- || !isset($entry_array['title']) ) {
- throw new InvalidArgumentException('The entry '. print_r($entry_array, true) .' does not follow the specifications!');
- } else {
- $this->entries[] = $entry_array;
- }
- return $this;
- }
-
- /**
- * adds many entries to the column. For the syntax of an entry see addEntry()
- *
- * @param array $entries_array
- * @return CalendarColumn
- */
- public function addEntries($entries_array = []) {
- foreach ($entries_array as $entry_array) {
- $this->addEntry($entry_array);
- }
- return $this;
- }
-
- /**
- * returns all entries of this column
- *
- * @return array of arrays like
- * array (
- * 'color' => the color in hex (css-like, without the #)
- * 'start' => the (start hour * 100) + (start minute)
- * 'end' => the (end hour * 100) + (end minute)
- * 'title' => the entry`s title
- * 'content' => whatever shall be the content of the entry as a string
- * )
- */
- public function getEntries() {
- return $this->entries;
- }
-
- /**
- * deletes all entries of this column. So the only way to edit an entry is
- * getting all entries with getEntries, edit this entry, eraseEntries() and
- * addEntries(). Not very short, but at least it works.
- *
- * @return CalendarColumn
- */
- public function eraseEntries() {
- $this->entries = [];
- return $this;
- }
-
- /**
- * Returns an array of calendar-entries, grouped by day and additionally grouped by same start and end
- * if groupEntries(true) has been called.
- *
- * @return mixed the (double-)grouped entries
- */
- public function getGroupedEntries()
- {
- if (empty($this->sorted_entries)) {
- if ($this->isGrouped()) {
- $this->sorted_entries = $this->sortAndGroupEntries();
- } else {
- $this->sorted_entries = $this->sortEntries();
- }
- }
-
- return $this->sorted_entries;
- }
-
- /**
- * sorts and groups entries and returns them
- * only used by columns with grouped entries like instituteschedules
- *
- * @return array
- */
- public function sortAndGroupEntries()
- {
- $day = $this->getTitle();
-
- $entries_for_column = $this->getEntries();
- $result = [];
- $new_entries = [];
-
- // 1st step - group all entries with the same duration
- foreach ($entries_for_column as $entry_id => $entry) {
- $new_entries[$entry['start'] .'_'. $entry['end']][] = $entry;
- }
-
- $column = 0;
-
- // 2nd step - optimize the groups
- while (sizeof($new_entries) > 0) {
- $lstart = 2399; $lend = 0;
-
- foreach ($new_entries as $time => $grouped_entries) {
- list($start, $end) = explode('_', $time);
- if ($start < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ ) {
- $lstart = $start;
- $lend = $end;
- }
- }
-
- $result['col_'. $column][] = $new_entries[$lstart .'_'. $lend];
- unset($new_entries[$lstart .'_'. $lend]);
-
- $hit = true;
-
- while ($hit) {
- $hit = false;
- $hstart = 2399; $hend = 2399;
-
- // check, if there is something, that can be placed after
- foreach ($new_entries as $time => $grouped_entries) {
- list($start, $end) = explode('_', $time);
-
- if ( ($start >= $lend) && ($start < $hstart) ) {
- $hstart = $start;
- $hend = $end;
- $hit = true;
- }
- }
-
- if ($hit) {
- $lend = $hend;
- $result['col_'. $column][] = $new_entries[$hstart .'_'. $hend];
- unset($new_entries[$hstart .'_'. $hend]);
- }
- }
-
- $column++;
- } // 2nd step
-
- return $result;
-
- }
-
- /**
- * sorts entries and returns them
- *
- * @return array
- */
- public function sortEntries()
- {
- $entries_for_column = $this->getEntries();
-
- $result = [];
- $column = 0;
-
- // 2nd step - optimize the groups
- while (sizeof($entries_for_column) > 0) {
- $lstart = 2399; $lend = 0; $lkey = null;
-
- foreach ($entries_for_column as $entry_key => $entry) {
- if ($entry['start'] < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ ) {
- $lstart = $entry['start'];
- $lend = $entry['end'];
- $lkey = $entry_key;
- }
- }
-
- $result['col_'. $column][] = $entries_for_column[$lkey];
- unset($entries_for_column[$lkey]);
-
- $hit = true;
-
- while ($hit) {
- $hit = false;
- $hstart = 2399; $hend = 2399; $hkey = null;
-
- // check, if there is something, that can be placed after
- foreach ($entries_for_column as $entry_key => $entry) {
- if ( ($entry['start'] >= $lend) && ($entry['start'] < $hstart) ) {
- // && (($end - $start) > ($hend - $hstart)) ) {
- $hstart = $entry['start'];
- $hend = $entry['end'];
- $hkey = $entry_key;
- $hit = true;
- }
- }
-
- if ($hit) {
- $lend = $hend;
- $result['col_'. $column][] = $entries_for_column[$hkey];
- unset($entries_for_column[$hkey]);
- }
- }
-
- $column++;
- } // 2nd step
- return $result;
-
- }
-
- /**
- * returns a matrix that tells the number of entries for a given timeslot
- *
- * @return array
- */
- public function getMatrix() {
- $group_matrix = [];
- foreach ($this->getGroupedEntries() as $groups) {
- foreach ($groups as $group) {
- if (isset($group[0]) && is_array($group[0])) {
- $data = $group[0];
- } else {
- $data = $group;
- }
-
- for ($i = floor($data['start'] / 100); $i <= floor($data['end'] / 100); $i++) {
- for ($j = 0; $j < 60; $j++) {
- if (($i * 100) + $j >= $data['start'] && ($i * 100) + $j < $data['end']) {
- if (!isset($group_matrix[$i * 100 + $j])) {
- $group_matrix[$i * 100 + $j] = 0;
- }
- $group_matrix[$i * 100 + $j]++;
- }
- }
- }
- }
- }
- return $group_matrix;
- }
-
- /**
- * check, if a grouped view of the entries is requested
- *
- * @return bool true if grouped, false otherwise
- */
- public function isGrouped()
- {
- return $this->grouped;
- }
-
- /**
- * Call this function th enable/disable the grouping of entries with the same start and end.
- *
- * @param bool $group optional, defaults to true
- * @return void
- */
- public function groupEntries($grouped = true)
- {
- $this->grouped = $grouped;
- }
-
-}
diff --git a/lib/calendar/CalendarView.php b/lib/calendar/CalendarView.php
deleted file mode 100644
index 9d9ebc2..0000000
--- a/lib/calendar/CalendarView.php
+++ /dev/null
@@ -1,344 +0,0 @@
-<?php
-# Lifter010: TODO
-
- /**
- * CalendarView.php - generates a calendar
- *
- * This class takes and checks all necessary parameters to display a calendar/schedule/time-table.
- *
- * 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 Rasmus Fuhse <fuhse@data-quest.de>
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- */
-
-/**
- * Kind of bean class for the calendar view.
- *
- * Example of use:
- *
- * // create a calendar-view and add a column
- * $plan = new CalendarView();
- * $plan->addColumn(_('Spalte 1'))
- * ->addEntry(array(
- * 'id' => 1,
- * 'color' => '#5C2D64',
- * 'start' => '0930',
- * 'end' => '1100',
- * 'title' => 'Mathe 2',
- * 'content' => 'Die Mathematiker kreiden sich mal wieder was an.'
- * )
- * );
- *
- * // display the calendar (containing one column)
- * print $plan->render();
- *
- * @since 2.0
- *
- * @deprecated since Stud.IP 5.5
- */
-
-class CalendarView
-{
-
- protected $entries = [];
- protected $entry_columns = [];
- protected $height = 40;
- protected $grouped = false;
- protected $start_hour = 8;
- protected $end_hour = 21;
- protected $insertFunction = "";
- protected $templates = [];
- protected $read_only = false;
-
- protected static $number_of_instances = 1;
- protected $view_id;
-
- public $sorted_entries = [];
-
-
- /**
- * You need to pass an instance of this class to the template. The constructor
- * expects an array of entries of the following type:
- * array(
- * $day_number => array(array (
- * 'color' => the color in hex (css-like, without the #)
- * 'start' => the (start hour * 100) + (start minute)
- * 'end' => the (end hour * 100) + (end minute)
- * //'day' => day of week (0 = Sunday, ... , 6 = Saturday)
- * 'title' => the entry`s title
- * 'content' => whatever shall be the content of the entry as a string
- * ) ...) ...
- * )
- *
- * @param mixed $entries an array of entries (see above)
- * @param string $controller the name of the controller. Used to create links.
- */
- public function __construct($entries = [])
- {
- if (!is_array($entries)) {
- throw new Exception('You need to pass some entries to the CalendarView!');
- }
- $this->view_id = self::$number_of_instances++;
- $this->checkEntries($entries);
- $this->entries = $entries;
- }
-
- /**
- * set the height for one hour. This value is used to calculate the whole height of the schedule.
- *
- * @param int $entry_height the height of one hour in the schedule
- */
- public function setHeight($height)
- {
- $this->height = $height;
- }
-
- /**
- * set the range of hours to be displayed. the start_hour has to be smaller than the end_hour
- *
- * @param int $start_hour the hour to start displaying at
- * @param int $end_hour the hour to stop displaying at
- */
- public function setRange($start_hour, $end_hour)
- {
- $this->start_hour = $start_hour;
- $this->end_hour = $end_hour;
- }
-
- /**
- * does some plausability checks on an array of calendar-entries
- *
- * @param mixed $entries an array of calendar-entries
- *
- * @return bool false if check failed, true otherwise
- */
- protected function checkEntries($entries)
- {
- foreach ($entries as $column) {
- if (!$column instanceof CalendarColumn) {
- throw new Exception('A column of the entries in the CalenarView is not of type CalendarColumn.');
- }
- }
- return true;
- }
-
- /**
- * adds a new column to this view. All entries created with addEntry will be
- * added to this column.
- *
- * @param string $title like "monday" to be displayed on top of the column
- * @param string $url to be called when clicked on the title of the column
- * @param string $id any kind of id of the column
- * @return CalendarView
- */
- public function addColumn($title, $url = "", $id = null)
- {
- $this->entries[] = CalendarColumn::create($id)
- ->setTitle($title)
- ->setURL($url);
- return $this;
- }
-
-
- /**
- * adds a new entry to the last current column. The entry needs to be an
- * associative array with parameters as follows:
- * @param array $entry_array: associative array for an entry in the column like
- * array (
- * 'color' => the color in hex (css-like, without the #)
- * 'start' => the (start hour * 100) + (start minute)
- * 'end' => the (end hour * 100) + (end minute)
- * 'title' => the entry`s title
- * 'content' => whatever shall be the content of the entry as a string
- * )
- * @return CalendarView
- */
- public function addEntry($entry_array)
- {
- if (count($this->entries)) {
- $this->entries[count($this->entries)-1]->addEntry($entry_array);
- } else {
- throw new InvalidArgumentException(_("Es existiert noch keine Spalte in der Ansicht, zu der der Eintrag hinzugefĂĽgt werden kann."));
- }
- return $this;
- }
-
-
- /**
- * Call this function to enable/disable the grouping of entries with the same start and end.
- *
- * @param bool $group optional, defaults to true
- */
- public function groupEntries($grouped = true)
- {
- $this->grouped = $grouped;
- foreach($this->getColumns() as $entry_column) {
- $entry_column->groupEntries();
- }
- }
-
- /**
- * When a column is clicked at no entry this function is called.
- * First the templates generates a new entry at the clicked time. Then this
- * js-function is called which gets the parameters
- * "function (new_entry_dom_object, column_id, hour) { ... }"
- * with new_entry_dom_object: a real dom-object of the div of the entry
- * column_id: id of the column
- * hour: integer number from 0 to 23
- * If js_function_object is an empty string, nothing will be done.
- *
- * @param string $js_function_object name of js-function or anonymous js-function
- * @return CalendarView
- */
- public function setInsertFunction($js_function_object)
- {
- $this->insertFunction = $js_function_object;
- return $this;
- }
-
- /**
- * outputs the CalendarView with all (grouped) dates in columns.
- *
- * @param array $params you can pass some additional variables to the templates
- *
- * @return string
- */
- public function render($params = [])
- {
- $style_parameters = [
- 'whole_height' => $this->getOverallHeight(),
- 'entry_height' => $this->getHeight()
- ];
- $factory = new Flexi\Factory(dirname(__file__).'/../../app/views');
- PageLayout::addStyle($factory->render('calendar/schedule/stylesheet', $style_parameters));
-
- $template = $GLOBALS['template_factory']->open("calendar/calendar_view.php");
- $template->set_attribute("calendar_view", $this);
- $template->set_attribute("view_id", $this->view_id);
- return $template->render($params);
- }
-
-
- /* * * * * * * * * * * * * * *
- * * * G E T T E R S * * *
- * * * * * * * * * * * * * * */
-
- /**
- * Returns an array of calendar-entries, grouped by day and additionally grouped by same start and end
- * if groupEntries(true) has been called.
- *
- * @return mixed the (double-)grouped entries
- */
- public function getEntries()
- {
- $this->sorted_entries = [];
- foreach ($this->getColumns() as $entry_column) {
- $this->sorted_entries['day_'. $entry_column->getId()] = $entry_column->getGroupedEntries();
- }
- return $this->sorted_entries;
- }
-
- /**
- * Returns an array where for each hour the number of concurrent entries is denoted.
- * Used by the calendar to display the entries in parallel.
- *
- * @return mixed concurrent entries at each hour
- */
- public function getMatrix()
- {
- $matrix = [];
- foreach ($this->getColumns() as $day => $entry_column) {
- $matrix['day_'.$day] = $entry_column->getMatrix();
- }
- return $matrix;
- }
-
-
- /**
- * returns the previously set start- and end-hour, denoting the
- * range of entries to be displayed in the current calendar-view
- *
- * @return array consisting of the start and end hour
- */
- public function getRange()
- {
- return [$this->start_hour, $this->end_hour];
- }
-
- /**
- * the calendar can be used in two modes. Use this function to check,
- * if the grouping-mode is enabled for the current calendar-view
- *
- * @return bool true if grouped, false otherwise
- */
- public function isGrouped()
- {
- return $this->grouped;
- }
-
- /**
- * returns the previously set height for one hour
- *
- * @return mixed the height
- */
- public function getHeight()
- {
- return $this->height;
- }
-
- /**
- * returns the overall height of the calendar
- *
- * @return mixed the overall height
- */
- public function getOverallHeight()
- {
- return $this->height * ($this->end_hour - $this->start_hour) + $this->height
- + 2 + ($this->end_hour - $this->start_hour) * 2;
- }
-
- /**
- * returns the previously set javasscript insert-function
- *
- * @return string name of js-function or anonymous js-function
- */
- public function getInsertFunction() {
- return $this->insertFunction;
- }
-
- /**
- * returns all columns of the calendar-view
- *
- * @return array of CalendarColumn
- */
- public function getColumns() {
- return $this->entries;
- }
-
- /**
- * Set the read-only status of the calendar
- *
- * @param bool $readonly true to make it read only, false otherwise
- *
- * @return void
- */
- public function setReadOnly($readonly = true)
- {
- $this->read_only = $readonly;
- }
-
- /**
- * Return the read-only status of this calendar
- *
- * @return bool the read-only status of this calendar
- */
- public function getReadOnly() {
- return $this->read_only;
- }
-
-}
diff --git a/lib/calendar/CalendarWeekView.php b/lib/calendar/CalendarWeekView.php
deleted file mode 100644
index 1d14ca21..0000000
--- a/lib/calendar/CalendarWeekView.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-# Lifter010: TODO
-
-/**
- * CalendarWeekView.php - a specialized calendar view for displaying weeks
- *
- * This class takes and checks all necessary parameters to display a calendar/schedule/time-table.
- *
- * 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> & Rasmus Fuhse <fuhse@data-quest.de>
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- */
-
-/**
- * Kind of bean class for the calendar view.
- *
- * @since 2.0
- *
- * @deprecated since Stud.IP 5.5
- */
-
-class CalendarWeekView extends CalendarView
-{
- protected $days = [1,2,3,4,5];
- protected $context;
-
-
- /**
- * You need to pass an instance of this class to the template. The constructor
- * expects an array of entries of the following type:
- * array(
- * $day_number => array(array (
- * 'color' => the color in hex (css-like, without the #)
- * 'start' => the (start hour * 100) + (start minute)
- * 'end' => the (end hour * 100) + (end minute)
- * //'day' => day of week (0 = Sunday, ... , 6 = Saturday)
- * 'title' => the entry`s title
- * 'content' => whatever shall be the content of the entry as a string
- * ) ...) ...
- * )
- *
- * @param mixed $entries an array of entries (see above)
- * @param string $controller the name of the controller. Used to create links.
- */
- public function __construct($entries, $controller)
- {
- parent::__construct($entries);
- $this->context = $controller;
- }
-
- /**
- * Call this function th enable/disable the grouping of entries with the same start and end.
- *
- * @param bool $group optional, defaults to true
- */
- public function groupEntries($grouped = true)
- {
- $this->grouped = $grouped;
- foreach($this->entries as $entry_column) {
- $entry_column->groupEntries();
- }
- }
-
- /* * * * * * * * * * * * * * *
- * * * G E T T E R S * * *
- * * * * * * * * * * * * * * */
-
- /**
- * @return mixed the context
- */
- public function getContext()
- {
- return $this->context;
- }
-
- /**
- * @return mixed the days
- */
- public function getDays()
- {
- return $this->days;
- }
-
- /**
- * returns the previously set javasscript insert-function only
- * if read_only is not set.
- *
- * @return string name of js-function or anonymous js-function
- */
- public function getInsertFunction() {
- if (!$this->read_only) {
- return parent::getInsertFunction();
- }
-
- return false;
- }
-
- /**
- * returns all columns of the calendar-view nad removes the url if
- * read_only is set
- *
- * @return array of CalendarColumn
- */
- public function getColumns() {
- // remove links and urls if calendar-view is read-only
- if ($this->read_only) {
- foreach ($this->entries as $column) {
- $column->setURL(false);
- foreach ($column->entries as $key => $entry) {
- unset($column->entries[$key]['url']);
- unset($column->entries[$key]['onClick']);
- unset($column->entries[$key]['icons']);
- }
- }
- }
-
- return parent::getColumns();
- }
-}
diff --git a/lib/calendar/CalendarWidgetView.php b/lib/calendar/CalendarWidgetView.php
deleted file mode 100644
index df980ff..0000000
--- a/lib/calendar/CalendarWidgetView.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * Calendar widget view, links to details page of courses.
- *
- * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
- * @license GPL2 or any later version
- * @since Stud.IP 3.4
- *
- * @deprecated since Stud.IP 5.5
- */
-class CalendarWidgetView extends CalendarWeekView
-{
- /**
- * Creates a widget view from a week view.
- *
- * @param CalendarWeekView $view The CalendarWeekView object
- * @return CalendarWidgetView object with the data from the
- * CalendarWeekView
- */
- public static function createFromWeekView(CalendarWeekView $view)
- {
- $new_view = new self($view->getColumns(), $view->getContext());
- $new_view->setReadOnly(true);
- return $new_view;
- }
-
- /**
- * Returns all columns of the calendar-view and removes everything that
- * is not needed and links the entry to the details page of the course.
- *
- * @return array of CalendarColumn
- */
- public function getColumns()
- {
- foreach ($this->entries as $column) {
- $column->setURL(false);
- foreach ($column->entries as $key => $entry) {
- if (isset($entry['cycle_id'])) {
- list($course_id, $cycle_id) = explode('-', $entry['id']);
-
- $url = URLHelper::getLink('dispatch.php/course/details/?sem_id=' . $course_id);
- $column->entries[$key]['url'] = $url;
- } else {
- unset($column->entries[$key]['url']);
- }
-
- unset($column->entries[$key]['onClick']);
- unset($column->entries[$key]['icons']);
- }
- }
-
- return $this->entries;
- }
-}
diff --git a/lib/classes/JsonApi/Models/ScheduleEntry.php b/lib/classes/JsonApi/Models/ScheduleEntry.php
deleted file mode 100644
index 37001ff..0000000
--- a/lib/classes/JsonApi/Models/ScheduleEntry.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-namespace JsonApi\Models;
-
-class ScheduleEntry extends \SimpleORMap
-{
- protected static function configure($config = array())
- {
- $config['db_table'] = 'schedule';
-
- $config['belongs_to']['user'] = array(
- 'class_name' => 'User',
- 'foreign_key' => 'user_id',
- );
-
- parent::configure($config);
- }
-}
diff --git a/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php b/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php
index 37c1c42..b92a1e8 100644
--- a/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php
+++ b/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php
@@ -5,7 +5,7 @@ namespace JsonApi\Routes\Schedule;
use JsonApi\Errors\AuthorizationFailedException;
use JsonApi\Errors\RecordNotFoundException;
use JsonApi\JsonApiController;
-use JsonApi\Models\ScheduleEntry;
+use \ScheduleEntry;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
diff --git a/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php b/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php
index 6e5bdf4..d1fb024 100644
--- a/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php
+++ b/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php
@@ -5,7 +5,6 @@ namespace JsonApi\Routes\Schedule;
use JsonApi\Errors\AuthorizationFailedException;
use JsonApi\Errors\RecordNotFoundException;
use JsonApi\JsonApiController;
-use JsonApi\Models\ScheduleEntry;
use JsonApi\Routes\Courses\Authority as CourseAuthority;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
diff --git a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php
index 85cf911..033916c 100644
--- a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php
+++ b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php
@@ -5,7 +5,7 @@ namespace JsonApi\Routes\Schedule;
use JsonApi\Errors\AuthorizationFailedException;
use JsonApi\Errors\RecordNotFoundException;
use JsonApi\JsonApiController;
-use JsonApi\Models\ScheduleEntry;
+use \ScheduleEntry;
use JsonApi\Routes\Users\Authority;
use Neomerx\JsonApi\Schema\Link;
use Psr\Http\Message\ResponseInterface as Response;
@@ -57,8 +57,8 @@ class UserScheduleShow extends JsonApiController
{
// get all virtually added seminars
$stmt = \DBManager::get()->prepare(
- 'SELECT c.seminar_id FROM schedule_seminare as c
- LEFT JOIN seminare USING (seminar_id)
+ 'SELECT c.course_id FROM schedule_courses as c
+ LEFT JOIN seminare ON seminare.seminar_id = c.course_id
WHERE user_id = ? AND start_time = ?'
);
$stmt->execute([$user->id, $semester['beginn']]);
diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php
index ff5040d..a5c1213 100644
--- a/lib/classes/JsonApi/SchemaMap.php
+++ b/lib/classes/JsonApi/SchemaMap.php
@@ -14,7 +14,7 @@ class SchemaMap
return [
\Slim\Routing\Route::class => Schemas\SlimRoute::class,
- \JsonApi\Models\ScheduleEntry::class => Schemas\ScheduleEntry::class,
+ \ScheduleEntry::class => Schemas\ScheduleEntry::class,
\Avatar::class => Schemas\Avatar::class,
diff --git a/lib/classes/JsonApi/Schemas/ScheduleEntry.php b/lib/classes/JsonApi/Schemas/ScheduleEntry.php
index 3318f35..0dfbc7d 100644
--- a/lib/classes/JsonApi/Schemas/ScheduleEntry.php
+++ b/lib/classes/JsonApi/Schemas/ScheduleEntry.php
@@ -20,14 +20,14 @@ class ScheduleEntry extends SchemaProvider
public function getAttributes($entry, ContextInterface $context): iterable
{
return [
- 'title' => $entry->title,
+ 'title' => $entry->label,
'description' => mb_strlen(trim($entry->content)) ? $entry->content : null,
- 'start' => $this->formatTime($entry->start),
- 'end' => $this->formatTime($entry->end),
- 'weekday' => (int) $entry->day,
+ 'start' => $this->formatTime($entry->start_time),
+ 'end' => $this->formatTime($entry->end_time),
+ 'weekday' => (int) $entry->dow,
- 'color' => $entry->color,
+ 'color' => '',
];
}
diff --git a/lib/classes/UserManagement.php b/lib/classes/UserManagement.php
index ed349a2..53b5675 100644
--- a/lib/classes/UserManagement.php
+++ b/lib/classes/UserManagement.php
@@ -1203,7 +1203,7 @@ class UserManagement
"DELETE FROM auto_insert_user WHERE user_id = ?",
"DELETE FROM roles_user WHERE userid = ?",
"DELETE FROM schedule WHERE user_id = ?",
- "DELETE FROM schedule_seminare WHERE user_id = ?",
+ "DELETE FROM schedule_courses WHERE user_id = ?",
"DELETE FROM termin_related_persons WHERE user_id = ?",
"DELETE FROM priorities WHERE user_id = ?",
"DELETE FROM help_tour_user WHERE user_id = ?",
diff --git a/lib/classes/calendar/CalendarScheduleModel.php b/lib/classes/calendar/CalendarScheduleModel.php
deleted file mode 100644
index bc884bb..0000000
--- a/lib/classes/calendar/CalendarScheduleModel.php
+++ /dev/null
@@ -1,813 +0,0 @@
-<?php
-# Lifter010: TODO
-
-/*
- * This class is the module for the seminar-schedules in Stud.IP
- *
- * 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
- */
-
-require_once __DIR__ . '/default_color_definitions.php';
-
-/**
- * Pseudo-namespace containing helper methods for the schedule.
- *
- * @since 2.0
- *
- * @deprecated since Stud.IP 5.5
- */
-class CalendarScheduleModel
-{
-
- /**
- * update an existing entry or -if $data['id'] is not set- create a new entry
- *
- * @param mixed $data
- */
- static function storeEntry($data)
- {
- if (!empty($data['id'])) { // update
- $stmt = DBManager::get()->prepare("UPDATE schedule
- SET start = ?, end = ?, day = ?, title = ?, content = ?, color = ?, user_id = ?
- WHERE id = ?");
- $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'],
- $data['content'], $data['color'], $data['user_id'], $data['id']]);
-
- NotificationCenter::postNotification('ScheduleDidUpdate', $GLOBALS['user']->id ?? null, ['values' => $data]);
-
- } else {
- $stmt = DBManager::get()->prepare("INSERT INTO schedule
- (start, end, day, title, content, color, user_id)
- VALUES (?, ?, ?, ?, ?, ?, ?)");
- $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'],
- $data['content'], $data['color'], $data['user_id']]);
- NotificationCenter::postNotification('ScheduleDidCreate', $GLOBALS['user']->id ?? null, ['values' => $data]);
- }
- }
-
- /**
- * Update an existing entry of a course or create a new entry if $data['id'] is not set
- *
- * @param mixed $data the data to store
- * @return void
- */
- static function storeSeminarEntry($data)
- {
- $stmt = DBManager::get()->prepare("REPLACE INTO schedule_seminare
- (seminar_id, user_id, metadate_id, color) VALUES(?, ? ,?, ?)");
-
- $stmt->execute([$data['id'], $GLOBALS['user']->id, $data['cycle_id'], $data['color']]);
- NotificationCenter::postNotification('ScheduleSeminarDidCreate', $GLOBALS['user']->id, $data['cycle_id']);
- }
-
- /**
- * delete the entry with the submitted id, belonging to the current user
- *
- * @param string $id
- * @return void
- */
- static function deleteEntry($id)
- {
- $stmt = DBManager::get()->prepare("DELETE FROM schedule
- WHERE id = ? AND user_id = ?");
- $stmt->execute([$id, $GLOBALS['user']->id]);
- NotificationCenter::postNotification('ScheduleDidDelete', $GLOBALS['user']->id, $id);
- }
-
-
- /**
- * Returns an array of CalendarColumn's containing the
- * schedule entries (optionally of a given id only).
- * The start- and end-hour are used to constrain the returned
- * entries to the passed time-period.
- * If you pass an id, there will be only the single entry with that id in
- * the CalendarColumn
- *
- * @param string $user_id the ID of the user
- * @param int $start_hour the start hour
- * @param int $end_hour the end hour
- * @param string $id optional; the ID of the schedule-entry
- * @return array an array containing the entries
- */
- static function getScheduleEntries($user_id, $start_hour, $end_hour, $id = false)
- {
- $ret = [];
-
- // fetch user-generated entries
- if (!$id) {
- $stmt = DBManager::get()->prepare("SELECT * FROM schedule
- WHERE user_id = ? AND (
- (start >= ? AND end <= ?)
- OR (start <= ? AND end >= ?)
- OR (start <= ? AND end >= ?)
- )");
- $start = $start_hour * 100;
- $end = $end_hour * 100;
- $stmt->execute([$user_id, $start, $end, $start, $start, $end, $end]);
- } else {
- $stmt = DBManager::get()->prepare("SELECT * FROM schedule
- WHERE user_id = ? AND id = ?");
- $stmt->execute([$user_id, $id]);
- }
-
- $entries = $stmt->fetchAll(PDO::FETCH_ASSOC);
- foreach($entries as $entry) {
- $entry['start_formatted'] = sprintf("%02d", floor($entry['start'] / 100)) .':'. sprintf("%02d", floor($entry['start'] % 100));
- $entry['end_formatted'] = sprintf("%02d", floor($entry['end'] / 100)) .':'. sprintf("%02d", floor($entry['end'] % 100));
- $entry['title'] = $entry['title'];
- $entry['content'] = $entry['content'];
- $entry['start_hour'] = sprintf("%02d", floor($entry['start'] / 100));
- $entry['start_minute'] = sprintf("%02d", $entry['start'] % 100);
- $entry['end_hour'] = sprintf("%02d", floor($entry['end'] / 100));
- $entry['end_minute'] = sprintf("%02d", $entry['end'] % 100);
- $entry['url'] = URLHelper::getLink('dispatch.php/calendar/schedule/entry/' . $entry['id']);
- $entry['onClick'] = "function (id) { STUDIP.Schedule.showScheduleDetails('". $entry['id'] ."'); }";
- $entry['visible'] = true;
-
- $day_number = ($entry['day']-1) % 7;
- if (!isset($ret[$day_number])) {
- $ret[$day_number] = CalendarColumn::create($day_number);
- }
- $ret[$day_number]->addEntry($entry);
- }
-
- return $ret;
- }
-
- /**
- * Return an entry for the specified course.
- *
- * @param string $seminar_id the ID of the course
- * @param string $user_id the ID of the user
- * @param mixed $cycle_id either false or the ID of the cycle
- * @param mixed $semester filter for this semester
- *
- * @return array the course's entry
- */
- static function getSeminarEntry($seminar_id, $user_id, $cycle_id = false, $semester = false)
- {
- $ret = [];
- $filterStart = 0;
- $filterEnd = 0;
-
- // filter dates (and their rooms) if semester is passed
- if ($semester) {
- $filterStart = $semester['vorles_beginn'];
- $filterEnd = $semester['vorles_ende'];
- }
-
- $course = Course::find($seminar_id);
- $regular_dates = SeminarCycleDate::findBySeminar($seminar_id);
- foreach ($regular_dates as $cycle) {
- if (!$cycle_id || $cycle->getMetaDateID() == $cycle_id) {
-
- $entry = [];
- $entry['id'] = $seminar_id .'-'. $cycle->getMetaDateId();
- $entry['cycle_id'] = $cycle->getMetaDateId();
- $entry['start_formatted'] = preg_replace('/\:00$/', '', $cycle->start_time);
- $entry['end_formatted'] = preg_replace('/\:00$/', '', $cycle->end_time);
-
- $start_parts = explode(':', $cycle->start_time);
- $end_parts = explode(':', $cycle->end_time);
- $entry['start'] = $start_parts[0] * 100 + $start_parts[1];
- $entry['end'] = $end_parts[0] * 100 + $end_parts[1];
- $entry['day'] = $cycle->weekday;
- $entry['content'] = $course->veranstaltungsnummer . ' ' . $course->name;
-
- $entry['title'] = $cycle->description;
-
- // check, if the date is assigned to a room
- if ($room = $cycle->getMostBookedRoom()) {
- $entry['title'] .= $room->getFullName();
- } else if ($rooms = $cycle->getFreeTextPredominantRoom($filterStart, $filterEnd)) {
- //TODO: replace
- unset($rooms['']);
- if (!empty($rooms)) {
- $entry['title'] .= '('. implode('), (', array_slice(array_keys($rooms), 0, 3)) .')';
- }
- }
-
- // add the lecturer
- $db = DBManager::get();
- $stmt = $db->prepare(
- "SELECT `Nachname`
- FROM `auth_user_md5`
- JOIN `seminar_user` USING (`user_id`)
- WHERE `seminar_id` = :course_id
- ORDER BY `Nachname`
- LIMIT 4"
- );
- $stmt->execute(['course_id' => $course->id]);
- $lecturers = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
-
- $entry['content'] .= " (". implode(', ', array_slice($lecturers, 0, 3))
- . (count($lecturers) > 3 ? ' et al.' : '').')';
-
-
- $entry['url'] = URLHelper::getLink('dispatch.php/calendar/schedule/entry/' . $seminar_id
- . '/' . $cycle->getMetaDateId());
- $entry['onClick'] = "function (id) {
- var ids = id.split('-');
- STUDIP.Schedule.showSeminarDetails(ids[0], ids[1]);
- }";
-
-
- // check the settings for this entry
- $member = CourseMember::find([$course->id, $user_id]);
- $entry['type'] = $member ? 'sem' : 'virtual';
-
- $stmt = $db->prepare('SELECT * FROM schedule_seminare WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?');
- $stmt->execute([$course->id, $user_id, $cycle->getMetaDateId()]);
- $details = $stmt->fetch();
-
- if ($entry['type'] === 'virtual') {
- $entry['color'] = $details ? ($details['color'] ?: DEFAULT_COLOR_VIRTUAL) : DEFAULT_COLOR_VIRTUAL;
- $entry['icons'][] = [
- 'image' => Icon::create('tag', Icon::ROLE_INFO_ALT)->asImagePath(),
- 'title' => _("Dies ist eine vorgemerkte Veranstaltung")
- ];
- } else {
- $entry['color'] = !empty($details['color']) ? $details['color'] : ($member->gruppe % 9 + 1);
- }
- $entry['visible'] = $details ? $details['visible'] : 1;
-
- // show an unhide icon if entry is invisible
- if (!$entry['visible']) {
- $entry['url'] .= '/?show_hidden=1';
-
- $bind_url = URLHelper::getLink('dispatch.php/calendar/schedule/bind/'
- . $seminar_id . '/' . $cycle->getMetaDateId() . '/?show_hidden=1');
-
- $entry['icons'][] = [
- 'url' => $bind_url,
- 'image' => Icon::create('visibility-invisible', Icon::ROLE_INFO_ALT)->asImagePath(),
- 'onClick' => "function(id) { window.location = '". $bind_url ."'; }",
- 'title' => _("Diesen Eintrag wieder einblenden"),
- ];
- }
-
- // show a hide-icon if the entry is not virtual
- else if ($entry['type'] != 'virtual') {
- $unbind_url = URLHelper::getLink('dispatch.php/calendar/schedule/unbind/'
- . $seminar_id . '/' . $cycle->getMetaDateId());
- $entry['icons'][] = [
- 'url' => $unbind_url,
- 'image' => Icon::create('visibility-visible', Icon::ROLE_INFO_ALT)->asImagePath(),
- 'onClick' => "function(id) { window.location = '". $unbind_url ."'; }",
- 'title' => _("Diesen Eintrag ausblenden"),
- ];
-
- }
-
- $ret[] = $entry;
- }
- }
-
- return $ret;
- }
-
- /**
- * Deletes the schedule entries of one user for one seminar.
- *
- * @param string $user_id the user of the schedule
- * @param string $seminar_id the seminar which entries should be deleted
- */
- static function deleteSeminarEntries($user_id, $seminar_id)
- {
- $stmt = DBManager::get()->prepare($query = "DELETE FROM schedule_seminare
- WHERE user_id = ? AND seminar_id = ?");
- $stmt->execute([$user_id, $seminar_id]);
- NotificationCenter::postNotification('ScheduleSeminarDidDelete', $GLOBALS['user']->id, $seminar_id);
- }
-
- /**
- * Returns an array of CalendarColumn's, containing the seminar-entries
- * for the passed user in the passed semester.
- * The start- and end-hour are used to constrain the returned
- * entries to the passed time-period.
- * Seminar-entries can be hidden, so you can opt-in to fetch the hidden
- * ones as well.
- *
- * @param string $user_id the ID of the user
- * @param string $semester an array containing the "beginn" of the semester
- * @param int $start_hour the start hour
- * @param int $end_hour the end hour
- * @param string $show_hidden optional; true to show hidden, false otherwise
- * @return array an array containing the properties of the entry
- */
- static function getSeminarEntries($user_id, $semester, $start_hour, $end_hour, $show_hidden = false)
- {
- $seminars = [];
-
- // get all virtually added seminars
- $stmt = DBManager::get()->prepare("SELECT * FROM schedule_seminare as c
- LEFT JOIN seminare as s ON (s.Seminar_id = c.Seminar_id)
- LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id)
- WHERE c.user_id = ? AND s.start_time <= ? AND
- (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?)");
- $stmt->execute([$user_id, $semester['beginn'], $semester['id']]);
-
- while ($entry = $stmt->fetch()) {
- $seminars[$entry['seminar_id']] = [
- 'Seminar_id' => $entry['seminar_id']
- ];
- }
-
- // fetch seminar-entries
- $stmt = DBManager::get()->prepare("SELECT s.Seminar_id FROM seminar_user as su
- LEFT JOIN seminare as s USING (Seminar_id)
- LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id)
- WHERE su.user_id = :userid
- AND s.start_time <= :begin
- AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id)
- ");
- $stmt->bindValue(':begin', $semester['beginn']);
- $stmt->bindValue(':semester_id', $semester['semester_id']);
- $stmt->bindValue(':userid', $user_id);
- $stmt->execute();
-
- while ($entry = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $seminars[$entry['Seminar_id']] = [
- 'Seminar_id' => $entry['Seminar_id']
- ];
- }
-
- $ret = [];
- foreach ($seminars as $data) {
- $entries = self::getSeminarEntry($data['Seminar_id'], $user_id, false, $semester);
-
- foreach ($entries as $entry) {
- if (($entry['start'] >= $start_hour * 100 && $entry['start'] <= $end_hour * 100
- || $entry['end'] >= $start_hour * 100 && $entry['end'] <= $end_hour * 100)
- && ($show_hidden || (!$show_hidden && $entry['visible']))) {
- $day_number = ($entry['day'] + 6) % 7;
- if (!isset($ret[$day_number])) {
- $ret[$day_number] = new CalendarColumn();
- }
-
- $ret[$day_number]->addEntry($entry);
- }
- }
- }
-
- return $ret;
-
- }
-
-
- /**
- * Returns an array of CalendarColumn's, containing the seminar-entries
- * for the passed user in the passed semester belonging to the passed institute.
- * The start- and end-hour are used to constrain the returned
- * entries to the passed time-period.
- *
- * @param string $user_id the ID of the user
- * @param array $semester an array containing the "beginn" of the semester
- * @param int $start_hour the start hour
- * @param int $end_hour the end hour
- * @param string $institute_id the ID of the institute
- * @return array an array containing the entries
- */
- static function getSeminarEntriesForInstitute($user_id, $semester, $start_hour, $end_hour, $institute_id)
- {
- $ret = [];
-
- // fetch seminar-entries
- $visibility_perms = $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM);
- $stmt = DBManager::get()->prepare("SELECT *
- FROM seminare
- LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
- WHERE Institut_id = :institute
- AND start_time <= :begin
- AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) "
- . (!$visibility_perms ? " AND visible='1'" : ""));
-
- $stmt->bindParam(':begin', $semester['beginn']);
- $stmt->bindParam(':semester_id', $semester['semester_id']);
- $stmt->bindParam(':institute', $institute_id);
- $stmt->execute();
-
- $seminars = $stmt->fetchAll(PDO::FETCH_ASSOC);
-
- foreach ($seminars as $data) {
- $entries = self::getSeminarEntry($data['Seminar_id'], $user_id, false, $semester);
-
- foreach ($entries as $entry) {
- unset($entry['url']);
- $entry['onClick'] = 'function(id) { STUDIP.Schedule.showInstituteDetails(id); }';
-
- if (($entry['start'] >= $start_hour * 100 && $entry['start'] <= $end_hour * 100
- || $entry['end'] >= $start_hour * 100 && $entry['end'] <= $end_hour * 100)) {
-
- $entry['color'] = DEFAULT_COLOR_SEM;
-
- $day_number = ($entry['day'] + 6) % 7;
- if (!isset($ret[$day_number])) {
- $ret[$day_number] = CalendarColumn::create($entry['day']);
- }
-
- $ret[$day_number]->addEntry($entry);
- }
- }
- }
-
- return $ret;
- }
-
-
- /**
- * Returns the ID of the cycle of a course specified by start and end.
- *
- * @param string $course_id The ID of a course.
- * @param string $start the start of the cycle
- * @param string $end the end of the cycle
- * @return string $day numeric day
- */
- static function getSeminarCycleId($course_id, $start, $end, $day)
- {
- $ret = [];
-
- $day = ($day + 1) % 7;
-
- $regular_dates = SeminarCyCleDate::findBySeminar($course_id);
-
- foreach ($regular_dates as $cycle) {
- $cycle_start = preg_replace('/\:00$/', '', $cycle->start_time);
- $cycle_end = preg_replace('/\:00$/', '', $cycle->end_time);
- if (
- leadingZero($cycle_start) == $start
- && leadingZero($cycle_end) == $end
- && $cycle->weekday == $day
- ) {
- $ret[] = $cycle;
- }
- }
-
- return $ret;
- }
-
- /**
- * check if the passed cycle of the passed id is visible
- * for the currently logged in user int the schedule
- *
- * @param string the ID of the course
- * @param string the ID of the cycle
- * @return bool true if visible, false otherwise
- */
- static function isSeminarVisible($seminar_id, $cycle_id)
- {
- $stmt = DBManager::get()->prepare("SELECT visible
- FROM schedule_seminare
- WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?");
- $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]);
- if (!$data = $stmt->fetch()) {
- return true;
- } else {
- return $data['visible'] ? true : false;
- }
- }
-
- /**
- * Returns an array of CalendarColumn's, containing the seminar-entries
- * for the passed user (in the passed semester belonging to the passed institute)
- * and the user-defined schedule-entries.
- * The start- and end-hour are used to constrain the returned
- * entries to the passed time-period. The passed days constrain the entries
- * to these.
- * Seminar-entries can be hidden, so you can opt-in to fetch the hidden
- * ones as well.
- *
- * @param string $user_id the user's ID
- * @param string $semester the data for the semester to be displayed
- * @param int $start_hour the start hour of the entries
- * @param int $end_hour the end hour of the entries
- * @param string $institute_id the institute's ID
- * @param array $days days to be displayed
- * @param bool $show_hidden filters hidden entries
- * @return array an array of entries
- */
- static function getInstituteEntries($user_id, $semester, $start_hour, $end_hour, $institute_id, $days, $show_hidden = false)
- {
- // merge the schedule and seminar-entries
- $entries = self::getScheduleEntries($user_id, $start_hour, $end_hour, false);
- $seminar = self::getSeminarEntriesForInstitute($user_id, $semester, $start_hour, $end_hour, $institute_id, $show_hidden);
-
- foreach($seminar as $day => $entry_column) {
- foreach ($entry_column->getEntries() as $entry) {
- if (!isset($entries[$day])) {
- $entries[$day] = CalendarColumn::create($day);
- }
- $entries[$day]->addEntry($entry);
- }
- }
-
- return self::addDayChooser($entries, $days);
- }
-
- /**
- *
- *
- * @param string $user_id
- * @param mixed $semester the data for the semester to be displayed
- */
-
- /**
- * Returns an array of CalendarColumn's, containing the seminar-entries
- * for the passed user (in the passed semester) and the user-defined schedule-entries.
- * The start- and end-hour are used to constrain the returned
- * entries to the passed time-period. The passed days constrain the entries
- * to these.
- * Seminar-entries can be hidden, so you can opt-in to fetch the hidden
- * ones as well.
- *
- * @param string $user_id the user's ID
- * @param string $semester the data for the semester to be displayed
- * @param int $start_hour the start hour of the entries
- * @param int $end_hour the end hour of the entries
- * @param array $days days to be displayed
- * @param bool $show_hidden filters hidden entries
- * @return array
- */
- static function getEntries($user_id, $semester, $start_hour, $end_hour, $days, $show_hidden = false)
- {
- // merge the schedule and seminar-entries
- $entries = self::getScheduleEntries($user_id, $start_hour, $end_hour, false);
- $seminar = self::getSeminarEntries($user_id, $semester, $start_hour, $end_hour, $show_hidden);
- foreach($seminar as $day => $entry_column) {
- foreach ($entry_column->getEntries() as $entry) {
- if (!isset($entries[$day])) {
- $entries[$day] = CalendarColumn::create($day);
- }
- $entries[$day]->addEntry($entry);
- }
- }
-
- return self::addDayChooser($entries, $days);
- }
-
- /**
- * adds title and link to CalendarColumn-objects and sorts the objects to be
- * displayed correctly in the calendar-view
- *
- * @param array $entries an array of CalendarColumn-objects
- * @param array $days an array of int's, denoting the days to be displayed
- * @return array
- */
- static function addDayChooser($entries, $days, $controller = 'schedule') {
- $day_names = [_("Mo"),_("Di"),_("Mi"),
- _("Do"),_("Fr"),_("Sa"),_("So")];
-
- $ret = [];
-
- foreach ($days as $day) {
- if (!isset($entries[$day])) {
- $ret[$day] = CalendarColumn::create($day);
- } else {
- $ret[$day] = $entries[$day];
- }
-
- if (sizeof($days) == 1) {
- $ret[$day]->setTitle($day_names[$day] .' ('. _('zurĂĽck zur Wochenansicht') .')')
- ->setURL('dispatch.php/calendar/'. $controller .'/index');
- } else {
- $ret[$day]->setTitle($day_names[$day])
- ->setURL('dispatch.php/calendar/'. $controller .'/index/'. $day);
- }
- }
-
- return $ret;
- }
-
- /**
- * Toggle entries' visibility
- *
- * @param string $seminar_id the course's ID
- * @param string $cycle_id the cycle's ID
- * @param bool $visible the value to switch to
- * @return void
- */
- static function adminBind($seminar_id, $cycle_id, $visible = true)
- {
- $stmt = DBManager::get()->prepare("SELECT * FROM schedule_seminare
- WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?");
- $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]);
-
- if ($stmt->fetch()) {
- $stmt = DBManager::get()->prepare("UPDATE schedule_seminare
- SET visible = ?
- WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?");
- } else {
- $stmt = DBManager::get()->prepare("INSERT INTO schedule_seminare
- (visible, seminar_id, user_id, metadate_id)
- VALUES(?, ?, ?, ?)");
- }
-
- $stmt->execute([$visible ? '1' : '0', $seminar_id, $GLOBALS['user']->id, $cycle_id]);
-
- }
-
- /**
- * Switch a seminars' cycle to invisible.
- *
- * @param string $seminar_id the course's ID
- * @param string $cycle_id the cycle's ID
- * @return void
- */
- public static function unbind($seminar_id, $cycle_id = null)
- {
- $stmt = DBManager::get()->prepare("SELECT su.*, sc.seminar_id as present
- FROM seminar_user as su
- LEFT JOIN schedule_seminare as sc ON (su.Seminar_id = sc.seminar_id
- AND sc.user_id = su.user_id AND sc.metadate_id = ?)
- WHERE su.Seminar_id = ? AND su.user_id = ?");
- $stmt->execute([$cycle_id, $seminar_id, $GLOBALS['user']->id]);
-
- // if we are participant of the seminar, just hide the entry
- if ($data = $stmt->fetch()) {
- if ($data['present']) {
- $stmt = DBManager::get()->prepare("UPDATE schedule_seminare
- SET visible = 0
- WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?");
- } else {
- $stmt = DBManager::get()->prepare("INSERT IGNORE INTO schedule_seminare
- (seminar_id, user_id, metadate_id, visible)
- VALUES(?, ?, ?, 0)");
- }
- $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]);
- }
-
- // otherwise delete the entry
- else {
- $stmt = DBManager::get()->prepare("DELETE FROM schedule_seminare
- WHERE seminar_id = ? AND user_id = ?");
- $stmt->execute([$seminar_id, $GLOBALS['user']->id]);
- NotificationCenter::postNotification('ScheduleSeminarDidDelete', $GLOBALS['user']->id, $seminar_id);
- }
- }
-
- /**
- * Switch a seminars' cycle to visible.
- *
- * @param string $seminar_id the course's ID
- * @param string $cycle_id the cycle's ID
- * @return void
- */
- static function bind($seminar_id, $cycle_id)
- {
- $stmt = DBManager::get()->prepare("UPDATE schedule_seminare
- SET visible = 1
- WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?");
-
- $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]);
- }
-
- /**
- * Get the schedule_settings from the user's config
- *
- * @param string $user_id the user to get the settings for, defaults
- * to current user
- * @return mixed the settings
- */
- static function getScheduleSettings($user_id = false)
- {
- if (!$user_id) {
- $user_id = $GLOBALS['user']->id;
- }
-
- $schedule_settings = UserConfig::get($user_id)->SCHEDULE_SETTINGS;
-
- // convert old settings, if necessary (mein_stundenplan.php)
- if (!$schedule_settings['converted']) {
- $schedule_settings['glb_days'] = [0, 1, 2, 3, 4];
- $schedule_settings['converted'] = true;
- }
-
- return $schedule_settings;
- }
-
- /**
- * Transforms day settings from SCHEDULE_SETTINGS::glb_days to valid
- * days that can be displayed.
- *
- * @param array $input Input from SCHEDULE_SETTINGS
- * @return array
- */
- public static function getDisplayedDays(array $input)
- {
- $days = [];
- foreach ($input as $key => $value) {
- // Fallback for old entries (["mo": true, ...])
- if (!is_numeric($key) || !is_numeric($value)) {
- $days = [6, 0, 1, 2, 3];
- break;
- }
- $days[$key] = ($value + 6) % 7;
- }
- return $days;
- }
-
- /**
- * Return the semester-entry for the current semester
- *
- * @return mixed the current semester
- */
- static function getCurrentSemester()
- {
- return Semester::findCurrent();
- }
-
- /**
- * Create a CalendarWeekView (a schedule) for an institute
- * for the current user and return it.
- *
- * @param string $institute_id the institute to get the calendar for
- * @param bool $show_hidden show hidden entries
- * @param mixed $semester the semester to use
- * @param mixed $days the days to consider
- *
- * @return CalendarWeekView
- */
- static function getInstCalendarView($institute_id, $show_hidden = false, $semester = false, $days = false)
- {
- $schedule_settings = self::getScheduleSettings();
-
- if (!$semester) {
- $semester = self::getCurrentSemester();
- }
-
- if (!$days) {
- $days = self::getDisplayedDays($schedule_settings['glb_days']);
- }
-
- $user_id = $GLOBALS['user']->id;
-
- $entries = CalendarScheduleModel::getInstituteEntries(
- $user_id,
- $semester,
- $schedule_settings['glb_start_time'],
- $schedule_settings['glb_end_time'],
- $institute_id,
- $days,
- $show_hidden
- );
-
- $view = new CalendarWeekView($entries, 'schedule');
-
- $view->setHeight(40 + (20 * $schedule_settings['zoom']));
- $view->setRange($schedule_settings['glb_start_time'], $schedule_settings['glb_end_time']);
-
- // group entries in institute calendar
- $view->groupEntries(); // if enabled, group entries with same start- and end-date
-
- return $view;
- }
-
- /**
- * Create a CalendarWeekView (a schedule) for the current user and return it.
- *
- * @param string $user_id the institute to get the calendar for
- * @param bool $show_hidden show hidden entries
- * @param mixed $semester the semester to use
- * @param mixed $days the days to consider
- *
- * @return CalendarWeekView
- */
- static function getUserCalendarView($user_id, $show_hidden = false, $semester = false, $days = false)
- {
- $schedule_settings = self::getScheduleSettings($user_id);
-
- if (!$semester) {
- $semester = self::getCurrentSemester();
- }
-
- if (!$days) {
- $days = self::getDisplayedDays($schedule_settings['glb_days']);
- }
-
- $entries = CalendarScheduleModel::getEntries(
- $user_id,
- $semester,
- $schedule_settings['glb_start_time'],
- $schedule_settings['glb_end_time'],
- $days,
- $show_hidden
- );
-
- $view = new CalendarWeekView($entries, 'schedule');
-
- $view->setHeight(40 + (20 * ($schedule_settings['zoom'] ?? 0)));
- $view->setRange($schedule_settings['glb_start_time'], $schedule_settings['glb_end_time']);
- $view->setInsertFunction("function (entry, column, hour, end_hour) {
- STUDIP.Schedule.newEntry(entry, column, hour, end_hour)
- }");
-
- return $view;
- }
-}
diff --git a/lib/classes/calendar/Helper.php b/lib/classes/calendar/Helper.php
index cd3163a..dd86007 100644
--- a/lib/classes/calendar/Helper.php
+++ b/lib/classes/calendar/Helper.php
@@ -108,4 +108,65 @@ class Helper
return $default_date;
}
+
+ /**
+ * Constructs a Fullcalendar instance of the schedule for the current user.
+ *
+ * @param string $semester_id The ID of the semester to be used. Defaults to an empty string
+ * which in turn means that the current semester shall be used.
+ *
+ * @param bool $show_hidden_courses Whether to include hidden courses in the schedule (true)
+ * or not (false). Defaults to false.
+ *
+ * @return \Studip\Fullcalendar A fullcalendar instance for the schedule of the current user.
+ */
+ public static function getScheduleFullcalendar(
+ string $semester_id = '',
+ bool $show_hidden_courses = false
+ ) : \Studip\Fullcalendar
+ {
+ if (!$semester_id) {
+ $semester_id = \Semester::findCurrent()?->id ?? '';
+ }
+ $calendar_settings = \User::findCurrent()->getConfiguration()->CALENDAR_SETTINGS ?? [];
+
+ return new \Studip\Fullcalendar(
+ _('Stundenplan'),
+ [
+ 'editable' => false,
+ 'selectable' => false,
+ 'dialog_size' => 'auto',
+ 'minTime' => sprintf('%02u:00', $calendar_settings['start'] ?? 8),
+ 'maxTime' => sprintf('%02u:00', $calendar_settings['end'] ?? 20),
+ 'allDaySlot' => false,
+ 'header' => [
+ 'left' => '',
+ 'right' => ''
+ ],
+ 'views' => [
+ 'timeGridWeek' => [
+ 'columnHeaderFormat' => ['weekday' => 'long'],
+ 'weekends' => $calendar_settings['type_week'] === 'LONG',
+ 'slotDuration' => self::getCalendarSlotDuration('week'),
+ ]
+ ],
+ 'defaultView' => 'timeGridWeek',
+ 'defaultDate' => date('Y-m-d'),
+ 'timeGridEventMinHeight' => 20,
+ 'eventSources' => [
+ [
+ 'url' => \URLHelper::getURL(
+ 'dispatch.php/calendar/schedule/data',
+ ['show_hidden' => $show_hidden_courses]
+ ),
+ 'method' => 'GET',
+ 'extraParams' => [
+ 'semester_id' => $semester_id,
+ 'full_semester_time_range' => false
+ ]
+ ]
+ ]
+ ]
+ );
+ }
}
diff --git a/lib/models/Course.php b/lib/models/Course.php
index ea6676c..b252063 100644
--- a/lib/models/Course.php
+++ b/lib/models/Course.php
@@ -334,7 +334,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
WikiPageConfig::deleteByRange_id($course->id);
//Remove all entries of the course in calendars:
- $query = 'DELETE FROM `schedule_seminare` WHERE `seminar_id` = ?';
+ $query = 'DELETE FROM `schedule_courses` WHERE `course_id` = ?';
$statement = DBManager::get()->execute($query, [$course->id]);
//Remove connections to other e-learning systems:
@@ -1114,7 +1114,13 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
}
//Delete course entries in the schedule:
- CalendarScheduleModel::deleteSeminarEntries($user->id, $this->id);
+ ScheduleCourseDate::deleteBySQL(
+ 'user_id = :user_id AND course_id = :course_id',
+ [
+ 'user_id' => $user->id,
+ 'course_id' => $this->id
+ ]
+ );
//Log the event:
StudipLog::log('SEM_USER_ADD', $this->id, $user->id, $permission_level, 'Wurde in die Veranstaltung eingetragen');
diff --git a/lib/models/CourseDate.php b/lib/models/CourseDate.php
index 3f13904..943bf23 100644
--- a/lib/models/CourseDate.php
+++ b/lib/models/CourseDate.php
@@ -549,7 +549,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
IFNULL(`termine`.`metadate_id`, '') = ''
OR `termine`.`metadate_id` NOT IN (
SELECT `metadate_id`
- FROM `schedule_seminare`
+ FROM `schedule_courses`
WHERE `user_id` = :user_id
AND `visible` = 0
)
diff --git a/lib/models/CourseExDate.php b/lib/models/CourseExDate.php
index 2d3afea..eb0f90a 100644
--- a/lib/models/CourseExDate.php
+++ b/lib/models/CourseExDate.php
@@ -261,7 +261,7 @@ class CourseExDate extends SimpleORMap implements PrivacyObject, Event
IFNULL(`ex_termine`.`metadate_id`, '') = ''
OR `ex_termine`.`metadate_id` NOT IN (
SELECT `metadate_id`
- FROM `schedule_seminare`
+ FROM `schedule_courses`
WHERE `user_id` = :user_id
AND `visible` = 0
)
diff --git a/lib/models/SeminarCycleDate.php b/lib/models/SeminarCycleDate.php
index ae85121..13b2520 100644
--- a/lib/models/SeminarCycleDate.php
+++ b/lib/models/SeminarCycleDate.php
@@ -442,7 +442,7 @@ class SeminarCycleDate extends SimpleORMap
$result = parent::delete();
if ($result) {
- $stmt = DBManager::get()->prepare('DELETE FROM schedule_seminare WHERE metadate_id = :metadate_id');
+ $stmt = DBManager::get()->prepare('DELETE FROM schedule_courses WHERE metadate_id = :metadate_id');
$stmt->execute(['metadate_id' => $metadate_id]);
StudipLog::log('SEM_DELETE_CYCLE', $seminar_id, null, $cycle_info);
diff --git a/lib/models/calendar/CalendarCourseDate.php b/lib/models/calendar/CalendarCourseDate.php
index 370dcd1..b312bda 100644
--- a/lib/models/calendar/CalendarCourseDate.php
+++ b/lib/models/calendar/CalendarCourseDate.php
@@ -24,7 +24,7 @@ class CalendarCourseDate extends CourseDate
IFNULL(`termine`.`metadate_id`, '') = ''
OR `termine`.`metadate_id` NOT IN (
SELECT `metadate_id`
- FROM `schedule_seminare`
+ FROM `schedule_courses`
WHERE `user_id` = :user_id
AND `visible` = 0
)
diff --git a/lib/models/calendar/CalendarCourseExDate.php b/lib/models/calendar/CalendarCourseExDate.php
index eb23aeb..5e979a8 100644
--- a/lib/models/calendar/CalendarCourseExDate.php
+++ b/lib/models/calendar/CalendarCourseExDate.php
@@ -19,7 +19,7 @@ class CalendarCourseExDate extends CourseExDate
IFNULL(`ex_termine`.`metadate_id`, '') = ''
OR `ex_termine`.`metadate_id` NOT IN (
SELECT `metadate_id`
- FROM `schedule_seminare`
+ FROM `schedule_courses`
WHERE `user_id` = :user_id
AND `visible` = 0
)
diff --git a/lib/models/calendar/ScheduleCourseDate.php b/lib/models/calendar/ScheduleCourseDate.php
new file mode 100644
index 0000000..9d05a72
--- /dev/null
+++ b/lib/models/calendar/ScheduleCourseDate.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * ScheduleCourseDate.php - Model class for regular course dates
+ * in the schedule 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 Moritz Strohm <strohm@data-quest.de>
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ * @since 6.0
+ *
+ * @property string $user_id database column
+ * @property string $course_id database column
+ * @property string $metadate_id database_column
+ * @property string $visible database column
+ * @property string $mkdate database column
+ * @property string $chdate database column
+ */
+class ScheduleCourseDate extends SimpleORMap
+{
+ protected static function configure($config = [])
+ {
+ $config['db_table'] = 'schedule_courses';
+ $config['belongs_to']['user'] = [
+ 'class_name' => User::class,
+ 'foreign_key' => 'user_id',
+ ];
+ $config['belongs_to']['course'] = [
+ 'class_name' => Course::class,
+ 'foreign_key' => 'course_id',
+ ];
+ $config['belongs_to']['regular_date'] = [
+ 'class_name' => SeminarCycleDate::class,
+ 'foreign_key' => 'metadate_id'
+ ];
+ parent::configure($config);
+ }
+}
diff --git a/lib/models/calendar/ScheduleEntry.php b/lib/models/calendar/ScheduleEntry.php
new file mode 100644
index 0000000..f1e23fd
--- /dev/null
+++ b/lib/models/calendar/ScheduleEntry.php
@@ -0,0 +1,341 @@
+<?php
+/**
+ * ScheduleEntry.php - Model class for regular dates
+ * in the schedule view that are not bound to a course.
+ *
+ * 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 Moritz Strohm <strohm@data-quest.de>
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ * @since 6.0
+ *
+ * @property string $id database column
+ * @property string $start_time database column
+ * @property string $end_time database column
+ * @property string $dow database column
+ * @property string $label database column
+ * @property string $content database column
+ * @property string $user_id database column
+ * @property string $mkdate database column
+ * @property string $chdate database column
+ */
+class ScheduleEntry extends SimpleORMap implements Event
+{
+ protected static function configure($config = [])
+ {
+ $config['db_table'] = 'schedule_entries';
+ $config['belongs_to']['user'] = [
+ 'class_name' => User::class,
+ 'foreign_key' => 'user_id'
+ ];
+ parent::configure($config);
+ }
+
+ /**
+ * A helper method to set the content of the start attribute by a formatted date
+ * in the format HH:mm.
+ *
+ * @param string $formatted_start The formatted date in the format HH:mm.
+ */
+ public function setFormattedStart(string $formatted_start) : void
+ {
+ $this->start_time = str_replace(':', '', $formatted_start);
+ }
+
+ /**
+ * A helper method to set the content of the end attribute by a formatted date
+ * in the format HH:mm.
+ *
+ * @param string $formatted_end The formatted date in the format HH:mm.
+ */
+ public function setFormattedEnd(string $formatted_end) : void
+ {
+ $this->end_time = str_replace(':', '', $formatted_end);
+ }
+
+ /**
+ * Formats the start time for human-readable output.
+ *
+ * @return string The start time in the format HH:mm or an empty string in case
+ * the format stored in the start attribute is not supported.
+ */
+ public function getFormattedStart() : string
+ {
+ if (strlen($this->start_time) === 3) {
+ return '0' . substr($this->start_time, 0, 1) . ':' . substr($this->start_time, 1, 2);
+ }
+
+ if (strlen($this->start_time) === 4) {
+ return substr($this->start_time, 0, 2) . ':' . substr($this->start_time, 2, 2);
+ }
+
+ //Invalid date format:
+ return '';
+ }
+
+ /**
+ * Formats the end time for human-readable output.
+ *
+ * @return string The end time in the format HH:mm or an empty string in case
+ * the format stored in the end attribute is not supported.
+ */
+ public function getFormattedEnd() : string
+ {
+ if (strlen($this->end_time) === 3) {
+ return '0' . substr($this->end_time, 0, 1) . ':' . substr($this->end_time, 1, 2);
+ }
+
+ if (strlen($this->end_time) === 4) {
+ return substr($this->end_time, 0, 2) . ':' . substr($this->end_time, 2, 2);
+ }
+
+ //Invalid date format:
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public static function getEvents(DateTime $begin, DateTime $end, string $range_id): array
+ {
+ return self::findBySQL(
+ "`user_id` = :range_id
+ AND `start` < :end AND `end` > :start
+ AND `day` >= :start_day AND day <= :end_day",
+ [
+ 'range_id' => $range_id,
+ 'start' => $begin->format('Hi'),
+ 'end' => $end->format('Hi'),
+ 'start_day' => $begin->format('N'),
+ 'end_day' => $end->format('N')
+ ]
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getObjectId(): string
+ {
+ return $this->id;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getPrimaryObjectID(): string
+ {
+ return $this->user_id;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getObjectClass(): string
+ {
+ return self::class;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle(): string
+ {
+ return $this->label;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBegin(): DateTime
+ {
+ //Map the entry to the current week:
+ $date = new DateTime();
+ $date->setTimestamp(strtotime('midnight this week'));
+ if ($this->dow > 1) {
+ $days_to_add = $this->dow - 1;
+ $date = $date->add(new DateInterval(sprintf('P%dD', $days_to_add)));
+ }
+ $time_parts = explode(':', $this->getFormattedStart());
+ $date->setTime($time_parts[0], $time_parts[1]);
+ return $date;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEnd(): DateTime
+ {
+ //Map the entry to the current week:
+ $date = new DateTime();
+ $date->setTimestamp(strtotime('midnight this week'));
+ if ($this->dow > 1) {
+ $days_to_add = $this->dow - 1;
+ $date = $date->add(new DateInterval(sprintf('P%dD', $days_to_add)));
+ }
+ $time_parts = explode(':', $this->getFormattedEnd());
+ $date->setTime($time_parts[0],$time_parts[1]);
+ return $date;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDuration(): DateInterval
+ {
+ return $this->getEnd()->diff($this->getBegin());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getLocation(): string
+ {
+ //No location supported.
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getUniqueId(): string
+ {
+ return implode('_', [
+ Config::get()->STUDIP_INSTALLATION_ID,
+ self::class,
+ $this->id,
+ ]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription(): string
+ {
+ return $this->content;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getAdditionalDescriptions(): array
+ {
+ //No additional description supported.
+ return [];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isAllDayEvent(): bool
+ {
+ return $this->start_time === '000' && $this->end_time === '2359';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isWritable(string $user_id): bool
+ {
+ //Only the owner and root may edit the entry:
+ return $user_id === $this->user_id
+ || $GLOBALS['perm']->have_perm('root', $user_id);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCreationDate(): DateTime
+ {
+ $date = new DateTime();
+ $date->setTimestamp($this->mkdate);
+ return $date;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getModificationDate(): DateTime
+ {
+ $date = new DateTime();
+ $date->setTimestamp($this->chdate);
+ return $date;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getImportDate(): DateTime
+ {
+ //The import date is not supported. Use mkdate instead.
+ $date = new DateTime();
+ $date->setTimestamp($this->mkdate);
+ return $date;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getAuthor(): ?User
+ {
+ return $this->user;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEditor(): ?User
+ {
+ return $this->user;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function toEventData(string $user_id): \Studip\Calendar\EventData
+ {
+ return new \Studip\Calendar\EventData(
+ $this->getBegin(),
+ $this->getEnd(),
+ $this->label,
+ ['schedule-entry'],
+ '#000000',
+ '#ffffff',
+ $this->isWritable($user_id),
+ self::class,
+ $this->id,
+ User::class,
+ $this->user_id,
+ User::class,
+ $this->user_id,
+ [
+ 'show' => URLHelper::getURL('dispatch.php/calendar/schedule/entry/' . $this->id)
+ ],
+ [],
+ '',
+ '#000000',
+ $this->isAllDayEvent()
+ );
+ }
+
+ /**
+ * Creates a string representation of the schedule entry.
+ *
+ * @return string A human-readable string describing the schedule entry.
+ */
+ public function toString() : string
+ {
+ return studip_interpolate(
+ _('Termin jeden %{dow} von %{start_time} bis %{end_time} Uhr'),
+ [
+ 'dow' => getWeekday($this->dow % 7, false),
+ 'start_time' => $this->getFormattedStart(),
+ 'end_time' => $this->getFormattedEnd()
+ ]
+ );
+ }
+}
diff --git a/lib/modules/ScheduleWidget.php b/lib/modules/ScheduleWidget.php
index c4ab769..42a0814 100644
--- a/lib/modules/ScheduleWidget.php
+++ b/lib/modules/ScheduleWidget.php
@@ -39,16 +39,8 @@ class ScheduleWidget extends CorePlugin implements PortalPlugin
*/
public function getPortalTemplate()
{
- $view = CalendarScheduleModel::getUserCalendarView(
- $GLOBALS['user']->id,
- false,
- false,
- $days = [0, 1, 2, 3, 4]
- );
-
- $template = $GLOBALS['template_factory']->open('shared/string');
- $template->content = CalendarWidgetView::createFromWeekView($view)->render();
-
+ $template = $GLOBALS['template_factory']->open('start/schedule_widget');
+ $template->fullcalendar = \Studip\Calendar\Helper::getScheduleFullcalendar()->render();
return $template;
}
}
diff --git a/lib/navigation/CalendarNavigation.php b/lib/navigation/CalendarNavigation.php
index 6b59d02..8df16b3 100644
--- a/lib/navigation/CalendarNavigation.php
+++ b/lib/navigation/CalendarNavigation.php
@@ -24,7 +24,7 @@ class CalendarNavigation extends Navigation
$main_url = URLHelper::getURL('dispatch.php/calendar/calendar', ['defaultDate' => date('Y-m-d')]);
if (!$GLOBALS['perm']->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) {
$title = _('Stundenplan');
- $main_url = URLHelper::getURL('dispatch.php/calendar/schedule');
+ $main_url = URLHelper::getURL('dispatch.php/calendar/schedule/index');
}
parent::__construct($title, $main_url);
@@ -37,12 +37,10 @@ class CalendarNavigation extends Navigation
*/
public function initSubNavigation()
{
- global $perm, $atime;
-
parent::initSubNavigation();
- if (!$perm->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) {
- $navigation = new Navigation(_('Stundenplan'), 'dispatch.php/calendar/schedule');
+ if (!$GLOBALS['perm']->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) {
+ $navigation = new Navigation(_('Stundenplan'), 'dispatch.php/calendar/schedule/index');
$this->addSubNavigation('schedule', $navigation);
}
diff --git a/resources/assets/stylesheets/scss/calendar.scss b/resources/assets/stylesheets/scss/calendar.scss
index 4ad94b8..0effce1 100644
--- a/resources/assets/stylesheets/scss/calendar.scss
+++ b/resources/assets/stylesheets/scss/calendar.scss
@@ -125,6 +125,22 @@
border-bottom: 1px solid $group-color-8;
}
}
+
+ &.marked-course {
+ border-color: var(--black);
+ background-color: var(--white);
+
+ .fc-time {
+ border-bottom: 1px solid var(--black);
+ }
+ }
+
+ &.marked-course,
+ &.hidden-course {
+ .fc-title > img {
+ filter: #{"invert()"};
+ }
+ }
}
}
diff --git a/resources/assets/stylesheets/scss/my_courses.scss b/resources/assets/stylesheets/scss/my_courses.scss
index 62c3be8..d47fb58 100644
--- a/resources/assets/stylesheets/scss/my_courses.scss
+++ b/resources/assets/stylesheets/scss/my_courses.scss
@@ -9,7 +9,16 @@
background: var(--white);
}
-form.default .mycourses-group-selector {
+form.default table.mycourses-group-selector {
+ table-layout: fixed;
+ width: unset;
+
+ td {
+ width: 2em;
+ }
+}
+
+form.default td.mycourses-group-selector {
position: relative;
background-clip: padding-box;
diff --git a/templates/start/schedule_widget.php b/templates/start/schedule_widget.php
new file mode 100644
index 0000000..23602db
--- /dev/null
+++ b/templates/start/schedule_widget.php
@@ -0,0 +1 @@
+<?= $fullcalendar ?>
diff --git a/tests/jsonapi/ScheduleEntriesShowTest.php b/tests/jsonapi/ScheduleEntriesShowTest.php
index 99dc895..64dcbc8 100644
--- a/tests/jsonapi/ScheduleEntriesShowTest.php
+++ b/tests/jsonapi/ScheduleEntriesShowTest.php
@@ -24,17 +24,14 @@ class ScheduleEntriesShowTest extends \Codeception\Test\Unit
{
$credentials = $this->tester->getCredentialsForTestAutor();
- \CalendarScheduleModel::storeEntry(
- [
- 'start' => 9,
- 'end' => 10,
- 'day' => 1,
- 'title' => 'test title',
- 'content' => 'test content',
- 'user_id' => $credentials['id'],
- 'color' => DEFAULT_COLOR_NEW
- ]
+ $stmt = DBManager::get()->prepare(
+ "INSERT INTO schedule_entries
+ (start_time, end_time, dow, label, content, user_id, mkdate, chdate)
+ VALUES
+ (9, 10, 1, 'test title', 'test content', :user_id, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())"
);
+ $stmt->execute(['user_id' => $credentials['id']]);
+
$scheduleEntryId = \DBManager::get()->lastInsertId();
$app = $this->tester->createApp($credentials, 'get', '/schedule-entries/{id}', ScheduleEntriesShow::class);
diff --git a/tests/jsonapi/UserScheduleShowTest.php b/tests/jsonapi/UserScheduleShowTest.php
index 9f5abd2..ab002ae 100644
--- a/tests/jsonapi/UserScheduleShowTest.php
+++ b/tests/jsonapi/UserScheduleShowTest.php
@@ -25,8 +25,8 @@ class UserScheduleShowTest extends \Codeception\Test\Unit
$credentials = $this->tester->getCredentialsForTestAutor();
$stmt = \DBManager::get()->prepare(
- "INSERT INTO schedule (start, end, day, title, content, color, user_id)
- VALUES (?, ?, ?, ?, ?, ?, ?)"
+ "INSERT INTO schedule_entries (start_time, end_time, dow, label, content, user_id, mkdate, chdate)
+ VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())"
);
$stmt->execute([
1000,
@@ -34,8 +34,7 @@ class UserScheduleShowTest extends \Codeception\Test\Unit
1,
'a title',
'some content',
- 1,
- $credentials['id'],
+ $credentials['id']
]);
$scheduleId = \DBManager::get()->lastInsertId();
diff --git a/tests/unit/lib/CalendarcolumnClassTest.php b/tests/unit/lib/CalendarcolumnClassTest.php
deleted file mode 100644
index d2ac9e0..0000000
--- a/tests/unit/lib/CalendarcolumnClassTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-/*
- * Copyright (C) 2011 - Rasmus Fuhse <fuhse@data-quest.de>
- *
- * 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.
- */
-
-require_once 'lib/calendar/CalendarColumn.php';
-
-class CalendarColumnCase extends \Codeception\Test\Unit {
-
-
- function setUp(): void {
- }
-
-
- function tearDown(): void {
- }
-
-
- function test_class_should_exist() {
- $this->assertTrue(class_exists('CalendarColumn'));
- }
-
- function test_create() {
- $this->assertInstanceOf("CalendarColumn", CalendarColumn::create());
- }
-
- function test_get_id() {
- $id = "test_id";
- $column = new CalendarColumn($id);
- $this->assertEquals($id, $column->getId());
- }
-
- function test_set_id() {
- $id = "test_id";
- $column = new CalendarColumn("falsche id");
- $column->setId($id);
- $this->assertEquals($id, $column->getId());
- }
-
- function test_set_title() {
- $title = "test_title";
- $column = new CalendarColumn();
- $column->setTitle($title);
- $this->assertEquals($title, $column->getTitle());
- }
-
- function test_set_url() {
- $url = URLHelper::getURL("dispatch.php/profile", ["username" => get_username()]);
- $column = CalendarColumn::create()->setURL($url);
- $this->assertEquals($url, $column->getURL());
- }
-
- function test_add_entry() {
- $entry = ['start' => "0800", 'end' => "1000", 'title' => "test_title"];
- $column = CalendarColumn::create()->addEntry($entry);
- $entry = ['start' => "1200", 'end' => "1230", 'title' => "test_title_number_2"];
- $column->addEntry($entry);
- $entries = $column->getEntries();
- $this->assertIsArray($entries);
- $this->assertEquals(2, count($entries));
- $this->assertNotEquals($entries[0], $entry);
- $this->assertEquals($entry, $entries[1]);
- $this->assertIsArray($entries[1]);
- }
-
- function test_wrong_entry() {
- $this->expectException(InvalidArgumentException::class);
- $entry1 = ['start' => "0800", 'end' => "1000"];
- $entry2 = ['start' => "1000", 'title' => "test_title"];
- $entry3 = ['end' => "1500", 'title' => "test_title"];
- $column = CalendarColumn::create()->addEntry($entry1);
- $column = CalendarColumn::create()->addEntry($entry2);
- $column = CalendarColumn::create()->addEntry($entry3);
- }
-
- function test_add_entries() {
- $entries = [
- ['start' => "0800", 'end' => "1000", 'title' => "test_title"],
- ['start' => "1200", 'end' => "1400", 'title' => "test_title"]
- ];
- $column = CalendarColumn::create()->addEntries($entries);
- $this->assertIsArray($column->getEntries());
- }
-
- function test_erase_entries() {
- $entry = ['start' => "0800", 'end' => "1000", 'title' => "test_title"];
- $column = CalendarColumn::create()->addEntry($entry);
- $column->eraseEntries();
- $entries = $column->getEntries();
- $this->assertIsArray($entries);
- $this->assertEquals(0, count($entries));
- }
-
-
- //Die anderen Methoden muss Till testen.
-
-}
diff --git a/tests/unit/lib/CalendarviewClassTest.php b/tests/unit/lib/CalendarviewClassTest.php
deleted file mode 100644
index d810575..0000000
--- a/tests/unit/lib/CalendarviewClassTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-/*
- * Copyright (C) 2011 - Rasmus Fuhse <fuhse@data-quest.de>
- *
- * 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.
- */
-
-require_once 'lib/calendar/CalendarView.php';
-
-class CalendarViewCase extends \Codeception\Test\Unit {
-
-
- function setUp(): void {
- }
-
-
- function tearDown(): void {
- }
-
-
- function test_class_should_exist() {
- $this->assertTrue(class_exists('CalendarView'));
- }
-
- function test_constructor() {
- $this->assertInstanceOf("CalendarView", new CalendarView());
- }
-
- function test_setHeight() {
- $height = 75;
- $cview = new CalendarView();
- $cview->setHeight($height);
- $this->assertEquals($height, $cview->getHeight());
- }
-
- function test_setRange() {
- $start_hour = 6;
- $end_hour = 12;
- $cview = new CalendarView();
- $cview->setRange($start_hour, $end_hour);
- $result = $cview->getRange();
- $this->assertEquals($start_hour, $result[0]);
- $this->assertEquals($end_hour, $result[1]);
- }
-
- function test_addColumn() {
- $view = new CalendarView();
- $title1 = "Mittwoch";
- $id1 = 3;
- $view->addColumn($title1, "", $id1);
- $title2 = "Donnerstag";
- $id2 = 4;
- $view->addColumn($title2, "", $id2);
- $columns = $view->getColumns();
- $this->assertIsArray($columns);
- $this->assertInstanceOf("CalendarColumn", $columns[0]);
- $this->assertEquals($title1, $columns[0]->getTitle());
- $this->assertEquals($id1, $columns[0]->getId());
- $this->assertInstanceOf("CalendarColumn", $columns[1]);
- $this->assertEquals($title2, $columns[1]->getTitle());
- $this->assertEquals($id2, $columns[1]->getId());
- }
-
- public function test_negative_addEntry() {
- $this->expectException(InvalidArgumentException::class);
- $view = new CalendarView();
- $entry = [
- 'title' => "Test Eintrag",
- 'start' => "0800",
- 'end' => "0900"
- ];
- $view->addEntry($entry);
- }
-
- public function test_addEntry_getEntries() {
- $view = new CalendarView();
- $id = 3;
- $view->addColumn("Montag", "", $id);
- $entry = [
- 'title' => "Test Eintrag",
- 'start' => "0800",
- 'end' => "0900"
- ];
- $view->addEntry($entry);
- $entries = $view->getEntries();
- $this->assertIsArray($entries);
- $this->assertNotNull($entries['day_'.$id]);
- }
-
- public function test_insertFunction() {
- $view = new CalendarView();
- $js_function_object = 'function () { alert("Watch out, Gringo!"); }';
- $view->setInsertFunction($js_function_object);
- $this->assertEquals($js_function_object, $view->getInsertFunction());
- }
-
- //Die anderen Methoden muss Till testen.
-
-}