Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CheckUserQuery
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 3
552
0.00% covered (danger)
0.00%
0 / 1
 loadMetadataBatch
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
210
 getResult
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
 extractActionAndIds
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace Flow\Formatter;
4
5use Flow\Exception\FlowException;
6use Flow\Model\UUID;
7use MediaWiki\MediaWikiServices;
8
9class CheckUserQuery extends AbstractQuery {
10
11    /**
12     * Revision data will be stored in cuc_comment & prefixed with this string
13     * so we can distinguish between different kinds of data in there, should we
14     * change that data format later.
15     */
16    public const VERSION_PREFIX = 'v1';
17
18    /**
19     * @param \stdClass[] $rows List of checkuser database rows
20     * @suppress PhanParamSignatureMismatch The signature doesn't match though
21     */
22    public function loadMetadataBatch( $rows ) {
23        $needed = [];
24
25        $commentStore = MediaWikiServices::getInstance()->getCommentStore();
26
27        foreach ( $rows as $row ) {
28            if ( $row->cuc_type != RC_FLOW || !$commentStore->getComment( 'cuc_comment', $row )->text ) {
29                continue;
30            }
31
32            $ids = self::extractActionAndIds( $row );
33            if ( !$ids ) {
34                continue;
35            }
36
37            /** @noinspection PhpUnusedLocalVariableInspection */
38            [ $action, $workflowId, $revisionId ] = $ids;
39
40            switch ( $action ) {
41                case 'create-topic-summary':
42                case 'edit-topic-summary':
43                    $needed['PostSummary'][] = $revisionId;
44                    break;
45                case 'create-header':
46                case 'edit-header':
47                    $needed['Header'][] = $revisionId;
48                    break;
49                default:
50                    $needed['PostRevision'][] = $revisionId;
51                    break;
52            }
53        }
54
55        $found = [];
56        foreach ( $needed as $type => $uids ) {
57            $found[] = $this->storage->getMulti( $type, $uids );
58        }
59
60        $count = count( $found );
61        if ( $count === 0 ) {
62            $results = [];
63        } elseif ( $count === 1 ) {
64            $results = reset( $found );
65        } else {
66            $results = array_merge( ...array_values( $found ) );
67        }
68
69        if ( $results ) {
70            parent::loadMetadataBatch( $results );
71        }
72    }
73
74    /**
75     * @param \StdClass $row
76     * @return FormatterRow|bool
77     * @throws FlowException
78     */
79    public function getResult( $row ) {
80        if ( $row->cuc_type != RC_FLOW ||
81            !MediaWikiServices::getInstance()
82                ->getCommentStore()
83                ->getComment( 'cuc_comment', $row )->text
84        ) {
85            return false;
86        }
87
88        $ids = self::extractActionAndIds( $row );
89        if ( !$ids ) {
90            return false;
91        }
92
93        // order of $ids is (workflowId, revisionId)
94        $alpha = $ids[2]->getAlphadecimal();
95        if ( !isset( $this->revisionCache[$alpha] ) ) {
96            throw new FlowException( "Revision not found in revisionCache: $alpha" );
97        }
98        $revision = $this->revisionCache[$alpha];
99
100        $res = new FormatterRow();
101        $this->buildResult( $revision, 'cuc_timestamp', $res );
102
103        return $res;
104    }
105
106    /**
107     * Extracts the workflow, revision & post ID (if any) from the CU's
108     * comment-column (cuc_comment), where they're stored in comma-separated
109     * format.
110     *
111     * @param \StdClass $row
112     * @return false|array{0:string,1:UUID,2:UUID} Array with workflow and revision id, or false on error
113     */
114    protected function extractActionAndIds( $row ) {
115        $comment = MediaWikiServices::getInstance()
116            ->getCommentStore()
117            ->getComment( 'cuc_comment', $row )->text;
118        $data = explode( ',', $comment );
119
120        // anything not prefixed v1 is a pre-versioned check user comment
121        // if it changes again the prefix can be updated.
122        if ( strpos( $comment, self::VERSION_PREFIX ) !== 0 ) {
123            return false;
124        }
125
126        // remove the version specifier
127        array_shift( $data );
128
129        $action = array_shift( $data );
130        $revisionId = null;
131        $workflowId = null;
132        switch ( count( $data ) ) {
133            case 2:
134                $revisionId = UUID::create( $data[1] );
135                $workflowId = UUID::create( $data[0] );
136                break;
137            default:
138                wfDebugLog( 'Flow', __METHOD__ . ': Invalid number of ids received from cuc_comment.' .
139                    ' Expected 2 but received ' . count( $data ) );
140                return false;
141        }
142
143        return [ $action, $workflowId, $revisionId ];
144    }
145}