GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

indexNewDocmanFolder()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
/**
3
 * Copyright (c) Enalean, 2012 - 2014. All Rights Reserved.
4
 *
5
 * This file is a part of Tuleap.
6
 *
7
 * Tuleap 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 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * Tuleap 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 Tuleap. If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
/**
22
 * Class responsible to send requests to an indexation server
23
 */
24
class FullTextSearchDocmanActions {
25
26
    /**
27
     * @var FullTextSearch_IIndexDocuments
28
     */
29
    private $client;
30
31
    /** @var ElasticSearch_1_2_RequestDocmanDataFactory */
32
    private $request_data_factory;
33
34
    /** @var Logger */
35
    private $logger;
36
37
    /** @var int File size in bytes */
38
    private $max_indexed_file_size;
39
40
    public function __construct(
41
        FullTextSearch_IIndexDocuments $client,
42
        ElasticSearch_1_2_RequestDocmanDataFactory $request_data_factory,
43
        Logger $logger,
44
        $max_indexed_file_size
45
    ) {
46
        $this->client                = $client;
47
        $this->request_data_factory  = $request_data_factory;
48
        $this->logger                = new WrapperLogger($logger, 'Docman');
49
        $this->max_indexed_file_size = $max_indexed_file_size;
50
    }
51
52
    public function checkProjectMappingExists($project_id) {
53
        $this->logger->debug('get the mapping for project #' . $project_id);
54
55
        return count($this->client->getMapping($project_id)) > 0;
56
    }
57
58
    public function initializeProjetMapping($project_id) {
59
        $this->logger->debug('initialize the mapping for project #' . $project_id);
60
61
        $this->client->setMapping(
62
            $project_id,
63
            $this->request_data_factory->getPUTMappingData($project_id)
64
        );
65
    }
66
67
    /**
68
     * Index a new document with permissions
69
     *
70
     * @param Docman_Item    $item    The docman item
71
     * @param Docman_Version $version The version to index
72
     *
73
     * @throws FullTextSearchDocmanIndexFileTooBigException
74
     */
75
    public function indexNewDocument(Docman_Item $item, Docman_Version $version) {
76
        $this->logger->debug('index new document #' . $item->getId());
77
78
        if (filesize($version->getPath()) > $this->max_indexed_file_size) {
79
            throw new FullTextSearchDocmanIndexFileTooBigException($item->getId());
80
        }
81
82
        $indexed_data = $this->getIndexedData($item) + $this->getItemContent($version);
83
84
        $this->client->index($item->getGroupId(), $item->getId(), $indexed_data);
85
    }
86
87
    public function indexNewEmptyDocument(Docman_Item $item) {
88
        $this->logger->debug('index new empty document #' . $item->getId());
89
90
        $indexed_data = $this->getIndexedData($item);
91
92
        $this->client->index($item->getGroupId(), $item->getId(), $indexed_data);
93
    }
94
95
    public function indexNewLinkDocument(Docman_Item $item) {
96
        $this->logger->debug('index new link document #' . $item->getId());
97
98
        $indexed_data = $this->getIndexedData($item) + $this->getLinkContent($item);
99
100
        $this->client->index($item->getGroupId(), $item->getId(), $indexed_data);
101
    }
102
103
    public function indexNewDocmanFolder(Docman_Item $item) {
104
        $this->logger->debug('index new folder #' . $item->getId());
105
106
        $indexed_data = $this->getIndexedData($item);
107
108
        $this->client->index($item->getGroupId(), $item->getId(), $indexed_data);
109
    }
110
111
    /**
112
     * Index a new wiki document with permissions
113
     *
114
     * @param Docman_Item    $item                The docman item
115
     * @param array          $wiki_page_metadata  The wiki page metadata
116
     */
117
    public function indexNewWikiDocument(Docman_Item $item, array $wiki_page_metadata) {
118
        $this->logger->debug('index new docman wiki document #' . $item->getId());
119
120
        $indexed_data = $this->getIndexedData($item) + $this->getWikiContent($wiki_page_metadata);
121
122
        $this->client->index($item->getGroupId(), $item->getId(), $indexed_data);
123
    }
124
125
    public function indexCopiedItem(Docman_Item $item) {
126
        $this->logger->debug('index new copied item #' . $item->getId() . ' and its children');
127
128
        $item_factory = $this->getDocmanItemFactory($item);
129
        $items        = array_merge(array($item), $item_factory->getAllChildrenFromParent($item));
130
131
        foreach($items as $item_to_index) {
132
            $this->logger->debug('index item #' . $item_to_index->getId());
133
134
            $indexed_data = $this->getIndexedData($item_to_index) + $this->getContent($item_to_index);
135
            $this->client->index($item_to_index->getGroupId(), $item_to_index->getId(), $indexed_data);
136
        }
137
    }
138
139
    /**
140
     * @param Docman_Item $item
141
     *
142
     * @return Docman_ItemFactory
143
     */
144
    private function getDocmanItemFactory(Docman_Item $item) {
145
        return Docman_ItemFactory::instance($item->getGroupId());
146
    }
147
148
    private function getContent(Docman_Item $item) {
149
        $item_factory = $this->getDocmanItemFactory($item);
150
        $item_type    = $item_factory->getItemTypeForItem($item);
151
152
        switch ($item_type) {
153
            case PLUGIN_DOCMAN_ITEM_TYPE_EMPTY:
154
            case PLUGIN_DOCMAN_ITEM_TYPE_FOLDER:
155
                return array();
156
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
157
158
            case PLUGIN_DOCMAN_ITEM_TYPE_WIKI:
159
                $wiki_page = new WikiPage($item->getGroupId(), $item->getPagename());
160
161
                return $this->getWikiContent($wiki_page->getMetadata());
162
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
163
164
            case PLUGIN_DOCMAN_ITEM_TYPE_LINK:
165
                return $this->getLinkContent($item);
166
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
167
168
            case PLUGIN_DOCMAN_ITEM_TYPE_EMBEDDEDFILE:
169
            case PLUGIN_DOCMAN_ITEM_TYPE_FILE:
170
                return $this->getItemContent($item->getCurrentVersion());
171
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
172
173
            default:
174
                $this->logger->debug("unrecognized item type, can't index content");
175
176
                return array();
177
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
178
        }
179
    }
180
181
    /**
182
     * Update document approval comments
183
     *
184
     * @param Docman_Item $item
185
     * @param Docman_Version $version
0 ignored issues
show
Bug introduced by
There is no parameter named $version. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
186
     */
187
    public function indexDocumentApprovalComment(Docman_Item $item) {
188
        $this->logger->debug('index new document approval comment #' . $item->getId());
189
190
        $update_data = array(
191
            'approval_table_comments' => $this->request_data_factory->getDocumentApprovalTableComments($item)
192
        );
193
194
        $this->client->update($item->getGroupId(), $item->getId(), $update_data);
195
    }
196
197
    /**
198
     * Index a new document with permissions
199
     *
200
     * @param Docman_Item    $item    The docman item
201
     * @param Docman_Version $version The version to index
202
     *
203
     * @throws FullTextSearchDocmanIndexFileTooBigException
204
     */
205
    public function indexNewVersion(Docman_Item $item, Docman_Version $version) {
206
        try {
207
            $this->client->getIndexedElement($item->getGroupId(), $item->getId());
208
209
            $this->logger->debug('index new version #' . $version->getId() . ' for document #' . $item->getId());
210
211
            $update_data = array();
212
213
            if (filesize($version->getPath()) > $this->max_indexed_file_size) {
214
                throw new FullTextSearchDocmanIndexFileTooBigException($item->getId());
215
            }
216
217
            $this->request_data_factory->updateFile($update_data, $version->getPath());
218
            $this->client->update($item->getGroupId(), $item->getId(), $update_data);
219
220
        } catch (ElasticSearch_ElementNotIndexed $exception) {
221
            $this->indexNewDocument($item, $version);
222
            return;
223
        }
224
    }
225
226
    /**
227
     * Index a new document with permissions
228
     *
229
     * @param Docman_Item    $item    The docman item
230
     * @param Docman_Version $version The version to index
231
     */
232
    public function indexNewLinkVersion(Docman_Item $item, Docman_LinkVersion $version) {
233
        try {
234
            $this->client->getIndexedElement($item->getGroupId(), $item->getId());
235
            $this->logger->debug('index new link version #' . $version->getId() . ' for document #' . $item->getId());
236
            $indexed_data = $this->getIndexedData($item) + $this->getLinkContent($item);
237
            $this->client->update($item->getGroupId(), $item->getId(), $indexed_data);
238
        } catch (ElasticSearch_ElementNotIndexed $exception) {
239
            $this->indexNewLinkDocument($item);
240
            return;
241
        }
242
    }
243
244
    /**
245
     * Index a new wiki document with permissions
246
     *
247
     * @param Docman_Item    $item               The docman item
248
     * @param Docman_Version $version            The version to index
0 ignored issues
show
Bug introduced by
There is no parameter named $version. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
249
     * @param array          $wiki_page_metadata WikiPage metadata
250
     */
251
    public function indexNewWikiVersion(Docman_Item $item, array $wiki_page_metadata) {
252
        try {
253
            $this->client->getIndexedElement($item->getGroupId(), $item->getId());
254
255
            $this->logger->debug('index new version for wiki document #' . $item->getId());
256
257
            $update_data = array();
258
            $this->request_data_factory->updateContent($update_data, $wiki_page_metadata['content']);
259
            $this->client->update($item->getGroupId(), $item->getId(), $update_data);
260
261
        } catch (ElasticSearch_ElementNotIndexed $exception) {
262
            $this->indexNewWikiDocument($item, $wiki_page_metadata);
263
            return;
264
        }
265
    }
266
267
    /**
268
     * Update title, description and custom textual metadata of a document
269
     *
270
     * @param Docman_Item $item The item
271
     * @throws FullTextSearchDocmanIndexFileTooBigException
272
     */
273
    public function updateDocument(Docman_Item $item) {
274
        try {
275
            $this->client->getIndexedElement($item->getGroupId(), $item->getId());
276
277
            $this->logger->debug('update document #' . $item->getId());
278
279
            $update_data = array();
280
            $this->request_data_factory->setUpdatedData($update_data, 'title',       $item->getTitle());
281
            $this->request_data_factory->setUpdatedData($update_data, 'description', $item->getDescription());
282
283
            $this->updateContent($item, $update_data);
284
285
            $update_data = $this->request_data_factory->updateCustomTextualMetadata($item, $update_data);
286
            $update_data = $this->updateCustomDateMetadata($item, $update_data);
287
288
            $this->client->update($item->getGroupId(), $item->getId(), $update_data);
289
290
        } catch (ElasticSearch_ElementNotIndexed $exception) {
291
            $this->indexNonexistantDocument($item);
292
            return;
293
        }
294
    }
295
296
    /**
297
     * @param Docman_Item $item
298
     * @throws FullTextSearchDocmanIndexFileTooBigException
299
     */
300
    private function indexNonexistantDocument(Docman_Item $item) {
301
        $item_factory = $this->getDocmanItemFactory($item);
302
        $item_type    = $item_factory->getItemTypeForItem($item);
303
304
        switch ($item_type) {
305
            case PLUGIN_DOCMAN_ITEM_TYPE_EMPTY:
306
                $this->indexNewEmptyDocument($item);
307
                break;
308
309
            case PLUGIN_DOCMAN_ITEM_TYPE_FOLDER:
310
                $this->indexNewDocmanFolder($item);
311
                break;
312
313
            case PLUGIN_DOCMAN_ITEM_TYPE_WIKI:
314
                $wiki_page = new WikiPage($item->getGroupId(), $item->getPagename());
315
                $this->indexNewWikiDocument($item, $wiki_page->getMetadata());
316
                break;
317
318
            case PLUGIN_DOCMAN_ITEM_TYPE_LINK:
319
                $this->indexNewLinkDocument($item);
320
                break;
321
322
            case PLUGIN_DOCMAN_ITEM_TYPE_EMBEDDEDFILE:
323
            case PLUGIN_DOCMAN_ITEM_TYPE_FILE:
324
                $this->indexNewDocument($item, $item->getCurrentVersion());
325
                break;
326
327
            default:
328
                $this->logger->debug("unrecognized item type, can't index it");
329
                break;
330
        }
331
    }
332
333
    private function updateContent(Docman_Item $item, array &$update_data) {
334
        $item_factory = Docman_ItemFactory::instance($item->getGroupId());
335
        $item_type    = $item_factory->getItemTypeForItem($item);
336
337
        switch ($item_type) {
338
            case PLUGIN_DOCMAN_ITEM_TYPE_EMPTY:
339
                break;
340
341
            case PLUGIN_DOCMAN_ITEM_TYPE_WIKI:
342
                $wiki_page = new WikiPage($item->getGroupId(), $item->getPagename());
343
                $this->request_data_factory->updateContent($update_data, $wiki_page->getContent());
344
                break;
345
346
            case PLUGIN_DOCMAN_ITEM_TYPE_LINK:
347
                $this->request_data_factory->updateContent($update_data, $item->getUrl());
348
                break;
349
350
            case PLUGIN_DOCMAN_ITEM_TYPE_EMBEDDEDFILE:
351
            case PLUGIN_DOCMAN_ITEM_TYPE_FILE:
352
                $this->request_data_factory->updateFile($update_data, $item->getCurrentVersion()->getPath());
353
                break;
354
355
            default:
356
                $this->logger->debug("unrecognized item type, can't update content");
357
                break;
358
        }
359
    }
360
361
    /**
362
     * Index the new permissions of a document
363
     *
364
     * @param Docman_Item the document
365
     * @throws FullTextSearchDocmanIndexFileTooBigException
366
     */
367
    public function updatePermissions(Docman_Item $item) {
368
        $this->logger->debug('update permissions of document #' . $item->getId(). ' and its children');
369
370
        $item_factory = $this->getDocmanItemFactory($item);
371
        $items        = array_merge(array($item), $item_factory->getAllChildrenFromParent($item));
372
373
        foreach($items as $item_to_index) {
374
            try {
375
                $this->client->getIndexedElement($item->getGroupId(), $item->getId());
376
377
                $this->logger->debug('update permissions of item #' . $item_to_index->getId());
378
379
                $update_data = array();
380
                $this->request_data_factory->setUpdatedData(
381
                    $update_data,
382
                    'permissions',
383
                    $this->request_data_factory->getCurrentPermissions($item)
384
                );
385
386
                $this->client->update($item_to_index->getGroupId(), $item_to_index->getId(), $update_data);
387
388
            } catch(ElasticSearch_ElementNotIndexed $exception) {
389
                $this->indexNonexistantDocument($item_to_index);
390
                return;
391
            }
392
        }
393
    }
394
395
    /**
396
     * Remove an indexed document
397
     *
398
     * @param Docman_Item $item The item to delete
399
     */
400
    public function delete(Docman_Item $item) {
401
        $this->logger->debug('delete document #' . $item->getId());
402
403
        try{
404
            $this->client->getIndexedElement($item->getGroupId(), $item->getId());
405
            $this->client->delete($item->getGroupId(), $item->getId());
406
407
        } catch (ElasticSearch_ElementNotIndexed $exception) {
408
            $this->logger->debug('element #' . $item->getId() . ' not indexed, nothing to delete');
409
            return;
410
        }
411
412
    }
413
414
    public function reIndexProjectDocuments(
415
        Docman_ProjectItemsBatchIterator $document_iterator,
416
        $project_id,
417
        FullTextSearch_NotIndexedCollector $notindexed_collector
418
    ) {
419
        $this->deleteForProject($project_id);
420
        $this->indexAllProjectDocuments($document_iterator, $project_id, $notindexed_collector);
421
    }
422
423
    private function deleteForProject($project_id) {
424
        $this->logger->debug('deleting all project documents #' . $project_id);
425
426
        try{
427
            $this->client->getIndexedType($project_id);
428
            $this->client->deleteType($project_id);
0 ignored issues
show
Bug introduced by
The method deleteType() does not exist on FullTextSearch_IIndexDocuments. Did you maybe mean delete()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
429
430
        } catch (ElasticSearch_TypeNotIndexed $exception) {
431
            $this->logger->debug('project #' . $project_id . ' not indexed, nothing to delete');
432
            return;
433
        }
434
    }
435
436
    private function indexAllProjectDocuments(
437
        Docman_ProjectItemsBatchIterator $document_iterator,
438
        $project_id,
439
        FullTextSearch_NotIndexedCollector $notindexed_collector
440
    ) {
441
        $this->logger->debug('indexing all project documents #' . $project_id);
442
443
        $this->initializeProjetMapping($project_id);
444
        $document_iterator->rewind();
445
        $docman_item_factory = Docman_ItemFactory::instance($project_id);
446
        while ($batch = $document_iterator->next()) {
447
            $this->indexBatch($batch, $notindexed_collector);
448
        }
449
    }
450
451
    private function indexBatch(array $batch, FullTextSearch_NotIndexedCollector $notindexed_collector) {
452
        foreach ($batch as $item) {
453
            try {
454
                $this->indexNonexistantDocument($item);
455
                $notindexed_collector->setAtLeastOneIndexed();
456
            } catch (ElasticSearchTransportHTTPException $exception) {
0 ignored issues
show
Bug introduced by
The class ElasticSearchTransportHTTPException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
457
                $this->logger->error('#'. $item->getId() .' cannot be indexed. '. $exception->getMessage());
458
                $notindexed_collector->add($item);
459
            } catch(FullTextSearchDocmanIndexFileTooBigException $exception) {
460
                $this->logger->error($exception->getMessage());
461
                $notindexed_collector->add($item);
462
            }
463
        }
464
    }
465
466
    private function getIndexedData(Docman_Item $item) {
467
        return $this->request_data_factory->getIndexedDataForItemVersion($item) +
468
            $this->request_data_factory->getCustomTextualMetadataValue($item) +
469
            $this->getCustomDateMetadata($item);
470
    }
471
472
    private function getItemContent(Docman_Version $version) {
473
        return $this->request_data_factory->getFileContent($version);
474
    }
475
476
    private function getWikiContent(array $wiki_metadata) {
477
        return $this->request_data_factory->getWikiContent($wiki_metadata);
478
    }
479
480
    private function getLinkContent(Docman_Item $item) {
481
        return $this->request_data_factory->getLinkContent($item);
482
    }
483
484
    /**
485
     * Get the user defined item date metadata
486
     *
487
     * @param Docman_Item $item The item indexed
488
     *
489
     * @return array
490
     */
491
492
    private function getCustomDateMetadata(Docman_Item $item) {
493
        $this->updateMappingWithNewDateMetadata($item);
494
495
        return $this->request_data_factory->getCustomDateMetadataValues($item);
496
    }
497
498
499
    private function updateCustomDateMetadata(Docman_Item $item, array $update_data) {
500
        $this->updateMappingWithNewDateMetadata($item);
501
502
        return $this->request_data_factory->updateCustomDateMetadata($item, $update_data);
503
    }
504
505
    private function updateMappingWithNewDateMetadata(Docman_Item $item) {
506
        $mapping_data = $this->request_data_factory->getPUTDateMappingMetadata(
507
            $item,
508
            $this->client->getMapping($item->getGroupId())
509
        );
510
511
        if (! $this->mappingNeedsToBoUpdated($item, $mapping_data)) {
512
            return;
513
        }
514
515
        $this->logger->debug('update mapping of project #' . $item->getGroupId() .
516
            ' with new custom date metadata');
517
518
        $this->client->setMapping(
519
            $item->getGroupId(),
520
            $mapping_data
521
        );
522
    }
523
524
    private function mappingNeedsToBoUpdated(Docman_Item $item, array $mapping_data) {
525
        return $mapping_data[$item->getGroupId()][ElasticSearch_1_2_RequestDocmanDataFactory::MAPPING_PROPERTIES_KEY]
526
            !== array();
527
    }
528
529
}
530