action_plugin_issuelinks_ajax::handleAjax()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 41
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 31
nc 6
nop 2
dl 0
loc 41
ccs 0
cts 30
cp 0
crap 42
rs 8.8017
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki Plugin Issuelinks (Action Component)
4
 *
5
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6
 * @author  Michael Große <[email protected]>
7
 */
8
9
use dokuwiki\plugin\issuelinks\classes\Issue;
10
use dokuwiki\plugin\issuelinks\classes\ServiceProvider;
11
12
class action_plugin_issuelinks_ajax extends DokuWiki_Action_Plugin
13
{
14
15
    /** @var helper_plugin_issuelinks_util util */
16
    public $util;
17
18 5
    public function __construct()
19
    {
20
        /** @var helper_plugin_issuelinks_util util */
21 5
        $this->util = plugin_load('helper', 'issuelinks_util');
22 5
    }
23
24
    /**
25
     * Registers a callback function for a given event
26
     *
27
     * @param Doku_Event_Handler $controller DokuWiki's event controller object
28
     *
29
     * @return void
30
     */
31 5
    public function register(Doku_Event_Handler $controller)
32
    {
33 5
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
34 5
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repoAdminToggle');
35 5
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repoAdminOrg');
36 5
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'asyncImportAllIssues');
37 5
    }
38
39
    /**
40
     * Create/Delete the webhook of a repository
41
     *
42
     * @param Doku_Event $event  event object by reference
43
     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
44
     *                           handler was registered]
45
     *
46
     * @return void
47
     */
48
    public function repoAdminToggle(Doku_Event $event, $param)
49
    {
50
        if ($event->data !== 'issuelinks_repo_admin_toggle') {
51
            return;
52
        }
53
        $event->preventDefault();
54
        $event->stopPropagation();
55
56
        if (empty($_SERVER['REMOTE_USER'])) {
57
            $this->util->sendResponse(401, 'Not logged in!');
58
            return;
59
        }
60
61
        global $INPUT, $INFO;
62
        if (!auth_isadmin()) {
63
            $this->util->sendResponse(403, 'Must be Admin');
64
            return;
65
        }
66
67
        $serviceId = $INPUT->str('servicename');
68
69
        $serviceProvider = ServiceProvider::getInstance();
70
        $services = $serviceProvider->getServices();
71
        $service = $services[$serviceId]::getInstance();
72
73
        $project = $INPUT->str('project');
74
75
        if ($INPUT->has('hookid')) {
76
            $response = $service->deleteWebhook($project, $INPUT->str('hookid'));
77
        } else {
78
            $response = $service->createWebhook($project);
79
        }
80
81
        $this->util->sendResponse($response['status'], $response['data']);
82
    }
83
84
    /**
85
     * Get the repos of an organisation and create HTML from them and return it to the request
86
     *
87
     * @param Doku_Event $event  event object by reference
88
     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
89
     *                           handler was registered]
90
     *
91
     * @return void
92
     */
93
    public function repoAdminOrg(Doku_Event $event, $param)
94
    {
95
        if ($event->data !== 'issuelinks_repo_admin_getorg') {
96
            return;
97
        }
98
        $event->preventDefault();
99
        $event->stopPropagation();
100
101
        if (empty($_SERVER['REMOTE_USER'])) {
102
            $this->util->sendResponse(401, 'Not logged in!');
103
            return;
104
        }
105
106
        global $INPUT;
107
        if (!auth_isadmin()) {
108
            $this->util->sendResponse(403, 'Must be Admin');
109
            return;
110
        }
111
112
        $serviceId = $INPUT->str('servicename');
113
        $organisation = $INPUT->str('org');
114
        try {
115
            $html = $this->createOrgRepoHTML($serviceId, $organisation);
116
        } catch (\Throwable $e) {
117
            $this->util->sendResponse($e->getCode(), $e->getMessage());
118
        }
119
        $this->util->sendResponse(200, $html);
120
    }
121
122
    /**
123
     * Create the HTML of the repositories of an organisation/group of a service.
124
     *
125
     * @param string $org the organisation from which to request the repositories
126
     *
127
     * @return string
128
     */
129
    public function createOrgRepoHTML($serviceId, $org)
130
    {
131
        $serviceProvider = ServiceProvider::getInstance();
132
        $services = $serviceProvider->getServices();
133
        $service = $services[$serviceId]::getInstance();
134
135
        $repos = $service->getListOfAllReposAndHooks($org);
136
        $html = '<div class="org_repos">';
137
        $html .= '<p>' . $this->getLang('text:repo admin') . '</p>';
138
        $orgAdvice = $service->getRepoPageText();
139
        if ($orgAdvice) {
140
            $html .= '<p>' . $orgAdvice . '</p>';
141
        }
142
        $html .= '<div><ul>';
143
        usort($repos, function ($repo1, $repo2) {
144
            return $repo1->displayName < $repo2->displayName ? -1 : 1;
145
        });
146
        $importSVG = inlineSVG(__DIR__ . '/../images/import.svg');
147
        foreach ($repos as $repo) {
148
            $stateIssue = empty($repo->hookID) ? 'inactive' : 'active';
149
            if ($repo->error === 403) {
150
                $stateIssue = 'forbidden';
151
            } elseif (!empty($repo->error)) {
152
                continue;
153
            }
154
            $repoDisplayName = $repo->displayName;
155
            $project = $repo->full_name;
156
            $hookTitle = $repo->error === 403 ? $this->getLang('title:forbidden') : $this->getLang('title:issue hook');
157
            $html .= "<li><div class='li'>";
158
            $spanAttributes = [
159
                'title' => $hookTitle,
160
                'data-project' => $project,
161
                'data-id' => $repo->hookID,
162
                'class' => "repohookstatus $stateIssue issue",
163
            ];
164
            $html .= '<span ' . buildAttributes($spanAttributes, true) . '></span>';
165
            $buttonAttributes = [
166
                'title' => 'Import all issues of this repository',
167
                'data-project' => $project,
168
                'class' => 'issueImport js-importIssues',
169
            ];
170
            $html .= '<button ' . buildAttributes($buttonAttributes, true) . ">$importSVG</button>";
171
            $html .= "<span class='mm_reponame'>$repoDisplayName</span>";
172
            $html .= '</div></li>';
173
        }
174
        $html .= '</ul></div></div>';
175
        return $html;
176
    }
177
178
    public function asyncImportAllIssues(Doku_Event $event, $param)
179
    {
180
        if ($event->data !== 'issuelinks_import_all_issues_async') {
181
            return;
182
        }
183
        $event->preventDefault();
184
        $event->stopPropagation();
185
186
        if (!auth_isadmin()) {
187
            $this->util->sendResponse(403, 'Must be Admin');
188
        }
189
        global $INPUT;
190
        $serviceName = $INPUT->str('servicename');
191
        $projectKey = $INPUT->str('project');
192
193
        // fixme check if $serviceName and $projectKey exist
194
        if (empty($serviceName) || empty($projectKey)) {
195
            $this->util->sendResponse(400, 'service or project is missing');
196
        }
197
198
199
        ignore_user_abort('true');
0 ignored issues
show
Bug introduced by
'true' of type string is incompatible with the type boolean expected by parameter $value of ignore_user_abort(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

199
        ignore_user_abort(/** @scrutinizer ignore-type */ 'true');
Loading history...
200
        set_time_limit(60 * 20);
201
        ob_start();
202
        $this->util->sendResponse(202, 'Importing  issues...');
203
        header('Connection: close');
204
        header('Content-Length: ' . ob_get_length());
205
        ob_end_flush();
206
        ob_end_flush();
207
        flush();
208
209
        /** @var helper_plugin_issuelinks_data $data */
210
        $data = plugin_load('helper', 'issuelinks_data');
211
        $data->importAllIssues($serviceName, $projectKey);
212
    }
213
214
    /**
215
     * Pass Ajax call to a type
216
     *
217
     * @param Doku_Event $event  event object by reference
218
     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
219
     *                           handler was registered]
220
     *
221
     * @return void
222
     */
223
    public function handleAjax(Doku_Event $event, $param)
224
    {
225
        if ($event->data !== 'plugin_issuelinks') {
226
            return;
227
        }
228
        $event->preventDefault();
229
        $event->stopPropagation();
230
231
        if (empty($_SERVER['REMOTE_USER'])) {
232
            $this->util->sendResponse(401, 'Not logged in!');
233
            return;
234
        }
235
236
        global $INPUT;
237
238
        $action = $INPUT->str('issuelinks-action');
239
        $serviceName = $INPUT->str('issuelinks-service');
240
        $projectKey = $INPUT->str('issuelinks-project');
241
        $issueId = $INPUT->str('issuelinks-issueid');
242
        $isMergeRequest = $INPUT->bool('issuelinks-ismergerequest');
243
244
        switch ($action) {
245
            case 'checkImportStatus':
246
                list($code, $data) = $this->checkImportStatus($serviceName, $projectKey);
247
                break;
248
            case 'issueToolTip':
249
                list($code, $data) = $this->getIssueTooltipHTML($serviceName, $projectKey, $issueId, $isMergeRequest);
250
                break;
251
            case 'getAdditionalIssueData':
252
                list($code, $data) = $this->getAdditionalIssueData(
253
                    $serviceName,
254
                    $projectKey,
255
                    $issueId,
256
                    $isMergeRequest
257
                );
258
                break;
259
            default:
260
                $code = 400;
261
                $data = 'malformed request';
262
        }
263
        $this->util->sendResponse($code, $data);
264
    }
265
266
    protected function checkImportStatus($serviceName, $projectKey)
267
    {
268
        if (!auth_isadmin()) {
269
            return [403, 'Must be Admin'];
270
        }
271
272
        /** @var helper_plugin_issuelinks_data $data */
273
        $data = plugin_load('helper', 'issuelinks_data');
274
        $lockID = $data->getImportLockID($serviceName, $projectKey);
275
        $lockData = $data->getLockContent($lockID);
276
        if ($lockData === false) {
277
            msg('Import not locked ' . $lockID, 2);
278
            return [200, ['status' => 'done']];
279
        }
280
        if (!empty($lockData['status']) && $lockData['status'] === 'done') {
281
            $data->removeLock($lockID);
282
        }
283
284
        return [200, $lockData];
285
    }
286
287
    /**
288
     * @param $pmServiceName
289
     * @param $projectKey
290
     * @param $issueId
291
     *
292
     * @return array
293
     */
294
    private function getIssueTooltipHTML($pmServiceName, $projectKey, $issueId, $isMergeRequest)
295
    {
296
        try {
297
            $issue = Issue::getInstance($pmServiceName, $projectKey, $issueId, $isMergeRequest);
298
            $issue->getFromDB();
299
        } catch (Exception $e) {
300
            return [400, $e->getMessage()];
301
        }
302
        if (!$issue->isValid()) {
303
            return [404, ''];
304
        }
305
306
        return [200, $issue->buildTooltipHTML()];
307
    }
308
309
    private function getAdditionalIssueData($pmServiceName, $projectKey, $issueId, $isMergeRequest)
310
    {
311
        try {
312
            $issue = Issue::getInstance($pmServiceName, $projectKey, $issueId, $isMergeRequest);
313
            $issue->getFromDB();
314
        } catch (Exception $e) {
315
            return [400, $e->getMessage()];
316
        }
317
        if (!$issue->isValid()) {
318
            return [404, ''];
319
        }
320
321
        return [200, $issue->getAdditionalDataHTML()];
322
    }
323
}
324