diff options
Diffstat (limited to 'CommentStreams/includes/CommentStreamsHooks.php')
-rw-r--r-- | CommentStreams/includes/CommentStreamsHooks.php | 334 |
1 files changed, 115 insertions, 219 deletions
diff --git a/CommentStreams/includes/CommentStreamsHooks.php b/CommentStreams/includes/CommentStreamsHooks.php index 897ce9c8..5dcf727e 100644 --- a/CommentStreams/includes/CommentStreamsHooks.php +++ b/CommentStreams/includes/CommentStreamsHooks.php @@ -26,14 +26,14 @@ namespace MediaWiki\Extension\CommentStreams; use Article; use DatabaseUpdater; use MediaWiki; +use MediaWiki\MediaWikiServices; +use MWException; use OutputPage; +use PageProps; use Parser; use PPFrame; use SearchResult; use Skin; -use SMW\DIWikiPage; -use SMW\DIProperty; -use SMW\PropertyRegistry; use SpecialSearch; use Status; use Title; @@ -42,7 +42,6 @@ use WebRequest; use WikiPage; class CommentStreamsHooks { - /** * Implements LoadExtensionSchemaUpdates hook. * See https://www.mediawiki.org/wiki/Manual:Hooks/LoadExtensionSchemaUpdates @@ -51,9 +50,8 @@ class CommentStreamsHooks { * @param DatabaseUpdater $updater database updater * @return bool continue checking hooks */ - public static function addCommentTableToDatabase( DatabaseUpdater $updater ) { - $dir = $GLOBALS['wgExtensionDirectory'] . DIRECTORY_SEPARATOR . - 'CommentStreams' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + public static function addCommentTableToDatabase( DatabaseUpdater $updater ) : bool { + $dir = __DIR__ . '/../sql/'; $updater->addExtensionTable( 'cs_comment_data', $dir . 'commentData.sql' ); $updater->addExtensionTable( 'cs_votes', $dir . 'votes.sql' ); $updater->addExtensionTable( 'cs_watchlist', $dir . 'watch.sql' ); @@ -63,6 +61,8 @@ class CommentStreamsHooks { $dir . 'dropForeignKey1.sql' ); $updater->dropExtensionIndex( 'cs_comment_data', 'cst_assoc_page_id', $dir . 'dropForeignKey2.sql' ); + $updater->addExtensionField( 'cs_comment_data', 'cst_id', + $dir . 'addCommentId.sql' ); return true; } @@ -75,7 +75,7 @@ class CommentStreamsHooks { * corresponding canonical names * @return bool continue checking hooks */ - public static function addCommentStreamsNamespaces( array &$namespaces ) { + public static function addCommentStreamsNamespaces( array &$namespaces ) : bool { $namespaces[NS_COMMENTSTREAMS] = 'CommentStreams'; $namespaces[NS_COMMENTSTREAMS_TALK] = 'CommentStreams_Talk'; return true; @@ -94,10 +94,17 @@ class CommentStreamsHooks { * @param WebRequest $request WebRequest object * @param MediaWiki $wiki MediaWiki object * @return bool continue checking hooks + * @noinspection PhpUnusedParameterInspection + * @throws MWException */ - public static function onMediaWikiPerformAction( OutputPage $output, - Article $article, Title $title, User $user, WebRequest $request, - MediaWiki $wiki ) { + public static function onMediaWikiPerformAction( + OutputPage $output, + Article $article, + Title $title, + User $user, + WebRequest $request, + MediaWiki $wiki + ) : bool { if ( $title->getNamespace() !== NS_COMMENTSTREAMS ) { return true; } @@ -108,10 +115,14 @@ class CommentStreamsHooks { if ( $action !== 'view' ) { $message = wfMessage( 'commentstreams-error-prohibitedaction', $action )->text(); - $output->addHTML( '<p class="error">' . $message . '</p>' ); + $output->addHTML( '<p class="error">' . htmlentities( $message ) . '</p>' ); } + + $commentStreamsFactory = + MediaWikiServices::getInstance()->getService( 'CommentStreamsFactory' ); + $wikipage = new WikiPage( $title ); - $comment = Comment::newFromWikiPage( $wikipage ); + $comment = $commentStreamsFactory->newFromWikiPage( $wikipage ); if ( $comment !== null ) { $commentTitle = $comment->getCommentTitle(); if ( $commentTitle !== null ) { @@ -119,29 +130,25 @@ class CommentStreamsHooks { } $associatedTitle = Title::newFromId( $comment->getAssociatedId() ); if ( $associatedTitle !== null ) { - $values = []; - if ( class_exists( 'PageProps' ) ) { - $values = \PageProps::getInstance()->getProperties( $associatedTitle, - 'displaytitle' ); - } + $values = PageProps::getInstance()->getProperties( $associatedTitle, + 'displaytitle' ); if ( array_key_exists( $comment->getAssociatedId(), $values ) ) { $displaytitle = $values[$comment->getAssociatedId()]; } else { $displaytitle = $associatedTitle->getPrefixedText(); } + $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); $output->setSubtitle( - CommentStreamsUtils::link( $associatedTitle, '< ' . $displaytitle ) - ); + $linkRenderer->makeLink( $associatedTitle, '< ' . $displaytitle ) ); } else { $message = wfMessage( 'commentstreams-error-comment-on-deleted-page' )->text(); - $output->addHTML( '<p class="error">' . $message . '</p>' ); - } - if ( method_exists( 'OutputPage', 'addWikiTextAsInterface' ) ) { - $output->addWikiTextAsInterface( $comment->getHTML() ); - } else { - $output->addWikiText( $comment->getHTML() ); + $output->addHTML( '<p class="error">' . htmlentities( $message ) . '</p>' ); } + CommentStreamsUtils::addWikiTextToOutputPage( + $comment->getHTML( $output->getContext() ), + $output + ); } return false; } @@ -156,8 +163,11 @@ class CommentStreamsHooks { * @param Status $status Status object to pass error messages to * @return bool continue checking hooks */ - public static function onMovePageIsValidMove( Title $oldTitle, - Title $newTitle, Status $status ) { + public static function onMovePageIsValidMove( + Title $oldTitle, + Title $newTitle, + Status $status + ) : bool { if ( $oldTitle->getNamespace() === NS_COMMENTSTREAMS || $newTitle->getNamespace() === NS_COMMENTSTREAMS ) { $status->fatal( wfMessage( 'commentstreams-error-prohibitedaction', @@ -172,15 +182,19 @@ class CommentStreamsHooks { * See https://www.mediawiki.org/wiki/Manual:Hooks/userCan * Ensures that only the original author can edit a comment * - * @param Title &$title the title object in question - * @param User &$user the user performing the action + * @param Title $title the title object in question + * @param User $user the user performing the action * @param string $action the action being performed * @param bool &$result true means the user is allowed, false means the * user is not allowed, untouched means this hook has no opinion * @return bool continue checking hooks */ - public static function userCan( Title &$title, User &$user, $action, - &$result ) { + public static function userCan( + Title $title, + User $user, + string $action, + bool &$result + ) : bool { if ( $title->getNamespace() !== NS_COMMENTSTREAMS ) { return true; } @@ -191,22 +205,9 @@ class CommentStreamsHooks { return true; } - if ( $user->isBlocked() ) { - $result = false; - return false; - } - if ( $action === 'cs-comment' ) { - if ( $user->getId() === $wikipage->getOldestRevision()->getUser() ) { - $result = true; - } else { - $result = false; - } - return false; - } - - if ( $action === 'cs-moderator-edit' ) { - if ( in_array( 'cs-moderator-edit', $user->getRights() ) ) { + if ( CommentStreamsUtils::userHasRight( $user, $action ) && + $user->getId() === CommentStreamsUtils::getAuthor( $title )->getId() ) { $result = true; } else { $result = false; @@ -214,12 +215,8 @@ class CommentStreamsHooks { return false; } - if ( $action === 'cs-moderator-delete' ) { - if ( in_array( 'cs-moderator-delete', $user->getRights() ) ) { - $result = true; - } else { - $result = false; - } + if ( in_array( $action, [ 'cs-moderator-edit', 'cs-moderator-delete' ] ) ) { + $result = CommentStreamsUtils::userHasRight( $user, $action ); return false; } @@ -234,8 +231,9 @@ class CommentStreamsHooks { * * @param Parser $parser the parser * @return bool continue checking hooks + * @throws MWException */ - public static function onParserSetup( Parser $parser ) { + public static function onParserSetup( Parser $parser ) : bool { $parser->setHook( 'comment-streams', 'MediaWiki\Extension\CommentStreams\CommentStreamsHooks::enableCommentStreams' ); $parser->setHook( 'no-comment-streams', @@ -249,22 +247,30 @@ class CommentStreamsHooks { * Implements tag function, <comment-streams/>, which enables * CommentStreams on a page. * - * @param string $input input between the tags (ignored) + * @param ?string $input input between the tags (ignored) * @param array $args tag arguments * @param Parser $parser the parser * @param PPFrame $frame the parent frame * @return string to replace tag with + * @noinspection PhpUnusedParameterInspection */ - public static function enableCommentStreams( $input, array $args, - Parser $parser, PPFrame $frame ) { + public static function enableCommentStreams( + ?string $input, + array $args, + Parser $parser, + PPFrame $frame + ) : string { $parser->getOutput()->updateCacheExpiry( 0 ); - $cs = CommentStreams::singleton(); + $cs = MediaWikiServices::getInstance()->getService( 'CommentStreamsHandler' ); $cs->enableCommentsOnPage(); - if ( isset( $args['location'] ) && $args['location'] === 'footer' ) { + if ( isset( $args['id'] ) ) { + $ret = '<div class="cs-comments" id="csc_' . md5( $args['id'] ) . '"></div>'; + } elseif ( isset( $args['location'] ) && $args['location'] === 'footer' ) { $ret = ''; } else { - $ret = '<div id="cs-comments"></div>'; + $ret = '<div class="cs-comments" id="cs-comments"></div>'; } + // @phan-suppress-next-line SecurityCheck-XSS return $ret; } @@ -272,34 +278,44 @@ class CommentStreamsHooks { * Implements tag function, <no-comment-streams/>, which disables * CommentStreams on a page. * - * @param string $input input between the tags (ignored) + * @param ?string $input input between the tags (ignored) * @param array $args tag arguments * @param Parser $parser the parser * @param PPFrame $frame the parent frame * @return string to replace tag with + * @noinspection PhpUnusedParameterInspection */ - public static function disableCommentStreams( $input, array $args, - Parser $parser, PPFrame $frame ) { + public static function disableCommentStreams( + ?string $input, + array $args, + Parser $parser, + PPFrame $frame + ) : string { $parser->getOutput()->updateCacheExpiry( 0 ); - $cs = CommentStreams::singleton(); + $cs = MediaWikiServices::getInstance()->getService( 'CommentStreamsHandler' ); $cs->disableCommentsOnPage(); - return ""; + return ''; } /** * Implements tag function, <comment-streams-initially-collapsed/>, which * makes CommentStreams on a page start as collapsed when the page is viewed. * - * @param string $input input between the tags (ignored) + * @param ?string $input input between the tags (ignored) * @param array $args tag arguments * @param Parser $parser the parser * @param PPFrame $frame the parent frame * @return string to replace tag with + * @noinspection PhpUnusedParameterInspection */ - public static function initiallyCollapseCommentStreams( $input, array $args, - Parser $parser, PPFrame $frame ) { + public static function initiallyCollapseCommentStreams( + ?string $input, + array $args, + Parser $parser, + PPFrame $frame + ) : string { $parser->getOutput()->updateCacheExpiry( 0 ); - $cs = CommentStreams::singleton(); + $cs = MediaWikiServices::getInstance()->getService( 'CommentStreamsHandler' ); $cs->initiallyCollapseCommentsOnPage(); return ""; } @@ -309,13 +325,16 @@ class CommentStreamsHooks { * See https://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay * Gets comments for page and initializes variables to be passed to JavaScript. * - * @param OutputPage &$output OutputPage object - * @param Skin &$skin Skin object that will be used to generate the page + * @param OutputPage $output OutputPage object + * @param Skin $skin Skin object that will be used to generate the page * @return bool continue checking hooks + * @noinspection PhpUnusedParameterInspection */ - public static function addCommentsAndInitializeJS( OutputPage &$output, - Skin &$skin ) { - $cs = CommentStreams::singleton(); + public static function addCommentsAndInitializeJS( + OutputPage $output, + Skin $skin + ) : bool { + $cs = MediaWikiServices::getInstance()->getService( 'CommentStreamsHandler' ); $cs->init( $output ); return true; } @@ -327,15 +346,27 @@ class CommentStreamsHooks { * associated content page instead. * * @param Title &$title title to link to - * @param string &$text text to use for the link + * @param ?string &$text text to use for the link * @param SearchResult $result the search result * @param array $terms the search terms entered * @param SpecialSearch $page the SpecialSearch object * @return bool continue checking hooks + * @noinspection PhpUnusedParameterInspection */ - public static function showSearchHitTitle( Title &$title, &$text, - SearchResult $result, array $terms, SpecialSearch $page ) { - $comment = Comment::newFromWikiPage( WikiPage::factory( $title ) ); + public static function showSearchHitTitle( + Title &$title, + ?string &$text, + SearchResult $result, + array $terms, + SpecialSearch $page + ) : bool { + if ( $title->getNamespace() !== NS_COMMENTSTREAMS ) { + return true; + } + $commentStreamsFactory = + MediaWikiServices::getInstance()->getService( 'CommentStreamsFactory' ); + $comment = $commentStreamsFactory->newFromWikiPage( + CommentStreamsUtils::newWikiPageFromId( $title->getArticleID() ) ); if ( $comment !== null ) { $t = Title::newFromId( $comment->getAssociatedId() ); if ( $t !== null ) { @@ -346,28 +377,16 @@ class CommentStreamsHooks { } /** - * Implements SMW::Settings::BeforeInitializationComplete callback. - * See https://github.com/SemanticMediaWiki/SemanticMediaWiki/blob/master/docs/technical/hooks/hook.settings.beforeinitializationcomplete.md - * Defines CommentStreams namespace constants. - * - * @param array &$configuration An array of the configuration options - */ - public static function onSMWInitialization( array &$configuration ) { - $namespace = $GLOBALS['wgCommentStreamsNamespaceIndex']; - $configuration['smwgNamespacesWithSemanticLinks'][$namespace] = true; - } - - /** * Implements extension registration callback. * See https://www.mediawiki.org/wiki/Manual:Extension_registration#Customizing_registration * Sets configuration constants. - * */ public static function onRegistration() { define( 'NS_COMMENTSTREAMS', $GLOBALS['wgCommentStreamsNamespaceIndex'] ); - define( 'NS_COMMENTSTREAMS_TALK', - $GLOBALS['wgCommentStreamsNamespaceIndex'] + 1 ); - $GLOBALS['wgNamespacesToBeSearchedDefault'][NS_COMMENTSTREAMS] = true; + define( 'NS_COMMENTSTREAMS_TALK', $GLOBALS['wgCommentStreamsNamespaceIndex'] + 1 ); + if ( $GLOBALS['wgCommentStreamsEnableSearch'] ) { + $GLOBALS['wgNamespacesToBeSearchedDefault'][NS_COMMENTSTREAMS] = true; + } $found = false; foreach ( $GLOBALS['wgGroupPermissions'] as $groupperms ) { if ( isset( $groupperms['cs-comment'] ) ) { @@ -383,13 +402,11 @@ class CommentStreamsHooks { } } } - if ( !isset( $GLOBALS['wgGroupPermissions']['csmoderator'] - ['cs-moderator-delete'] ) ) { + if ( !isset( $GLOBALS['wgGroupPermissions']['csmoderator']['cs-moderator-delete'] ) ) { $GLOBALS['wgGroupPermissions']['csmoderator']['cs-moderator-delete'] = true; } - if ( !isset( $GLOBALS['wgGroupPermissions']['csmoderator'] - ['cs-moderator-edit'] ) ) { + if ( !isset( $GLOBALS['wgGroupPermissions']['csmoderator']['cs-moderator-edit'] ) ) { $GLOBALS['wgGroupPermissions']['csmoderator']['cs-moderator-edit'] = false; } @@ -399,125 +416,4 @@ class CommentStreamsHooks { $GLOBALS['wgLogTypes'][] = 'commentstreams'; $GLOBALS['wgLogActionsHandlers']['commentstreams/*'] = 'LogFormatter'; } - - /** - * Initialize extra Semantic MediaWiki properties. - * This won't get called unless Semantic MediaWiki is installed. - */ - public static function initProperties() { - $pr = PropertyRegistry::getInstance(); - $pr->registerProperty( '___CS_ASSOCPG', '_wpg', 'Comment on' ); - $pr->registerProperty( '___CS_REPLYTO', '_wpg', 'Reply to' ); - $pr->registerProperty( '___CS_TITLE', '_txt', 'Comment title of' ); - $pr->registerProperty( '___CS_UPVOTES', '_num', 'Comment up votes' ); - $pr->registerProperty( '___CS_DOWNVOTES', '_num', 'Comment down votes' ); - $pr->registerProperty( '___CS_VOTEDIFF', '_num', 'Comment vote diff' ); - } - - /** - * Implements Semantic MediaWiki SMWStore::updateDataBefore callback. - * This won't get called unless Semantic MediaWiki is installed. - * If the comment has not been added to the database yet, which is indicated - * by a null associated page id, this function will return early, but it - * will be invoked again by an update job. - * - * @param SMW\Store $store semantic data store - * @param SMW\SemanticData $semanticData semantic data for page - * @return bool true to continue - */ - public static function updateData( $store, $semanticData ) { - $subject = $semanticData->getSubject(); - if ( $subject !== null && $subject->getTitle() !== null && - $subject->getTitle()->getNamespace() === NS_COMMENTSTREAMS ) { - $page_id = $subject->getTitle()->getArticleID( Title::GAID_FOR_UPDATE ); - $wikipage = WikiPage::newFromId( $page_id ); - $comment = Comment::newFromWikiPage( $wikipage ); - - if ( $comment === null ) { - return true; - } - - $assoc_page_id = $comment->getAssociatedId(); - if ( $assoc_page_id !== null ) { - $assoc_wikipage = WikiPage::newFromId( $assoc_page_id ); - if ( $assoc_wikipage !== null ) { - $propertyDI = new DIProperty( '___CS_ASSOCPG' ); - $dataItem = - DIWikiPage::newFromTitle( $assoc_wikipage->getTitle() ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - } - } - - $parent_page_id = $comment->getParentId(); - if ( $parent_page_id !== null ) { - $parent_wikipage = WikiPage::newFromId( $parent_page_id ); - if ( $parent_wikipage !== null ) { - $propertyDI = new DIProperty( '___CS_REPLYTO' ); - $dataItem = - DIWikiPage::newFromTitle( $parent_wikipage->getTitle() ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - } - } - - $commentTitle = $comment->getCommentTitle(); - if ( $commentTitle !== null ) { - $propertyDI = new DIProperty( '___CS_TITLE' ); - $dataItem = new SMWDIBlob( $comment->getCommentTitle() ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - } - - if ( $GLOBALS['wgCommentStreamsEnableVoting'] === true ) { - $upvotes = $comment->getNumUpVotes(); - $propertyDI = new DIProperty( '___CS_UPVOTES' ); - $dataItem = new SMWDINumber( $upvotes ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - $downvotes = $comment->getNumDownVotes(); - $propertyDI = new DIProperty( '___CS_DOWNVOTES' ); - $dataItem = new SMWDINumber( $downvotes ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - $votediff = $upvotes - $downvotes; - $propertyDI = new DIProperty( '___CS_VOTEDIFF' ); - $dataItem = new SMWDINumber( $votediff ); - $semanticData->addPropertyObjectValue( $propertyDI, $dataItem ); - } - } - return true; - } - - /** - * @param array &$notifications notifications - * @param array &$notificationCategories notification categories - * @param array &$icons notification icons - */ - public static function onBeforeCreateEchoEvent( &$notifications, - &$notificationCategories, &$icons ) { - $notificationCategories['commentstreams-notification-category'] = [ - 'priority' => 3 - ]; - - $notifications['commentstreams-comment-on-watched-page'] = [ - 'category' => 'commentstreams-notification-category', - 'group' => 'positive', - 'section' => 'alert', - 'presentation-model' => EchoCSPresentationModel::class, - 'user-locators' => [ 'EchoUserLocator::locateUsersWatchingTitle' ] - ]; - - $notifications['commentstreams-reply-on-watched-page'] = [ - 'category' => 'commentstreams-notification-category', - 'group' => 'positive', - 'section' => 'alert', - 'presentation-model' => EchoCSPresentationModel::class, - 'user-locators' => [ 'EchoUserLocator::locateUsersWatchingTitle' ], - 'user-filters' => [ 'Comment::locateUsersWatchingComment' ] - ]; - - $notifications['commentstreams-reply-to-watched-comment'] = [ - 'category' => 'commentstreams-notification-category', - 'group' => 'positive', - 'section' => 'alert', - 'presentation-model' => EchoCSPresentationModel::class, - 'user-locators' => [ 'Comment::locateUsersWatchingComment' ] - ]; - } } |