elkarte /
Elkarte
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Used to allow users to like or unlike a post or an entire topic |
||
| 5 | * |
||
| 6 | * @package ElkArte Forum |
||
| 7 | * @copyright ElkArte Forum contributors |
||
| 8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
| 9 | * |
||
| 10 | * @version 2.0 dev |
||
| 11 | * |
||
| 12 | */ |
||
| 13 | |||
| 14 | namespace ElkArte\Controller; |
||
| 15 | |||
| 16 | use ElkArte\AbstractController; |
||
| 17 | use ElkArte\Action; |
||
| 18 | use ElkArte\Exceptions\Exception; |
||
| 19 | use ElkArte\Languages\Txt; |
||
| 20 | use ElkArte\MembersList; |
||
| 21 | use ElkArte\Notifications\Notifications; |
||
| 22 | use ElkArte\Notifications\NotificationsTask; |
||
| 23 | use ElkArte\User; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * This class contains one likable use, which allows members to like a post |
||
| 27 | * |
||
| 28 | * @package Likes |
||
| 29 | */ |
||
| 30 | class Likes extends AbstractController |
||
| 31 | { |
||
| 32 | /** @var array Holds the ajax response */ |
||
| 33 | protected $_likes_response = []; |
||
| 34 | |||
| 35 | /** @var int The id of the message being liked */ |
||
| 36 | protected $_id_liked; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Entry point function for likes, permission checks, just makes sure its on |
||
| 40 | */ |
||
| 41 | public function pre_dispatch() |
||
| 42 | { |
||
| 43 | global $modSettings; |
||
| 44 | |||
| 45 | // If likes are disabled, we don't go any further |
||
| 46 | if (empty($modSettings['likes_enabled'])) |
||
| 47 | 4 | { |
|
| 48 | throw new Exception('feature_disabled', true); |
||
| 49 | 4 | } |
|
| 50 | } |
||
| 51 | |||
| 52 | 4 | /** |
|
| 53 | * Default action method, if a specific methods was not |
||
| 54 | * directly called already. Simply forwards to likepost. |
||
| 55 | * |
||
| 56 | 4 | * @see AbstractController::action_index |
|
| 57 | */ |
||
| 58 | public function action_index() |
||
| 59 | { |
||
| 60 | global $context; |
||
| 61 | |||
| 62 | $subActions = [ |
||
| 63 | 'likepost' => [$this, 'action_likepost'], |
||
| 64 | 'unlikepost' => [$this, 'action_unlikepost'], |
||
| 65 | 'likestats' => [$this, 'action_likestats'], |
||
| 66 | ]; |
||
| 67 | |||
| 68 | // We may or may not like you. |
||
| 69 | $action = new Action('likes'); |
||
| 70 | $subAction = $action->initialize($subActions, 'likepost'); |
||
| 71 | $context['sub_action'] = $subAction; |
||
| 72 | |||
| 73 | $action->dispatch($subAction); |
||
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * Likes a post due to its awesomeness |
||
| 78 | * |
||
| 79 | * What it does: |
||
| 80 | * |
||
| 81 | * - Permission checks are done in prepare_likes |
||
| 82 | * - It redirects back to the referrer afterward. |
||
| 83 | * - It is accessed via ?action=like,sa=likepost |
||
| 84 | */ |
||
| 85 | public function action_likepost(): void |
||
| 86 | { |
||
| 87 | global $topic; |
||
| 88 | |||
| 89 | if ($this->getApi() === 'json') |
||
| 90 | { |
||
| 91 | $this->action_likepost_api(); |
||
| 92 | return; |
||
| 93 | } |
||
| 94 | |||
| 95 | $this->_doLikePost('+', 'likemsg'); |
||
| 96 | |||
| 97 | redirectexit('topic=' . $topic . '.msg' . $this->_id_liked . '#msg' . $this->_id_liked); |
||
| 98 | } |
||
| 99 | 2 | ||
| 100 | /** |
||
| 101 | 2 | * Actually perform the "like" operation. |
|
| 102 | * |
||
| 103 | 2 | * Fills $_likes_response that can be used by likeResponse() in order to |
|
| 104 | * return a JSON response |
||
| 105 | * |
||
| 106 | 2 | * @param string $sign '+' or '-' |
|
| 107 | 2 | * @param string $type the type of like 'likemsg' or 'rlikemsg' |
|
| 108 | * |
||
| 109 | * @return bool |
||
| 110 | 2 | */ |
|
| 111 | protected function _doLikePost($sign, $type): bool |
||
| 112 | 2 | { |
|
| 113 | 2 | global $modSettings; |
|
| 114 | |||
| 115 | $this->_id_liked = $this->_req->getPost('msg', 'intval', (isset($this->_req->query->msg) ? (int) $this->_req->query->msg : 0)); |
||
| 116 | 2 | ||
| 117 | 2 | // We like these |
|
| 118 | require_once(SUBSDIR . '/Likes.subs.php'); |
||
| 119 | require_once(SUBSDIR . '/Messages.subs.php'); |
||
| 120 | 2 | ||
| 121 | // Have to be able to access it to like/unlike it |
||
| 122 | if ($this->prepare_like() && canAccessMessage($this->_id_liked)) |
||
| 123 | { |
||
| 124 | $liked_message = basicMessageInfo($this->_id_liked, true, true); |
||
| 125 | if ($liked_message && empty($liked_message['locked'])) |
||
| 126 | { |
||
| 127 | // Like it |
||
| 128 | $likeResult = likePost($this->user->id, $liked_message, $sign); |
||
| 129 | |||
| 130 | // Lets add in a mention to the member that just had their post liked/unliked |
||
| 131 | if (($likeResult === true) && !empty($modSettings['mentions_enabled'])) |
||
| 132 | 2 | { |
|
| 133 | $notifier = Notifications::instance(); |
||
| 134 | $notifier->add(new NotificationsTask( |
||
| 135 | $type, |
||
| 136 | $this->_id_liked, |
||
| 137 | $this->user->id, |
||
| 138 | ['id_members' => [$liked_message['id_member']], 'rlike_notif' => $type === 'rlikemsg', 'subject' => $liked_message['subject']] |
||
| 139 | )); |
||
| 140 | } |
||
| 141 | |||
| 142 | 2 | return true; |
|
| 143 | } |
||
| 144 | 2 | } |
|
| 145 | |||
| 146 | 2 | return false; |
|
| 147 | } |
||
| 148 | |||
| 149 | 2 | /** |
|
| 150 | * Checks that few things are in order (in addition to permissions) for likes. |
||
| 151 | */ |
||
| 152 | 2 | private function prepare_like() |
|
| 153 | 2 | { |
|
| 154 | global $modSettings, $txt; |
||
| 155 | |||
| 156 | 2 | $check = true; |
|
| 157 | |||
| 158 | // Valid request |
||
| 159 | 2 | checkSession('get'); |
|
| 160 | |||
| 161 | // If you're a guest or simply can't do this, we stop |
||
| 162 | 2 | is_not_guest(); |
|
| 163 | isAllowedTo('like_posts'); |
||
| 164 | |||
| 165 | // Load up the helpers |
||
| 166 | require_once(SUBSDIR . '/Likes.subs.php'); |
||
| 167 | |||
| 168 | // Maintain our log |
||
| 169 | 2 | clearLikes(empty($modSettings['likeWaitTime']) ? 0 : $modSettings['likeWaitTime']); |
|
| 170 | |||
| 171 | // Not a moderator/administrator then we do some checking |
||
| 172 | if (!empty($modSettings['likeRestrictAdmins']) || !allowedTo('moderate_forum')) |
||
| 173 | { |
||
| 174 | // Find out if this user has done this recently... |
||
| 175 | 2 | $check = lastLikeOn($this->user->id); |
|
| 176 | } |
||
| 177 | |||
| 178 | // Past the post threshold? |
||
| 179 | if ($this->user->is_admin === false && !empty($modSettings['likeMinPosts']) && $this->user->posts < $modSettings['likeMinPosts']) |
||
| 180 | { |
||
| 181 | $check = false; |
||
| 182 | } |
||
| 183 | 2 | ||
| 184 | // If they have exceeded their limits, provide a message for the ajax response |
||
| 185 | if ($check === false) |
||
| 186 | { |
||
| 187 | Txt::load('Errors'); |
||
| 188 | $wait = $modSettings['likeWaitTime'] > 60 ? round($modSettings['likeWaitTime'] / 60, 2) : $modSettings['likeWaitTime']; |
||
| 189 | $error = sprintf($txt['like_wait_time'], $wait, ($modSettings['likeWaitTime'] < 60 ? strtolower($txt['minutes']) : $txt['hours'])); |
||
| 190 | $this->_likes_response = ['result' => false, 'data' => $error]; |
||
| 191 | } |
||
| 192 | 2 | ||
| 193 | return $check; |
||
| 194 | 2 | } |
|
| 195 | |||
| 196 | /** |
||
| 197 | 2 | * Liking a post via ajax |
|
| 198 | * |
||
| 199 | * Calls the standard like method and then the api return method |
||
| 200 | */ |
||
| 201 | public function action_likepost_api(): void |
||
| 202 | { |
||
| 203 | global $txt; |
||
| 204 | |||
| 205 | // An error if not possible to like. |
||
| 206 | 2 | if (!$this->_doLikePost('+', 'likemsg') && empty($this->_likes_response)) { |
|
| 207 | 2 | Txt::load('Errors'); |
|
| 208 | $this->_likes_response = ['result' => false, 'data' => $txt['like_unlike_error']]; |
||
| 209 | } |
||
| 210 | |||
| 211 | $this->likeResponse(); |
||
| 212 | } |
||
| 213 | 2 | ||
| 214 | /** |
||
| 215 | 2 | * When liking / unliking via ajax, clears the templates and returns a json |
|
| 216 | * response to the page |
||
| 217 | */ |
||
| 218 | 2 | private function likeResponse(): void |
|
| 219 | 2 | { |
|
| 220 | global $context, $txt; |
||
| 221 | |||
| 222 | 2 | // Make room for ajax |
|
| 223 | setJsonTemplate(); |
||
| 224 | 2 | ||
| 225 | 2 | // No errors, build the new button tag |
|
| 226 | 2 | if (empty($this->_likes_response)) |
|
| 227 | 2 | { |
|
| 228 | 2 | $details = loadLikes($this->_id_liked, true); |
|
| 229 | 2 | $count = empty($details) ? 0 : $details[$this->_id_liked]['count']; |
|
| 230 | 2 | $youLiked = $count !== 0 && array_key_exists(User::$info->id , $details[$this->_id_liked]['member']); |
|
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
| 231 | 2 | $text = $count !== 0 ? ($youLiked ? $txt['unlike_post'] : $txt['likes']) : $txt['like_post']; |
|
| 232 | 2 | $title = empty($details) ? '' : $txt['liked_by'] . ' ' . implode(', ', $details[$this->_id_liked]['member']); |
|
| 233 | $this->_likes_response = [ |
||
| 234 | 'result' => true, |
||
| 235 | 'text' => $text, |
||
| 236 | 'count' => $count, |
||
| 237 | 2 | 'title' => $title |
|
| 238 | 2 | ]; |
|
| 239 | } |
||
| 240 | |||
| 241 | // Provide the response |
||
| 242 | $context['json_data'] = $this->_likes_response; |
||
| 243 | } |
||
| 244 | |||
| 245 | /** |
||
| 246 | * Un liking a post via ajax |
||
| 247 | * |
||
| 248 | * Calls the standard unlike method and then the api return method |
||
| 249 | */ |
||
| 250 | public function action_unlikepost_api(): void |
||
| 251 | { |
||
| 252 | global $txt; |
||
| 253 | |||
| 254 | // An error if not possible to like. |
||
| 255 | if (!$this->_doLikePost('-', 'rlikemsg') && empty($this->_likes_response)) { |
||
| 256 | Txt::load('Errors'); |
||
| 257 | $this->_likes_response = ['result' => false, 'data' => $txt['like_unlike_error']]; |
||
| 258 | } |
||
| 259 | |||
| 260 | $this->likeResponse(); |
||
| 261 | } |
||
| 262 | |||
| 263 | /** |
||
| 264 | * Unlikes a post that you previously liked ... no negatives though, hurts feelings :'( |
||
| 265 | * |
||
| 266 | * - It redirects back to the referrer afterward. |
||
| 267 | * - It is accessed via ?action=like,sa=unlikepost. |
||
| 268 | */ |
||
| 269 | public function action_unlikepost(): void |
||
| 270 | { |
||
| 271 | global $topic; |
||
| 272 | |||
| 273 | if ($this->getApi() === 'json') |
||
| 274 | { |
||
| 275 | $this->action_unlikepost_api(); |
||
| 276 | return; |
||
| 277 | } |
||
| 278 | |||
| 279 | $this->_doLikePost('-', 'rlikemsg'); |
||
| 280 | |||
| 281 | // No longer liked, return to whence you came |
||
| 282 | if (!isset($this->_req->query->profile)) |
||
| 283 | { |
||
| 284 | redirectexit('topic=' . $topic . '.msg' . $this->_id_liked . '#msg' . $this->_id_liked); |
||
| 285 | } |
||
| 286 | else |
||
| 287 | { |
||
| 288 | 2 | redirectexit('action=profile;area=showlikes;sa=given;u=' . $this->user->id); |
|
| 289 | } |
||
| 290 | } |
||
| 291 | 2 | ||
| 292 | /** |
||
| 293 | 2 | * Dispatch to show all the posts you liked OR all your posts liked |
|
| 294 | */ |
||
| 295 | public function action_showProfileLikes(): void |
||
| 296 | { |
||
| 297 | // Load in our helper functions |
||
| 298 | require_once(SUBSDIR . '/Likes.subs.php'); |
||
| 299 | 2 | ||
| 300 | if ($this->_req->getQuery('sa') === 'received') |
||
| 301 | 2 | { |
|
| 302 | $this->_action_showReceived(); |
||
| 303 | } |
||
| 304 | else |
||
| 305 | { |
||
| 306 | $this->_action_showGiven(); |
||
| 307 | } |
||
| 308 | } |
||
| 309 | |||
| 310 | /** |
||
| 311 | * Shows all posts that others have liked of theirs |
||
| 312 | */ |
||
| 313 | private function _action_showReceived(): void |
||
| 314 | { |
||
| 315 | global $context, $txt; |
||
| 316 | |||
| 317 | $memID = currentMemberID(); |
||
| 318 | $name = MembersList::get($memID)->real_name; |
||
|
0 ignored issues
–
show
The property
real_name does not exist on anonymous//sources/ElkArte/MembersList.php$0. Since you implemented __get, consider adding a @property annotation.
Loading history...
|
|||
| 319 | |||
| 320 | // Build the listoption array to display the data |
||
| 321 | $listOptions = [ |
||
| 322 | 'id' => 'view_likes', |
||
| 323 | 'title' => $txt['likes'], |
||
| 324 | 'items_per_page' => 25, |
||
| 325 | 'no_items_label' => $txt['likes_none_received'], |
||
| 326 | 'base_href' => getUrl('profile', ['action' => 'profile', 'area' => 'showlikes', 'sa' => 'received', 'u' => $memID, 'name' => $name]), |
||
| 327 | 'default_sort_col' => 'subject', |
||
| 328 | 'get_items' => [ |
||
| 329 | 'function' => fn($start, $items_per_page, $sort, $memberID) => $this->list_loadLikesReceived($start, $items_per_page, $sort, $memberID), |
||
| 330 | 'params' => [ |
||
| 331 | $memID, |
||
| 332 | ], |
||
| 333 | ], |
||
| 334 | 'get_count' => [ |
||
| 335 | 'function' => fn($memberID, $given) => $this->list_getLikesCount($memberID, $given), |
||
| 336 | 'params' => [ |
||
| 337 | $memID, |
||
| 338 | false, |
||
| 339 | ], |
||
| 340 | ], |
||
| 341 | 'columns' => [ |
||
| 342 | 'subject' => [ |
||
| 343 | 'header' => [ |
||
| 344 | 'value' => $txt['subject'], |
||
| 345 | ], |
||
| 346 | 'data' => [ |
||
| 347 | 'db' => 'subject', |
||
| 348 | ], |
||
| 349 | 'sort' => [ |
||
| 350 | 'default' => 'm.subject DESC', |
||
| 351 | 'reverse' => 'm.subject', |
||
| 352 | ], |
||
| 353 | ], |
||
| 354 | 'name' => [ |
||
| 355 | 'header' => [ |
||
| 356 | 'value' => $txt['board'], |
||
| 357 | ], |
||
| 358 | 'data' => [ |
||
| 359 | 'db' => 'name', |
||
| 360 | ], |
||
| 361 | 'sort' => [ |
||
| 362 | 'default' => 'b.name', |
||
| 363 | 'reverse' => 'b.name DESC', |
||
| 364 | ], |
||
| 365 | ], |
||
| 366 | 'likes' => [ |
||
| 367 | 'header' => [ |
||
| 368 | 'value' => $txt['likes'], |
||
| 369 | ], |
||
| 370 | 'data' => [ |
||
| 371 | 'db' => 'likes', |
||
| 372 | ], |
||
| 373 | 'sort' => [ |
||
| 374 | 'default' => 'likes', |
||
| 375 | 'reverse' => 'likes DESC', |
||
| 376 | ], |
||
| 377 | ], |
||
| 378 | 'action' => [ |
||
| 379 | 'header' => [ |
||
| 380 | 'value' => $txt['show'], |
||
| 381 | 'class' => 'centertext', |
||
| 382 | ], |
||
| 383 | 'data' => [ |
||
| 384 | 'function' => static function ($row) { |
||
| 385 | global $txt; |
||
| 386 | return '<a href="' . $row['who'] . '" title="' . $txt['likes_show_who'] . '"><i class="icon i-users"></i></a>'; |
||
| 387 | }, |
||
| 388 | 'class' => 'centertext', |
||
| 389 | 'style' => 'width: 10%', |
||
| 390 | ], |
||
| 391 | ], |
||
| 392 | ], |
||
| 393 | ]; |
||
| 394 | |||
| 395 | // Menu tabs |
||
| 396 | $context[$context['profile_menu_name']]['object']->prepareTabData([ |
||
| 397 | 'title' => $txt['likes'], |
||
| 398 | 'description' => $txt['likes_received'], |
||
| 399 | 'class' => 'i-thumbsup', |
||
| 400 | ]); |
||
| 401 | |||
| 402 | // Set the context values |
||
| 403 | $context['page_title'] = $txt['likes']; |
||
| 404 | $context['sub_template'] = 'show_list'; |
||
| 405 | $context['default_list'] = 'view_likes'; |
||
| 406 | |||
| 407 | // Create the list. |
||
| 408 | createList($listOptions); |
||
| 409 | } |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Callback for createList() |
||
| 413 | * Returns a list of received likes based on posts |
||
| 414 | * |
||
| 415 | * @param int $start The item to start with (for pagination purposes) |
||
| 416 | * @param int $items_per_page The number of items to show per page |
||
| 417 | * @param string $sort A string indicating how to sort the results |
||
| 418 | * @param int $memberID |
||
| 419 | * |
||
| 420 | * @return array |
||
| 421 | */ |
||
| 422 | public function list_loadLikesReceived($start, $items_per_page, $sort, $memberID): array |
||
| 423 | { |
||
| 424 | // Get a list of all posts (of a members) that have been liked |
||
| 425 | return likesPostsReceived($start, $items_per_page, $sort, $memberID); |
||
| 426 | } |
||
| 427 | |||
| 428 | /** |
||
| 429 | * Callback for createList(), |
||
| 430 | * Returns the number of likes a member has given if given = true |
||
| 431 | * else the number of posts (not likes) of theirs that have been liked |
||
| 432 | * |
||
| 433 | * @param int $memberID |
||
| 434 | * @param bool $given |
||
| 435 | 2 | * |
|
| 436 | * @return int |
||
| 437 | 2 | */ |
|
| 438 | public function list_getLikesCount($memberID, $given): int |
||
| 439 | { |
||
| 440 | return likesCount($memberID, $given); |
||
| 441 | } |
||
| 442 | |||
| 443 | 2 | /** |
|
| 444 | * Shows all posts that they have liked |
||
| 445 | 2 | */ |
|
| 446 | private function _action_showGiven(): void |
||
| 447 | 2 | { |
|
| 448 | 2 | global $context, $txt; |
|
| 449 | |||
| 450 | $memID = currentMemberID(); |
||
| 451 | $name = MembersList::get($memID)->real_name; |
||
|
0 ignored issues
–
show
The property
real_name does not exist on anonymous//sources/ElkArte/MembersList.php$0. Since you implemented __get, consider adding a @property annotation.
Loading history...
|
|||
| 452 | 2 | ||
| 453 | 2 | // Build the listoption array to display the like data |
|
| 454 | 2 | $listOptions = [ |
|
| 455 | 2 | 'id' => 'view_likes', |
|
| 456 | 2 | 'title' => $txt['likes'], |
|
| 457 | 2 | 'items_per_page' => 25, |
|
| 458 | 'no_items_label' => $txt['likes_none_given'], |
||
| 459 | 'base_href' => getUrl('profile', ['action' => 'profile', 'area' => 'showlikes', 'sa' => 'given', 'u' => $memID, 'name' => $name]), |
||
| 460 | 2 | 'default_sort_col' => 'subject', |
|
| 461 | 2 | 'get_items' => [ |
|
| 462 | 'function' => fn($start, $items_per_page, $sort, $memberID) => $this->list_loadLikesPosts($start, $items_per_page, $sort, $memberID), |
||
| 463 | 2 | 'params' => [ |
|
| 464 | $memID, |
||
| 465 | ], |
||
| 466 | ], |
||
| 467 | 'get_count' => [ |
||
| 468 | 2 | 'function' => fn($memberID, $given) => $this->list_getLikesCount($memberID, $given), |
|
| 469 | 2 | 'params' => [ |
|
| 470 | $memID, |
||
| 471 | 2 | true |
|
| 472 | ], |
||
| 473 | ], |
||
| 474 | 'columns' => [ |
||
| 475 | 'subject' => [ |
||
| 476 | 'header' => [ |
||
| 477 | 'value' => $txt['subject'], |
||
| 478 | 2 | ], |
|
| 479 | 'data' => [ |
||
| 480 | 'db' => 'subject', |
||
| 481 | ], |
||
| 482 | 'sort' => [ |
||
| 483 | 'default' => 'm.subject DESC', |
||
| 484 | 'reverse' => 'm.subject', |
||
| 485 | ], |
||
| 486 | ], |
||
| 487 | 'name' => [ |
||
| 488 | 'header' => [ |
||
| 489 | 'value' => $txt['board'], |
||
| 490 | 2 | ], |
|
| 491 | 'data' => [ |
||
| 492 | 'db' => 'name', |
||
| 493 | ], |
||
| 494 | 'sort' => [ |
||
| 495 | 'default' => 'b.name ', |
||
| 496 | 'reverse' => 'b.name DESC', |
||
| 497 | ], |
||
| 498 | ], |
||
| 499 | 'poster_name' => [ |
||
| 500 | 'header' => [ |
||
| 501 | 'value' => $txt['username'], |
||
| 502 | 2 | ], |
|
| 503 | 'data' => [ |
||
| 504 | 'db' => 'poster_name', |
||
| 505 | ], |
||
| 506 | 'sort' => [ |
||
| 507 | 'default' => 'm.poster_name ', |
||
| 508 | 'reverse' => 'm.poster_name DESC', |
||
| 509 | ], |
||
| 510 | ], |
||
| 511 | 'action' => [ |
||
| 512 | 'header' => [ |
||
| 513 | 'value' => $txt['delete'], |
||
| 514 | 2 | 'class' => 'centertext', |
|
| 515 | 2 | ], |
|
| 516 | 'data' => [ |
||
| 517 | 'function' => static function ($row) { |
||
| 518 | global $txt; |
||
| 519 | return '<a href="' . $row['delete'] . '" onclick="return confirm(\'' . $txt['likes_confirm_delete'] . '\');" title="' . $txt['likes_delete'] . '"><i class="icon i-delete"></i></a>'; |
||
| 520 | }, |
||
| 521 | 'class' => 'centertext', |
||
| 522 | 2 | 'style' => 'width: 10%', |
|
| 523 | 2 | ], |
|
| 524 | 2 | ], |
|
| 525 | ], |
||
| 526 | ]; |
||
| 527 | |||
| 528 | // Menu tabs |
||
| 529 | $context[$context['profile_menu_name']]['object']->prepareTabData([ |
||
| 530 | 'title' => $txt['likes'], |
||
| 531 | 2 | 'description' => $txt['likes_given'], |
|
| 532 | 2 | 'class' => 'i-thumbsup', |
|
| 533 | 2 | ]); |
|
| 534 | |||
| 535 | // Set the context values |
||
| 536 | $context['page_title'] = $txt['likes']; |
||
| 537 | 2 | $context['sub_template'] = 'show_list'; |
|
| 538 | 2 | $context['default_list'] = 'view_likes'; |
|
| 539 | 2 | ||
| 540 | // Create the list. |
||
| 541 | createList($listOptions); |
||
| 542 | 2 | } |
|
| 543 | 2 | ||
| 544 | /** |
||
| 545 | * Callback for createList() |
||
| 546 | * Returns a list of liked posts for a member |
||
| 547 | * |
||
| 548 | * @param int $start The item to start with (for pagination purposes) |
||
| 549 | * @param int $items_per_page The number of items to show per page |
||
| 550 | * @param string $sort A string indicating how to sort the results |
||
| 551 | * @param int $memberID |
||
| 552 | * |
||
| 553 | * @return array |
||
| 554 | */ |
||
| 555 | public function list_loadLikesPosts($start, $items_per_page, $sort, $memberID): array |
||
| 556 | 2 | { |
|
| 557 | // Get all of our liked posts |
||
| 558 | return likesPostsGiven($start, $items_per_page, $sort, $memberID); |
||
| 559 | 2 | } |
|
| 560 | |||
| 561 | /** |
||
| 562 | * Function to return an array of users that liked a particular message. |
||
| 563 | * |
||
| 564 | * - Used in profile so a user can see the full list of members, vs the |
||
| 565 | * truncated (optional) one shown in message display |
||
| 566 | * - Accessed by ?action=likes;sa=showWhoLiked;msg=x |
||
| 567 | */ |
||
| 568 | public function action_showWhoLiked(): void |
||
| 569 | { |
||
| 570 | global $context, $txt; |
||
| 571 | |||
| 572 | require_once(SUBSDIR . '/Likes.subs.php'); |
||
| 573 | Txt::load('Profile'); |
||
| 574 | |||
| 575 | // Get the message in question |
||
| 576 | $message = $this->_req->getQuery('msg', 'intval', 0); |
||
| 577 | |||
| 578 | // Build the listoption array to display the data |
||
| 579 | $listOptions = [ |
||
| 580 | 'id' => 'view_likers', |
||
| 581 | 'title' => $txt['likes_by'], |
||
| 582 | 'items_per_page' => 25, |
||
| 583 | 'no_items_label' => $txt['likes_none_given'], |
||
| 584 | 'base_href' => getUrl('action', ['action' => 'likes', 'sa' => 'showWhoLiked', 'msg' => $message]), |
||
| 585 | 'default_sort_col' => 'member', |
||
| 586 | 'get_items' => [ |
||
| 587 | 'function' => fn($start, $items_per_page, $sort, $messageID) => $this->list_loadPostLikers($start, $items_per_page, $sort, $messageID), |
||
| 588 | 'params' => [ |
||
| 589 | $message, |
||
| 590 | ], |
||
| 591 | ], |
||
| 592 | 'get_count' => [ |
||
| 593 | 'function' => fn($messageID) => $this->list_getMessageLikeCount($messageID), |
||
| 594 | 'params' => [ |
||
| 595 | $message, |
||
| 596 | ], |
||
| 597 | ], |
||
| 598 | 'columns' => [ |
||
| 599 | 'member' => [ |
||
| 600 | 'header' => [ |
||
| 601 | 'value' => $txt['members'], |
||
| 602 | 'class' => 'lefttext', |
||
| 603 | ], |
||
| 604 | 'data' => [ |
||
| 605 | 'db' => 'link', |
||
| 606 | ], |
||
| 607 | 'sort' => [ |
||
| 608 | 'default' => 'm.real_name DESC', |
||
| 609 | 'reverse' => 'm.real_name', |
||
| 610 | ], |
||
| 611 | ], |
||
| 612 | ], |
||
| 613 | 'additional_rows' => [ |
||
| 614 | [ |
||
| 615 | 'position' => 'below_table_data', |
||
| 616 | 'class' => 'submitbutton', |
||
| 617 | 'value' => '<a class="linkbutton" href="javascript:history.go(-1)">' . $txt['back'] . '</a>', |
||
| 618 | ], |
||
| 619 | ], |
||
| 620 | ]; |
||
| 621 | |||
| 622 | // Set the context values |
||
| 623 | $context['page_title'] = $txt['likes_by']; |
||
| 624 | $context['sub_template'] = 'show_list'; |
||
| 625 | $context['default_list'] = 'view_likers'; |
||
| 626 | |||
| 627 | // Create the list. |
||
| 628 | createList($listOptions); |
||
| 629 | } |
||
| 630 | |||
| 631 | /** |
||
| 632 | * Callback for createList() |
||
| 633 | * Returns a list of members that liked a post |
||
| 634 | * |
||
| 635 | * @param int $start The item to start with (for pagination purposes) |
||
| 636 | * @param int $items_per_page The number of items to show per page |
||
| 637 | * @param string $sort A string indicating how to sort the results |
||
| 638 | * @param int $messageID |
||
| 639 | * |
||
| 640 | * @return array |
||
| 641 | */ |
||
| 642 | public function list_loadPostLikers($start, $items_per_page, $sort, $messageID): array |
||
| 643 | { |
||
| 644 | // Get a list of this posts likers |
||
| 645 | return postLikers($start, $items_per_page, $sort, $messageID); |
||
| 646 | } |
||
| 647 | |||
| 648 | /** |
||
| 649 | * Callback for createList(), |
||
| 650 | * Returns the number of likes a message has received |
||
| 651 | * |
||
| 652 | * @param int $messageID |
||
| 653 | * |
||
| 654 | * @return int |
||
| 655 | */ |
||
| 656 | public function list_getMessageLikeCount($messageID): int |
||
| 657 | { |
||
| 658 | return messageLikeCount($messageID); |
||
| 659 | } |
||
| 660 | |||
| 661 | /** |
||
| 662 | * Like stats controller function, used by API calls. |
||
| 663 | * |
||
| 664 | * What it does: |
||
| 665 | * |
||
| 666 | * - Validates whether user is allowed to see stats or not. |
||
| 667 | * - Decides which tab data to fetch and show to user. |
||
| 668 | */ |
||
| 669 | public function action_likestats_api(): void |
||
| 670 | { |
||
| 671 | global $context; |
||
| 672 | |||
| 673 | checkSession('get'); |
||
| 674 | |||
| 675 | Txt::load('LikePosts'); |
||
| 676 | |||
| 677 | $subActions = [ |
||
| 678 | 'messagestats' => [$this, 'action_messageStats'], |
||
| 679 | 'topicstats' => [$this, 'action_topicStats'], |
||
| 680 | 'boardstats' => [$this, 'action_boardStats'], |
||
| 681 | 'mostlikesreceiveduserstats' => [$this, 'action_mostLikesReceivedUserStats'], |
||
| 682 | 'mostlikesgivenuserstats' => [$this, 'action_mostLikesGivenUserStats'], |
||
| 683 | ]; |
||
| 684 | |||
| 685 | // Set up the action controller |
||
| 686 | $action = new Action('likesstats'); |
||
| 687 | |||
| 688 | // Pick the correct sub-action, call integrate_sa_likesstats |
||
| 689 | $subAction = $action->initialize($subActions, 'messagestats', 'area'); |
||
| 690 | $context['sub_action'] = $subAction; |
||
| 691 | |||
| 692 | // Call the right function for this sub-action. |
||
| 693 | $action->dispatch($subAction); |
||
| 694 | } |
||
| 695 | |||
| 696 | /** |
||
| 697 | * Like stats controller function. |
||
| 698 | * |
||
| 699 | * What it does: |
||
| 700 | * |
||
| 701 | * - Validates whether user is allowed to see stats or not. |
||
| 702 | * - Presents a general page without data that will be fully loaded by API calls. |
||
| 703 | * - Used when call is made from the main menu selection |
||
| 704 | */ |
||
| 705 | public function action_likestats(): void |
||
| 706 | { |
||
| 707 | global $context, $txt, $modSettings; |
||
| 708 | |||
| 709 | require_once(SUBSDIR . '/Likes.subs.php'); |
||
| 710 | |||
| 711 | // Likes are not on, your quest for statistics ends here |
||
| 712 | if (empty($modSettings['likes_enabled'])) |
||
| 713 | { |
||
| 714 | throw new Exception('feature_disabled', true); |
||
| 715 | } |
||
| 716 | |||
| 717 | // Worthy to view like statistics? |
||
| 718 | isAllowedTo('like_posts_stats'); |
||
| 719 | |||
| 720 | if ($this->getApi() === 'json') |
||
| 721 | { |
||
| 722 | $this->action_likestats_api(); |
||
| 723 | return; |
||
| 724 | } |
||
| 725 | |||
| 726 | // Load the required files |
||
| 727 | Txt::load('LikePosts'); |
||
| 728 | loadJavascriptFile('like_posts.js'); |
||
| 729 | theme()->getTemplates()->load('LikePostsStats'); |
||
| 730 | |||
| 731 | // Template and tab data |
||
| 732 | $context['page_title'] = $txt['like_post_stats']; |
||
| 733 | $context['like_posts']['tab_desc'] = $txt['like_posts_stats_desc']; |
||
| 734 | $context['lp_stats_tabs'] = [ |
||
| 735 | 'messagestats' => [ |
||
| 736 | 'label' => $txt['like_post_message'], |
||
| 737 | 'id' => 'messagestats', |
||
| 738 | ], |
||
| 739 | 'topicstats' => [ |
||
| 740 | 'label' => $txt['like_post_topic'], |
||
| 741 | 'id' => 'topicstats', |
||
| 742 | ], |
||
| 743 | 'boardstats' => [ |
||
| 744 | 'label' => $txt['like_post_board'], |
||
| 745 | 'id' => 'boardstats', |
||
| 746 | ], |
||
| 747 | 'usergivenstats' => [ |
||
| 748 | 'label' => $txt['like_post_tab_mlmember'], |
||
| 749 | 'id' => 'mostlikesreceiveduserstats', |
||
| 750 | ], |
||
| 751 | 'userreceivedstats' => [ |
||
| 752 | 'label' => $txt['like_post_tab_mlgmember'], |
||
| 753 | 'id' => 'mostlikesgivenuserstats', |
||
| 754 | ], |
||
| 755 | ]; |
||
| 756 | $context['sub_template'] = 'lp_stats'; |
||
| 757 | } |
||
| 758 | |||
| 759 | /** |
||
| 760 | * Determines the most liked message in the system |
||
| 761 | * |
||
| 762 | * What it does: |
||
| 763 | * |
||
| 764 | * - Fetches the most liked message data |
||
| 765 | * - Returns the data via ajax |
||
| 766 | */ |
||
| 767 | public function action_messageStats(): void |
||
| 768 | { |
||
| 769 | global $txt; |
||
| 770 | |||
| 771 | // Lets get the statistics! |
||
| 772 | $data = dbMostLikedMessage(); |
||
| 773 | |||
| 774 | // Set the response |
||
| 775 | if (!empty($data)) |
||
| 776 | { |
||
| 777 | $this->_likes_response = ['result' => true, 'data' => $data]; |
||
| 778 | } |
||
| 779 | else |
||
| 780 | { |
||
| 781 | $this->_likes_response = ['result' => false, 'error' => $txt['like_post_error_something_wrong']]; |
||
| 782 | } |
||
| 783 | |||
| 784 | // Off we go |
||
| 785 | $this->likeResponse(); |
||
| 786 | } |
||
| 787 | |||
| 788 | /** |
||
| 789 | * Determine the most liked topics in the system |
||
| 790 | * |
||
| 791 | * What it does: |
||
| 792 | * |
||
| 793 | * - Gets the most liked topics in the system |
||
| 794 | * - Returns the data via ajax |
||
| 795 | */ |
||
| 796 | public function action_topicStats(): void |
||
| 797 | { |
||
| 798 | global $txt; |
||
| 799 | |||
| 800 | $data = dbMostLikedTopic(); |
||
| 801 | |||
| 802 | if (!empty($data)) |
||
| 803 | { |
||
| 804 | $this->_likes_response = ['result' => true, 'data' => $data]; |
||
| 805 | } |
||
| 806 | else |
||
| 807 | { |
||
| 808 | $this->_likes_response = ['result' => false, 'error' => $txt['like_post_error_something_wrong']]; |
||
| 809 | } |
||
| 810 | |||
| 811 | $this->likeResponse(); |
||
| 812 | } |
||
| 813 | |||
| 814 | /** |
||
| 815 | * Fetches the most liked board data |
||
| 816 | * Returns the data via ajax |
||
| 817 | */ |
||
| 818 | public function action_boardStats(): void |
||
| 819 | { |
||
| 820 | global $txt; |
||
| 821 | |||
| 822 | $data = dbMostLikedBoard(); |
||
| 823 | |||
| 824 | if (!empty($data)) |
||
| 825 | { |
||
| 826 | $this->_likes_response = ['result' => true, 'data' => $data]; |
||
| 827 | } |
||
| 828 | else |
||
| 829 | { |
||
| 830 | $this->_likes_response = ['result' => false, 'error' => $txt['like_post_error_something_wrong']]; |
||
| 831 | } |
||
| 832 | |||
| 833 | $this->likeResponse(); |
||
| 834 | } |
||
| 835 | |||
| 836 | /** |
||
| 837 | * Fetches the data for the highest likes received user |
||
| 838 | * Returns the data via ajax |
||
| 839 | */ |
||
| 840 | public function action_mostLikesReceivedUserStats(): void |
||
| 841 | { |
||
| 842 | global $txt; |
||
| 843 | |||
| 844 | $data = dbMostLikesReceivedUser(); |
||
| 845 | |||
| 846 | if (!empty($data)) |
||
| 847 | { |
||
| 848 | $this->_likes_response = ['result' => true, 'data' => $data]; |
||
| 849 | } |
||
| 850 | else |
||
| 851 | { |
||
| 852 | $this->_likes_response = ['result' => false, 'error' => $txt['like_post_error_something_wrong']]; |
||
| 853 | } |
||
| 854 | |||
| 855 | $this->likeResponse(); |
||
| 856 | } |
||
| 857 | |||
| 858 | /** |
||
| 859 | * Retrieves the most like giving user |
||
| 860 | * |
||
| 861 | * Returns the data via ajax |
||
| 862 | */ |
||
| 863 | public function action_mostLikesGivenUserStats(): void |
||
| 864 | { |
||
| 865 | global $txt; |
||
| 866 | |||
| 867 | $data = dbMostLikesGivenUser(); |
||
| 868 | |||
| 869 | if (!empty($data)) |
||
| 870 | { |
||
| 871 | $this->_likes_response = ['result' => true, 'data' => $data]; |
||
| 872 | } |
||
| 873 | else |
||
| 874 | { |
||
| 875 | $this->_likes_response = ['result' => false, 'error' => $txt['like_post_error_something_wrong']]; |
||
| 876 | } |
||
| 877 | |||
| 878 | $this->likeResponse(); |
||
| 879 | } |
||
| 880 | } |
||
| 881 |