first commit
This commit is contained in:
858
includes/Comment.class.php
Normal file
858
includes/Comment.class.php
Normal file
@@ -0,0 +1,858 @@
|
||||
<?php
|
||||
/**
|
||||
* Comment class
|
||||
* Functions for managing comments and everything related to them, including:
|
||||
* -blocking comments from a given user
|
||||
* -counting the total amount of comments in the database
|
||||
* -displaying the form for adding a new comment
|
||||
* -getting all comments for a given page
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
class Comment extends ContextSource {
|
||||
/**
|
||||
* @var CommentsPage: page of the page the <comments /> tag is in
|
||||
*/
|
||||
public $page = null;
|
||||
|
||||
/**
|
||||
* @var Integer: total amount of comments by distinct commenters that the
|
||||
* current page has
|
||||
*/
|
||||
public $commentTotal = 0;
|
||||
|
||||
/**
|
||||
* @var String: text of the current comment
|
||||
*/
|
||||
public $text = null;
|
||||
|
||||
/* START Anpassung znilwiki */
|
||||
public $CommentUsernameKOK = null; /* 25.10.2013 von Kai-Ole Kirsten */
|
||||
/* ENDE Anpassung znilwiki */
|
||||
|
||||
/**
|
||||
* Date when the comment was posted
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
public $date = null;
|
||||
|
||||
/**
|
||||
* @var Integer: internal ID number (Comments.CommentID DB field) of the
|
||||
* current comment that we're dealing with
|
||||
*/
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* @var Integer: ID of the parent comment, if this is a child comment
|
||||
*/
|
||||
public $parentID = 0;
|
||||
|
||||
/**
|
||||
* The current vote from this user on this comment
|
||||
*
|
||||
* @var int|boolean: false if no vote, otherwise -1, 0, or 1
|
||||
*/
|
||||
public $currentVote = false;
|
||||
|
||||
/**
|
||||
* @var string: comment score (SUM() of all votes) of the current comment
|
||||
*/
|
||||
public $currentScore = '0';
|
||||
|
||||
/**
|
||||
* Username of the user who posted the comment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $username = '';
|
||||
|
||||
/**
|
||||
* IP of the comment poster
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $ip = '';
|
||||
|
||||
/**
|
||||
* ID of the user who posted the comment
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $userID = 0;
|
||||
|
||||
/**
|
||||
* @TODO document
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $userPoints = 0;
|
||||
|
||||
/**
|
||||
* Comment ID of the thread this comment is in
|
||||
* this is the ID of the parent comment if there is one,
|
||||
* or this comment if there is not
|
||||
* Used for sorting
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
public $thread = null;
|
||||
|
||||
/**
|
||||
* Unix timestamp when the comment was posted
|
||||
* Used for sorting
|
||||
* Processed from $date
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
public $timestamp = null;
|
||||
|
||||
/**
|
||||
* Constructor - set the page ID
|
||||
*
|
||||
* @param $page CommentsPage: ID number of the current page
|
||||
* @param IContextSource $context
|
||||
* @param $data: straight from the DB about the comment
|
||||
*/
|
||||
public function __construct( CommentsPage $page, $context = null, $data ) {
|
||||
$this->page = $page;
|
||||
|
||||
$this->setContext( $context );
|
||||
|
||||
$this->username = $data['Comment_Username'];
|
||||
$this->ip = $data['Comment_IP'];
|
||||
$this->text = $data['Comment_Text'];
|
||||
$this->date = $data['Comment_Date'];
|
||||
$this->userID = $data['Comment_user_id'];
|
||||
$this->userPoints = $data['Comment_user_points'];
|
||||
$this->id = $data['CommentID'];
|
||||
$this->parentID = $data['Comment_Parent_ID'];
|
||||
$this->thread = $data['thread'];
|
||||
$this->timestamp = $data['timestamp'];
|
||||
|
||||
if ( isset( $data['current_vote'] ) ) {
|
||||
$vote = $data['current_vote'];
|
||||
} else {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$row = $dbr->selectRow(
|
||||
'Comments_Vote',
|
||||
array( 'Comment_Vote_Score' ),
|
||||
array(
|
||||
'Comment_Vote_ID' => $this->id,
|
||||
'Comment_Vote_Username' => $this->getUser()->getName()
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
if ( $row !== false ) {
|
||||
$vote = $row->Comment_Vote_Score;
|
||||
} else {
|
||||
$vote = false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->currentVote = $vote;
|
||||
|
||||
$this->currentScore = isset( $data['total_vote'] )
|
||||
? $data['total_vote'] : $this->getScore();
|
||||
}
|
||||
|
||||
public static function newFromID( $id ) {
|
||||
$context = RequestContext::getMain();
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
if ( !is_numeric( $id ) || $id == 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
$params = array();
|
||||
$joinConds = array();
|
||||
|
||||
// Defaults (for non-social wikis)
|
||||
$tables[] = 'Comments';
|
||||
$fields = array(
|
||||
'Comment_Username', 'Comment_IP', 'Comment_Text',
|
||||
'Comment_Date', 'Comment_Date AS timestamp',
|
||||
'Comment_user_id', 'CommentID', 'Comment_Parent_ID',
|
||||
'CommentID', 'Comment_Page_ID'
|
||||
);
|
||||
|
||||
// If SocialProfile is installed, query the user_stats table too.
|
||||
if (
|
||||
class_exists( 'UserProfile' ) &&
|
||||
$dbr->tableExists( 'user_stats' )
|
||||
) {
|
||||
$tables[] = 'user_stats';
|
||||
$fields[] = 'stats_total_points';
|
||||
$joinConds = array(
|
||||
'Comments' => array(
|
||||
'LEFT JOIN', 'Comment_user_id = stats_user_id'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Perform the query
|
||||
$res = $dbr->select(
|
||||
$tables,
|
||||
$fields,
|
||||
array( 'CommentID' => $id ),
|
||||
__METHOD__,
|
||||
$params,
|
||||
$joinConds
|
||||
);
|
||||
|
||||
$row = $res->fetchObject();
|
||||
|
||||
if ( $row->Comment_Parent_ID == 0 ) {
|
||||
$thread = $row->CommentID;
|
||||
} else {
|
||||
$thread = $row->Comment_Parent_ID;
|
||||
}
|
||||
$data = array(
|
||||
'Comment_Username' => $row->Comment_Username,
|
||||
'Comment_IP' => $row->Comment_IP,
|
||||
'Comment_Text' => $row->Comment_Text,
|
||||
'Comment_Date' => $row->Comment_Date,
|
||||
'Comment_user_id' => $row->Comment_user_id,
|
||||
'Comment_user_points' => ( isset( $row->stats_total_points ) ? number_format( $row->stats_total_points ) : 0 ),
|
||||
'CommentID' => $row->CommentID,
|
||||
'Comment_Parent_ID' => $row->Comment_Parent_ID,
|
||||
'thread' => $thread,
|
||||
'timestamp' => wfTimestamp( TS_UNIX, $row->timestamp )
|
||||
);
|
||||
|
||||
$page = new CommentsPage( $row->Comment_Page_ID, $context );
|
||||
|
||||
return new Comment( $page, $context, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and return the text for this comment
|
||||
*
|
||||
* @return mixed|string
|
||||
* @throws MWException
|
||||
*/
|
||||
function getText() {
|
||||
global $wgParser;
|
||||
|
||||
$commentText = trim( str_replace( '"', "'", $this->text ) );
|
||||
$comment_text_parts = explode( "\n", $commentText );
|
||||
$comment_text_fix = '';
|
||||
foreach ( $comment_text_parts as $part ) {
|
||||
$comment_text_fix .= ( ( $comment_text_fix ) ? "\n" : '' ) . trim( $part );
|
||||
}
|
||||
|
||||
if ( $this->getTitle()->getArticleID() > 0 ) {
|
||||
$commentText = $wgParser->recursiveTagParse( $comment_text_fix );
|
||||
} else {
|
||||
$commentText = $this->getOutput()->parse( $comment_text_fix );
|
||||
}
|
||||
|
||||
// really bad hack because we want to parse=firstline, but don't want wrapping <p> tags
|
||||
if ( substr( $commentText, 0 , 3 ) == '<p>' ) {
|
||||
$commentText = substr( $commentText, 3 );
|
||||
}
|
||||
|
||||
if ( substr( $commentText, strlen( $commentText ) -4 , 4 ) == '</p>' ) {
|
||||
$commentText = substr( $commentText, 0, strlen( $commentText ) -4 );
|
||||
}
|
||||
|
||||
// make sure link text is not too long (will overflow)
|
||||
// this function changes too long links to <a href=#>http://www.abc....xyz.html</a>
|
||||
$commentText = preg_replace_callback(
|
||||
"/(<a[^>]*>)(.*?)(<\/a>)/i",
|
||||
array( 'CommentFunctions', 'cutCommentLinkText' ),
|
||||
$commentText
|
||||
);
|
||||
|
||||
return $commentText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the comment and all necessary info into the Comments table in the
|
||||
* database.
|
||||
*
|
||||
* @param string $text: text of the comment
|
||||
* @param CommentsPage $page: container page
|
||||
* @param User $user: user commenting
|
||||
* @param int $parentID: ID of parent comment, if this is a reply
|
||||
*
|
||||
* @return Comment: the added comment
|
||||
*/
|
||||
static function add( $text, CommentsPage $page, User $user, $parentID ) {
|
||||
global $wgCommentsInRecentChanges;
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
$context = RequestContext::getMain();
|
||||
|
||||
wfSuppressWarnings();
|
||||
$commentDate = date( 'Y-m-d H:i:s' );
|
||||
wfRestoreWarnings();
|
||||
/*if ( $this->getUser()->isLoggedIn() ) {
|
||||
$kok_username = $user->getName();
|
||||
} else {
|
||||
$kok_username = $this->CommentUsernameKOK;
|
||||
$kok_username = preg_replace('/<.*>/i', '', $kok_username);
|
||||
$kok_username = preg_replace('/[^A-Za-z0-9. \-\@]/i', '', $kok_username);
|
||||
$kok_username = str_replace("1'1", '', $kok_username);
|
||||
$kok_username = str_replace('USER_NAME', '', $kok_username);
|
||||
$kok_username = str_replace('DESC', '', $kok_username);
|
||||
$kok_username = str_replace('(*)', '', $kok_username);
|
||||
$kok_username = str_replace('EXEC', '', $kok_username);
|
||||
}*/
|
||||
$dbw->insert(
|
||||
'Comments',
|
||||
array(
|
||||
'Comment_Page_ID' => $page->id,
|
||||
'Comment_Username' => $user->getName(),
|
||||
'Comment_user_id' => $user->getId(),
|
||||
'Comment_Text' => $text,
|
||||
'Comment_Date' => $commentDate,
|
||||
'Comment_Parent_ID' => $parentID,
|
||||
'Comment_IP' => $_SERVER['REMOTE_ADDR']
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
$commentId = $dbw->insertId();
|
||||
$dbw->commit( __METHOD__ ); // misza: added this
|
||||
$id = $commentId;
|
||||
|
||||
$page->clearCommentListCache();
|
||||
|
||||
// Add a log entry.
|
||||
self::log( 'add', $user, $page->id, $commentId, $text );
|
||||
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
if (
|
||||
class_exists( 'UserProfile' ) &&
|
||||
$dbr->tableExists( 'user_stats' )
|
||||
) {
|
||||
$res = $dbr->select( // need this data for seeding a Comment object
|
||||
'user_stats',
|
||||
'stats_total_points',
|
||||
array( 'stats_user_id' => $user->getId() ),
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
$row = $res->fetchObject();
|
||||
$userPoints = number_format( $row->stats_total_points );
|
||||
} else {
|
||||
$userPoints = 0;
|
||||
}
|
||||
|
||||
if ( $parentID == 0 ) {
|
||||
$thread = $id;
|
||||
} else {
|
||||
$thread = $parentID;
|
||||
}
|
||||
$data = array(
|
||||
'Comment_Username' => $user->getName(),
|
||||
'Comment_IP' => $context->getRequest()->getIP(),
|
||||
'Comment_Text' => $text,
|
||||
'Comment_Date' => $commentDate,
|
||||
'Comment_user_id' => $user->getID(),
|
||||
'Comment_user_points' => $userPoints,
|
||||
'CommentID' => $id,
|
||||
'Comment_Parent_ID' => $parentID,
|
||||
'thread' => $thread,
|
||||
'timestamp' => strtotime( $commentDate )
|
||||
);
|
||||
|
||||
$page = new CommentsPage( $page->id, $context );
|
||||
$comment = new Comment( $page, $context, $data );
|
||||
|
||||
Hooks::run( 'Comment::add', array( $comment, $commentId, $comment->page->id ) );
|
||||
/* ## START Kommentar auch per Email versenden ## 11/2014 Bernhard Linz */
|
||||
$znilpageTitle = "";
|
||||
$comment_mailto = "root@linz.email";
|
||||
$comment_mailsubject = "Neuer Kommentar von: " . $kok_username . " - IP: " . $_SERVER['REMOTE_ADDR'] . " - DNS: " . gethostbyaddr($_SERVER['REMOTE_ADDR']) ;
|
||||
$comment_mailfrom = "MIME-Version: 1.0\r\n";
|
||||
$comment_mailfrom .= "Content-type: text/html; charset=utf-8\r\n";
|
||||
$comment_mailfrom .= "From: znil.net Kommentare <root@linz.email>\r\n";
|
||||
$comment_url = "<a href=\"http://znil.net/index.php?title={$znilpageTitle}#comment-{$commentId}\">http://znil.net/index.php?title={$znilpageTitle}#comment-{$commentId}</a>";
|
||||
$comment_mailtext = $commentDate . "<br><br>" . $comment_url . "<br><br><hr>" . "IP: " . $_SERVER['REMOTE_ADDR'] . "<br>" . "DNS: " . gethostbyaddr($_SERVER['REMOTE_ADDR']) ."<br><br>" . $kok_username . "<br><br>" . $text;
|
||||
$comment_mailtext = nl2br($comment_mailtext);
|
||||
mail($comment_mailto, $comment_mailsubject, $comment_mailtext, $comment_mailfrom);
|
||||
/* ## ENDE Bernhard Linz */
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the score for this comment from the database table Comments_Vote
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getScore() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$row = $dbr->selectRow(
|
||||
'Comments_Vote',
|
||||
array( 'SUM(Comment_Vote_Score) AS CommentScore' ),
|
||||
array( 'Comment_Vote_ID' => $this->id ),
|
||||
__METHOD__
|
||||
);
|
||||
$score = '0';
|
||||
if ( $row !== false && $row->CommentScore ) {
|
||||
$score = $row->CommentScore;
|
||||
}
|
||||
return $score;
|
||||
}
|
||||
|
||||
/* START Anpassungen znilwiki */
|
||||
/* ## START ## 25.10.2013 Hinzugefügt von Kai-Ole */
|
||||
function setCommentUsernameKOK( $UsernameKOK ) {
|
||||
$this->CommentUsernameKOK = $UsernameKOK;
|
||||
}
|
||||
/* ## ENDE ## 25.10.2013 Kai-Ole */
|
||||
/* ENDE Anpassungen znilwiki */
|
||||
|
||||
/**
|
||||
* Adds a vote for a comment if the user hasn't voted for said comment yet.
|
||||
*
|
||||
* @param $value int: upvote or downvote (1 or -1)
|
||||
*/
|
||||
function vote( $value ) {
|
||||
global $wgMemc;
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
|
||||
if ( $value < -1 ) { // limit to range -1 -> 0 -> 1
|
||||
$value = -1;
|
||||
} elseif ( $value > 1 ) {
|
||||
$value = 1;
|
||||
}
|
||||
|
||||
if ( $value == $this->currentVote ) { // user toggling off a preexisting vote
|
||||
$value = 0;
|
||||
}
|
||||
|
||||
wfSuppressWarnings();
|
||||
$commentDate = date( 'Y-m-d H:i:s' );
|
||||
wfRestoreWarnings();
|
||||
|
||||
if ( $this->currentVote === false ) { // no vote, insert
|
||||
$dbw->insert(
|
||||
'Comments_Vote',
|
||||
array(
|
||||
'Comment_Vote_id' => $this->id,
|
||||
'Comment_Vote_Username' => $this->getUser()->getName(),
|
||||
'Comment_Vote_user_id' => $this->getUser()->getId(),
|
||||
'Comment_Vote_Score' => $value,
|
||||
'Comment_Vote_Date' => $commentDate,
|
||||
'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR']
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
} else { // already a vote, update
|
||||
$dbw->update(
|
||||
'Comments_Vote',
|
||||
array(
|
||||
'Comment_Vote_Score' => $value,
|
||||
'Comment_Vote_Date' => $commentDate,
|
||||
'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR']
|
||||
),
|
||||
array(
|
||||
'Comment_Vote_id' => $this->id,
|
||||
'Comment_Vote_Username' => $this->getUser()->getName(),
|
||||
'Comment_Vote_user_id' => $this->getUser()->getId(),
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
$dbw->commit( __METHOD__ );
|
||||
|
||||
// update cache for comment list
|
||||
// should perform better than deleting cache completely since Votes happen more frequently
|
||||
$key = wfMemcKey( 'comment', 'pagethreadlist', $this->page->id );
|
||||
$comments = $wgMemc->get( $key );
|
||||
if ( $comments ) {
|
||||
foreach ( $comments as &$comment ) {
|
||||
if ( $comment->id == $this->id ) {
|
||||
$comment->currentScore = $this->currentScore;
|
||||
}
|
||||
}
|
||||
$wgMemc->set( $key, $comments );
|
||||
}
|
||||
|
||||
$score = $this->getScore();
|
||||
|
||||
$this->currentVote = $value;
|
||||
$this->currentScore = $score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes entries from Comments and Comments_Vote tables and clears caches
|
||||
*/
|
||||
function delete() {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
$dbw->delete(
|
||||
'Comments',
|
||||
array( 'CommentID' => $this->id ),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->delete(
|
||||
'Comments_Vote',
|
||||
array( 'Comment_Vote_ID' => $this->id ),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->commit( __METHOD__ );
|
||||
|
||||
// Log the deletion to Special:Log/comments.
|
||||
self::log( 'delete', $this->getUser(), $this->page->id, $this->id );
|
||||
|
||||
// Clear memcache & Squid cache
|
||||
$this->page->clearCommentListCache();
|
||||
|
||||
// Ping other extensions that may have hooked into this point (i.e. LinkFilter)
|
||||
Hooks::run( 'Comment::delete', array( $this, $this->id, $this->page->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an action in the comment log.
|
||||
*
|
||||
* @param string $action Action to log, can be either 'add' or 'delete'
|
||||
* @param User $user User who performed the action
|
||||
* @param int $pageId Page ID of the page that contains the comment thread
|
||||
* @param int $commentId Comment ID of the affected comment
|
||||
* @param string $commentText Supplementary log comment, if any
|
||||
*/
|
||||
static function log( $action, $user, $pageId, $commentId, $commentText = null ) {
|
||||
global $wgCommentsInRecentChanges;
|
||||
$logEntry = new ManualLogEntry( 'comments', $action );
|
||||
$logEntry->setPerformer( $user );
|
||||
$logEntry->setTarget( Title::newFromId( $pageId ) );
|
||||
if ( $commentText !== null ) {
|
||||
$logEntry->setComment( $commentText );
|
||||
}
|
||||
$logEntry->setParameters( array(
|
||||
'4::commentid' => $commentId
|
||||
) );
|
||||
$logId = $logEntry->insert();
|
||||
$logEntry->publish( $logId, ( $wgCommentsInRecentChanges ? 'rcandudp' : 'udp' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTML for the comment vote links
|
||||
*
|
||||
* @param int $voteType up (+1) vote or down (-1) vote
|
||||
* @return string
|
||||
*/
|
||||
function getVoteLink( $voteType ) {
|
||||
global $wgExtensionAssetsPath;
|
||||
|
||||
// Blocked users cannot vote, obviously
|
||||
if ( $this->getUser()->isBlocked() ) {
|
||||
return '';
|
||||
}
|
||||
if ( !$this->getUser()->isAllowed( 'comment' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$voteLink = '';
|
||||
if ( $this->getUser()->isLoggedIn() ) {
|
||||
$voteLink .= '<a id="comment-vote-link" data-comment-id="' .
|
||||
$this->id . '" data-vote-type="' . $voteType .
|
||||
'" data-voting="' . $this->page->voting . '" href="javascript:void(0);">';
|
||||
} else {
|
||||
$login = SpecialPage::getTitleFor( 'Userlogin' ); // Anonymous users need to log in before they can vote
|
||||
$returnTo = $this->page->title->getPrefixedDBkey(); // Determine a sane returnto URL parameter
|
||||
|
||||
$voteLink .=
|
||||
"<a href=\"" .
|
||||
htmlspecialchars( $login->getLocalURL( array( 'returnto' => $returnTo ) ) ) .
|
||||
"\" rel=\"nofollow\">";
|
||||
}
|
||||
|
||||
$imagePath = $wgExtensionAssetsPath . '/Comments/resources/images';
|
||||
if ( $voteType == 1 ) {
|
||||
if ( $this->currentVote == 1 ) {
|
||||
$voteLink .= "<img src=\"{$imagePath}/up-voted.png\" border=\"0\" alt=\"+\" /></a>";
|
||||
} else {
|
||||
$voteLink .= "<img src=\"{$imagePath}/up-unvoted.png\" border=\"0\" alt=\"+\" /></a>";
|
||||
}
|
||||
} else {
|
||||
if ( $this->currentVote == -1 ) {
|
||||
$voteLink .= "<img src=\"{$imagePath}/down-voted.png\" border=\"0\" alt=\"+\" /></a>";
|
||||
} else {
|
||||
$voteLink .= "<img src=\"{$imagePath}/down-unvoted.png\" border=\"0\" alt=\"+\" /></a>";
|
||||
}
|
||||
}
|
||||
|
||||
return $voteLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the HTML for this comment and ignore section
|
||||
*
|
||||
* @param array $blockList list of users the current user has blocked
|
||||
* @param array $anonList map of ip addresses to names like anon#1, anon#2
|
||||
* @return string html
|
||||
*/
|
||||
function display( $blockList, $anonList ) {
|
||||
if ( $this->parentID == 0 ) {
|
||||
$container_class = 'full';
|
||||
} else {
|
||||
$container_class = 'reply';
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
if ( in_array( $this->username, $blockList ) ) {
|
||||
$output .= $this->showIgnore( false, $container_class );
|
||||
$output .= $this->showComment( true, $container_class, $blockList, $anonList );
|
||||
} else {
|
||||
$output .= $this->showIgnore( true, $container_class );
|
||||
$output .= $this->showComment( false, $container_class, $blockList, $anonList );
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function displayForCommentOfTheDay() {
|
||||
$output = '';
|
||||
|
||||
$title2 = $this->page->getTitle();
|
||||
|
||||
if ( $this->userID != 0 ) {
|
||||
$title = Title::makeTitle( NS_USER, $this->username );
|
||||
$commentPoster_Display = $this->username;
|
||||
$commentPoster = '<a href="' . $title->getFullURL() . '" title="' . $title->getText() . '" rel="nofollow">' . $this->username . '</a>';
|
||||
if ( class_exists( 'wAvatar' ) ) {
|
||||
$avatar = new wAvatar( $this->userID, 's' );
|
||||
$commentIcon = $avatar->getAvatarImage();
|
||||
} else {
|
||||
$commentIcon = '';
|
||||
}
|
||||
} else {
|
||||
$commentPoster_Display = wfMessage( 'comments-anon-name' )->plain();
|
||||
$commentPoster = wfMessage( 'comments-anon-name' )->plain();
|
||||
$commentIcon = 'default_s.gif';
|
||||
}
|
||||
|
||||
$avatarHTML = '';
|
||||
if ( class_exists( 'wAvatar' ) ) {
|
||||
global $wgUploadPath;
|
||||
$avatarHTML = '<img src="' . $wgUploadPath . '/avatars/' . $commentIcon .
|
||||
'" alt="" align="middle" border="0"/>';
|
||||
}
|
||||
|
||||
$comment_text = substr( $this->text, 0, 50 - strlen( $commentPoster_Display ) );
|
||||
if ( $comment_text != $this->text ) {
|
||||
$comment_text .= wfMessage( 'ellipsis' )->plain();
|
||||
}
|
||||
|
||||
$output .= '<div class="cod">';
|
||||
$sign = '';
|
||||
if ( $this->currentScore > 0 ) {
|
||||
$sign = '+';
|
||||
} elseif ( $this->currentScore < 0 ) {
|
||||
$sign = '-'; // this *really* shouldn't be happening...
|
||||
}
|
||||
$output .= '<span class="cod-score">' . $sign . $this->currentScore .
|
||||
'</span> ' . $avatarHTML .
|
||||
'<span class="cod-poster">' . $commentPoster . '</span>';
|
||||
$output .= '<span class="cod-comment"><a href="' .
|
||||
$title2->getFullURL() . '#comment-' . $this->id .
|
||||
'" title="' . $title2->getText() . '">' . $comment_text .
|
||||
'</a></span>';
|
||||
$output .= '</div>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the box for if this comment has been ignored
|
||||
*
|
||||
* @param bool $hide
|
||||
* @param $containerClass
|
||||
* @return string
|
||||
*/
|
||||
function showIgnore( $hide = false, $containerClass ) {
|
||||
$blockListTitle = SpecialPage::getTitleFor( 'CommentIgnoreList' );
|
||||
|
||||
$style = '';
|
||||
if ( $hide ) {
|
||||
$style = " style='display:none;'";
|
||||
}
|
||||
|
||||
$output = "<div id='ignore-{$this->id}' class='c-ignored {$containerClass}'{$style}>\n";
|
||||
$output .= wfMessage( 'comments-ignore-message' )->parse();
|
||||
$output .= '<div class="c-ignored-links">' . "\n";
|
||||
$output .= "<a href=\"javascript:void(0);\" data-comment-id=\"{$this->id}\">" .
|
||||
$this->msg( 'comments-show-comment-link' )->plain() . '</a> | ';
|
||||
$output .= '<a href="' . htmlspecialchars( $blockListTitle->getFullURL() ) . '">' .
|
||||
$this->msg( 'comments-manage-blocklist-link' )->plain() . '</a>';
|
||||
$output .= '</div>' . "\n";
|
||||
$output .= '</div>' . "\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the comment
|
||||
*
|
||||
* @param bool $hide: if true, comment is returned but hidden (display:none)
|
||||
* @param $containerClass
|
||||
* @param $blockList
|
||||
* @param $anonList
|
||||
* @return string
|
||||
*/
|
||||
function showComment( $hide = false, $containerClass, $blockList, $anonList ) {
|
||||
global $wgUserLevels, $wgExtensionAssetsPath;
|
||||
|
||||
$style = '';
|
||||
if ( $hide ) {
|
||||
$style = " style='display:none;'";
|
||||
}
|
||||
|
||||
$commentPosterLevel = '';
|
||||
|
||||
if ( $this->userID != 0 ) {
|
||||
$title = Title::makeTitle( NS_USER, $this->username );
|
||||
|
||||
$commentPoster = '<a href="' . htmlspecialchars( $title->getFullURL() ) .
|
||||
'" rel="nofollow">' . $this->username . '</a>';
|
||||
|
||||
$CommentReplyTo = $this->username;
|
||||
|
||||
if ( $wgUserLevels && class_exists( 'UserLevel' ) ) {
|
||||
$user_level = new UserLevel( $this->userPoints );
|
||||
$commentPosterLevel = "{$user_level->getLevelName()}";
|
||||
}
|
||||
|
||||
$user = User::newFromId( $this->userID );
|
||||
$CommentReplyToGender = $user->getOption( 'gender', 'unknown' );
|
||||
} else {
|
||||
$anonMsg = $this->msg( 'comments-anon-name' )->inContentLanguage()->plain();
|
||||
$commentPoster = $anonMsg . ' #' . $anonList[$this->username];
|
||||
$CommentReplyTo = $anonMsg;
|
||||
$CommentReplyToGender = 'unknown'; // Undisclosed gender as anon user
|
||||
}
|
||||
|
||||
// Comment delete button for privileged users
|
||||
$dlt = '';
|
||||
|
||||
if ( $this->getUser()->isAllowed( 'commentadmin' ) ) {
|
||||
$dlt = ' | <span class="c-delete">' .
|
||||
'<a href="javascript:void(0);" rel="nofollow" class="comment-delete-link" data-comment-id="' .
|
||||
$this->id . '">' .
|
||||
$this->msg( 'comments-delete-link' )->plain() . '</a></span>';
|
||||
}
|
||||
|
||||
// Reply Link (does not appear on child comments)
|
||||
$replyRow = '';
|
||||
if ( $this->getUser()->isAllowed( 'comment' ) ) {
|
||||
if ( $this->parentID == 0 ) {
|
||||
if ( $replyRow ) {
|
||||
$replyRow .= wfMessage( 'pipe-separator' )->plain();
|
||||
}
|
||||
$replyRow .= " | <a href=\"#end\" rel=\"nofollow\" class=\"comments-reply-to\" data-comment-id=\"{$this->id}\" data-comments-safe-username=\"" .
|
||||
htmlspecialchars( $CommentReplyTo, ENT_QUOTES ) . "\" data-comments-user-gender=\"" .
|
||||
htmlspecialchars( $CommentReplyToGender ) . '">' .
|
||||
wfMessage( 'comments-reply' )->plain() . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->parentID == 0 ) {
|
||||
$comment_class = 'f-message';
|
||||
} else {
|
||||
$comment_class = 'r-message';
|
||||
}
|
||||
|
||||
// Display Block icon for logged in users for comments of users
|
||||
// that are already not in your block list
|
||||
$blockLink = '';
|
||||
|
||||
if (
|
||||
$this->getUser()->getID() != 0 && $this->getUser()->getID() != $this->userID &&
|
||||
!( in_array( $this->userID, $blockList ) )
|
||||
) {
|
||||
$blockLink = '<a href="javascript:void(0);" rel="nofollow" class="comments-block-user" data-comments-safe-username="' .
|
||||
htmlspecialchars( $this->username, ENT_QUOTES ) .
|
||||
'" data-comments-comment-id="' . $this->id . '" data-comments-user-id="' .
|
||||
$this->userID . "\">
|
||||
<img src=\"{$wgExtensionAssetsPath}/Comments/resources/images/block.svg\" border=\"0\" alt=\"\"/>
|
||||
</a>";
|
||||
}
|
||||
|
||||
// Default avatar image, if SocialProfile extension isn't enabled
|
||||
global $wgCommentsDefaultAvatar;
|
||||
$avatarImg = '<img src="' . $wgCommentsDefaultAvatar . '" alt="" border="0" />';
|
||||
// If SocialProfile *is* enabled, then use its wAvatar class to get the avatars for each commenter
|
||||
if ( class_exists( 'wAvatar' ) ) {
|
||||
$avatar = new wAvatar( $this->userID, 'ml' );
|
||||
$avatarImg = $avatar->getAvatarURL() . "\n";
|
||||
}
|
||||
|
||||
$output = "<div id='comment-{$this->id}' class='c-item {$containerClass}'{$style}>" . "\n";
|
||||
$output .= "<div class=\"c-avatar\">{$avatarImg}</div>" . "\n";
|
||||
$output .= '<div class="c-container">' . "\n";
|
||||
$output .= '<div class="c-user">' . "\n";
|
||||
$output .= "{$commentPoster}";
|
||||
$output .= "<span class=\"c-user-level\">{$commentPosterLevel}</span> {$blockLink}" . "\n";
|
||||
|
||||
wfSuppressWarnings(); // E_STRICT bitches about strtotime()
|
||||
$output .= '<div class="c-time">' .
|
||||
wfMessage(
|
||||
'comments-time-ago',
|
||||
CommentFunctions::getTimeAgo( strtotime( $this->date ) )
|
||||
)->parse() . '</div>' . "\n";
|
||||
wfRestoreWarnings();
|
||||
|
||||
$output .= '<div class="c-score">' . "\n";
|
||||
$output .= $this->getScoreHTML();
|
||||
$output .= '</div>' . "\n";
|
||||
|
||||
$output .= '</div>' . "\n";
|
||||
$output .= "<div class=\"c-comment {$comment_class}\">" . "\n";
|
||||
$output .= $this->getText();
|
||||
$output .= '</div>' . "\n";
|
||||
$output .= '<div class="c-actions">' . "\n";
|
||||
if ( $this->page->title ) { // for some reason doesn't always exist
|
||||
$output .= '<a href="' . htmlspecialchars( $this->page->title->getFullURL() ) . "#comment-{$this->id}\" rel=\"nofollow\">" .
|
||||
$this->msg( 'comments-permalink' )->plain() . '</a> ';
|
||||
}
|
||||
if ( $replyRow || $dlt ) {
|
||||
$output .= "{$replyRow} {$dlt}" . "\n";
|
||||
}
|
||||
$output .= '</div>' . "\n";
|
||||
$output .= '</div>' . "\n";
|
||||
$output .= '<div class="visualClear"></div>' . "\n";
|
||||
$output .= '</div>' . "\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML for the comment score section of the comment
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getScoreHTML() {
|
||||
$output = '';
|
||||
|
||||
if ( $this->page->allowMinus == true || $this->page->allowPlus == true ) {
|
||||
$output .= '<span class="c-score-title">' .
|
||||
wfMessage( 'comments-score-text' )->plain() .
|
||||
" <span id=\"Comment{$this->id}\">{$this->currentScore}</span></span>";
|
||||
|
||||
// Voting is possible only when database is unlocked
|
||||
if ( !wfReadOnly() ) {
|
||||
// You can only vote for other people's comments, not for your own
|
||||
if ( $this->getUser()->getName() != $this->username ) {
|
||||
$output .= "<span id=\"CommentBtn{$this->id}\">";
|
||||
if ( $this->page->allowPlus == true ) {
|
||||
$output .= $this->getVoteLink( 1 );
|
||||
}
|
||||
|
||||
if ( $this->page->allowMinus == true ) {
|
||||
$output .= $this->getVoteLink( -1 );
|
||||
}
|
||||
$output .= '</span>';
|
||||
} else {
|
||||
$output .= wfMessage( 'word-separator' )->plain() . wfMessage( 'comments-you' )->plain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
319
includes/CommentFunctions.class.php
Normal file
319
includes/CommentFunctions.class.php
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
class CommentFunctions {
|
||||
/**
|
||||
* The following four functions are borrowed
|
||||
* from includes/wikia/GlobalFunctionsNY.php
|
||||
*/
|
||||
static function dateDiff( $date1, $date2 ) {
|
||||
$dtDiff = $date1 - $date2;
|
||||
|
||||
$totalDays = intval( $dtDiff / ( 24 * 60 * 60 ) );
|
||||
$totalSecs = $dtDiff - ( $totalDays * 24 * 60 * 60 );
|
||||
$dif['mo'] = intval( $totalDays / 30 );
|
||||
$dif['d'] = $totalDays;
|
||||
$dif['h'] = $h = intval( $totalSecs / ( 60 * 60 ) );
|
||||
$dif['m'] = $m = intval( ( $totalSecs - ( $h * 60 * 60 ) ) / 60 );
|
||||
$dif['s'] = $totalSecs - ( $h * 60 * 60 ) - ( $m * 60 );
|
||||
|
||||
return $dif;
|
||||
}
|
||||
|
||||
static function getTimeOffset( $time, $timeabrv, $timename ) {
|
||||
$timeStr = ''; // misza: initialize variables, DUMB FUCKS!
|
||||
if( $time[$timeabrv] > 0 ) {
|
||||
// Give grep a chance to find the usages:
|
||||
// comments-time-days, comments-time-hours, comments-time-minutes, comments-time-seconds, comments-time-months
|
||||
$timeStr = wfMessage( "comments-time-{$timename}", $time[$timeabrv] )->parse();
|
||||
}
|
||||
if( $timeStr ) {
|
||||
$timeStr .= ' ';
|
||||
}
|
||||
return $timeStr;
|
||||
}
|
||||
|
||||
static function getTimeAgo( $time ) {
|
||||
$timeArray = self::dateDiff( time(), $time );
|
||||
$timeStr = '';
|
||||
$timeStrMo = self::getTimeOffset( $timeArray, 'mo', 'months' );
|
||||
$timeStrD = self::getTimeOffset( $timeArray, 'd', 'days' );
|
||||
$timeStrH = self::getTimeOffset( $timeArray, 'h', 'hours' );
|
||||
$timeStrM = self::getTimeOffset( $timeArray, 'm', 'minutes' );
|
||||
$timeStrS = self::getTimeOffset( $timeArray, 's', 'seconds' );
|
||||
|
||||
if ( $timeStrMo ) {
|
||||
$timeStr = $timeStrMo;
|
||||
} else {
|
||||
$timeStr = $timeStrD;
|
||||
if( $timeStr < 2 ) {
|
||||
$timeStr .= $timeStrH;
|
||||
$timeStr .= $timeStrM;
|
||||
if( !$timeStr ) {
|
||||
$timeStr .= $timeStrS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !$timeStr ) {
|
||||
$timeStr = wfMessage( 'comments-time-seconds', 1 )->parse();
|
||||
}
|
||||
return $timeStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that link text is not too long by changing too long links to
|
||||
* <a href=#>http://www.abc....xyz.html</a>
|
||||
*
|
||||
* @param $matches Array
|
||||
* @return String: shortened URL
|
||||
*/
|
||||
public static function cutCommentLinkText( $matches ) {
|
||||
$tagOpen = $matches[1];
|
||||
$linkText = $matches[2];
|
||||
$tagClose = $matches[3];
|
||||
|
||||
$image = preg_match( "/<img src=/i", $linkText );
|
||||
$isURL = ( preg_match( '%^(?:http|https|ftp)://(?:www\.)?.*$%i', $linkText ) ? true : false );
|
||||
|
||||
if( $isURL && !$image && strlen( $linkText ) > 30 ) {
|
||||
$start = substr( $linkText, 0, ( 30 / 2 ) - 3 );
|
||||
$end = substr( $linkText, strlen( $linkText ) - ( 30 / 2 ) + 3, ( 30 / 2 ) - 3 );
|
||||
$linkText = trim( $start ) . wfMessage( 'ellipsis' )->escaped() . trim( $end );
|
||||
}
|
||||
return $tagOpen . $linkText . $tagClose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple spam check -- checks the supplied text against MediaWiki's
|
||||
* built-in regex-based spam filters
|
||||
*
|
||||
* @param $text String: text to check for spam patterns
|
||||
* @return Boolean: true if it contains spam, otherwise false
|
||||
*/
|
||||
public static function isSpam( $text ) {
|
||||
global $wgSpamRegex, $wgSummarySpamRegex;
|
||||
|
||||
$retVal = false;
|
||||
// Allow to hook other anti-spam extensions so that sites that use,
|
||||
// for example, AbuseFilter, Phalanx or SpamBlacklist can add additional
|
||||
// checks
|
||||
Hooks::run( 'Comments::isSpam', array( &$text, &$retVal ) );
|
||||
if ( $retVal ) {
|
||||
// Should only be true here...
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
// Run text through $wgSpamRegex (and $wgSummarySpamRegex if it has been specified)
|
||||
if ( $wgSpamRegex && preg_match( $wgSpamRegex, $text ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $wgSummarySpamRegex && is_array( $wgSummarySpamRegex ) ) {
|
||||
foreach ( $wgSummarySpamRegex as $spamRegex ) {
|
||||
if ( preg_match( $spamRegex, $text ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the supplied text for links
|
||||
*
|
||||
* @param $text String: text to check
|
||||
* @return Boolean: true if it contains links, otherwise false
|
||||
*/
|
||||
public static function haveLinks( $text ) {
|
||||
$linkPatterns = array(
|
||||
'/(https?)|(ftp):\/\//',
|
||||
'/=\\s*[\'"]?\\s*mailto:/',
|
||||
);
|
||||
foreach ( $linkPatterns as $linkPattern ) {
|
||||
if ( preg_match( $linkPattern, $text ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks comments from a user
|
||||
*
|
||||
* @param User $blocker The user who is blocking someone else's comments
|
||||
* @param int $userId User ID of the guy whose comments we want to block
|
||||
* @param mixed $userName User name of the same guy
|
||||
*/
|
||||
public static function blockUser( $blocker, $userId, $userName ) {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
|
||||
wfSuppressWarnings(); // E_STRICT bitching
|
||||
$date = date( 'Y-m-d H:i:s' );
|
||||
wfRestoreWarnings();
|
||||
$dbw->insert(
|
||||
'Comments_block',
|
||||
array(
|
||||
'cb_user_id' => $blocker->getId(),
|
||||
'cb_user_name' => $blocker->getName(),
|
||||
'cb_user_id_blocked' => $userId,
|
||||
'cb_user_name_blocked' => $userName,
|
||||
'cb_date' => $date
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->commit( __METHOD__ );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the list of blocked users from the database
|
||||
*
|
||||
* @param int $userId User ID for whom we're getting the blocks(?)
|
||||
* @return array List of comment-blocked users
|
||||
*/
|
||||
static function getBlockList( $userId ) {
|
||||
$blockList = array();
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$res = $dbr->select(
|
||||
'Comments_block',
|
||||
'cb_user_name_blocked',
|
||||
array( 'cb_user_id' => $userId ),
|
||||
__METHOD__
|
||||
);
|
||||
foreach ( $res as $row ) {
|
||||
$blockList[] = $row->cb_user_name_blocked;
|
||||
}
|
||||
return $blockList;
|
||||
}
|
||||
|
||||
static function isUserCommentBlocked( $userId, $userIdBlocked ) {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$s = $dbr->selectRow(
|
||||
'Comments_block',
|
||||
array( 'cb_id' ),
|
||||
array(
|
||||
'cb_user_id' => $userId,
|
||||
'cb_user_id_blocked' => $userIdBlocked
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
if ( $s !== false ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a user from your personal comment-block list.
|
||||
*
|
||||
* @param int $userId Your user ID
|
||||
* @param int $userIdBlocked User ID of the blocked user
|
||||
*/
|
||||
public static function deleteBlock( $userId, $userIdBlocked ) {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
$dbw->delete(
|
||||
'Comments_block',
|
||||
array(
|
||||
'cb_user_id' => $userId,
|
||||
'cb_user_id_blocked' => $userIdBlocked
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->commit( __METHOD__ );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort threads ascending
|
||||
*
|
||||
* @param $x
|
||||
* @param $y
|
||||
* @return int
|
||||
*/
|
||||
public static function sortAsc( $x, $y ) {
|
||||
// return -1 - x goes above y
|
||||
// return 1 - x goes below y
|
||||
// return 0 - order irrelevant (only when x == y)
|
||||
|
||||
if ( $x[0]->timestamp < $y[0]->timestamp ) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort threads descending
|
||||
*
|
||||
* @param $x
|
||||
* @param $y
|
||||
* @return int
|
||||
*/
|
||||
public static function sortDesc( $x, $y ) {
|
||||
// return -1 - x goes above y
|
||||
// return 1 - x goes below y
|
||||
// return 0 - order irrelevant (only when x == y)
|
||||
|
||||
if ( $x[0]->timestamp > $y[0]->timestamp ) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort threads by score
|
||||
*
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public static function sortScore( $x, $y ) {
|
||||
// return -1 - x goes above y
|
||||
// return 1 - x goes below y
|
||||
// return 0 - order irrelevant (only when x == y)
|
||||
|
||||
if ( $x[0]->currentScore > $y[0]->currentScore ) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort COMMENTS (not threads) by score
|
||||
*
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public static function sortCommentScore( $x, $y ) {
|
||||
// return -1 - x goes above y
|
||||
// return 1 - x goes below y
|
||||
// return 0 - order irrelevant (only when x == y)
|
||||
|
||||
if ( $x->currentScore > $y->currentScore ) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the comments purely by the time, from earliest to latest
|
||||
*
|
||||
* @param $x
|
||||
* @param $y
|
||||
* @return int
|
||||
*/
|
||||
public static function sortTime( $x, $y ) {
|
||||
// return -1 - x goes above y
|
||||
// return 1 - x goes below y
|
||||
// return 0 - order irrelevant (only when x == y)
|
||||
if ( $x->timestamp == $y->timestamp ) {
|
||||
return 0;
|
||||
} elseif ( $x->timestamp < $y->timestamp ) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
includes/Comments.alias.php
Normal file
15
includes/Comments.alias.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* Aliases for special pages
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
// @codingStandardsIgnoreFile
|
||||
|
||||
$specialPageAliases = array();
|
||||
|
||||
/** English */
|
||||
$specialPageAliases['en'] = array(
|
||||
'CommentIgnoreList' => array( 'CommentIgnoreList' ),
|
||||
);
|
||||
173
includes/Comments.hooks.php
Normal file
173
includes/Comments.hooks.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* Hooked functions used by the Comments extension.
|
||||
* All class methods are public and static.
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
* @author Jack Phoenix <jack@countervandalism.net>
|
||||
* @author Alexia E. Smith
|
||||
* @copyright (c) 2013 Curse Inc.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
|
||||
* @link https://www.mediawiki.org/wiki/Extension:Comments Documentation
|
||||
*/
|
||||
|
||||
class CommentsHooks {
|
||||
/**
|
||||
* Registers the <comments> tag with the Parser.
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @return bool
|
||||
*/
|
||||
public static function onParserFirstCallInit( Parser &$parser ) {
|
||||
$parser->setHook( 'comments', array( 'CommentsHooks', 'displayComments' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for onParserFirstCallInit().
|
||||
*
|
||||
* @param $input
|
||||
* @param array $args
|
||||
* @param Parser $parser
|
||||
* @return string HTML
|
||||
*/
|
||||
public static function displayComments( $input, $args, $parser ) {
|
||||
global $wgOut, $wgCommentsSortDescending;
|
||||
|
||||
$parser->disableCache();
|
||||
// If an unclosed <comments> tag is added to a page, the extension will
|
||||
// go to an infinite loop...this protects against that condition.
|
||||
$parser->setHook( 'comments', array( 'CommentsHooks', 'nonDisplayComments' ) );
|
||||
|
||||
$title = $parser->getTitle();
|
||||
if ( $title->getArticleID() == 0 && $title->getDBkey() == 'CommentListGet' ) {
|
||||
return self::nonDisplayComments( $input, $args, $parser );
|
||||
}
|
||||
|
||||
// Add required CSS & JS via ResourceLoader
|
||||
$wgOut->addModuleStyles( 'ext.comments.css' );
|
||||
$wgOut->addModules( 'ext.comments.js' );
|
||||
$wgOut->addJsConfigVars( array( 'wgCommentsSortDescending' => $wgCommentsSortDescending ) );
|
||||
|
||||
// Parse arguments
|
||||
// The preg_match() lines here are to support the old-style way of
|
||||
// adding arguments:
|
||||
// <comments>
|
||||
// Allow=Foo,Bar
|
||||
// Voting=Plus
|
||||
// </comments>
|
||||
// whereas the normal, standard MediaWiki style, which this extension
|
||||
// also supports is: <comments allow="Foo,Bar" voting="Plus" />
|
||||
$allow = '';
|
||||
if ( preg_match( '/^\s*Allow\s*=\s*(.*)/mi', $input, $matches ) ) {
|
||||
$allow = htmlspecialchars( $matches[1] );
|
||||
} elseif ( !empty( $args['allow'] ) ) {
|
||||
$allow = $args['allow'];
|
||||
}
|
||||
|
||||
$voting = '';
|
||||
if ( preg_match( '/^\s*Voting\s*=\s*(.*)/mi', $input, $matches ) ) {
|
||||
$voting = htmlspecialchars( $matches[1] );
|
||||
} elseif (
|
||||
!empty( $args['voting'] ) &&
|
||||
in_array( strtoupper( $args['voting'] ), array( 'OFF', 'PLUS', 'MINUS' ) )
|
||||
) {
|
||||
$voting = $args['voting'];
|
||||
}
|
||||
|
||||
$commentsPage = new CommentsPage( $title->getArticleID(), $wgOut->getContext() );
|
||||
$commentsPage->allow = $allow;
|
||||
$commentsPage->setVoting( $voting );
|
||||
|
||||
$output = '<div class="comments-body">';
|
||||
|
||||
if ( $wgCommentsSortDescending ) { // form before comments
|
||||
$output .= '<a id="end" rel="nofollow"></a>';
|
||||
if ( !wfReadOnly() ) {
|
||||
$output .= $commentsPage->displayForm();
|
||||
} else {
|
||||
$output .= wfMessage( 'comments-db-locked' )->parse();
|
||||
}
|
||||
}
|
||||
|
||||
$output .= $commentsPage->displayOrderForm();
|
||||
|
||||
$output .= '<div id="allcomments">' . $commentsPage->display() . '</div>';
|
||||
|
||||
// If the database is in read-only mode, display a message informing the
|
||||
// user about that, otherwise allow them to comment
|
||||
if ( !$wgCommentsSortDescending ) { // form after comments
|
||||
if ( !wfReadOnly() ) {
|
||||
$output .= $commentsPage->displayForm();
|
||||
} else {
|
||||
$output .= wfMessage( 'comments-db-locked' )->parse();
|
||||
}
|
||||
$output .= '<a id="end" rel="nofollow"></a>';
|
||||
}
|
||||
|
||||
$output .= '</div>'; // div.comments-body
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function nonDisplayComments( $input, $args, $parser ) {
|
||||
$attr = array();
|
||||
|
||||
foreach ( $args as $name => $value ) {
|
||||
$attr[] = htmlspecialchars( $name ) . '="' . htmlspecialchars( $value ) . '"';
|
||||
}
|
||||
|
||||
$output = '<comments';
|
||||
if ( count( $attr ) > 0 ) {
|
||||
$output .= ' ' . implode( ' ', $attr );
|
||||
}
|
||||
|
||||
if ( !is_null( $input ) ) {
|
||||
$output .= '>' . htmlspecialchars( $input ) . '</comments>';
|
||||
} else {
|
||||
$output .= ' />';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the three new required database tables into the database when the
|
||||
* user runs /maintenance/update.php (the core database updater script).
|
||||
*
|
||||
* @param DatabaseUpdater $updater
|
||||
* @return bool
|
||||
*/
|
||||
public static function onLoadExtensionSchemaUpdates( $updater ) {
|
||||
$dir = __DIR__ . '/../sql';
|
||||
|
||||
$dbType = $updater->getDB()->getType();
|
||||
// For non-MySQL/MariaDB/SQLite DBMSes, use the appropriately named file
|
||||
if ( !in_array( $dbType, array( 'mysql', 'sqlite' ) ) ) {
|
||||
$filename = "comments.{$dbType}.sql";
|
||||
} else {
|
||||
$filename = 'comments.sql';
|
||||
}
|
||||
|
||||
$updater->addExtensionUpdate( array( 'addTable', 'Comments', "{$dir}/{$filename}", true ) );
|
||||
$updater->addExtensionUpdate( array( 'addTable', 'Comments_Vote', "{$dir}/{$filename}", true ) );
|
||||
$updater->addExtensionUpdate( array( 'addTable', 'Comments_block', "{$dir}/{$filename}", true ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For integration with the Renameuser extension.
|
||||
*
|
||||
* @param RenameuserSQL $renameUserSQL
|
||||
* @return bool
|
||||
*/
|
||||
public static function onRenameUserSQL( $renameUserSQL ) {
|
||||
$renameUserSQL->tables['Comments'] = array( 'Comment_Username', 'Comment_user_id' );
|
||||
$renameUserSQL->tables['Comments_Vote'] = array( 'Comment_Vote_Username', 'Comment_Vote_user_id' );
|
||||
$renameUserSQL->tables['Comments_block'] = array( 'cb_user_name', 'cb_user_id' );
|
||||
$renameUserSQL->tables['Comments_block'] = array( 'cb_user_name_blocked', 'cb_user_id_blocked' );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
12
includes/Comments.i18n.magic.php
Normal file
12
includes/Comments.i18n.magic.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Magic words for extension.
|
||||
*/
|
||||
|
||||
$magicWords = array();
|
||||
|
||||
/** English (English) */
|
||||
$magicWords['en'] = array(
|
||||
'NUMBEROFCOMMENTS' => array( 0, 'NUMBEROFCOMMENTS' ),
|
||||
'NUMBEROFCOMMENTSPAGE' => array( 0, 'NUMBEROFCOMMENTSPAGE' ),
|
||||
);
|
||||
65
includes/CommentsLogFormatter.class.php
Normal file
65
includes/CommentsLogFormatter.class.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Logging formatter for Comments' log entries.
|
||||
*
|
||||
* @file
|
||||
* @date 28 July 2013
|
||||
*/
|
||||
class CommentsLogFormatter extends LogFormatter {
|
||||
/**
|
||||
* Gets the log action, including username.
|
||||
*
|
||||
* This is a copy of LogFormatter::getActionText() with one "escaped"
|
||||
* swapped to parse; no other changes here!
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getActionText() {
|
||||
if ( $this->canView( LogPage::DELETED_ACTION ) ) {
|
||||
$element = $this->getActionMessage();
|
||||
if ( $element instanceof Message ) {
|
||||
$element = $this->plaintext ? $element->text() : $element->parse(); // <-- here's the change!
|
||||
}
|
||||
if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
|
||||
$element = $this->styleRestricedElement( $element );
|
||||
}
|
||||
} else {
|
||||
$performer = $this->getPerformerElement() . $this->msg( 'word-separator' )->text();
|
||||
$element = $performer . $this->getRestrictedElement( 'rev-deleted-event' );
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats parameters intented for action message from
|
||||
* array of all parameters. There are three hardcoded
|
||||
* parameters (array is zero-indexed, this list not):
|
||||
* - 1: user name with premade link
|
||||
* - 2: usable for gender magic function
|
||||
* - 3: target page with premade link
|
||||
* @return array
|
||||
*/
|
||||
protected function getMessageParameters() {
|
||||
if ( isset( $this->parsedParameters ) ) {
|
||||
return $this->parsedParameters;
|
||||
}
|
||||
|
||||
$entry = $this->entry;
|
||||
$params = $this->extractParameters();
|
||||
|
||||
$commentId = $params[3]; // = $4, because array numbering starts from 0
|
||||
|
||||
$params[0] = Message::rawParam( $this->getPerformerElement() );
|
||||
$params[1] = $this->canView( LogPage::DELETED_USER ) ? $entry->getPerformer()->getName() : '';
|
||||
$title = $entry->getTarget();
|
||||
if ( $title instanceof Title ) { // healthy paranoia
|
||||
$title->setFragment( '#comment-' . $commentId );
|
||||
}
|
||||
$params[2] = Message::rawParam( $this->makePageLink( $title ) );
|
||||
|
||||
// Bad things happens if the numbers are not in correct order
|
||||
ksort( $params );
|
||||
return $this->parsedParameters = $params;
|
||||
}
|
||||
}
|
||||
120
includes/CommentsOfTheDay.class.php
Normal file
120
includes/CommentsOfTheDay.class.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Comments of the Day parser hook -- shows the five newest comments that have
|
||||
* been sent within the last 24 hours.
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
* @date 27 November 2015
|
||||
*/
|
||||
|
||||
class CommentsOfTheDay {
|
||||
|
||||
/**
|
||||
* Register the new <commentsoftheday /> parser hook with the Parser.
|
||||
*
|
||||
* @param Parser $parser Instance of Parser
|
||||
* @return bool
|
||||
*/
|
||||
public static function registerTag( &$parser ) {
|
||||
$parser->setHook( 'commentsoftheday', array( __CLASS__, 'getHTML' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments of the day -- five newest comments within the last 24 hours
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public static function getHTML( $input, $args, $parser ) {
|
||||
$comments = self::get( (bool)$args['nocache'] );
|
||||
$commentOutput = '';
|
||||
|
||||
foreach ( $comments as $comment ) {
|
||||
$commentOutput .= $comment->displayForCommentOfTheDay();
|
||||
}
|
||||
|
||||
$output = '';
|
||||
if ( !empty( $commentOutput ) ) {
|
||||
$output .= $commentOutput;
|
||||
} else {
|
||||
$output .= wfMessage( 'comments-no-comments-of-day' )->plain();
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments of the day, either from cache or the DB.
|
||||
*
|
||||
* @param bool $skipCache Skip using memcached and fetch data directly from the DB?
|
||||
* @param int $cacheTime How long to cache the results in memcached? Default is one day (60 * 60 * 24).
|
||||
* @param array $whereConds WHERE conditions for the SQL clause (if not using the defaults)
|
||||
* @return array
|
||||
*/
|
||||
public static function get( $skipCache = false, $cacheTime = 86400, $whereConds = array() ) {
|
||||
global $wgMemc;
|
||||
|
||||
// Try memcached first
|
||||
$key = wfMemcKey( 'comments-of-the-day', 'standalone-hook-new' );
|
||||
$data = $wgMemc->get( $key );
|
||||
|
||||
if ( $data ) { // success, got it from memcached!
|
||||
$comments = $data;
|
||||
} elseif ( !$data || $skipCache ) { // just query the DB
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
if ( empty( $whereConds ) ) {
|
||||
$whereConds = array(
|
||||
'Comment_Page_ID = page_id',
|
||||
'UNIX_TIMESTAMP(Comment_Date) > ' . ( time() - ( $cacheTime ) )
|
||||
);
|
||||
}
|
||||
|
||||
$res = $dbr->select(
|
||||
array( 'Comments', 'page' ),
|
||||
array(
|
||||
'Comment_Username', 'Comment_IP', 'Comment_Text',
|
||||
'Comment_Date', 'Comment_User_Id', 'CommentID',
|
||||
'Comment_Parent_ID', 'Comment_Page_ID'
|
||||
),
|
||||
$whereConds,
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
$comments = array();
|
||||
|
||||
foreach ( $res as $row ) {
|
||||
if ( $row->Comment_Parent_ID == 0 ) {
|
||||
$thread = $row->CommentID;
|
||||
} else {
|
||||
$thread = $row->Comment_Parent_ID;
|
||||
}
|
||||
$data = array(
|
||||
'Comment_Username' => $row->Comment_Username,
|
||||
'Comment_IP' => $row->Comment_IP,
|
||||
'Comment_Text' => $row->Comment_Text,
|
||||
'Comment_Date' => $row->Comment_Date,
|
||||
'Comment_user_id' => $row->Comment_User_Id,
|
||||
// @todo FIXME: absolutely disgusting -- should use Language's formatNum() for better i18n
|
||||
'Comment_user_points' => ( isset( $row->stats_total_points ) ? number_format( $row->stats_total_points ) : 0 ),
|
||||
'CommentID' => $row->CommentID,
|
||||
'Comment_Parent_ID' => $row->Comment_Parent_ID,
|
||||
'thread' => $thread,
|
||||
'timestamp' => wfTimestamp( TS_UNIX, $row->Comment_Date )
|
||||
);
|
||||
|
||||
$page = new CommentsPage( $row->Comment_Page_ID, new RequestContext() );
|
||||
$comments[] = new Comment( $page, new RequestContext(), $data );
|
||||
}
|
||||
|
||||
usort( $comments, array( 'CommentFunctions', 'sortCommentScore' ) );
|
||||
$comments = array_slice( $comments, 0, 5 );
|
||||
|
||||
$wgMemc->set( $key, $comments, $cacheTime );
|
||||
}
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
}
|
||||
608
includes/CommentsPage.class.php
Normal file
608
includes/CommentsPage.class.php
Normal file
@@ -0,0 +1,608 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Comments methods that are not specific to one comments,
|
||||
* but specific to one comment-using page
|
||||
*/
|
||||
class CommentsPage extends ContextSource {
|
||||
|
||||
/**
|
||||
* @var Integer: page ID (page.page_id) of this page.
|
||||
*/
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* @var Integer: if this is _not_ 0, then the comments are ordered by their
|
||||
* Comment_Score in descending order
|
||||
*/
|
||||
public $orderBy = 0;
|
||||
|
||||
/**
|
||||
* @var Integer: maximum amount of threads of comments shown per page before pagination is enabled;
|
||||
*/
|
||||
public $limit = 50;
|
||||
|
||||
/**
|
||||
* @TODO document
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $pagerLimit = 9;
|
||||
|
||||
/**
|
||||
* The current page of comments we are paged to
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $currentPagerPage = 0;
|
||||
|
||||
/**
|
||||
* List of users allowed to comment. Empty string - any user can comment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $allow = '';
|
||||
|
||||
/**
|
||||
* What voting to disallow - disallow PLUS, MINUS, or BOTH
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $voting = '';
|
||||
|
||||
/**
|
||||
* @var Boolean: allow positive (plus) votes?
|
||||
*/
|
||||
public $allowPlus = true;
|
||||
|
||||
/**
|
||||
* @var Boolean: allow negative (minus) votes?
|
||||
*/
|
||||
public $allowMinus = true;
|
||||
|
||||
/**
|
||||
* @TODO document
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $pageQuery = 'cpage';
|
||||
|
||||
/**
|
||||
* @var Title: title object for this page
|
||||
*/
|
||||
public $title = null;
|
||||
|
||||
/**
|
||||
* List of lists of comments on this page.
|
||||
* Each list is a separate 'thread' of comments, with the parent comment first, and any replies following
|
||||
* Not populated until display() is called
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $comments = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param $pageID: current page ID
|
||||
*/
|
||||
function __construct ( $pageID, $context ) {
|
||||
$this->id = $pageID;
|
||||
$this->setContext( $context );
|
||||
$this->title = Title::newFromID( $pageID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of comments on this page
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function countTotal() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$count = 0;
|
||||
$s = $dbr->selectRow(
|
||||
'Comments',
|
||||
array( 'COUNT(*) AS CommentCount' ),
|
||||
array( 'Comment_Page_ID' => $this->id ),
|
||||
__METHOD__
|
||||
);
|
||||
if ( $s !== false ) {
|
||||
$count = $s->CommentCount;
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID number of the latest comment for the current page.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function getLatestCommentID() {
|
||||
$latestCommentID = 0;
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$s = $dbr->selectRow(
|
||||
'Comments',
|
||||
array( 'CommentID' ),
|
||||
array( 'Comment_Page_ID' => $this->id ),
|
||||
__METHOD__,
|
||||
array( 'ORDER BY' => 'Comment_Date DESC', 'LIMIT' => 1 )
|
||||
);
|
||||
if ( $s !== false ) {
|
||||
$latestCommentID = $s->CommentID;
|
||||
}
|
||||
return $latestCommentID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set voting either totally off, or disallow "thumbs down" or disallow
|
||||
* "thumbs up".
|
||||
*
|
||||
* @param string $voting 'OFF', 'PLUS' or 'MINUS' (will be strtoupper()ed)
|
||||
*/
|
||||
function setVoting( $voting ) {
|
||||
$this->voting = $voting;
|
||||
$voting = strtoupper( $voting );
|
||||
|
||||
if ( $voting == 'OFF' ) {
|
||||
$this->allowMinus = false;
|
||||
$this->allowPlus = false;
|
||||
}
|
||||
if ( $voting == 'PLUS' ) {
|
||||
$this->allowMinus = false;
|
||||
}
|
||||
if ( $voting == 'MINUS' ) {
|
||||
$this->allowPlus = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all comments, called by display().
|
||||
*
|
||||
* @return array Array containing every possible bit of information about
|
||||
* a comment, including score, timestamp and more
|
||||
*/
|
||||
public function getComments() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
// Defaults (for non-social wikis)
|
||||
$tables = array(
|
||||
'Comments',
|
||||
'vote1' => 'Comments_Vote',
|
||||
'vote2' => 'Comments_Vote',
|
||||
);
|
||||
$fields = array(
|
||||
'Comment_Username', 'Comment_IP', 'Comment_Text',
|
||||
'Comment_Date', 'Comment_Date AS timestamp',
|
||||
'Comment_user_id', 'CommentID', 'Comment_Parent_ID',
|
||||
'vote1.Comment_Vote_Score AS current_vote',
|
||||
'SUM(vote2.Comment_Vote_Score) AS comment_score'
|
||||
);
|
||||
$joinConds = array(
|
||||
// For current user's vote
|
||||
'vote1' => array(
|
||||
'LEFT JOIN',
|
||||
array(
|
||||
'vote1.Comment_Vote_ID = CommentID',
|
||||
'vote1.Comment_Vote_Username' => $this->getUser()->getName()
|
||||
)
|
||||
),
|
||||
// For total vote count
|
||||
'vote2' => array( 'LEFT JOIN', 'vote2.Comment_Vote_ID = CommentID' )
|
||||
);
|
||||
$params = array( 'GROUP BY' => 'CommentID' );
|
||||
|
||||
// If SocialProfile is installed, query the user_stats table too.
|
||||
if (
|
||||
class_exists( 'UserProfile' ) &&
|
||||
$dbr->tableExists( 'user_stats' )
|
||||
) {
|
||||
$tables[] = 'user_stats';
|
||||
$fields[] = 'stats_total_points';
|
||||
$joinConds['Comments'] = array(
|
||||
'LEFT JOIN', 'Comment_user_id = stats_user_id'
|
||||
);
|
||||
}
|
||||
|
||||
// Perform the query
|
||||
$res = $dbr->select(
|
||||
$tables,
|
||||
$fields,
|
||||
array( 'Comment_Page_ID' => $this->id ),
|
||||
__METHOD__,
|
||||
$params,
|
||||
$joinConds
|
||||
);
|
||||
|
||||
$comments = array();
|
||||
|
||||
foreach ( $res as $row ) {
|
||||
if ( $row->Comment_Parent_ID == 0 ) {
|
||||
$thread = $row->CommentID;
|
||||
} else {
|
||||
$thread = $row->Comment_Parent_ID;
|
||||
}
|
||||
$data = array(
|
||||
'Comment_Username' => $row->Comment_Username,
|
||||
'Comment_IP' => $row->Comment_IP,
|
||||
'Comment_Text' => $row->Comment_Text,
|
||||
'Comment_Date' => $row->Comment_Date,
|
||||
'Comment_user_id' => $row->Comment_user_id,
|
||||
'Comment_user_points' => ( isset( $row->stats_total_points ) ? number_format( $row->stats_total_points ) : 0 ),
|
||||
'CommentID' => $row->CommentID,
|
||||
'Comment_Parent_ID' => $row->Comment_Parent_ID,
|
||||
'thread' => $thread,
|
||||
'timestamp' => wfTimestamp( TS_UNIX, $row->timestamp ),
|
||||
'current_vote' => ( isset( $row->current_vote ) ? $row->current_vote : false ),
|
||||
'total_vote' => ( isset( $row->comment_score ) ? $row->comment_score : 0 ),
|
||||
);
|
||||
|
||||
$comments[] = new Comment( $this, $this->getContext(), $data );
|
||||
}
|
||||
|
||||
$commentThreads = array();
|
||||
|
||||
foreach ( $comments as $comment ) {
|
||||
if ( $comment->parentID == 0 ) {
|
||||
$commentThreads[$comment->id] = array( $comment );
|
||||
} else {
|
||||
$commentThreads[$comment->parentID][] = $comment;
|
||||
}
|
||||
}
|
||||
|
||||
return $commentThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int The page we are currently paged to
|
||||
* not used for any API calls
|
||||
*/
|
||||
function getCurrentPagerPage() {
|
||||
if ( $this->currentPagerPage == 0 ) {
|
||||
$this->currentPagerPage = $this->getRequest()->getInt( $this->pageQuery, 1 );
|
||||
|
||||
if ( $this->currentPagerPage < 1 ) {
|
||||
$this->currentPagerPage = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->currentPagerPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display pager for the current page.
|
||||
*
|
||||
* @param int $pagerCurrent Page we are currently paged to
|
||||
* @param int $pagesCount The maximum page number
|
||||
*
|
||||
* @return string: the links for paging through pages of comments
|
||||
*/
|
||||
function displayPager( $pagerCurrent, $pagesCount ) {
|
||||
// Middle is used to "center" pages around the current page.
|
||||
$pager_middle = ceil( $this->pagerLimit / 2 );
|
||||
// first is the first page listed by this pager piece (re quantity)
|
||||
$pagerFirst = $pagerCurrent - $pager_middle + 1;
|
||||
// last is the last page listed by this pager piece (re quantity)
|
||||
$pagerLast = $pagerCurrent + $this->pagerLimit - $pager_middle;
|
||||
|
||||
// Prepare for generation loop.
|
||||
$i = $pagerFirst;
|
||||
if ( $pagerLast > $pagesCount ) {
|
||||
// Adjust "center" if at end of query.
|
||||
$i = $i + ( $pagesCount - $pagerLast );
|
||||
$pagerLast = $pagesCount;
|
||||
}
|
||||
if ( $i <= 0 ) {
|
||||
// Adjust "center" if at start of query.
|
||||
$pagerLast = $pagerLast + ( 1 - $i );
|
||||
$i = 1;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
if ( $pagesCount > 1 ) {
|
||||
$output .= '<ul class="c-pager">';
|
||||
$pagerEllipsis = '<li class="c-pager-item c-pager-ellipsis"><span>...</span></li>';
|
||||
|
||||
// Whether to display the "Previous page" link
|
||||
if ( $pagerCurrent > 1 ) {
|
||||
$output .= '<li class="c-pager-item c-pager-previous">' .
|
||||
Html::rawElement(
|
||||
'a',
|
||||
array(
|
||||
'rel' => 'nofollow',
|
||||
'class' => 'c-pager-link',
|
||||
'href' => '#cfirst',
|
||||
'data-' . $this->pageQuery => ( $pagerCurrent - 1 ),
|
||||
),
|
||||
'<'
|
||||
) .
|
||||
'</li>';
|
||||
}
|
||||
|
||||
// Whether to display the "First page" link
|
||||
if ( $i > 1 ) {
|
||||
$output .= '<li class="c-pager-item c-pager-first">' .
|
||||
Html::rawElement(
|
||||
'a',
|
||||
array(
|
||||
'rel' => 'nofollow',
|
||||
'class' => 'c-pager-link',
|
||||
'href' => '#cfirst',
|
||||
'data-' . $this->pageQuery => 1,
|
||||
),
|
||||
1
|
||||
) .
|
||||
'</li>';
|
||||
}
|
||||
|
||||
// When there is more than one page, create the pager list.
|
||||
if ( $i != $pagesCount ) {
|
||||
if ( $i > 2 ) {
|
||||
$output .= $pagerEllipsis;
|
||||
}
|
||||
|
||||
// Now generate the actual pager piece.
|
||||
for ( ; $i <= $pagerLast && $i <= $pagesCount; $i++ ) {
|
||||
if ( $i == $pagerCurrent ) {
|
||||
$output .= '<li class="c-pager-item c-pager-current"><span>' .
|
||||
$i . '</span></li>';
|
||||
} else {
|
||||
$output .= '<li class="c-pager-item">' .
|
||||
Html::rawElement(
|
||||
'a',
|
||||
array(
|
||||
'rel' => 'nofollow',
|
||||
'class' => 'c-pager-link',
|
||||
'href' => '#cfirst',
|
||||
'data-' . $this->pageQuery => $i,
|
||||
),
|
||||
$i
|
||||
) .
|
||||
'</li>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $i < $pagesCount ) {
|
||||
$output .= $pagerEllipsis;
|
||||
}
|
||||
}
|
||||
|
||||
// Whether to display the "Last page" link
|
||||
if ( $pagesCount > ( $i - 1 ) ) {
|
||||
$output .= '<li class="c-pager-item c-pager-last">' .
|
||||
Html::rawElement(
|
||||
'a',
|
||||
array(
|
||||
'rel' => 'nofollow',
|
||||
'class' => 'c-pager-link',
|
||||
'href' => '#cfirst',
|
||||
'data-' . $this->pageQuery => $pagesCount,
|
||||
),
|
||||
$pagesCount
|
||||
) .
|
||||
'</li>';
|
||||
}
|
||||
|
||||
// Whether to display the "Next page" link
|
||||
if ( $pagerCurrent < $pagesCount ) {
|
||||
$output .= '<li class="c-pager-item c-pager-next">' .
|
||||
Html::rawElement(
|
||||
'a',
|
||||
array(
|
||||
'rel' => 'nofollow',
|
||||
'class' => 'c-pager-link',
|
||||
'href' => '#cfirst',
|
||||
'data-' . $this->pageQuery => ( $pagerCurrent + 1 ),
|
||||
),
|
||||
'>'
|
||||
) .
|
||||
'</li>';
|
||||
}
|
||||
|
||||
$output .= '</ul>';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this list of anon commenters in the given list of comments,
|
||||
* and return a mapped array of IP adressess to the the number anon poster
|
||||
* (so anon posters can be called Anon#1, Anon#2, etc
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getAnonList() {
|
||||
$counter = 1;
|
||||
$bucket = array();
|
||||
|
||||
$commentThreads = $this->comments;
|
||||
|
||||
$comments = array(); // convert 2nd threads array to a simple list of comments
|
||||
foreach ( $commentThreads as $thread ) {
|
||||
$comments = array_merge( $comments, $thread );
|
||||
}
|
||||
usort( $comments, array( 'CommentFunctions', 'sortTime' ) );
|
||||
|
||||
foreach ( $comments as $comment ) {
|
||||
if (
|
||||
!array_key_exists( $comment->username, $bucket ) &&
|
||||
$comment->userID == 0
|
||||
) {
|
||||
$bucket[$comment->username] = $counter;
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return $bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort an array of comment threads
|
||||
* @param $threads
|
||||
* @return mixed
|
||||
*/
|
||||
function sort( $threads ) {
|
||||
global $wgCommentsSortDescending;
|
||||
|
||||
if ( $this->orderBy ) {
|
||||
usort( $threads, array( 'CommentFunctions', 'sortScore' ) );
|
||||
} elseif ( $wgCommentsSortDescending ) {
|
||||
usort( $threads, array( 'CommentFunctions', 'sortDesc' ) );
|
||||
} else {
|
||||
usort( $threads, array( 'CommentFunctions', 'sortAsc' ) );
|
||||
}
|
||||
|
||||
return $threads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of comment threads into an array of pages (arrays) of comment threads
|
||||
* @param $comments
|
||||
* @return array
|
||||
*/
|
||||
function page( $comments ) {
|
||||
return array_chunk( $comments, $this->limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all the comments for the current page.
|
||||
* CSS and JS is loaded in CommentsHooks.php
|
||||
*/
|
||||
function display() {
|
||||
$output = '';
|
||||
|
||||
$commentThreads = $this->getComments();
|
||||
$commentThreads = $this->sort( $commentThreads );
|
||||
|
||||
$this->comments = $commentThreads;
|
||||
|
||||
$commentPages = $this->page( $commentThreads );
|
||||
$currentPageNum = $this->getCurrentPagerPage();
|
||||
$numPages = count( $commentPages );
|
||||
// Suppress random E_NOTICE about "Undefined offset: 0", which seems to
|
||||
// be breaking ProblemReports (at least on my local devbox, not sure
|
||||
// about prod). --Jack Phoenix, 13 July 2015
|
||||
wfSuppressWarnings();
|
||||
$currentPage = $commentPages[$currentPageNum - 1];
|
||||
wfRestoreWarnings();
|
||||
|
||||
// Load complete blocked list for logged in user so they don't see their comments
|
||||
$blockList = array();
|
||||
if ( $this->getUser()->getID() != 0 ) {
|
||||
$blockList = CommentFunctions::getBlockList( $this->getUser()->getId() );
|
||||
}
|
||||
|
||||
if ( $currentPage ) {
|
||||
$pager = $this->displayPager( $currentPageNum, $numPages );
|
||||
$output .= $pager;
|
||||
$output .= '<a id="cfirst" name="cfirst" rel="nofollow"></a>';
|
||||
|
||||
$anonList = $this->getAnonList();
|
||||
|
||||
foreach ( $currentPage as $thread ) {
|
||||
foreach ( $thread as $comment ) {
|
||||
$output .= $comment->display( $blockList, $anonList );
|
||||
}
|
||||
}
|
||||
$output .= $pager;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the "Sort by X" form and a link to auto-refresh comments
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
function displayOrderForm() {
|
||||
$output = '<div class="c-order">
|
||||
<div class="c-order-select">
|
||||
<form name="ChangeOrder" action="">
|
||||
<select name="TheOrder">
|
||||
<option value="0">' .
|
||||
wfMessage( 'comments-sort-by-date' )->plain() .
|
||||
'</option>
|
||||
<option value="1">' .
|
||||
wfMessage( 'comments-sort-by-score' )->plain() .
|
||||
'</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div id="spy" class="c-spy">
|
||||
<a href="javascript:void(0)">' .
|
||||
wfMessage( 'comments-auto-refresher-enable' )->plain() .
|
||||
'</a>
|
||||
</div>
|
||||
<div class="visualClear"></div>
|
||||
</div>
|
||||
<br />' . "\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the form for adding new comments
|
||||
*
|
||||
* @return string HTML output
|
||||
*/
|
||||
function displayForm() {
|
||||
$output = '<form action="" method="post" name="commentForm">' . "\n";
|
||||
|
||||
if ( $this->allow ) {
|
||||
$pos = strpos(
|
||||
strtoupper( addslashes( $this->allow ) ),
|
||||
strtoupper( addslashes( $this->getUser()->getName() ) )
|
||||
);
|
||||
}
|
||||
|
||||
// 'comment' user right is required to add new comments
|
||||
if ( !$this->getUser()->isAllowed( 'comment' ) ) {
|
||||
$output .= wfMessage( 'comments-not-allowed' )->parse();
|
||||
} else {
|
||||
// Blocked users can't add new comments under any conditions...
|
||||
// and maybe there's a list of users who should be allowed to post
|
||||
// comments
|
||||
if ( $this->getUser()->isBlocked() == false && ( $this->allow == '' || $pos !== false ) ) {
|
||||
$output .= '<div class="c-form-title">' . wfMessage( 'comments-submit' )->plain() . '</div>' . "\n";
|
||||
$output .= '<div id="replyto" class="c-form-reply-to"></div>' . "\n";
|
||||
// Show a message to anons, prompting them to register or log in
|
||||
if ( !$this->getUser()->isLoggedIn() ) {
|
||||
$login_title = SpecialPage::getTitleFor( 'Userlogin' );
|
||||
$register_title = SpecialPage::getTitleFor( 'Userlogin', 'signup' );
|
||||
$output .= '<div class="c-form-message">' . wfMessage(
|
||||
'comments-anon-message',
|
||||
htmlspecialchars( $register_title->getFullURL() ),
|
||||
htmlspecialchars( $login_title->getFullURL() )
|
||||
)->text() . '</div>' . "\n";
|
||||
}
|
||||
|
||||
$output .= '<textarea name="commentText" id="comment" rows="5" cols="64"></textarea>' . "\n";
|
||||
$output .= '<div class="c-form-button"><input type="button" value="' .
|
||||
wfMessage( 'comments-post' )->plain() . '" class="site-button" /></div>' . "\n";
|
||||
}
|
||||
$output .= '<input type="hidden" name="action" value="purge" />' . "\n";
|
||||
$output .= '<input type="hidden" name="pageId" value="' . $this->id . '" />' . "\n";
|
||||
$output .= '<input type="hidden" name="commentid" />' . "\n";
|
||||
$output .= '<input type="hidden" name="lastCommentId" value="' . $this->getLatestCommentID() . '" />' . "\n";
|
||||
$output .= '<input type="hidden" name="commentParentId" />' . "\n";
|
||||
$output .= '<input type="hidden" name="' . $this->pageQuery . '" value="' . $this->getCurrentPagerPage() . '" />' . "\n";
|
||||
$output .= Html::hidden( 'token', $this->getUser()->getEditToken() );
|
||||
}
|
||||
$output .= '</form>' . "\n";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge caches (parser cache and Squid cache)
|
||||
*/
|
||||
function clearCommentListCache() {
|
||||
wfDebug( "Clearing comments for page {$this->id} from cache\n" );
|
||||
|
||||
if ( is_object( $this->title ) ) {
|
||||
$this->title->invalidateCache();
|
||||
$this->title->purgeSquid();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
135
includes/NumberOfComments.class.php
Normal file
135
includes/NumberOfComments.class.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
class NumberOfComments {
|
||||
/**
|
||||
* Registers NUMBEROFCOMMENTS and NUMPBEROFCOMMENTSPAGE as a valid magic word identifier.
|
||||
*
|
||||
* @param array $variableIds Array of valid magic word identifiers
|
||||
* @return bool
|
||||
*/
|
||||
public static function registerNumberOfCommentsMagicWord( &$variableIds ) {
|
||||
$variableIds[] = 'NUMBEROFCOMMENTS';
|
||||
$variableIds[] = 'NUMBEROFCOMMENTSPAGE';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to setup parser function
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @return bool
|
||||
*/
|
||||
static function setupNumberOfCommentsPageParser( &$parser ) {
|
||||
$parser->setFunctionHook( 'NUMBEROFCOMMENTSPAGE', 'NumberOfComments::getNumberOfCommentsPageParser', Parser::SFH_NO_HASH );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main backend logic for the {{NUMBEROFCOMMENTS}} and {{NUMBEROFCOMMENTSPAGE}}
|
||||
* magic word.
|
||||
* If the {{NUMBEROFCOMMENTS}} magic word is found, first checks memcached to
|
||||
* see if we can get the value from cache, but if that fails for some reason,
|
||||
* then a COUNT(*) SQL query is done to fetch the amount from the database.
|
||||
* If the {{NUMBEROFCOMMENTSPAGE}} magic word is found, uses
|
||||
* NumberOfComments::getNumberOfCommentsPage to get the number of comments
|
||||
* for this article.
|
||||
*
|
||||
* @param $parser Parser
|
||||
* @param $cache
|
||||
* @param string $magicWordId Magic word identifier
|
||||
* @param int $ret What to return to the user (in our case, the number of comments)
|
||||
* @return bool
|
||||
*/
|
||||
public static function getNumberOfCommentsMagic( &$parser, &$cache, &$magicWordId, &$ret ) {
|
||||
global $wgMemc;
|
||||
|
||||
if ( $magicWordId == 'NUMBEROFCOMMENTS' ) {
|
||||
$key = wfMemcKey( 'comments', 'magic-word' );
|
||||
$data = $wgMemc->get( $key );
|
||||
if ( $data != '' ) {
|
||||
// We have it in cache? Oh goody, let's just use the cached value!
|
||||
wfDebugLog(
|
||||
'Comments',
|
||||
'Got the amount of comments from memcached'
|
||||
);
|
||||
// return value
|
||||
$ret = $data;
|
||||
} else {
|
||||
// Not cached → have to fetch it from the database
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$commentCount = (int)$dbr->selectField(
|
||||
'Comments',
|
||||
'COUNT(*) AS count',
|
||||
array(),
|
||||
__METHOD__
|
||||
);
|
||||
wfDebugLog( 'Comments', 'Got the amount of comments from DB' );
|
||||
// Store the count in cache...
|
||||
// (86400 = seconds in a day)
|
||||
$wgMemc->set( $key, $commentCount, 86400 );
|
||||
// ...and return the value to the user
|
||||
$ret = $commentCount;
|
||||
}
|
||||
} elseif ( $magicWordId == 'NUMBEROFCOMMENTSPAGE' ) {
|
||||
$id = $parser->getTitle()->getArticleID();
|
||||
$ret = NumberOfComments::getNumberOfCommentsPage( $id );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for parser function {{NUMBEROFCOMMENTSPAGE:<page>}}
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param string $pagename Page name
|
||||
* @return int Amount of comments on the given page
|
||||
*/
|
||||
static function getNumberOfCommentsPageParser( $parser, $pagename ) {
|
||||
$page = Title::newFromText( $pagename );
|
||||
|
||||
if ( $page instanceof Title ) {
|
||||
$id = $page->getArticleID();
|
||||
} else {
|
||||
$id = $parser->getTitle()->getArticleID();
|
||||
}
|
||||
|
||||
return NumberOfComments::getNumberOfCommentsPage( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual number of comments
|
||||
*
|
||||
* @param int $pageId ID of page to get number of comments for
|
||||
* @return int
|
||||
*/
|
||||
static function getNumberOfCommentsPage( $pageId ) {
|
||||
global $wgMemc;
|
||||
|
||||
$key = wfMemcKey( 'comments', 'numberofcommentspage', $pageId );
|
||||
$cache = $wgMemc->get( $key );
|
||||
|
||||
if ( $cache ) {
|
||||
$val = intval( $cache );
|
||||
} else {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
$res = $dbr->selectField(
|
||||
'Comments',
|
||||
'COUNT(*)',
|
||||
array( 'Comment_Page_ID' => $pageId ),
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
if ( !$res ) {
|
||||
$val = 0;
|
||||
} else {
|
||||
$val = intval( $res );
|
||||
}
|
||||
$wgMemc->set( $key, $val, 60 * 60 ); // cache for an hour
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
}
|
||||
52
includes/api/CommentBlock.api.php
Normal file
52
includes/api/CommentBlock.api.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
class CommentBlockAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
// Do nothing when the database is in read-only mode
|
||||
if ( wfReadOnly() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load user_name and user_id for person we want to block from the comment it originated from
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$s = $dbr->selectRow(
|
||||
'Comments',
|
||||
array( 'comment_username', 'comment_user_id' ),
|
||||
array( 'CommentID' => $this->getMain()->getVal( 'commentID' ) ),
|
||||
__METHOD__
|
||||
);
|
||||
if ( $s !== false ) {
|
||||
$userID = $s->comment_user_id;
|
||||
$username = $s->comment_username;
|
||||
}
|
||||
|
||||
CommentFunctions::blockUser( $this->getUser(), $userID, $username );
|
||||
|
||||
if ( class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $userID, $username );
|
||||
$stats->incStatField( 'comment_ignored' );
|
||||
}
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'ok', 'ok' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function needsToken() {
|
||||
return 'csrf';
|
||||
}
|
||||
|
||||
public function isWriteMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'commentID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
41
includes/api/CommentDelete.api.php
Normal file
41
includes/api/CommentDelete.api.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
class CommentDeleteAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
$user = $this->getUser();
|
||||
// Blocked users cannot delete comments, and neither can unprivileged ones.
|
||||
// Also check for database read-only status
|
||||
if (
|
||||
$user->isBlocked() ||
|
||||
!$user->isAllowed( 'commentadmin' ) ||
|
||||
wfReadOnly()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$comment = Comment::newFromID( $this->getMain()->getVal( 'commentID' ) );
|
||||
$comment->delete();
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'ok', 'ok' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function needsToken() {
|
||||
return 'csrf';
|
||||
}
|
||||
|
||||
public function isWriteMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'commentID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
22
includes/api/CommentLatestID.api.php
Normal file
22
includes/api/CommentLatestID.api.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
class CommentLatestIdAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
$pageID = $this->getMain()->getVal( 'pageID' );
|
||||
|
||||
$commentsPage = new CommentsPage( $pageID, RequestContext::getMain() );
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'id', $commentsPage->getLatestCommentID() );
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'pageID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'int'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
44
includes/api/CommentList.api.php
Normal file
44
includes/api/CommentList.api.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
class CommentListAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
$commentsPage = new CommentsPage( $this->getMain()->getVal( 'pageID' ), RequestContext::getMain() );
|
||||
$commentsPage->orderBy = $this->getMain()->getVal( 'order' );
|
||||
$commentsPage->currentPagerPage = $this->getMain()->getVal( 'pagerPage' );
|
||||
|
||||
$output = '';
|
||||
if ( $this->getMain()->getVal( 'showForm' ) ) {
|
||||
$output .= $commentsPage->displayOrderForm();
|
||||
}
|
||||
$output .= $commentsPage->display();
|
||||
if ( $this->getMain()->getVal( 'showForm' ) ) {
|
||||
$output .= $commentsPage->displayForm();
|
||||
}
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'html', $output );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'pageID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
'order' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'boolean'
|
||||
),
|
||||
'pagerPage' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
'showForm' => array(
|
||||
ApiBase::PARAM_REQUIRED => false,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
73
includes/api/CommentSubmit.api.php
Normal file
73
includes/api/CommentSubmit.api.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
class CommentSubmitAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
$user = $this->getUser();
|
||||
// Blocked users cannot submit new comments, and neither can those users
|
||||
// without the necessary privileges. Also prevent obvious cross-site request
|
||||
// forgeries (CSRF)
|
||||
if (
|
||||
$user->isBlocked() ||
|
||||
!$user->isAllowed( 'comment' ) ||
|
||||
wfReadOnly()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$commentText = $this->getMain()->getVal( 'commentText' );
|
||||
|
||||
if ( $commentText != '' ) {
|
||||
// To protect against spam, it's necessary to check the supplied text
|
||||
// against spam filters (but comment admins are allowed to bypass the
|
||||
// spam filters)
|
||||
if ( !$user->isAllowed( 'commentadmin' ) && CommentFunctions::isSpam( $commentText ) ) {
|
||||
$this->dieUsage( wfMessage( 'comments-is-spam' )->plain(), 'comments-is-spam' );
|
||||
}
|
||||
|
||||
// If the comment contains links but the user isn't allowed to post
|
||||
// links, reject the submission
|
||||
if ( !$user->isAllowed( 'commentlinks' ) && CommentFunctions::haveLinks( $commentText ) ) {
|
||||
$this->dieUsage( wfMessage( 'comments-links-are-forbidden' )->plain(), 'comments-links-are-forbidden' );
|
||||
}
|
||||
|
||||
$page = new CommentsPage( $this->getMain()->getVal( 'pageID' ), $this->getContext() );
|
||||
|
||||
Comment::add( $commentText, $page, $user, $this->getMain()->getVal( 'parentID' ) );
|
||||
|
||||
if ( class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $user->getID(), $user->getName() );
|
||||
$stats->incStatField( 'comment' );
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'ok', 'ok' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function needsToken() {
|
||||
return 'csrf';
|
||||
}
|
||||
|
||||
public function isWriteMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'pageID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
'parentID' => array(
|
||||
ApiBase::PARAM_REQUIRED => false,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
'commentText' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'string'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
72
includes/api/CommentVote.api.php
Normal file
72
includes/api/CommentVote.api.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
class CommentVoteAPI extends ApiBase {
|
||||
|
||||
public function execute() {
|
||||
// Blocked users cannot vote, obviously, and neither can those users without the necessary privileges
|
||||
if (
|
||||
$this->getUser()->isBlocked() ||
|
||||
!$this->getUser()->isAllowed( 'comment' ) ||
|
||||
wfReadOnly()
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$comment = Comment::newFromID( $this->getMain()->getVal( 'commentID' ) );
|
||||
$voteValue = $this->getMain()->getVal( 'voteValue' );
|
||||
|
||||
if ( $comment && is_numeric( $voteValue ) ) {
|
||||
$comment->vote( $voteValue );
|
||||
|
||||
$html = $comment->getScoreHTML();
|
||||
$html = htmlspecialchars( $html );
|
||||
|
||||
if ( class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $this->getUser()->getID(), $this->getUser()->getName() );
|
||||
|
||||
// Must update stats for user doing the voting
|
||||
if ( $voteValue == 1 ) {
|
||||
$stats->incStatField( 'comment_give_plus' );
|
||||
}
|
||||
if ( $voteValue == -1 ) {
|
||||
$stats->incStatField( 'comment_give_neg' );
|
||||
}
|
||||
|
||||
// Also must update the stats for user receiving the vote
|
||||
$stats_comment_owner = new UserStatsTrack( $comment->userID, $comment->username );
|
||||
$stats_comment_owner->updateCommentScoreRec( $voteValue );
|
||||
|
||||
$stats_comment_owner->updateTotalPoints();
|
||||
if ( $voteValue === 1 ) {
|
||||
$stats_comment_owner->updateWeeklyPoints( $stats_comment_owner->point_values['comment_plus'] );
|
||||
$stats_comment_owner->updateMonthlyPoints( $stats_comment_owner->point_values['comment_plus'] );
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->getResult();
|
||||
$result->addValue( $this->getModuleName(), 'html', $html );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function needsToken() {
|
||||
return 'csrf';
|
||||
}
|
||||
|
||||
public function isWriteMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
return array(
|
||||
'commentID' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
'voteValue' => array(
|
||||
ApiBase::PARAM_REQUIRED => true,
|
||||
ApiBase::PARAM_TYPE => 'integer'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
146
includes/specials/SpecialCommentIgnoreList.php
Normal file
146
includes/specials/SpecialCommentIgnoreList.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* A special page for displaying the list of users whose comments you're
|
||||
* ignoring.
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
class CommentIgnoreList extends SpecialPage {
|
||||
|
||||
/**
|
||||
* Constructor -- set up the new special page
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct( 'CommentIgnoreList' );
|
||||
}
|
||||
|
||||
public function doesWrites() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group this special page under the correct header in Special:SpecialPages.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getGroupName() {
|
||||
return 'users';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the special page
|
||||
*
|
||||
* @param mixed|null $par Parameter passed to the page or null
|
||||
*/
|
||||
public function execute( $par ) {
|
||||
$out = $this->getOutput();
|
||||
$request = $this->getRequest();
|
||||
$user = $this->getUser();
|
||||
|
||||
$user_name = $request->getVal( 'user' );
|
||||
|
||||
/**
|
||||
* Redirect anonymous users to Login Page
|
||||
* It will automatically return them to the CommentIgnoreList page
|
||||
*/
|
||||
if ( $user->getID() == 0 && $user_name == '' ) {
|
||||
$loginPage = SpecialPage::getTitleFor( 'Userlogin' );
|
||||
$out->redirect( $loginPage->getLocalURL( 'returnto=Special:CommentIgnoreList' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$out->setPageTitle( $this->msg( 'comments-ignore-title' )->text() );
|
||||
|
||||
$output = ''; // Prevent E_NOTICE
|
||||
|
||||
if ( $user_name == '' ) {
|
||||
$output .= $this->displayCommentBlockList();
|
||||
} else {
|
||||
if ( $request->wasPosted() ) {
|
||||
// Check for cross-site request forgeries (CSRF)
|
||||
if ( !$user->matchEditToken( $request->getVal( 'token' ) ) ) {
|
||||
$out->addWikiMsg( 'sessionfailure' );
|
||||
return;
|
||||
}
|
||||
$user_name = htmlspecialchars_decode( $user_name );
|
||||
$user_id = User::idFromName( $user_name );
|
||||
// Anons can be comment-blocked, but idFromName returns nothing
|
||||
// for an anon, so...
|
||||
if ( !$user_id ) {
|
||||
$user_id = 0;
|
||||
}
|
||||
|
||||
CommentFunctions::deleteBlock( $user->getID(), $user_id );
|
||||
if ( $user_id && class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $user_id, $user_name );
|
||||
$stats->decStatField( 'comment_ignored' );
|
||||
}
|
||||
$output .= $this->displayCommentBlockList();
|
||||
} else {
|
||||
$output .= $this->confirmCommentBlockDelete();
|
||||
}
|
||||
}
|
||||
|
||||
$out->addHTML( $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the list of users whose comments you're ignoring.
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
function displayCommentBlockList() {
|
||||
$lang = $this->getLanguage();
|
||||
$title = $this->getPageTitle();
|
||||
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$res = $dbr->select(
|
||||
'Comments_block',
|
||||
array( 'cb_user_name_blocked', 'cb_date' ),
|
||||
array( 'cb_user_id' => $this->getUser()->getID() ),
|
||||
__METHOD__,
|
||||
array( 'ORDER BY' => 'cb_user_name' )
|
||||
);
|
||||
|
||||
if ( $dbr->numRows( $res ) > 0 ) {
|
||||
$out = '<ul>';
|
||||
foreach ( $res as $row ) {
|
||||
$user_title = Title::makeTitle( NS_USER, $row->cb_user_name_blocked );
|
||||
$out .= '<li>' . $this->msg(
|
||||
'comments-ignore-item',
|
||||
htmlspecialchars( $user_title->getFullURL() ),
|
||||
$user_title->getText(),
|
||||
$lang->timeanddate( $row->cb_date ),
|
||||
htmlspecialchars( $title->getFullURL( 'user=' . $user_title->getText() ) )
|
||||
)->text() . '</li>';
|
||||
}
|
||||
$out .= '</ul>';
|
||||
} else {
|
||||
$out = '<div class="comment_blocked_user">' .
|
||||
$this->msg( 'comments-ignore-no-users' )->text() . '</div>';
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for a confirmation when you're about to unblock someone's comments.
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
function confirmCommentBlockDelete() {
|
||||
$user_name = $this->getRequest()->getVal( 'user' );
|
||||
|
||||
$out = '<div class="comment_blocked_user">' .
|
||||
$this->msg( 'comments-ignore-remove-message', $user_name )->parse() .
|
||||
'</div>
|
||||
<div>
|
||||
<form action="" method="post" name="comment_block">' .
|
||||
Html::hidden( 'user', $user_name ) . "\n" .
|
||||
Html::hidden( 'token', $this->getUser()->getEditToken() ) . "\n" .
|
||||
'<input type="button" class="site-button" value="' . $this->msg( 'comments-ignore-unblock' )->text() . '" onclick="document.comment_block.submit()" />
|
||||
<input type="button" class="site-button" value="' . $this->msg( 'comments-ignore-cancel' )->text() . '" onclick="history.go(-1)" />
|
||||
</form>
|
||||
</div>';
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user