Passed
Push — master ( 450f84...6bf8e2 )
by Michael
05:14
created

action_plugin_issuelinks_ajax   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 274
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 274
rs 8.2608
wmc 40

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A register() 0 5 1
B repo_admin_toggle() 0 35 5
C createOrgRepoHTML() 0 30 8
B repo_admin_org() 0 26 5
B asyncImportAllIssues() 0 33 5
A getIssueTooltipHTML() 0 12 2
A getAdditionalIssueData() 0 11 2
B checkImportStatus() 0 18 5
B handle_ajax() 0 33 6

How to fix   Complexity   

Complex Class

Complex classes like action_plugin_issuelinks_ajax often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use action_plugin_issuelinks_ajax, and based on these observations, apply Extract Interface, too.

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
if (!defined('DOKU_INC')) die();
10
11
use dokuwiki\plugin\issuelinks\classes\Issue;
12
use dokuwiki\plugin\issuelinks\classes\ServiceProvider;
13
14
class action_plugin_issuelinks_ajax extends DokuWiki_Action_Plugin {
15
16
    /** @var helper_plugin_issuelinks_util util */
17
    public $util;
18
19
    public function __construct() {
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
     * @return void
29
     */
30
    public function register(Doku_Event_Handler $controller) {
31
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax');
32
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repo_admin_toggle');
33
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'repo_admin_org');
34
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'asyncImportAllIssues');
35
    }
36
37
    /**
38
     * Create/Delete the webhook of a repository
39
     *
40
     * @param Doku_Event $event event object by reference
41
     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
42
     *                           handler was registered]
43
     *
44
     * @return void
45
     */
46
    public function repo_admin_toggle(Doku_Event $event, $param) {
47
        if ($event->data !== 'issuelinks_repo_admin_toggle') {
48
            return;
49
        }
50
        $event->preventDefault();
51
        $event->stopPropagation();
52
53
        if (empty($_SERVER['REMOTE_USER'])) {
54
            $this->util->sendResponse(401, 'Not logged in!');
55
            return;
56
        }
57
58
        global $INPUT, $INFO;
59
        if (!auth_isadmin()) {
60
            $this->util->sendResponse(403, 'Must be Admin');
61
            return;
62
        }
63
64
        $serviceId = $INPUT->str('servicename');
65
66
        $serviceProvider = ServiceProvider::getInstance();
67
        $services = $serviceProvider->getServices();
68
        $service = $services[$serviceId]::getInstance();
69
70
        $project = $INPUT->str('project');
71
72
        if ($INPUT->has('hookid')) {
73
            $response = $service->deleteWebhook($project, $INPUT->str('hookid'));
74
        } else {
75
            $response = $service->createWebhook($project);
76
        }
77
78
        // jira: https://developer.atlassian.com/cloud/jira/platform/webhooks/#registering-a-webhook-via-the-jira-rest-api
79
80
        $this->util->sendResponse($response['status'], $response['data']);
81
    }
82
83
    /**
84
     * Get the repos of an organisation and create HTML from them and return it to the request
85
     *
86
     * @param Doku_Event $event event object by reference
87
     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
88
     *                           handler was registered]
89
     * @return void
90
     */
91
    public function repo_admin_org(Doku_Event $event, $param) {
92
        if ($event->data !== 'issuelinks_repo_admin_getorg') {
93
            return;
94
        }
95
        $event->preventDefault();
96
        $event->stopPropagation();
97
98
        if (empty($_SERVER['REMOTE_USER'])) {
99
            $this->util->sendResponse(401, 'Not logged in!');
100
            return;
101
        }
102
103
        global $INPUT;
104
        if (!auth_isadmin()) {
105
            $this->util->sendResponse(403, 'Must be Admin');
106
            return;
107
        }
108
109
        $serviceId = $INPUT->str('servicename');
110
        $organisation = $INPUT->str('org');
111
        try {
112
            $html = $this->createOrgRepoHTML($serviceId, $organisation);
113
        } catch (\Throwable $e) {
114
            $this->util->sendResponse($e->getCode(), $e->getMessage());
115
        }
116
        $this->util->sendResponse(200, $html);
117
    }
118
119
    /**
120
     * Create the HTML of the repositories of an organisation/group of a service.
121
     *
122
     * @param string $org the organisation from which to request the repositories
123
     * @return string
124
     */
125
    public function createOrgRepoHTML($serviceId, $org) {
126
        $serviceProvider = ServiceProvider::getInstance();
127
        $services = $serviceProvider->getServices();
128
        $service = $services[$serviceId]::getInstance();
129
130
        $repos = $service->getListOfAllReposAndHooks($org);
131
        $html = '<div class="org_repos">';
132
        $html .= '<p>Below are the repositories of the organisation to which the authorized user has access to. Click on the icon to create/delete the webhook.</p>';
133
        $html .= '<div><ul>';
134
        usort($repos, function ($repo1, $repo2) {return $repo1->displayName < $repo2->displayName ? -1 : 1;});
135
        foreach ($repos as $repo) {
136
            $stateIssue = empty($repo->hookID) ? 'inactive' : 'active';
137
            if ($repo->error === 403) {
138
                $stateIssue = 'forbidden';
139
            } elseif (!empty($repo->error)) {
140
                continue;
141
            }
142
            $repoDisplayName = $repo->displayName;
143
            $project = $repo->full_name;
144
            $issueHookID = empty($repo->hookID) ? '' : "data-id='$repo->hookID'";
145
            $issueHookTitle = $repo->error === 403 ? 'The associated account has insufficient rights for this action' : 'Toggle the hook for issue-events';
146
            $html .= "<li><div class='li'>";
147
            $html .= "<span title='$issueHookTitle' data-project='$project' $issueHookID class='repohookstatus $stateIssue issue'></span>";
148
            $importSVG = inlineSVG(__DIR__ . '/../images/import.svg');
149
            $html .= "<button title='Import all issues of this repository' data-project='$project' class='issueImport js-importIssues'>$importSVG</button>";
150
            $html .= "<span class='mm_reponame'>$repoDisplayName</span>";
151
            $html .= '</div></li>';
152
        }
153
        $html .= '</ul></div></div>';
154
        return $html;
155
    }
156
157
    public function asyncImportAllIssues(Doku_Event $event, $param) {
158
        if ($event->data !== 'issuelinks_import_all_issues_async') {
159
            return;
160
        }
161
        $event->preventDefault();
162
        $event->stopPropagation();
163
164
        if (!auth_isadmin()) {
165
            $this->util->sendResponse(403, 'Must be Admin');
166
        }
167
        global $INPUT;
168
        $serviceName = $INPUT->str('servicename');
169
        $projectKey = $INPUT->str('project');
170
171
        // fixme check if $serviceName and $projectKey exist
172
        if (empty($serviceName) || empty($projectKey)) {
173
            $this->util->sendResponse(400, 'service or project is missing');
174
        }
175
176
177
        ignore_user_abort(true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string 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

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