Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
69.06% covered (warning)
69.06%
96 / 139
53.85% covered (warning)
53.85%
7 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
CounterDao
69.06% covered (warning)
69.06%
96 / 139
53.85% covered (warning)
53.85%
7 / 13
27.59
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getAllEditCounts
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
2.00
 getAllEditCountsForKey
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 getEditCountForKeyAndLang
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 deleteAllCountsForKey
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 incrementEditCountForKeyAndLang
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 decrementEditCountForKeyAndLang
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 setEditCountForKeyAndLang
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 getEditStreak
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 setEditStreak
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 incrementRevertCountForKeyAndLang
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 getAllRevertCounts
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
2.00
 getRevertCountForKeyAndLang
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * @file
18 */
19namespace MediaWiki\Extension\WikimediaEditorTasks;
20
21use Wikimedia\Rdbms\IDatabase;
22use Wikimedia\Rdbms\IDBAccessObject;
23use Wikimedia\Rdbms\IReadableDatabase;
24
25class CounterDao {
26
27    /** @var IDatabase */
28    private $dbw;
29
30    /** @var IReadableDatabase */
31    private $dbr;
32
33    /**
34     * CounterDao constructor.
35     * @param IDatabase $dbw handle to DB_PRIMARY for writes
36     * @param IReadableDatabase $dbr handle to DB_REPLICA for reads
37     */
38    public function __construct( $dbw, $dbr ) {
39        $this->dbw = $dbw;
40        $this->dbr = $dbr;
41    }
42
43    /**
44     * Get all stored counts by lang for the user.
45     * @param int $centralId central user ID
46     * @return array[] All counts in the form:
47     * [
48     *     <counter key> => [
49     *         <language code> => <count>,
50     *         ...
51     *     ],
52     *     ...
53     * ]
54     */
55    public function getAllEditCounts( $centralId ) {
56        $wrapper = $this->dbr->newSelectQueryBuilder()
57            ->select( [ 'wet_key', 'wetc_lang', 'wetc_count' ] )
58            ->from( 'wikimedia_editor_tasks_counts' )
59            ->leftJoin( 'wikimedia_editor_tasks_keys', null, 'wet_id=wetc_key_id' )
60            ->where( [ 'wetc_user' => $centralId ] )
61            ->caller( __METHOD__ )
62            ->fetchResultSet();
63        $result = [];
64        foreach ( $wrapper as $row ) {
65            $result[$row->wet_key][$row->wetc_lang] = (int)$row->wetc_count;
66        }
67        return $result;
68    }
69
70    /**
71     * Get all counts by lang for a specific key for a user.
72     * @param int $centralId central user ID
73     * @param int $keyId counter key ID
74     * @param int $flags IDBAccessObject flags
75     * @return array counts for all langs for the specified key
76     */
77    public function getAllEditCountsForKey( $centralId, $keyId, $flags = 0 ) {
78        if ( ( $flags & IDBAccessObject::READ_LATEST ) == IDBAccessObject::READ_LATEST ) {
79            $db = $this->dbw;
80        } else {
81            $db = $this->dbr;
82        }
83
84        $wrapper = $db->newSelectQueryBuilder()
85            ->select( [ 'wetc_lang', 'wetc_count' ] )
86            ->from( 'wikimedia_editor_tasks_counts' )
87            ->where( [ 'wetc_user' => $centralId, 'wetc_key_id' => $keyId ] )
88            ->recency( $flags )
89            ->caller( __METHOD__ )->fetchResultSet();
90        $result = [];
91        foreach ( $wrapper as $row ) {
92            $result[$row->wetc_lang] = (int)$row->wetc_count;
93        }
94        return $result;
95    }
96
97    /**
98     * Get a single count by key and lang for a user.
99     * @param int $centralId central user ID
100     * @param int $keyId counter key ID
101     * @param string $lang language code
102     * @return int count for the specified key (returns 0 if not found)
103     */
104    public function getEditCountForKeyAndLang( $centralId, $keyId, $lang ) {
105        return (int)$this->dbr->newSelectQueryBuilder()
106            ->select( 'wetc_count' )
107            ->from( 'wikimedia_editor_tasks_counts' )
108            ->where( [
109                'wetc_user' => $centralId,
110                'wetc_key_id' => $keyId,
111                'wetc_lang' => $lang,
112            ] )
113            ->caller( __METHOD__ )
114            ->fetchField();
115    }
116
117    /**
118     * Delete counts for all languages for a single key and user.
119     * @param int $centralId central user ID
120     * @param int $keyId ID for counter key
121     */
122    public function deleteAllCountsForKey( $centralId, $keyId ) {
123        $this->dbw->newDeleteQueryBuilder()
124            ->deleteFrom( 'wikimedia_editor_tasks_counts' )
125            ->where( [
126                'wetc_user' => $centralId,
127                'wetc_key_id' => $keyId,
128            ] )
129            ->caller( __METHOD__ )
130            ->execute();
131    }
132
133    /**
134     * Increment a user's count for a key and language.
135     * @param int $centralId central user ID
136     * @param int $keyId
137     * @param string $lang language code for this count
138     */
139    public function incrementEditCountForKeyAndLang( $centralId, $keyId, $lang ) {
140        $this->dbw->newUpdateQueryBuilder()
141            ->update( 'wikimedia_editor_tasks_counts' )
142            ->set( [ 'wetc_count = wetc_count + 1' ] )
143            ->where( [
144                'wetc_user' => $centralId,
145                'wetc_key_id' => $keyId,
146                'wetc_lang' => $lang,
147            ] )
148            ->caller( __METHOD__ )
149            ->execute();
150    }
151
152    /**
153     * Decrement a user's count for a key and language.
154     * @param int $centralId central user ID
155     * @param int $keyId
156     * @param string $lang language code for this count
157     */
158    public function decrementEditCountForKeyAndLang( $centralId, $keyId, $lang ) {
159        $this->dbw->newUpdateQueryBuilder()
160            ->update( 'wikimedia_editor_tasks_counts' )
161            ->set( [ 'wetc_count = wetc_count - 1' ] )
162            ->where( [
163                'wetc_user' => $centralId,
164                'wetc_key_id' => $keyId,
165                'wetc_lang' => $lang,
166                $this->dbw->expr( 'wetc_count', '>', 0 ),
167            ] )
168            ->caller( __METHOD__ )
169            ->execute();
170    }
171
172    /**
173     * Set the count for a given counter.
174     * @param int $centralId central user ID
175     * @param int $keyId counter key ID
176     * @param string $lang language code for this count
177     * @param int $count new count
178     */
179    public function setEditCountForKeyAndLang( $centralId, $keyId, $lang, $count ) {
180        $this->dbw->newInsertQueryBuilder()
181            ->insertInto( 'wikimedia_editor_tasks_counts' )
182            ->row( [
183                'wetc_user' => $centralId,
184                'wetc_key_id' => $keyId,
185                'wetc_lang' => $lang,
186                'wetc_count' => $count,
187            ] )
188            ->onDuplicateKeyUpdate()
189            ->uniqueIndexFields( [ 'wetc_user', 'wetc_key_id', 'wetc_lang' ] )
190            ->set( [ 'wetc_count = wetc_count + ' . (int)$count ] )
191            ->caller( __METHOD__ )
192            ->execute();
193    }
194
195    /**
196     * Get the edit streak length and last edit time for the user
197     * @param int $centralId central user ID
198     * @return array[] An array contains current streak length and last edit time
199     */
200    public function getEditStreak( $centralId ) {
201        $wrapper = $this->dbr->newSelectQueryBuilder()
202            ->select( [ 'wetes_streak_length', 'wetes_last_edit_time' ] )
203            ->from( 'wikimedia_editor_tasks_edit_streak' )
204            ->where( [ 'wetes_user' => $centralId ] )
205            ->caller( __METHOD__ )
206            ->fetchRow();
207        $result = [];
208        if ( $wrapper != false ) {
209            $result['length'] = (int)$wrapper->wetes_streak_length;
210            $result['last_edit_time'] = $wrapper->wetes_last_edit_time;
211        }
212        return $result;
213    }
214
215    /**
216     * Set the edit streak for a user.
217     * Increase the edit streak length if the user makes an edit within 2 days.
218     * @param int $centralId central user ID
219     */
220    public function setEditStreak( $centralId ) {
221        $currentTime = $this->dbw->timestamp( time() );
222        $this->dbw->newInsertQueryBuilder()
223            ->insertInto( 'wikimedia_editor_tasks_edit_streak' )
224            ->row( [
225                'wetes_user' => $centralId,
226                'wetes_streak_length' => 1,
227                'wetes_last_edit_time' => $currentTime,
228            ] )
229            ->onDuplicateKeyUpdate()
230            ->uniqueIndexFields( 'wetes_user' )
231            ->set( [
232                'wetes_streak_length = IF (
233                    DATEDIFF ( ' . $currentTime . ', wetes_last_edit_time ) >= 2,
234                    1,
235                    IF (
236                        DATEDIFF ( ' . $currentTime . ', wetes_last_edit_time ) = 1,
237                        wetes_streak_length + 1,
238                        wetes_streak_length
239                    )
240                )',
241                'wetes_last_edit_time' => $currentTime,
242            ] )
243            ->caller( __METHOD__ )
244            ->execute();
245    }
246
247    /**
248     * Increment a user's revert count for a key and language.
249     * @param int $centralId central user ID
250     * @param int $keyId
251     * @param string $lang language code for this count
252     */
253    public function incrementRevertCountForKeyAndLang( $centralId, $keyId, $lang ) {
254        $this->dbw->newUpdateQueryBuilder()
255            ->update( 'wikimedia_editor_tasks_counts' )
256            ->set( [ 'wetc_revert_count = wetc_revert_count + 1' ] )
257            ->where( [
258                'wetc_user' => $centralId,
259                'wetc_key_id' => $keyId,
260                'wetc_lang' => $lang,
261            ] )
262            ->caller( __METHOD__ )
263            ->execute();
264    }
265
266    /**
267     * Get all stored reverts counts by lang for the user.
268     * @param int $centralId central user ID
269     * @return array[] All counts in the form:
270     * [
271     *     <counter key> => [
272     *         <language code> => <count>,
273     *         ...
274     *     ],
275     *     ...
276     * ]
277     */
278    public function getAllRevertCounts( $centralId ) {
279        $wrapper = $this->dbr->newSelectQueryBuilder()
280            ->select( [ 'wet_key', 'wetc_lang', 'wetc_revert_count' ] )
281            ->from( 'wikimedia_editor_tasks_counts' )
282            ->leftJoin( 'wikimedia_editor_tasks_keys', null, 'wet_id=wetc_key_id' )
283            ->where( [ 'wetc_user' => $centralId ] )
284            ->caller( __METHOD__ )
285            ->fetchResultSet();
286        $result = [];
287        foreach ( $wrapper as $row ) {
288            $result[$row->wet_key][$row->wetc_lang] = (int)$row->wetc_revert_count;
289        }
290        return $result;
291    }
292
293    /**
294     * Get a single revert count by key and lang for a user.
295     * @param int $centralId central user ID
296     * @param int $keyId counter key ID
297     * @param string $lang language code
298     * @return int revert count for the specified key (returns 0 if not found)
299     */
300    public function getRevertCountForKeyAndLang( $centralId, $keyId, $lang ) {
301        return (int)$this->dbr->newSelectQueryBuilder()
302            ->select( 'wetc_revert_count' )
303            ->from( 'wikimedia_editor_tasks_counts' )
304            ->where( [
305                'wetc_user' => $centralId,
306                'wetc_key_id' => $keyId,
307                'wetc_lang' => $lang,
308            ] )
309            ->caller( __METHOD__ )
310            ->fetchField();
311    }
312}