diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php
index dfc6706071636873b9c7c62a979a75ac379b2195..468c35d9155d9702640a94e8223ddd2eaea69aa9 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 668ed7739562146582c4d1f75c9c9ac37afc8579..33c9f6dd00beb118d8e106e0b96f3c1396e0f11e 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 10f3f57ccc2b50c2bdec26d355ad0b7c01788f48..7f9c078255f96fb550b4becd87784679e6521869 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 cf3d282ca6498decfea1f89a5bd58a1aea415a21..85d4cd01552fa48633042882014eaac03ae24568 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 e1f12667286a84a0559def5671aef2c03eec4337..0000000000000000000000000000000000000000
--- 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 0b64f9db25e1b2aa190548709b6274deb296d331..0000000000000000000000000000000000000000
--- 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 f6002184daf8d37443e13f397b55132ddcdb9fa6..0000000000000000000000000000000000000000
--- 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 228751f47f1b18bcbfd2e49da8db6f908abaecb7..0000000000000000000000000000000000000000
--- 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 ad5bbcd6503b3d3297543ec036a24b50e82c0aae..0000000000000000000000000000000000000000
--- 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 a8a783e41b72f768de758cb8635c5d8598ee839d..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..b8135926a3ca896b4213240f07593ef12be7a6db
--- /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 54d44e9cef40c4f8f6c315305598ae8b07721074..676f07308c17ef4d1f7e8cb0bbe731035201aaff 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 fe022a2317765a8f19cd109eb701b755c29ce609..390a0161ec105c4da38b2c5e617196c5770d6bc1 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 0e2674e6e00f27bd1310d863621b8157689405d2..0000000000000000000000000000000000000000
--- 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 aaf7334c04bf9fe840bcd99f4f9bd6638c9e7db1..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..8d99a64060890dfa8c0d6e7639732c43e8dc6609
--- /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 4476aeb20df2c48cda15b0c61c33d91529237bc6..fff9d63e9452bf9d0cd608e5964dd9a9c642f9f3 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 0000000000000000000000000000000000000000..d27bf81f5e4c564babf17b05390ac1026d8342c4
--- /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 78a38090e6d0d7bb1cd2b13e468681268c00dcb8..0000000000000000000000000000000000000000
--- 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 9d9ebc29556baedc579e292a6037d3c9b0431f11..0000000000000000000000000000000000000000
--- 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 1d14ca2188f6defe8fa4294987e0e1d4ea1cb3da..0000000000000000000000000000000000000000
--- 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 df980ff3953e529e720c799566d975ed670d08f5..0000000000000000000000000000000000000000
--- 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 37001ff1b56de81d23541e22ee3d30c521fb9dc6..0000000000000000000000000000000000000000
--- 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 37c1c422642f68c7a1a82107c1ebb23c2fcb68eb..b92a1e847679c49379328ff0ccd96fab7dcdac93 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 6e5bdf42bd9aa774f05c2f8dab65daa1182aa3cb..d1fb02406d0518987e5c5513f20c9fb989594685 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 85cf9113e08fa9947ec72832678e3577ca231bf9..033916cc408f7a585dce4379c1ed490a9feaac28 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 ff5040dc57fd1c0993965a6e5163693c8ddb310e..a5c1213e689e3ba30d5f4e8c5655e14b0980118e 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 3318f358b64ce2af734ad17a315f02a6ada2f93c..0dfbc7d2cfe359c513263c138c22cafea8e1bfad 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 ed349a2d31591d58f1e2394ec0b34cd506bb7af5..53b567555788a4ff474387a5fb50f1cc26b0e32a 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 bc884bbfc06b5239e8b8c448fbd82c06f211d0e7..0000000000000000000000000000000000000000
--- 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 cd3163afe2cabfa7932df9c23e0f1e4bb2ddf2b2..dd860070982fd6cf0c243dcfb5e136837156efec 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 ea6676c14b6902e14e86542afacdcaef0e2d5862..b252063120b20b88ada5d2c94f2ed553ad61e7cb 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 3f139045effe3b1708da83a0996eca9260251585..943bf2378550c00d4ce43fb51b668e4c9a8b4c60 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 2d3afea2e92479e530507548b125d10a6de2ed52..eb0f90a8e10c072e43f0d526039fe5d0c5553632 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 ae851217178890fae9e976c1e858f39422dbbe32..13b2520883c4b0b4f5f5ca954ab3b10754a0fbe2 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 370dcd14449dc1b7bca932ea410efcdf63290f22..b312bda3094601c00d168acf9c1e159d705f1c63 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 eb23aeb79d53964681157a1f9d63c9753791d774..5e979a816f48554afb467f74e3ba0ae7b1702f9f 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 0000000000000000000000000000000000000000..9d05a7231b2e57e51a688d54e991efaae72c3cd8
--- /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 0000000000000000000000000000000000000000..f1e23fddaff6be45ca025417b242cd74e346b72b
--- /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 c4ab769fe5d2c7a502c3fb1baded55b5c99b1b80..42a08146d9cba441ab631f29d6a9a8eec3b0325e 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 6b59d02d19695125a343179c6a61a2e191d2799c..8df16b3c4b260b05a37b5a33effa55402f90e80a 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 4ad94b885ce967c5d1fb052ff7343695503413df..0effce153d3e9acbc0d73fdf6fb9141d9126e088 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 62c3be813679fcf9c09d2036db86ee47bc3a3a9e..d47fb58de7b6435f4c8229eadd6325f4328ed4b7 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 0000000000000000000000000000000000000000..23602dbb62490dc895f4651d4220c631f8af4c01
--- /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 99dc8950a9e6b92947b6eb6ba71c585cf55e0047..64dcbc85214689856b6bba9738ef5aeaa71de367 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 9f5abd222337440fbd173db076d45a7a332aaa17..ab002ae4f26c2b611ad8ab74efd97ba03b645329 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 d2ac9e0f97e7c7cffeaa6db80acb771a6a73e26b..0000000000000000000000000000000000000000
--- 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 d810575fefb9403fcdbc72ddbac2215b32b5d450..0000000000000000000000000000000000000000
--- 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.
-
-}