elkarte /
Elkarte
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file has only one real task, showing the calendar. |
||
| 5 | * Original module by Aaron O'Neil - [email protected] |
||
| 6 | * |
||
| 7 | * @package ElkArte Forum |
||
| 8 | * @copyright ElkArte Forum contributors |
||
| 9 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
| 10 | * |
||
| 11 | * This file contains code covered by: |
||
| 12 | * copyright: 2011 Simple Machines (http://www.simplemachines.org) |
||
| 13 | * |
||
| 14 | * @version 2.0 dev |
||
| 15 | * |
||
| 16 | */ |
||
| 17 | |||
| 18 | namespace ElkArte\Controller; |
||
| 19 | |||
| 20 | use ElkArte\AbstractController; |
||
| 21 | use ElkArte\CalendarEvent; |
||
| 22 | use ElkArte\EventManager; |
||
| 23 | use ElkArte\Exceptions\Exception; |
||
| 24 | use ElkArte\Helper\Util; |
||
| 25 | use ElkArte\Http\Headers; |
||
| 26 | use ElkArte\User; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * Displays the calendar for the site and provides for its navigation |
||
| 30 | */ |
||
| 31 | class Calendar extends AbstractController |
||
| 32 | { |
||
| 33 | /** |
||
| 34 | * Default action handler for requests on the calendar |
||
| 35 | * |
||
| 36 | * @see AbstractController::action_index |
||
| 37 | 2 | */ |
|
| 38 | public function action_index() |
||
| 39 | { |
||
| 40 | 2 | // when you don't know what you're doing... we know! :P |
|
| 41 | $this->action_calendar(); |
||
| 42 | } |
||
| 43 | |||
| 44 | /** |
||
| 45 | * Show the calendar. |
||
| 46 | * |
||
| 47 | * - It loads the specified month's events, holidays, and birthdays. |
||
| 48 | * - It requires the calendar_view permission. |
||
| 49 | * - It depends on the cal_enabled setting, and many of the other cal_ settings. |
||
| 50 | * - It uses the calendar_start_day theme option. (Monday/Sunday) |
||
| 51 | * - It goes to the month and year passed in 'month' and 'year' by get or post. |
||
| 52 | * - It is accessed through ?action=calendar. |
||
| 53 | * |
||
| 54 | * @uses the main sub template in the Calendar template. |
||
| 55 | 2 | */ |
|
| 56 | public function action_calendar(): void |
||
| 57 | 2 | { |
|
| 58 | global $txt, $context, $modSettings, $options; |
||
| 59 | |||
| 60 | 2 | // Permissions, permissions, permissions. |
|
| 61 | isAllowedTo('calendar_view'); |
||
| 62 | |||
| 63 | 2 | // This is gonna be needed... |
|
| 64 | theme()->getTemplates()->load('Calendar'); |
||
| 65 | |||
| 66 | 2 | // You can't do anything if the calendar is off. |
|
| 67 | if (empty($modSettings['cal_enabled'])) |
||
| 68 | 2 | { |
|
| 69 | throw new Exception('calendar_off', false); |
||
| 70 | } |
||
| 71 | |||
| 72 | if (empty($modSettings['cal_limityear'])) |
||
| 73 | { |
||
| 74 | $modSettings['cal_limityear'] = 20; |
||
| 75 | } |
||
| 76 | |||
| 77 | // Set the page title to mention the calendar ;). |
||
| 78 | $context['page_title'] = $txt['calendar']; |
||
| 79 | $context['sub_template'] = 'show_calendar'; |
||
| 80 | |||
| 81 | // Is this a week view? |
||
| 82 | $context['view_week'] = isset($_GET['viewweek']); |
||
| 83 | $context['cal_minyear'] = $modSettings['cal_minyear']; |
||
| 84 | $context['cal_maxyear'] = (int) date('Y') + (int) $modSettings['cal_limityear']; |
||
| 85 | |||
| 86 | // Don't let search engines index weekly calendar pages. |
||
| 87 | if ($context['view_week']) |
||
| 88 | { |
||
| 89 | $context['robot_no_index'] = true; |
||
| 90 | } |
||
| 91 | |||
| 92 | // Get the current day of month... |
||
| 93 | require_once(SUBSDIR . '/Calendar.subs.php'); |
||
| 94 | $today = getTodayInfo(); |
||
| 95 | |||
| 96 | // If the month and year are not passed in, use today's date as a starting point. |
||
| 97 | $curPage = [ |
||
| 98 | 'day' => isset($_REQUEST['day']) ? (int) $_REQUEST['day'] : $today['day'], |
||
| 99 | 'month' => isset($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'], |
||
| 100 | 'year' => isset($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year'] |
||
| 101 | ]; |
||
| 102 | |||
| 103 | // Make sure the year and month are in valid ranges. |
||
| 104 | if ($curPage['month'] < 1 || $curPage['month'] > 12) |
||
| 105 | { |
||
| 106 | throw new Exception('invalid_month', false); |
||
| 107 | } |
||
| 108 | |||
| 109 | if ($curPage['year'] < $context['cal_minyear'] || $curPage['year'] > $context['cal_maxyear']) |
||
| 110 | { |
||
| 111 | throw new Exception('invalid_year', false); |
||
| 112 | } |
||
| 113 | |||
| 114 | // If we have a day clean that too. |
||
| 115 | if ($context['view_week'] && ($curPage['day'] > 31 || !mktime(0, 0, 0, $curPage['month'], $curPage['day'], $curPage['year']))) |
||
| 116 | { |
||
| 117 | throw new Exception('invalid_day', false); |
||
| 118 | } |
||
| 119 | |||
| 120 | // Load all the context information needed to show the calendar grid. |
||
| 121 | $calendarOptions = [ |
||
| 122 | 'start_day' => empty($options['calendar_start_day']) ? 0 : $options['calendar_start_day'], |
||
| 123 | 'show_birthdays' => in_array((int) $modSettings['cal_showbdays'], [1, 2]), |
||
| 124 | 'show_events' => in_array((int) $modSettings['cal_showevents'], [1, 2]), |
||
| 125 | 'show_holidays' => in_array((int) $modSettings['cal_showholidays'], [1, 2]), |
||
| 126 | 'show_week_num' => true, |
||
| 127 | 'short_day_titles' => false, |
||
| 128 | 'show_next_prev' => true, |
||
| 129 | 'show_week_links' => true, |
||
| 130 | 'size' => 'large', |
||
| 131 | ]; |
||
| 132 | |||
| 133 | // Load up the main view. |
||
| 134 | if ($context['view_week']) |
||
| 135 | { |
||
| 136 | $context['calendar_grid_main'] = getCalendarWeek($curPage['month'], $curPage['year'], $curPage['day'], $calendarOptions); |
||
| 137 | } |
||
| 138 | else |
||
| 139 | { |
||
| 140 | $context['calendar_grid_main'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions); |
||
| 141 | } |
||
| 142 | |||
| 143 | // Load up the previous and next months. |
||
| 144 | $calendarOptions['show_birthdays'] = $calendarOptions['show_events'] = $calendarOptions['show_holidays'] = false; |
||
| 145 | $calendarOptions['short_day_titles'] = true; |
||
| 146 | $calendarOptions['show_next_prev'] = false; |
||
| 147 | $calendarOptions['show_week_links'] = false; |
||
| 148 | $calendarOptions['size'] = 'small'; |
||
| 149 | $context['calendar_grid_current'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions); |
||
| 150 | |||
| 151 | // Only show previous month if it isn't pre-January of the min-year |
||
| 152 | if ($context['calendar_grid_current']['previous_calendar']['year'] > $context['cal_minyear'] || $curPage['month'] != 1) |
||
| 153 | { |
||
| 154 | $context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['month'], $context['calendar_grid_current']['previous_calendar']['year'], $calendarOptions); |
||
| 155 | } |
||
| 156 | |||
| 157 | // Only show next month if it isn't post-December of the max-year |
||
| 158 | if ($context['calendar_grid_current']['next_calendar']['year'] < $context['cal_maxyear'] || $curPage['month'] != 12) |
||
| 159 | { |
||
| 160 | $context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['month'], $context['calendar_grid_current']['next_calendar']['year'], $calendarOptions); |
||
| 161 | } |
||
| 162 | |||
| 163 | // Basic template stuff. |
||
| 164 | $context['can_post'] = allowedTo('calendar_post'); |
||
| 165 | $context['current_day'] = $curPage['day']; |
||
| 166 | $context['current_month'] = $curPage['month']; |
||
| 167 | $context['current_year'] = $curPage['year']; |
||
| 168 | $context['show_all_birthdays'] = isset($_GET['showbd']); |
||
| 169 | |||
| 170 | // Set the page title to mention the month or week, too |
||
| 171 | $context['page_title'] .= ' - ' . ($context['view_week'] ? sprintf($txt['calendar_week_title'], $context['calendar_grid_main']['week_number'], ($context['calendar_grid_main']['week_number'] == 53 ? $context['current_year'] - 1 : $context['current_year'])) : $txt['months'][$context['current_month']] . ' ' . $context['current_year']); |
||
| 172 | |||
| 173 | // Load up the breadcrumbs! |
||
| 174 | $context['breadcrumbs'][] = [ |
||
| 175 | 'url' => getUrl('action', ['action' => 'calendar']), |
||
| 176 | 'name' => $txt['calendar'] |
||
| 177 | ]; |
||
| 178 | |||
| 179 | // Add the current month to the breadcrumbs. |
||
| 180 | $context['breadcrumbs'][] = [ |
||
| 181 | 'url' => getUrl('action', ['action' => 'calendar', 'year' => $context['current_year'], 'month' => $context['current_month']]), |
||
| 182 | 'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year'] |
||
| 183 | ]; |
||
| 184 | |||
| 185 | // If applicable, add the current week to the breadcrumbs. |
||
| 186 | if ($context['view_week']) |
||
| 187 | { |
||
| 188 | $context['breadcrumbs'][] = [ |
||
| 189 | 'url' => getUrl('action', ['action' => 'calendar', 'year' => $context['current_year'], 'month' => $context['current_month'], 'day' => $context['current_day'], 'viewweek']), |
||
| 190 | 'name' => $txt['calendar_week'] . ' ' . $context['calendar_grid_main']['week_number'] |
||
| 191 | ]; |
||
| 192 | } |
||
| 193 | |||
| 194 | // Build the calendar button array. |
||
| 195 | $context['calendar_buttons'] = [ |
||
| 196 | 'post_event' => [ |
||
| 197 | 'test' => 'can_post', |
||
| 198 | 'text' => 'calendar_post_event', |
||
| 199 | 'lang' => true, |
||
| 200 | 'url' => getUrl('action', ['action' => 'calendar', 'sa' => 'post', 'year' => $context['current_year'], 'month' => $context['current_month'], '{session_data}']) |
||
| 201 | ], |
||
| 202 | ]; |
||
| 203 | |||
| 204 | // Allow mods to add additional buttons here |
||
| 205 | call_integration_hook('integrate_calendar_buttons'); |
||
| 206 | } |
||
| 207 | |||
| 208 | /** |
||
| 209 | * This function processes posting/editing/deleting a calendar event. |
||
| 210 | * |
||
| 211 | * - Calls action_post() function if event is linked to a post. |
||
| 212 | * - Calls insertEvent() to insert the event if not linked to post. |
||
| 213 | * - It requires the calendar_post permission to use. |
||
| 214 | * - It is accessed with ?action=calendar;sa=post. |
||
| 215 | * |
||
| 216 | * @uses the event_post sub template in the Calendar template. |
||
| 217 | */ |
||
| 218 | public function action_post() |
||
| 219 | { |
||
| 220 | global $context, $txt, $modSettings; |
||
| 221 | |||
| 222 | // You need to view what you're doing :P |
||
| 223 | isAllowedTo('calendar_view'); |
||
| 224 | |||
| 225 | // Well - can they post? |
||
| 226 | isAllowedTo('calendar_post'); |
||
| 227 | |||
| 228 | // Cast this for safety... |
||
| 229 | $event_id = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : null; |
||
| 230 | |||
| 231 | // Submitting? |
||
| 232 | if (isset($_POST[$context['session_var']], $event_id)) |
||
| 233 | { |
||
| 234 | return $this->action_save(); |
||
| 235 | } |
||
| 236 | |||
| 237 | // If we are not enabled... we are not enabled. |
||
| 238 | if (empty($modSettings['cal_allow_unlinked']) && empty($event_id)) |
||
| 239 | { |
||
| 240 | $_REQUEST['calendar'] = 1; |
||
| 241 | |||
| 242 | return $this->_returnToPost(); |
||
| 243 | } |
||
| 244 | |||
| 245 | $event = new CalendarEvent($event_id, $modSettings); |
||
| 246 | |||
| 247 | $context['event'] = $event->load($_REQUEST, $this->user->id); |
||
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
| 248 | |||
| 249 | if ($event->isNew()) |
||
| 250 | { |
||
| 251 | // Get list of boards that can be posted in. |
||
| 252 | $boards = boardsAllowedTo('post_new'); |
||
| 253 | if (empty($boards)) |
||
| 254 | { |
||
| 255 | throw new Exception('cannot_post_new', 'permission'); |
||
| 256 | } |
||
| 257 | |||
| 258 | // Load the list of boards and categories in the context. |
||
| 259 | require_once(SUBSDIR . '/Boards.subs.php'); |
||
| 260 | $boardListOptions = [ |
||
| 261 | 'included_boards' => in_array(0, $boards) ? null : $boards, |
||
| 262 | 'not_redirection' => true, |
||
| 263 | 'selected_board' => $modSettings['cal_defaultboard'], |
||
| 264 | ]; |
||
| 265 | $context += getBoardList($boardListOptions); |
||
| 266 | } |
||
| 267 | |||
| 268 | // Template, sub template, etc. |
||
| 269 | theme()->getTemplates()->load('Calendar'); |
||
| 270 | $context['sub_template'] = 'unlinked_event_post'; |
||
| 271 | |||
| 272 | $modSettings['cal_limityear'] = empty($modSettings['cal_limityear']) ? 20 : (int) $modSettings['cal_limityear']; |
||
| 273 | |||
| 274 | $context['cal_minyear'] = $modSettings['cal_minyear']; |
||
| 275 | $context['cal_maxyear'] = (int) date('Y') + $modSettings['cal_limityear']; |
||
| 276 | $context['page_title'] = $event->isNew() ? $txt['calendar_edit'] : $txt['calendar_post_event']; |
||
| 277 | $context['breadcrumbs'][] = [ |
||
| 278 | 'name' => $context['page_title'], |
||
| 279 | ]; |
||
| 280 | } |
||
| 281 | |||
| 282 | /** |
||
| 283 | * Takes care of the saving process. |
||
| 284 | */ |
||
| 285 | public function action_save(): ?bool |
||
| 286 | { |
||
| 287 | global $modSettings; |
||
| 288 | |||
| 289 | checkSession(); |
||
| 290 | |||
| 291 | // Cast this for safety... |
||
| 292 | $event_id = $this->_req->get('eventid', 'intval'); |
||
| 293 | |||
| 294 | $event = new CalendarEvent($event_id, $modSettings); |
||
| 295 | |||
| 296 | // Validate the post... |
||
| 297 | $save_data = []; |
||
| 298 | if (!isset($_POST['link_to_board'])) |
||
| 299 | { |
||
| 300 | try |
||
| 301 | { |
||
| 302 | $save_data = $event->validate($_POST); |
||
| 303 | } |
||
| 304 | catch (Exception $e) |
||
| 305 | { |
||
| 306 | // @todo This should really integrate into $post_errors. |
||
| 307 | $e->fatalLangError(); |
||
| 308 | } |
||
| 309 | } |
||
| 310 | |||
| 311 | // If you're not allowed to edit any events, you have to be the poster. |
||
| 312 | if (!$event->isNew() && !allowedTo('calendar_edit_any')) |
||
| 313 | { |
||
| 314 | isAllowedTo('calendar_edit_' . ($event->isStarter($this->user->id) ? 'own' : 'any')); |
||
| 315 | } |
||
| 316 | |||
| 317 | // New - and directing? |
||
| 318 | if ($event->isNew() && isset($_POST['link_to_board'])) |
||
| 319 | { |
||
| 320 | $_REQUEST['calendar'] = 1; |
||
| 321 | |||
| 322 | return $this->_returnToPost(); |
||
| 323 | } |
||
| 324 | |||
| 325 | // New... |
||
| 326 | if ($event->isNew()) |
||
| 327 | { |
||
| 328 | $event->insert($save_data, $this->user->id); |
||
| 329 | } |
||
| 330 | elseif (isset($_REQUEST['deleteevent'])) |
||
| 331 | { |
||
| 332 | $event->remove(); |
||
| 333 | } |
||
| 334 | else |
||
| 335 | { |
||
| 336 | $event->update($save_data); |
||
| 337 | } |
||
| 338 | |||
| 339 | // No point hanging around here now... |
||
| 340 | redirectexit('action=calendar;month=' . $this->_req->get('month', 'intval') . ';year=' . $this->_req->get('year', 'intval')); |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * |
||
| 345 | * What it does: |
||
| 346 | * - require_once modules of the controller (not addons because these are always all require'd by the dispatcher), |
||
| 347 | * - Creates the event manager and registers addons and modules, |
||
| 348 | * - Instantiate the controller |
||
| 349 | * - Runs pre_dispatch |
||
| 350 | */ |
||
| 351 | protected function _returnToPost(): bool |
||
| 352 | { |
||
| 353 | $controller = new Post(new EventManager()); |
||
| 354 | $controller->setUser(User::$info); |
||
| 355 | |||
| 356 | $hook = $controller->getHook(); |
||
| 357 | $controller->pre_dispatch(); |
||
| 358 | $function_name = 'action_post'; |
||
| 359 | |||
| 360 | call_integration_hook('integrate_action_' . $hook . '_before', [$function_name]); |
||
| 361 | |||
| 362 | $controller->{$function_name}(); |
||
| 363 | |||
| 364 | call_integration_hook('integrate_action_' . $hook . '_after', [$function_name]); |
||
| 365 | |||
| 366 | return true; |
||
| 367 | } |
||
| 368 | |||
| 369 | /** |
||
| 370 | * This function offers up a download of an event in iCal 2.0 format. |
||
| 371 | * |
||
| 372 | * What it does: |
||
| 373 | * |
||
| 374 | * - Follows the conventions in RFC5546 https://tools.ietf.org/html/rfc5546 |
||
| 375 | * - Sets events as all day events since we don't have hourly events |
||
| 376 | * - Will honor and set multi day events |
||
| 377 | * - Sets a sequence number if the event has been modified. |
||
| 378 | * - Accessed by action=calendar;sa=ical |
||
| 379 | */ |
||
| 380 | public function action_ical(): void |
||
| 381 | { |
||
| 382 | global $modSettings; |
||
| 383 | |||
| 384 | // What do you think you export? |
||
| 385 | isAllowedTo('calendar_view'); |
||
| 386 | |||
| 387 | // You can't export if the calendar export feature is off. |
||
| 388 | if (empty($modSettings['cal_export'])) |
||
| 389 | { |
||
| 390 | throw new Exception('calendar_export_off', false); |
||
| 391 | } |
||
| 392 | |||
| 393 | // Goes without saying that this is required. |
||
| 394 | if (!isset($_REQUEST['eventid'])) |
||
| 395 | { |
||
| 396 | throw new Exception('no_access', false); |
||
| 397 | } |
||
| 398 | |||
| 399 | // This is kinda wanted. |
||
| 400 | require_once(SUBSDIR . '/Calendar.subs.php'); |
||
| 401 | |||
| 402 | // Load up the event in question and check it exists. |
||
| 403 | $event = getEventProperties($_REQUEST['eventid']); |
||
| 404 | |||
| 405 | if ($event === false) |
||
|
0 ignored issues
–
show
|
|||
| 406 | { |
||
| 407 | throw new Exception('no_access', false); |
||
| 408 | } |
||
| 409 | |||
| 410 | $filecontents = build_ical_content($event); |
||
| 411 | |||
| 412 | // Send some standard headers. |
||
| 413 | obStart(!empty($modSettings['enableCompressedOutput'])); |
||
| 414 | |||
| 415 | // Send the file headers |
||
| 416 | $headers = Headers::instance(); |
||
| 417 | $headers |
||
| 418 | ->header('Pragma', 'no-cache') |
||
| 419 | ->header('Cache-Control', 'no-cache') |
||
| 420 | ->header('Expires', gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT') |
||
| 421 | ->header('Last-Modified', gmdate('D, d M Y H:i:s', time()) . 'GMT') |
||
| 422 | ->header('Accept-Ranges', 'bytes') |
||
| 423 | ->header('Connection', 'close') |
||
| 424 | ->header('Content-Disposition', 'attachment; filename="' . $event['title'] . '.ics"'); |
||
| 425 | if (empty($modSettings['enableCompressedOutput'])) |
||
| 426 | { |
||
| 427 | $headers->header('Content-Length', Util::strlen($filecontents)); |
||
| 428 | } |
||
| 429 | |||
| 430 | // This is a calendar item! |
||
| 431 | |||
| 432 | $headers |
||
| 433 | ->contentType('text/calendar', 'UTF-8') |
||
| 434 | ->sendHeaders(); |
||
| 435 | |||
| 436 | // Chuck out the card. |
||
| 437 | echo $filecontents; |
||
| 438 | |||
| 439 | // Off we pop - lovely! |
||
| 440 | obExit(false); |
||
| 441 | } |
||
| 442 | } |
||
| 443 |