xref: /plugin/calendar/action.php (revision 19378907f6c3c154fcddd2ddfe78fa2d88d43359)
1<?php
2/**
3 * DokuWiki Plugin calendar (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  DokuWiki Community
7 */
8
9if (!defined('DOKU_INC')) die();
10
11class action_plugin_calendar extends DokuWiki_Action_Plugin {
12
13    public function register(Doku_Event_Handler $controller) {
14        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
15        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'addAssets');
16    }
17
18    public function handleAjax(Doku_Event $event, $param) {
19        if ($event->data !== 'plugin_calendar') return;
20        $event->preventDefault();
21        $event->stopPropagation();
22
23        $action = $_REQUEST['action'] ?? '';
24
25        switch ($action) {
26            case 'save_event':
27                $this->saveEvent();
28                break;
29            case 'delete_event':
30                $this->deleteEvent();
31                break;
32            case 'get_event':
33                $this->getEvent();
34                break;
35            case 'load_month':
36                $this->loadMonth();
37                break;
38            case 'toggle_task':
39                $this->toggleTaskComplete();
40                break;
41            default:
42                echo json_encode(['success' => false, 'error' => 'Unknown action']);
43        }
44    }
45
46    private function saveEvent() {
47        global $INPUT;
48
49        $namespace = $INPUT->str('namespace', '');
50        $date = $INPUT->str('date');
51        $eventId = $INPUT->str('eventId', '');
52        $title = $INPUT->str('title');
53        $time = $INPUT->str('time', '');
54        $description = $INPUT->str('description', '');
55        $color = $INPUT->str('color', '#3498db');
56        $oldDate = $INPUT->str('oldDate', ''); // Track original date for moves
57        $isTask = $INPUT->bool('isTask', false);
58        $completed = $INPUT->bool('completed', false);
59        $endDate = $INPUT->str('endDate', '');
60
61        if (!$date || !$title) {
62            echo json_encode(['success' => false, 'error' => 'Missing required fields']);
63            return;
64        }
65
66        list($year, $month, $day) = explode('-', $date);
67
68        $dataDir = DOKU_INC . 'data/meta/';
69        if ($namespace) {
70            $dataDir .= str_replace(':', '/', $namespace) . '/';
71        }
72        $dataDir .= 'calendar/';
73
74        if (!is_dir($dataDir)) {
75            mkdir($dataDir, 0755, true);
76        }
77
78        $eventFile = $dataDir . sprintf('%04d-%02d.json', $year, $month);
79
80        $events = [];
81        if (file_exists($eventFile)) {
82            $events = json_decode(file_get_contents($eventFile), true);
83        }
84
85        // If editing and date changed, remove from old date first
86        if ($eventId && $oldDate && $oldDate !== $date) {
87            list($oldYear, $oldMonth, $oldDay) = explode('-', $oldDate);
88            $oldEventFile = $dataDir . sprintf('%04d-%02d.json', $oldYear, $oldMonth);
89
90            if (file_exists($oldEventFile)) {
91                $oldEvents = json_decode(file_get_contents($oldEventFile), true);
92                if (isset($oldEvents[$oldDate])) {
93                    $oldEvents[$oldDate] = array_filter($oldEvents[$oldDate], function($evt) use ($eventId) {
94                        return $evt['id'] !== $eventId;
95                    });
96
97                    if (empty($oldEvents[$oldDate])) {
98                        unset($oldEvents[$oldDate]);
99                    }
100
101                    file_put_contents($oldEventFile, json_encode($oldEvents, JSON_PRETTY_PRINT));
102                }
103            }
104        }
105
106        if (!isset($events[$date])) {
107            $events[$date] = [];
108        }
109
110        $eventData = [
111            'id' => $eventId ?: uniqid(),
112            'title' => $title,
113            'time' => $time,
114            'description' => $description,
115            'color' => $color,
116            'isTask' => $isTask,
117            'completed' => $completed,
118            'endDate' => $endDate,
119            'created' => date('Y-m-d H:i:s')
120        ];
121
122        // If editing, replace existing event
123        if ($eventId) {
124            $found = false;
125            foreach ($events[$date] as $key => $evt) {
126                if ($evt['id'] === $eventId) {
127                    $events[$date][$key] = $eventData;
128                    $found = true;
129                    break;
130                }
131            }
132            if (!$found) {
133                $events[$date][] = $eventData;
134            }
135        } else {
136            $events[$date][] = $eventData;
137        }
138
139        file_put_contents($eventFile, json_encode($events, JSON_PRETTY_PRINT));
140
141        echo json_encode(['success' => true, 'events' => $events, 'eventId' => $eventData['id']]);
142    }
143
144    private function deleteEvent() {
145        global $INPUT;
146
147        $namespace = $INPUT->str('namespace', '');
148        $date = $INPUT->str('date');
149        $eventId = $INPUT->str('eventId');
150
151        list($year, $month, $day) = explode('-', $date);
152
153        $dataDir = DOKU_INC . 'data/meta/';
154        if ($namespace) {
155            $dataDir .= str_replace(':', '/', $namespace) . '/';
156        }
157        $dataDir .= 'calendar/';
158
159        $eventFile = $dataDir . sprintf('%04d-%02d.json', $year, $month);
160
161        if (file_exists($eventFile)) {
162            $events = json_decode(file_get_contents($eventFile), true);
163
164            if (isset($events[$date])) {
165                $events[$date] = array_filter($events[$date], function($event) use ($eventId) {
166                    return $event['id'] !== $eventId;
167                });
168
169                if (empty($events[$date])) {
170                    unset($events[$date]);
171                }
172
173                file_put_contents($eventFile, json_encode($events, JSON_PRETTY_PRINT));
174            }
175        }
176
177        echo json_encode(['success' => true]);
178    }
179
180    private function getEvent() {
181        global $INPUT;
182
183        $namespace = $INPUT->str('namespace', '');
184        $date = $INPUT->str('date');
185        $eventId = $INPUT->str('eventId');
186
187        list($year, $month, $day) = explode('-', $date);
188
189        $dataDir = DOKU_INC . 'data/meta/';
190        if ($namespace) {
191            $dataDir .= str_replace(':', '/', $namespace) . '/';
192        }
193        $dataDir .= 'calendar/';
194
195        $eventFile = $dataDir . sprintf('%04d-%02d.json', $year, $month);
196
197        if (file_exists($eventFile)) {
198            $events = json_decode(file_get_contents($eventFile), true);
199
200            if (isset($events[$date])) {
201                foreach ($events[$date] as $event) {
202                    if ($event['id'] === $eventId) {
203                        echo json_encode(['success' => true, 'event' => $event]);
204                        return;
205                    }
206                }
207            }
208        }
209
210        echo json_encode(['success' => false, 'error' => 'Event not found']);
211    }
212
213    private function loadMonth() {
214        global $INPUT;
215
216        $namespace = $INPUT->str('namespace', '');
217        $year = $INPUT->int('year');
218        $month = $INPUT->int('month');
219
220        $dataDir = DOKU_INC . 'data/meta/';
221        if ($namespace) {
222            $dataDir .= str_replace(':', '/', $namespace) . '/';
223        }
224        $dataDir .= 'calendar/';
225
226        $eventFile = $dataDir . sprintf('%04d-%02d.json', $year, $month);
227
228        $events = [];
229        if (file_exists($eventFile)) {
230            $events = json_decode(file_get_contents($eventFile), true);
231        }
232
233        echo json_encode(['success' => true, 'events' => $events, 'year' => $year, 'month' => $month]);
234    }
235
236    private function toggleTaskComplete() {
237        global $INPUT;
238
239        $namespace = $INPUT->str('namespace', '');
240        $date = $INPUT->str('date');
241        $eventId = $INPUT->str('eventId');
242        $completed = $INPUT->bool('completed', false);
243
244        list($year, $month, $day) = explode('-', $date);
245
246        $dataDir = DOKU_INC . 'data/meta/';
247        if ($namespace) {
248            $dataDir .= str_replace(':', '/', $namespace) . '/';
249        }
250        $dataDir .= 'calendar/';
251
252        $eventFile = $dataDir . sprintf('%04d-%02d.json', $year, $month);
253
254        if (file_exists($eventFile)) {
255            $events = json_decode(file_get_contents($eventFile), true);
256
257            if (isset($events[$date])) {
258                foreach ($events[$date] as $key => $event) {
259                    if ($event['id'] === $eventId) {
260                        $events[$date][$key]['completed'] = $completed;
261                        break;
262                    }
263                }
264
265                file_put_contents($eventFile, json_encode($events, JSON_PRETTY_PRINT));
266                echo json_encode(['success' => true, 'events' => $events]);
267                return;
268            }
269        }
270
271        echo json_encode(['success' => false, 'error' => 'Event not found']);
272    }
273
274    public function addAssets(Doku_Event $event, $param) {
275        $event->data['link'][] = array(
276            'type' => 'text/css',
277            'rel' => 'stylesheet',
278            'href' => DOKU_BASE . 'lib/plugins/calendar/style.css'
279        );
280
281        $event->data['script'][] = array(
282            'type' => 'text/javascript',
283            'src' => DOKU_BASE . 'lib/plugins/calendar/script.js'
284        );
285    }
286}
287