Completed
Push — master ( b3591c...450f84 )
by Michael
14s queued 10s
created

helper_plugin_issuelinks_db::getWebhooks()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 3
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki Plugin issuelinks (Helper Component)
4
 *
5
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6
 * @author  Andreas Gohr <[email protected]>
7
 */
8
9
// must be run within Dokuwiki
10
use dokuwiki\plugin\issuelinks\classes\Issue;
11
12
if(!defined('DOKU_INC')) die();
13
14
class helper_plugin_issuelinks_db extends DokuWiki_Plugin
1 ignored issue
show
Bug introduced by
The type DokuWiki_Plugin was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
{
16
    private $db = null;
17
18
    /**
19
     * Gives access to the sqlite DB.
20
     *
21
     * Returns null on error
22
     *
23
     * @return helper_plugin_sqlite|null
1 ignored issue
show
Bug introduced by
The type helper_plugin_sqlite was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
     * @throws Exception Only thrown in unittests
25
     */
26
    public function getDB() {
27
        if(null === $this->db) {
28
            /** @var helper_plugin_sqlite $sqlite */
29
            $sqlite = plugin_load('helper', 'sqlite');
1 ignored issue
show
Bug introduced by
The function plugin_load was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

29
            $sqlite = /** @scrutinizer ignore-call */ plugin_load('helper', 'sqlite');
Loading history...
30
            if(!$sqlite) {
0 ignored issues
show
introduced by
$sqlite is of type helper_plugin_sqlite, thus it always evaluated to true.
Loading history...
31
                msg('This plugin requires the sqlite plugin. Please install it', -1);
1 ignored issue
show
Bug introduced by
The function msg was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

31
                /** @scrutinizer ignore-call */ 
32
                msg('This plugin requires the sqlite plugin. Please install it', -1);
Loading history...
32
                return null;
33
            }
34
35
            if($sqlite->getAdapter()->getName() !== DOKU_EXT_PDO) {
1 ignored issue
show
Bug introduced by
The constant DOKU_EXT_PDO was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
36
                if(defined('DOKU_UNITTEST')) throw new \Exception('Couldn\'t load PDO sqlite.');
37
                return null;
38
            }
39
            $sqlite->getAdapter()->setUseNativeAlter(true);
40
41
            // initialize the database connection
42
            if(!$sqlite->init('issuelinks', DOKU_PLUGIN . 'issuelinks/db/')) {
1 ignored issue
show
Bug introduced by
The constant DOKU_PLUGIN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
43
                return null;
44
            }
45
46
            $this->db = $sqlite;
47
        }
48
        return $this->db;
49
    }
50
51
52
53
    /**
54
     * Save a key value pair to the database
55
     *
56
     * @param $key
57
     * @param $value
58
     * @return bool|null Returns false on error, nothing otherwise
59
     */
60
    public function saveKeyValuePair($key, $value) {
61
        $db = $this->getDB();
62
        if(!$db) return false;
63
        $sql = 'REPLACE INTO opts VALUES (?, ?)';
64
        $db->query($sql, array($key, $value));
65
    }
66
67
    /**
68
     * Get a value to a stored key from the database
69
     *
70
     * @param $key
71
     * @return bool|string
72
     */
73
    public function getKeyValue($key) {
74
        $db = $this->getDB();
75
        if(!$db) return false;
76
        $sql = 'SELECT val FROM opts WHERE opt = ?';
77
        $res = $db->query($sql, array($key));
78
        $value = $db->res2single($res);
79
        $db->res_close($res);
80
        return $value;
81
    }
82
83
84
    /**
85
     * @param string $service   The name of the repository management service
86
     * @param string $repo      The repository
87
     * @param string $id        The id of the webhook
88
     * @param string $secret    The secret to use when authenicationg incoming webhooks
89
     */
90
    public function saveWebhook($service, $repo, $id, $secret) {
91
        $entity = array(
92
            'service' => $service,
93
            'repository_id' => $repo,
94
            'id' => $id,
95
            'secret' => $secret
96
        );
97
        $this->saveEntity('webhooks', $entity);
98
    }
99
100
    /**
101
     * Get the stored secret used to authenticate an incoming webhook
102
     *
103
     * @param string $rmservice
104
     * @param string $repo
105
     * @return array
106
     */
107
    public function getWebhookSecrets($service, $repo) {
108
        $sql = "SELECT secret FROM webhooks WHERE service = ? AND repository_id = ?";
109
        $secrets = $this->sqlArrayQuery($sql, array($service, $repo));
110
        return $secrets;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $secrets also could return the type boolean which is incompatible with the documented return type array.
Loading history...
111
    }
112
113
    /**
114
     * @param string $service
115
     * @param string $repo
116
     * @param string $id
117
     */
118
    public function deleteWebhook($service, $repo, $id) {
119
        $entity = array(
120
            'service' => $service,
121
            'repository_id' => $repo,
122
            'id' => $id
123
        );
124
        $this->deleteEntity('webhooks', $entity);
125
    }
126
127
    public function getWebhooks($service, $repo = null, $id = null)
128
    {
129
        $sql = 'SELECT * FROM webhooks WHERE service = ?';
130
        $params = [$service];
131
        if ($repo) {
132
            $sql .= ' AND repository_id = ?';
133
            $params[] = $repo;
134
        }
135
        if ($id) {
136
            $sql .= ' AND id = ?';
137
            $params[] = $id;
138
        }
139
140
        $webhooks = $this->sqlArrayQuery($sql, $params);
141
        return $webhooks;
142
    }
143
144
145
    /**
146
     * Save an issue into the database
147
     *
148
     * @param Issue $issue
149
     * @return bool
150
     */
151
    public function saveIssue(Issue $issue) {
152
        $ok = $this->saveEntity('issues', array (
153
            'service' => $issue->getServiceName(),
154
            'project' => $issue->getProject(),
155
            'id' => $issue->getKey(),
156
            'is_mergerequest' => $issue->isMergeRequest() ? '1' : '0',
157
            'summary' => $issue->getSummary(),
158
            'description' => $issue->getDescription(),
159
            'type' => $issue->getType(),
160
            'status' => $issue->getStatus(),
161
            'parent' => $issue->getParent(),
162
            'components' => implode(',',$issue->getComponents()),
163
            'labels' => implode(',', $issue->getLabels()),
164
            'priority' => $issue->getPriority(),
165
            'duedate' => $issue->getDuedate(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $issue->getDuedate() targeting dokuwiki\plugin\issuelin...ses\Issue::getDuedate() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
166
            'versions' => implode(',', $issue->getVersions()),
167
            'updated' => $issue->getUpdated()
0 ignored issues
show
Bug introduced by
Are you sure the usage of $issue->getUpdated() targeting dokuwiki\plugin\issuelin...ses\Issue::getUpdated() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
168
        ));
169
        return (bool)$ok;
170
    }
171
172
173
    /**
174
     * Query the database for the issue corresponding to the given project and issueId
175
     *
176
     * @param string $serviceName The name of the project management service
177
     * @param string $projectKey  The short-key of a project, e.g. SPR
178
     * @param int    $issueId     The id of an issue e.g. 42
179
     *
180
     * @return bool|array
181
     */
182
    public function loadIssue($serviceName, $projectKey, $issueId, $isMergeRequest) {
183
        $sql = 'SELECT * FROM issues WHERE service = ? AND project = ? AND id = ? AND is_mergerequest = ?';
184
        $issues = $this->sqlArrayQuery($sql, array($serviceName, $projectKey, $issueId, $isMergeRequest ? 1 : 0));
185
        return blank($issues[0]) ? false : $issues[0];
1 ignored issue
show
Bug introduced by
The function blank was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

185
        return /** @scrutinizer ignore-call */ blank($issues[0]) ? false : $issues[0];
Loading history...
186
    }
187
188
    public function saveIssueIssues(Issue $issue, array $issues) {
189
        $this->deleteEntity('issue_issues', array(
190
            'service' => $issue->getServiceName(),
191
            'project' => $issue->getProject(),
192
            'id' => $issue->getKey(),
193
            'is_mergerequest' => $issue->isMergeRequest() ? 1 : 0,
194
        ));
195
        foreach ($issues as $issueData) {
196
            $this->saveEntity('issue_issues', array(
197
                'service' => $issue->getServiceName(),
198
                'project' => $issue->getProject(),
199
                'id' => $issue->getKey(),
200
                'is_mergerequest' => $issue->isMergeRequest() ? 1 : 0,
201
                'referenced_service' => $issueData['service'],
202
                'referenced_project' => $issueData['project'],
203
                'referenced_id' => $issueData['issueId'],
204
                'referenced_is_mergerequest' => 0,
205
            ));
206
        }
207
    }
208
209
    public function getMergeRequestsReferencingIssue($serviceName, $project, $issueId, $isMergeRequest) {
210
        $sql = '
211
        SELECT service, project as project_id, id as issue_id, is_mergerequest
212
        FROM issue_issues
213
        WHERE referenced_service = ?
214
        AND referenced_project = ?
215
        AND referenced_id = ?
216
        AND referenced_is_mergerequest = ?
217
        AND is_mergerequest = 1
218
        ';
219
        return $this->sqlArrayQuery($sql, array($serviceName, $project, $issueId, $isMergeRequest ? 1 : 0));
220
    }
221
222
    /**
223
     * Query the database for pages with link-syntax to the given issue
224
     *
225
     * @param string $serviceName The name of the project management service
226
     * @param string $projectKey  The project short-key
227
     * @param int    $issue_id    The ID of the issue, e.g. 42
228
     *
229
     * @return array
230
     */
231
    public function getAllPageLinkingToIssue($serviceName, $projectKey, $issue_id, $isMergeRequest) {
232
        $sql = "SELECT page, rev
233
                FROM pagerev_issues
234
                WHERE service = ?
235
                AND project_id = ?
236
                AND issue_id = ?
237
                AND is_mergerequest = ?
238
                AND type = 'link'
239
                ORDER BY rev DESC ";
240
        return $this->sqlArrayQuery($sql, array($serviceName, $projectKey, $issue_id, $isMergeRequest ? 1 : 0));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->sqlArrayQu...sMergeRequest ? 1 : 0)) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
241
    }
242
243
    /**
244
     * Delete "Link"-references to old revisions from database
245
     *
246
     * @param string $serviceName The name of the project management service
247
     * @param string $projectKey  The short-key for the project, e.g. SPR
248
     * @param int    $issue_id    The id of the issue, e.g. 42
249
     * @param array  $pages
250
     *
251
     * @return array
252
     */
253
    public function removeOldLinks($serviceName, $projectKey, $issue_id, $isMergeRequest, $pages) {
254
        $activeLinks = array();
255
256
        foreach($pages as $linkingPage) {
257
            $changelog = new PageChangelog($linkingPage['page']);
1 ignored issue
show
Bug introduced by
The type PageChangelog was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
258
            $currentRev = $changelog->getRelativeRevision(time(), -1);
259
            if($linkingPage['rev'] < $currentRev) {
260
                $entity = array(
261
                    'page'     => $linkingPage['page'],
262
                    'issue_id' => $issue_id,
263
                    'project_id' => $projectKey,
264
                    'service' => $serviceName,
265
                    'is_mergerequest' => $isMergeRequest ? '1' : '0',
266
                    'type'     => 'link',
267
                );
268
                $this->deleteEntity('pagerev_issues', $entity);
269
            } else {
270
                $activeLinks[] = $linkingPage;
271
            }
272
        }
273
        return $activeLinks;
274
    }
275
276
    /**
277
     * Save the connection between a Jira issue and a revision of a page.
278
     *
279
     * @param string $page
280
     * @param int    $rev
281
     * @param string $serviceName The name of the project management service
282
     * @param string $project
283
     * @param int    $issue_id
284
     * @param string $type
285
     *
286
     * @return bool
287
     *
288
     * @throws \InvalidArgumentException
289
     */
290
    public function savePageRevIssues($page, $rev, $serviceName, $project, $issue_id, $isMergeRequest, $type) {
291
        /** @var helper_plugin_issuelinks_util $util */
292
        $util = plugin_load('helper', 'issuelinks_util');
1 ignored issue
show
Bug introduced by
The function plugin_load was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

292
        $util = /** @scrutinizer ignore-call */ plugin_load('helper', 'issuelinks_util');
Loading history...
293
        if (!$util->isValidTimeStamp($rev)) {
294
            throw new InvalidArgumentException("Second parameter must be a valid timestamp!");
295
        }
296
        if ((int)$rev === 0) {
297
            $rev = filemtime(wikiFN($page));
1 ignored issue
show
Bug introduced by
The function wikiFN was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

297
            $rev = filemtime(/** @scrutinizer ignore-call */ wikiFN($page));
Loading history...
298
            $changelog = new PageChangelog($page);
299
            $rev_info = $changelog->getRevisionInfo($rev);
300
            $user = $rev_info['user'] ? $rev_info['user'] : $rev_info['ip'];
301
            $this->savePageRev($page, $rev, $rev_info['sum'], $user);
302
        }
303
        /** @noinspection TypeUnsafeComparisonInspection this is done to ensure $issue_id is a natural number */
304
        if (!is_numeric($issue_id) || (int)$issue_id != $issue_id) {
0 ignored issues
show
introduced by
The condition is_numeric($issue_id) is always true.
Loading history...
305
            throw new InvalidArgumentException("IssueId must be an integer!");
306
        }
307
        $ok = $this->saveEntity('pagerev_issues', array (
308
            'page' => $page,
309
            'rev' => $rev,
310
            'service' => $serviceName,
311
            'project_id' => $project,
312
            'issue_id' => $issue_id,
313
            'is_mergerequest' => $isMergeRequest ? '1' : '0',
314
            'type' => $type
315
        ));
316
317
        return (bool)$ok;
318
    }
319
320
    /**
321
     * Save the data about a pagerevision
322
     *
323
     * @param string $page
324
     * @param int    $rev
325
     * @param string $summary
326
     * @param string $user
327
     * @return bool
328
     */
329
    public function savePageRev($page, $rev, $summary, $user) {
330
        if (blank($page) || blank($rev) || blank($user)) {
1 ignored issue
show
Bug introduced by
The function blank was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

330
        if (/** @scrutinizer ignore-call */ blank($page) || blank($rev) || blank($user)) {
Loading history...
331
            throw new InvalidArgumentException("No empty values allowed!");
332
        }
333
        /** @var helper_plugin_issuelinks_util $util */
334
        $util = plugin_load('helper', 'issuelinks_util');
1 ignored issue
show
Bug introduced by
The function plugin_load was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

334
        $util = /** @scrutinizer ignore-call */ plugin_load('helper', 'issuelinks_util');
Loading history...
335
        if (!$util->isValidTimeStamp($rev)) {
336
            throw new InvalidArgumentException("Second parameter must be a valid timestamp!");
337
        }
338
        $ok = $this->saveEntity('pagerevs', array (
339
            'page' => $page,
340
            'rev' => $rev,
341
            'summary' => $summary,
342
            'user' => $user,
343
        ));
344
        return (bool)$ok;
345
    }
346
347
    /**
348
     * Delete ALL entries from the database that correspond to the given page, issue and type.
349
     *
350
     * @param string $page        the wikipage
351
     * @param string $serviceName The name of the project management service
352
     * @param string $projectKey  the key of the project, e.g. SPR
353
     * @param int    $issueId     the id of the issue, e.g. 42
354
     * @param bool   $isMergeRequest
355
     * @param string $type        either 'context' or 'link'
356
     */
357
    public function deleteAllIssuePageRevisions($page, $serviceName, $projectKey, $issueId, $isMergeRequest, $type) {
358
        // todo: validation
359
        $this->deleteEntity('pagerev_issues', array(
360
            'page' => $page,
361
            'service' => $serviceName,
362
            'project_id' => $projectKey,
363
            'issue_id' => $issueId,
364
            'is_mergerequest' => $isMergeRequest ? 1 : 0,
365
            'type' => $type
366
        ));
367
    }
368
369
    /**
370
     * Deletes the given key-value array to the given table
371
     *
372
     * @param string $table
373
     * @param array $entity associative array holding the key/value pairs for the where clause
374
     */
375
    private function deleteEntity($table, $entity) {
376
        $db = $this->getDB();
377
        if(!$db) return;
378
379
        $where = implode(' = ? AND ', array_keys($entity)) . ' = ?';
380
        $vals = array_values($entity);
381
382
        $sql = "DELETE FROM $table WHERE $where";
383
        $db->query($sql, $vals);
384
    }
385
386
    /**
387
     * Saves the given key-value array to the given table
388
     *
389
     * @param string $table
390
     * @param array $entity associative array holding the key/value pairs
391
     * @return bool|\SQLiteResult
392
     */
393
    private function saveEntity($table, $entity) {
394
        $db = $this->getDB();
395
        if(!$db) return false;
396
397
        $keys = implode(', ', array_keys($entity));
398
        $vals = array_values($entity);
399
        $wlds = implode(', ', array_fill(0, count($vals), '?'));
400
401
        $sql = "REPLACE INTO $table ($keys) VALUES ($wlds)";
402
        $ok = $db->query($sql, $vals);
403
        if (empty($ok)) {
404
            global $conf;
405
            msg("Saving into table $table failed!", -1);
1 ignored issue
show
Bug introduced by
The function msg was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

405
            /** @scrutinizer ignore-call */ 
406
            msg("Saving into table $table failed!", -1);
Loading history...
406
            msg(print_r($entity, true), -1);
407
            if ($conf['debug']) {
408
                msg(dbg_backtrace(), -1);
1 ignored issue
show
Bug introduced by
The function dbg_backtrace was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

408
                msg(/** @scrutinizer ignore-call */ dbg_backtrace(), -1);
Loading history...
409
            }
410
        }
411
        return $ok;
412
    }
413
414
    /**
415
     * make a provided sql query and return the resulting lines as an array of associative arrays
416
     *
417
     * @param string        $sql          the query
418
     * @param string|array  $conditional  the parameters of the query
419
     *
420
     * @return array|bool
421
     */
422
    private function sqlArrayQuery($sql, $conditional) {
423
        if (substr(trim($sql),0,strlen('SELECT')) !== 'SELECT') {
424
            throw new InvalidArgumentException("SQL-Statement must be a SELECT statement! \n" . $sql);
425
        }
426
        if (strpos(trim($sql,';'), ';') !== false) {
427
            throw new InvalidArgumentException("SQL-Statement must be one single statement! \n" . $sql);
428
        }
429
        $db = $this->getDB();
430
        if(!$db) return false;
431
432
        $res = $db->query($sql,$conditional);
433
        $result = $db->res2arr($res);
434
        $db->res_close($res);
435
        return $result;
436
    }
437
438
}
439