@@ -192,27 +192,27 @@ discard block |
||
| 192 | 192 | |
| 193 | 193 | // request states |
| 194 | 194 | $availableRequestStates = array( |
| 195 | - 'Open' => array( |
|
| 196 | - 'defertolog' => 'users', // don't change or you'll break old logs |
|
| 197 | - 'deferto' => 'users', |
|
| 198 | - 'header' => 'Open requests', |
|
| 199 | - 'api' => "open", |
|
| 200 | - 'queuehelp' => null |
|
| 201 | - ), |
|
| 202 | - 'Flagged users' => array( |
|
| 203 | - 'defertolog' => 'flagged users', // don't change or you'll break old logs |
|
| 204 | - 'deferto' => 'flagged users', |
|
| 205 | - 'header' => 'Flagged user needed', |
|
| 206 | - 'api' => "admin", |
|
| 207 | - 'queuehelp' => 'This queue lists the requests which require a user with the <code>accountcreator</code> flag to create.<br />If creation is determined to be the correct course of action, requests here will require the overriding the AntiSpoof checks or the title blacklist in order to create. It is recommended to try to create the account <em>without</em> checking the flags to validate the results of the AntiSpoof and/or title blacklist hits.' |
|
| 208 | - ), |
|
| 209 | - 'Checkuser' => array( |
|
| 210 | - 'defertolog' => 'checkusers', // don't change or you'll break old logs |
|
| 211 | - 'deferto' => 'checkusers', |
|
| 212 | - 'header' => 'Checkuser needed', |
|
| 213 | - 'api' => "checkuser", |
|
| 214 | - 'queuehelp' => null |
|
| 215 | - ), |
|
| 195 | + 'Open' => array( |
|
| 196 | + 'defertolog' => 'users', // don't change or you'll break old logs |
|
| 197 | + 'deferto' => 'users', |
|
| 198 | + 'header' => 'Open requests', |
|
| 199 | + 'api' => "open", |
|
| 200 | + 'queuehelp' => null |
|
| 201 | + ), |
|
| 202 | + 'Flagged users' => array( |
|
| 203 | + 'defertolog' => 'flagged users', // don't change or you'll break old logs |
|
| 204 | + 'deferto' => 'flagged users', |
|
| 205 | + 'header' => 'Flagged user needed', |
|
| 206 | + 'api' => "admin", |
|
| 207 | + 'queuehelp' => 'This queue lists the requests which require a user with the <code>accountcreator</code> flag to create.<br />If creation is determined to be the correct course of action, requests here will require the overriding the AntiSpoof checks or the title blacklist in order to create. It is recommended to try to create the account <em>without</em> checking the flags to validate the results of the AntiSpoof and/or title blacklist hits.' |
|
| 208 | + ), |
|
| 209 | + 'Checkuser' => array( |
|
| 210 | + 'defertolog' => 'checkusers', // don't change or you'll break old logs |
|
| 211 | + 'deferto' => 'checkusers', |
|
| 212 | + 'header' => 'Checkuser needed', |
|
| 213 | + 'api' => "checkuser", |
|
| 214 | + 'queuehelp' => null |
|
| 215 | + ), |
|
| 216 | 216 | ); |
| 217 | 217 | |
| 218 | 218 | $defaultRequestStateKey = 'Open'; |
@@ -274,24 +274,24 @@ discard block |
||
| 274 | 274 | require_once('config.local.inc.php'); |
| 275 | 275 | |
| 276 | 276 | $cDatabaseConfig = array( |
| 277 | - "acc" => array( |
|
| 278 | - "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database, |
|
| 279 | - "username" => $toolserver_username, |
|
| 280 | - "password" => $toolserver_password, |
|
| 281 | - "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
| 282 | - ), |
|
| 283 | - "wikipedia" => array( |
|
| 284 | - "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db, |
|
| 285 | - "username" => $toolserver_username, |
|
| 286 | - "password" => $toolserver_password, |
|
| 287 | - "options" => array(), |
|
| 288 | - ), |
|
| 289 | - "notifications" => array( |
|
| 290 | - "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database, |
|
| 291 | - "username" => $notifications_username, |
|
| 292 | - "password" => $notifications_password, |
|
| 293 | - "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
| 294 | - ), |
|
| 277 | + "acc" => array( |
|
| 278 | + "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database, |
|
| 279 | + "username" => $toolserver_username, |
|
| 280 | + "password" => $toolserver_password, |
|
| 281 | + "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
| 282 | + ), |
|
| 283 | + "wikipedia" => array( |
|
| 284 | + "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db, |
|
| 285 | + "username" => $toolserver_username, |
|
| 286 | + "password" => $toolserver_password, |
|
| 287 | + "options" => array(), |
|
| 288 | + ), |
|
| 289 | + "notifications" => array( |
|
| 290 | + "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database, |
|
| 291 | + "username" => $notifications_username, |
|
| 292 | + "password" => $notifications_password, |
|
| 293 | + "options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'), |
|
| 294 | + ), |
|
| 295 | 295 | ); |
| 296 | 296 | |
| 297 | 297 | // //Keep the included files from being executed. |
@@ -303,18 +303,18 @@ discard block |
||
| 303 | 303 | ini_set('user_agent', $toolUserAgent); |
| 304 | 304 | |
| 305 | 305 | foreach (array( |
| 306 | - "mbstring", // unicode and stuff |
|
| 307 | - "pdo", |
|
| 308 | - "pdo_mysql", // new database module |
|
| 309 | - "session", |
|
| 310 | - "date", |
|
| 311 | - "pcre", // core stuff |
|
| 312 | - "curl", // mediawiki api access etc |
|
| 313 | - "openssl", // token generation |
|
| 306 | + "mbstring", // unicode and stuff |
|
| 307 | + "pdo", |
|
| 308 | + "pdo_mysql", // new database module |
|
| 309 | + "session", |
|
| 310 | + "date", |
|
| 311 | + "pcre", // core stuff |
|
| 312 | + "curl", // mediawiki api access etc |
|
| 313 | + "openssl", // token generation |
|
| 314 | 314 | ) as $x) { |
| 315 | - if (!extension_loaded($x)) { |
|
| 316 | - die("extension $x is required."); |
|
| 317 | - } |
|
| 315 | + if (!extension_loaded($x)) { |
|
| 316 | + die("extension $x is required."); |
|
| 317 | + } |
|
| 318 | 318 | } |
| 319 | 319 | |
| 320 | 320 | // Set up the AutoLoader |
@@ -338,48 +338,48 @@ discard block |
||
| 338 | 338 | $siteConfiguration = new \Waca\SiteConfiguration(); |
| 339 | 339 | |
| 340 | 340 | $siteConfiguration->setBaseUrl($baseurl) |
| 341 | - ->setFilePath(__DIR__) |
|
| 342 | - ->setDebuggingTraceEnabled($enableErrorTrace) |
|
| 343 | - ->setForceIdentification($forceIdentification) |
|
| 344 | - ->setIdentificationCacheExpiry($identificationCacheExpiry) |
|
| 345 | - ->setMediawikiScriptPath($mediawikiScriptPath) |
|
| 346 | - ->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint) |
|
| 347 | - ->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint) |
|
| 348 | - ->setEnforceOAuth($enforceOAuth) |
|
| 349 | - ->setEmailConfirmationEnabled($enableEmailConfirm == 1) |
|
| 350 | - ->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays) |
|
| 351 | - ->setMiserModeLimit($requestLimitShowOnly) |
|
| 352 | - ->setRequestStates($availableRequestStates) |
|
| 353 | - ->setSquidList($squidIpList) |
|
| 354 | - ->setDefaultCreatedTemplateId($createdid) |
|
| 355 | - ->setDefaultRequestStateKey($defaultRequestStateKey) |
|
| 356 | - ->setUseStrictTransportSecurity($strictTransportSecurityExpiry) |
|
| 357 | - ->setUserAgent($toolUserAgent) |
|
| 358 | - ->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer) |
|
| 359 | - ->setUseOAuthSignup($useOauthSignup) |
|
| 360 | - ->setOAuthBaseUrl($oauthBaseUrl)// |
|
| 361 | - ->setOAuthConsumerToken($oauthConsumerToken) |
|
| 362 | - ->setOAuthLegacyConsumerTokens($oauthLegacyTokens) |
|
| 363 | - ->setOAuthConsumerSecret($oauthSecretToken) |
|
| 364 | - ->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer) |
|
| 365 | - ->setDataClearInterval($dataclear_interval) |
|
| 366 | - ->setXffTrustedHostsFile($xff_trusted_hosts_file) |
|
| 367 | - ->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1) |
|
| 368 | - ->setIrcNotificationType($ircBotNotificationType) |
|
| 369 | - ->setIrcNotificationsInstance($whichami) |
|
| 370 | - ->setTitleBlacklistEnabled($enableTitleblacklist == 1) |
|
| 371 | - ->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org'))) |
|
| 372 | - ->setCreationBotUsername($creationBotUsername) |
|
| 373 | - ->setCreationBotPassword($creationBotPassword) |
|
| 374 | - ->setCurlCookieJar($curlCookieJar) |
|
| 375 | - ->setYubicoApiId($yubicoApiId) |
|
| 376 | - ->setYubicoApiKey($yubicoApiKey) |
|
| 377 | - ->setTotpEncryptionKey($totpEncryptionKey) |
|
| 378 | - ->setRegistrationAllowed($allowRegistration) |
|
| 379 | - ->setCspReportUri($cspReportUri) |
|
| 380 | - ->setResourceCacheEpoch($resourceCacheEpoch) |
|
| 381 | - ->setLocationProviderApiKey($locationProviderApiKey) |
|
| 382 | - ->setCommonEmailDomains($commonEmailDomains) |
|
| 383 | - ->setBanMaxIpRange($banMaxIpRange) |
|
| 384 | - ->setBanMaxIpBlockRange($banMaxIpBlockRange) |
|
| 385 | - ->setJobQueueBatchSize($jobQueueBatchSize); |
|
| 341 | + ->setFilePath(__DIR__) |
|
| 342 | + ->setDebuggingTraceEnabled($enableErrorTrace) |
|
| 343 | + ->setForceIdentification($forceIdentification) |
|
| 344 | + ->setIdentificationCacheExpiry($identificationCacheExpiry) |
|
| 345 | + ->setMediawikiScriptPath($mediawikiScriptPath) |
|
| 346 | + ->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint) |
|
| 347 | + ->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint) |
|
| 348 | + ->setEnforceOAuth($enforceOAuth) |
|
| 349 | + ->setEmailConfirmationEnabled($enableEmailConfirm == 1) |
|
| 350 | + ->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays) |
|
| 351 | + ->setMiserModeLimit($requestLimitShowOnly) |
|
| 352 | + ->setRequestStates($availableRequestStates) |
|
| 353 | + ->setSquidList($squidIpList) |
|
| 354 | + ->setDefaultCreatedTemplateId($createdid) |
|
| 355 | + ->setDefaultRequestStateKey($defaultRequestStateKey) |
|
| 356 | + ->setUseStrictTransportSecurity($strictTransportSecurityExpiry) |
|
| 357 | + ->setUserAgent($toolUserAgent) |
|
| 358 | + ->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer) |
|
| 359 | + ->setUseOAuthSignup($useOauthSignup) |
|
| 360 | + ->setOAuthBaseUrl($oauthBaseUrl)// |
|
| 361 | + ->setOAuthConsumerToken($oauthConsumerToken) |
|
| 362 | + ->setOAuthLegacyConsumerTokens($oauthLegacyTokens) |
|
| 363 | + ->setOAuthConsumerSecret($oauthSecretToken) |
|
| 364 | + ->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer) |
|
| 365 | + ->setDataClearInterval($dataclear_interval) |
|
| 366 | + ->setXffTrustedHostsFile($xff_trusted_hosts_file) |
|
| 367 | + ->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1) |
|
| 368 | + ->setIrcNotificationType($ircBotNotificationType) |
|
| 369 | + ->setIrcNotificationsInstance($whichami) |
|
| 370 | + ->setTitleBlacklistEnabled($enableTitleblacklist == 1) |
|
| 371 | + ->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org'))) |
|
| 372 | + ->setCreationBotUsername($creationBotUsername) |
|
| 373 | + ->setCreationBotPassword($creationBotPassword) |
|
| 374 | + ->setCurlCookieJar($curlCookieJar) |
|
| 375 | + ->setYubicoApiId($yubicoApiId) |
|
| 376 | + ->setYubicoApiKey($yubicoApiKey) |
|
| 377 | + ->setTotpEncryptionKey($totpEncryptionKey) |
|
| 378 | + ->setRegistrationAllowed($allowRegistration) |
|
| 379 | + ->setCspReportUri($cspReportUri) |
|
| 380 | + ->setResourceCacheEpoch($resourceCacheEpoch) |
|
| 381 | + ->setLocationProviderApiKey($locationProviderApiKey) |
|
| 382 | + ->setCommonEmailDomains($commonEmailDomains) |
|
| 383 | + ->setBanMaxIpRange($banMaxIpRange) |
|
| 384 | + ->setBanMaxIpBlockRange($banMaxIpBlockRange) |
|
| 385 | + ->setJobQueueBatchSize($jobQueueBatchSize); |
|
@@ -27,455 +27,455 @@ |
||
| 27 | 27 | |
| 28 | 28 | class LogHelper |
| 29 | 29 | { |
| 30 | - /** |
|
| 31 | - * Summary of getRequestLogsWithComments |
|
| 32 | - * |
|
| 33 | - * @param int $requestId |
|
| 34 | - * @param PdoDatabase $db |
|
| 35 | - * @param SecurityManager $securityManager |
|
| 36 | - * |
|
| 37 | - * @return DataObject[] |
|
| 38 | - */ |
|
| 39 | - public static function getRequestLogsWithComments($requestId, PdoDatabase $db, SecurityManager $securityManager) |
|
| 40 | - { |
|
| 41 | - $logs = LogSearchHelper::get($db)->byObjectType('Request')->byObjectId($requestId)->fetch(); |
|
| 42 | - |
|
| 43 | - $currentUser = User::getCurrent($db); |
|
| 44 | - $showRestrictedComments = $securityManager->allows('RequestData', 'seeRestrictedComments', $currentUser) === SecurityManager::ALLOWED; |
|
| 45 | - $showCheckuserComments = $securityManager->allows('RequestData', 'seeCheckuserComments', $currentUser) === SecurityManager::ALLOWED; |
|
| 46 | - |
|
| 47 | - $comments = Comment::getForRequest($requestId, $db, $showRestrictedComments, $showCheckuserComments, $currentUser->getId()); |
|
| 48 | - |
|
| 49 | - $items = array_merge($logs, $comments); |
|
| 50 | - |
|
| 51 | - /** |
|
| 52 | - * @param DataObject $item |
|
| 53 | - * |
|
| 54 | - * @return int |
|
| 55 | - */ |
|
| 56 | - $sortKey = function(DataObject $item) { |
|
| 57 | - if ($item instanceof Log) { |
|
| 58 | - return $item->getTimestamp()->getTimestamp(); |
|
| 59 | - } |
|
| 60 | - |
|
| 61 | - if ($item instanceof Comment) { |
|
| 62 | - return $item->getTime()->getTimestamp(); |
|
| 63 | - } |
|
| 64 | - |
|
| 65 | - return 0; |
|
| 66 | - }; |
|
| 67 | - |
|
| 68 | - do { |
|
| 69 | - $flag = false; |
|
| 70 | - |
|
| 71 | - $loopLimit = (count($items) - 1); |
|
| 72 | - for ($i = 0; $i < $loopLimit; $i++) { |
|
| 73 | - // are these two items out of order? |
|
| 74 | - if ($sortKey($items[$i]) > $sortKey($items[$i + 1])) { |
|
| 75 | - // swap them |
|
| 76 | - $swap = $items[$i]; |
|
| 77 | - $items[$i] = $items[$i + 1]; |
|
| 78 | - $items[$i + 1] = $swap; |
|
| 79 | - |
|
| 80 | - // set a flag to say we've modified the array this time around |
|
| 81 | - $flag = true; |
|
| 82 | - } |
|
| 83 | - } |
|
| 84 | - } |
|
| 85 | - while ($flag); |
|
| 86 | - |
|
| 87 | - return $items; |
|
| 88 | - } |
|
| 89 | - |
|
| 90 | - /** |
|
| 91 | - * Summary of getLogDescription |
|
| 92 | - * |
|
| 93 | - * @param Log $entry |
|
| 94 | - * |
|
| 95 | - * @return string |
|
| 96 | - */ |
|
| 97 | - public static function getLogDescription(Log $entry) |
|
| 98 | - { |
|
| 99 | - $text = "Deferred to "; |
|
| 100 | - if (substr($entry->getAction(), 0, strlen($text)) == $text) { |
|
| 101 | - // Deferred to a different queue |
|
| 102 | - // This is exactly what we want to display. |
|
| 103 | - return $entry->getAction(); |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - $text = "Closed custom-n"; |
|
| 107 | - if ($entry->getAction() == $text) { |
|
| 108 | - // Custom-closed |
|
| 109 | - return "closed (custom reason - account not created)"; |
|
| 110 | - } |
|
| 111 | - |
|
| 112 | - $text = "Closed custom-y"; |
|
| 113 | - if ($entry->getAction() == $text) { |
|
| 114 | - // Custom-closed |
|
| 115 | - return "closed (custom reason - account created)"; |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - $text = "Closed 0"; |
|
| 119 | - if ($entry->getAction() == $text) { |
|
| 120 | - // Dropped the request - short-circuit the lookup |
|
| 121 | - return "dropped request"; |
|
| 122 | - } |
|
| 123 | - |
|
| 124 | - $text = "Closed "; |
|
| 125 | - if (substr($entry->getAction(), 0, strlen($text)) == $text) { |
|
| 126 | - // Closed with a reason - do a lookup here. |
|
| 127 | - $id = substr($entry->getAction(), strlen($text)); |
|
| 128 | - /** @var EmailTemplate $template */ |
|
| 129 | - $template = EmailTemplate::getById((int)$id, $entry->getDatabase()); |
|
| 130 | - |
|
| 131 | - if ($template != false) { |
|
| 132 | - return "closed (" . $template->getName() . ")"; |
|
| 133 | - } |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - // Fall back to the basic stuff |
|
| 137 | - $lookup = array( |
|
| 138 | - 'Reserved' => 'reserved', |
|
| 139 | - 'Email Confirmed' => 'email-confirmed', |
|
| 140 | - 'Unreserved' => 'unreserved', |
|
| 141 | - 'Approved' => 'approved', |
|
| 142 | - 'Suspended' => 'suspended', |
|
| 143 | - 'RoleChange' => 'changed roles', |
|
| 144 | - 'Banned' => 'banned', |
|
| 145 | - 'Edited' => 'edited interface message', |
|
| 146 | - 'Declined' => 'declined', |
|
| 147 | - 'EditComment-c' => 'edited a comment', |
|
| 148 | - 'EditComment-r' => 'edited a comment', |
|
| 149 | - 'Unbanned' => 'unbanned', |
|
| 150 | - 'Promoted' => 'promoted to tool admin', |
|
| 151 | - 'BreakReserve' => 'forcibly broke the reservation', |
|
| 152 | - 'Prefchange' => 'changed user preferences', |
|
| 153 | - 'Renamed' => 'renamed', |
|
| 154 | - 'Demoted' => 'demoted from tool admin', |
|
| 155 | - 'ReceiveReserved' => 'received the reservation', |
|
| 156 | - 'SendReserved' => 'sent the reservation', |
|
| 157 | - 'EditedEmail' => 'edited email', |
|
| 158 | - 'DeletedTemplate' => 'deleted template', |
|
| 159 | - 'EditedTemplate' => 'edited template', |
|
| 160 | - 'CreatedEmail' => 'created email', |
|
| 161 | - 'CreatedTemplate' => 'created template', |
|
| 162 | - 'SentMail' => 'sent an email to the requester', |
|
| 163 | - 'Registered' => 'registered a tool account', |
|
| 164 | - 'JobIssue' => 'ran a background job unsuccessfully', |
|
| 165 | - 'JobCompleted' => 'completed a background job', |
|
| 166 | - 'JobAcknowledged' => 'acknowledged a job failure', |
|
| 167 | - 'JobRequeued' => 'requeued a job for re-execution', |
|
| 168 | - 'JobCancelled' => 'cancelled execution of a job', |
|
| 169 | - 'EnqueuedJobQueue' => 'scheduled for creation', |
|
| 170 | - 'Hospitalised' => 'sent to the hospital', |
|
| 171 | - ); |
|
| 172 | - |
|
| 173 | - if (array_key_exists($entry->getAction(), $lookup)) { |
|
| 174 | - return $lookup[$entry->getAction()]; |
|
| 175 | - } |
|
| 176 | - |
|
| 177 | - // OK, I don't know what this is. Fall back to something sane. |
|
| 178 | - return "performed an unknown action ({$entry->getAction()})"; |
|
| 179 | - } |
|
| 180 | - |
|
| 181 | - /** |
|
| 182 | - * @param PdoDatabase $database |
|
| 183 | - * |
|
| 184 | - * @return array |
|
| 185 | - */ |
|
| 186 | - public static function getLogActions(PdoDatabase $database) |
|
| 187 | - { |
|
| 188 | - $lookup = array( |
|
| 189 | - "Requests" => [ |
|
| 190 | - 'Reserved' => 'reserved', |
|
| 191 | - 'Email Confirmed' => 'email-confirmed', |
|
| 192 | - 'Unreserved' => 'unreserved', |
|
| 193 | - 'EditComment-c' => 'edited a comment (by comment ID)', |
|
| 194 | - 'EditComment-r' => 'edited a comment (by request)', |
|
| 195 | - 'BreakReserve' => 'forcibly broke the reservation', |
|
| 196 | - 'ReceiveReserved' => 'received the reservation', |
|
| 197 | - 'SendReserved' => 'sent the reservation', |
|
| 198 | - 'SentMail' => 'sent an email to the requester', |
|
| 199 | - 'Closed 0' => 'dropped request', |
|
| 200 | - 'Closed custom-y' => 'closed (custom reason - account created)', |
|
| 201 | - 'Closed custom-n' => 'closed (custom reason - account not created)', |
|
| 202 | - ], |
|
| 203 | - 'Users' => [ |
|
| 204 | - 'Approved' => 'approved', |
|
| 205 | - 'Suspended' => 'suspended', |
|
| 206 | - 'RoleChange' => 'changed roles', |
|
| 207 | - 'Declined' => 'declined', |
|
| 208 | - 'Prefchange' => 'changed user preferences', |
|
| 209 | - 'Renamed' => 'renamed', |
|
| 210 | - 'Promoted' => 'promoted to tool admin', |
|
| 211 | - 'Demoted' => 'demoted from tool admin', |
|
| 212 | - 'Registered' => 'registered a tool account', |
|
| 213 | - ], |
|
| 214 | - "Bans" => [ |
|
| 215 | - 'Banned' => 'banned', |
|
| 216 | - 'Unbanned' => 'unbanned', |
|
| 217 | - ], |
|
| 218 | - "Site notice" => [ |
|
| 219 | - 'Edited' => 'edited interface message', |
|
| 220 | - ], |
|
| 221 | - "Email close templates" => [ |
|
| 222 | - 'EditedEmail' => 'edited email', |
|
| 223 | - 'CreatedEmail' => 'created email', |
|
| 224 | - ], |
|
| 225 | - "Welcome templates" => [ |
|
| 226 | - 'DeletedTemplate' => 'deleted template', |
|
| 227 | - 'EditedTemplate' => 'edited template', |
|
| 228 | - 'CreatedTemplate' => 'created template', |
|
| 229 | - ], |
|
| 230 | - "Job queue" => [ |
|
| 231 | - 'JobIssue' => 'ran a background job unsuccessfully', |
|
| 232 | - 'JobCompleted' => 'completed a background job', |
|
| 233 | - 'JobAcknowledged' => 'acknowledged a job failure', |
|
| 234 | - 'JobRequeued' => 'requeued a job for re-execution', |
|
| 235 | - 'JobCancelled' => 'cancelled execution of a job', |
|
| 236 | - 'EnqueuedJobQueue' => 'scheduled for creation', |
|
| 237 | - 'Hospitalised' => 'sent to the hospital', |
|
| 238 | - ], |
|
| 239 | - ); |
|
| 240 | - |
|
| 241 | - $statement = $database->query(<<<SQL |
|
| 30 | + /** |
|
| 31 | + * Summary of getRequestLogsWithComments |
|
| 32 | + * |
|
| 33 | + * @param int $requestId |
|
| 34 | + * @param PdoDatabase $db |
|
| 35 | + * @param SecurityManager $securityManager |
|
| 36 | + * |
|
| 37 | + * @return DataObject[] |
|
| 38 | + */ |
|
| 39 | + public static function getRequestLogsWithComments($requestId, PdoDatabase $db, SecurityManager $securityManager) |
|
| 40 | + { |
|
| 41 | + $logs = LogSearchHelper::get($db)->byObjectType('Request')->byObjectId($requestId)->fetch(); |
|
| 42 | + |
|
| 43 | + $currentUser = User::getCurrent($db); |
|
| 44 | + $showRestrictedComments = $securityManager->allows('RequestData', 'seeRestrictedComments', $currentUser) === SecurityManager::ALLOWED; |
|
| 45 | + $showCheckuserComments = $securityManager->allows('RequestData', 'seeCheckuserComments', $currentUser) === SecurityManager::ALLOWED; |
|
| 46 | + |
|
| 47 | + $comments = Comment::getForRequest($requestId, $db, $showRestrictedComments, $showCheckuserComments, $currentUser->getId()); |
|
| 48 | + |
|
| 49 | + $items = array_merge($logs, $comments); |
|
| 50 | + |
|
| 51 | + /** |
|
| 52 | + * @param DataObject $item |
|
| 53 | + * |
|
| 54 | + * @return int |
|
| 55 | + */ |
|
| 56 | + $sortKey = function(DataObject $item) { |
|
| 57 | + if ($item instanceof Log) { |
|
| 58 | + return $item->getTimestamp()->getTimestamp(); |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + if ($item instanceof Comment) { |
|
| 62 | + return $item->getTime()->getTimestamp(); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + return 0; |
|
| 66 | + }; |
|
| 67 | + |
|
| 68 | + do { |
|
| 69 | + $flag = false; |
|
| 70 | + |
|
| 71 | + $loopLimit = (count($items) - 1); |
|
| 72 | + for ($i = 0; $i < $loopLimit; $i++) { |
|
| 73 | + // are these two items out of order? |
|
| 74 | + if ($sortKey($items[$i]) > $sortKey($items[$i + 1])) { |
|
| 75 | + // swap them |
|
| 76 | + $swap = $items[$i]; |
|
| 77 | + $items[$i] = $items[$i + 1]; |
|
| 78 | + $items[$i + 1] = $swap; |
|
| 79 | + |
|
| 80 | + // set a flag to say we've modified the array this time around |
|
| 81 | + $flag = true; |
|
| 82 | + } |
|
| 83 | + } |
|
| 84 | + } |
|
| 85 | + while ($flag); |
|
| 86 | + |
|
| 87 | + return $items; |
|
| 88 | + } |
|
| 89 | + |
|
| 90 | + /** |
|
| 91 | + * Summary of getLogDescription |
|
| 92 | + * |
|
| 93 | + * @param Log $entry |
|
| 94 | + * |
|
| 95 | + * @return string |
|
| 96 | + */ |
|
| 97 | + public static function getLogDescription(Log $entry) |
|
| 98 | + { |
|
| 99 | + $text = "Deferred to "; |
|
| 100 | + if (substr($entry->getAction(), 0, strlen($text)) == $text) { |
|
| 101 | + // Deferred to a different queue |
|
| 102 | + // This is exactly what we want to display. |
|
| 103 | + return $entry->getAction(); |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + $text = "Closed custom-n"; |
|
| 107 | + if ($entry->getAction() == $text) { |
|
| 108 | + // Custom-closed |
|
| 109 | + return "closed (custom reason - account not created)"; |
|
| 110 | + } |
|
| 111 | + |
|
| 112 | + $text = "Closed custom-y"; |
|
| 113 | + if ($entry->getAction() == $text) { |
|
| 114 | + // Custom-closed |
|
| 115 | + return "closed (custom reason - account created)"; |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + $text = "Closed 0"; |
|
| 119 | + if ($entry->getAction() == $text) { |
|
| 120 | + // Dropped the request - short-circuit the lookup |
|
| 121 | + return "dropped request"; |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + $text = "Closed "; |
|
| 125 | + if (substr($entry->getAction(), 0, strlen($text)) == $text) { |
|
| 126 | + // Closed with a reason - do a lookup here. |
|
| 127 | + $id = substr($entry->getAction(), strlen($text)); |
|
| 128 | + /** @var EmailTemplate $template */ |
|
| 129 | + $template = EmailTemplate::getById((int)$id, $entry->getDatabase()); |
|
| 130 | + |
|
| 131 | + if ($template != false) { |
|
| 132 | + return "closed (" . $template->getName() . ")"; |
|
| 133 | + } |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + // Fall back to the basic stuff |
|
| 137 | + $lookup = array( |
|
| 138 | + 'Reserved' => 'reserved', |
|
| 139 | + 'Email Confirmed' => 'email-confirmed', |
|
| 140 | + 'Unreserved' => 'unreserved', |
|
| 141 | + 'Approved' => 'approved', |
|
| 142 | + 'Suspended' => 'suspended', |
|
| 143 | + 'RoleChange' => 'changed roles', |
|
| 144 | + 'Banned' => 'banned', |
|
| 145 | + 'Edited' => 'edited interface message', |
|
| 146 | + 'Declined' => 'declined', |
|
| 147 | + 'EditComment-c' => 'edited a comment', |
|
| 148 | + 'EditComment-r' => 'edited a comment', |
|
| 149 | + 'Unbanned' => 'unbanned', |
|
| 150 | + 'Promoted' => 'promoted to tool admin', |
|
| 151 | + 'BreakReserve' => 'forcibly broke the reservation', |
|
| 152 | + 'Prefchange' => 'changed user preferences', |
|
| 153 | + 'Renamed' => 'renamed', |
|
| 154 | + 'Demoted' => 'demoted from tool admin', |
|
| 155 | + 'ReceiveReserved' => 'received the reservation', |
|
| 156 | + 'SendReserved' => 'sent the reservation', |
|
| 157 | + 'EditedEmail' => 'edited email', |
|
| 158 | + 'DeletedTemplate' => 'deleted template', |
|
| 159 | + 'EditedTemplate' => 'edited template', |
|
| 160 | + 'CreatedEmail' => 'created email', |
|
| 161 | + 'CreatedTemplate' => 'created template', |
|
| 162 | + 'SentMail' => 'sent an email to the requester', |
|
| 163 | + 'Registered' => 'registered a tool account', |
|
| 164 | + 'JobIssue' => 'ran a background job unsuccessfully', |
|
| 165 | + 'JobCompleted' => 'completed a background job', |
|
| 166 | + 'JobAcknowledged' => 'acknowledged a job failure', |
|
| 167 | + 'JobRequeued' => 'requeued a job for re-execution', |
|
| 168 | + 'JobCancelled' => 'cancelled execution of a job', |
|
| 169 | + 'EnqueuedJobQueue' => 'scheduled for creation', |
|
| 170 | + 'Hospitalised' => 'sent to the hospital', |
|
| 171 | + ); |
|
| 172 | + |
|
| 173 | + if (array_key_exists($entry->getAction(), $lookup)) { |
|
| 174 | + return $lookup[$entry->getAction()]; |
|
| 175 | + } |
|
| 176 | + |
|
| 177 | + // OK, I don't know what this is. Fall back to something sane. |
|
| 178 | + return "performed an unknown action ({$entry->getAction()})"; |
|
| 179 | + } |
|
| 180 | + |
|
| 181 | + /** |
|
| 182 | + * @param PdoDatabase $database |
|
| 183 | + * |
|
| 184 | + * @return array |
|
| 185 | + */ |
|
| 186 | + public static function getLogActions(PdoDatabase $database) |
|
| 187 | + { |
|
| 188 | + $lookup = array( |
|
| 189 | + "Requests" => [ |
|
| 190 | + 'Reserved' => 'reserved', |
|
| 191 | + 'Email Confirmed' => 'email-confirmed', |
|
| 192 | + 'Unreserved' => 'unreserved', |
|
| 193 | + 'EditComment-c' => 'edited a comment (by comment ID)', |
|
| 194 | + 'EditComment-r' => 'edited a comment (by request)', |
|
| 195 | + 'BreakReserve' => 'forcibly broke the reservation', |
|
| 196 | + 'ReceiveReserved' => 'received the reservation', |
|
| 197 | + 'SendReserved' => 'sent the reservation', |
|
| 198 | + 'SentMail' => 'sent an email to the requester', |
|
| 199 | + 'Closed 0' => 'dropped request', |
|
| 200 | + 'Closed custom-y' => 'closed (custom reason - account created)', |
|
| 201 | + 'Closed custom-n' => 'closed (custom reason - account not created)', |
|
| 202 | + ], |
|
| 203 | + 'Users' => [ |
|
| 204 | + 'Approved' => 'approved', |
|
| 205 | + 'Suspended' => 'suspended', |
|
| 206 | + 'RoleChange' => 'changed roles', |
|
| 207 | + 'Declined' => 'declined', |
|
| 208 | + 'Prefchange' => 'changed user preferences', |
|
| 209 | + 'Renamed' => 'renamed', |
|
| 210 | + 'Promoted' => 'promoted to tool admin', |
|
| 211 | + 'Demoted' => 'demoted from tool admin', |
|
| 212 | + 'Registered' => 'registered a tool account', |
|
| 213 | + ], |
|
| 214 | + "Bans" => [ |
|
| 215 | + 'Banned' => 'banned', |
|
| 216 | + 'Unbanned' => 'unbanned', |
|
| 217 | + ], |
|
| 218 | + "Site notice" => [ |
|
| 219 | + 'Edited' => 'edited interface message', |
|
| 220 | + ], |
|
| 221 | + "Email close templates" => [ |
|
| 222 | + 'EditedEmail' => 'edited email', |
|
| 223 | + 'CreatedEmail' => 'created email', |
|
| 224 | + ], |
|
| 225 | + "Welcome templates" => [ |
|
| 226 | + 'DeletedTemplate' => 'deleted template', |
|
| 227 | + 'EditedTemplate' => 'edited template', |
|
| 228 | + 'CreatedTemplate' => 'created template', |
|
| 229 | + ], |
|
| 230 | + "Job queue" => [ |
|
| 231 | + 'JobIssue' => 'ran a background job unsuccessfully', |
|
| 232 | + 'JobCompleted' => 'completed a background job', |
|
| 233 | + 'JobAcknowledged' => 'acknowledged a job failure', |
|
| 234 | + 'JobRequeued' => 'requeued a job for re-execution', |
|
| 235 | + 'JobCancelled' => 'cancelled execution of a job', |
|
| 236 | + 'EnqueuedJobQueue' => 'scheduled for creation', |
|
| 237 | + 'Hospitalised' => 'sent to the hospital', |
|
| 238 | + ], |
|
| 239 | + ); |
|
| 240 | + |
|
| 241 | + $statement = $database->query(<<<SQL |
|
| 242 | 242 | SELECT CONCAT('Closed ', id) AS k, CONCAT('closed (',name,')') AS v |
| 243 | 243 | FROM emailtemplate; |
| 244 | 244 | SQL |
| 245 | - ); |
|
| 246 | - foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) { |
|
| 247 | - $lookup["Requests"][$row['k']] = $row['v']; |
|
| 248 | - } |
|
| 249 | - |
|
| 250 | - return $lookup; |
|
| 251 | - } |
|
| 252 | - |
|
| 253 | - public static function getObjectTypes() |
|
| 254 | - { |
|
| 255 | - return array( |
|
| 256 | - 'Ban' => 'Ban', |
|
| 257 | - 'Comment' => 'Comment', |
|
| 258 | - 'EmailTemplate' => 'Email template', |
|
| 259 | - 'JobQueue' => 'Job queue item', |
|
| 260 | - 'Request' => 'Request', |
|
| 261 | - 'SiteNotice' => 'Site notice', |
|
| 262 | - 'User' => 'User', |
|
| 263 | - 'WelcomeTemplate' => 'Welcome template', |
|
| 264 | - ); |
|
| 265 | - } |
|
| 266 | - |
|
| 267 | - /** |
|
| 268 | - * This returns a HTML |
|
| 269 | - * |
|
| 270 | - * @param string $objectId |
|
| 271 | - * @param string $objectType |
|
| 272 | - * @param PdoDatabase $database |
|
| 273 | - * @param SiteConfiguration $configuration |
|
| 274 | - * |
|
| 275 | - * @return null|string |
|
| 276 | - * @category Security-Critical |
|
| 277 | - */ |
|
| 278 | - private static function getObjectDescription( |
|
| 279 | - $objectId, |
|
| 280 | - $objectType, |
|
| 281 | - PdoDatabase $database, |
|
| 282 | - SiteConfiguration $configuration |
|
| 283 | - ) { |
|
| 284 | - if ($objectType == '') { |
|
| 285 | - return null; |
|
| 286 | - } |
|
| 287 | - |
|
| 288 | - $baseurl = $configuration->getBaseUrl(); |
|
| 289 | - |
|
| 290 | - switch ($objectType) { |
|
| 291 | - case 'Ban': |
|
| 292 | - /** @var Ban $ban */ |
|
| 293 | - $ban = Ban::getById($objectId, $database); |
|
| 294 | - |
|
| 295 | - if ($ban === false) { |
|
| 296 | - return 'Ban #' . $objectId; |
|
| 297 | - } |
|
| 298 | - |
|
| 299 | - return <<<HTML |
|
| 245 | + ); |
|
| 246 | + foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) { |
|
| 247 | + $lookup["Requests"][$row['k']] = $row['v']; |
|
| 248 | + } |
|
| 249 | + |
|
| 250 | + return $lookup; |
|
| 251 | + } |
|
| 252 | + |
|
| 253 | + public static function getObjectTypes() |
|
| 254 | + { |
|
| 255 | + return array( |
|
| 256 | + 'Ban' => 'Ban', |
|
| 257 | + 'Comment' => 'Comment', |
|
| 258 | + 'EmailTemplate' => 'Email template', |
|
| 259 | + 'JobQueue' => 'Job queue item', |
|
| 260 | + 'Request' => 'Request', |
|
| 261 | + 'SiteNotice' => 'Site notice', |
|
| 262 | + 'User' => 'User', |
|
| 263 | + 'WelcomeTemplate' => 'Welcome template', |
|
| 264 | + ); |
|
| 265 | + } |
|
| 266 | + |
|
| 267 | + /** |
|
| 268 | + * This returns a HTML |
|
| 269 | + * |
|
| 270 | + * @param string $objectId |
|
| 271 | + * @param string $objectType |
|
| 272 | + * @param PdoDatabase $database |
|
| 273 | + * @param SiteConfiguration $configuration |
|
| 274 | + * |
|
| 275 | + * @return null|string |
|
| 276 | + * @category Security-Critical |
|
| 277 | + */ |
|
| 278 | + private static function getObjectDescription( |
|
| 279 | + $objectId, |
|
| 280 | + $objectType, |
|
| 281 | + PdoDatabase $database, |
|
| 282 | + SiteConfiguration $configuration |
|
| 283 | + ) { |
|
| 284 | + if ($objectType == '') { |
|
| 285 | + return null; |
|
| 286 | + } |
|
| 287 | + |
|
| 288 | + $baseurl = $configuration->getBaseUrl(); |
|
| 289 | + |
|
| 290 | + switch ($objectType) { |
|
| 291 | + case 'Ban': |
|
| 292 | + /** @var Ban $ban */ |
|
| 293 | + $ban = Ban::getById($objectId, $database); |
|
| 294 | + |
|
| 295 | + if ($ban === false) { |
|
| 296 | + return 'Ban #' . $objectId; |
|
| 297 | + } |
|
| 298 | + |
|
| 299 | + return <<<HTML |
|
| 300 | 300 | <a href="{$baseurl}/internal.php/bans/show?id={$objectId}">Ban #{$objectId}</a> |
| 301 | 301 | HTML; |
| 302 | - case 'EmailTemplate': |
|
| 303 | - /** @var EmailTemplate $emailTemplate */ |
|
| 304 | - $emailTemplate = EmailTemplate::getById($objectId, $database); |
|
| 302 | + case 'EmailTemplate': |
|
| 303 | + /** @var EmailTemplate $emailTemplate */ |
|
| 304 | + $emailTemplate = EmailTemplate::getById($objectId, $database); |
|
| 305 | 305 | |
| 306 | - if ($emailTemplate === false) { |
|
| 307 | - return 'Email Template #' . $objectId; |
|
| 308 | - } |
|
| 306 | + if ($emailTemplate === false) { |
|
| 307 | + return 'Email Template #' . $objectId; |
|
| 308 | + } |
|
| 309 | 309 | |
| 310 | - $name = htmlentities($emailTemplate->getName(), ENT_COMPAT, 'UTF-8'); |
|
| 310 | + $name = htmlentities($emailTemplate->getName(), ENT_COMPAT, 'UTF-8'); |
|
| 311 | 311 | |
| 312 | - return <<<HTML |
|
| 312 | + return <<<HTML |
|
| 313 | 313 | <a href="{$baseurl}/internal.php/emailManagement/view?id={$objectId}">Email Template #{$objectId} ({$name})</a> |
| 314 | 314 | HTML; |
| 315 | - case 'SiteNotice': |
|
| 316 | - return "<a href=\"{$baseurl}/internal.php/siteNotice\">the site notice</a>"; |
|
| 317 | - case 'Request': |
|
| 318 | - /** @var Request $request */ |
|
| 319 | - $request = Request::getById($objectId, $database); |
|
| 315 | + case 'SiteNotice': |
|
| 316 | + return "<a href=\"{$baseurl}/internal.php/siteNotice\">the site notice</a>"; |
|
| 317 | + case 'Request': |
|
| 318 | + /** @var Request $request */ |
|
| 319 | + $request = Request::getById($objectId, $database); |
|
| 320 | 320 | |
| 321 | - if ($request === false) { |
|
| 322 | - return 'Request #' . $objectId; |
|
| 323 | - } |
|
| 321 | + if ($request === false) { |
|
| 322 | + return 'Request #' . $objectId; |
|
| 323 | + } |
|
| 324 | 324 | |
| 325 | - $name = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8'); |
|
| 325 | + $name = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8'); |
|
| 326 | 326 | |
| 327 | - return <<<HTML |
|
| 327 | + return <<<HTML |
|
| 328 | 328 | <a href="{$baseurl}/internal.php/viewRequest?id={$objectId}">Request #{$objectId} ({$name})</a> |
| 329 | 329 | HTML; |
| 330 | - case 'User': |
|
| 331 | - /** @var User $user */ |
|
| 332 | - $user = User::getById($objectId, $database); |
|
| 333 | - |
|
| 334 | - // Some users were merged out of existence |
|
| 335 | - if ($user === false) { |
|
| 336 | - return 'User #' . $objectId; |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - $username = htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8'); |
|
| 340 | - |
|
| 341 | - return "<a href=\"{$baseurl}/internal.php/statistics/users/detail?user={$objectId}\">{$username}</a>"; |
|
| 342 | - case 'WelcomeTemplate': |
|
| 343 | - /** @var WelcomeTemplate $welcomeTemplate */ |
|
| 344 | - $welcomeTemplate = WelcomeTemplate::getById($objectId, $database); |
|
| 345 | - |
|
| 346 | - // some old templates have been completely deleted and lost to the depths of time. |
|
| 347 | - if ($welcomeTemplate === false) { |
|
| 348 | - return "Welcome template #{$objectId}"; |
|
| 349 | - } |
|
| 350 | - else { |
|
| 351 | - $userCode = htmlentities($welcomeTemplate->getUserCode(), ENT_COMPAT, 'UTF-8'); |
|
| 352 | - |
|
| 353 | - return "<a href=\"{$baseurl}/internal.php/welcomeTemplates/view?template={$objectId}\">{$userCode}</a>"; |
|
| 354 | - } |
|
| 355 | - case 'JobQueue': |
|
| 356 | - /** @var JobQueue $job */ |
|
| 357 | - $job = JobQueue::getById($objectId, $database); |
|
| 358 | - |
|
| 359 | - $taskDescriptions = JobQueue::getTaskDescriptions(); |
|
| 360 | - |
|
| 361 | - if ($job === false) { |
|
| 362 | - return 'Job Queue Task #' . $objectId; |
|
| 363 | - } |
|
| 364 | - |
|
| 365 | - $task = $job->getTask(); |
|
| 366 | - if (isset($taskDescriptions[$task])) { |
|
| 367 | - $description = $taskDescriptions[$task]; |
|
| 368 | - } |
|
| 369 | - else { |
|
| 370 | - $description = 'Unknown task'; |
|
| 371 | - } |
|
| 372 | - |
|
| 373 | - return "<a href=\"{$baseurl}/internal.php/jobQueue/view?id={$objectId}\">Job #{$job->getId()} ({$description})</a>"; |
|
| 374 | - default: |
|
| 375 | - return '[' . $objectType . " " . $objectId . ']'; |
|
| 376 | - } |
|
| 377 | - } |
|
| 378 | - |
|
| 379 | - /** |
|
| 380 | - * @param Log[] $logs |
|
| 381 | - * @param PdoDatabase $database |
|
| 382 | - * @param SiteConfiguration $configuration |
|
| 383 | - * |
|
| 384 | - * @return array |
|
| 385 | - * @throws Exception |
|
| 386 | - */ |
|
| 387 | - public static function prepareLogsForTemplate($logs, PdoDatabase $database, SiteConfiguration $configuration) |
|
| 388 | - { |
|
| 389 | - $userIds = array(); |
|
| 390 | - |
|
| 391 | - foreach ($logs as $logEntry) { |
|
| 392 | - if (!$logEntry instanceof Log) { |
|
| 393 | - // if this happens, we've done something wrong with passing back the log data. |
|
| 394 | - throw new Exception('Log entry is not an instance of a Log, this should never happen.'); |
|
| 395 | - } |
|
| 396 | - |
|
| 397 | - $user = $logEntry->getUser(); |
|
| 398 | - if ($user === -1) { |
|
| 399 | - continue; |
|
| 400 | - } |
|
| 401 | - |
|
| 402 | - if (!array_search($user, $userIds)) { |
|
| 403 | - $userIds[] = $user; |
|
| 404 | - } |
|
| 405 | - } |
|
| 406 | - |
|
| 407 | - $users = UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'); |
|
| 408 | - $users[-1] = User::getCommunity()->getUsername(); |
|
| 409 | - |
|
| 410 | - $logData = array(); |
|
| 411 | - |
|
| 412 | - foreach ($logs as $logEntry) { |
|
| 413 | - $objectDescription = self::getObjectDescription($logEntry->getObjectId(), $logEntry->getObjectType(), |
|
| 414 | - $database, $configuration); |
|
| 415 | - |
|
| 416 | - // initialise to sane default |
|
| 417 | - $comment = null; |
|
| 418 | - |
|
| 419 | - switch ($logEntry->getAction()) { |
|
| 420 | - case 'Renamed': |
|
| 421 | - $renameData = unserialize($logEntry->getComment()); |
|
| 422 | - $oldName = htmlentities($renameData['old'], ENT_COMPAT, 'UTF-8'); |
|
| 423 | - $newName = htmlentities($renameData['new'], ENT_COMPAT, 'UTF-8'); |
|
| 424 | - $comment = 'Renamed \'' . $oldName . '\' to \'' . $newName . '\'.'; |
|
| 425 | - break; |
|
| 426 | - case 'RoleChange': |
|
| 427 | - $roleChangeData = unserialize($logEntry->getComment()); |
|
| 428 | - |
|
| 429 | - $removed = array(); |
|
| 430 | - foreach ($roleChangeData['removed'] as $r) { |
|
| 431 | - $removed[] = htmlentities($r, ENT_COMPAT, 'UTF-8'); |
|
| 432 | - } |
|
| 433 | - |
|
| 434 | - $added = array(); |
|
| 435 | - foreach ($roleChangeData['added'] as $r) { |
|
| 436 | - $added[] = htmlentities($r, ENT_COMPAT, 'UTF-8'); |
|
| 437 | - } |
|
| 438 | - |
|
| 439 | - $reason = htmlentities($roleChangeData['reason'], ENT_COMPAT, 'UTF-8'); |
|
| 440 | - |
|
| 441 | - $roleDelta = 'Removed [' . implode(', ', $removed) . '], Added [' . implode(', ', $added) . ']'; |
|
| 442 | - $comment = $roleDelta . ' with comment: ' . $reason; |
|
| 443 | - break; |
|
| 444 | - case 'JobIssue': |
|
| 445 | - $jobIssueData = unserialize($logEntry->getComment()); |
|
| 446 | - $errorMessage = $jobIssueData['error']; |
|
| 447 | - $status = $jobIssueData['status']; |
|
| 448 | - |
|
| 449 | - $comment = 'Job ' . htmlentities($status, ENT_COMPAT, 'UTF-8') . ': '; |
|
| 450 | - $comment .= htmlentities($errorMessage, ENT_COMPAT, 'UTF-8'); |
|
| 451 | - break; |
|
| 452 | - case 'JobIssueRequest': |
|
| 453 | - case 'JobCompletedRequest': |
|
| 454 | - $jobData = unserialize($logEntry->getComment()); |
|
| 455 | - |
|
| 456 | - /** @var JobQueue $job */ |
|
| 457 | - $job = JobQueue::getById($jobData['job'], $database); |
|
| 458 | - $descs = JobQueue::getTaskDescriptions(); |
|
| 459 | - $comment = htmlentities($descs[$job->getTask()], ENT_COMPAT, 'UTF-8'); |
|
| 460 | - break; |
|
| 461 | - |
|
| 462 | - case 'JobCompleted': |
|
| 463 | - break; |
|
| 464 | - default: |
|
| 465 | - $comment = $logEntry->getComment(); |
|
| 466 | - break; |
|
| 467 | - } |
|
| 468 | - |
|
| 469 | - $logData[] = array( |
|
| 470 | - 'timestamp' => $logEntry->getTimestamp(), |
|
| 471 | - 'userid' => $logEntry->getUser(), |
|
| 472 | - 'username' => $users[$logEntry->getUser()], |
|
| 473 | - 'description' => self::getLogDescription($logEntry), |
|
| 474 | - 'objectdescription' => $objectDescription, |
|
| 475 | - 'comment' => $comment, |
|
| 476 | - ); |
|
| 477 | - } |
|
| 478 | - |
|
| 479 | - return array($users, $logData); |
|
| 480 | - } |
|
| 330 | + case 'User': |
|
| 331 | + /** @var User $user */ |
|
| 332 | + $user = User::getById($objectId, $database); |
|
| 333 | + |
|
| 334 | + // Some users were merged out of existence |
|
| 335 | + if ($user === false) { |
|
| 336 | + return 'User #' . $objectId; |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + $username = htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8'); |
|
| 340 | + |
|
| 341 | + return "<a href=\"{$baseurl}/internal.php/statistics/users/detail?user={$objectId}\">{$username}</a>"; |
|
| 342 | + case 'WelcomeTemplate': |
|
| 343 | + /** @var WelcomeTemplate $welcomeTemplate */ |
|
| 344 | + $welcomeTemplate = WelcomeTemplate::getById($objectId, $database); |
|
| 345 | + |
|
| 346 | + // some old templates have been completely deleted and lost to the depths of time. |
|
| 347 | + if ($welcomeTemplate === false) { |
|
| 348 | + return "Welcome template #{$objectId}"; |
|
| 349 | + } |
|
| 350 | + else { |
|
| 351 | + $userCode = htmlentities($welcomeTemplate->getUserCode(), ENT_COMPAT, 'UTF-8'); |
|
| 352 | + |
|
| 353 | + return "<a href=\"{$baseurl}/internal.php/welcomeTemplates/view?template={$objectId}\">{$userCode}</a>"; |
|
| 354 | + } |
|
| 355 | + case 'JobQueue': |
|
| 356 | + /** @var JobQueue $job */ |
|
| 357 | + $job = JobQueue::getById($objectId, $database); |
|
| 358 | + |
|
| 359 | + $taskDescriptions = JobQueue::getTaskDescriptions(); |
|
| 360 | + |
|
| 361 | + if ($job === false) { |
|
| 362 | + return 'Job Queue Task #' . $objectId; |
|
| 363 | + } |
|
| 364 | + |
|
| 365 | + $task = $job->getTask(); |
|
| 366 | + if (isset($taskDescriptions[$task])) { |
|
| 367 | + $description = $taskDescriptions[$task]; |
|
| 368 | + } |
|
| 369 | + else { |
|
| 370 | + $description = 'Unknown task'; |
|
| 371 | + } |
|
| 372 | + |
|
| 373 | + return "<a href=\"{$baseurl}/internal.php/jobQueue/view?id={$objectId}\">Job #{$job->getId()} ({$description})</a>"; |
|
| 374 | + default: |
|
| 375 | + return '[' . $objectType . " " . $objectId . ']'; |
|
| 376 | + } |
|
| 377 | + } |
|
| 378 | + |
|
| 379 | + /** |
|
| 380 | + * @param Log[] $logs |
|
| 381 | + * @param PdoDatabase $database |
|
| 382 | + * @param SiteConfiguration $configuration |
|
| 383 | + * |
|
| 384 | + * @return array |
|
| 385 | + * @throws Exception |
|
| 386 | + */ |
|
| 387 | + public static function prepareLogsForTemplate($logs, PdoDatabase $database, SiteConfiguration $configuration) |
|
| 388 | + { |
|
| 389 | + $userIds = array(); |
|
| 390 | + |
|
| 391 | + foreach ($logs as $logEntry) { |
|
| 392 | + if (!$logEntry instanceof Log) { |
|
| 393 | + // if this happens, we've done something wrong with passing back the log data. |
|
| 394 | + throw new Exception('Log entry is not an instance of a Log, this should never happen.'); |
|
| 395 | + } |
|
| 396 | + |
|
| 397 | + $user = $logEntry->getUser(); |
|
| 398 | + if ($user === -1) { |
|
| 399 | + continue; |
|
| 400 | + } |
|
| 401 | + |
|
| 402 | + if (!array_search($user, $userIds)) { |
|
| 403 | + $userIds[] = $user; |
|
| 404 | + } |
|
| 405 | + } |
|
| 406 | + |
|
| 407 | + $users = UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'); |
|
| 408 | + $users[-1] = User::getCommunity()->getUsername(); |
|
| 409 | + |
|
| 410 | + $logData = array(); |
|
| 411 | + |
|
| 412 | + foreach ($logs as $logEntry) { |
|
| 413 | + $objectDescription = self::getObjectDescription($logEntry->getObjectId(), $logEntry->getObjectType(), |
|
| 414 | + $database, $configuration); |
|
| 415 | + |
|
| 416 | + // initialise to sane default |
|
| 417 | + $comment = null; |
|
| 418 | + |
|
| 419 | + switch ($logEntry->getAction()) { |
|
| 420 | + case 'Renamed': |
|
| 421 | + $renameData = unserialize($logEntry->getComment()); |
|
| 422 | + $oldName = htmlentities($renameData['old'], ENT_COMPAT, 'UTF-8'); |
|
| 423 | + $newName = htmlentities($renameData['new'], ENT_COMPAT, 'UTF-8'); |
|
| 424 | + $comment = 'Renamed \'' . $oldName . '\' to \'' . $newName . '\'.'; |
|
| 425 | + break; |
|
| 426 | + case 'RoleChange': |
|
| 427 | + $roleChangeData = unserialize($logEntry->getComment()); |
|
| 428 | + |
|
| 429 | + $removed = array(); |
|
| 430 | + foreach ($roleChangeData['removed'] as $r) { |
|
| 431 | + $removed[] = htmlentities($r, ENT_COMPAT, 'UTF-8'); |
|
| 432 | + } |
|
| 433 | + |
|
| 434 | + $added = array(); |
|
| 435 | + foreach ($roleChangeData['added'] as $r) { |
|
| 436 | + $added[] = htmlentities($r, ENT_COMPAT, 'UTF-8'); |
|
| 437 | + } |
|
| 438 | + |
|
| 439 | + $reason = htmlentities($roleChangeData['reason'], ENT_COMPAT, 'UTF-8'); |
|
| 440 | + |
|
| 441 | + $roleDelta = 'Removed [' . implode(', ', $removed) . '], Added [' . implode(', ', $added) . ']'; |
|
| 442 | + $comment = $roleDelta . ' with comment: ' . $reason; |
|
| 443 | + break; |
|
| 444 | + case 'JobIssue': |
|
| 445 | + $jobIssueData = unserialize($logEntry->getComment()); |
|
| 446 | + $errorMessage = $jobIssueData['error']; |
|
| 447 | + $status = $jobIssueData['status']; |
|
| 448 | + |
|
| 449 | + $comment = 'Job ' . htmlentities($status, ENT_COMPAT, 'UTF-8') . ': '; |
|
| 450 | + $comment .= htmlentities($errorMessage, ENT_COMPAT, 'UTF-8'); |
|
| 451 | + break; |
|
| 452 | + case 'JobIssueRequest': |
|
| 453 | + case 'JobCompletedRequest': |
|
| 454 | + $jobData = unserialize($logEntry->getComment()); |
|
| 455 | + |
|
| 456 | + /** @var JobQueue $job */ |
|
| 457 | + $job = JobQueue::getById($jobData['job'], $database); |
|
| 458 | + $descs = JobQueue::getTaskDescriptions(); |
|
| 459 | + $comment = htmlentities($descs[$job->getTask()], ENT_COMPAT, 'UTF-8'); |
|
| 460 | + break; |
|
| 461 | + |
|
| 462 | + case 'JobCompleted': |
|
| 463 | + break; |
|
| 464 | + default: |
|
| 465 | + $comment = $logEntry->getComment(); |
|
| 466 | + break; |
|
| 467 | + } |
|
| 468 | + |
|
| 469 | + $logData[] = array( |
|
| 470 | + 'timestamp' => $logEntry->getTimestamp(), |
|
| 471 | + 'userid' => $logEntry->getUser(), |
|
| 472 | + 'username' => $users[$logEntry->getUser()], |
|
| 473 | + 'description' => self::getLogDescription($logEntry), |
|
| 474 | + 'objectdescription' => $objectDescription, |
|
| 475 | + 'comment' => $comment, |
|
| 476 | + ); |
|
| 477 | + } |
|
| 478 | + |
|
| 479 | + return array($users, $logData); |
|
| 480 | + } |
|
| 481 | 481 | } |
@@ -13,112 +13,112 @@ |
||
| 13 | 13 | |
| 14 | 14 | class HttpHelper |
| 15 | 15 | { |
| 16 | - private $curlHandle; |
|
| 17 | - |
|
| 18 | - /** |
|
| 19 | - * HttpHelper constructor. |
|
| 20 | - * |
|
| 21 | - * @param SiteConfiguration $siteConfiguration |
|
| 22 | - * @param string $cookieJar |
|
| 23 | - */ |
|
| 24 | - public function __construct($siteConfiguration, $cookieJar = null) |
|
| 25 | - { |
|
| 26 | - $this->curlHandle = curl_init(); |
|
| 27 | - |
|
| 28 | - curl_setopt($this->curlHandle, CURLOPT_RETURNTRANSFER, true); |
|
| 29 | - curl_setopt($this->curlHandle, CURLOPT_USERAGENT, $siteConfiguration->getUserAgent()); |
|
| 30 | - curl_setopt($this->curlHandle, CURLOPT_FAILONERROR, true); |
|
| 31 | - |
|
| 32 | - if ($siteConfiguration->getCurlDisableVerifyPeer()) { |
|
| 33 | - curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYPEER, false); |
|
| 34 | - } |
|
| 35 | - |
|
| 36 | - if ($cookieJar !== null) { |
|
| 37 | - curl_setopt($this->curlHandle, CURLOPT_COOKIEFILE, $cookieJar); |
|
| 38 | - curl_setopt($this->curlHandle, CURLOPT_COOKIEJAR, $cookieJar); |
|
| 39 | - } |
|
| 40 | - } |
|
| 41 | - |
|
| 42 | - public function __destruct() |
|
| 43 | - { |
|
| 44 | - curl_close($this->curlHandle); |
|
| 45 | - } |
|
| 46 | - |
|
| 47 | - /** |
|
| 48 | - * Fetches the content of a URL, with an optional parameter set. |
|
| 49 | - * |
|
| 50 | - * @param string $url The URL to fetch. |
|
| 51 | - * @param null|array $parameters Key/value pair of GET parameters to add to the request. |
|
| 52 | - * Null lets you handle it yourself. |
|
| 53 | - * |
|
| 54 | - * @param array $headers |
|
| 55 | - * @param int $timeout Timeout in ms |
|
| 56 | - * |
|
| 57 | - * @return string |
|
| 58 | - * @throws CurlException |
|
| 59 | - */ |
|
| 60 | - public function get($url, $parameters = null, $headers = array(), $timeout = 300000) |
|
| 61 | - { |
|
| 62 | - if ($parameters !== null && is_array($parameters)) { |
|
| 63 | - $getString = '?' . http_build_query($parameters); |
|
| 64 | - $url .= $getString; |
|
| 65 | - } |
|
| 66 | - |
|
| 67 | - curl_setopt($this->curlHandle, CURLOPT_URL, $url); |
|
| 68 | - |
|
| 69 | - // Make sure we're doing a GET |
|
| 70 | - curl_setopt($this->curlHandle, CURLOPT_POST, false); |
|
| 71 | - |
|
| 72 | - curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, $headers); |
|
| 73 | - |
|
| 74 | - curl_setopt($this->curlHandle, CURLOPT_CONNECTTIMEOUT_MS, $timeout); |
|
| 75 | - curl_setopt($this->curlHandle, CURLOPT_TIMEOUT_MS, $timeout); |
|
| 76 | - |
|
| 77 | - $result = curl_exec($this->curlHandle); |
|
| 78 | - |
|
| 79 | - if ($result === false) { |
|
| 80 | - $error = curl_error($this->curlHandle); |
|
| 81 | - throw new CurlException('Remote request failed with error ' . $error); |
|
| 82 | - } |
|
| 83 | - |
|
| 84 | - return $result; |
|
| 85 | - } |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * Posts data to a URL |
|
| 89 | - * |
|
| 90 | - * @param string $url The URL to fetch. |
|
| 91 | - * @param array $parameters Key/value pair of POST parameters to add to the request. |
|
| 92 | - * @param array $headers |
|
| 93 | - * |
|
| 94 | - * @return string |
|
| 95 | - * @throws CurlException |
|
| 96 | - */ |
|
| 97 | - public function post($url, $parameters, $headers = array()) |
|
| 98 | - { |
|
| 99 | - curl_setopt($this->curlHandle, CURLOPT_URL, $url); |
|
| 100 | - |
|
| 101 | - // Make sure we're doing a POST |
|
| 102 | - curl_setopt($this->curlHandle, CURLOPT_POST, true); |
|
| 103 | - curl_setopt($this->curlHandle, CURLOPT_POSTFIELDS, http_build_query($parameters)); |
|
| 104 | - |
|
| 105 | - curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, $headers); |
|
| 106 | - |
|
| 107 | - $result = curl_exec($this->curlHandle); |
|
| 108 | - |
|
| 109 | - if ($result === false) { |
|
| 110 | - $error = curl_error($this->curlHandle); |
|
| 111 | - throw new CurlException('Remote request failed with error ' . $error); |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - return $result; |
|
| 115 | - } |
|
| 116 | - |
|
| 117 | - /** |
|
| 118 | - * @return string |
|
| 119 | - */ |
|
| 120 | - public function getError() |
|
| 121 | - { |
|
| 122 | - return curl_error($this->curlHandle); |
|
| 123 | - } |
|
| 16 | + private $curlHandle; |
|
| 17 | + |
|
| 18 | + /** |
|
| 19 | + * HttpHelper constructor. |
|
| 20 | + * |
|
| 21 | + * @param SiteConfiguration $siteConfiguration |
|
| 22 | + * @param string $cookieJar |
|
| 23 | + */ |
|
| 24 | + public function __construct($siteConfiguration, $cookieJar = null) |
|
| 25 | + { |
|
| 26 | + $this->curlHandle = curl_init(); |
|
| 27 | + |
|
| 28 | + curl_setopt($this->curlHandle, CURLOPT_RETURNTRANSFER, true); |
|
| 29 | + curl_setopt($this->curlHandle, CURLOPT_USERAGENT, $siteConfiguration->getUserAgent()); |
|
| 30 | + curl_setopt($this->curlHandle, CURLOPT_FAILONERROR, true); |
|
| 31 | + |
|
| 32 | + if ($siteConfiguration->getCurlDisableVerifyPeer()) { |
|
| 33 | + curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYPEER, false); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + if ($cookieJar !== null) { |
|
| 37 | + curl_setopt($this->curlHandle, CURLOPT_COOKIEFILE, $cookieJar); |
|
| 38 | + curl_setopt($this->curlHandle, CURLOPT_COOKIEJAR, $cookieJar); |
|
| 39 | + } |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + public function __destruct() |
|
| 43 | + { |
|
| 44 | + curl_close($this->curlHandle); |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + /** |
|
| 48 | + * Fetches the content of a URL, with an optional parameter set. |
|
| 49 | + * |
|
| 50 | + * @param string $url The URL to fetch. |
|
| 51 | + * @param null|array $parameters Key/value pair of GET parameters to add to the request. |
|
| 52 | + * Null lets you handle it yourself. |
|
| 53 | + * |
|
| 54 | + * @param array $headers |
|
| 55 | + * @param int $timeout Timeout in ms |
|
| 56 | + * |
|
| 57 | + * @return string |
|
| 58 | + * @throws CurlException |
|
| 59 | + */ |
|
| 60 | + public function get($url, $parameters = null, $headers = array(), $timeout = 300000) |
|
| 61 | + { |
|
| 62 | + if ($parameters !== null && is_array($parameters)) { |
|
| 63 | + $getString = '?' . http_build_query($parameters); |
|
| 64 | + $url .= $getString; |
|
| 65 | + } |
|
| 66 | + |
|
| 67 | + curl_setopt($this->curlHandle, CURLOPT_URL, $url); |
|
| 68 | + |
|
| 69 | + // Make sure we're doing a GET |
|
| 70 | + curl_setopt($this->curlHandle, CURLOPT_POST, false); |
|
| 71 | + |
|
| 72 | + curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, $headers); |
|
| 73 | + |
|
| 74 | + curl_setopt($this->curlHandle, CURLOPT_CONNECTTIMEOUT_MS, $timeout); |
|
| 75 | + curl_setopt($this->curlHandle, CURLOPT_TIMEOUT_MS, $timeout); |
|
| 76 | + |
|
| 77 | + $result = curl_exec($this->curlHandle); |
|
| 78 | + |
|
| 79 | + if ($result === false) { |
|
| 80 | + $error = curl_error($this->curlHandle); |
|
| 81 | + throw new CurlException('Remote request failed with error ' . $error); |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + return $result; |
|
| 85 | + } |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * Posts data to a URL |
|
| 89 | + * |
|
| 90 | + * @param string $url The URL to fetch. |
|
| 91 | + * @param array $parameters Key/value pair of POST parameters to add to the request. |
|
| 92 | + * @param array $headers |
|
| 93 | + * |
|
| 94 | + * @return string |
|
| 95 | + * @throws CurlException |
|
| 96 | + */ |
|
| 97 | + public function post($url, $parameters, $headers = array()) |
|
| 98 | + { |
|
| 99 | + curl_setopt($this->curlHandle, CURLOPT_URL, $url); |
|
| 100 | + |
|
| 101 | + // Make sure we're doing a POST |
|
| 102 | + curl_setopt($this->curlHandle, CURLOPT_POST, true); |
|
| 103 | + curl_setopt($this->curlHandle, CURLOPT_POSTFIELDS, http_build_query($parameters)); |
|
| 104 | + |
|
| 105 | + curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, $headers); |
|
| 106 | + |
|
| 107 | + $result = curl_exec($this->curlHandle); |
|
| 108 | + |
|
| 109 | + if ($result === false) { |
|
| 110 | + $error = curl_error($this->curlHandle); |
|
| 111 | + throw new CurlException('Remote request failed with error ' . $error); |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + return $result; |
|
| 115 | + } |
|
| 116 | + |
|
| 117 | + /** |
|
| 118 | + * @return string |
|
| 119 | + */ |
|
| 120 | + public function getError() |
|
| 121 | + { |
|
| 122 | + return curl_error($this->curlHandle); |
|
| 123 | + } |
|
| 124 | 124 | } |
@@ -19,60 +19,60 @@ discard block |
||
| 19 | 19 | |
| 20 | 20 | class BanHelper implements IBanHelper |
| 21 | 21 | { |
| 22 | - /** @var PdoDatabase */ |
|
| 23 | - private $database; |
|
| 24 | - /** @var IXffTrustProvider */ |
|
| 25 | - private $xffTrustProvider; |
|
| 26 | - /** @var Ban[][] */ |
|
| 27 | - private $banCache = []; |
|
| 28 | - /** |
|
| 29 | - * @var null|SecurityManager |
|
| 30 | - */ |
|
| 31 | - private $securityManager; |
|
| 32 | - |
|
| 33 | - public function __construct( |
|
| 34 | - PdoDatabase $database, |
|
| 35 | - IXffTrustProvider $xffTrustProvider, |
|
| 36 | - ?SecurityManager $securityManager |
|
| 37 | - ) { |
|
| 38 | - $this->database = $database; |
|
| 39 | - $this->xffTrustProvider = $xffTrustProvider; |
|
| 40 | - $this->securityManager = $securityManager; |
|
| 41 | - } |
|
| 42 | - |
|
| 43 | - public function isBlockBanned(Request $request): bool |
|
| 44 | - { |
|
| 45 | - if (!isset($this->banCache[$request->getId()])) { |
|
| 46 | - $this->banCache[$request->getId()] = $this->getBansForRequestFromDatabase($request); |
|
| 47 | - } |
|
| 48 | - |
|
| 49 | - foreach ($this->banCache[$request->getId()] as $ban) { |
|
| 50 | - if ($ban->getAction() === Ban::ACTION_BLOCK) { |
|
| 51 | - return true; |
|
| 52 | - } |
|
| 53 | - } |
|
| 54 | - |
|
| 55 | - return false; |
|
| 56 | - } |
|
| 57 | - |
|
| 58 | - /** |
|
| 59 | - * @param Request $request |
|
| 60 | - * |
|
| 61 | - * @return Ban[] |
|
| 62 | - */ |
|
| 63 | - public function getBans(Request $request): array |
|
| 64 | - { |
|
| 65 | - if (!isset($this->banCache[$request->getId()])) { |
|
| 66 | - $this->banCache[$request->getId()] = $this->getBansForRequestFromDatabase($request); |
|
| 67 | - } |
|
| 68 | - |
|
| 69 | - return $this->banCache[$request->getId()]; |
|
| 70 | - } |
|
| 71 | - |
|
| 72 | - public function getBansByTarget(?string $name, ?string $email, ?string $ip, ?int $mask, ?string $useragent) |
|
| 73 | - { |
|
| 74 | - /** @noinspection SqlConstantCondition */ |
|
| 75 | - $query = <<<SQL |
|
| 22 | + /** @var PdoDatabase */ |
|
| 23 | + private $database; |
|
| 24 | + /** @var IXffTrustProvider */ |
|
| 25 | + private $xffTrustProvider; |
|
| 26 | + /** @var Ban[][] */ |
|
| 27 | + private $banCache = []; |
|
| 28 | + /** |
|
| 29 | + * @var null|SecurityManager |
|
| 30 | + */ |
|
| 31 | + private $securityManager; |
|
| 32 | + |
|
| 33 | + public function __construct( |
|
| 34 | + PdoDatabase $database, |
|
| 35 | + IXffTrustProvider $xffTrustProvider, |
|
| 36 | + ?SecurityManager $securityManager |
|
| 37 | + ) { |
|
| 38 | + $this->database = $database; |
|
| 39 | + $this->xffTrustProvider = $xffTrustProvider; |
|
| 40 | + $this->securityManager = $securityManager; |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + public function isBlockBanned(Request $request): bool |
|
| 44 | + { |
|
| 45 | + if (!isset($this->banCache[$request->getId()])) { |
|
| 46 | + $this->banCache[$request->getId()] = $this->getBansForRequestFromDatabase($request); |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + foreach ($this->banCache[$request->getId()] as $ban) { |
|
| 50 | + if ($ban->getAction() === Ban::ACTION_BLOCK) { |
|
| 51 | + return true; |
|
| 52 | + } |
|
| 53 | + } |
|
| 54 | + |
|
| 55 | + return false; |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + /** |
|
| 59 | + * @param Request $request |
|
| 60 | + * |
|
| 61 | + * @return Ban[] |
|
| 62 | + */ |
|
| 63 | + public function getBans(Request $request): array |
|
| 64 | + { |
|
| 65 | + if (!isset($this->banCache[$request->getId()])) { |
|
| 66 | + $this->banCache[$request->getId()] = $this->getBansForRequestFromDatabase($request); |
|
| 67 | + } |
|
| 68 | + |
|
| 69 | + return $this->banCache[$request->getId()]; |
|
| 70 | + } |
|
| 71 | + |
|
| 72 | + public function getBansByTarget(?string $name, ?string $email, ?string $ip, ?int $mask, ?string $useragent) |
|
| 73 | + { |
|
| 74 | + /** @noinspection SqlConstantCondition */ |
|
| 75 | + $query = <<<SQL |
|
| 76 | 76 | SELECT * FROM ban |
| 77 | 77 | WHERE 1 = 1 |
| 78 | 78 | AND ((name is null and :nname is null) OR name = :name) |
@@ -84,76 +84,76 @@ discard block |
||
| 84 | 84 | AND active = 1; |
| 85 | 85 | SQL; |
| 86 | 86 | |
| 87 | - $statement = $this->database->prepare($query); |
|
| 88 | - $statement->execute([ |
|
| 89 | - ':name' => $name, |
|
| 90 | - ':nname' => $name, |
|
| 91 | - ':email' => $email, |
|
| 92 | - ':nemail' => $email, |
|
| 93 | - ':ip' => $ip, |
|
| 94 | - ':nip' => $ip, |
|
| 95 | - ':ipmask' => $mask, |
|
| 96 | - ':nipmask' => $mask, |
|
| 97 | - ':useragent' => $useragent, |
|
| 98 | - ':nuseragent' => $useragent, |
|
| 99 | - ]); |
|
| 100 | - |
|
| 101 | - $result = array(); |
|
| 102 | - |
|
| 103 | - /** @var Ban $v */ |
|
| 104 | - foreach ($statement->fetchAll(PDO::FETCH_CLASS, Ban::class) as $v) { |
|
| 105 | - $v->setDatabase($this->database); |
|
| 106 | - $result[] = $v; |
|
| 107 | - } |
|
| 108 | - |
|
| 109 | - return $result; |
|
| 110 | - } |
|
| 111 | - |
|
| 112 | - public function isActive(Ban $ban): bool |
|
| 113 | - { |
|
| 114 | - if (!$ban->isActive()) { |
|
| 115 | - return false; |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - if ($ban->getDuration() !== null && $ban->getDuration() < time()) { |
|
| 119 | - return false; |
|
| 120 | - } |
|
| 121 | - |
|
| 122 | - return true; |
|
| 123 | - } |
|
| 124 | - |
|
| 125 | - public function canUnban(Ban $ban): bool |
|
| 126 | - { |
|
| 127 | - if ($this->securityManager === null) { |
|
| 128 | - return false; |
|
| 129 | - } |
|
| 130 | - |
|
| 131 | - if (!$this->isActive($ban)) { |
|
| 132 | - return false; |
|
| 133 | - } |
|
| 134 | - |
|
| 135 | - $user = User::getCurrent($this->database); |
|
| 136 | - |
|
| 137 | - $allowed = true; |
|
| 138 | - $allowed = $allowed && ($ban->getName() === null || $this->securityManager->allows('BanType', 'name', $user) === SecurityManager::ALLOWED); |
|
| 139 | - $allowed = $allowed && ($ban->getEmail() === null || $this->securityManager->allows('BanType', 'email', $user) === SecurityManager::ALLOWED); |
|
| 140 | - $allowed = $allowed && ($ban->getIp() === null || $this->securityManager->allows('BanType', 'ip', $user) === SecurityManager::ALLOWED); |
|
| 141 | - $allowed = $allowed && ($ban->getUseragent() === null || $this->securityManager->allows('BanType', 'useragent', $user) === SecurityManager::ALLOWED); |
|
| 142 | - |
|
| 143 | - $allowed = $allowed && $this->securityManager->allows('BanVisibility', $ban->getVisibility(), $user) === SecurityManager::ALLOWED; |
|
| 144 | - |
|
| 145 | - return $allowed; |
|
| 146 | - } |
|
| 147 | - |
|
| 148 | - /** |
|
| 149 | - * @param Request $request |
|
| 150 | - * |
|
| 151 | - * @return Ban[] |
|
| 152 | - */ |
|
| 153 | - private function getBansForRequestFromDatabase(Request $request): array |
|
| 154 | - { |
|
| 155 | - /** @noinspection SqlConstantCondition - included for clarity of code */ |
|
| 156 | - $query = <<<SQL |
|
| 87 | + $statement = $this->database->prepare($query); |
|
| 88 | + $statement->execute([ |
|
| 89 | + ':name' => $name, |
|
| 90 | + ':nname' => $name, |
|
| 91 | + ':email' => $email, |
|
| 92 | + ':nemail' => $email, |
|
| 93 | + ':ip' => $ip, |
|
| 94 | + ':nip' => $ip, |
|
| 95 | + ':ipmask' => $mask, |
|
| 96 | + ':nipmask' => $mask, |
|
| 97 | + ':useragent' => $useragent, |
|
| 98 | + ':nuseragent' => $useragent, |
|
| 99 | + ]); |
|
| 100 | + |
|
| 101 | + $result = array(); |
|
| 102 | + |
|
| 103 | + /** @var Ban $v */ |
|
| 104 | + foreach ($statement->fetchAll(PDO::FETCH_CLASS, Ban::class) as $v) { |
|
| 105 | + $v->setDatabase($this->database); |
|
| 106 | + $result[] = $v; |
|
| 107 | + } |
|
| 108 | + |
|
| 109 | + return $result; |
|
| 110 | + } |
|
| 111 | + |
|
| 112 | + public function isActive(Ban $ban): bool |
|
| 113 | + { |
|
| 114 | + if (!$ban->isActive()) { |
|
| 115 | + return false; |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + if ($ban->getDuration() !== null && $ban->getDuration() < time()) { |
|
| 119 | + return false; |
|
| 120 | + } |
|
| 121 | + |
|
| 122 | + return true; |
|
| 123 | + } |
|
| 124 | + |
|
| 125 | + public function canUnban(Ban $ban): bool |
|
| 126 | + { |
|
| 127 | + if ($this->securityManager === null) { |
|
| 128 | + return false; |
|
| 129 | + } |
|
| 130 | + |
|
| 131 | + if (!$this->isActive($ban)) { |
|
| 132 | + return false; |
|
| 133 | + } |
|
| 134 | + |
|
| 135 | + $user = User::getCurrent($this->database); |
|
| 136 | + |
|
| 137 | + $allowed = true; |
|
| 138 | + $allowed = $allowed && ($ban->getName() === null || $this->securityManager->allows('BanType', 'name', $user) === SecurityManager::ALLOWED); |
|
| 139 | + $allowed = $allowed && ($ban->getEmail() === null || $this->securityManager->allows('BanType', 'email', $user) === SecurityManager::ALLOWED); |
|
| 140 | + $allowed = $allowed && ($ban->getIp() === null || $this->securityManager->allows('BanType', 'ip', $user) === SecurityManager::ALLOWED); |
|
| 141 | + $allowed = $allowed && ($ban->getUseragent() === null || $this->securityManager->allows('BanType', 'useragent', $user) === SecurityManager::ALLOWED); |
|
| 142 | + |
|
| 143 | + $allowed = $allowed && $this->securityManager->allows('BanVisibility', $ban->getVisibility(), $user) === SecurityManager::ALLOWED; |
|
| 144 | + |
|
| 145 | + return $allowed; |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + /** |
|
| 149 | + * @param Request $request |
|
| 150 | + * |
|
| 151 | + * @return Ban[] |
|
| 152 | + */ |
|
| 153 | + private function getBansForRequestFromDatabase(Request $request): array |
|
| 154 | + { |
|
| 155 | + /** @noinspection SqlConstantCondition - included for clarity of code */ |
|
| 156 | + $query = <<<SQL |
|
| 157 | 157 | select b.* from ban b |
| 158 | 158 | left join netmask n on 1 = 1 |
| 159 | 159 | and n.cidr = b.ipmask |
@@ -174,27 +174,27 @@ discard block |
||
| 174 | 174 | and (duration > UNIX_TIMESTAMP() or duration is null) |
| 175 | 175 | SQL; |
| 176 | 176 | |
| 177 | - $statement = $this->database->prepare($query); |
|
| 178 | - $trustedIp = $this->xffTrustProvider->getTrustedClientIp($request->getIp(), $request->getForwardedIp()); |
|
| 179 | - |
|
| 180 | - $statement->execute([ |
|
| 181 | - ':name' => $request->getName(), |
|
| 182 | - ':email' => $request->getEmail(), |
|
| 183 | - ':useragent' => $request->getUserAgent(), |
|
| 184 | - ':ip4' => $trustedIp, |
|
| 185 | - ':ip6h' => $trustedIp, |
|
| 186 | - ':ip6l' => $trustedIp, |
|
| 187 | - ]); |
|
| 188 | - |
|
| 189 | - /** @var Ban[] $result */ |
|
| 190 | - $result = []; |
|
| 191 | - |
|
| 192 | - /** @var Ban $v */ |
|
| 193 | - foreach ($statement->fetchAll(PDO::FETCH_CLASS, Ban::class) as $v) { |
|
| 194 | - $v->setDatabase($this->database); |
|
| 195 | - $result[] = $v; |
|
| 196 | - } |
|
| 197 | - |
|
| 198 | - return $result; |
|
| 199 | - } |
|
| 177 | + $statement = $this->database->prepare($query); |
|
| 178 | + $trustedIp = $this->xffTrustProvider->getTrustedClientIp($request->getIp(), $request->getForwardedIp()); |
|
| 179 | + |
|
| 180 | + $statement->execute([ |
|
| 181 | + ':name' => $request->getName(), |
|
| 182 | + ':email' => $request->getEmail(), |
|
| 183 | + ':useragent' => $request->getUserAgent(), |
|
| 184 | + ':ip4' => $trustedIp, |
|
| 185 | + ':ip6h' => $trustedIp, |
|
| 186 | + ':ip6l' => $trustedIp, |
|
| 187 | + ]); |
|
| 188 | + |
|
| 189 | + /** @var Ban[] $result */ |
|
| 190 | + $result = []; |
|
| 191 | + |
|
| 192 | + /** @var Ban $v */ |
|
| 193 | + foreach ($statement->fetchAll(PDO::FETCH_CLASS, Ban::class) as $v) { |
|
| 194 | + $v->setDatabase($this->database); |
|
| 195 | + $result[] = $v; |
|
| 196 | + } |
|
| 197 | + |
|
| 198 | + return $result; |
|
| 199 | + } |
|
| 200 | 200 | } |
@@ -16,95 +16,95 @@ |
||
| 16 | 16 | |
| 17 | 17 | class OAuthProtocolHelper implements Interfaces\IOAuthProtocolHelper |
| 18 | 18 | { |
| 19 | - private $oauthClient; |
|
| 20 | - |
|
| 21 | - private $mediawikiWebServiceEndpoint; |
|
| 22 | - |
|
| 23 | - private $authUrl; |
|
| 24 | - |
|
| 25 | - /** |
|
| 26 | - * OAuthHelper constructor. |
|
| 27 | - * |
|
| 28 | - * @param string $oauthEndpoint |
|
| 29 | - * @param string $consumerKey |
|
| 30 | - * @param string $consumerSecret |
|
| 31 | - * @param string $mediawikiWebServiceEndpoint |
|
| 32 | - */ |
|
| 33 | - public function __construct( |
|
| 34 | - $oauthEndpoint, |
|
| 35 | - $consumerKey, |
|
| 36 | - $consumerSecret, |
|
| 37 | - $mediawikiWebServiceEndpoint |
|
| 38 | - ) { |
|
| 39 | - $this->mediawikiWebServiceEndpoint = $mediawikiWebServiceEndpoint; |
|
| 40 | - |
|
| 41 | - $oauthClientConfig = new ClientConfig($oauthEndpoint); |
|
| 42 | - $oauthClientConfig->setConsumer(new Consumer($consumerKey, $consumerSecret)); |
|
| 43 | - |
|
| 44 | - $this->oauthClient = new Client($oauthClientConfig); |
|
| 45 | - } |
|
| 46 | - |
|
| 47 | - /** |
|
| 48 | - * @inheritDoc |
|
| 49 | - */ |
|
| 50 | - public function getRequestToken() |
|
| 51 | - { |
|
| 52 | - /** @var Token $requestToken */ |
|
| 53 | - list($authUrl, $requestToken) = $this->oauthClient->initiate(); |
|
| 54 | - $this->authUrl = $authUrl; |
|
| 55 | - return $requestToken; |
|
| 56 | - } |
|
| 57 | - |
|
| 58 | - /** |
|
| 59 | - * @inheritDoc |
|
| 60 | - */ |
|
| 61 | - public function getAuthoriseUrl($requestToken) |
|
| 62 | - { |
|
| 63 | - return $this->authUrl; |
|
| 64 | - } |
|
| 65 | - |
|
| 66 | - /** |
|
| 67 | - * @inheritDoc |
|
| 68 | - */ |
|
| 69 | - public function callbackCompleted($oauthRequestToken, $oauthRequestSecret, $oauthVerifier) |
|
| 70 | - { |
|
| 71 | - $requestToken = new Token($oauthRequestToken, $oauthRequestSecret); |
|
| 72 | - |
|
| 73 | - return $this->oauthClient->complete($requestToken, $oauthVerifier); |
|
| 74 | - } |
|
| 75 | - |
|
| 76 | - /** |
|
| 77 | - * @inheritDoc |
|
| 78 | - */ |
|
| 79 | - public function getIdentityTicket($oauthAccessToken, $oauthAccessSecret) |
|
| 80 | - { |
|
| 81 | - return $this->oauthClient->identify(new Token($oauthAccessToken, $oauthAccessSecret)); |
|
| 82 | - } |
|
| 83 | - |
|
| 84 | - /** |
|
| 85 | - * @inheritDoc |
|
| 86 | - */ |
|
| 87 | - public function apiCall($apiParams, $accessToken, $accessSecret, $method = 'GET') |
|
| 88 | - { |
|
| 89 | - $userToken = new Token($accessToken, $accessSecret); |
|
| 90 | - |
|
| 91 | - $apiParams['format'] = 'json'; |
|
| 92 | - |
|
| 93 | - if ($apiParams === null || !is_array($apiParams)) { |
|
| 94 | - throw new CurlException("Invalid API call"); |
|
| 95 | - } |
|
| 96 | - |
|
| 97 | - $url = $this->mediawikiWebServiceEndpoint; |
|
| 98 | - $isPost = ($method === 'POST'); |
|
| 99 | - |
|
| 100 | - if ($method === 'GET') { |
|
| 101 | - $query = http_build_query($apiParams); |
|
| 102 | - $url .= '?' . $query; |
|
| 103 | - $apiParams = null; |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - $data = $this->oauthClient->makeOAuthCall($userToken, $url, $isPost, $apiParams); |
|
| 107 | - |
|
| 108 | - return json_decode($data); |
|
| 109 | - } |
|
| 19 | + private $oauthClient; |
|
| 20 | + |
|
| 21 | + private $mediawikiWebServiceEndpoint; |
|
| 22 | + |
|
| 23 | + private $authUrl; |
|
| 24 | + |
|
| 25 | + /** |
|
| 26 | + * OAuthHelper constructor. |
|
| 27 | + * |
|
| 28 | + * @param string $oauthEndpoint |
|
| 29 | + * @param string $consumerKey |
|
| 30 | + * @param string $consumerSecret |
|
| 31 | + * @param string $mediawikiWebServiceEndpoint |
|
| 32 | + */ |
|
| 33 | + public function __construct( |
|
| 34 | + $oauthEndpoint, |
|
| 35 | + $consumerKey, |
|
| 36 | + $consumerSecret, |
|
| 37 | + $mediawikiWebServiceEndpoint |
|
| 38 | + ) { |
|
| 39 | + $this->mediawikiWebServiceEndpoint = $mediawikiWebServiceEndpoint; |
|
| 40 | + |
|
| 41 | + $oauthClientConfig = new ClientConfig($oauthEndpoint); |
|
| 42 | + $oauthClientConfig->setConsumer(new Consumer($consumerKey, $consumerSecret)); |
|
| 43 | + |
|
| 44 | + $this->oauthClient = new Client($oauthClientConfig); |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + /** |
|
| 48 | + * @inheritDoc |
|
| 49 | + */ |
|
| 50 | + public function getRequestToken() |
|
| 51 | + { |
|
| 52 | + /** @var Token $requestToken */ |
|
| 53 | + list($authUrl, $requestToken) = $this->oauthClient->initiate(); |
|
| 54 | + $this->authUrl = $authUrl; |
|
| 55 | + return $requestToken; |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + /** |
|
| 59 | + * @inheritDoc |
|
| 60 | + */ |
|
| 61 | + public function getAuthoriseUrl($requestToken) |
|
| 62 | + { |
|
| 63 | + return $this->authUrl; |
|
| 64 | + } |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * @inheritDoc |
|
| 68 | + */ |
|
| 69 | + public function callbackCompleted($oauthRequestToken, $oauthRequestSecret, $oauthVerifier) |
|
| 70 | + { |
|
| 71 | + $requestToken = new Token($oauthRequestToken, $oauthRequestSecret); |
|
| 72 | + |
|
| 73 | + return $this->oauthClient->complete($requestToken, $oauthVerifier); |
|
| 74 | + } |
|
| 75 | + |
|
| 76 | + /** |
|
| 77 | + * @inheritDoc |
|
| 78 | + */ |
|
| 79 | + public function getIdentityTicket($oauthAccessToken, $oauthAccessSecret) |
|
| 80 | + { |
|
| 81 | + return $this->oauthClient->identify(new Token($oauthAccessToken, $oauthAccessSecret)); |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + /** |
|
| 85 | + * @inheritDoc |
|
| 86 | + */ |
|
| 87 | + public function apiCall($apiParams, $accessToken, $accessSecret, $method = 'GET') |
|
| 88 | + { |
|
| 89 | + $userToken = new Token($accessToken, $accessSecret); |
|
| 90 | + |
|
| 91 | + $apiParams['format'] = 'json'; |
|
| 92 | + |
|
| 93 | + if ($apiParams === null || !is_array($apiParams)) { |
|
| 94 | + throw new CurlException("Invalid API call"); |
|
| 95 | + } |
|
| 96 | + |
|
| 97 | + $url = $this->mediawikiWebServiceEndpoint; |
|
| 98 | + $isPost = ($method === 'POST'); |
|
| 99 | + |
|
| 100 | + if ($method === 'GET') { |
|
| 101 | + $query = http_build_query($apiParams); |
|
| 102 | + $url .= '?' . $query; |
|
| 103 | + $apiParams = null; |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + $data = $this->oauthClient->makeOAuthCall($userToken, $url, $isPost, $apiParams); |
|
| 107 | + |
|
| 108 | + return json_decode($data); |
|
| 109 | + } |
|
| 110 | 110 | } |
| 111 | 111 | \ No newline at end of file |
@@ -31,362 +31,362 @@ |
||
| 31 | 31 | */ |
| 32 | 32 | class Logger |
| 33 | 33 | { |
| 34 | - /** |
|
| 35 | - * @param PdoDatabase $database |
|
| 36 | - * @param Request $object |
|
| 37 | - */ |
|
| 38 | - public static function emailConfirmed(PdoDatabase $database, Request $object) |
|
| 39 | - { |
|
| 40 | - self::createLogEntry($database, $object, "Email Confirmed", null, User::getCommunity()); |
|
| 41 | - } |
|
| 42 | - |
|
| 43 | - /** |
|
| 44 | - * @param PdoDatabase $database |
|
| 45 | - * @param DataObject $object |
|
| 46 | - * @param string $logAction |
|
| 47 | - * @param null|string $comment |
|
| 48 | - * @param User $user |
|
| 49 | - * |
|
| 50 | - * @throws Exception |
|
| 51 | - */ |
|
| 52 | - private static function createLogEntry( |
|
| 53 | - PdoDatabase $database, |
|
| 54 | - DataObject $object, |
|
| 55 | - $logAction, |
|
| 56 | - $comment = null, |
|
| 57 | - $user = null |
|
| 58 | - ) { |
|
| 59 | - if ($user == null) { |
|
| 60 | - $user = User::getCurrent($database); |
|
| 61 | - } |
|
| 62 | - |
|
| 63 | - $objectType = get_class($object); |
|
| 64 | - if (strpos($objectType, 'Waca\\DataObjects\\') !== false) { |
|
| 65 | - $objectType = str_replace('Waca\\DataObjects\\', '', $objectType); |
|
| 66 | - } |
|
| 67 | - |
|
| 68 | - $log = new Log(); |
|
| 69 | - $log->setDatabase($database); |
|
| 70 | - $log->setAction($logAction); |
|
| 71 | - $log->setObjectId($object->getId()); |
|
| 72 | - $log->setObjectType($objectType); |
|
| 73 | - $log->setUser($user); |
|
| 74 | - $log->setComment($comment); |
|
| 75 | - $log->save(); |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - #region Users |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * @param PdoDatabase $database |
|
| 82 | - * @param User $user |
|
| 83 | - */ |
|
| 84 | - public static function newUser(PdoDatabase $database, User $user) |
|
| 85 | - { |
|
| 86 | - self::createLogEntry($database, $user, 'Registered', null, User::getCommunity()); |
|
| 87 | - } |
|
| 88 | - |
|
| 89 | - /** |
|
| 90 | - * @param PdoDatabase $database |
|
| 91 | - * @param User $object |
|
| 92 | - */ |
|
| 93 | - public static function approvedUser(PdoDatabase $database, User $object) |
|
| 94 | - { |
|
| 95 | - self::createLogEntry($database, $object, "Approved"); |
|
| 96 | - } |
|
| 97 | - |
|
| 98 | - /** |
|
| 99 | - * @param PdoDatabase $database |
|
| 100 | - * @param User $object |
|
| 101 | - * @param string $comment |
|
| 102 | - */ |
|
| 103 | - public static function declinedUser(PdoDatabase $database, User $object, $comment) |
|
| 104 | - { |
|
| 105 | - self::createLogEntry($database, $object, "Declined", $comment); |
|
| 106 | - } |
|
| 107 | - |
|
| 108 | - /** |
|
| 109 | - * @param PdoDatabase $database |
|
| 110 | - * @param User $object |
|
| 111 | - * @param string $comment |
|
| 112 | - */ |
|
| 113 | - public static function suspendedUser(PdoDatabase $database, User $object, $comment) |
|
| 114 | - { |
|
| 115 | - self::createLogEntry($database, $object, "Suspended", $comment); |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - /** |
|
| 119 | - * @param PdoDatabase $database |
|
| 120 | - * @param User $object |
|
| 121 | - * @param string $comment |
|
| 122 | - */ |
|
| 123 | - public static function demotedUser(PdoDatabase $database, User $object, $comment) |
|
| 124 | - { |
|
| 125 | - self::createLogEntry($database, $object, "Demoted", $comment); |
|
| 126 | - } |
|
| 127 | - |
|
| 128 | - /** |
|
| 129 | - * @param PdoDatabase $database |
|
| 130 | - * @param User $object |
|
| 131 | - */ |
|
| 132 | - public static function promotedUser(PdoDatabase $database, User $object) |
|
| 133 | - { |
|
| 134 | - self::createLogEntry($database, $object, "Promoted"); |
|
| 135 | - } |
|
| 136 | - |
|
| 137 | - /** |
|
| 138 | - * @param PdoDatabase $database |
|
| 139 | - * @param User $object |
|
| 140 | - * @param string $comment |
|
| 141 | - */ |
|
| 142 | - public static function renamedUser(PdoDatabase $database, User $object, $comment) |
|
| 143 | - { |
|
| 144 | - self::createLogEntry($database, $object, "Renamed", $comment); |
|
| 145 | - } |
|
| 146 | - |
|
| 147 | - /** |
|
| 148 | - * @param PdoDatabase $database |
|
| 149 | - * @param User $object |
|
| 150 | - */ |
|
| 151 | - public static function userPreferencesChange(PdoDatabase $database, User $object) |
|
| 152 | - { |
|
| 153 | - self::createLogEntry($database, $object, "Prefchange"); |
|
| 154 | - } |
|
| 155 | - |
|
| 156 | - /** |
|
| 157 | - * @param PdoDatabase $database |
|
| 158 | - * @param User $object |
|
| 159 | - * @param string $reason |
|
| 160 | - * @param array $added |
|
| 161 | - * @param array $removed |
|
| 162 | - */ |
|
| 163 | - public static function userRolesEdited(PdoDatabase $database, User $object, $reason, $added, $removed) |
|
| 164 | - { |
|
| 165 | - $logData = serialize(array( |
|
| 166 | - 'added' => $added, |
|
| 167 | - 'removed' => $removed, |
|
| 168 | - 'reason' => $reason, |
|
| 169 | - )); |
|
| 170 | - |
|
| 171 | - self::createLogEntry($database, $object, "RoleChange", $logData); |
|
| 172 | - } |
|
| 173 | - |
|
| 174 | - #endregion |
|
| 175 | - |
|
| 176 | - /** |
|
| 177 | - * @param PdoDatabase $database |
|
| 178 | - * @param SiteNotice $object |
|
| 179 | - */ |
|
| 180 | - public static function siteNoticeEdited(PdoDatabase $database, SiteNotice $object) |
|
| 181 | - { |
|
| 182 | - self::createLogEntry($database, $object, "Edited"); |
|
| 183 | - } |
|
| 184 | - |
|
| 185 | - #region Welcome Templates |
|
| 186 | - |
|
| 187 | - /** |
|
| 188 | - * @param PdoDatabase $database |
|
| 189 | - * @param WelcomeTemplate $object |
|
| 190 | - */ |
|
| 191 | - public static function welcomeTemplateCreated(PdoDatabase $database, WelcomeTemplate $object) |
|
| 192 | - { |
|
| 193 | - self::createLogEntry($database, $object, "CreatedTemplate"); |
|
| 194 | - } |
|
| 195 | - |
|
| 196 | - /** |
|
| 197 | - * @param PdoDatabase $database |
|
| 198 | - * @param WelcomeTemplate $object |
|
| 199 | - */ |
|
| 200 | - public static function welcomeTemplateEdited(PdoDatabase $database, WelcomeTemplate $object) |
|
| 201 | - { |
|
| 202 | - self::createLogEntry($database, $object, "EditedTemplate"); |
|
| 203 | - } |
|
| 204 | - |
|
| 205 | - /** |
|
| 206 | - * @param PdoDatabase $database |
|
| 207 | - * @param WelcomeTemplate $object |
|
| 208 | - */ |
|
| 209 | - public static function welcomeTemplateDeleted(PdoDatabase $database, WelcomeTemplate $object) |
|
| 210 | - { |
|
| 211 | - self::createLogEntry($database, $object, "DeletedTemplate"); |
|
| 212 | - } |
|
| 213 | - |
|
| 214 | - #endregion |
|
| 215 | - |
|
| 216 | - #region Bans |
|
| 217 | - |
|
| 218 | - /** |
|
| 219 | - * @param PdoDatabase $database |
|
| 220 | - * @param Ban $object |
|
| 221 | - * @param string $reason |
|
| 222 | - */ |
|
| 223 | - public static function banned(PdoDatabase $database, Ban $object, $reason) |
|
| 224 | - { |
|
| 225 | - self::createLogEntry($database, $object, "Banned", $reason); |
|
| 226 | - } |
|
| 227 | - |
|
| 228 | - /** |
|
| 229 | - * @param PdoDatabase $database |
|
| 230 | - * @param Ban $object |
|
| 231 | - * @param string $reason |
|
| 232 | - */ |
|
| 233 | - public static function unbanned(PdoDatabase $database, Ban $object, $reason) |
|
| 234 | - { |
|
| 235 | - self::createLogEntry($database, $object, "Unbanned", $reason); |
|
| 236 | - } |
|
| 237 | - |
|
| 238 | - #endregion |
|
| 239 | - |
|
| 240 | - #region Requests |
|
| 241 | - |
|
| 242 | - /** |
|
| 243 | - * @param PdoDatabase $database |
|
| 244 | - * @param Request $object |
|
| 245 | - * @param string $target |
|
| 246 | - */ |
|
| 247 | - public static function deferRequest(PdoDatabase $database, Request $object, $target) |
|
| 248 | - { |
|
| 249 | - self::createLogEntry($database, $object, "Deferred to $target"); |
|
| 250 | - } |
|
| 251 | - |
|
| 252 | - /** |
|
| 253 | - * @param PdoDatabase $database |
|
| 254 | - * @param Request $object |
|
| 255 | - * @param integer $target |
|
| 256 | - * @param string $comment |
|
| 257 | - * @param User|null $logUser |
|
| 258 | - */ |
|
| 259 | - public static function closeRequest(PdoDatabase $database, Request $object, $target, $comment, User $logUser = null) |
|
| 260 | - { |
|
| 261 | - self::createLogEntry($database, $object, "Closed $target", $comment, $logUser); |
|
| 262 | - } |
|
| 263 | - |
|
| 264 | - /** |
|
| 265 | - * @param PdoDatabase $database |
|
| 266 | - * @param Request $object |
|
| 267 | - */ |
|
| 268 | - public static function reserve(PdoDatabase $database, Request $object) |
|
| 269 | - { |
|
| 270 | - self::createLogEntry($database, $object, "Reserved"); |
|
| 271 | - } |
|
| 272 | - |
|
| 273 | - /** |
|
| 274 | - * @param PdoDatabase $database |
|
| 275 | - * @param Request $object |
|
| 276 | - */ |
|
| 277 | - public static function breakReserve(PdoDatabase $database, Request $object) |
|
| 278 | - { |
|
| 279 | - self::createLogEntry($database, $object, "BreakReserve"); |
|
| 280 | - } |
|
| 281 | - |
|
| 282 | - /** |
|
| 283 | - * @param PdoDatabase $database |
|
| 284 | - * @param Request $object |
|
| 285 | - */ |
|
| 286 | - public static function unreserve(PdoDatabase $database, Request $object) |
|
| 287 | - { |
|
| 288 | - self::createLogEntry($database, $object, "Unreserved"); |
|
| 289 | - } |
|
| 290 | - |
|
| 291 | - /** |
|
| 292 | - * @param PdoDatabase $database |
|
| 293 | - * @param Comment $object |
|
| 294 | - * @param Request $request |
|
| 295 | - */ |
|
| 296 | - public static function editComment(PdoDatabase $database, Comment $object, Request $request) |
|
| 297 | - { |
|
| 298 | - self::createLogEntry($database, $request, "EditComment-r"); |
|
| 299 | - self::createLogEntry($database, $object, "EditComment-c"); |
|
| 300 | - } |
|
| 301 | - |
|
| 302 | - /** |
|
| 303 | - * @param PdoDatabase $database |
|
| 304 | - * @param Request $object |
|
| 305 | - * @param User $target |
|
| 306 | - */ |
|
| 307 | - public static function sendReservation(PdoDatabase $database, Request $object, User $target) |
|
| 308 | - { |
|
| 309 | - self::createLogEntry($database, $object, "SendReserved"); |
|
| 310 | - self::createLogEntry($database, $object, "ReceiveReserved", null, $target); |
|
| 311 | - } |
|
| 312 | - |
|
| 313 | - /** |
|
| 314 | - * @param PdoDatabase $database |
|
| 315 | - * @param Request $object |
|
| 316 | - * @param string $comment |
|
| 317 | - */ |
|
| 318 | - public static function sentMail(PdoDatabase $database, Request $object, $comment) |
|
| 319 | - { |
|
| 320 | - self::createLogEntry($database, $object, "SentMail", $comment); |
|
| 321 | - } |
|
| 322 | - |
|
| 323 | - /** |
|
| 324 | - * @param PdoDatabase $database |
|
| 325 | - * @param Request $object |
|
| 326 | - */ |
|
| 327 | - public static function enqueuedJobQueue(PdoDatabase $database, Request $object) |
|
| 328 | - { |
|
| 329 | - self::createLogEntry($database, $object, 'EnqueuedJobQueue'); |
|
| 330 | - } |
|
| 331 | - |
|
| 332 | - public static function hospitalised(PdoDatabase $database, Request $object) |
|
| 333 | - { |
|
| 334 | - self::createLogEntry($database, $object, 'Hospitalised'); |
|
| 335 | - } |
|
| 336 | - #endregion |
|
| 337 | - |
|
| 338 | - #region Email templates |
|
| 339 | - |
|
| 340 | - /** |
|
| 341 | - * @param PdoDatabase $database |
|
| 342 | - * @param EmailTemplate $object |
|
| 343 | - */ |
|
| 344 | - public static function createEmail(PdoDatabase $database, EmailTemplate $object) |
|
| 345 | - { |
|
| 346 | - self::createLogEntry($database, $object, "CreatedEmail"); |
|
| 347 | - } |
|
| 348 | - |
|
| 349 | - /** |
|
| 350 | - * @param PdoDatabase $database |
|
| 351 | - * @param EmailTemplate $object |
|
| 352 | - */ |
|
| 353 | - public static function editedEmail(PdoDatabase $database, EmailTemplate $object) |
|
| 354 | - { |
|
| 355 | - self::createLogEntry($database, $object, "EditedEmail"); |
|
| 356 | - } |
|
| 357 | - |
|
| 358 | - #endregion |
|
| 359 | - |
|
| 360 | - #region Display |
|
| 361 | - |
|
| 362 | - #endregion |
|
| 363 | - |
|
| 364 | - #region Automation |
|
| 365 | - |
|
| 366 | - public static function backgroundJobComplete(PdoDatabase $database, JobQueue $job) |
|
| 367 | - { |
|
| 368 | - self::createLogEntry($database, $job, 'JobCompleted', null, User::getCommunity()); |
|
| 369 | - } |
|
| 370 | - |
|
| 371 | - public static function backgroundJobIssue(PdoDatabase $database, JobQueue $job) |
|
| 372 | - { |
|
| 373 | - $data = array('status' => $job->getStatus(), 'error' => $job->getError()); |
|
| 374 | - self::createLogEntry($database, $job, 'JobIssue', serialize($data), User::getCommunity()); |
|
| 375 | - } |
|
| 376 | - |
|
| 377 | - public static function backgroundJobCancelled(PdoDatabase $database, JobQueue $job) |
|
| 378 | - { |
|
| 379 | - self::createLogEntry($database, $job, 'JobCancelled', $job->getError()); |
|
| 380 | - } |
|
| 381 | - |
|
| 382 | - public static function backgroundJobRequeued(PdoDatabase $database, JobQueue $job) |
|
| 383 | - { |
|
| 384 | - self::createLogEntry($database, $job, 'JobRequeued'); |
|
| 385 | - } |
|
| 386 | - |
|
| 387 | - public static function backgroundJobAcknowledged(PdoDatabase $database, JobQueue $job, $comment = null) |
|
| 388 | - { |
|
| 389 | - self::createLogEntry($database, $job, 'JobAcknowledged', $comment); |
|
| 390 | - } |
|
| 391 | - #endregion |
|
| 34 | + /** |
|
| 35 | + * @param PdoDatabase $database |
|
| 36 | + * @param Request $object |
|
| 37 | + */ |
|
| 38 | + public static function emailConfirmed(PdoDatabase $database, Request $object) |
|
| 39 | + { |
|
| 40 | + self::createLogEntry($database, $object, "Email Confirmed", null, User::getCommunity()); |
|
| 41 | + } |
|
| 42 | + |
|
| 43 | + /** |
|
| 44 | + * @param PdoDatabase $database |
|
| 45 | + * @param DataObject $object |
|
| 46 | + * @param string $logAction |
|
| 47 | + * @param null|string $comment |
|
| 48 | + * @param User $user |
|
| 49 | + * |
|
| 50 | + * @throws Exception |
|
| 51 | + */ |
|
| 52 | + private static function createLogEntry( |
|
| 53 | + PdoDatabase $database, |
|
| 54 | + DataObject $object, |
|
| 55 | + $logAction, |
|
| 56 | + $comment = null, |
|
| 57 | + $user = null |
|
| 58 | + ) { |
|
| 59 | + if ($user == null) { |
|
| 60 | + $user = User::getCurrent($database); |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + $objectType = get_class($object); |
|
| 64 | + if (strpos($objectType, 'Waca\\DataObjects\\') !== false) { |
|
| 65 | + $objectType = str_replace('Waca\\DataObjects\\', '', $objectType); |
|
| 66 | + } |
|
| 67 | + |
|
| 68 | + $log = new Log(); |
|
| 69 | + $log->setDatabase($database); |
|
| 70 | + $log->setAction($logAction); |
|
| 71 | + $log->setObjectId($object->getId()); |
|
| 72 | + $log->setObjectType($objectType); |
|
| 73 | + $log->setUser($user); |
|
| 74 | + $log->setComment($comment); |
|
| 75 | + $log->save(); |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + #region Users |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * @param PdoDatabase $database |
|
| 82 | + * @param User $user |
|
| 83 | + */ |
|
| 84 | + public static function newUser(PdoDatabase $database, User $user) |
|
| 85 | + { |
|
| 86 | + self::createLogEntry($database, $user, 'Registered', null, User::getCommunity()); |
|
| 87 | + } |
|
| 88 | + |
|
| 89 | + /** |
|
| 90 | + * @param PdoDatabase $database |
|
| 91 | + * @param User $object |
|
| 92 | + */ |
|
| 93 | + public static function approvedUser(PdoDatabase $database, User $object) |
|
| 94 | + { |
|
| 95 | + self::createLogEntry($database, $object, "Approved"); |
|
| 96 | + } |
|
| 97 | + |
|
| 98 | + /** |
|
| 99 | + * @param PdoDatabase $database |
|
| 100 | + * @param User $object |
|
| 101 | + * @param string $comment |
|
| 102 | + */ |
|
| 103 | + public static function declinedUser(PdoDatabase $database, User $object, $comment) |
|
| 104 | + { |
|
| 105 | + self::createLogEntry($database, $object, "Declined", $comment); |
|
| 106 | + } |
|
| 107 | + |
|
| 108 | + /** |
|
| 109 | + * @param PdoDatabase $database |
|
| 110 | + * @param User $object |
|
| 111 | + * @param string $comment |
|
| 112 | + */ |
|
| 113 | + public static function suspendedUser(PdoDatabase $database, User $object, $comment) |
|
| 114 | + { |
|
| 115 | + self::createLogEntry($database, $object, "Suspended", $comment); |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + /** |
|
| 119 | + * @param PdoDatabase $database |
|
| 120 | + * @param User $object |
|
| 121 | + * @param string $comment |
|
| 122 | + */ |
|
| 123 | + public static function demotedUser(PdoDatabase $database, User $object, $comment) |
|
| 124 | + { |
|
| 125 | + self::createLogEntry($database, $object, "Demoted", $comment); |
|
| 126 | + } |
|
| 127 | + |
|
| 128 | + /** |
|
| 129 | + * @param PdoDatabase $database |
|
| 130 | + * @param User $object |
|
| 131 | + */ |
|
| 132 | + public static function promotedUser(PdoDatabase $database, User $object) |
|
| 133 | + { |
|
| 134 | + self::createLogEntry($database, $object, "Promoted"); |
|
| 135 | + } |
|
| 136 | + |
|
| 137 | + /** |
|
| 138 | + * @param PdoDatabase $database |
|
| 139 | + * @param User $object |
|
| 140 | + * @param string $comment |
|
| 141 | + */ |
|
| 142 | + public static function renamedUser(PdoDatabase $database, User $object, $comment) |
|
| 143 | + { |
|
| 144 | + self::createLogEntry($database, $object, "Renamed", $comment); |
|
| 145 | + } |
|
| 146 | + |
|
| 147 | + /** |
|
| 148 | + * @param PdoDatabase $database |
|
| 149 | + * @param User $object |
|
| 150 | + */ |
|
| 151 | + public static function userPreferencesChange(PdoDatabase $database, User $object) |
|
| 152 | + { |
|
| 153 | + self::createLogEntry($database, $object, "Prefchange"); |
|
| 154 | + } |
|
| 155 | + |
|
| 156 | + /** |
|
| 157 | + * @param PdoDatabase $database |
|
| 158 | + * @param User $object |
|
| 159 | + * @param string $reason |
|
| 160 | + * @param array $added |
|
| 161 | + * @param array $removed |
|
| 162 | + */ |
|
| 163 | + public static function userRolesEdited(PdoDatabase $database, User $object, $reason, $added, $removed) |
|
| 164 | + { |
|
| 165 | + $logData = serialize(array( |
|
| 166 | + 'added' => $added, |
|
| 167 | + 'removed' => $removed, |
|
| 168 | + 'reason' => $reason, |
|
| 169 | + )); |
|
| 170 | + |
|
| 171 | + self::createLogEntry($database, $object, "RoleChange", $logData); |
|
| 172 | + } |
|
| 173 | + |
|
| 174 | + #endregion |
|
| 175 | + |
|
| 176 | + /** |
|
| 177 | + * @param PdoDatabase $database |
|
| 178 | + * @param SiteNotice $object |
|
| 179 | + */ |
|
| 180 | + public static function siteNoticeEdited(PdoDatabase $database, SiteNotice $object) |
|
| 181 | + { |
|
| 182 | + self::createLogEntry($database, $object, "Edited"); |
|
| 183 | + } |
|
| 184 | + |
|
| 185 | + #region Welcome Templates |
|
| 186 | + |
|
| 187 | + /** |
|
| 188 | + * @param PdoDatabase $database |
|
| 189 | + * @param WelcomeTemplate $object |
|
| 190 | + */ |
|
| 191 | + public static function welcomeTemplateCreated(PdoDatabase $database, WelcomeTemplate $object) |
|
| 192 | + { |
|
| 193 | + self::createLogEntry($database, $object, "CreatedTemplate"); |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + /** |
|
| 197 | + * @param PdoDatabase $database |
|
| 198 | + * @param WelcomeTemplate $object |
|
| 199 | + */ |
|
| 200 | + public static function welcomeTemplateEdited(PdoDatabase $database, WelcomeTemplate $object) |
|
| 201 | + { |
|
| 202 | + self::createLogEntry($database, $object, "EditedTemplate"); |
|
| 203 | + } |
|
| 204 | + |
|
| 205 | + /** |
|
| 206 | + * @param PdoDatabase $database |
|
| 207 | + * @param WelcomeTemplate $object |
|
| 208 | + */ |
|
| 209 | + public static function welcomeTemplateDeleted(PdoDatabase $database, WelcomeTemplate $object) |
|
| 210 | + { |
|
| 211 | + self::createLogEntry($database, $object, "DeletedTemplate"); |
|
| 212 | + } |
|
| 213 | + |
|
| 214 | + #endregion |
|
| 215 | + |
|
| 216 | + #region Bans |
|
| 217 | + |
|
| 218 | + /** |
|
| 219 | + * @param PdoDatabase $database |
|
| 220 | + * @param Ban $object |
|
| 221 | + * @param string $reason |
|
| 222 | + */ |
|
| 223 | + public static function banned(PdoDatabase $database, Ban $object, $reason) |
|
| 224 | + { |
|
| 225 | + self::createLogEntry($database, $object, "Banned", $reason); |
|
| 226 | + } |
|
| 227 | + |
|
| 228 | + /** |
|
| 229 | + * @param PdoDatabase $database |
|
| 230 | + * @param Ban $object |
|
| 231 | + * @param string $reason |
|
| 232 | + */ |
|
| 233 | + public static function unbanned(PdoDatabase $database, Ban $object, $reason) |
|
| 234 | + { |
|
| 235 | + self::createLogEntry($database, $object, "Unbanned", $reason); |
|
| 236 | + } |
|
| 237 | + |
|
| 238 | + #endregion |
|
| 239 | + |
|
| 240 | + #region Requests |
|
| 241 | + |
|
| 242 | + /** |
|
| 243 | + * @param PdoDatabase $database |
|
| 244 | + * @param Request $object |
|
| 245 | + * @param string $target |
|
| 246 | + */ |
|
| 247 | + public static function deferRequest(PdoDatabase $database, Request $object, $target) |
|
| 248 | + { |
|
| 249 | + self::createLogEntry($database, $object, "Deferred to $target"); |
|
| 250 | + } |
|
| 251 | + |
|
| 252 | + /** |
|
| 253 | + * @param PdoDatabase $database |
|
| 254 | + * @param Request $object |
|
| 255 | + * @param integer $target |
|
| 256 | + * @param string $comment |
|
| 257 | + * @param User|null $logUser |
|
| 258 | + */ |
|
| 259 | + public static function closeRequest(PdoDatabase $database, Request $object, $target, $comment, User $logUser = null) |
|
| 260 | + { |
|
| 261 | + self::createLogEntry($database, $object, "Closed $target", $comment, $logUser); |
|
| 262 | + } |
|
| 263 | + |
|
| 264 | + /** |
|
| 265 | + * @param PdoDatabase $database |
|
| 266 | + * @param Request $object |
|
| 267 | + */ |
|
| 268 | + public static function reserve(PdoDatabase $database, Request $object) |
|
| 269 | + { |
|
| 270 | + self::createLogEntry($database, $object, "Reserved"); |
|
| 271 | + } |
|
| 272 | + |
|
| 273 | + /** |
|
| 274 | + * @param PdoDatabase $database |
|
| 275 | + * @param Request $object |
|
| 276 | + */ |
|
| 277 | + public static function breakReserve(PdoDatabase $database, Request $object) |
|
| 278 | + { |
|
| 279 | + self::createLogEntry($database, $object, "BreakReserve"); |
|
| 280 | + } |
|
| 281 | + |
|
| 282 | + /** |
|
| 283 | + * @param PdoDatabase $database |
|
| 284 | + * @param Request $object |
|
| 285 | + */ |
|
| 286 | + public static function unreserve(PdoDatabase $database, Request $object) |
|
| 287 | + { |
|
| 288 | + self::createLogEntry($database, $object, "Unreserved"); |
|
| 289 | + } |
|
| 290 | + |
|
| 291 | + /** |
|
| 292 | + * @param PdoDatabase $database |
|
| 293 | + * @param Comment $object |
|
| 294 | + * @param Request $request |
|
| 295 | + */ |
|
| 296 | + public static function editComment(PdoDatabase $database, Comment $object, Request $request) |
|
| 297 | + { |
|
| 298 | + self::createLogEntry($database, $request, "EditComment-r"); |
|
| 299 | + self::createLogEntry($database, $object, "EditComment-c"); |
|
| 300 | + } |
|
| 301 | + |
|
| 302 | + /** |
|
| 303 | + * @param PdoDatabase $database |
|
| 304 | + * @param Request $object |
|
| 305 | + * @param User $target |
|
| 306 | + */ |
|
| 307 | + public static function sendReservation(PdoDatabase $database, Request $object, User $target) |
|
| 308 | + { |
|
| 309 | + self::createLogEntry($database, $object, "SendReserved"); |
|
| 310 | + self::createLogEntry($database, $object, "ReceiveReserved", null, $target); |
|
| 311 | + } |
|
| 312 | + |
|
| 313 | + /** |
|
| 314 | + * @param PdoDatabase $database |
|
| 315 | + * @param Request $object |
|
| 316 | + * @param string $comment |
|
| 317 | + */ |
|
| 318 | + public static function sentMail(PdoDatabase $database, Request $object, $comment) |
|
| 319 | + { |
|
| 320 | + self::createLogEntry($database, $object, "SentMail", $comment); |
|
| 321 | + } |
|
| 322 | + |
|
| 323 | + /** |
|
| 324 | + * @param PdoDatabase $database |
|
| 325 | + * @param Request $object |
|
| 326 | + */ |
|
| 327 | + public static function enqueuedJobQueue(PdoDatabase $database, Request $object) |
|
| 328 | + { |
|
| 329 | + self::createLogEntry($database, $object, 'EnqueuedJobQueue'); |
|
| 330 | + } |
|
| 331 | + |
|
| 332 | + public static function hospitalised(PdoDatabase $database, Request $object) |
|
| 333 | + { |
|
| 334 | + self::createLogEntry($database, $object, 'Hospitalised'); |
|
| 335 | + } |
|
| 336 | + #endregion |
|
| 337 | + |
|
| 338 | + #region Email templates |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * @param PdoDatabase $database |
|
| 342 | + * @param EmailTemplate $object |
|
| 343 | + */ |
|
| 344 | + public static function createEmail(PdoDatabase $database, EmailTemplate $object) |
|
| 345 | + { |
|
| 346 | + self::createLogEntry($database, $object, "CreatedEmail"); |
|
| 347 | + } |
|
| 348 | + |
|
| 349 | + /** |
|
| 350 | + * @param PdoDatabase $database |
|
| 351 | + * @param EmailTemplate $object |
|
| 352 | + */ |
|
| 353 | + public static function editedEmail(PdoDatabase $database, EmailTemplate $object) |
|
| 354 | + { |
|
| 355 | + self::createLogEntry($database, $object, "EditedEmail"); |
|
| 356 | + } |
|
| 357 | + |
|
| 358 | + #endregion |
|
| 359 | + |
|
| 360 | + #region Display |
|
| 361 | + |
|
| 362 | + #endregion |
|
| 363 | + |
|
| 364 | + #region Automation |
|
| 365 | + |
|
| 366 | + public static function backgroundJobComplete(PdoDatabase $database, JobQueue $job) |
|
| 367 | + { |
|
| 368 | + self::createLogEntry($database, $job, 'JobCompleted', null, User::getCommunity()); |
|
| 369 | + } |
|
| 370 | + |
|
| 371 | + public static function backgroundJobIssue(PdoDatabase $database, JobQueue $job) |
|
| 372 | + { |
|
| 373 | + $data = array('status' => $job->getStatus(), 'error' => $job->getError()); |
|
| 374 | + self::createLogEntry($database, $job, 'JobIssue', serialize($data), User::getCommunity()); |
|
| 375 | + } |
|
| 376 | + |
|
| 377 | + public static function backgroundJobCancelled(PdoDatabase $database, JobQueue $job) |
|
| 378 | + { |
|
| 379 | + self::createLogEntry($database, $job, 'JobCancelled', $job->getError()); |
|
| 380 | + } |
|
| 381 | + |
|
| 382 | + public static function backgroundJobRequeued(PdoDatabase $database, JobQueue $job) |
|
| 383 | + { |
|
| 384 | + self::createLogEntry($database, $job, 'JobRequeued'); |
|
| 385 | + } |
|
| 386 | + |
|
| 387 | + public static function backgroundJobAcknowledged(PdoDatabase $database, JobQueue $job, $comment = null) |
|
| 388 | + { |
|
| 389 | + self::createLogEntry($database, $job, 'JobAcknowledged', $comment); |
|
| 390 | + } |
|
| 391 | + #endregion |
|
| 392 | 392 | } |
@@ -16,135 +16,135 @@ |
||
| 16 | 16 | |
| 17 | 17 | class BotMediaWikiClient implements IMediaWikiClient |
| 18 | 18 | { |
| 19 | - /** |
|
| 20 | - * @var HttpHelper |
|
| 21 | - */ |
|
| 22 | - private $httpHelper; |
|
| 23 | - /** @var string */ |
|
| 24 | - private $mediawikiWebServiceEndpoint; |
|
| 25 | - /** @var string */ |
|
| 26 | - private $creationBotUsername; |
|
| 27 | - /** @var string */ |
|
| 28 | - private $creationBotPassword; |
|
| 29 | - /** @var bool */ |
|
| 30 | - private $knownLoggedIn = false; |
|
| 31 | - |
|
| 32 | - /** |
|
| 33 | - * BotMediaWikiClient constructor. |
|
| 34 | - * |
|
| 35 | - * @param SiteConfiguration $siteConfiguration |
|
| 36 | - */ |
|
| 37 | - public function __construct(SiteConfiguration $siteConfiguration) |
|
| 38 | - { |
|
| 39 | - $this->mediawikiWebServiceEndpoint = $siteConfiguration->getMediawikiWebServiceEndpoint(); |
|
| 40 | - |
|
| 41 | - $this->creationBotUsername = $siteConfiguration->getCreationBotUsername(); |
|
| 42 | - $this->creationBotPassword = $siteConfiguration->getCreationBotPassword(); |
|
| 43 | - |
|
| 44 | - $this->httpHelper = new HttpHelper( |
|
| 45 | - $siteConfiguration, |
|
| 46 | - $siteConfiguration->getCurlCookieJar() |
|
| 47 | - ); |
|
| 48 | - } |
|
| 49 | - |
|
| 50 | - public function doApiCall($apiParams, $method = 'GET') |
|
| 51 | - { |
|
| 52 | - $this->ensureLoggedIn(); |
|
| 53 | - $apiParams['assert'] = 'user'; |
|
| 54 | - |
|
| 55 | - return $this->callApi($apiParams, $method); |
|
| 56 | - } |
|
| 57 | - |
|
| 58 | - private function ensureLoggedIn() |
|
| 59 | - { |
|
| 60 | - if ($this->knownLoggedIn) { |
|
| 61 | - return; |
|
| 62 | - } |
|
| 63 | - |
|
| 64 | - $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET'); |
|
| 65 | - if (isset($userinfoResult->query->userinfo->anon)) { |
|
| 66 | - // not logged in. |
|
| 67 | - $this->logIn(); |
|
| 68 | - |
|
| 69 | - // retest |
|
| 70 | - $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET'); |
|
| 71 | - if (isset($userinfoResult->query->userinfo->anon)) { |
|
| 72 | - throw new MediaWikiApiException('Unable to log in.'); |
|
| 73 | - } |
|
| 74 | - else { |
|
| 75 | - $this->knownLoggedIn = true; |
|
| 76 | - } |
|
| 77 | - } |
|
| 78 | - else { |
|
| 79 | - $this->knownLoggedIn = true; |
|
| 80 | - } |
|
| 81 | - } |
|
| 82 | - |
|
| 83 | - /** |
|
| 84 | - * @param $apiParams |
|
| 85 | - * @param $method |
|
| 86 | - * |
|
| 87 | - * @return mixed |
|
| 88 | - * @throws ApplicationLogicException |
|
| 89 | - * @throws CurlException |
|
| 90 | - */ |
|
| 91 | - private function callApi($apiParams, $method) |
|
| 92 | - { |
|
| 93 | - $apiParams['format'] = 'json'; |
|
| 94 | - |
|
| 95 | - if ($method == 'GET') { |
|
| 96 | - $data = $this->httpHelper->get($this->mediawikiWebServiceEndpoint, $apiParams); |
|
| 97 | - } |
|
| 98 | - elseif ($method == 'POST') { |
|
| 99 | - $data = $this->httpHelper->post($this->mediawikiWebServiceEndpoint, $apiParams); |
|
| 100 | - } |
|
| 101 | - else { |
|
| 102 | - throw new ApplicationLogicException('Unsupported HTTP Method'); |
|
| 103 | - } |
|
| 104 | - |
|
| 105 | - if ($data === false) { |
|
| 106 | - throw new CurlException('Curl error: ' . $this->httpHelper->getError()); |
|
| 107 | - } |
|
| 108 | - |
|
| 109 | - $result = json_decode($data); |
|
| 110 | - |
|
| 111 | - return $result; |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - private function logIn() |
|
| 115 | - { |
|
| 116 | - // get token |
|
| 117 | - $tokenParams = array( |
|
| 118 | - 'action' => 'query', |
|
| 119 | - 'meta' => 'tokens', |
|
| 120 | - 'type' => 'login', |
|
| 121 | - ); |
|
| 122 | - |
|
| 123 | - $response = $this->callApi($tokenParams, 'POST'); |
|
| 124 | - |
|
| 125 | - if (isset($response->error)) { |
|
| 126 | - throw new MediaWikiApiException($response->error->code . ': ' . $response->error->info); |
|
| 127 | - } |
|
| 128 | - |
|
| 129 | - $token = $response->query->tokens->logintoken; |
|
| 130 | - |
|
| 131 | - if ($token === null) { |
|
| 132 | - throw new MediaWikiApiException('Edit token could not be acquired'); |
|
| 133 | - } |
|
| 134 | - |
|
| 135 | - $params = array( |
|
| 136 | - 'action' => 'login', |
|
| 137 | - 'lgname' => $this->creationBotUsername, |
|
| 138 | - 'lgpassword' => $this->creationBotPassword, |
|
| 139 | - 'lgtoken' => $token, |
|
| 140 | - ); |
|
| 141 | - |
|
| 142 | - $loginResponse = $this->callApi($params, 'POST'); |
|
| 143 | - |
|
| 144 | - if ($loginResponse->login->result == 'Success') { |
|
| 145 | - return; |
|
| 146 | - } |
|
| 147 | - |
|
| 148 | - throw new ApplicationLogicException(json_encode($loginResponse)); |
|
| 149 | - } |
|
| 19 | + /** |
|
| 20 | + * @var HttpHelper |
|
| 21 | + */ |
|
| 22 | + private $httpHelper; |
|
| 23 | + /** @var string */ |
|
| 24 | + private $mediawikiWebServiceEndpoint; |
|
| 25 | + /** @var string */ |
|
| 26 | + private $creationBotUsername; |
|
| 27 | + /** @var string */ |
|
| 28 | + private $creationBotPassword; |
|
| 29 | + /** @var bool */ |
|
| 30 | + private $knownLoggedIn = false; |
|
| 31 | + |
|
| 32 | + /** |
|
| 33 | + * BotMediaWikiClient constructor. |
|
| 34 | + * |
|
| 35 | + * @param SiteConfiguration $siteConfiguration |
|
| 36 | + */ |
|
| 37 | + public function __construct(SiteConfiguration $siteConfiguration) |
|
| 38 | + { |
|
| 39 | + $this->mediawikiWebServiceEndpoint = $siteConfiguration->getMediawikiWebServiceEndpoint(); |
|
| 40 | + |
|
| 41 | + $this->creationBotUsername = $siteConfiguration->getCreationBotUsername(); |
|
| 42 | + $this->creationBotPassword = $siteConfiguration->getCreationBotPassword(); |
|
| 43 | + |
|
| 44 | + $this->httpHelper = new HttpHelper( |
|
| 45 | + $siteConfiguration, |
|
| 46 | + $siteConfiguration->getCurlCookieJar() |
|
| 47 | + ); |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + public function doApiCall($apiParams, $method = 'GET') |
|
| 51 | + { |
|
| 52 | + $this->ensureLoggedIn(); |
|
| 53 | + $apiParams['assert'] = 'user'; |
|
| 54 | + |
|
| 55 | + return $this->callApi($apiParams, $method); |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + private function ensureLoggedIn() |
|
| 59 | + { |
|
| 60 | + if ($this->knownLoggedIn) { |
|
| 61 | + return; |
|
| 62 | + } |
|
| 63 | + |
|
| 64 | + $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET'); |
|
| 65 | + if (isset($userinfoResult->query->userinfo->anon)) { |
|
| 66 | + // not logged in. |
|
| 67 | + $this->logIn(); |
|
| 68 | + |
|
| 69 | + // retest |
|
| 70 | + $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET'); |
|
| 71 | + if (isset($userinfoResult->query->userinfo->anon)) { |
|
| 72 | + throw new MediaWikiApiException('Unable to log in.'); |
|
| 73 | + } |
|
| 74 | + else { |
|
| 75 | + $this->knownLoggedIn = true; |
|
| 76 | + } |
|
| 77 | + } |
|
| 78 | + else { |
|
| 79 | + $this->knownLoggedIn = true; |
|
| 80 | + } |
|
| 81 | + } |
|
| 82 | + |
|
| 83 | + /** |
|
| 84 | + * @param $apiParams |
|
| 85 | + * @param $method |
|
| 86 | + * |
|
| 87 | + * @return mixed |
|
| 88 | + * @throws ApplicationLogicException |
|
| 89 | + * @throws CurlException |
|
| 90 | + */ |
|
| 91 | + private function callApi($apiParams, $method) |
|
| 92 | + { |
|
| 93 | + $apiParams['format'] = 'json'; |
|
| 94 | + |
|
| 95 | + if ($method == 'GET') { |
|
| 96 | + $data = $this->httpHelper->get($this->mediawikiWebServiceEndpoint, $apiParams); |
|
| 97 | + } |
|
| 98 | + elseif ($method == 'POST') { |
|
| 99 | + $data = $this->httpHelper->post($this->mediawikiWebServiceEndpoint, $apiParams); |
|
| 100 | + } |
|
| 101 | + else { |
|
| 102 | + throw new ApplicationLogicException('Unsupported HTTP Method'); |
|
| 103 | + } |
|
| 104 | + |
|
| 105 | + if ($data === false) { |
|
| 106 | + throw new CurlException('Curl error: ' . $this->httpHelper->getError()); |
|
| 107 | + } |
|
| 108 | + |
|
| 109 | + $result = json_decode($data); |
|
| 110 | + |
|
| 111 | + return $result; |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + private function logIn() |
|
| 115 | + { |
|
| 116 | + // get token |
|
| 117 | + $tokenParams = array( |
|
| 118 | + 'action' => 'query', |
|
| 119 | + 'meta' => 'tokens', |
|
| 120 | + 'type' => 'login', |
|
| 121 | + ); |
|
| 122 | + |
|
| 123 | + $response = $this->callApi($tokenParams, 'POST'); |
|
| 124 | + |
|
| 125 | + if (isset($response->error)) { |
|
| 126 | + throw new MediaWikiApiException($response->error->code . ': ' . $response->error->info); |
|
| 127 | + } |
|
| 128 | + |
|
| 129 | + $token = $response->query->tokens->logintoken; |
|
| 130 | + |
|
| 131 | + if ($token === null) { |
|
| 132 | + throw new MediaWikiApiException('Edit token could not be acquired'); |
|
| 133 | + } |
|
| 134 | + |
|
| 135 | + $params = array( |
|
| 136 | + 'action' => 'login', |
|
| 137 | + 'lgname' => $this->creationBotUsername, |
|
| 138 | + 'lgpassword' => $this->creationBotPassword, |
|
| 139 | + 'lgtoken' => $token, |
|
| 140 | + ); |
|
| 141 | + |
|
| 142 | + $loginResponse = $this->callApi($params, 'POST'); |
|
| 143 | + |
|
| 144 | + if ($loginResponse->login->result == 'Success') { |
|
| 145 | + return; |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + throw new ApplicationLogicException(json_encode($loginResponse)); |
|
| 149 | + } |
|
| 150 | 150 | } |
@@ -13,21 +13,21 @@ |
||
| 13 | 13 | |
| 14 | 14 | interface IBanHelper |
| 15 | 15 | { |
| 16 | - /** |
|
| 17 | - * @param Request $request |
|
| 18 | - * |
|
| 19 | - * @return bool |
|
| 20 | - */ |
|
| 21 | - public function isBlockBanned(Request $request): bool; |
|
| 16 | + /** |
|
| 17 | + * @param Request $request |
|
| 18 | + * |
|
| 19 | + * @return bool |
|
| 20 | + */ |
|
| 21 | + public function isBlockBanned(Request $request): bool; |
|
| 22 | 22 | |
| 23 | - /** |
|
| 24 | - * @param Request $request |
|
| 25 | - * |
|
| 26 | - * @return Ban[] |
|
| 27 | - */ |
|
| 28 | - public function getBans(Request $request): array; |
|
| 23 | + /** |
|
| 24 | + * @param Request $request |
|
| 25 | + * |
|
| 26 | + * @return Ban[] |
|
| 27 | + */ |
|
| 28 | + public function getBans(Request $request): array; |
|
| 29 | 29 | |
| 30 | - public function canUnban(Ban $ban): bool; |
|
| 30 | + public function canUnban(Ban $ban): bool; |
|
| 31 | 31 | |
| 32 | - public function isActive(Ban $ban): bool; |
|
| 32 | + public function isActive(Ban $ban): bool; |
|
| 33 | 33 | } |
@@ -25,460 +25,460 @@ |
||
| 25 | 25 | |
| 26 | 26 | class OAuthUserHelper implements IMediaWikiClient |
| 27 | 27 | { |
| 28 | - const TOKEN_REQUEST = 'request'; |
|
| 29 | - const TOKEN_ACCESS = 'access'; |
|
| 30 | - /** @var PDOStatement */ |
|
| 31 | - private static $tokenCountStatement = null; |
|
| 32 | - /** @var PDOStatement */ |
|
| 33 | - private $getTokenStatement; |
|
| 34 | - /** |
|
| 35 | - * @var User |
|
| 36 | - */ |
|
| 37 | - private $user; |
|
| 38 | - /** |
|
| 39 | - * @var PdoDatabase |
|
| 40 | - */ |
|
| 41 | - private $database; |
|
| 42 | - /** |
|
| 43 | - * @var IOAuthProtocolHelper |
|
| 44 | - */ |
|
| 45 | - private $oauthProtocolHelper; |
|
| 46 | - /** |
|
| 47 | - * @var bool|null Is the user linked to OAuth |
|
| 48 | - */ |
|
| 49 | - private $linked; |
|
| 50 | - private $partiallyLinked; |
|
| 51 | - /** @var OAuthToken */ |
|
| 52 | - private $accessToken; |
|
| 53 | - /** @var bool */ |
|
| 54 | - private $accessTokenLoaded = false; |
|
| 55 | - /** |
|
| 56 | - * @var OAuthIdentity |
|
| 57 | - */ |
|
| 58 | - private $identity = null; |
|
| 59 | - /** |
|
| 60 | - * @var bool |
|
| 61 | - */ |
|
| 62 | - private $identityLoaded = false; |
|
| 63 | - /** |
|
| 64 | - * @var SiteConfiguration |
|
| 65 | - */ |
|
| 66 | - private $siteConfiguration; |
|
| 67 | - |
|
| 68 | - private $legacyTokens; |
|
| 69 | - |
|
| 70 | - #region Static methods |
|
| 71 | - |
|
| 72 | - public static function findUserByRequestToken($requestToken, PdoDatabase $database) |
|
| 73 | - { |
|
| 74 | - $statement = $database->prepare(<<<'SQL' |
|
| 28 | + const TOKEN_REQUEST = 'request'; |
|
| 29 | + const TOKEN_ACCESS = 'access'; |
|
| 30 | + /** @var PDOStatement */ |
|
| 31 | + private static $tokenCountStatement = null; |
|
| 32 | + /** @var PDOStatement */ |
|
| 33 | + private $getTokenStatement; |
|
| 34 | + /** |
|
| 35 | + * @var User |
|
| 36 | + */ |
|
| 37 | + private $user; |
|
| 38 | + /** |
|
| 39 | + * @var PdoDatabase |
|
| 40 | + */ |
|
| 41 | + private $database; |
|
| 42 | + /** |
|
| 43 | + * @var IOAuthProtocolHelper |
|
| 44 | + */ |
|
| 45 | + private $oauthProtocolHelper; |
|
| 46 | + /** |
|
| 47 | + * @var bool|null Is the user linked to OAuth |
|
| 48 | + */ |
|
| 49 | + private $linked; |
|
| 50 | + private $partiallyLinked; |
|
| 51 | + /** @var OAuthToken */ |
|
| 52 | + private $accessToken; |
|
| 53 | + /** @var bool */ |
|
| 54 | + private $accessTokenLoaded = false; |
|
| 55 | + /** |
|
| 56 | + * @var OAuthIdentity |
|
| 57 | + */ |
|
| 58 | + private $identity = null; |
|
| 59 | + /** |
|
| 60 | + * @var bool |
|
| 61 | + */ |
|
| 62 | + private $identityLoaded = false; |
|
| 63 | + /** |
|
| 64 | + * @var SiteConfiguration |
|
| 65 | + */ |
|
| 66 | + private $siteConfiguration; |
|
| 67 | + |
|
| 68 | + private $legacyTokens; |
|
| 69 | + |
|
| 70 | + #region Static methods |
|
| 71 | + |
|
| 72 | + public static function findUserByRequestToken($requestToken, PdoDatabase $database) |
|
| 73 | + { |
|
| 74 | + $statement = $database->prepare(<<<'SQL' |
|
| 75 | 75 | SELECT u.* FROM user u |
| 76 | 76 | INNER JOIN oauthtoken t ON t.user = u.id |
| 77 | 77 | WHERE t.type = :type AND t.token = :token |
| 78 | 78 | SQL |
| 79 | - ); |
|
| 80 | - $statement->execute(array(':type' => self::TOKEN_REQUEST, ':token' => $requestToken)); |
|
| 81 | - |
|
| 82 | - /** @var User $user */ |
|
| 83 | - $user = $statement->fetchObject(User::class); |
|
| 84 | - $statement->closeCursor(); |
|
| 85 | - |
|
| 86 | - if ($user === false) { |
|
| 87 | - throw new ApplicationLogicException('Token not found in store, please try again'); |
|
| 88 | - } |
|
| 89 | - |
|
| 90 | - $user->setDatabase($database); |
|
| 91 | - |
|
| 92 | - return $user; |
|
| 93 | - } |
|
| 94 | - |
|
| 95 | - public static function userIsFullyLinked(User $user, PdoDatabase $database = null) |
|
| 96 | - { |
|
| 97 | - if (self::$tokenCountStatement === null && $database === null) { |
|
| 98 | - throw new ApplicationLogicException('Static link request without initialised statement'); |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - return self::runTokenCount($user->getId(), $database, self::TOKEN_ACCESS); |
|
| 102 | - } |
|
| 103 | - |
|
| 104 | - public static function userIsPartiallyLinked(User $user, PdoDatabase $database = null) |
|
| 105 | - { |
|
| 106 | - if (self::$tokenCountStatement === null && $database === null) { |
|
| 107 | - throw new ApplicationLogicException('Static link request without initialised statement'); |
|
| 108 | - } |
|
| 109 | - |
|
| 110 | - if (self::userIsFullyLinked($user, $database)) { |
|
| 111 | - return false; |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - return self::runTokenCount($user->getId(), $database, self::TOKEN_REQUEST) |
|
| 115 | - || $user->getOnWikiName() == null; |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - /** |
|
| 119 | - * @param PdoDatabase $database |
|
| 120 | - */ |
|
| 121 | - public static function prepareTokenCountStatement(PdoDatabase $database) |
|
| 122 | - { |
|
| 123 | - if (self::$tokenCountStatement === null) { |
|
| 124 | - self::$tokenCountStatement = $database->prepare('SELECT COUNT(*) FROM oauthtoken WHERE user = :user AND type = :type'); |
|
| 125 | - } |
|
| 126 | - } |
|
| 127 | - |
|
| 128 | - private static function runTokenCount($userId, $database, $tokenType) |
|
| 129 | - { |
|
| 130 | - if (self::$tokenCountStatement === null) { |
|
| 131 | - self::prepareTokenCountStatement($database); |
|
| 132 | - } |
|
| 133 | - |
|
| 134 | - self::$tokenCountStatement->execute(array( |
|
| 135 | - ':user' => $userId, |
|
| 136 | - ':type' => $tokenType, |
|
| 137 | - )); |
|
| 138 | - |
|
| 139 | - $tokenCount = self::$tokenCountStatement->fetchColumn(); |
|
| 140 | - $linked = $tokenCount > 0; |
|
| 141 | - self::$tokenCountStatement->closeCursor(); |
|
| 142 | - |
|
| 143 | - return $linked; |
|
| 144 | - } |
|
| 145 | - |
|
| 146 | - #endregion Static methods |
|
| 147 | - |
|
| 148 | - /** |
|
| 149 | - * OAuthUserHelper constructor. |
|
| 150 | - * |
|
| 151 | - * @param User $user |
|
| 152 | - * @param PdoDatabase $database |
|
| 153 | - * @param IOAuthProtocolHelper $oauthProtocolHelper |
|
| 154 | - * @param SiteConfiguration $siteConfiguration |
|
| 155 | - */ |
|
| 156 | - public function __construct( |
|
| 157 | - User $user, |
|
| 158 | - PdoDatabase $database, |
|
| 159 | - IOAuthProtocolHelper $oauthProtocolHelper, |
|
| 160 | - SiteConfiguration $siteConfiguration |
|
| 161 | - ) { |
|
| 162 | - $this->user = $user; |
|
| 163 | - $this->database = $database; |
|
| 164 | - $this->oauthProtocolHelper = $oauthProtocolHelper; |
|
| 165 | - |
|
| 166 | - $this->linked = null; |
|
| 167 | - $this->partiallyLinked = null; |
|
| 168 | - $this->siteConfiguration = $siteConfiguration; |
|
| 169 | - |
|
| 170 | - self::prepareTokenCountStatement($database); |
|
| 171 | - $this->getTokenStatement = $this->database->prepare('SELECT * FROM oauthtoken WHERE user = :user AND type = :type'); |
|
| 172 | - |
|
| 173 | - $this->legacyTokens = $this->siteConfiguration->getOauthLegacyConsumerTokens(); |
|
| 174 | - } |
|
| 175 | - |
|
| 176 | - /** |
|
| 177 | - * Determines if the user is fully connected to OAuth. |
|
| 178 | - * |
|
| 179 | - * @return bool |
|
| 180 | - */ |
|
| 181 | - public function isFullyLinked() |
|
| 182 | - { |
|
| 183 | - if ($this->linked === null) { |
|
| 184 | - $this->linked = self::userIsFullyLinked($this->user, $this->database); |
|
| 185 | - } |
|
| 186 | - |
|
| 187 | - return $this->linked; |
|
| 188 | - } |
|
| 189 | - |
|
| 190 | - /** |
|
| 191 | - * Attempts to figure out if a user is partially linked to OAuth, and therefore needs to complete the OAuth |
|
| 192 | - * procedure before configuring. |
|
| 193 | - * @return bool |
|
| 194 | - */ |
|
| 195 | - public function isPartiallyLinked() |
|
| 196 | - { |
|
| 197 | - if ($this->partiallyLinked === null) { |
|
| 198 | - $this->partiallyLinked = self::userIsPartiallyLinked($this->user, $this->database); |
|
| 199 | - } |
|
| 200 | - |
|
| 201 | - return $this->partiallyLinked; |
|
| 202 | - } |
|
| 203 | - |
|
| 204 | - public function canCreateAccount() |
|
| 205 | - { |
|
| 206 | - return $this->isFullyLinked() |
|
| 207 | - && $this->getIdentity(true)->getGrantBasic() |
|
| 208 | - && $this->getIdentity(true)->getGrantHighVolume() |
|
| 209 | - && $this->getIdentity(true)->getGrantCreateAccount(); |
|
| 210 | - } |
|
| 211 | - |
|
| 212 | - public function canWelcome() |
|
| 213 | - { |
|
| 214 | - return $this->isFullyLinked() |
|
| 215 | - && $this->getIdentity(true)->getGrantBasic() |
|
| 216 | - && $this->getIdentity(true)->getGrantHighVolume() |
|
| 217 | - && $this->getIdentity(true)->getGrantCreateEditMovePage(); |
|
| 218 | - } |
|
| 219 | - |
|
| 220 | - /** |
|
| 221 | - * @throws OAuthException |
|
| 222 | - * @throws CurlException |
|
| 223 | - * @throws OptimisticLockFailedException |
|
| 224 | - * @throws Exception |
|
| 225 | - */ |
|
| 226 | - public function refreshIdentity() |
|
| 227 | - { |
|
| 228 | - $this->loadIdentity(); |
|
| 229 | - |
|
| 230 | - if ($this->identity === null) { |
|
| 231 | - $this->identity = new OAuthIdentity(); |
|
| 232 | - $this->identity->setUserId($this->user->getId()); |
|
| 233 | - $this->identity->setDatabase($this->database); |
|
| 234 | - } |
|
| 235 | - |
|
| 236 | - $token = $this->loadAccessToken(); |
|
| 237 | - |
|
| 238 | - try { |
|
| 239 | - $rawTicket = $this->oauthProtocolHelper->getIdentityTicket($token->getToken(), $token->getSecret()); |
|
| 240 | - } |
|
| 241 | - catch (Exception $ex) { |
|
| 242 | - if (strpos($ex->getMessage(), "mwoauthdatastore-access-token-not-found") !== false) { |
|
| 243 | - throw new OAuthException('No approved grants for this access token.', -1, $ex); |
|
| 244 | - } |
|
| 245 | - |
|
| 246 | - throw $ex; |
|
| 247 | - } |
|
| 248 | - |
|
| 249 | - $this->identity->populate($rawTicket); |
|
| 250 | - |
|
| 251 | - if (!$this->identityIsValid()) { |
|
| 252 | - throw new OAuthException('Identity ticket is not valid!'); |
|
| 253 | - } |
|
| 254 | - |
|
| 255 | - $this->identity->save(); |
|
| 256 | - |
|
| 257 | - $this->user->setOnWikiName($this->identity->getUsername()); |
|
| 258 | - $this->user->save(); |
|
| 259 | - } |
|
| 260 | - |
|
| 261 | - /** |
|
| 262 | - * @return string |
|
| 263 | - * @throws CurlException |
|
| 264 | - */ |
|
| 265 | - public function getRequestToken() |
|
| 266 | - { |
|
| 267 | - $token = $this->oauthProtocolHelper->getRequestToken(); |
|
| 268 | - |
|
| 269 | - $this->partiallyLinked = true; |
|
| 270 | - $this->linked = false; |
|
| 271 | - |
|
| 272 | - $this->database |
|
| 273 | - ->prepare('DELETE FROM oauthtoken WHERE user = :user AND type = :type') |
|
| 274 | - ->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_REQUEST)); |
|
| 275 | - |
|
| 276 | - $this->database |
|
| 277 | - ->prepare('INSERT INTO oauthtoken (user, type, token, secret, expiry) VALUES (:user, :type, :token, :secret, DATE_ADD(NOW(), INTERVAL 1 DAY))') |
|
| 278 | - ->execute(array( |
|
| 279 | - ':user' => $this->user->getId(), |
|
| 280 | - ':type' => self::TOKEN_REQUEST, |
|
| 281 | - ':token' => $token->key, |
|
| 282 | - ':secret' => $token->secret, |
|
| 283 | - )); |
|
| 284 | - |
|
| 285 | - return $this->oauthProtocolHelper->getAuthoriseUrl($token->key); |
|
| 286 | - } |
|
| 287 | - |
|
| 288 | - /** |
|
| 289 | - * @param $verificationToken |
|
| 290 | - * |
|
| 291 | - * @throws ApplicationLogicException |
|
| 292 | - * @throws CurlException |
|
| 293 | - * @throws OAuthException |
|
| 294 | - * @throws OptimisticLockFailedException |
|
| 295 | - */ |
|
| 296 | - public function completeHandshake($verificationToken) |
|
| 297 | - { |
|
| 298 | - $this->getTokenStatement->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_REQUEST)); |
|
| 299 | - |
|
| 300 | - /** @var OAuthToken $token */ |
|
| 301 | - $token = $this->getTokenStatement->fetchObject(OAuthToken::class); |
|
| 302 | - $this->getTokenStatement->closeCursor(); |
|
| 303 | - |
|
| 304 | - if ($token === false) { |
|
| 305 | - throw new ApplicationLogicException('Cannot find request token'); |
|
| 306 | - } |
|
| 307 | - |
|
| 308 | - $token->setDatabase($this->database); |
|
| 309 | - |
|
| 310 | - $accessToken = $this->oauthProtocolHelper->callbackCompleted($token->getToken(), $token->getSecret(), |
|
| 311 | - $verificationToken); |
|
| 312 | - |
|
| 313 | - $clearStatement = $this->database->prepare('DELETE FROM oauthtoken WHERE user = :u AND type = :t'); |
|
| 314 | - $clearStatement->execute(array(':u' => $this->user->getId(), ':t' => self::TOKEN_ACCESS)); |
|
| 315 | - |
|
| 316 | - $token->setToken($accessToken->key); |
|
| 317 | - $token->setSecret($accessToken->secret); |
|
| 318 | - $token->setType(self::TOKEN_ACCESS); |
|
| 319 | - $token->setExpiry(null); |
|
| 320 | - $token->save(); |
|
| 321 | - |
|
| 322 | - $this->partiallyLinked = false; |
|
| 323 | - $this->linked = true; |
|
| 324 | - |
|
| 325 | - $this->refreshIdentity(); |
|
| 326 | - } |
|
| 327 | - |
|
| 328 | - public function detach() |
|
| 329 | - { |
|
| 330 | - $this->loadIdentity(); |
|
| 331 | - |
|
| 332 | - $this->identity->delete(); |
|
| 333 | - $statement = $this->database->prepare('DELETE FROM oauthtoken WHERE user = :user'); |
|
| 334 | - $statement->execute(array(':user' => $this->user->getId())); |
|
| 335 | - |
|
| 336 | - $this->identity = null; |
|
| 337 | - $this->linked = false; |
|
| 338 | - $this->partiallyLinked = false; |
|
| 339 | - } |
|
| 340 | - |
|
| 341 | - /** |
|
| 342 | - * @param bool $expiredOk |
|
| 343 | - * |
|
| 344 | - * @return OAuthIdentity |
|
| 345 | - * @throws OAuthException |
|
| 346 | - */ |
|
| 347 | - public function getIdentity($expiredOk = false) |
|
| 348 | - { |
|
| 349 | - $this->loadIdentity(); |
|
| 350 | - |
|
| 351 | - if (!$this->identityIsValid($expiredOk)) { |
|
| 352 | - throw new OAuthException('Stored identity is not valid.'); |
|
| 353 | - } |
|
| 354 | - |
|
| 355 | - return $this->identity; |
|
| 356 | - } |
|
| 357 | - |
|
| 358 | - public function doApiCall($params, $method) |
|
| 359 | - { |
|
| 360 | - // Ensure we're logged in |
|
| 361 | - $params['assert'] = 'user'; |
|
| 362 | - |
|
| 363 | - $token = $this->loadAccessToken(); |
|
| 364 | - return $this->oauthProtocolHelper->apiCall($params, $token->getToken(), $token->getSecret(), $method); |
|
| 365 | - } |
|
| 366 | - |
|
| 367 | - /** |
|
| 368 | - * @param bool $expiredOk |
|
| 369 | - * |
|
| 370 | - * @return bool |
|
| 371 | - */ |
|
| 372 | - private function identityIsValid($expiredOk = false) |
|
| 373 | - { |
|
| 374 | - $this->loadIdentity(); |
|
| 375 | - |
|
| 376 | - if ($this->identity === null) { |
|
| 377 | - return false; |
|
| 378 | - } |
|
| 379 | - |
|
| 380 | - if ($this->identity->getIssuedAtTime() === false |
|
| 381 | - || $this->identity->getExpirationTime() === false |
|
| 382 | - || $this->identity->getAudience() === false |
|
| 383 | - || $this->identity->getIssuer() === false |
|
| 384 | - ) { |
|
| 385 | - // this isn't populated properly. |
|
| 386 | - return false; |
|
| 387 | - } |
|
| 388 | - |
|
| 389 | - $issue = DateTimeImmutable::createFromFormat("U", $this->identity->getIssuedAtTime()); |
|
| 390 | - $now = new DateTimeImmutable(); |
|
| 391 | - |
|
| 392 | - if ($issue > $now) { |
|
| 393 | - // wat. |
|
| 394 | - return false; |
|
| 395 | - } |
|
| 396 | - |
|
| 397 | - if ($this->identityExpired() && !$expiredOk) { |
|
| 398 | - // soz. |
|
| 399 | - return false; |
|
| 400 | - } |
|
| 401 | - |
|
| 402 | - if ($this->identity->getAudience() !== $this->siteConfiguration->getOAuthConsumerToken()) { |
|
| 403 | - // token not issued for us |
|
| 404 | - |
|
| 405 | - // we allow cases where the cache is expired and the cache is for a legacy token |
|
| 406 | - if (!($expiredOk && in_array($this->identity->getAudience(), $this->legacyTokens))) { |
|
| 407 | - return false; |
|
| 408 | - } |
|
| 409 | - } |
|
| 410 | - |
|
| 411 | - if ($this->identity->getIssuer() !== $this->siteConfiguration->getOauthMediaWikiCanonicalServer()) { |
|
| 412 | - // token not issued by the right person |
|
| 413 | - return false; |
|
| 414 | - } |
|
| 415 | - |
|
| 416 | - // can't find a reason to not trust it |
|
| 417 | - return true; |
|
| 418 | - } |
|
| 419 | - |
|
| 420 | - /** |
|
| 421 | - * @return bool |
|
| 422 | - */ |
|
| 423 | - public function identityExpired() |
|
| 424 | - { |
|
| 425 | - // allowed max age |
|
| 426 | - $gracePeriod = $this->siteConfiguration->getOauthIdentityGraceTime(); |
|
| 427 | - |
|
| 428 | - $expiry = DateTimeImmutable::createFromFormat("U", $this->identity->getExpirationTime()); |
|
| 429 | - $graceExpiry = $expiry->modify($gracePeriod); |
|
| 430 | - $now = new DateTimeImmutable(); |
|
| 431 | - |
|
| 432 | - return $graceExpiry < $now; |
|
| 433 | - } |
|
| 434 | - |
|
| 435 | - /** |
|
| 436 | - * Loads the OAuth identity from the database for the current user. |
|
| 437 | - */ |
|
| 438 | - private function loadIdentity() |
|
| 439 | - { |
|
| 440 | - if ($this->identityLoaded) { |
|
| 441 | - return; |
|
| 442 | - } |
|
| 443 | - |
|
| 444 | - $statement = $this->database->prepare('SELECT * FROM oauthidentity WHERE user = :user'); |
|
| 445 | - $statement->execute(array(':user' => $this->user->getId())); |
|
| 446 | - /** @var OAuthIdentity $obj */ |
|
| 447 | - $obj = $statement->fetchObject(OAuthIdentity::class); |
|
| 448 | - |
|
| 449 | - if ($obj === false) { |
|
| 450 | - // failed to load identity. |
|
| 451 | - $this->identityLoaded = true; |
|
| 452 | - $this->identity = null; |
|
| 453 | - |
|
| 454 | - return; |
|
| 455 | - } |
|
| 456 | - |
|
| 457 | - $obj->setDatabase($this->database); |
|
| 458 | - $this->identityLoaded = true; |
|
| 459 | - $this->identity = $obj; |
|
| 460 | - } |
|
| 461 | - |
|
| 462 | - /** |
|
| 463 | - * @return OAuthToken |
|
| 464 | - * @throws OAuthException |
|
| 465 | - */ |
|
| 466 | - private function loadAccessToken() |
|
| 467 | - { |
|
| 468 | - if (!$this->accessTokenLoaded) { |
|
| 469 | - $this->getTokenStatement->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_ACCESS)); |
|
| 470 | - /** @var OAuthToken $token */ |
|
| 471 | - $token = $this->getTokenStatement->fetchObject(OAuthToken::class); |
|
| 472 | - $this->getTokenStatement->closeCursor(); |
|
| 473 | - |
|
| 474 | - if ($token === false) { |
|
| 475 | - throw new OAuthException('Access token not found!'); |
|
| 476 | - } |
|
| 477 | - |
|
| 478 | - $this->accessToken = $token; |
|
| 479 | - $this->accessTokenLoaded = true; |
|
| 480 | - } |
|
| 481 | - |
|
| 482 | - return $this->accessToken; |
|
| 483 | - } |
|
| 79 | + ); |
|
| 80 | + $statement->execute(array(':type' => self::TOKEN_REQUEST, ':token' => $requestToken)); |
|
| 81 | + |
|
| 82 | + /** @var User $user */ |
|
| 83 | + $user = $statement->fetchObject(User::class); |
|
| 84 | + $statement->closeCursor(); |
|
| 85 | + |
|
| 86 | + if ($user === false) { |
|
| 87 | + throw new ApplicationLogicException('Token not found in store, please try again'); |
|
| 88 | + } |
|
| 89 | + |
|
| 90 | + $user->setDatabase($database); |
|
| 91 | + |
|
| 92 | + return $user; |
|
| 93 | + } |
|
| 94 | + |
|
| 95 | + public static function userIsFullyLinked(User $user, PdoDatabase $database = null) |
|
| 96 | + { |
|
| 97 | + if (self::$tokenCountStatement === null && $database === null) { |
|
| 98 | + throw new ApplicationLogicException('Static link request without initialised statement'); |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + return self::runTokenCount($user->getId(), $database, self::TOKEN_ACCESS); |
|
| 102 | + } |
|
| 103 | + |
|
| 104 | + public static function userIsPartiallyLinked(User $user, PdoDatabase $database = null) |
|
| 105 | + { |
|
| 106 | + if (self::$tokenCountStatement === null && $database === null) { |
|
| 107 | + throw new ApplicationLogicException('Static link request without initialised statement'); |
|
| 108 | + } |
|
| 109 | + |
|
| 110 | + if (self::userIsFullyLinked($user, $database)) { |
|
| 111 | + return false; |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + return self::runTokenCount($user->getId(), $database, self::TOKEN_REQUEST) |
|
| 115 | + || $user->getOnWikiName() == null; |
|
| 116 | + } |
|
| 117 | + |
|
| 118 | + /** |
|
| 119 | + * @param PdoDatabase $database |
|
| 120 | + */ |
|
| 121 | + public static function prepareTokenCountStatement(PdoDatabase $database) |
|
| 122 | + { |
|
| 123 | + if (self::$tokenCountStatement === null) { |
|
| 124 | + self::$tokenCountStatement = $database->prepare('SELECT COUNT(*) FROM oauthtoken WHERE user = :user AND type = :type'); |
|
| 125 | + } |
|
| 126 | + } |
|
| 127 | + |
|
| 128 | + private static function runTokenCount($userId, $database, $tokenType) |
|
| 129 | + { |
|
| 130 | + if (self::$tokenCountStatement === null) { |
|
| 131 | + self::prepareTokenCountStatement($database); |
|
| 132 | + } |
|
| 133 | + |
|
| 134 | + self::$tokenCountStatement->execute(array( |
|
| 135 | + ':user' => $userId, |
|
| 136 | + ':type' => $tokenType, |
|
| 137 | + )); |
|
| 138 | + |
|
| 139 | + $tokenCount = self::$tokenCountStatement->fetchColumn(); |
|
| 140 | + $linked = $tokenCount > 0; |
|
| 141 | + self::$tokenCountStatement->closeCursor(); |
|
| 142 | + |
|
| 143 | + return $linked; |
|
| 144 | + } |
|
| 145 | + |
|
| 146 | + #endregion Static methods |
|
| 147 | + |
|
| 148 | + /** |
|
| 149 | + * OAuthUserHelper constructor. |
|
| 150 | + * |
|
| 151 | + * @param User $user |
|
| 152 | + * @param PdoDatabase $database |
|
| 153 | + * @param IOAuthProtocolHelper $oauthProtocolHelper |
|
| 154 | + * @param SiteConfiguration $siteConfiguration |
|
| 155 | + */ |
|
| 156 | + public function __construct( |
|
| 157 | + User $user, |
|
| 158 | + PdoDatabase $database, |
|
| 159 | + IOAuthProtocolHelper $oauthProtocolHelper, |
|
| 160 | + SiteConfiguration $siteConfiguration |
|
| 161 | + ) { |
|
| 162 | + $this->user = $user; |
|
| 163 | + $this->database = $database; |
|
| 164 | + $this->oauthProtocolHelper = $oauthProtocolHelper; |
|
| 165 | + |
|
| 166 | + $this->linked = null; |
|
| 167 | + $this->partiallyLinked = null; |
|
| 168 | + $this->siteConfiguration = $siteConfiguration; |
|
| 169 | + |
|
| 170 | + self::prepareTokenCountStatement($database); |
|
| 171 | + $this->getTokenStatement = $this->database->prepare('SELECT * FROM oauthtoken WHERE user = :user AND type = :type'); |
|
| 172 | + |
|
| 173 | + $this->legacyTokens = $this->siteConfiguration->getOauthLegacyConsumerTokens(); |
|
| 174 | + } |
|
| 175 | + |
|
| 176 | + /** |
|
| 177 | + * Determines if the user is fully connected to OAuth. |
|
| 178 | + * |
|
| 179 | + * @return bool |
|
| 180 | + */ |
|
| 181 | + public function isFullyLinked() |
|
| 182 | + { |
|
| 183 | + if ($this->linked === null) { |
|
| 184 | + $this->linked = self::userIsFullyLinked($this->user, $this->database); |
|
| 185 | + } |
|
| 186 | + |
|
| 187 | + return $this->linked; |
|
| 188 | + } |
|
| 189 | + |
|
| 190 | + /** |
|
| 191 | + * Attempts to figure out if a user is partially linked to OAuth, and therefore needs to complete the OAuth |
|
| 192 | + * procedure before configuring. |
|
| 193 | + * @return bool |
|
| 194 | + */ |
|
| 195 | + public function isPartiallyLinked() |
|
| 196 | + { |
|
| 197 | + if ($this->partiallyLinked === null) { |
|
| 198 | + $this->partiallyLinked = self::userIsPartiallyLinked($this->user, $this->database); |
|
| 199 | + } |
|
| 200 | + |
|
| 201 | + return $this->partiallyLinked; |
|
| 202 | + } |
|
| 203 | + |
|
| 204 | + public function canCreateAccount() |
|
| 205 | + { |
|
| 206 | + return $this->isFullyLinked() |
|
| 207 | + && $this->getIdentity(true)->getGrantBasic() |
|
| 208 | + && $this->getIdentity(true)->getGrantHighVolume() |
|
| 209 | + && $this->getIdentity(true)->getGrantCreateAccount(); |
|
| 210 | + } |
|
| 211 | + |
|
| 212 | + public function canWelcome() |
|
| 213 | + { |
|
| 214 | + return $this->isFullyLinked() |
|
| 215 | + && $this->getIdentity(true)->getGrantBasic() |
|
| 216 | + && $this->getIdentity(true)->getGrantHighVolume() |
|
| 217 | + && $this->getIdentity(true)->getGrantCreateEditMovePage(); |
|
| 218 | + } |
|
| 219 | + |
|
| 220 | + /** |
|
| 221 | + * @throws OAuthException |
|
| 222 | + * @throws CurlException |
|
| 223 | + * @throws OptimisticLockFailedException |
|
| 224 | + * @throws Exception |
|
| 225 | + */ |
|
| 226 | + public function refreshIdentity() |
|
| 227 | + { |
|
| 228 | + $this->loadIdentity(); |
|
| 229 | + |
|
| 230 | + if ($this->identity === null) { |
|
| 231 | + $this->identity = new OAuthIdentity(); |
|
| 232 | + $this->identity->setUserId($this->user->getId()); |
|
| 233 | + $this->identity->setDatabase($this->database); |
|
| 234 | + } |
|
| 235 | + |
|
| 236 | + $token = $this->loadAccessToken(); |
|
| 237 | + |
|
| 238 | + try { |
|
| 239 | + $rawTicket = $this->oauthProtocolHelper->getIdentityTicket($token->getToken(), $token->getSecret()); |
|
| 240 | + } |
|
| 241 | + catch (Exception $ex) { |
|
| 242 | + if (strpos($ex->getMessage(), "mwoauthdatastore-access-token-not-found") !== false) { |
|
| 243 | + throw new OAuthException('No approved grants for this access token.', -1, $ex); |
|
| 244 | + } |
|
| 245 | + |
|
| 246 | + throw $ex; |
|
| 247 | + } |
|
| 248 | + |
|
| 249 | + $this->identity->populate($rawTicket); |
|
| 250 | + |
|
| 251 | + if (!$this->identityIsValid()) { |
|
| 252 | + throw new OAuthException('Identity ticket is not valid!'); |
|
| 253 | + } |
|
| 254 | + |
|
| 255 | + $this->identity->save(); |
|
| 256 | + |
|
| 257 | + $this->user->setOnWikiName($this->identity->getUsername()); |
|
| 258 | + $this->user->save(); |
|
| 259 | + } |
|
| 260 | + |
|
| 261 | + /** |
|
| 262 | + * @return string |
|
| 263 | + * @throws CurlException |
|
| 264 | + */ |
|
| 265 | + public function getRequestToken() |
|
| 266 | + { |
|
| 267 | + $token = $this->oauthProtocolHelper->getRequestToken(); |
|
| 268 | + |
|
| 269 | + $this->partiallyLinked = true; |
|
| 270 | + $this->linked = false; |
|
| 271 | + |
|
| 272 | + $this->database |
|
| 273 | + ->prepare('DELETE FROM oauthtoken WHERE user = :user AND type = :type') |
|
| 274 | + ->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_REQUEST)); |
|
| 275 | + |
|
| 276 | + $this->database |
|
| 277 | + ->prepare('INSERT INTO oauthtoken (user, type, token, secret, expiry) VALUES (:user, :type, :token, :secret, DATE_ADD(NOW(), INTERVAL 1 DAY))') |
|
| 278 | + ->execute(array( |
|
| 279 | + ':user' => $this->user->getId(), |
|
| 280 | + ':type' => self::TOKEN_REQUEST, |
|
| 281 | + ':token' => $token->key, |
|
| 282 | + ':secret' => $token->secret, |
|
| 283 | + )); |
|
| 284 | + |
|
| 285 | + return $this->oauthProtocolHelper->getAuthoriseUrl($token->key); |
|
| 286 | + } |
|
| 287 | + |
|
| 288 | + /** |
|
| 289 | + * @param $verificationToken |
|
| 290 | + * |
|
| 291 | + * @throws ApplicationLogicException |
|
| 292 | + * @throws CurlException |
|
| 293 | + * @throws OAuthException |
|
| 294 | + * @throws OptimisticLockFailedException |
|
| 295 | + */ |
|
| 296 | + public function completeHandshake($verificationToken) |
|
| 297 | + { |
|
| 298 | + $this->getTokenStatement->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_REQUEST)); |
|
| 299 | + |
|
| 300 | + /** @var OAuthToken $token */ |
|
| 301 | + $token = $this->getTokenStatement->fetchObject(OAuthToken::class); |
|
| 302 | + $this->getTokenStatement->closeCursor(); |
|
| 303 | + |
|
| 304 | + if ($token === false) { |
|
| 305 | + throw new ApplicationLogicException('Cannot find request token'); |
|
| 306 | + } |
|
| 307 | + |
|
| 308 | + $token->setDatabase($this->database); |
|
| 309 | + |
|
| 310 | + $accessToken = $this->oauthProtocolHelper->callbackCompleted($token->getToken(), $token->getSecret(), |
|
| 311 | + $verificationToken); |
|
| 312 | + |
|
| 313 | + $clearStatement = $this->database->prepare('DELETE FROM oauthtoken WHERE user = :u AND type = :t'); |
|
| 314 | + $clearStatement->execute(array(':u' => $this->user->getId(), ':t' => self::TOKEN_ACCESS)); |
|
| 315 | + |
|
| 316 | + $token->setToken($accessToken->key); |
|
| 317 | + $token->setSecret($accessToken->secret); |
|
| 318 | + $token->setType(self::TOKEN_ACCESS); |
|
| 319 | + $token->setExpiry(null); |
|
| 320 | + $token->save(); |
|
| 321 | + |
|
| 322 | + $this->partiallyLinked = false; |
|
| 323 | + $this->linked = true; |
|
| 324 | + |
|
| 325 | + $this->refreshIdentity(); |
|
| 326 | + } |
|
| 327 | + |
|
| 328 | + public function detach() |
|
| 329 | + { |
|
| 330 | + $this->loadIdentity(); |
|
| 331 | + |
|
| 332 | + $this->identity->delete(); |
|
| 333 | + $statement = $this->database->prepare('DELETE FROM oauthtoken WHERE user = :user'); |
|
| 334 | + $statement->execute(array(':user' => $this->user->getId())); |
|
| 335 | + |
|
| 336 | + $this->identity = null; |
|
| 337 | + $this->linked = false; |
|
| 338 | + $this->partiallyLinked = false; |
|
| 339 | + } |
|
| 340 | + |
|
| 341 | + /** |
|
| 342 | + * @param bool $expiredOk |
|
| 343 | + * |
|
| 344 | + * @return OAuthIdentity |
|
| 345 | + * @throws OAuthException |
|
| 346 | + */ |
|
| 347 | + public function getIdentity($expiredOk = false) |
|
| 348 | + { |
|
| 349 | + $this->loadIdentity(); |
|
| 350 | + |
|
| 351 | + if (!$this->identityIsValid($expiredOk)) { |
|
| 352 | + throw new OAuthException('Stored identity is not valid.'); |
|
| 353 | + } |
|
| 354 | + |
|
| 355 | + return $this->identity; |
|
| 356 | + } |
|
| 357 | + |
|
| 358 | + public function doApiCall($params, $method) |
|
| 359 | + { |
|
| 360 | + // Ensure we're logged in |
|
| 361 | + $params['assert'] = 'user'; |
|
| 362 | + |
|
| 363 | + $token = $this->loadAccessToken(); |
|
| 364 | + return $this->oauthProtocolHelper->apiCall($params, $token->getToken(), $token->getSecret(), $method); |
|
| 365 | + } |
|
| 366 | + |
|
| 367 | + /** |
|
| 368 | + * @param bool $expiredOk |
|
| 369 | + * |
|
| 370 | + * @return bool |
|
| 371 | + */ |
|
| 372 | + private function identityIsValid($expiredOk = false) |
|
| 373 | + { |
|
| 374 | + $this->loadIdentity(); |
|
| 375 | + |
|
| 376 | + if ($this->identity === null) { |
|
| 377 | + return false; |
|
| 378 | + } |
|
| 379 | + |
|
| 380 | + if ($this->identity->getIssuedAtTime() === false |
|
| 381 | + || $this->identity->getExpirationTime() === false |
|
| 382 | + || $this->identity->getAudience() === false |
|
| 383 | + || $this->identity->getIssuer() === false |
|
| 384 | + ) { |
|
| 385 | + // this isn't populated properly. |
|
| 386 | + return false; |
|
| 387 | + } |
|
| 388 | + |
|
| 389 | + $issue = DateTimeImmutable::createFromFormat("U", $this->identity->getIssuedAtTime()); |
|
| 390 | + $now = new DateTimeImmutable(); |
|
| 391 | + |
|
| 392 | + if ($issue > $now) { |
|
| 393 | + // wat. |
|
| 394 | + return false; |
|
| 395 | + } |
|
| 396 | + |
|
| 397 | + if ($this->identityExpired() && !$expiredOk) { |
|
| 398 | + // soz. |
|
| 399 | + return false; |
|
| 400 | + } |
|
| 401 | + |
|
| 402 | + if ($this->identity->getAudience() !== $this->siteConfiguration->getOAuthConsumerToken()) { |
|
| 403 | + // token not issued for us |
|
| 404 | + |
|
| 405 | + // we allow cases where the cache is expired and the cache is for a legacy token |
|
| 406 | + if (!($expiredOk && in_array($this->identity->getAudience(), $this->legacyTokens))) { |
|
| 407 | + return false; |
|
| 408 | + } |
|
| 409 | + } |
|
| 410 | + |
|
| 411 | + if ($this->identity->getIssuer() !== $this->siteConfiguration->getOauthMediaWikiCanonicalServer()) { |
|
| 412 | + // token not issued by the right person |
|
| 413 | + return false; |
|
| 414 | + } |
|
| 415 | + |
|
| 416 | + // can't find a reason to not trust it |
|
| 417 | + return true; |
|
| 418 | + } |
|
| 419 | + |
|
| 420 | + /** |
|
| 421 | + * @return bool |
|
| 422 | + */ |
|
| 423 | + public function identityExpired() |
|
| 424 | + { |
|
| 425 | + // allowed max age |
|
| 426 | + $gracePeriod = $this->siteConfiguration->getOauthIdentityGraceTime(); |
|
| 427 | + |
|
| 428 | + $expiry = DateTimeImmutable::createFromFormat("U", $this->identity->getExpirationTime()); |
|
| 429 | + $graceExpiry = $expiry->modify($gracePeriod); |
|
| 430 | + $now = new DateTimeImmutable(); |
|
| 431 | + |
|
| 432 | + return $graceExpiry < $now; |
|
| 433 | + } |
|
| 434 | + |
|
| 435 | + /** |
|
| 436 | + * Loads the OAuth identity from the database for the current user. |
|
| 437 | + */ |
|
| 438 | + private function loadIdentity() |
|
| 439 | + { |
|
| 440 | + if ($this->identityLoaded) { |
|
| 441 | + return; |
|
| 442 | + } |
|
| 443 | + |
|
| 444 | + $statement = $this->database->prepare('SELECT * FROM oauthidentity WHERE user = :user'); |
|
| 445 | + $statement->execute(array(':user' => $this->user->getId())); |
|
| 446 | + /** @var OAuthIdentity $obj */ |
|
| 447 | + $obj = $statement->fetchObject(OAuthIdentity::class); |
|
| 448 | + |
|
| 449 | + if ($obj === false) { |
|
| 450 | + // failed to load identity. |
|
| 451 | + $this->identityLoaded = true; |
|
| 452 | + $this->identity = null; |
|
| 453 | + |
|
| 454 | + return; |
|
| 455 | + } |
|
| 456 | + |
|
| 457 | + $obj->setDatabase($this->database); |
|
| 458 | + $this->identityLoaded = true; |
|
| 459 | + $this->identity = $obj; |
|
| 460 | + } |
|
| 461 | + |
|
| 462 | + /** |
|
| 463 | + * @return OAuthToken |
|
| 464 | + * @throws OAuthException |
|
| 465 | + */ |
|
| 466 | + private function loadAccessToken() |
|
| 467 | + { |
|
| 468 | + if (!$this->accessTokenLoaded) { |
|
| 469 | + $this->getTokenStatement->execute(array(':user' => $this->user->getId(), ':type' => self::TOKEN_ACCESS)); |
|
| 470 | + /** @var OAuthToken $token */ |
|
| 471 | + $token = $this->getTokenStatement->fetchObject(OAuthToken::class); |
|
| 472 | + $this->getTokenStatement->closeCursor(); |
|
| 473 | + |
|
| 474 | + if ($token === false) { |
|
| 475 | + throw new OAuthException('Access token not found!'); |
|
| 476 | + } |
|
| 477 | + |
|
| 478 | + $this->accessToken = $token; |
|
| 479 | + $this->accessTokenLoaded = true; |
|
| 480 | + } |
|
| 481 | + |
|
| 482 | + return $this->accessToken; |
|
| 483 | + } |
|
| 484 | 484 | } |