Original: https://www.mediawiki.org/wiki/Extension:Comments Das hier ist eine an https://znil.net angepasste Version.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Comment.php 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. <?php
  2. use MediaWiki\MediaWikiServices;
  3. /**
  4. * Comment class
  5. * Functions for managing comments and everything related to them, including:
  6. * -blocking comments from a given user
  7. * -counting the total amount of comments in the database
  8. * -displaying the form for adding a new comment
  9. * -getting all comments for a given page
  10. *
  11. * @file
  12. * @ingroup Extensions
  13. */
  14. class Comment extends ContextSource {
  15. /**
  16. * @var CommentsPage: page of the page the <comments /> tag is in
  17. */
  18. public $page = null;
  19. /**
  20. * @var Integer: total amount of comments by distinct commenters that the
  21. * current page has
  22. */
  23. public $commentTotal = 0;
  24. /**
  25. * @var String: text of the current comment
  26. */
  27. public $text = null;
  28. /**
  29. * Date when the comment was posted
  30. *
  31. * @var null
  32. */
  33. public $date = null;
  34. /**
  35. * @var Integer: internal ID number (Comments.CommentID DB field) of the
  36. * current comment that we're dealing with
  37. */
  38. public $id = 0;
  39. /**
  40. * @var Integer: ID of the parent comment, if this is a child comment
  41. */
  42. public $parentID = 0;
  43. /**
  44. * The current vote from this user on this comment
  45. *
  46. * @var int|boolean: false if no vote, otherwise -1, 0, or 1
  47. */
  48. public $currentVote = false;
  49. /**
  50. * @var string: comment score (SUM() of all votes) of the current comment
  51. */
  52. public $currentScore = '0';
  53. /**
  54. * Username of the user who posted the comment
  55. *
  56. * @var string
  57. */
  58. public $username = '';
  59. /**
  60. * IP of the comment poster
  61. *
  62. * @var string
  63. */
  64. public $ip = '';
  65. /**
  66. * ID of the user who posted the comment
  67. *
  68. * @var int
  69. */
  70. public $userID = 0;
  71. /**
  72. * The amount of points the user has; fetched from the user_stats table if
  73. * SocialProfile is installed, otherwise this remains 0
  74. *
  75. * @var int
  76. */
  77. public $userPoints = 0;
  78. /**
  79. * Comment ID of the thread this comment is in
  80. * this is the ID of the parent comment if there is one,
  81. * or this comment if there is not
  82. * Used for sorting
  83. *
  84. * @var null
  85. */
  86. public $thread = null;
  87. /**
  88. * Unix timestamp when the comment was posted
  89. * Used for sorting
  90. * Processed from $date
  91. *
  92. * @var null
  93. */
  94. public $timestamp = null;
  95. /**
  96. * Constructor - set the page ID
  97. *
  98. * @param CommentsPage $page ID number of the current page
  99. * @param IContextSource|null $context
  100. * @param array $data Straight from the DB about the comment
  101. */
  102. public function __construct( CommentsPage $page, $context = null, $data ) {
  103. $this->page = $page;
  104. $this->setContext( $context );
  105. $this->username = $data['Comment_Username'];
  106. $this->ip = $data['Comment_IP'];
  107. $this->text = $data['Comment_Text'];
  108. $this->date = $data['Comment_Date'];
  109. $this->userID = (int)$data['Comment_user_id'];
  110. $this->userPoints = $data['Comment_user_points'];
  111. $this->id = (int)$data['CommentID'];
  112. $this->parentID = (int)$data['Comment_Parent_ID'];
  113. $this->thread = $data['thread'];
  114. $this->timestamp = $data['timestamp'];
  115. if ( isset( $data['current_vote'] ) ) {
  116. $vote = $data['current_vote'];
  117. } else {
  118. $dbr = wfGetDB( DB_REPLICA );
  119. $row = $dbr->selectRow(
  120. 'Comments_Vote',
  121. [ 'Comment_Vote_Score' ],
  122. [
  123. 'Comment_Vote_ID' => $this->id,
  124. 'Comment_Vote_Username' => $this->getUser()->getName()
  125. ],
  126. __METHOD__
  127. );
  128. if ( $row !== false ) {
  129. $vote = $row->Comment_Vote_Score;
  130. } else {
  131. $vote = false;
  132. }
  133. }
  134. $this->currentVote = $vote;
  135. $this->currentScore = isset( $data['total_vote'] )
  136. ? $data['total_vote'] : $this->getScore();
  137. }
  138. public static function newFromID( $id ) {
  139. $context = RequestContext::getMain();
  140. $dbr = wfGetDB( DB_REPLICA );
  141. if ( !is_numeric( $id ) || $id == 0 ) {
  142. return null;
  143. }
  144. $tables = [];
  145. $params = [];
  146. $joinConds = [];
  147. // Defaults (for non-social wikis)
  148. $tables[] = 'Comments';
  149. $fields = [
  150. 'Comment_Username', 'Comment_IP', 'Comment_Text',
  151. 'Comment_Date', 'Comment_Date AS timestamp',
  152. 'Comment_user_id', 'CommentID', 'Comment_Parent_ID',
  153. 'CommentID', 'Comment_Page_ID'
  154. ];
  155. // If SocialProfile is installed, query the user_stats table too.
  156. if (
  157. class_exists( 'UserProfile' ) &&
  158. $dbr->tableExists( 'user_stats' )
  159. ) {
  160. $tables[] = 'user_stats';
  161. $fields[] = 'stats_total_points';
  162. $joinConds = [
  163. 'Comments' => [
  164. 'LEFT JOIN', 'Comment_user_id = stats_user_id'
  165. ]
  166. ];
  167. }
  168. // Perform the query
  169. $res = $dbr->select(
  170. $tables,
  171. $fields,
  172. [ 'CommentID' => $id ],
  173. __METHOD__,
  174. $params,
  175. $joinConds
  176. );
  177. $row = $res->fetchObject();
  178. if ( $row->Comment_Parent_ID == 0 ) {
  179. $thread = $row->CommentID;
  180. } else {
  181. $thread = $row->Comment_Parent_ID;
  182. }
  183. $data = [
  184. 'Comment_Username' => $row->Comment_Username,
  185. 'Comment_IP' => $row->Comment_IP,
  186. 'Comment_Text' => $row->Comment_Text,
  187. 'Comment_Date' => $row->Comment_Date,
  188. 'Comment_user_id' => $row->Comment_user_id,
  189. 'Comment_user_points' => ( isset( $row->stats_total_points ) ? number_format( $row->stats_total_points ) : 0 ),
  190. 'CommentID' => $row->CommentID,
  191. 'Comment_Parent_ID' => $row->Comment_Parent_ID,
  192. 'thread' => $thread,
  193. 'timestamp' => wfTimestamp( TS_UNIX, $row->timestamp )
  194. ];
  195. $page = new CommentsPage( $row->Comment_Page_ID, $context );
  196. return new Comment( $page, $context, $data );
  197. }
  198. /**
  199. * Is the given User the owner (author) of this comment?
  200. *
  201. * @param User $user
  202. * @return bool
  203. */
  204. public function isOwner( User $user ) {
  205. return ( $this->username === $user->getName() && $this->userID === $user->getId() );
  206. }
  207. /**
  208. * Parse and return the text for this comment
  209. *
  210. * @return mixed|string
  211. * @throws MWException
  212. */
  213. function getText() {
  214. $parser = MediaWikiServices::getInstance()->getParser();
  215. $commentText = trim( str_replace( '&quot;', "'", $this->text ) );
  216. $comment_text_parts = explode( "\n", $commentText );
  217. $comment_text_fix = '';
  218. foreach ( $comment_text_parts as $part ) {
  219. $comment_text_fix .= ( ( $comment_text_fix ) ? "\n" : '' ) . trim( $part );
  220. }
  221. if ( $this->getTitle()->getArticleID() > 0 ) {
  222. $commentText = $parser->recursiveTagParse( $comment_text_fix );
  223. } else {
  224. $commentText = $this->getOutput()->parse( $comment_text_fix );
  225. }
  226. // really bad hack because we want to parse=firstline, but don't want wrapping <p> tags
  227. if ( substr( $commentText, 0, 3 ) == '<p>' ) {
  228. $commentText = substr( $commentText, 3 );
  229. }
  230. if ( substr( $commentText, strlen( $commentText ) - 4, 4 ) == '</p>' ) {
  231. $commentText = substr( $commentText, 0, strlen( $commentText ) - 4 );
  232. }
  233. // make sure link text is not too long (will overflow)
  234. // this function changes too long links to <a href=#>http://www.abc....xyz.html</a>
  235. $commentText = preg_replace_callback(
  236. "/(<a[^>]*>)(.*?)(<\/a>)/i",
  237. [ 'CommentFunctions', 'cutCommentLinkText' ],
  238. $commentText
  239. );
  240. return $commentText;
  241. }
  242. /**
  243. * Adds the comment and all necessary info into the Comments table in the
  244. * database.
  245. *
  246. * @param string $text text of the comment
  247. * @param CommentsPage $page container page
  248. * @param User $user user commenting
  249. * @param int $parentID ID of parent comment, if this is a reply
  250. *
  251. * @return Comment the added comment
  252. */
  253. static function add( $text, CommentsPage $page, User $user, $parentID ) {
  254. $dbw = wfGetDB( DB_MASTER );
  255. $context = RequestContext::getMain();
  256. Wikimedia\suppressWarnings();
  257. $commentDate = date( 'Y-m-d H:i:s' );
  258. Wikimedia\restoreWarnings();
  259. // ## START ## 25.05.2019 von Bernhard Linz ###################################################################################################
  260. $kok_username = preg_match('/(?<=#START#).*?(?=#ENDE#)/s', $text, $result);
  261. $kok_username = $result[0];
  262. $text = str_replace('#START#' . $result[0] . '#ENDE#', '', $text);
  263. if ( $kok_username == "" ) {
  264. $kok_username = $user->getName();
  265. }
  266. if ( $kok_username == "none" ) {
  267. $kok_username = $user->getName();
  268. }
  269. // ## ENDE ## 25.05.2019 von Bernhard Linz ###################################################################################################
  270. $dbw->insert(
  271. 'Comments',
  272. [
  273. 'Comment_Page_ID' => $page->id,
  274. // ## START ## 25.05.2019 von Bernhard Linz ###################################################################################################
  275. //'Comment_Username' => $user->getName(),
  276. 'Comment_Username' => $kok_username,
  277. // ## ENDE ## 25.05.2019 von Bernhard Linz ###################################################################################################
  278. 'Comment_user_id' => $user->getId(),
  279. 'Comment_Text' => $text,
  280. 'Comment_Date' => $commentDate,
  281. 'Comment_Parent_ID' => $parentID,
  282. 'Comment_IP' => $_SERVER['REMOTE_ADDR']
  283. ],
  284. __METHOD__
  285. );
  286. $commentId = $dbw->insertId();
  287. $id = $commentId;
  288. $page->clearCommentListCache();
  289. // Add a log entry.
  290. self::log( 'add', $user, $page->id, $commentId, $text );
  291. $dbr = wfGetDB( DB_REPLICA );
  292. if (
  293. class_exists( 'UserProfile' ) &&
  294. $dbr->tableExists( 'user_stats' )
  295. ) {
  296. $res = $dbr->select( // need this data for seeding a Comment object
  297. 'user_stats',
  298. 'stats_total_points',
  299. [ 'stats_user_id' => $user->getId() ],
  300. __METHOD__
  301. );
  302. $row = $res->fetchObject();
  303. $userPoints = number_format( $row->stats_total_points );
  304. } else {
  305. $userPoints = 0;
  306. }
  307. if ( $parentID == 0 ) {
  308. $thread = $id;
  309. } else {
  310. $thread = $parentID;
  311. }
  312. $data = [
  313. 'Comment_Username' => $user->getName(),
  314. 'Comment_IP' => $context->getRequest()->getIP(),
  315. 'Comment_Text' => $text,
  316. 'Comment_Date' => $commentDate,
  317. 'Comment_user_id' => $user->getId(),
  318. 'Comment_user_points' => $userPoints,
  319. 'CommentID' => $id,
  320. 'Comment_Parent_ID' => $parentID,
  321. 'thread' => $thread,
  322. 'timestamp' => strtotime( $commentDate )
  323. ];
  324. $page = new CommentsPage( $page->id, $context );
  325. $comment = new Comment( $page, $context, $data );
  326. Hooks::run( 'Comment::add', [ $comment, $commentId, $comment->page->id ] );
  327. // ## START ## 25.05.2019 von Bernhard Linz ###################################################################################################
  328. // Kommentar auch noch einmal per Email versenden (zur Kontrolle)
  329. $znilpageTitle = Title::newFromID( $comment->page->id );
  330. $comment_mailto = "root@linz.email";
  331. $comment_mailsubject = "Neuer Kommentar von: " . $kok_username . " - IP: " . $_SERVER['REMOTE_ADDR'] . " - DNS: " . gethostbyaddr($_SERVER['REMOTE_ADDR']) ;
  332. $comment_mailfrom = "MIME-Version: 1.0\r\n";
  333. $comment_mailfrom .= "Content-type: text/html; charset=utf-8\r\n";
  334. $comment_mailfrom .= "From: znil.net Kommentare <root@linz.email>\r\n";
  335. // $comment_url = $znilpageTitle;
  336. $comment_url = "<a href=\"https://znil.net/index.php?title={$znilpageTitle}#comment-{$commentId}\">https://znil.net/index.php?title={$znilpageTitle}#comment-{$commentId}</a>";
  337. // $comment_url = "<a href=\"" . $title->getFullURL() . "\">" . $title->getFullURL() . "</a>";
  338. $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;
  339. $comment_mailtext = nl2br($comment_mailtext);
  340. mail($comment_mailto, $comment_mailsubject, $comment_mailtext, $comment_mailfrom);
  341. // ## ENDE ## 25.05.2019 von Bernhard Linz ###################################################################################################
  342. return $comment;
  343. }
  344. /**
  345. * Gets the score for this comment from the database table Comments_Vote
  346. *
  347. * @return string
  348. */
  349. function getScore() {
  350. $dbr = wfGetDB( DB_REPLICA );
  351. $row = $dbr->selectRow(
  352. 'Comments_Vote',
  353. [ 'SUM(Comment_Vote_Score) AS CommentScore' ],
  354. [ 'Comment_Vote_ID' => $this->id ],
  355. __METHOD__
  356. );
  357. $score = '0';
  358. if ( $row !== false && $row->CommentScore ) {
  359. $score = $row->CommentScore;
  360. }
  361. return $score;
  362. }
  363. /**
  364. * Adds a vote for a comment if the user hasn't voted for said comment yet.
  365. *
  366. * @param int $value Upvote or downvote (1 or -1)
  367. */
  368. function vote( $value ) {
  369. $dbw = wfGetDB( DB_MASTER );
  370. if ( $value < -1 ) { // limit to range -1 -> 0 -> 1
  371. $value = -1;
  372. } elseif ( $value > 1 ) {
  373. $value = 1;
  374. }
  375. if ( $value == $this->currentVote ) { // user toggling off a preexisting vote
  376. $value = 0;
  377. }
  378. Wikimedia\suppressWarnings();
  379. $commentDate = date( 'Y-m-d H:i:s' );
  380. Wikimedia\restoreWarnings();
  381. if ( $this->currentVote === false ) { // no vote, insert
  382. $dbw->insert(
  383. 'Comments_Vote',
  384. [
  385. 'Comment_Vote_id' => $this->id,
  386. 'Comment_Vote_Username' => $this->getUser()->getName(),
  387. 'Comment_Vote_user_id' => $this->getUser()->getId(),
  388. 'Comment_Vote_Score' => $value,
  389. 'Comment_Vote_Date' => $commentDate,
  390. 'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR']
  391. ],
  392. __METHOD__
  393. );
  394. } else { // already a vote, update
  395. $dbw->update(
  396. 'Comments_Vote',
  397. [
  398. 'Comment_Vote_Score' => $value,
  399. 'Comment_Vote_Date' => $commentDate,
  400. 'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR']
  401. ],
  402. [
  403. 'Comment_Vote_id' => $this->id,
  404. 'Comment_Vote_Username' => $this->getUser()->getName(),
  405. 'Comment_Vote_user_id' => $this->getUser()->getId(),
  406. ],
  407. __METHOD__
  408. );
  409. }
  410. $score = $this->getScore();
  411. $this->currentVote = $value;
  412. $this->currentScore = $score;
  413. }
  414. /**
  415. * Deletes entries from Comments and Comments_Vote tables and clears caches
  416. */
  417. function delete() {
  418. $dbw = wfGetDB( DB_MASTER );
  419. $dbw->startAtomic( __METHOD__ );
  420. $dbw->delete(
  421. 'Comments',
  422. [ 'CommentID' => $this->id ],
  423. __METHOD__
  424. );
  425. $dbw->delete(
  426. 'Comments_Vote',
  427. [ 'Comment_Vote_ID' => $this->id ],
  428. __METHOD__
  429. );
  430. $dbw->endAtomic( __METHOD__ );
  431. // Log the deletion to Special:Log/comments.
  432. self::log( 'delete', $this->getUser(), $this->page->id, $this->id );
  433. // Clear memcache & Squid cache
  434. $this->page->clearCommentListCache();
  435. // Ping other extensions that may have hooked into this point (i.e. LinkFilter)
  436. Hooks::run( 'Comment::delete', [ $this, $this->id, $this->page->id ] );
  437. }
  438. /**
  439. * Log an action in the comment log.
  440. *
  441. * @param string $action Action to log, can be either 'add' or 'delete'
  442. * @param User $user User who performed the action
  443. * @param int $pageId Page ID of the page that contains the comment thread
  444. * @param int $commentId Comment ID of the affected comment
  445. * @param string|null $commentText Supplementary log comment, if any
  446. */
  447. static function log( $action, $user, $pageId, $commentId, $commentText = null ) {
  448. global $wgCommentsInRecentChanges;
  449. $logEntry = new ManualLogEntry( 'comments', $action );
  450. $logEntry->setPerformer( $user );
  451. $logEntry->setTarget( Title::newFromId( $pageId ) );
  452. if ( $commentText !== null ) {
  453. $logEntry->setComment( $commentText );
  454. }
  455. $logEntry->setParameters( [
  456. '4::commentid' => $commentId
  457. ] );
  458. $logId = $logEntry->insert();
  459. $logEntry->publish( $logId, ( $wgCommentsInRecentChanges ? 'rcandudp' : 'udp' ) );
  460. }
  461. /**
  462. * Return the HTML for the comment vote links
  463. *
  464. * @param int $voteType up (+1) vote or down (-1) vote
  465. * @return string
  466. */
  467. function getVoteLink( $voteType ) {
  468. global $wgExtensionAssetsPath;
  469. // Blocked users cannot vote, obviously
  470. if ( $this->getUser()->isBlocked() ) {
  471. return '';
  472. }
  473. if ( !$this->getUser()->isAllowed( 'comment' ) ) {
  474. return '';
  475. }
  476. $voteLink = '';
  477. if ( $this->getUser()->isLoggedIn() ) {
  478. $voteLink .= '<a id="comment-vote-link" data-comment-id="' .
  479. $this->id . '" data-vote-type="' . $voteType .
  480. '" data-voting="' . $this->page->voting . '" href="javascript:void(0);">';
  481. } else {
  482. $login = SpecialPage::getTitleFor( 'Userlogin' ); // Anonymous users need to log in before they can vote
  483. $urlParams = [];
  484. // @todo FIXME: *when* and *why* is this null?
  485. if ( $this->page->title instanceof Title ) {
  486. $returnTo = $this->page->title->getPrefixedDBkey(); // Determine a sane returnto URL parameter
  487. $urlParams = [ 'returnto' => $returnTo ];
  488. }
  489. $voteLink .=
  490. "<a href=\"" .
  491. htmlspecialchars( $login->getLocalURL( $urlParams ) ) .
  492. "\" rel=\"nofollow\">";
  493. }
  494. $imagePath = $wgExtensionAssetsPath . '/Comments/resources/images';
  495. if ( $voteType == 1 ) {
  496. if ( $this->currentVote == 1 ) {
  497. $voteLink .= "<img src=\"{$imagePath}/up-voted.png\" border=\"0\" alt=\"+\" /></a>";
  498. } else {
  499. $voteLink .= "<img src=\"{$imagePath}/up-unvoted.png\" border=\"0\" alt=\"+\" /></a>";
  500. }
  501. } else {
  502. if ( $this->currentVote == -1 ) {
  503. $voteLink .= "<img src=\"{$imagePath}/down-voted.png\" border=\"0\" alt=\"+\" /></a>";
  504. } else {
  505. $voteLink .= "<img src=\"{$imagePath}/down-unvoted.png\" border=\"0\" alt=\"+\" /></a>";
  506. }
  507. }
  508. return $voteLink;
  509. }
  510. /**
  511. * Show the HTML for this comment and ignore section
  512. *
  513. * @param array $blockList List of users the current user has blocked
  514. * @param array $anonList Map of IP addresses to names like anon#1, anon#2
  515. * @return string HTML
  516. */
  517. function display( $blockList, $anonList ) {
  518. if ( $this->parentID == 0 ) {
  519. $container_class = 'full';
  520. } else {
  521. $container_class = 'reply';
  522. }
  523. $output = '';
  524. if ( in_array( $this->username, $blockList ) ) {
  525. $output .= $this->showIgnore( false, $container_class );
  526. $output .= $this->showComment( true, $container_class, $blockList, $anonList );
  527. } else {
  528. $output .= $this->showIgnore( true, $container_class );
  529. $output .= $this->showComment( false, $container_class, $blockList, $anonList );
  530. }
  531. return $output;
  532. }
  533. /**
  534. * Show the box for if this comment has been ignored
  535. *
  536. * @param bool $hide
  537. * @param $containerClass
  538. * @return string
  539. */
  540. function showIgnore( $hide = false, $containerClass ) {
  541. $blockListTitle = SpecialPage::getTitleFor( 'CommentIgnoreList' );
  542. $style = '';
  543. if ( $hide ) {
  544. $style = " style='display:none;'";
  545. }
  546. $output = "<div id='ignore-{$this->id}' class='c-ignored {$containerClass}'{$style}>\n";
  547. $output .= wfMessage( 'comments-ignore-message' )->parse();
  548. $output .= '<div class="c-ignored-links">' . "\n";
  549. $output .= "<a href=\"javascript:void(0);\" data-comment-id=\"{$this->id}\">" .
  550. $this->msg( 'comments-show-comment-link' )->plain() . '</a> | ';
  551. $output .= '<a href="' . htmlspecialchars( $blockListTitle->getFullURL() ) . '">' .
  552. $this->msg( 'comments-manage-blocklist-link' )->plain() . '</a>';
  553. $output .= '</div>' . "\n";
  554. $output .= '</div>' . "\n";
  555. return $output;
  556. }
  557. /**
  558. * Show the comment
  559. *
  560. * @param bool $hide If true, comment is returned but hidden (display:none)
  561. * @param string $containerClass
  562. * @param array $blockList
  563. * @param array $anonList
  564. * @return string
  565. */
  566. function showComment( $hide = false, $containerClass, $blockList, $anonList ) {
  567. global $wgUserLevels, $wgExtensionAssetsPath;
  568. $style = '';
  569. if ( $hide ) {
  570. $style = " style='display:none;'";
  571. }
  572. $commentPosterLevel = '';
  573. if ( $this->userID != 0 ) {
  574. $title = Title::makeTitle( NS_USER, $this->username );
  575. $commentPoster = '<a href="' . htmlspecialchars( $title->getFullURL() ) .
  576. '" rel="nofollow">' . $this->username . '</a>';
  577. $CommentReplyTo = $this->username;
  578. if ( $wgUserLevels && class_exists( 'UserLevel' ) ) {
  579. $user_level = new UserLevel( $this->userPoints );
  580. $commentPosterLevel = "{$user_level->getLevelName()}";
  581. }
  582. $user = User::newFromId( $this->userID );
  583. $CommentReplyToGender = $user->getOption( 'gender', 'unknown' );
  584. } else {
  585. $anonMsg = $this->msg( 'comments-anon-name' )->inContentLanguage()->plain();
  586. // ## START ## 25.05.2019 von Bernhard Linz ###################################################################################################
  587. //Bei Anonymen Benutzern den Namen trotzdem aus der Datenbank benutzen
  588. //$commentPoster = $anonMsg . ' #' . $anonList[$this->username];
  589. $commentPoster = $this->username;
  590. if ( filter_var($commentPoster, FILTER_VALIDATE_IP) !== false ){
  591. // Wert ist eine IP-Adresse
  592. $commentPoster = $anonMsg . ' #' . $anonList[$this->username];
  593. }
  594. // Name Fett drucken
  595. $commentPoster = '<b>' . $commentPoster . '</b>';
  596. // ## ENDE ## 25.05.2019 von Bernhard Linz ###################################################################################################
  597. $CommentReplyTo = $anonMsg;
  598. $CommentReplyToGender = 'unknown'; // Undisclosed gender as anon user
  599. }
  600. // Comment delete button for privileged users
  601. $userObj = $this->getUser();
  602. $dlt = '';
  603. if (
  604. $userObj->isAllowed( 'commentadmin' ) ||
  605. // Allow users to delete their own comments if that feature is enabled in
  606. // site configuration
  607. // @see https://phabricator.wikimedia.org/T147796
  608. $userObj->isAllowed( 'comment-delete-own' ) && $this->isOwner( $userObj )
  609. ) {
  610. $dlt = ' | <span class="c-delete">' .
  611. '<a href="javascript:void(0);" rel="nofollow" class="comment-delete-link" data-comment-id="' .
  612. $this->id . '">' .
  613. $this->msg( 'comments-delete-link' )->plain() . '</a></span>';
  614. }
  615. // Reply Link (does not appear on child comments)
  616. $replyRow = '';
  617. if ( $userObj->isAllowed( 'comment' ) ) {
  618. if ( $this->parentID == 0 ) {
  619. if ( $replyRow ) {
  620. $replyRow .= wfMessage( 'pipe-separator' )->plain();
  621. }
  622. $replyRow .= " | <a href=\"#end\" rel=\"nofollow\" class=\"comments-reply-to\" data-comment-id=\"{$this->id}\" data-comments-safe-username=\"" .
  623. htmlspecialchars( $CommentReplyTo, ENT_QUOTES ) . "\" data-comments-user-gender=\"" .
  624. htmlspecialchars( $CommentReplyToGender ) . '">' .
  625. wfMessage( 'comments-reply' )->plain() . '</a>';
  626. }
  627. }
  628. if ( $this->parentID == 0 ) {
  629. $comment_class = 'f-message';
  630. } else {
  631. $comment_class = 'r-message';
  632. }
  633. // Display Block icon for logged in users for comments of users
  634. // that are already not in your block list
  635. $blockLink = '';
  636. if (
  637. $userObj->getId() != 0 && $userObj->getId() != $this->userID &&
  638. !( in_array( $this->userID, $blockList ) )
  639. ) {
  640. $blockLink = '<a href="javascript:void(0);" rel="nofollow" class="comments-block-user" data-comments-safe-username="' .
  641. htmlspecialchars( $this->username, ENT_QUOTES ) .
  642. '" data-comments-comment-id="' . $this->id . '" data-comments-user-id="' .
  643. $this->userID . "\">
  644. <img src=\"{$wgExtensionAssetsPath}/Comments/resources/images/block.svg\" border=\"0\" alt=\"\"/>
  645. </a>";
  646. }
  647. // Default avatar image, if SocialProfile extension isn't enabled
  648. global $wgCommentsDefaultAvatar;
  649. // ## START ## 25.05.2019 von Bernhard Linz ###################################################################################################
  650. if ( $this->username == "BLinz" ) {
  651. $avatarImg = '<img src="' . $wgExtensionAssetsPath . '/Comments/' . 'resources/images/bernhard2.gif' . '" alt="" border="0" />';
  652. } else {
  653. $avatarImg = '<img src="' . $wgCommentsDefaultAvatar . '" alt="" border="0" />';
  654. }
  655. // ## ENDE ## 25.05.2019 von Bernhard Linz ###################################################################################################
  656. // If SocialProfile *is* enabled, then use its wAvatar class to get the avatars for each commenter
  657. if ( class_exists( 'wAvatar' ) ) {
  658. $avatar = new wAvatar( $this->userID, 'ml' );
  659. $avatarImg = $avatar->getAvatarURL() . "\n";
  660. }
  661. $output = "<div id='comment-{$this->id}' class='c-item {$containerClass}'{$style}>" . "\n";
  662. $output .= "<div class=\"c-avatar\">{$avatarImg}</div>" . "\n";
  663. $output .= '<div class="c-container">' . "\n";
  664. $output .= '<div class="c-user">' . "\n";
  665. $output .= "{$commentPoster}";
  666. $output .= "<span class=\"c-user-level\">{$commentPosterLevel}</span> {$blockLink}" . "\n";
  667. Wikimedia\suppressWarnings(); // E_STRICT bitches about strtotime()
  668. $output .= '<div class="c-time">' .
  669. wfMessage(
  670. 'comments-time-ago',
  671. CommentFunctions::getTimeAgo( strtotime( $this->date ) )
  672. )->parse() . '</div>' . "\n";
  673. Wikimedia\restoreWarnings();
  674. $output .= '<div class="c-score">' . "\n";
  675. $output .= $this->getScoreHTML();
  676. $output .= '</div>' . "\n";
  677. $output .= '</div>' . "\n";
  678. $output .= "<div class=\"c-comment {$comment_class}\">" . "\n";
  679. $output .= $this->getText();
  680. $output .= '</div>' . "\n";
  681. $output .= '<div class="c-actions">' . "\n";
  682. if ( $this->page->title ) { // for some reason doesn't always exist
  683. $output .= '<a href="' . htmlspecialchars( $this->page->title->getFullURL() ) . "#comment-{$this->id}\" rel=\"nofollow\">" .
  684. $this->msg( 'comments-permalink' )->plain() . '</a> ';
  685. }
  686. if ( $replyRow || $dlt ) {
  687. $output .= "{$replyRow} {$dlt}" . "\n";
  688. }
  689. $output .= '</div>' . "\n";
  690. $output .= '</div>' . "\n";
  691. $output .= '<div class="visualClear"></div>' . "\n";
  692. $output .= '</div>' . "\n";
  693. return $output;
  694. }
  695. /**
  696. * Get the HTML for the comment score section of the comment
  697. *
  698. * @return string
  699. */
  700. function getScoreHTML() {
  701. $output = '';
  702. if ( $this->page->allowMinus == true || $this->page->allowPlus == true ) {
  703. $output .= '<span class="c-score-title">' .
  704. wfMessage( 'comments-score-text' )->plain() .
  705. " <span id=\"Comment{$this->id}\">{$this->currentScore}</span></span>";
  706. // Voting is possible only when database is unlocked
  707. if ( !wfReadOnly() ) {
  708. // You can only vote for other people's comments, not for your own
  709. if ( $this->getUser()->getName() != $this->username ) {
  710. $output .= "<span id=\"CommentBtn{$this->id}\">";
  711. if ( $this->page->allowPlus == true ) {
  712. $output .= $this->getVoteLink( 1 );
  713. }
  714. if ( $this->page->allowMinus == true ) {
  715. $output .= $this->getVoteLink( -1 );
  716. }
  717. $output .= '</span>';
  718. } else {
  719. $output .= wfMessage( 'word-separator' )->plain() . wfMessage( 'comments-you' )->plain();
  720. }
  721. }
  722. }
  723. return $output;
  724. }
  725. }