1<?php
2/*
3 * Yurii's Gantt Plugin
4 *
5 * Copyright (C) 2020 Yurii K.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program.  If not, see http://www.gnu.org/licenses
19 */
20
21namespace dokuwiki\plugin\yuriigantt\src;
22
23use dokuwiki\plugin\yuriigantt\src\Driver\DriverInterface;
24use dokuwiki\plugin\yuriigantt\src\Entities\Link;
25use dokuwiki\plugin\yuriigantt\src\Entities\Task;
26
27
28
29class JsonRequest
30{
31    const PERMISSIONS = AUTH_EDIT | AUTH_UPLOAD | AUTH_ADMIN;
32
33    const ACTION_UPDATE = 'update';
34    const ACTION_DELETE = 'delete';
35    const ACTION_CREATE = 'create';
36    const ENTITY_TASK = 'task';
37    const ENTITY_LINK = 'link';
38
39    protected $payload;
40    protected $driver;
41    protected $csrf;
42
43
44    /**
45     * JsonRequest constructor.
46     * @param DriverInterface $driver
47     * @param string|null $csrf
48     * @param string|null $payload
49     */
50    public function __construct(DriverInterface $driver, $csrf, $payload)
51    {
52        $this->csrf = $csrf;
53        $this->driver = $driver;
54        $this->payload = json_decode($payload);
55    }
56
57
58    protected function checkCSRF(&$error)
59    {
60        if ($this->csrf !== getSecurityToken()) {
61            $error = $this->error("Invalid CSRF token {$this->csrf}");
62            return false;
63        }
64
65        return true;
66    }
67
68
69    public function handle()
70    {
71        if (!$this->checkCSRF($error)) {
72            return json_encode($error);
73        }
74
75        if (!$this->validate($error)) {
76            return json_encode($error);
77        }
78
79        $this->driver->open($this->payload->pageId);
80
81        switch ($this->payload->action) {
82            case self::ACTION_CREATE:
83                if ($this->payload->entity === self::ENTITY_TASK) {
84                    $task = $this->driver->addTask(new Task($this->payload->data));
85                    $responseData = ['action' => 'inserted', 'tid' => $task->id];
86                } elseif ($this->payload->entity === self::ENTITY_LINK) {
87                    $link = $this->driver->addLink(new Link($this->payload->data));
88                    $responseData = ['action' => 'inserted', 'tid' => $link->id];
89                }
90                break;
91
92            case self::ACTION_DELETE:
93                if ($this->payload->entity === self::ENTITY_TASK) {
94                    $this->driver->deleteTask($this->payload->id);
95                    $responseData = ['action' => 'deleted'];
96                } elseif ($this->payload->entity === self::ENTITY_LINK) {
97                    $this->driver->deleteLink($this->payload->id);
98                    $responseData = ['action' => 'deleted'];
99                }
100                break;
101
102            case self::ACTION_UPDATE:
103                if ($this->payload->entity === self::ENTITY_TASK) {
104                    $this->driver->updateTask(new Task($this->payload->data));
105                    $responseData = ['action' => 'updated'];
106                } elseif ($this->payload->entity === self::ENTITY_LINK) {
107                    $this->driver->updateLink(new Link($this->payload->data));
108                    $responseData = ['action' => 'updated'];
109                }
110                break;
111
112            default:
113                $responseData = $this->error('Unknown action');
114                break;
115        }
116
117        return json_encode($responseData);
118    }
119
120
121    protected function validate(&$error)
122    {
123        if (!$this->payload) {
124            $error = $this->error('no payload');
125            return false;
126        }
127
128        if (empty($this->payload->action) || !in_array($this->payload->action, [self::ACTION_UPDATE, self::ACTION_CREATE, self::ACTION_DELETE])) {
129            $error = $this->error('this action is not supported');
130            return false;
131        }
132
133        if (empty($this->payload->action) || !in_array($this->payload->action, [self::ACTION_UPDATE, self::ACTION_CREATE, self::ACTION_DELETE])) {
134            $error = $this->error('this action is not supported');
135            return false;
136        }
137
138        if (empty($this->payload->pageId) || !page_exists($this->payload->pageId)) {
139            $error = $this->error('invalid pageId');
140            return false;
141        }
142
143        if (!(auth_quickaclcheck(cleanID($this->payload->pageId)) & self::PERMISSIONS)) {
144            $error = $this->error('you don\'t have permissions');
145            return false;
146        }
147
148        return true;
149    }
150
151
152    protected function error($msg)
153    {
154        return ['action' => 'error', 'msg' => $msg];
155    }
156
157
158}
159