aboutsummaryrefslogtreecommitdiff
path: root/app/controllers/calendar/calendar.php
diff options
context:
space:
mode:
authorMoritz Strohm <strohm@data-quest.de>2024-01-29 15:16:24 +0000
committerMoritz Strohm <strohm@data-quest.de>2024-01-29 15:16:24 +0000
commit7c1df847d94d3956bc763b94b73cebfe108dc9a1 (patch)
treee18e003bff65c5bf0748c644d6cd3d235cb1feca /app/controllers/calendar/calendar.php
parentda0110d5e85279123e8dde392cb4c926397238bf (diff)
StEP 01354, closes #1354
Closes #1354 Merge request studip/studip!2116
Diffstat (limited to 'app/controllers/calendar/calendar.php')
-rw-r--r--app/controllers/calendar/calendar.php1350
1 files changed, 805 insertions, 545 deletions
diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php
index 2e17ff2..eecf900 100644
--- a/app/controllers/calendar/calendar.php
+++ b/app/controllers/calendar/calendar.php
@@ -1,636 +1,896 @@
<?php
-/*
- * The controller for the personal 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 Peter Thienel <thienel@data-quest.de>
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- * @since
- */
class Calendar_CalendarController extends AuthenticatedController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
- PageLayout::setHelpKeyword('Basis.Terminkalender');
- $this->settings = $GLOBALS['user']->cfg->CALENDAR_SETTINGS;
- if ($this->settings['start'] < 0 || $this->settings['start'] > 23) {
- $this->settings['start'] = 0;
- }
- if ($this->settings['end'] < 0 || $this->settings['end'] > 23) {
- $this->settings['end'] = 23;
- }
- if (!in_array($this->settings['view'], ['day','week','month','year'])) {
- $this->settings['view'] = 'week';
- }
- if (!is_array($this->settings)) {
- $this->settings = Calendar::getDefaultUserSettings();
- }
- URLHelper::bindLinkParam('atime', $this->atime);
- $this->atime = Request::int('atime', time());
- $this->category = Request::int('category');
- $this->last_view = Request::option('last_view',
- $this->settings['view']);
- $this->action = $action;
- $this->restrictions = [
- 'STUDIP_CATEGORY' => $this->category ?: null,
- // hide events with status 3 (CalendarEvent::PARTSTAT_DECLINED)
- 'STUDIP_GROUP_STATUS' => !empty($this->settings['show_declined']) ? null : [0,1,2,5]
- ];
- if ($this->category) {
- URLHelper::bindLinkParam('category', $this->category);
- }
-
- $this->range_id = '';
- if (Config::get()->COURSE_CALENDAR_ENABLE
- && !Request::get('self')
- && Course::findCurrent()) {
- $current_seminar = new Seminar(Course::findCurrent());
- if ($current_seminar->getSlotModule('calendar') instanceOf CoreCalendar) {
- $this->range_id = $current_seminar->id;
- Navigation::activateItem('/course/calendar');
- }
- }
- if (!$this->range_id) {
- $this->range_id = Request::option('range_id', $GLOBALS['user']->id);
- Navigation::activateItem('/calendar/calendar');
- URLHelper::bindLinkParam('range_id', $this->range_id);
+ if (!Context::isCourse() && Navigation::hasItem('/calendar')) {
+ Navigation::activateItem('/calendar');
}
-
- URLHelper::bindLinkParam('last_view', $this->last_view);
}
- protected function createSidebar($active = null, $calendar = null)
- {
- $active = $active ?: $this->last_view;
- $sidebar = Sidebar::Get();
-
- $views = new ViewsWidget();
- $views->addLink(_('Tag'), $this->url_for($this->base . 'day'))
- ->setActive($active == 'day');
- $views->addLink(_('Woche'), $this->url_for($this->base . 'week'))
- ->setActive($active == 'week');
- $views->addLink(_('Monat'), $this->url_for($this->base . 'month'))
- ->setActive($active == 'month');
- $views->addLink(_('Jahr'), $this->url_for($this->base . 'year'))
- ->setActive($active == 'year');
- $sidebar->addWidget($views);
- }
- protected function createSidebarFilter()
+ protected function buildSidebar($schedule = false)
{
- $tmpl_factory = $this->get_template_factory();
-
- $filters = new SidebarWidget();
- $filters->setTitle('Auswahl');
-
- $tmpl = $tmpl_factory->open('calendar/single/_jump_to');
- $tmpl->atime = $this->atime;
- $tmpl->action = $this->action;
- $tmpl->action_url = $this->url_for('calendar/single/jump_to');
- $filters->addElement(new WidgetElement($tmpl->render()));
-
- $tmpl = $tmpl_factory->open('calendar/single/_select_category');
- $tmpl->action_url = $this->url_for();
- $tmpl->category = $this->category;
- $filters->addElement(new WidgetElement($tmpl->render()));
- Sidebar::get()->addWidget($filters);
-
- if (Config::get()->CALENDAR_GROUP_ENABLE
- || Config::get()->COURSE_CALENDAR_ENABLE) {
- $tmpl = $tmpl_factory->open('calendar/single/_select_calendar');
- $tmpl->range_id = $this->range_id;
- $tmpl->action_url = $this->url_for('calendar/group/switch');
- $tmpl->view = $this->action;
- $filters->addElement(new WidgetElement($tmpl->render()));
-
- $settings = new OptionsWidget();
- $settings->addCheckbox(
- _('Abgelehnte Termine anzeigen'),
- $this->settings['show_declined'] ?? false,
- $this->url_for($this->base . 'show_declined', ['show_declined' => 1]),
- $this->url_for($this->base . 'show_declined', ['show_declined' => 0])
+ $sidebar = Sidebar::get();
+
+ $actions = new ActionsWidget();
+ if ($schedule) {
+ $actions->addLink(
+ _('Neuer Eintrag'),
+ $this->url_for('calendar/calendar/add_schedule_entry'),
+ Icon::create('add'),
+ ['data-dialog' => 'size=default']
+ );
+ } else {
+ $actions->addLink(
+ _('Termin anlegen'),
+ $this->url_for('calendar/date/add'),
+ Icon::create('add'),
+ ['data-dialog' => 'size=auto']
);
- Sidebar::get()->addWidget($settings);
+ }
+
+ if (!$GLOBALS['perm']->have_perm('admin')) {
+ $actions->addLink(
+ _('Veranstaltung auswählen'),
+ $this->url_for('calendar/calendar/add_courses'),
+ Icon::create('add'),
+ ['data-dialog' => 'size=medium']
+ );
+ }
+ if (!$schedule) {
+ $actions->addLink(
+ _('Termine exportieren'),
+ $this->url_for('calendar/calendar/export'),
+ Icon::create('export'),
+ ['data-dialog' => 'size=auto']
+ );
+ $actions->addLink(
+ _('Termine importieren'),
+ $this->url_for('calendar/calendar/import'),
+ Icon::create('import'),
+ ['data-dialog' => 'size=auto']
+ );
+ $actions->addLink(
+ _('Kalender veröffentlichen'),
+ $this->url_for('calendar/calendar/publish'),
+ Icon::create('export'),
+ ['data-dialog' => 'size=auto']
+ );
+ }
+ if (!$schedule && Config::get()->CALENDAR_GROUP_ENABLE) {
+ $actions->addLink(
+ _('Kalender teilen'),
+ $this->url_for('calendar/calendar/share'),
+ Icon::create('share'),
+ ['data-dialog' => 'size=default']
+ );
+ }
+ $actions->addLink(
+ _('Drucken'),
+ 'javascript:void(window.print());',
+ Icon::create('print')
+ );
+ $actions->addLink(
+ _('Einstellungen'),
+ $this->url_for('settings/calendar'),
+ Icon::create('settings'),
+ ['data-dialog' => 'size=auto;reload-on-close']
+ );
+ $sidebar->addWidget($actions);
+
+ if (!$schedule) {
+ $date = new DateSelectWidget();
+ $date->setDate(\Studip\Calendar\Helper::getDefaultCalendarDate());
+ $date->setCalendarControl(true);
+ $sidebar->addWidget($date);
}
}
- public function index_action()
+ protected function getUserCalendarSlotSettings() : array
{
- // switch to the view the user has selected in his personal settings
- $default_view = $this->settings['view'] ?: 'week';
-
- // Remove cid
- if (Request::option('self')) {
- Context::close();
-
- $this->redirect(URLHelper::getURL('dispatch.php/' . $this->base
- . $default_view . '/' . $GLOBALS['user']->id, [], true));
- } else {
- $this->redirect(URLHelper::getURL('dispatch.php/' . $this->base
- . $default_view));
- }
+ return [
+ 'day' => \Studip\Calendar\Helper::getCalendarSlotDuration('day'),
+ 'week' => \Studip\Calendar\Helper::getCalendarSlotDuration('week'),
+ 'day_group' => \Studip\Calendar\Helper::getCalendarSlotDuration('day_group'),
+ 'week_group' => \Studip\Calendar\Helper::getCalendarSlotDuration('week_group')
+ ];
}
- public function edit_action($range_id = null, $event_id = null)
+ public function index_action()
{
- $this->range_id = $range_id ?: $this->range_id;
- $this->calendar = new SingleCalendar($this->range_id);
- $this->event = $this->calendar->getEvent($event_id);
-
- if ($this->event->isNew()) {
- // $this->event = $this->calendar->getNewEvent();
- if (Request::get('isdayevent')) {
- $this->event->setStart(mktime(0, 0, 0, date('n', $this->atime),
- date('j', $this->atime), date('Y', $this->atime)));
- $this->event->setEnd(mktime(23, 59, 59, date('n', $this->atime),
- date('j', $this->atime), date('Y', $this->atime)));
+ PageLayout::setTitle(_('Kalender'));
+
+ if (Request::isPost()) {
+ //In case the checkbox of the options widget is clicked, the resulting
+ //POST request must be catched here and result in a redirect.
+ CSRFProtection::verifyUnsafeRequest();
+ if (Request::bool('show_declined')) {
+ $this->redirect('calendar/calendar', ['show_declined' => '1']);
} else {
- $this->event->setStart($this->atime);
- $this->event->setEnd($this->atime + 3600);
+ $this->redirect('calendar/calendar');
}
- $this->event->setAuthorId($GLOBALS['user']->id);
- $this->event->setEditorId($GLOBALS['user']->id);
- $this->event->setAccessibility('PRIVATE');
- if (!Request::isXhr()) {
- PageLayout::setTitle($this->getTitle($this->calendar, _('Neuer Termin')));
+ return;
+ }
+
+ if (!Context::isCourse() && Navigation::hasItem('/calendar/calendar')) {
+ Navigation::activateItem('/calendar/calendar');
+ }
+
+ $view = Request::get('view', 'single');
+ $group_view = false;
+ $timeline_view = false;
+ if (Config::get()->CALENDAR_GROUP_ENABLE) {
+ $group_view = in_array($view, ['group', 'timeline']);
+ $timeline_view = $view === 'timeline';
+ }
+
+ $calendar_owner = null;
+ $selected_group = null;
+ $user_id = Request::option('user_id', User::findCurrent()->id);
+ $group_id = Request::option('group_id');
+
+ if (Config::get()->CALENDAR_GROUP_ENABLE) {
+ if ($group_id) {
+ $selected_group = ContactGroup::find($group_id);
+ if ($selected_group->owner_id !== User::findCurrent()->id) {
+ //Thou shalt not see the groups of others!
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
+ $view = $view === 'timeline' ? 'timeline' : 'group';
+ } elseif ($user_id) {
+ $calendar_owner = User::getCalendarOwner($user_id);
+ $view = 'single';
}
} else {
- // open read only events and course events not as form
- // show information in dialog instead
- if (!$this->event->havePermission(Event::PERMISSION_WRITABLE)
- || $this->event instanceof CourseEvent) {
- if (!$this->event instanceof CourseEvent && $this->event->attendees->count() > 1) {
- if ($this->event->group_status) {
- $this->redirect($this->url_for('calendar/single/edit_status/' . implode('/',
- [$this->range_id, $this->event->event_id])));
- } else {
- $this->redirect($this->url_for('calendar/single/event/' . implode('/',
- [$this->range_id, $this->event->event_id])));
+ //Show the calendar of the current user.
+ $view = 'single';
+ $calendar_owner = User::findCurrent();
+ }
+
+ //Check for permissions:
+ $read_permissions = false;
+ $write_permissions = false;
+ if ($calendar_owner) {
+ $read_permissions = $calendar_owner->isCalendarReadable();
+ $write_permissions = $calendar_owner->isCalendarWritable();
+ } elseif ($selected_group) {
+ //Count on how many group member calendars the current user has read or write permissions:
+ foreach ($selected_group->items as $item) {
+ if ($item->user) {
+ if ($item->user->isCalendarReadable()) {
+ $read_permissions = true;
+ }
+ if ($item->user->isCalendarWritable()) {
+ $write_permissions = true;
}
- } else {
- $this->redirect($this->url_for('calendar/single/event/' . implode('/',
- [$this->range_id, $this->event->event_id])));
}
- return null;
- }
- if (!Request::isXhr()) {
- PageLayout::setTitle($this->getTitle($this->calendar, _('Termin bearbeiten')));
+ if ($read_permissions && $write_permissions) {
+ //We only need to determine one read and one write permission to set the relevant fullcalendar
+ //properties. The action to add/edit a date determines in which calendars the current user
+ //may write into.
+ break;
+ }
}
}
+ if (!$read_permissions) {
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
- if (Config::get()->CALENDAR_GROUP_ENABLE
- && $this->calendar->getRange() == Calendar::RANGE_USER) {
-
- if (Config::get()->CALENDAR_GRANT_ALL_INSERT) {
- $search_obj = SQLSearch::get("SELECT DISTINCT auth_user_md5.user_id, "
- . "{$GLOBALS['_fullname_sql']['full_rev_username']} as fullname, "
- . "auth_user_md5.perms, auth_user_md5.username "
- . "FROM auth_user_md5 "
- . "LEFT JOIN user_info ON (auth_user_md5.user_id = user_info.user_id) "
- . 'WHERE auth_user_md5.user_id <> ' . DBManager::get()->quote($GLOBALS['user']->id)
- . ' AND (username LIKE :input OR Vorname LIKE :input '
- . "OR CONCAT(Vorname,' ',Nachname) LIKE :input "
- . "OR CONCAT(Nachname,' ',Vorname) LIKE :input "
- . "OR Nachname LIKE :input OR {$GLOBALS['_fullname_sql']['full_rev']} LIKE :input "
- . ") ORDER BY fullname ASC",
- _('Person suchen'), 'user_id');
- } else {
- $search_obj = SQLSearch::get("SELECT DISTINCT auth_user_md5.user_id, "
- . "{$GLOBALS['_fullname_sql']['full_rev_username']} as fullname, "
- . "auth_user_md5.perms, auth_user_md5.username "
- . "FROM calendar_user "
- . "LEFT JOIN auth_user_md5 ON calendar_user.owner_id = auth_user_md5.user_id "
- . "LEFT JOIN user_info ON (auth_user_md5.user_id = user_info.user_id) "
- . 'WHERE calendar_user.user_id = '
- . DBManager::get()->quote($GLOBALS['user']->id)
- . ' AND calendar_user.permission > ' . Event::PERMISSION_READABLE
- . ' AND auth_user_md5.user_id <> ' . DBManager::get()->quote($GLOBALS['user']->id)
- . ' AND (username LIKE :input OR Vorname LIKE :input '
- . "OR CONCAT(Vorname,' ',Nachname) LIKE :input "
- . "OR CONCAT(Nachname,' ',Vorname) LIKE :input "
- . "OR Nachname LIKE :input OR {$GLOBALS['_fullname_sql']['full_rev']} LIKE :input "
- . ") ORDER BY fullname ASC",
- _('Person suchen'), 'user_id');
+ $this->buildSidebar(false);
+
+ $sidebar = Sidebar::get();
+
+ if (Config::get()->CALENDAR_GROUP_ENABLE) {
+ if ($calendar_owner && $calendar_owner->id === User::findCurrent()->id) {
+ //The user is viewing their own calendar.
+ $options = new OptionsWidget();
+ $options->addCheckbox(
+ _('Abgelehnte Termine anzeigen'),
+ Request::bool('show_declined'),
+ $this->url_for('calendar/calendar', ['show_declined' => '1']),
+ $this->url_for('calendar/calendar')
+ );
+ $sidebar->addWidget($options);
}
- // SEMBBS
- // Eintrag von Terminen bereits ab PERMISSION_READABLE
- /*
- $search_obj = new SQLSearch('SELECT DISTINCT auth_user_md5.user_id, '
- . $GLOBALS['_fullname_sql']['full_rev'] . ' as fullname, username, perms '
- . 'FROM calendar_user '
- . 'LEFT JOIN auth_user_md5 ON calendar_user.owner_id = auth_user_md5.user_id '
- . 'LEFT JOIN user_info ON (auth_user_md5.user_id = user_info.user_id) '
- . 'WHERE calendar_user.user_id = '
- . DBManager::get()->quote($GLOBALS['user']->id)
- . ' AND calendar_user.permission >= ' . Event::PERMISSION_READABLE
- . ' AND (username LIKE :input OR Vorname LIKE :input '
- . "OR CONCAT(Vorname,' ',Nachname) LIKE :input "
- . "OR CONCAT(Nachname,' ',Vorname) LIKE :input "
- . 'OR Nachname LIKE :input OR '
- . $GLOBALS['_fullname_sql']['full_rev'] . ' LIKE :input '
- . ') ORDER BY fullname ASC',
- _('Nutzer suchen'), 'user_id');
- // SEMBBS
- *
- */
-
-
- $this->quick_search = QuickSearch::get('user_id', $search_obj)
- ->fireJSFunctionOnSelect('STUDIP.Messages.add_adressee')
- ->withButton();
-
- // $default_selected_user = array($this->calendar->getRangeId());
- $this->mps = MultiPersonSearch::get('add_adressees')
- ->setLinkText(_('Mehrere Teilnehmende hinzufügen'))
- // ->setDefaultSelectedUser($default_selected_user)
- ->setTitle(_('Mehrere Teilnehmende hinzufügen'))
- ->setExecuteURL($this->url_for($this->base . 'edit'))
- ->setJSFunctionOnSubmit('STUDIP.Messages.add_adressees')
- ->setSearchObject($search_obj);
- $owners = SimpleORMapCollection::createFromArray(
- CalendarUser::findByUser_id($this->calendar->getRangeId()))
- ->pluck('owner_id');
- foreach (Calendar::getGroups($GLOBALS['user']->id) as $group) {
- $this->mps->addQuickfilter(
- $group->name,
- $group->members->filter(
- function ($member) use ($owners) {
- if (in_array($member->user_id, $owners)) {
- return $member;
- }
- })->pluck('user_id')
+ //Check if the user has groups. If so, display a select widget to select a group.
+ $groups = ContactGroup::findBySQL(
+ 'owner_id = :owner_id ORDER BY name ASC',
+ [
+ 'owner_id' => User::findCurrent()->id
+ ]
+ );
+ if ($groups) {
+ $available_groups = [];
+
+ //Check if the user has at least read permissions for the calendar of one user of one group:
+ foreach ($groups as $group) {
+ foreach ($group->items as $item) {
+ if ($item->user && $item->user->isCalendarReadable()) {
+ $available_groups[] = $group;
+ break 1;
+ }
+ }
+ }
+ if ($available_groups) {
+ $group_select = new SelectWidget(
+ _('Gruppe'),
+ $this->url_for('calendar/calendar/index', ['view' => 'group']),
+ 'group_id'
+ );
+ $options = [
+ '' => _('(bitte wählen)')
+ ];
+ foreach ($available_groups as $available_group) {
+ $options[$available_group->id] = $available_group->name;
+ }
+ $group_select->setOptions($options);
+ $group_select->setSelection($group_id);
+ $sidebar->addWidget($group_select);
+ }
+ }
+ //Get all calendars where the user has access to:
+ $other_users = User::findBySql(
+ "INNER JOIN `contact` c
+ ON `auth_user_md5`.`user_id` = c.`owner_id`
+ WHERE c.`user_id` = :current_user_id
+ AND c.`calendar_permissions` <> ''
+ ORDER BY `auth_user_md5`.`Vorname` ASC, `auth_user_md5`.`Nachname` ASC",
+ ['current_user_id' => User::findCurrent()->id]
+ );
+ if ($other_users) {
+ $calendar_select = new SelectWidget(
+ _('Kalender auswählen'),
+ $this->url_for('calendar/calendar'),
+ 'user_id'
);
+ $select_options = [
+ '' => _('(bitte wählen)'),
+ User::findCurrent()->id => _('Eigener Kalender')
+ ];
+ foreach ($other_users as $user) {
+ $select_options[$user->id] = $user->getFullName();
+ }
+ $calendar_select->setOptions($select_options, Request::get('user_id'));
+ $sidebar->addWidget($calendar_select);
}
}
- $stored = false;
- if (Request::submitted('store')) {
- $stored = $this->storeEventData($this->event, $this->calendar);
+ if (Config::get()->CALENDAR_GROUP_ENABLE && $selected_group) {
+ $views = new ViewsWidget();
+ $views->setTitle(_('Kalenderansicht'));
+ $views->addLink(
+ _('Gruppenkalender'),
+ $this->url_for('calendar/calendar', ['view' => 'group', 'group_id' => $group_id])
+ )->setActive($view === 'group');
+ $views->addLink(
+ _('Zeitleiste'),
+ $this->url_for('calendar/calendar', ['view' => 'timeline', 'group_id' => $group_id])
+ )->setActive($view === 'timeline');
+ $sidebar->addWidget($views);
}
- if ($stored !== false) {
- if ($stored === 0) {
- if (Request::isXhr()) {
- header('X-Dialog-Close: 1');
- exit;
- } else {
- PageLayout::postMessage(MessageBox::success(_('Der Termin wurde nicht geändert.')));
- $this->relocate('calendar/single/' . $this->last_view, ['atime' => $this->atime]);
+ $calendar_resources = [];
+ $calendar_group_title = '';
+ if ($group_view && $selected_group) {
+ //All users in the selected group that have granted read permissions to the user can be shown.
+ foreach ($selected_group->items as $item) {
+ if ($item->user && $item->user->isCalendarReadable()) {
+ $calendar_resources[] = [
+ 'id' => $item->user_id,
+ 'title' => $item->user ? $item->user->getFullName() : '',
+ 'parent_name' => ''
+ ];
}
- } else {
- PageLayout::postMessage(MessageBox::success(_('Der Termin wurde gespeichert.')));
- $this->relocate('calendar/single/' . $this->last_view, ['atime' => $this->atime]);
}
+ $calendar_group_title = $selected_group->name;
}
- $this->createSidebar('edit', $this->calendar);
- $this->createSidebarFilter();
+ $fullcalendar_studip_urls = [];
+ if ($write_permissions) {
+ if ($calendar_owner) {
+ $fullcalendar_studip_urls['add'] = $this->url_for('calendar/date/add', ['user_id' => $calendar_owner->id]);
+ } elseif ($selected_group) {
+ $fullcalendar_studip_urls['add'] = $this->url_for('calendar/date/add', ['group_id' => $group->id]);
+ }
+ }
+
+ $calendar_settings = User::findCurrent()->getConfiguration()->CALENDAR_SETTINGS ?? [];
+
+ //Map calendar settings to fullcalendar settings:
+
+ $default_view = 'timeGridWeek';
+ if ($timeline_view) {
+ $default_view = 'resourceTimelineWeek';
+ if ($calendar_settings['view'] === 'day') {
+ $default_view = 'resourceTimelineDay';
+ }
+ } elseif (!empty($calendar_settings['view'])) {
+ if ($calendar_settings['view'] === 'day') {
+ $default_view = 'timeGridDay';
+ } elseif ($calendar_settings['view'] === 'month') {
+ $default_view = 'dayGridMonth';
+ }
+ }
+
+ $slot_durations = $this->getUserCalendarSlotSettings();
+
+ //Create the fullcalendar object:
+ $default_date = \Studip\Calendar\Helper::getDefaultCalendarDate();
+
+ $data_url_params = [];
+ if (Request::bool('show_declined')) {
+ $data_url_params['show_declined'] = '1';
+ }
+ if ($timeline_view) {
+ $data_url_params['timeline_view'] = '1';
+ }
+
+ $this->fullcalendar = Studip\Fullcalendar::create(
+ _('Kalender'),
+ [
+ 'editable' => $write_permissions,
+ 'selectable' => $write_permissions,
+ 'studip_urls' => $fullcalendar_studip_urls,
+ 'dialog_size' => 'auto',
+ 'minTime' => sprintf('%02u:00', $calendar_settings['start'] ?? 8),
+ 'maxTime' => sprintf('%02u:00', $calendar_settings['end'] ?? 20),
+ 'defaultDate' => $default_date->format('Y-m-d'),
+ 'allDaySlot' => !$group_view,
+ 'allDayText' => '',
+ 'header' => [
+ 'left' => (
+ $timeline_view
+ ? 'resourceTimelineWeek,resourceTimelineDay'
+ : 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay'
+ ),
+ 'right' => 'prev,today,next'
+ ],
+ 'weekNumbers' => true,
+ 'views' => [
+ 'dayGridMonth' => [
+ 'eventTimeFormat' => ['hour' => 'numeric', 'minute' => '2-digit'],
+ 'displayEventEnd' => true
+ ],
+ 'timeGridWeek' => [
+ 'columnHeaderFormat' => ['weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
+ 'weekends' => $calendar_settings['type_week'] === 'LONG',
+ 'slotDuration' => $slot_durations['week']
+ ],
+ 'timeGridDay' => [
+ 'columnHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
+ 'slotDuration' => $slot_durations['day']
+ ],
+ 'resourceTimelineWeek' => [
+ 'columnHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
+ 'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
+ 'weekends' => $calendar_settings['type_week'] === 'LONG',
+ 'slotDuration' => $slot_durations['week_group']
+ ],
+ 'resourceTimelineDay' => [
+ 'columnHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
+ 'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
+ 'slotDuration' => $slot_durations['day_group']
+ ]
+ ],
+ 'defaultView' => $default_view,
+ 'timeGridEventMinHeight' => 20,
+ 'eventSources' => [
+ [
+ 'url' => $this->url_for(
+ (
+ $group_view
+ ? 'calendar/calendar/calendar_group_data/' . $selected_group->id
+ : 'calendar/calendar/calendar_data/' . $calendar_owner->id
+ ),
+ $data_url_params
+ ),
+ 'method' => 'GET',
+ 'extraParams' => []
+ ]
+ ],
+ 'resources' => $calendar_resources,
+ 'resourceLabelText' => $calendar_group_title
+ ]
+ );
}
- public function edit_status_action($range_id, $event_id)
+ public function course_action($course_id)
{
- global $user;
+ PageLayout::setTitle(_('Veranstaltungskalender'));
- $this->range_id = $range_id ?: $this->range_id;
- $this->calendar = new SingleCalendar($this->range_id);
- $this->event = $this->calendar->getEvent($event_id);
- $stored = false;
- $old_status = $this->event->group_status;
+ if (!$course_id || !Config::get()->CALENDAR_GROUP_ENABLE || !Config::get()->COURSE_CALENDAR_ENABLE) {
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
- if (Request::submitted('store')) {
+ $course = Course::find($course_id);
+ if (!$course) {
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
- if ($this->event->isNew()
- || !Config::get()->CALENDAR_GROUP_ENABLE
- || !$this->calendar->havePermission(Calendar::PERMISSION_OWN)
- || !$this->calendar->getRange() == Calendar::RANGE_USER
- || !$this->event->havePermission(Event::PERMISSION_READABLE)) {
- throw new AccessDeniedException();
+ if (!$course->isVisibleForUser() || !$course->isCalendarReadable()) {
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
+
+ if (Navigation::hasItem('/course/calendar')) {
+ Navigation::activateItem('/course/calendar');
+ }
+
+ $sidebar = Sidebar::get();
+
+ $actions = new ActionsWidget();
+ $actions->addLink(
+ _('Termin anlegen'),
+ $this->url_for('calendar/date/add/course_' . $course->id),
+ Icon::create('add'),
+ ['data-dialog' => 'size=default']
+ );
+ $actions->addLink(
+ _('Drucken'),
+ 'javascript:void(window.print());',
+ Icon::create('print')
+ );
+ $actions->addLink(
+ _('Einstellungen'),
+ $this->url_for('settings/calendar'),
+ Icon::create('settings'),
+ ['data-dialog' => 'reload-on-close']
+ );
+ $sidebar->addWidget($actions);
+
+ $date = new DateSelectWidget();
+ $date->setCalendarControl(true);
+ $sidebar->addWidget($date);
+
+ //Create the fullcalendar object:
+
+ $calendar_writable = $course->isCalendarWritable();
+ $calendar_settings = User::findCurrent()->getConfiguration()->CALENDAR_SETTINGS ?? [];
+ $slot_settings = $this->getUserCalendarSlotSettings();
+
+ $fullcalendar_studip_urls = [];
+ if ($calendar_writable) {
+ $fullcalendar_studip_urls['add'] = $this->url_for('calendar/date/add/course_' . $course->id);
+ }
+
+ $this->fullcalendar = Studip\Fullcalendar::create(
+ _('Veranstaltungskalender'),
+ [
+ 'editable' => $calendar_writable,
+ 'selectable' => $calendar_writable,
+ 'studip_urls' => $fullcalendar_studip_urls,
+ 'minTime' => sprintf('%02u:00', $calendar_settings['start'] ?? 8),
+ 'maxTime' => sprintf('%02u:00', $calendar_settings['end'] ?? 20),
+ 'allDaySlot' => true,
+ 'allDayText' => '',
+ 'header' => [
+ 'left' => 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay',
+ 'right' => 'prev,today,next'
+ ],
+ 'weekNumbers' => true,
+ 'views' => [
+ 'dayGridMonth' => [
+ 'eventTimeFormat' => ['hour' => 'numeric', 'minute' => '2-digit'],
+ 'displayEventEnd' => true
+ ],
+ 'timeGridWeek' => [
+ 'columnHeaderFormat' => [ 'weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true ],
+ 'weekends' => $calendar_settings['type_week'] === 'LONG',
+ 'slotDuration' => $slot_settings['week']
+ ],
+ 'timeGridDay' => [
+ 'columnHeaderFormat' => [ 'weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true ],
+ 'slotDuration' => $slot_settings['day']
+ ]
+ ],
+ 'defaultView' => 'timeGridWeek',
+ 'timeGridEventMinHeight' => 20,
+ 'eventSources' => [
+ [
+ 'url' => $this->url_for('calendar/calendar/calendar_data/course_' . $course->id),
+ 'method' => 'GET',
+ 'extraParams' => []
+ ]
+ ]
+ ]
+ );
+ }
+
+ public function calendar_data_action($range_and_id)
+ {
+ $range_and_id = explode('_', $range_and_id);
+ $range = '';
+ $range_id = '';
+ if (!empty($range_and_id[1])) {
+ $range = $range_and_id[0];
+ $range_id = $range_and_id[1];
+ }
+ if (!$range) {
+ //Show the personal calendar of the current user:
+ $range = 'user';
+ $range_id = User::findCurrent()->id;
+ }
+ $owner = null;
+ if (!$range_id) {
+ //Assume a user calendar. $range contains the user-ID.
+ $owner = User::getCalendarOwner($range);
+ } elseif ($range === 'user') {
+ $owner = User::getCalendarOwner($range_id);
+ } elseif ($range === 'course') {
+ $owner = Course::getCalendarOwner($range_id);
+ }
+
+ if (!$owner || !$owner->isCalendarReadable()) {
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
+ }
+
+ $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!');
+ }
+
+ $calendar_events = CalendarDateAssignment::getEvents(
+ $begin,
+ $end,
+ $owner->id,
+ ['PUBLIC', 'PRIVATE', 'CONFIDENTIAL'],
+ Request::bool('show_declined', false)
+ );
+
+ $result = [];
+
+ foreach ($calendar_events as $date) {
+ $event = $date->toEventData(User::findCurrent()->id);
+ $result[] = $event->toFullcalendarEvent();
+ }
+
+ if ($range === 'user') {
+ //Include course dates of courses that shall be displayed in the calendar:
+ $course_dates = CalendarCourseDate::getEvents($begin, $end, $owner->id);
+ foreach ($course_dates as $course_date) {
+ $event = $course_date->toEventData(User::findCurrent()->id);
+ $event->background_colour = '#ffffff';
+ $event->text_colour = '#000000';
+ $event->border_colour = '#000000';
+ $event->event_classes = [];
+ $result[] = $event->toFullcalendarEvent();
+ }
+ //Include relevant cancelled course dates:
+ $cancelled_course_dates = CalendarCourseExDate::getEvents($begin, $end, $owner->id);
+ foreach ($cancelled_course_dates as $cancelled_course_date) {
+ $event = $cancelled_course_date->toEventData(User::findCurrent()->id);
+ $event->background_colour = '#ffffff';
+ $event->text_colour = '#000000';
+ $event->border_colour = '#000000';
+ $event->event_classes = [];
+ $result[] = $event->toFullcalendarEvent();
}
+ }
+ //At this point, everything went fine. We can save the beginning as default date
+ //if the current user is looking at their own calendar:
+ if ($owner instanceof User && $owner->id === User::findCurrent()->id) {
+ $_SESSION['calendar_date'] = $begin->format('Y-m-d');
+ }
+ $this->render_json($result);
+ }
- $status = Request::int('status', 1);
- if ($status > 0 && $status < 6) {
- $this->event->group_status = $status;
- $stored = $this->event->store();
+ public function calendar_group_data_action($group_id)
+ {
+ $begin = Request::getDateTime('start', \DateTime::RFC3339);
+ $end = Request::getDateTime('end', \DateTime::RFC3339);
+ $timeline_view = Request::bool('timeline_view', false);
+
+ if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) {
+ //No time range specified.
+ throw new InvalidArgumentException('Invalid parameters!');
+ }
+
+ $group = null;
+ $users = [];
+ if ($group_id) {
+ //Get the group first:
+ $group = ContactGroup::find($group_id);
+ if ($group->owner_id !== User::findCurrent()->id) {
+ throw new AccessDeniedException();
+ }
+ foreach ($group->items as $item) {
+ if ($item->user->isCalendarReadable()) {
+ $users[] = $item->user;
+ }
+ }
+ if (!$users) {
+ //No user has granted read access to the calendar for the current user.
+ throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!'));
}
+ }
- if ($stored !== false) {
- if ($stored === 0) {
- if (Request::isXhr()) {
- header('X-Dialog-Close: 1');
- exit;
- } else {
- PageLayout::postMessage(MessageBox::success(_('Der Teilnahmestatus wurde nicht geändert.')));
- $this->relocate('calendar/single/' . $this->last_view, ['atime' => $this->atime]);
- }
- } else {
- // send message to organizer...
- if ($this->event->author_id != $user->id) {
- setTempLanguage($this->event->author_id);
- $message = new messaging();
- $msg_text = sprintf(_('%s hat den Terminvorschlag für "%s" am %s von %s auf %s geändert.'),
- get_fullname(), $this->event->getTitle(),
- strftime('%c', $this->event->getStart()),
- $this->event->toStringGroupStatus($old_status), $this->event->toStringGroupStatus());
- if ($status == CalendarEvent::PARTSTAT_DELEGATED) {
- $msg_text .= "\n"
- . sprintf(_('Der Termin wird akzeptiert, aber %s nimmt nicht selbst am Termin teil.'),
- get_fullname());
- }
- $subject = sprintf(_('Terminvorschlag am %s von %s %s'),
- strftime('%c', $this->event->getStart()), get_fullname(), $this->event->toStringGroupStatus());
- $msg_text .= "\n\n**" . _('Beginn') . ':** ';
- if ($this->event->isDayEvent()) {
- $msg_text .= strftime('%x ', $this->event->getStart());
- $msg_text .= _('ganztägig');
- } else {
- $msg_text .= strftime('%c', $this->event->getStart());
- }
- $msg_text .= "\n**" . _('Ende') . ':** ';
- if ($this->event->isDayEvent()) {
- $msg_text .= strftime('%x ', $this->event->getEnd());
- } else {
- $msg_text .= strftime('%c', $this->event->getEnd());
- }
- $msg_text .= "\n**" . _('Zusammenfassung') . ':** ' . $this->event->getTitle() . "\n";
- if ($event_data = $this->event->getDescription()) {
- $msg_text .= '**' . _('Beschreibung') . ":** $event_data\n";
- }
- if ($event_data = $this->event->toStringCategories()) {
- $msg_text .= '**' . _('Kategorie') . ":** $event_data\n";
- }
- if ($event_data = $this->event->toStringPriority()) {
- $msg_text .= '**' . _('Priorität') . ":** $event_data\n";
- }
- if ($event_data = $this->event->toStringAccessibility()) {
- $msg_text .= '**' . _('Zugriff') . ":** $event_data\n";
- }
- if ($event_data = $this->event->toStringRecurrence()) {
- $msg_text .= '**' . _('Wiederholung') . ":** $event_data\n";
- }
- $member = [];
- foreach ($this->event->attendees as $attendee) {
- if ($attendee->range_id == $this->event->getAuthorId()) {
- $member[] = $attendee->user->getFullName()
- . ' ('. _('Organisator') . ')';
- } else {
- $member[] = $attendee->user->getFullName()
- . ' (' . $this->event->toStringGroupStatus($attendee->group_status)
- . ')';
- }
- }
- $msg_text .= '**' . _('Teilnehmende') . ':** ' . implode(', ', $member);
- $msg_text .= "\n\n" . _('Hier kommen Sie direkt zum Termin in Ihrem Kalender:') . "\n";
- $msg_text .= URLHelper::getURL('dispatch.php/calendar/single/edit/'
- . $this->event->getAuthorId() . '/' . $this->event->event_id);
- $message->insert_message(
- addslashes($msg_text),
- [get_username($this->event->getAuthorId())],
- $this->event->range_id,
- '', '', '', '', addslashes($subject));
- restoreLanguage();
+ $result = [];
+
+ foreach ($users as $user) {
+ $events = CalendarDateAssignment::getEvents($begin, $end, $user->id);
+ if ($events) {
+ foreach ($events as $event) {
+ $data = $event->toEventData(User::findCurrent()->id);
+ if (!$timeline_view) {
+ $data->title = $user->getFullName();
}
- PageLayout::postMessage(MessageBox::success(_('Der Teilnahmestatus wurde gespeichert.')));
- $this->relocate('calendar/single/' . $this->last_view, ['atime' => $this->atime]);
+ $result[] = $data->toFullcalendarEvent();
}
}
}
-
- $this->createSidebar('edit', $this->calendar);
- $this->createSidebarFilter();
+ $this->render_json($result);
}
- public function switch_action()
+ public function add_courses_action()
{
- $default_view = $this->settings['view'] ?: 'week';
- $view = Request::option('last_view', $default_view);
- $this->range_id = Request::option('range_id', $GLOBALS['user']->id);
- $object_type = get_object_type($this->range_id);
- switch ($object_type) {
- case 'user':
- URLHelper::addLinkParam('cid', '');
- $this->redirect($this->url_for('calendar/single/'
- . $view . '/' . $this->range_id));
- break;
- case 'sem':
- case 'inst':
- case 'fak':
- URLHelper::addLinkParam('cid', $this->range_id);
- $this->redirect($this->url_for('calendar/single/'
- . $view . '/' . $this->range_id));
- break;
- case 'group':
- URLHelper::addLinkParam('cid', '');
- $this->redirect($this->url_for('calendar/group/'
- . $view . '/' . $this->range_id));
- break;
+ $selected_semester_pseudo_id = Request::option('semester_id');
+ $this->selected_semesters_id = '';
+ $this->available_semester_data = [];
+ $semesters = Semester::getAll();
+ foreach ($semesters as $semester) {
+ $this->available_semester_data[$semester['id']] = [
+ 'id' => $semester['id'],
+ 'name' => $semester['name']
+ ];
}
- }
+ $this->available_semester_data = array_reverse($this->available_semester_data);
- public function jump_to_action()
- {
- $date = Request::get('jmp_date');
- if ($date) {
- $atime = strtotime($date . strftime(' %T', $this->atime));
+ if (!$selected_semester_pseudo_id) {
+ $selected_semester_pseudo_id = User::findCurrent()->getConfiguration()->MY_COURSES_SELECTED_CYCLE;
+ if (!Config::get()->MY_COURSES_ENABLE_ALL_SEMESTERS && $selected_semester_pseudo_id === 'all') {
+ $selected_semester_pseudo_id = 'next';
+ }
+ if (!$selected_semester_pseudo_id) {
+ $selected_semester_pseudo_id = Config::get()->MY_COURSES_DEFAULT_CYCLE;
+ }
+ }
+ if ($selected_semester_pseudo_id === 'next') {
+ $semester = Semester::findNext();
+ $this->selected_semester_id = $semester->id;
+ } elseif (in_array($selected_semester_pseudo_id, ['all', 'current'])) {
+ $semester = Semester::findCurrent();
+ $this->selected_semester_id = $semester->id;
+ } elseif ($selected_semester_pseudo_id === 'last') {
+ $semester = Semester::findPrevious();
+ $this->selected_semester_id = $semester->id;
} else {
- $atime = 'now';
+ $this->selected_semester_id = $selected_semester_pseudo_id ?? '';
+ if (!Semester::exists($this->selected_semesters_id)) {
+ $this->selected_semester_id = '';
+ }
+ }
+
+ $this->selected_course_ids = SimpleCollection::createFromArray(
+ CourseMember::findBySQL(
+ 'user_id = :user_id AND bind_calendar = 1',
+ ['user_id' => User::findCurrent()->id]
+ )
+ )->pluck('seminar_id');
+
+ $this->semester_data = [];
+ $all_semesters = Semester::getAll();
+ foreach ($all_semesters as $semester) {
+ $data = [
+ 'id' => $semester->id,
+ 'name' => $semester->name,
+ 'courses' => []
+ ];
+ $this->semester_data[] = $data;
+ }
+
+ if (Request::submitted('add')) {
+ CSRFProtection::verifyUnsafeRequest();
+
+ $course_ids = Request::getArray('courses_course_ids');
+ foreach ($course_ids as $course_id => $selected) {
+ $course_membership = CourseMember::findOneBySQL(
+ 'seminar_id = :course_id AND user_id = :user_id',
+ [
+ 'course_id' => $course_id,
+ 'user_id' => User::findCurrent()->id
+ ]
+ );
+ if ($course_membership) {
+ $course_membership->bind_calendar = $selected ? '1' : '0';
+ $course_membership->store();
+ }
+ }
+ PageLayout::postSuccess(_('Die Zuordnung von Veranstaltungen zum Kalender wurde aktualisiert.'));
+ $this->redirect('calendar/calendar');
}
- $action = Request::option('action', 'week');
- $this->range_id = $this->range_id ?: $GLOBALS['user']->id;
- $this->redirect($this->url_for($this->base . $action,
- ['atime' => $atime, 'range_id' => $this->range_id]));
}
- public function show_declined_action ()
+ public function export_action()
{
- $config = UserConfig::get($GLOBALS['user']->id);
- $this->settings['show_declined'] = Request::int('show_declined') ? '1' : '0';
- // var_dump($this->settings); exit;
- $config->store('CALENDAR_SETTINGS', $this->settings);
- $action = Request::option('action', 'week');
- $this->range_id = $this->range_id ?: $GLOBALS['user']->id;
- $this->redirect($this->url_for($this->base . $action,
- ['range_id' => $this->range_id]));
+ PageLayout::setTitle(_('Termine exportieren'));
+ $this->begin = new DateTimeImmutable();
+ $this->end = $this->begin->add(new DateInterval('P1Y'));
+ $this->dates_to_export = 'user';
+ if (Request::submitted('export')) {
+ CSRFProtection::verifyUnsafeRequest();
+ $this->begin = Request::getDateTime('begin', 'd.m.Y');
+ $this->end = Request::getDateTime('end', 'd.m.Y');
+ if ($this->begin >= $this->end) {
+ PageLayout::postError(_('Der Startzeitpunkt darf nicht nach dem Endzeitpunkt liegen!'));
+ return;
+ }
+ $this->dates_to_export = Request::get('dates_to_export');
+ if (!in_array($this->dates_to_export, ['user', 'course', 'all'])) {
+ PageLayout::postError(_('Bitte wählen Sie aus, welche Termine exportiert werden sollen!'));
+ return;
+ }
+ $ical = '';
+ $calendar_export = new ICalendarExport();
+ if ($this->dates_to_export === 'user') {
+ $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $this->begin, $this->end);
+ } elseif ($this->dates_to_export === 'course') {
+ $ical = $calendar_export->exportCourseDates(User::findCurrent()->id, $this->begin, $this->end);
+ $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $this->begin, $this->end);
+ } elseif ($this->dates_to_export === 'all') {
+ $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $this->begin, $this->end);
+ $ical .= $calendar_export->exportCourseDates(User::findCurrent()->id, $this->begin, $this->end);
+ $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $this->begin, $this->end);
+ }
+ $ical = $calendar_export->writeHeader() . $ical . $calendar_export->writeFooter();
+ $this->response->add_header('Content-Type', 'text/calendar;charset=utf-8');
+ $this->response->add_header('Content-Disposition', 'attachment; filename="studip.ics"');
+ $this->response->add_header('Content-Transfer-Encoding', 'binary');
+ $this->response->add_header('Pragma', 'public');
+ $this->response->add_header('Cache-Control', 'private');
+ $this->response->add_header('Content-Length', strlen($ical));
+ $this->render_text($ical);
+ }
}
- protected function storeEventData(CalendarEvent $event, SingleCalendar $calendar)
+ public function import_action() {}
+
+ public function import_file_action()
{
- $messages = [];
- if (Request::int('isdayevent')) {
- $dt_string = Request::get('start_date') . ' 00:00:00';
- } else {
- $dt_string = sprintf(
- '%s %u:%02u',
- Request::get('start_date'),
- Request::int('start_hour'),
- Request::int('start_minute')
- );
- }
- $event->setStart($this->parseDateTime($dt_string));
- if (Request::int('isdayevent')) {
- $dt_string = Request::get('end_date') . ' 23:59:59';
- } else {
- $dt_string = sprintf(
- '%s %u:%02u',
- Request::get('end_date'),
- Request::int('end_hour'),
- Request::int('end_minute')
- );
+ if (Request::submitted('import')) {
+ CSRFProtection::verifySecurityToken();
+ $range_id = Context::getId() ?? User::findCurrent()->id;
+ $calendar_import = new ICalendarImport($range_id);
+ $calendar_import->convertPublicToPrivate(Request::bool('import_as_private_imp'));
+ $calendar_import->import(file_get_contents($_FILES['importfile']['tmp_name']));
+ $import_count = $calendar_import->getCountEvents();
+ PageLayout::postSuccess(sprintf(
+ ngettext(
+ 'Ein Termin wurde importiert.',
+ 'Es wurden %u Termine importiert.',
+ $import_count
+ ),
+ $import_count
+ ));
+ $this->redirect($this->url_for('calendar/calendar/'));
}
- $event->setEnd($this->parseDateTime($dt_string));
+ }
- if (!$this->validate_datetime(sprintf('%02u:%02u',Request::int('start_hour'),Request::int('start_minute')))
- || !$this->validate_datetime(sprintf('%02u:%02u',Request::int('end_hour'),Request::int('end_minute')))
- ) {
- $messages[] = _('Die Start- und/oder Endzeit ist ungültig!');
+ public function share_action()
+ {
+ PageLayout::setTitle(_('Kalender teilen'));
+ if (!Config::get()->CALENDAR_GROUP_ENABLE) {
+ throw new FeatureDisabledException();
}
- if ($event->getStart() > $event->getEnd()) {
- $messages[] = _('Die Startzeit muss vor der Endzeit liegen.');
+ $calendar_contacts = Contact::findBySql(
+ "JOIN `auth_user_md5` USING (`user_id`)
+ WHERE `contact`.`owner_id` = :user_id
+ AND `contact`.`calendar_permissions` <> ''
+ ORDER BY `auth_user_md5`.`Vorname`, `auth_user_md5`.`Nachname`",
+ [
+ 'user_id' => User::findCurrent()->id
+ ]
+ );
+ $user_data = [];
+ foreach ($calendar_contacts as $contact) {
+ $user_data[$contact->user_id] = [
+ 'id' => $contact->user_id,
+ 'name' => $contact->friend->getFullName(),
+ 'write_permissions' => $contact->calendar_permissions === 'WRITE'
+ ];
}
+ $this->selected_users_json = json_encode($user_data, JSON_FORCE_OBJECT);
+ $this->searchtype = new StandardSearch('user_id', ['simple_name' => true]);
- $event->setTitle(Request::get('summary', ''));
- $event->event->description = Request::get('description', '');
- $event->setUserDefinedCategories(Request::get('categories', ''));
- $event->event->location = Request::get('location', '');
- $event->event->category_intern = Request::int('category_intern', 1);
- $event->setAccessibility(Request::option('accessibility', 'PRIVATE'));
- $event->setPriority(Request::int('priority', 0));
+ if (Request::submitted('share')) {
+ CSRFProtection::verifyUnsafeRequest();
+ $selected_user_ids = Request::getArray('calendar_permissions', []);
+ $write_permissions = Request::getArray('calendar_write_permissions', []);
- if (!$event->getTitle()) {
- $messages[] = _('Es muss eine Zusammenfassung angegeben werden.');
- }
+ //Add/update contacts with calendar permissions:
- $rec_type = Request::option('recurrence', 'single');
- $expire = Request::option('exp_c', 'never');
- $rrule = [
- 'linterval' => null,
- 'sinterval' => null,
- 'wdays' => null,
- 'month' => null,
- 'day' => null,
- 'rtype' => 'SINGLE',
- 'count' => null,
- 'expire' => null
- ];
- if ($expire == 'count') {
- $rrule['count'] = Request::int('exp_count', 10);
- } else if ($expire == 'date') {
- if (Request::isXhr()) {
- $exp_date = Request::get('exp_date');
- } else {
- $exp_date = Request::get('exp_date');
- }
- $exp_date = $exp_date ?: strftime('%x', time());
- $rrule['expire'] = $this->parseDateTime($exp_date . ' 12:00');
- }
- switch ($rec_type) {
- case 'daily':
- if (Request::option('type_daily', 'day') === 'day') {
- $rrule['linterval'] = Request::int('linterval_d', 1);
- $rrule['rtype'] = 'DAILY';
- } else {
- $rrule['linterval'] = 1;
- $rrule['wdays'] = '12345';
- $rrule['rtype'] = 'WEEKLY';
+ foreach ($selected_user_ids as $user_id) {
+ $user = User::find($user_id);
+ if (!$user) {
+ //No user? No contact!
+ continue;
}
- break;
- case 'weekly':
- $rrule['rtype'] = 'WEEKLY';
- $rrule['linterval'] = Request::int('linterval_w', 1);
- $rrule['wdays'] = implode('', Request::intArray('wdays',
- [strftime('%u', $event->getStart())]));
- break;
- case 'monthly':
- $rrule['rtype'] = 'MONTHLY';
- if (Request::option('type_m', 'day') === 'day') {
- $rrule['linterval'] = Request::int('linterval_m1', 1);
- $rrule['day'] = Request::int('day_m',
- strftime('%e', $event->getStart()));
- } else {
- $rrule['linterval'] = Request::int('linterval_m2', 1);
- $rrule['sinterval'] = Request::int('sinterval_m', 1);
- $rrule['wdays'] = Request::int('wday_m',
- strftime('%u', $event->getStart()));
+ $contact = Contact::findOneBySql(
+ 'owner_id = :owner_id AND user_id = :user_id',
+ [
+ 'owner_id' => User::findCurrent()->id,
+ 'user_id' => $user_id
+ ]
+ );
+ if (!$contact) {
+ $contact = new Contact();
+ $contact->owner_id = User::findCurrent()->id;
+ $contact->user_id = $user->id;
}
- break;
- case 'yearly':
- $rrule['rtype'] = 'YEARLY';
- $rrule['linterval'] = 1;
- if (Request::option('type_y', 'day') === 'day') {
- $rrule['day'] = Request::int('day_y',
- strftime('%e', $event->getStart()));
- $rrule['month'] = Request::int('month_y1',
- date('n', $event->getStart()));
+ if (in_array($user->id, $write_permissions)) {
+ $contact->calendar_permissions = 'WRITE';
} else {
- $rrule['sinterval'] = Request::int('sinterval_y', 1);
- $rrule['wdays'] = Request::int('wday_y',
- strftime('%u', $event->getStart()));
- $rrule['month'] = Request::int('month_y2',
- date('n', $event->getStart()));
+ $contact->calendar_permissions = 'READ';
}
- break;
- }
- if (sizeof($messages)) {
- PageLayout::postMessage(MessageBox::error(_('Bitte Eingaben korrigieren'), $messages));
- return false;
- } else {
- $event->setRecurrence($rrule);
- $exceptions = array_diff(Request::getArray('exc_dates'),
- Request::getArray('del_exc_dates'));
- $event->setExceptions($this->parseExceptions($exceptions));
- // if this is a group event, store event in the calendars of each attendee
- if (Config::get()->CALENDAR_GROUP_ENABLE) {
- $attendee_ids = Request::optionArray('attendees');
- return $calendar->storeEvent($event, $attendee_ids);
- } else {
- return $calendar->storeEvent($event);
+ $contact->store();
}
- }
- }
- /**
- * Parses a string with exception dates from input form and returns an array
- * with all dates as unix timestamp identified by an internally used pattern.
- *
- * @param string $exc_dates
- * @return array An array of unix timestamps.
- */
- protected function parseExceptions($exc_dates) {
- $matches = [];
- $dates = [];
- preg_match_all('%(\d{1,2})\h*([/.])\h*(\d{1,2})\h*([/.])\h*(\d{4})\s*%',
- implode(' ', $exc_dates), $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- if ($match[2] == '/') {
- $dates[] = strtotime($match[1].'/'.$match[3].'/'.$match[5]);
+ //Revoke calendar permissions for all users that aren't in the list
+ //of selected users:
+ if ($selected_user_ids) {
+ $stmt = DBManager::get()->prepare(
+ "UPDATE `contact` SET `calendar_permissions` = ''
+ WHERE `owner_id` = :owner_id
+ AND `user_id` NOT IN ( :user_ids )"
+ );
+ $stmt->execute([
+ 'owner_id' => User::findCurrent()->id,
+ 'user_ids' => $selected_user_ids
+ ]);
} else {
- $dates[] = strtotime($match[1].$match[2].$match[3].$match[4].$match[5]);
+ $stmt = DBManager::get()->prepare(
+ "UPDATE `contact` SET `calendar_permissions` = ''
+ WHERE `owner_id` = :owner_id"
+ );
+ $stmt->execute(['owner_id' => User::findCurrent()->id]);
}
+
+ PageLayout::postSuccess(
+ _('Die Kalenderfreigaben wurden geändert.')
+ );
+ $this->response->add_header('X-Dialog-Close', '1');
}
- return $dates;
}
- /**
- * Parses a string as date time in the format "j.n.Y H:i:s" and returns the
- * corresponding unix time stamp.
- *
- * @param string $dt_string The date time string.
- * @return int A unix time stamp
- */
- protected function parseDateTime($dt_string)
+ public function publish_action()
{
- $dt_array = date_parse_from_format('j.n.Y H:i:s', $dt_string);
- return mktime($dt_array['hour'], $dt_array['minute'], $dt_array['second'],
- $dt_array['month'], $dt_array['day'], $dt_array['year']);
- }
+ $this->short_id = null;
+ if (Request::submitted('delete_id')) {
+ CSRFProtection::verifySecurityToken();
+ IcalExport::deleteKey(User::findCurrent()->id);
+ PageLayout::postSuccess(_('Die Adresse, unter der Ihre Termine abrufbar sind, wurde gelöscht'));
+ }
+
+ if (Request::submitted('new_id')) {
+ CSRFProtection::verifySecurityToken();
+ $this->short_id = IcalExport::setKey(User::findCurrent()->id);
+ PageLayout::postSuccess(_('Eine Adresse, unter der Ihre Termine abrufbar sind, wurde erstellt.'));
+ } else {
+ $this->short_id = IcalExport::getKeyByUser(User::findCurrent()->id);
+ }
+ $text = '';
+ if (Request::submitted('submit_email')) {
+ $email_reg_exp = '/^([-.0-9=?A-Z_a-z{|}~])+@([-.0-9=?A-Z_a-z{|}~])+\.[a-zA-Z]{2,6}$/i';
+ if (preg_match($email_reg_exp, Request::get('email')) !== 0) {
+ $subject = '[' .Config::get()->UNI_NAME_CLEAN . ']' . _('Exportadresse für Ihre Termine');
+ $text .= _('Diese Email wurde vom Stud.IP-System verschickt. Sie können auf diese Nachricht nicht antworten.') . "\n\n";
+ $text .= _('Über diese Adresse erreichen Sie den Export für Ihre Termine:') . "\n\n";
+ $text .= $GLOBALS['ABSOLUTE_URI_STUDIP'] . 'dispatch.php/ical/index/'
+ . IcalExport::getKeyByUser(User::findCurrent()->id);
+ StudipMail::sendMessage(Request::get('email'), $subject, $text);
+ PageLayout::postSuccess(_('Die Adresse wurde verschickt!'));
+ } else {
+ PageLayout::postError(_('Bitte geben Sie eine gültige Email-Adresse an.'));
+ }
+ $this->short_id = IcalExport::getKeyByUser(User::findCurrent()->id);
+ }
+ PageLayout::setTitle(_('Kalender veröffentlichen'));
+ }
}