MediaWiki master
PatrolManager.php
Go to the documentation of this file.
1<?php
8
19
24
25 public const PRC_UNPATROLLED = 0;
26 public const PRC_PATROLLED = 1;
27 public const PRC_AUTOPATROLLED = 2;
28
32 public const CONSTRUCTOR_OPTIONS = [
36 ];
37
38 private IConnectionProvider $connectionProvider;
39 private UserFactory $userFactory;
40 private HookContainer $hookContainer;
41 private RevertedTagUpdateManager $revertedTagUpdateManager;
42
43 private bool $useRCPatrol;
44 private bool $useNPPatrol;
45 private bool $useFilePatrol;
46
47 public function __construct(
48 ServiceOptions $options,
49 IConnectionProvider $connectionProvider,
50 UserFactory $userFactory,
51 HookContainer $hookContainer,
52 RevertedTagUpdateManager $revertedTagUpdateManager
53 ) {
54 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
55
56 $this->connectionProvider = $connectionProvider;
57 $this->userFactory = $userFactory;
58 $this->hookContainer = $hookContainer;
59 $this->revertedTagUpdateManager = $revertedTagUpdateManager;
60
61 $this->useRCPatrol = $options->get( MainConfigNames::UseRCPatrol );
62 $this->useNPPatrol = $options->get( MainConfigNames::UseNPPatrol );
63 $this->useFilePatrol = $options->get( MainConfigNames::UseFilePatrol );
64 }
65
78 public function markPatrolled(
79 RecentChange $recentChange,
80 Authority $performer,
81 $tags = null
83 // Fix up $tags so that the MarkPatrolled hook below always gets an array
84 if ( $tags === null ) {
85 $tags = [];
86 } elseif ( is_string( $tags ) ) {
87 $tags = [ $tags ];
88 }
89
90 // If recentchanges patrol is disabled, only new pages or new file versions
91 // can be patrolled, provided the appropriate config variable is set
92 if ( !$this->useRCPatrol &&
93 ( !$this->useNPPatrol || $recentChange->getAttribute( 'rc_source' ) != RecentChange::SRC_NEW ) &&
94 ( !$this->useFilePatrol || !( $recentChange->getAttribute( 'rc_source' ) == RecentChange::SRC_LOG &&
95 $recentChange->getAttribute( 'rc_log_type' ) == 'upload' ) )
96 ) {
97 return PermissionStatus::newFatal( 'rcpatroldisabled' );
98 }
99
100 // Users without the 'autopatrol' right can't patrol their own revisions
101 if ( $performer->getUser()->equals( $recentChange->getPerformerIdentity() )
102 && !$performer->isAllowed( 'autopatrol' )
103 ) {
104 return PermissionStatus::newFatal( 'markedaspatrollederror-noautopatrol' );
105 }
106
107 $status = PermissionStatus::newEmpty();
108 $performer->authorizeWrite( 'patrol', $recentChange->getTitle(), $status );
109 if ( !$status->isGood() ) {
110 return $status;
111 }
112
113 $user = $this->userFactory->newFromAuthority( $performer );
114 $hookRunner = new HookRunner( $this->hookContainer );
115
116 if ( !$hookRunner->onMarkPatrolled( $recentChange->getAttribute( 'rc_id' ), $user, false, false, $tags ) ) {
117 return PermissionStatus::newFatal( 'hookaborted' );
118 }
119
120 // If the change was patrolled already, do nothing
121 if ( $recentChange->getAttribute( 'rc_patrolled' ) ) {
122 return $status;
123 }
124
125 // Attempt to set the 'patrolled' flag in RC database
126 $affectedRowCount = $this->reallyMarkPatrolled( $recentChange );
127
128 if ( $affectedRowCount === 0 ) {
129 // Query succeeded but no rows change, e.g. another request
130 // patrolled the same change just before us.
131 // Avoid duplicate log entry (T196182).
132 return $status;
133 }
134
135 // Log this patrol event
136 PatrolLog::record( $recentChange, false, $performer->getUser(), $tags );
137
138 $hookRunner->onMarkPatrolledComplete( $recentChange->getAttribute( 'rc_id' ), $user, false, false );
139
140 return $status;
141 }
142
150 public function reallyMarkPatrolled( RecentChange $recentChange ): int {
151 $dbw = $this->connectionProvider->getPrimaryDatabase();
152 $dbw->newUpdateQueryBuilder()
153 ->update( 'recentchanges' )
154 ->set( [ 'rc_patrolled' => self::PRC_PATROLLED ] )
155 ->where( [
156 'rc_id' => $recentChange->getAttribute( 'rc_id' ),
157 'rc_patrolled' => self::PRC_UNPATROLLED,
158 ] )
159 ->caller( __METHOD__ )->execute();
160
161 $affectedRowCount = $dbw->affectedRows();
162
163 // The change was patrolled already, do nothing
164 if ( $affectedRowCount === 0 ) {
165 return 0;
166 }
167
168 // Invalidate the page cache after the page has been patrolled
169 // to make sure that the Patrol link isn't visible any longer!
170 $recentChange->getTitle()->invalidateCache();
171
172 // Enqueue a reverted tag update (in case the edit was a revert)
173 $revisionId = $recentChange->getAttribute( 'rc_this_oldid' );
174 if ( $revisionId ) {
175 $this->revertedTagUpdateManager->approveRevertedTagForRevision( $revisionId );
176 }
177
178 return $affectedRowCount;
179 }
180}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:68
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Class containing static functions for working with logs of patrol events.
Definition PatrolLog.php:22
static record( $rc, $auto, UserIdentity $user, $tags=null)
Record a log event for a change being patrolled.
Definition PatrolLog.php:35
A class containing constants representing the names of configuration variables.
const UseRCPatrol
Name constant for the UseRCPatrol setting, for use with Config::get()
const UseNPPatrol
Name constant for the UseNPPatrol setting, for use with Config::get()
const UseFilePatrol
Name constant for the UseFilePatrol setting, for use with Config::get()
A StatusValue for permission errors.
markPatrolled(RecentChange $recentChange, Authority $performer, $tags=null)
Mark this RecentChange as patrolled.
reallyMarkPatrolled(RecentChange $recentChange)
Mark this RecentChange patrolled, without error checking.
__construct(ServiceOptions $options, IConnectionProvider $connectionProvider, UserFactory $userFactory, HookContainer $hookContainer, RevertedTagUpdateManager $revertedTagUpdateManager)
Utility class for creating and reading rows in the recentchanges table.
getPerformerIdentity()
Get the UserIdentity of the client that performed this change.
getAttribute( $name)
Get an attribute value.
Class for managing delayed RevertedTagUpdateJob waiting for user approval.
Create User objects.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
Provide primary and replica IDatabase connections.