Completed
Push — master ( 4ffd57...6a646c )
by Michael
02:30
created

action_plugin_issuelinks_ajax::repoAdminOrg()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 27
rs 8.439
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
    public function __construct()
19
    {
20
        /** @var helper_plugin_issuelinks_util util */
21
        $this->util = plugin_load('helper', 'issuelinks_util');
22
    }
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
    public function register(Doku_Event_Handler $controller)
32
    {
33
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
34
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repoAdminToggle');
35
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repoAdminOrg');
36
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'asyncImportAllIssues');
37
    }
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
        $html .= '<div><ul>';
139
        usort($repos, function ($repo1, $repo2) {
140
            return $repo1->displayName < $repo2->displayName ? -1 : 1;
141
        });
142
        $importSVG = inlineSVG(__DIR__ . '/../images/import.svg');
143
        foreach ($repos as $repo) {
144
            $stateIssue = empty($repo->hookID) ? 'inactive' : 'active';
145
            if ($repo->error === 403) {
146
                $stateIssue = 'forbidden';
147
            } elseif (!empty($repo->error)) {
148
                continue;
149
            }
150
            $repoDisplayName = $repo->displayName;
151
            $project = $repo->full_name;
152
            $hookTitle = $repo->error === 403 ? $this->getLang('title:forbidden') : $this->getLang('title:issue hook');
153
            $html .= "<li><div class='li'>";
154
            $spanAttributes = [
155
                'title' => $hookTitle,
156
                'data-project' => $project,
157
                'data-id' => $repo->hookID,
158
                'class' => "repohookstatus $stateIssue issue",
159
            ];
160
            $html .= '<span ' . buildAttributes($spanAttributes, true) . '></span>';
161
            $buttonAttributes = [
162
                'title' => 'Import all issues of this repository',
163
                'data-project' => $project,
164
                'class' => 'issueImport js-importIssues',
165
            ];
166
            $html .= '<button ' . buildAttributes($buttonAttributes, true) . ">$importSVG</button>";
167
            $html .= "<span class='mm_reponame'>$repoDisplayName</span>";
168
            $html .= '</div></li>';
169
        }
170
        $html .= '</ul></div></div>';
171
        return $html;
172
    }
173
174
    public function asyncImportAllIssues(Doku_Event $event, $param)
175
    {
176
        if ($event->data !== 'issuelinks_import_all_issues_async') {
177
            return;
178
        }
179
        $event->preventDefault();
180
        $event->stopPropagation();
181
182
        if (!auth_isadmin()) {
183
            $this->util->sendResponse(403, 'Must be Admin');
184
        }
185
        global $INPUT;
186
        $serviceName = $INPUT->str('servicename');
187
        $projectKey = $INPUT->str('project');
188
189
        // fixme check if $serviceName and $projectKey exist
190
        if (empty($serviceName) || empty($projectKey)) {
191
            $this->util->sendResponse(400, 'service or project is missing');
192
        }
193
194
195
        ignore_user_abort('true');
196
        set_time_limit(60 * 20);
197
        ob_start();
198
        $this->util->sendResponse(202, 'Importing  issues...');
199
        header('Connection: close');
200
        header('Content-Length: ' . ob_get_length());
201
        ob_end_flush();
202
        ob_end_flush();
203
        flush();
204
205
        /** @var helper_plugin_issuelinks_data $data */
206
        $data = plugin_load('helper', 'issuelinks_data');
207
        $data->importAllIssues($serviceName, $projectKey);
208
    }
209
210
    /**
211
     * Pass Ajax call to a type
212
     *
213
     * @param Doku_Event $event  event object by reference
214
     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
215
     *                           handler was registered]
216
     *
217
     * @return void
218
     */
219
    public function handleAjax(Doku_Event $event, $param)
220
    {
221
        if ($event->data !== 'plugin_issuelinks') {
222
            return;
223
        }
224
        $event->preventDefault();
225
        $event->stopPropagation();
226
227
        if (empty($_SERVER['REMOTE_USER'])) {
228
            $this->util->sendResponse(401, 'Not logged in!');
229
            return;
230
        }
231
232
        global $INPUT;
233
234
        $action = $INPUT->str('issuelinks-action');
235
        $serviceName = $INPUT->str('issuelinks-service');
236
        $projectKey = $INPUT->str('issuelinks-project');
237
        $issueId = $INPUT->str('issuelinks-issueid');
238
        $isMergeRequest = $INPUT->bool('issuelinks-ismergerequest');
239
240
        switch ($action) {
241
            case 'checkImportStatus':
242
                list($code, $data) = $this->checkImportStatus($serviceName, $projectKey);
243
                break;
244
            case 'issueToolTip':
245
                list($code, $data) = $this->getIssueTooltipHTML($serviceName, $projectKey, $issueId, $isMergeRequest);
246
                break;
247
            case 'getAdditionalIssueData':
248
                list($code, $data) = $this->getAdditionalIssueData(
249
                    $serviceName,
250
                    $projectKey,
251
                    $issueId,
252
                    $isMergeRequest
253
                );
254
                break;
255
            default:
256
                $code = 400;
257
                $data = 'malformed request';
258
        }
259
        $this->util->sendResponse($code, $data);
260
    }
261
262
    protected function checkImportStatus($serviceName, $projectKey)
263
    {
264
        if (!auth_isadmin()) {
265
            return [403, 'Must be Admin'];
266
        }
267
268
        /** @var helper_plugin_issuelinks_data $data */
269
        $data = plugin_load('helper', 'issuelinks_data');
270
        $lockID = $data->getImportLockID($serviceName, $projectKey);
271
        $lockData = $data->getLockContent($lockID);
272
        if ($lockData === false) {
273
            msg('Import not locked ' . $lockID, 2);
274
            return [200, ['status' => 'done']];
275
        }
276
        if (!empty($lockData['status']) && $lockData['status'] === 'done') {
277
            $data->removeLock($lockID);
278
        }
279
280
        return [200, $lockData];
281
    }
282
283
    /**
284
     * @param $pmServiceName
285
     * @param $projectKey
286
     * @param $issueId
287
     *
288
     * @return array
289
     */
290
    private function getIssueTooltipHTML($pmServiceName, $projectKey, $issueId, $isMergeRequest)
291
    {
292
        try {
293
            $issue = Issue::getInstance($pmServiceName, $projectKey, $issueId, $isMergeRequest);
294
            $issue->getFromDB();
295
        } catch (Exception $e) {
296
            return [400, $e->getMessage()];
297
        }
298
        if (!$issue->isValid()) {
299
            return [404, ''];
300
        }
301
302
        return [200, $issue->buildTooltipHTML()];
303
    }
304
305
    private function getAdditionalIssueData($pmServiceName, $projectKey, $issueId, $isMergeRequest)
306
    {
307
        try {
308
            $issue = Issue::getInstance($pmServiceName, $projectKey, $issueId, $isMergeRequest);
309
            $issue->getFromDB();
310
        } catch (Exception $e) {
311
            return [400, $e->getMessage()];
312
        }
313
        if (!$issue->isValid()) {
314
            return [404, ''];
315
        }
316
317
        return [200, $issue->getAdditionalDataHTML()];
318
    }
319
}
320