1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22 23declare(strict_types=0); 24 25namespace Ampache\Repository\Model; 26 27use Ampache\Module\Authorization\Access; 28use Ampache\Module\Api\Ajax; 29use Ampache\Module\User\Activity\UserActivityPosterInterface; 30use Ampache\Module\Util\InterfaceImplementationChecker; 31use Ampache\Module\Util\Mailer; 32use Ampache\Module\Util\ObjectTypeToClassNameMapper; 33use Ampache\Config\AmpConfig; 34use Ampache\Module\System\Core; 35use Ampache\Module\System\Dba; 36use PDOStatement; 37use Ampache\Module\Util\Ui; 38 39class Shoutbox 40{ 41 public $id; 42 public $object_type; 43 public $object_id; 44 public $user; 45 public $sticky; 46 public $text; 47 public $data; 48 public $date; 49 50 /** 51 * Constructor 52 * This pulls the shoutbox information from the database and returns 53 * a constructed object, uses user_shout table 54 * @param integer $shout_id 55 */ 56 public function __construct($shout_id) 57 { 58 // Load the data from the database 59 $this->has_info($shout_id); 60 61 return true; 62 } // Constructor 63 64 public function getId(): int 65 { 66 return (int) $this->id; 67 } 68 69 /** 70 * has_info 71 * does the db call, reads from the user_shout table 72 * @param integer $shout_id 73 * @return boolean 74 */ 75 private function has_info($shout_id) 76 { 77 $sql = "SELECT * FROM `user_shout` WHERE `id` = ?"; 78 $db_results = Dba::read($sql, array($shout_id)); 79 80 $data = Dba::fetch_assoc($db_results); 81 82 foreach ($data as $key => $value) { 83 $this->$key = $value; 84 } 85 86 return true; 87 } // has_info 88 89 /** 90 * get_top 91 * This returns the top user_shouts, shoutbox objects are always shown regardless and count against the total 92 * number of objects shown 93 * @param integer $limit 94 * @param string $username 95 * @return integer[] 96 */ 97 public static function get_top($limit, $username = null) 98 { 99 $shouts = self::get_sticky(); 100 101 // If we've already got too many stop here 102 if (count($shouts) > $limit) { 103 $shouts = array_slice($shouts, 0, $limit); 104 105 return $shouts; 106 } 107 108 // Only get as many as we need 109 $limit = (int)($limit) - count($shouts); 110 $params = array(); 111 $sql = "SELECT `user_shout`.`id` AS `id` FROM `user_shout` LEFT JOIN `user` ON `user`.`id` = `user_shout`.`user` WHERE `user_shout`.`sticky`='0' "; 112 if ($username !== null) { 113 $sql .= "AND `user`.`username` = ? "; 114 $params[] = $username; 115 } 116 $sql .= "ORDER BY `user_shout`.`date` DESC LIMIT " . $limit; 117 $db_results = Dba::read($sql, $params); 118 119 while ($row = Dba::fetch_assoc($db_results)) { 120 $shouts[] = (int)$row['id']; 121 } 122 123 return $shouts; 124 } // get_top 125 126 /** 127 * get_sticky 128 * This returns all current sticky shoutbox items 129 */ 130 private static function get_sticky() 131 { 132 $sql = "SELECT * FROM `user_shout` WHERE `sticky`='1' ORDER BY `date` DESC"; 133 134 $db_results = Dba::read($sql); 135 $results = array(); 136 while ($row = Dba::fetch_assoc($db_results)) { 137 $results[] = $row['id']; 138 } 139 140 return $results; 141 } // get_sticky 142 143 /** 144 * get_object 145 * This takes a type and an ID and returns a created object 146 * @param string $type 147 * @param integer $object_id 148 * @return Object 149 */ 150 public static function get_object($type, $object_id) 151 { 152 if (!InterfaceImplementationChecker::is_library_item($type)) { 153 return null; 154 } 155 156 $class_name = ObjectTypeToClassNameMapper::map($type); 157 $object = new $class_name($object_id); 158 159 if ($object->id > 0) { 160 if (strtolower((string)$type) === 'song') { 161 if (!$object->enabled) { 162 $object = null; 163 } 164 } 165 } else { 166 $object = null; 167 } 168 169 return $object; 170 } // get_object 171 172 /** 173 * get_image 174 * This returns an image tag if the type of object we're currently rolling with 175 * has an image associated with it 176 */ 177 public function get_image() 178 { 179 $image_string = ''; 180 if (Art::has_db($this->object_id, $this->object_type)) { 181 $image_string = "<img class=\"shoutboximage\" height=\"75\" width=\"75\" src=\"" . AmpConfig::get('web_path') . "/image.php?object_id=" . $this->object_id . "&object_type=" . $this->object_type . "&thumb=1\" />"; 182 } 183 184 return $image_string; 185 } // get_image 186 187 /** 188 * create 189 * This takes a key'd array of data as input and inserts a new shoutbox entry, it returns the auto_inc id 190 * @param array $data 191 * @return boolean|string|null 192 * @throws \PHPMailer\PHPMailer\Exception 193 */ 194 public static function create(array $data) 195 { 196 if (!InterfaceImplementationChecker::is_library_item($data['object_type'])) { 197 return false; 198 } 199 200 $sticky = isset($data['sticky']) ? 1 : 0; 201 $user = (int)($data['user'] ?: Core::get_global('user')->id); 202 $date = (int)($data['date'] ?: time()); 203 $comment = strip_tags($data['comment']); 204 205 $sql = "INSERT INTO `user_shout` (`user`, `date`, `text`, `sticky`, `object_id`, `object_type`, `data`) VALUES (?, ?, ?, ?, ?, ?, ?)"; 206 Dba::write($sql, 207 array($user, $date, $comment, $sticky, $data['object_id'], $data['object_type'], $data['data'])); 208 209 static::getUserActivityPoster()->post((int) $user, 'shout', $data['object_type'], (int) $data['object_id'], time()); 210 211 $insert_id = Dba::insert_id(); 212 213 // Never send email in case of user impersonation 214 if (!isset($data['user']) && $insert_id !== null) { 215 $class_name = ObjectTypeToClassNameMapper::map($data['object_type']); 216 $libitem = new $class_name($data['object_id']); 217 $item_owner_id = $libitem->get_user_owner(); 218 if ($item_owner_id) { 219 if (Preference::get_by_user($item_owner_id, 'notify_email')) { 220 $item_owner = new User($item_owner_id); 221 if (!empty($item_owner->email) && Mailer::is_mail_enabled()) { 222 $libitem->format(); 223 $mailer = new Mailer(); 224 $mailer->set_default_sender(); 225 $mailer->recipient = $item_owner->email; 226 $mailer->recipient_name = $item_owner->fullname; 227 $mailer->subject = T_('New shout on your content'); 228 /* HINT: %1 username %2 item name being commented on */ 229 $mailer->message = sprintf(T_('You just received a new shout from %1$s on your content %2$s'), 230 Core::get_global('user')->fullname, $libitem->get_fullname()); 231 $mailer->message .= "\n\n----------------------\n\n"; 232 $mailer->message .= $comment; 233 $mailer->message .= "\n\n----------------------\n\n"; 234 $mailer->message .= AmpConfig::get('web_path') . "/shout.php?action=show_add_shout&type=" . $data['object_type'] . "&id=" . $data['object_id'] . "#shout" . $insert_id; 235 $mailer->send(); 236 } 237 } 238 } 239 } 240 241 return $insert_id; 242 } // create 243 244 /** 245 * update 246 * This takes a key'd array of data as input and updates a shoutbox entry 247 * @param array $data 248 * @return mixed 249 */ 250 public function update(array $data) 251 { 252 $sql = "UPDATE `user_shout` SET `text` = ?, `sticky` = ? WHERE `id` = ?"; 253 Dba::write($sql, array($data['comment'], (int) make_bool($data['sticky']), $this->id)); 254 255 return $this->id; 256 } // create 257 258 public function getStickyFormatted(): string 259 { 260 return $this->sticky == '0' ? 'No' : 'Yes'; 261 } 262 263 public function getTextFormatted(): string 264 { 265 return preg_replace('/(\r\n|\n|\r)/', '<br />', $this->text); 266 } 267 268 public function getDateFormatted(): string 269 { 270 return get_datetime((int)$this->date); 271 } 272 273 /** 274 * @param boolean $details 275 * @param boolean $jsbuttons 276 * @return string 277 */ 278 public function get_display($details = true, $jsbuttons = false) 279 { 280 $object = Shoutbox::get_object($this->object_type, $this->object_id); 281 $object->format(); 282 $img = $this->get_image(); 283 $html = "<div class='shoutbox-item'>"; 284 $html .= "<div class='shoutbox-data'>"; 285 if ($details && $img) { 286 $html .= "<div class='shoutbox-img'>" . $img . "</div>"; 287 } 288 $html .= "<div class='shoutbox-info'>"; 289 if ($details) { 290 $html .= "<div class='shoutbox-object'>" . $object->f_link . "</div>"; 291 $html .= "<div class='shoutbox-date'>" . get_datetime((int)$this->date) . "</div>"; 292 } 293 $html .= "<div class='shoutbox-text'>" . $this->getTextFormatted() . "</div>"; 294 $html .= "</div>"; 295 $html .= "</div>"; 296 $html .= "<div class='shoutbox-footer'>"; 297 if ($details) { 298 $html .= "<div class='shoutbox-actions'>"; 299 if ($jsbuttons) { 300 $html .= Ajax::button('?page=stream&action=directplay&playtype=' . $this->object_type . '&' . $this->object_type . '_id=' . $this->object_id, 301 'play', T_('Play'), 'play_' . $this->object_type . '_' . $this->object_id); 302 $html .= Ajax::button('?action=basket&type=' . $this->object_type . '&id=' . $this->object_id, 'add', 303 T_('Add'), 'add_' . $this->object_type . '_' . $this->object_id); 304 } 305 if (Access::check('interface', 25)) { 306 $html .= "<a href=\"" . AmpConfig::get('web_path') . "/shout.php?action=show_add_shout&type=" . $this->object_type . "&id=" . $this->object_id . "\">" . Ui::get_icon('comment', 307 T_('Post Shout')) . "</a>"; 308 } 309 $html .= "</div>"; 310 } 311 $html .= "<div class='shoutbox-user'>" . T_('by') . " "; 312 313 if ($this->user > 0) { 314 $user = new User($this->user); 315 $user->format(); 316 if ($details) { 317 $html .= $user->f_link; 318 } else { 319 $html .= $user->username; 320 } 321 } else { 322 $html .= T_('Guest'); 323 } 324 $html .= "</div>"; 325 $html .= "</div>"; 326 $html .= "</div>"; 327 328 return $html; 329 } 330 331 /** 332 * Migrate an object associate stats to a new object 333 * @param string $object_type 334 * @param integer $old_object_id 335 * @param integer $new_object_id 336 * @return PDOStatement|boolean 337 */ 338 public static function migrate($object_type, $old_object_id, $new_object_id) 339 { 340 $sql = "UPDATE `user_shout` SET `object_id` = ? WHERE `object_type` = ? AND `object_id` = ?"; 341 342 return Dba::write($sql, array($new_object_id, $object_type, $old_object_id)); 343 } 344 345 /** 346 * @deprecated inject dependency 347 */ 348 private static function getUserActivityPoster(): UserActivityPosterInterface 349 { 350 global $dic; 351 352 return $dic->get(UserActivityPosterInterface::class); 353 } 354} 355