summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CommentStreams/includes/Comment.php')
-rw-r--r--CommentStreams/includes/Comment.php1142
1 files changed, 336 insertions, 806 deletions
diff --git a/CommentStreams/includes/Comment.php b/CommentStreams/includes/Comment.php
index 755c24c3..4769a4ca 100644
--- a/CommentStreams/includes/Comment.php
+++ b/CommentStreams/includes/Comment.php
@@ -23,537 +23,374 @@
namespace MediaWiki\Extension\CommentStreams;
+use ConfigException;
+use FatalError;
use Html;
-use MediaWiki\MediaWikiServices;
+use IContextSource;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\User\UserIdentity;
+use MWException;
use MWTimestamp;
-use Parser;
-use ParserOptions;
-use SMWDataItem;
-use SMWUpdateJob;
+use PageProps;
use Title;
use User;
-use wAvatar;
+use Wikimedia\Assert\Assert;
use WikiPage;
-use WikitextContent;
class Comment {
+ public const CONSTRUCTOR_OPTIONS = [
+ 'CommentStreamsUserAvatarPropertyName',
+ 'CommentStreamsUserRealNamePropertyName',
+ 'CommentStreamsEnableVoting'
+ ];
- // wiki page object for this comment wiki page
- private $wikipage = null;
-
- // data for this comment has been loaded from the database
- private $loaded = false;
-
- // int page ID for the wikipage this comment is on
- private $assoc_page_id;
-
- // int page ID for the wikipage this comment is in reply to or null
- private $parent_page_id;
+ /**
+ * @var CommentStreamsStore
+ */
+ private $commentStreamsStore;
- // string title of comment
- private $comment_title;
+ /**
+ * @var CommentStreamsEchoInterface
+ */
+ private $echoInterface;
- // string wikitext of comment
- private $wikitext = null;
+ /**
+ * @var CommentStreamsSMWInterface
+ */
+ private $smwInterface;
- // string HTML of comment
- private $html = null;
+ /**
+ * @var CommentStreamsSocialProfileInterface
+ */
+ private $socialProfileInterface;
- // User user object for the author of this comment
- private $user = null;
+ /**
+ * @var LinkRenderer
+ */
+ private $linkRenderer;
- // Avatar for author of this comment
- private $avatar = null;
+ /**
+ * @var string
+ */
+ private $userAvatarPropertyName;
- // MWTimestamp the earliest revision date for this comment
- private $creation_timestamp = null;
+ /**
+ * @var string
+ */
+ private $userRealNamePropertyName;
- // MWTimestamp the latest revision date for this comment
- private $modification_timestamp = null;
+ /**
+ * @var mixed
+ */
+ private $enableVoting;
- // number of replies to this comment
- private $num_replies = null;
+ /**
+ * wiki page object for this comment wiki page
+ * @var WikiPage
+ */
+ private $wikipage;
- // number of up votes for this comment
- private $num_up_votes = null;
+ /**
+ * unique id to identify comment block in a page
+ * @var ?string
+ */
+ private $comment_block_id;
- // number of dow votes for this comment
- private $num_down_votes = null;
+ /**
+ * page ID for the wiki page this comment is on
+ * @var int
+ */
+ private $assoc_page_id;
/**
- * create a new Comment object from existing wiki page
- *
- * @param WikiPage $wikipage WikiPage object corresponding to comment page
- * @return Comment|null the newly created comment or null if there was an
- * error
+ * page ID for the wiki page this comment is in reply to or null
+ * @var ?int
*/
- public static function newFromWikiPage( $wikipage ) {
- if ( $wikipage !== null &&
- $wikipage->getTitle()->getNamespace() === NS_COMMENTSTREAMS ) {
- $comment = new Comment( $wikipage );
- if ( $wikipage->exists() ) {
- $comment->loadFromDatabase();
- }
- return $comment;
- }
- return null;
- }
+ private $parent_page_id;
/**
- * create a new Comment object from values and save to database
- * NOTE: since only head comments can contain a comment title, either
- * $comment_title or $parent_page_id must be non null, but not both
- *
- * @param int $assoc_page_id page ID for the wikipage this comment is on
- * @param int $parent_page_id page ID for the wikipage this comment is in
- * reply to or null
- * @param string $comment_title string title of comment
- * @param string $wikitext the wikitext to add
- * @param User $user the user
- * @return Comment|null new comment object or null if there was a problem
- * creating it
+ * title of comment
+ * @var ?string
*/
- public static function newFromValues( $assoc_page_id, $parent_page_id,
- $comment_title, $wikitext, $user ) {
- if ( $comment_title === null && $parent_page_id === null ) {
- return null;
- }
- if ( $comment_title !== null && $parent_page_id !== null ) {
- return null;
- }
- $annotated_wikitext = self::addAnnotations( $wikitext, $comment_title,
- $assoc_page_id );
- $content = new WikitextContent( $annotated_wikitext );
- $success = false;
- while ( !$success ) {
- $index = wfRandomString();
- $title = Title::newFromText( (string)$index, NS_COMMENTSTREAMS );
- if ( !$title->isDeletedQuick() && !$title->exists() ) {
- if ( class_exists( 'MediaWiki\Permissions\PermissionManager' ) ) {
- // MW 1.33+
- if ( !MediaWikiServices::getInstance()
- ->getPermissionManager()
- ->userCan( 'cs-comment', $user, $title )
- ) {
- return null;
- }
- } else {
- if ( !$title->userCan( 'cs-comment' ) ) {
- return null;
- }
- }
+ private $comment_title;
- $wikipage = new WikiPage( $title );
- $status = $wikipage->doEditContent( $content, '',
- EDIT_NEW | EDIT_SUPPRESS_RC, false, $user, null );
- if ( !$status->isOK() && !$status->isGood() ) {
- if ( $status->getMessage()->getKey() == 'edit-already-exists' ) {
- $index = wfRandomString();
- } else {
- return null;
- }
- } else {
- $success = true;
- }
- } else {
- $index = wfRandomString();
- }
- }
- $comment = new Comment( $wikipage );
- $comment->wikitext = $wikitext;
+ /**
+ * wikitext of comment
+ * @var ?string
+ */
+ private $wikitext;
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->insert(
- 'cs_comment_data',
- [
- 'cst_page_id' => $wikipage->getId(),
- 'cst_assoc_page_id' => $assoc_page_id,
- 'cst_parent_page_id' => $parent_page_id,
- 'cst_comment_title' => $comment_title
- ],
- __METHOD__
- );
- if ( !$result ) {
- return null;
- }
- $comment->loadFromValues( $assoc_page_id, $parent_page_id, $comment_title );
+ /**
+ * number of replies to this comment
+ * @var ?int
+ */
+ private $num_replies;
- if ( $parent_page_id === null ) {
- $comment->watch( $user );
- } else {
- self::watchComment( $parent_page_id, $user );
- }
+ /**
+ * user object for the author of this comment
+ * @var User
+ */
+ private $author;
- if ( defined( 'SMW_VERSION' ) ) {
- $job = new SMWUpdateJob( $title, [] );
- \JobQueueGroup::singleton()->push( $job );
- }
+ /**
+ * user object for the last editor of this comment
+ * @var ?UserIdentity
+ */
+ private $lastEditor;
- return $comment;
- }
+ /**
+ * Avatar for author of this comment
+ * @var ?string
+ */
+ private $avatar;
/**
- * constructor
- *
- * @param WikiPage $wikipage WikiPage object corresponding to comment page
+ * @var array
*/
- private function __construct( $wikipage ) {
- $this->wikipage = $wikipage;
- }
+ private static $avatarCache = [];
/**
- * load comment data from database
+ * the earliest revision date for this comment
+ * @var ?MWTimestamp
*/
- private function loadFromDatabase() {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->selectRow(
- 'cs_comment_data',
- [
- 'cst_assoc_page_id',
- 'cst_parent_page_id',
- 'cst_comment_title'
- ],
- [
- 'cst_page_id' => $this->getId()
- ],
- __METHOD__
- );
- if ( $result ) {
- $this->assoc_page_id = (int)$result->cst_assoc_page_id;
- $this->parent_page_id = $result->cst_parent_page_id;
- if ( $this->parent_page_id !== null ) {
- $this->parent_page_id = (int)$this->parent_page_id;
- }
- $this->comment_title = $result->cst_comment_title;
- $this->loaded = true;
- }
- }
+ private $creation_timestamp;
/**
- * load comment data from values
- *
- * @param int $assoc_page_id page ID for the wikipage this comment is on
- * @param int $parent_page_id page ID for the wikipage this comment is in
- * reply to or null
- * @param string $comment_title string title of comment
+ * the latest revision date for this comment
+ * @var ?MWTimestamp
*/
- private function loadFromValues( $assoc_page_id, $parent_page_id,
- $comment_title ) {
- $this->assoc_page_id = (int)$assoc_page_id;
+ private $modification_timestamp;
+
+ /**
+ * Do not instantiate directly. Use CommentStreamsFactory instead.
+ * @param \MediaWiki\Config\ServiceOptions|\Config $options
+ * @param CommentStreamsStore $commentStreamsStore
+ * @param CommentStreamsEchoInterface $echoInterface
+ * @param CommentStreamsSMWInterface $smwInterface
+ * @param CommentStreamsSocialProfileInterface $socialProfileInterface
+ * @param LinkRenderer $linkRenderer
+ * @param WikiPage $wikipage WikiPage object corresponding to comment page
+ * @param ?string $comment_block_id
+ * @param int $assoc_page_id
+ * @param ?int $parent_page_id
+ * @param ?string $comment_title
+ * @param string $wikitext
+ * @throws ConfigException
+ */
+ public function __construct(
+ $options,
+ CommentStreamsStore $commentStreamsStore,
+ CommentStreamsEchoInterface $echoInterface,
+ CommentStreamsSMWInterface $smwInterface,
+ CommentStreamsSocialProfileInterface $socialProfileInterface,
+ LinkRenderer $linkRenderer,
+ WikiPage $wikipage,
+ ?string $comment_block_id,
+ int $assoc_page_id,
+ ?int $parent_page_id,
+ ?string $comment_title,
+ string $wikitext
+ ) {
+ if ( class_exists( '\MediaWiki\Config\ServiceOptions' ) ) {
+ $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
+ }
+ $this->userAvatarPropertyName = $options->get( 'CommentStreamsUserAvatarPropertyName' );
+ $this->userRealNamePropertyName = $options->get( 'CommentStreamsUserRealNamePropertyName' );
+ $this->enableVoting = (bool)$options->get( 'CommentStreamsEnableVoting' );
+ $this->commentStreamsStore = $commentStreamsStore;
+ $this->echoInterface = $echoInterface;
+ $this->smwInterface = $smwInterface;
+ $this->socialProfileInterface = $socialProfileInterface;
+ $this->linkRenderer = $linkRenderer;
+ $this->wikipage = $wikipage;
+ $this->comment_block_id = $comment_block_id;
+ $this->assoc_page_id = $assoc_page_id;
$this->parent_page_id = $parent_page_id;
- if ( $this->parent_page_id !== null ) {
- $this->parent_page_id = (int)$this->parent_page_id;
- }
$this->comment_title = $comment_title;
- $this->loaded = true;
+ $this->wikitext = $wikitext;
+ $this->num_replies = $commentStreamsStore->getNumReplies( $wikipage->getId() );
+ $title = $wikipage->getTitle();
+ $user = CommentStreamsUtils::getAuthor( $title );
+ if ( $user !== null ) {
+ $this->author = $user;
+ }
+ $this->setAvatar();
+ $this->lastEditor = CommentStreamsUtils::getLastEditor( $wikipage ) ?: $this->author;
+ $timestamp = CommentStreamsUtils::getCreationTimestamp( $title );
+ if ( $timestamp !== null ) {
+ $this->creation_timestamp = MWTimestamp::getLocalInstance( $timestamp );
+ }
+ $this->setModificationTimestamp();
}
/**
- * @return int page ID of the comment's wikipage
+ * @return int page ID of the comment's wiki page
*/
- public function getId() {
+ public function getId() : int {
return $this->wikipage->getId();
}
/**
- * @return WikiPage wiki page object associate with this comment page
+ * @return Title Title object associated with this comment page
*/
- public function getWikiPage() {
- return $this->wikipage;
+ public function getTitle() : Title {
+ return $this->wikipage->getTitle();
}
/**
- * @return int page ID for the wikipage this comment is on
+ * @return ?string comment block id
*/
- public function getAssociatedId() {
- if ( $this->loaded === false ) {
- $this->loadFromDatabase();
- }
+ public function getBlockId() : ?string {
+ return $this->comment_block_id;
+ }
+
+ /**
+ * @return int page ID for the wiki page this comment is on
+ */
+ public function getAssociatedId() : int {
return $this->assoc_page_id;
}
/**
- * @return int|null page ID for the wikipage this comment is in reply to or
+ * @return int|null page ID for the wiki page this comment is in reply to or
* null if this comment is a discussion, not a reply
*/
- public function getParentId() {
- if ( $this->loaded === false ) {
- $this->loadFromDatabase();
- }
+ public function getParentId() : ?int {
return $this->parent_page_id;
}
/**
- * @return string the title of the comment
+ * @return ?string the title of the comment
*/
- public function getCommentTitle() {
- if ( $this->loaded === false ) {
- $this->loadFromDatabase();
- }
+ public function getCommentTitle() : ?string {
return $this->comment_title;
}
/**
* @return string wikitext of the comment
*/
- public function getWikiText() {
- if ( $this->wikitext === null ) {
- $wikitext = \ContentHandler::getContentText( $this->wikipage->getContent(
- \Revision::RAW ) );
- $wikitext = $this->removeAnnotations( $wikitext );
- $this->wikitext = $wikitext;
- }
+ public function getWikiText() : string {
return $this->wikitext;
}
/**
+ * @param IContextSource $context
* @return string parsed HTML of the comment
*/
- public function getHTML() {
- if ( $this->html === null ) {
- $this->getWikiText();
- if ( $this->wikitext !== null ) {
- if ( class_exists( \ParserFactory::class ) ) {
- // @requires MediaWiki >= 1.32.0
- $parser = MediaWikiServices::getInstance()->getParserFactory()->create();
- } else {
- $parser = new Parser();
- }
-
- $this->html = $parser->parse( $this->wikitext,
- $this->wikipage->getTitle(), new ParserOptions )->getText();
- }
- }
- return $this->html;
+ public function getHTML( IContextSource $context ) : string {
+ return CommentStreamsUtils::parse( $this->wikitext, $this->wikipage, $context );
}
/**
- * @return User the author of this comment
+ * @return int number of replies
*/
- public function getUser() {
- if ( $this->user === null ) {
- $user_id = $this->wikipage->getOldestRevision()->getUser();
- $this->user = User::newFromId( $user_id );
- }
- return $this->user;
+ public function getNumReplies() : int {
+ return $this->num_replies;
}
/**
- * @return bool true if the last edit to this comment was not done by the
- * original author
+ * @return ?User the author of this comment
*/
- public function isLastEditModerated() {
- $author = $this->wikipage->getOldestRevision()->getUser();
- $lastEditor = $this->wikipage->getRevision()->getUser();
- return $author !== $lastEditor;
+ public function getAuthor() : ?User {
+ return $this->author;
}
/**
* @return string username of the author of this comment
*/
- public function getUsername() {
- return $this->getUser()->getName();
+ public function getUsername() : string {
+ return $this->author->getName();
}
/**
* @return string display name of the author of this comment linked to
* the user's user page if it exists
*/
- public function getUserDisplayName() {
- return self::getDisplayNameFromUser( $this->getUser() );
+ public function getUserDisplayName() : string {
+ return $this->getDisplayNameFromUser( $this->author, true );
}
/**
* @return string display name of the author of this comment
*/
- public function getUserDisplayNameUnlinked() {
- return self::getDisplayNameFromUser( $this->getUser(), false );
- }
-
- /**
- * @return string the URL of the avatar of the author of this comment
- */
- public function getAvatar() {
- if ( $this->avatar === null ) {
- if ( class_exists( 'wAvatar' ) ) {
- // from Extension:SocialProfile
- $avatar = new wAvatar( $this->getUser()->getId(), 'l' );
- $this->avatar = $GLOBALS['wgUploadPath'] . '/avatars/' .
- $avatar->getAvatarImage();
- } else {
- $this->avatar = self::getAvatarFromUser( $this->getUser() );
- }
- }
- return $this->avatar;
+ public function getUserDisplayNameUnlinked() : string {
+ return $this->getDisplayNameFromUser( $this->author, false );
}
/**
- * @return MWTimestamp the earliest revision date for this
+ * @return UserIdentity the last editor of this comment
*/
- public function getCreationTimestamp() {
- if ( $this->creation_timestamp === null ) {
- $this->creation_timestamp = MWTimestamp::getLocalInstance(
- $this->wikipage->getTitle()->getEarliestRevTime() );
- }
- return $this->creation_timestamp;
+ public function getLastEditor() : UserIdentity {
+ return $this->lastEditor;
}
/**
- * @return MWTimestamp the earliest revision date for this
+ * @return bool true if the last edit to this comment was not done by the
+ * original author
*/
- public function getCreationDate() {
- if ( $this->getCreationTimestamp() !== null ) {
- return $this->creation_timestamp->format( "M j \a\\t g:i a" );
- }
- return "";
+ public function isLastEditModerated() : bool {
+ return $this->author->getId() !== $this->lastEditor->getId();
}
/**
- * @return MWTimestamp the latest revision date for this
+ * @return MWTimestamp
*/
- public function getModificationTimestamp() {
- if ( $this->modification_timestamp === null ) {
- $title = $this->wikipage->getTitle();
- if ( $title->getFirstRevision()->getId() === $title->getLatestRevID() ) {
- return null;
- }
-
- $revStore = MediaWikiServices::getInstance()->getRevisionStore();
- $latestRev = $title->getLatestRevId();
- if ( version_compare( MW_VERSION, '1.34', '<' ) ) {
- $timestamp = $revStore->getTimestampFromId( $title, $latestRev );
- } else {
- $timestamp = $revStore->getTimestampFromId( $latestRev );
- }
-
- $this->modification_timestamp = MWTimestamp::getLocalInstance(
- $timestamp );
- }
- return $this->modification_timestamp;
+ public function getCreationTimestamp() : MWTimestamp {
+ return $this->creation_timestamp;
}
/**
- * @return MWTimestamp the earliest revision date for this
+ * @return string
*/
- public function getModificationDate() {
- if ( $this->getModificationTimestamp() !== null ) {
- return $this->modification_timestamp->format( "M j \a\\t g:i a" );
- }
- return null;
+ public function getCreationDate() : string {
+ return $this->creation_timestamp->format( "M j \a\\t g:i a" );
}
/**
- * @return int number of replies
+ * @return ?string
*/
- public function getNumReplies() {
- if ( $this->num_replies === null ) {
- $dbr = wfGetDB( DB_REPLICA );
- $this->num_replies = $dbr->selectRowCount(
- 'cs_comment_data',
- '*',
- [
- 'cst_parent_page_id' => $this->getId()
- ],
- __METHOD__
- );
- }
- return $this->num_replies;
+ public function getModificationDate() : ?string {
+ return $this->modification_timestamp ?
+ $this->modification_timestamp->format( "M j \a\\t g:i a" ) : null;
}
/**
+ * @param IContextSource $context
* @return array get comment data in array suitable for JSON
*/
- public function getJSON() {
+ public function getJSON( IContextSource $context ) : array {
$json = [
- 'commenttitle' => $this->getCommentTitle(),
+ 'pageid' => $this->wikipage->getId(),
+ 'commentblockid' => $this->comment_block_id,
+ 'associatedid' => $this->assoc_page_id,
+ 'parentid' => $this->parent_page_id,
+ 'commenttitle' => $this->comment_title,
+ 'wikitext' => htmlentities( $this->wikitext ),
+ 'html' => $this->getHTML( $context ),
'username' => $this->getUsername(),
+ 'numreplies' => $this->num_replies,
'userdisplayname' => $this->getUserDisplayName(),
- 'avatar' => $this->getAvatar(),
- 'created' => $this->getCreationDate(),
- 'created_timestamp' => $this->getCreationTimestamp()->format( "U" ),
- 'modified' => $this->getModificationDate(),
+ 'avatar' => $this->avatar,
'moderated' => $this->isLastEditModerated() ? "moderated" : null,
- 'wikitext' => htmlentities( $this->getWikiText() ),
- 'html' => $this->getHTML(),
- 'pageid' => $this->getId(),
- 'associatedid' => $this->getAssociatedId(),
- 'parentid' => $this->getParentId(),
- 'numreplies' => $this->getNumReplies(),
+ 'created' => $this->getCreationDate(),
+ 'created_timestamp' => $this->creation_timestamp->format( "U" ),
+ 'modified' => $this->getModificationDate()
];
- if ( $GLOBALS['wgCommentStreamsEnableVoting'] ) {
- $json['numupvotes'] = $this->getNumUpVotes();
- $json['numdownvotes'] = $this->getNumDownVotes();
- }
- return $json;
- }
- /**
- * get vote for user
- *
- * @param User $user the author of the edit
- * @return +1 for up vote, -1 for down vote, 0 for no vote
- */
- public function getVote( $user ) {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->selectRow(
- 'cs_votes',
- [
- 'cst_v_vote'
- ],
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_user_id' => $user->getId()
- ],
- __METHOD__
- );
- if ( $result ) {
- $vote = (int)$result->cst_v_vote;
- if ( $vote > 0 ) {
- return 1;
+ $user = $context->getUser();
+ if ( $this->parent_page_id === null ) {
+ if ( $this->enableVoting ) {
+ $json['numupvotes'] = $this->commentStreamsStore->getNumUpVotes( $this->getId() );
+ $json['numdownvotes'] =
+ $this->commentStreamsStore->getNumDownVotes( $this->getId() );
+ $json['vote'] = $this->getVote( $user );
}
- if ( $vote < 0 ) {
- return -1;
+ if ( $this->echoInterface->isLoaded() ) {
+ $json['watching'] = $this->isWatching( $user ) ? 1 : 0;
}
}
- return 0;
- }
-
- /**
- * @return int number of up votes
- */
- public function getNumUpVotes() {
- if ( $this->num_up_votes === null ) {
- $dbr = wfGetDB( DB_REPLICA );
- $this->num_up_votes = $dbr->selectRowCount(
- 'cs_votes',
- '*',
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_vote' => 1
- ],
- __METHOD__
- );
- }
- return $this->num_up_votes;
- }
- /**
- * @return int number of down votes
- */
- public function getNumDownVotes() {
- if ( $this->num_down_votes === null ) {
- $dbr = wfGetDB( DB_REPLICA );
- $this->num_down_votes = $dbr->selectRowCount(
- 'cs_votes',
- '*',
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_vote' => -1
- ],
- __METHOD__
- );
- }
- return $this->num_down_votes;
+ return $json;
}
/**
@@ -563,184 +400,44 @@ class Comment {
* @param User $user the user voting on the comment
* @return bool database status code
*/
- public function vote( $vote, $user ) {
- if ( $vote !== "-1" && $vote !== "0" && $vote !== "1" ) {
- return false;
- }
- $vote = (int)$vote;
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->selectRow(
- 'cs_votes',
- [
- 'cst_v_vote'
- ],
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_user_id' => $user->getId()
- ],
- __METHOD__
- );
- if ( $result ) {
- if ( $vote === (int)$result->cst_v_vote ) {
- return true;
- }
- if ( $vote === 1 || $vote === -1 ) {
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->update(
- 'cs_votes',
- [
- 'cst_v_vote' => $vote
- ],
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_user_id' => $user->getId()
- ],
- __METHOD__
- );
- } else {
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->delete(
- 'cs_votes',
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_user_id' => $user->getId()
- ],
- __METHOD__
- );
- }
- } else {
- if ( $vote === 0 ) {
- return true;
- }
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->insert(
- 'cs_votes',
- [
- 'cst_v_page_id' => $this->getId(),
- 'cst_v_user_id' => $user->getId(),
- 'cst_v_vote' => $vote
- ],
- __METHOD__
- );
- }
- return $result;
- }
-
- /**
- * watch a comment (get page ID from this comment)
- *
- * @param User $user the user watching the comment
- * @return bool database true for OK, false for error
- */
- public function watch( $user ) {
- return self::watchComment( $this->getID(), $user );
- }
-
- /**
- * watch a comment (get page ID from parameter)
- *
- * @param int $pageid the page ID of the comment to watch
- * @param User $user the user watching the comment
- * @return bool database true for OK, false for error
- */
- private static function watchComment( $pageid, $user ) {
- if ( self::isWatchingComment( $pageid, $user ) ) {
- return true;
- }
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->insert(
- 'cs_watchlist',
- [
- 'cst_wl_page_id' => $pageid,
- 'cst_wl_user_id' => $user->getId()
- ],
- __METHOD__
- );
+ public function vote( string $vote, User $user ) : bool {
+ Assert::parameter( $vote === "-1" || $vote === "0" || $vote === "1", '$vote',
+ 'must be "-1", "0", or "1"' );
+ $result = $this->commentStreamsStore->vote( (int)$vote, $this->getId(), $user->getId() );
+ $this->smwInterface->update( $this->getTitle() );
return $result;
}
/**
- * unwatch a comment
- *
- * @param User $user the user unwatching the comment
- * @return bool database true for OK, false for error
+ * @param User $user
+ * @return int
*/
- public function unwatch( $user ) {
- if ( !$this->isWatching( $user ) ) {
- return true;
- }
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->delete(
- 'cs_watchlist',
- [
- 'cst_wl_page_id' => $this->getId(),
- 'cst_wl_user_id' => $user->getId()
- ],
- __METHOD__
- );
- return $result;
+ public function getVote( User $user ) : int {
+ return $this->commentStreamsStore->getVote( $this->getId(), $user->getId() );
}
/**
- * Check if a particular user is watching this comment
- *
- * @param User $user the user watching the comment
- * @return bool database true for OK, false for error
+ * @param int $user_id
+ * @return bool
*/
- public function isWatching( $user ) {
- return self::isWatchingComment( $this->getId(), $user );
+ public function watch( int $user_id ) : bool {
+ return $this->commentStreamsStore->watch( $this->getId(), $user_id );
}
/**
- * Check if a particular user is watching a comment
- *
- * @param int $pageid the page ID of the comment to check
- * @param User $user the user watching the comment
- * @return bool database true for OK, false for error
+ * @param int $user_id
+ * @return bool
*/
- private static function isWatchingComment( $pageid, $user ) {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->selectRow(
- 'cs_watchlist',
- [
- 'cst_wl_page_id'
- ],
- [
- 'cst_wl_page_id' => $pageid,
- 'cst_wl_user_id' => $user->getId()
- ],
- __METHOD__
- );
- if ( $result ) {
- return true;
- }
- return false;
+ public function unwatch( int $user_id ) : bool {
+ return $this->commentStreamsStore->unwatch( $this->getId(), $user_id );
}
/**
- * Get an array of watchers for this comment
- *
- * @return array of user IDs
+ * @param User $user
+ * @return bool
*/
- public function getWatchers() {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->select(
- 'cs_watchlist',
- [
- 'cst_wl_user_id'
- ],
- [
- 'cst_wl_page_id' => $this->getId()
- ],
- __METHOD__
- );
- $users = [];
- foreach ( $result as $row ) {
- $user_id = $row->cst_wl_user_id;
- $user = User::newFromId( $user_id );
- $users[$user_id] = $user;
- }
- return $users;
+ public function isWatching( User $user ) : bool {
+ return $this->commentStreamsStore->isWatching( $this->getId(), $user->getId() );
}
/**
@@ -749,47 +446,43 @@ class Comment {
* $comment_title may only be non null if this comment has a null parent id
* and vice versa
*
- * @param string $comment_title the new title for the comment
+ * @param ?string $comment_title the new title for the comment
* @param string $wikitext the wikitext to add
* @param User $user the author of the edit
* @return bool true if successful
- */
- public function update( $comment_title, $wikitext, $user ) {
- if ( $comment_title === null && $this->getParentId() === null ) {
- return false;
- }
- if ( $comment_title !== null && $this->getParentId() !== null ) {
- return false;
- }
- $annotated_wikitext =
- self::addAnnotations( $wikitext, $comment_title,
- $this->getAssociatedId() );
- $content = new WikitextContent( $annotated_wikitext );
- $status = $this->wikipage->doEditContent( $content, '',
- EDIT_UPDATE | EDIT_SUPPRESS_RC, false, $user, null );
- if ( !$status->isOK() && !$status->isGood() ) {
- return false;
- }
- $this->wikitext = $wikitext;
- $this->modification_timestamp = null;
- $this->wikipage = WikiPage::newFromID( $this->wikipage->getId() );
-
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->update(
- 'cs_comment_data',
- [
- 'cst_comment_title' => $comment_title
- ],
- [
- 'cst_page_id' => $this->getId()
- ],
- __METHOD__
+ * @throws MWException
+ */
+ public function update(
+ ?string $comment_title,
+ string $wikitext,
+ User $user
+ ) : bool {
+ Assert::parameter(
+ ( $comment_title === null && $this->parent_page_id !== null ) ||
+ ( $comment_title !== null && $this->parent_page_id === null ),
+ '$comment_title',
+ 'must be null if parent page ID is non-null or non-null if parent page ID is null'
+ );
+ $result = $this->commentStreamsStore->updateComment(
+ $this->wikipage,
+ $comment_title,
+ $wikitext,
+ $user
);
if ( !$result ) {
return false;
}
$this->comment_title = $comment_title;
-
+ $this->wikitext = $wikitext;
+ $this->modification_timestamp = null;
+ $wikipage = CommentStreamsUtils::newWikiPageFromId( $this->wikipage->getId(),
+ 'fromdbmaster' );
+ if ( $wikipage !== null ) {
+ $this->wikipage = $wikipage;
+ }
+ if ( $this->parent_page_id === null ) {
+ $this->smwInterface->update( $this->getTitle() );
+ }
return true;
}
@@ -798,134 +491,56 @@ class Comment {
*
* @param User $deleter
* @return bool true if successful
+ * @throws FatalError
+ * @throws MWException
*/
- public function delete( User $deleter ) {
- if ( version_compare( MW_VERSION, '1.35', '<' ) ) {
- $status = $this->getWikiPage()->doDeleteArticleReal(
- 'comment deleted',
- true
- );
- } else {
- $status = $this->getWikiPage()->doDeleteArticleReal(
- 'comment deleted',
- $deleter,
- true
- );
- }
+ public function delete( User $deleter ) : bool {
+ return $this->commentStreamsStore->deleteComment( $this->wikipage, $deleter );
+ }
- if ( !$status->isOK() && !$status->isGood() ) {
- return false;
+ private function setAvatar() {
+ if ( array_key_exists( $this->author->getId(), self::$avatarCache ) ) {
+ $this->avatar = self::$avatarCache[ $this->author->getId() ];
+ return;
}
- $pageid = $this->getId();
- $dbw = wfGetDB( DB_MASTER );
- $result = $dbw->delete(
- 'cs_comment_data',
- [
- 'cst_page_id' => $pageid
- ],
- __METHOD__
- );
- return $result;
- }
+ $this->avatar = $this->socialProfileInterface->getAvatar( $this->author );
- /**
- * add extra information to wikitext before storage
- *
- * @param string $wikitext the wikitext to which to add
- * @param string $comment_title string title of comment
- * @param int $assoc_page_id page ID for the wikipage this comment is on
- * @return string annotated wikitext
- */
- public static function addAnnotations( $wikitext, $comment_title,
- $assoc_page_id ) {
- if ( $comment_title !== null ) {
- $wikitext .= <<<EOT
-{{DISPLAYTITLE:
-$comment_title
-}}
-EOT;
+ if ( $this->avatar === null && $this->userAvatarPropertyName !== null ) {
+ $title = $this->smwInterface->getUserProperty( $this->author,
+ $this->userAvatarPropertyName );
+ if ( $title !== null ) {
+ if ( is_string( $title ) ) {
+ $title = Title::newFromText( $title );
+ }
+ if ( $title->isKnown() && $title->getNamespace() === NS_FILE ) {
+ $file = CommentStreamsUtils::findFile( $title->getText() );
+ if ( $file ) {
+ $this->avatar = $file->createThumb( 48, 48 );
+ }
+ }
+ }
}
- return $wikitext;
+
+ self::$avatarCache[ $this->author->getId() ] = $this->avatar;
}
- /**
- * add extra information to wikitext before storage
- *
- * @param string $wikitext the wikitext to which to add
- * @return string wikitext without annotations
- */
- public function removeAnnotations( $wikitext ) {
- $comment_title = $this->getCommentTitle();
- if ( $comment_title !== null ) {
- $strip = <<<EOT
-{{DISPLAYTITLE:
-$comment_title
-}}
-EOT;
- $wikitext = str_replace( $strip, '', $wikitext );
+ private function setModificationTimestamp() {
+ $title = $this->wikipage->getTitle();
+ $firstRevisionId = CommentStreamsUtils::getFirstRevisionId( $title );
+ if ( $firstRevisionId === null ) {
+ return;
}
- return $wikitext;
- }
- /**
- * get comments for the given page
- *
- * @param int $assoc_page_id ID of page to get comments for
- * @return array array of comments for the given page
- */
- public static function getAssociatedComments( $assoc_page_id ) {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->select(
- 'cs_comment_data',
- [
- 'cst_page_id'
- ],
- [
- 'cst_assoc_page_id' => $assoc_page_id
- ],
- __METHOD__
- );
- $comments = [];
- foreach ( $result as $row ) {
- $page_id = $row->cst_page_id;
- $wikipage = WikiPage::newFromId( $page_id );
- $comment = self::newFromWikiPage( $wikipage );
- if ( $comment !== null ) {
- $comments[] = $comment;
- }
+ $latestRevisionId = $title->getLatestRevId();
+ if ( $firstRevisionId === $latestRevisionId ) {
+ return;
}
- return $comments;
- }
- /**
- * get replies for the given comment
- *
- * @param int $parent_page_id ID of page to get comments for
- * @return array array of comments for the given page
- */
- public static function getReplies( $parent_page_id ) {
- $dbr = wfGetDB( DB_REPLICA );
- $result = $dbr->select(
- 'cs_comment_data',
- [
- 'cst_page_id'
- ],
- [
- 'cst_parent_page_id' => $parent_page_id
- ],
- __METHOD__
- );
- $comments = [];
- foreach ( $result as $row ) {
- $page_id = $row->cst_page_id;
- $wikipage = WikiPage::newFromId( $page_id );
- $comment = self::newFromWikiPage( $wikipage );
- if ( $comment !== null ) {
- $comments[] = $comment;
- }
+ $timestamp = CommentStreamsUtils::getTimestampFromId( $latestRevisionId, $title );
+ if ( $timestamp !== false ) {
+ $this->modification_timestamp = MWTimestamp::getLocalInstance( $timestamp );
}
- return $comments;
}
/**
@@ -933,31 +548,33 @@ EOT;
*
* @param User $user the user
* @param bool $linked whether to link the display name to the user page,
- * if it exists
+ * if it exists
* @return string display name for user
*/
- public static function getDisplayNameFromUser( $user, $linked = true ) {
+ private function getDisplayNameFromUser(
+ User $user,
+ bool $linked
+ ) : string {
if ( $user->isAnon() ) {
- $html = Html::openElement( 'span', [
+ return Html::openElement( 'span', [
'class' => 'cs-comment-author-anonymous'
] )
. wfMessage( 'commentstreams-author-anonymous' )
. Html::closeElement( 'span' );
- return $html;
}
$userpage = $user->getUserPage();
$displayname = null;
- if ( $GLOBALS['wgCommentStreamsUserRealNamePropertyName'] !== null ) {
- $displayname = self::getUserProperty( $user,
- $GLOBALS['wgCommentStreamsUserRealNamePropertyName'] );
+ if ( $this->userRealNamePropertyName !== null ) {
+ $displayname = $this->smwInterface->getUserProperty(
+ $user,
+ $this->userRealNamePropertyName
+ );
}
if ( $displayname === null || strlen( $displayname ) == 0 ) {
- if ( class_exists( 'PageProps' ) ) {
- $values = \PageProps::getInstance()->getProperties( $userpage,
- 'displaytitle' );
- if ( array_key_exists( $userpage->getArticleID(), $values ) ) {
- $displayname = $values[$userpage->getArticleID()];
- }
+ $values = PageProps::getInstance()->getProperties( $userpage,
+ 'displaytitle' );
+ if ( array_key_exists( $userpage->getArticleID(), $values ) ) {
+ $displayname = $values[$userpage->getArticleID()];
}
}
if ( $displayname === null || strlen( $displayname ) == 0 ) {
@@ -967,95 +584,8 @@ EOT;
$displayname = $user->getName();
}
if ( $linked && $userpage->exists() ) {
- $displayname = CommentStreamsUtils::link( $userpage, $displayname );
+ $displayname = $this->linkRenderer->makeLink( $userpage, $displayname );
}
return $displayname;
}
-
- /**
- * return the name of the file page containing the user's avatar
- *
- * @param User $user the user
- * @return string URL of avatar
- */
- public static function getAvatarFromUser( $user ) {
- $avatar = null;
- if ( $GLOBALS['wgCommentStreamsUserAvatarPropertyName'] !== null ) {
- $avatar = self::getUserProperty( $user,
- $GLOBALS['wgCommentStreamsUserAvatarPropertyName'] );
- if ( $avatar !== null ) {
- if ( gettype( $avatar ) === 'string' ) {
- $avatar = Title::newFromText( $avatar );
- if ( $avatar === null ) {
- return null;
- }
- }
- if ( !get_class( $avatar ) === 'Title' ) {
- return null;
- }
- if ( $avatar->isKnown() && $avatar->getNamespace() === NS_FILE ) {
- if ( method_exists( MediaWikiServices::class, 'getRepoGroup' ) ) {
- // MediaWiki 1.34+
- $file = MediaWikiServices::getInstance()->getRepoGroup()
- ->findFile( $avatar );
- } else {
- $file = wfFindFile( $avatar );
- }
- if ( $file ) {
- return $file->getFullUrl();
- }
- }
- }
- }
- return null;
- }
-
- /**
- * return the value of a property on a user page
- *
- * @param User $user the user
- * @param string $propertyName the name of the property
- * @return string|null the value of the property
- */
- private static function getUserProperty( $user, $propertyName ) {
- if ( defined( 'SMW_VERSION' ) ) {
- $userpage = $user->getUserPage();
- if ( $userpage->exists() ) {
- $store = \SMW\StoreFactory::getStore();
- $subject = \SMWDIWikiPage::newFromTitle( $userpage );
- $data = $store->getSemanticData( $subject );
- $property = \SMWDIProperty::newFromUserLabel( $propertyName );
- $values = $data->getPropertyValues( $property );
- if ( count( $values ) > 0 ) {
- // this property should only have one value so pick the first one
- $value = $values[0];
- if ( ( defined( 'SMWDataItem::TYPE_STRING' ) &&
- $value->getDIType() == SMWDataItem::TYPE_STRING ) ||
- $value->getDIType() == SMWDataItem::TYPE_BLOB ) {
- return $value->getString();
- } elseif ( $value->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
- return $value->getTitle();
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Used by Echo to locate the users watching a comment being replied to.
- * @param EchoEvent $event the Echo event
- * @return array array mapping user id to User object
- */
- public static function locateUsersWatchingComment( $event ) {
- $id = $event->getExtraParam( 'parent_id' );
- $wikipage = WikiPage::newFromId( $id );
- if ( $wikipage !== null ) {
- $comment = self::newFromWikiPage( $wikipage );
- if ( $comment !== null ) {
- return $comment->getWatchers();
- }
- }
- return [];
- }
}