Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 55 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
FlowRevisionsDb | |
0.00% |
0 / 55 |
|
0.00% |
0 / 10 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setAssociation | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getImportedId | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 | |||
save | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
rollback | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCollectionId | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
6 | |||
getObjectRevision | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getUserTuple | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getUser | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getUUIDRange | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace Flow\Import\SourceStore; |
4 | |
5 | use Flow\Import\IImportHeader; |
6 | use Flow\Import\IImportObject; |
7 | use Flow\Import\IImportPost; |
8 | use Flow\Import\IImportSummary; |
9 | use Flow\Import\IImportTopic; |
10 | use Flow\Import\IObjectRevision; |
11 | use Flow\Import\IRevisionableObject; |
12 | use Flow\Model\UserTuple; |
13 | use Flow\Model\UUID; |
14 | use MediaWiki\User\User; |
15 | use MediaWiki\Utils\MWTimestamp; |
16 | use Wikimedia\IPUtils; |
17 | use Wikimedia\Rdbms\IDatabase; |
18 | use Wikimedia\Timestamp\TimestampException; |
19 | |
20 | /** |
21 | * Unlike other source stores, this doesn't really "store" anything. This just |
22 | * does a lookup for certain types of objects to the database to figure out if |
23 | * they have already been imported. |
24 | * |
25 | * This is less versatile than other source stores (you can't just throw |
26 | * anything at it, it's tied to a specific schema and throwing new objects at it |
27 | * will prompt changes in here) but it's more reliable (if the source store is |
28 | * lost, it can use the "result" of a previous import) |
29 | */ |
30 | class FlowRevisionsDb implements SourceStoreInterface { |
31 | /** |
32 | * @var IDatabase |
33 | */ |
34 | protected $dbr; |
35 | |
36 | /** |
37 | * @param IDatabase $dbr |
38 | */ |
39 | public function __construct( IDatabase $dbr ) { |
40 | $this->dbr = $dbr; |
41 | } |
42 | |
43 | public function setAssociation( UUID $objectId, $importSourceKey ) { |
44 | return ''; |
45 | } |
46 | |
47 | public function getImportedId( IImportObject $object ) { |
48 | if ( $object instanceof IImportHeader ) { |
49 | $conds = [ 'rev_type' => 'header' ]; |
50 | } elseif ( $object instanceof IImportSummary ) { |
51 | $conds = [ 'rev_type' => 'post-summary' ]; |
52 | } elseif ( $object instanceof IImportTopic ) { |
53 | $conds = [ 'rev_type' => 'post', 'tree_parent_id' => null ]; |
54 | } elseif ( $object instanceof IImportPost ) { |
55 | $conds = [ 'rev_type' => 'post', 'tree_parent_id IS NOT NULL' ]; |
56 | } else { |
57 | throw new Exception( 'Import object of type ' . get_class( $object ) . ' not supported.' ); |
58 | } |
59 | |
60 | $revision = $this->getObjectRevision( $object ); |
61 | return $this->getCollectionId( $revision->getTimestamp(), $revision->getAuthor(), $conds ); |
62 | } |
63 | |
64 | public function save() { |
65 | } |
66 | |
67 | public function rollback() { |
68 | } |
69 | |
70 | /** |
71 | * @param string $timestamp |
72 | * @param string $author |
73 | * @param array $conds |
74 | * @return bool|UUID |
75 | * @throws Exception |
76 | * @throws \Wikimedia\Rdbms\DBUnexpectedError |
77 | * @throws \Flow\Exception\FlowException |
78 | * @throws \Flow\Exception\InvalidInputException |
79 | */ |
80 | protected function getCollectionId( $timestamp, $author, array $conds = [] ) { |
81 | $range = $this->getUUIDRange( new MWTimestamp( $timestamp ) ); |
82 | $tuple = $this->getUserTuple( $author ); |
83 | |
84 | // flow_revision will LEFT JOIN against flow_tree_revision, meaning that |
85 | // we'll also have info about the parent; or it can just be ignored if |
86 | // there is no parent |
87 | $rows = $this->dbr->select( |
88 | [ 'flow_revision', 'flow_tree_revision' ], |
89 | [ 'rev_type_id' ], |
90 | array_merge( |
91 | [ |
92 | 'rev_type_id >= ' . $this->dbr->addQuotes( $range[0]->getBinary() ), |
93 | 'rev_type_id < ' . $this->dbr->addQuotes( $range[1]->getBinary() ), |
94 | ], |
95 | $tuple->toArray( 'rev_user_' ), |
96 | $conds |
97 | ), |
98 | __METHOD__, |
99 | [ 'LIMIT' => 1 ], |
100 | [ |
101 | 'flow_tree_revision' => [ |
102 | 'LEFT OUTER JOIN', |
103 | [ 'tree_rev_descendant_id = rev_type_id' ] |
104 | ], |
105 | ] |
106 | ); |
107 | |
108 | if ( $rows->numRows() === 0 ) { |
109 | return false; |
110 | } |
111 | |
112 | return UUID::create( $rows->fetchObject()->rev_type_id ); |
113 | } |
114 | |
115 | /** |
116 | * @param IRevisionableObject $object |
117 | * @return IObjectRevision |
118 | */ |
119 | protected function getObjectRevision( IRevisionableObject $object ) { |
120 | $revisions = $object->getRevisions(); |
121 | $revisions->rewind(); |
122 | return $revisions->current(); |
123 | } |
124 | |
125 | /** |
126 | * @param string $name |
127 | * @return UserTuple |
128 | * @throws Exception |
129 | */ |
130 | protected function getUserTuple( $name ) { |
131 | $user = $this->getUser( $name ); |
132 | if ( $user === false ) { |
133 | throw new Exception( 'Invalid author: ' . $name ); |
134 | } |
135 | return UserTuple::newFromUser( $user ); |
136 | } |
137 | |
138 | /** |
139 | * @param string $name |
140 | * @return bool|User |
141 | */ |
142 | protected function getUser( $name ) { |
143 | if ( IPUtils::isIPAddress( $name ) ) { |
144 | return User::newFromName( $name, false ); |
145 | } |
146 | |
147 | return User::newFromName( $name ); |
148 | } |
149 | |
150 | /** |
151 | * Gets the min <= ? < max boundaries for a UUID that has a given |
152 | * timestamp. Returns an array where [0] = min & [1] is max. |
153 | * |
154 | * @param MWTimestamp $timestamp |
155 | * @return UUID[] [min, max] |
156 | * @throws TimestampException |
157 | */ |
158 | protected function getUUIDRange( MWTimestamp $timestamp ) { |
159 | return [ |
160 | UUID::getComparisonUUID( (int)$timestamp->getTimestamp( TS_UNIX ) ), |
161 | UUID::getComparisonUUID( (int)$timestamp->getTimestamp( TS_UNIX ) + 1 ), |
162 | ]; |
163 | } |
164 | } |