Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
BlockAutopromoteStore
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
5 / 5
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAutoPromoteBlockStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 blockAutoPromote
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
3
 unblockAutopromote
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
3
 getAutoPromoteBlockKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Extension\AbuseFilter;
4
5use MediaWiki\Logging\ManualLogEntry;
6use MediaWiki\Title\TitleValue;
7use MediaWiki\User\UserIdentity;
8use Psr\Log\LoggerInterface;
9use Wikimedia\ObjectCache\BagOStuff;
10
11/**
12 * Class responsible for storing and retrieving blockautopromote status
13 */
14class BlockAutopromoteStore {
15
16    public const SERVICE_NAME = 'AbuseFilterBlockAutopromoteStore';
17
18    public function __construct(
19        private readonly BagOStuff $store,
20        private readonly LoggerInterface $logger,
21        private readonly FilterUser $filterUser
22    ) {
23    }
24
25    /**
26     * Gets the autopromotion block status for the given user
27     *
28     * @param UserIdentity $target
29     * @return int
30     */
31    public function getAutoPromoteBlockStatus( UserIdentity $target ): int {
32        return (int)$this->store->get( $this->getAutoPromoteBlockKey( $target ) );
33    }
34
35    /**
36     * Blocks autopromotion for the given user
37     *
38     * @param UserIdentity $target
39     * @param string $msg The message to show in the log
40     * @param int $duration Duration for which autopromotion is blocked, in seconds
41     * @return bool True on success, false on failure
42     */
43    public function blockAutoPromote( UserIdentity $target, string $msg, int $duration ): bool {
44        if ( !$this->store->set(
45            $this->getAutoPromoteBlockKey( $target ),
46            1,
47            $duration
48        ) ) {
49            // Failed to set key
50            $this->logger->warning(
51                'Failed to block autopromotion for {target}. Error: {error}',
52                [
53                    'target' => $target->getName(),
54                    'error' => $this->store->getLastError(),
55                ]
56            );
57            return false;
58        }
59
60        $logEntry = new ManualLogEntry( 'rights', 'blockautopromote' );
61        $logEntry->setPerformer( $this->filterUser->getUserIdentity() );
62        $logEntry->setTarget( new TitleValue( NS_USER, $target->getName() ) );
63
64        $logEntry->setParameters( [
65            '7::duration' => $duration,
66            // These parameters are unused in our message, but some parts of the code check for them
67            '4::oldgroups' => [],
68            '5::newgroups' => []
69        ] );
70        $logEntry->setComment( $msg );
71        if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
72            // FIXME Remove this check once ManualLogEntry is servicified (T253717)
73            // @codeCoverageIgnoreStart
74            $logEntry->publish( $logEntry->insert() );
75            // @codeCoverageIgnoreEnd
76        }
77
78        return true;
79    }
80
81    /**
82     * Unblocks autopromotion for the given user
83     *
84     * @param UserIdentity $target
85     * @param UserIdentity $performer
86     * @param string $msg The message to show in the log
87     * @return bool True on success, false on failure
88     */
89    public function unblockAutopromote( UserIdentity $target, UserIdentity $performer, string $msg ): bool {
90        // Immediately expire (delete) the key, failing if it does not exist
91        $expireAt = time() - BagOStuff::TTL_HOUR;
92        if ( !$this->store->changeTTL(
93            $this->getAutoPromoteBlockKey( $target ),
94            $expireAt
95        ) ) {
96            // Key did not exist to begin with; nothing to do
97            return false;
98        }
99
100        $logEntry = new ManualLogEntry( 'rights', 'restoreautopromote' );
101        $logEntry->setTarget( new TitleValue( NS_USER, $target->getName() ) );
102        $logEntry->setComment( $msg );
103        // These parameters are unused in our message, but some parts of the code check for them
104        $logEntry->setParameters( [
105            '4::oldgroups' => [],
106            '5::newgroups' => []
107        ] );
108        $logEntry->setPerformer( $performer );
109        if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
110            // FIXME Remove this check once ManualLogEntry is servicified (T253717)
111            // @codeCoverageIgnoreStart
112            $logEntry->publish( $logEntry->insert() );
113            // @codeCoverageIgnoreEnd
114        }
115
116        return true;
117    }
118
119    private function getAutoPromoteBlockKey( UserIdentity $target ): string {
120        // TODO: Migration strategy to abusefilter-block-autopromote keygroup
121        return $this->store->makeKey( 'abusefilter', 'block-autopromote', $target->getId() );
122    }
123}