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