| 1 |
<?php |
| 2 |
|
| 3 |
namespace wpforo\modules\subscriptions; |
| 4 |
|
| 5 |
use stdClass; |
| 6 |
use wpforo\modules\subscriptions\classes\Template; |
| 7 |
use wpforo\modules\subscriptions\classes\Actions; |
| 8 |
use wpforo\modules\mentioning\Mentioning; |
| 9 |
use wpforo\modules\follows\Follows; |
| 10 |
|
| 11 |
// Exit if accessed directly |
| 12 |
if( ! defined( 'ABSPATH' ) ) exit; |
| 13 |
|
| 14 |
class Subscriptions { |
| 15 |
public $default; |
| 16 |
/* @var Template */ public $Template; |
| 17 |
/* @var Actions */ public $Actions; |
| 18 |
/* @var Mentioning */ public $Mentioning; |
| 19 |
/* @var Follows */ public $Follows; |
| 20 |
|
| 21 |
function __construct() { |
| 22 |
$this->init_defaults(); |
| 23 |
$this->init_classes(); |
| 24 |
$this->init_hooks(); |
| 25 |
} |
| 26 |
|
| 27 |
private function init_defaults() { |
| 28 |
$this->default = new stdClass; |
| 29 |
$this->default->subscribe_format = [ |
| 30 |
'subid' => '%d', |
| 31 |
'type' => '%s', |
| 32 |
'itemid' => '%d', |
| 33 |
'userid' => '%d', |
| 34 |
'confirmkey' => '%s', |
| 35 |
'active' => '%d', |
| 36 |
'user_name' => '%s', |
| 37 |
'user_email' => '%s', |
| 38 |
]; |
| 39 |
} |
| 40 |
|
| 41 |
private function init_classes() { |
| 42 |
$this->Template = new Template(); |
| 43 |
$this->Actions = new Actions(); |
| 44 |
$this->Mentioning = new Mentioning(); |
| 45 |
$this->Follows = new Follows(); |
| 46 |
} |
| 47 |
|
| 48 |
private function init_hooks() { |
| 49 |
add_filter( 'wpforo_init_member_templates', [ $this, 'add_templates' ] ); |
| 50 |
add_filter( 'wpforo_after_init_current_object', [ $this, 'init_current_object' ] ); |
| 51 |
} |
| 52 |
|
| 53 |
public function add_templates( $templates ) { |
| 54 |
$templates['subscriptions'] = [ |
| 55 |
'type' => 'callback', |
| 56 |
'key' => 'subscriptions', |
| 57 |
'menu_shortcode' => 'wpforo-profile-subscriptions', |
| 58 |
'ico' => '<i class="fas fa-rss"></i>', |
| 59 |
'title' => 'Subscriptions', |
| 60 |
'is_default' => 1, |
| 61 |
'can' => 'vprs', |
| 62 |
'add_in_member_menu' => 1, |
| 63 |
'add_in_member_buttons' => 1, |
| 64 |
'callback_for_page' => function(){ |
| 65 |
require wpftpl( 'profile-subscriptions.php' ); |
| 66 |
}, |
| 67 |
]; |
| 68 |
|
| 69 |
return $templates; |
| 70 |
} |
| 71 |
|
| 72 |
public function init_current_object( $current_object ) { |
| 73 |
if( !$current_object['is_404'] && $current_object['template'] === 'subscriptions' ){ |
| 74 |
$args = [ |
| 75 |
'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'], |
| 76 |
'row_count' => $current_object['items_per_page'], |
| 77 |
'userid' => $current_object['userid'], |
| 78 |
'order' => 'DESC', |
| 79 |
]; |
| 80 |
$current_object['items_count'] = 0; |
| 81 |
$current_object['subscribes'] = $this->get_subscribes( $args, $current_object['items_count'] ); |
| 82 |
} |
| 83 |
|
| 84 |
return $current_object; |
| 85 |
} |
| 86 |
|
| 87 |
function get_confirm_key() { |
| 88 |
return substr( md5( rand() . time() ), 0, 32 ); |
| 89 |
} |
| 90 |
|
| 91 |
function add( $args = [] ) { |
| 92 |
if( empty( $args ) && empty( $_REQUEST['sbscrb'] ) ) return false; |
| 93 |
if( empty( $args ) && ! empty( $_REQUEST['sbscrb'] ) ) $args = $_REQUEST['sbscrb']; |
| 94 |
if( ! isset( $args['active'] ) || ! $args['active'] ) $args['active'] = 0; |
| 95 |
|
| 96 |
extract( $args ); |
| 97 |
if( ! isset( $itemid ) || ! ( ( isset( $userid ) && $userid ) || ( isset( $user_email ) && $user_email ) ) || ! isset( $type ) || ! $type ) return false; |
| 98 |
|
| 99 |
if( empty( $confirmkey ) ) $confirmkey = $this->get_confirm_key(); |
| 100 |
|
| 101 |
$user_name = ( isset( $user_name ) && $user_name ? $user_name : '' ); |
| 102 |
$user_email = ( isset( $user_email ) && $user_email ? $user_email : '' ); |
| 103 |
|
| 104 |
$sql = "SELECT EXISTS( |
| 105 |
SELECT * FROM `" . WPF()->tables->subscribes . "` |
| 106 |
WHERE `itemid` = %d |
| 107 |
AND `type` = %s |
| 108 |
AND `userid` = %d |
| 109 |
AND `user_email` = %s |
| 110 |
) AS is_exists"; |
| 111 |
$sql = WPF()->db->prepare( $sql, $itemid, $type, $userid, $user_email ); |
| 112 |
if( ! WPF()->db->get_var( $sql ) ) { |
| 113 |
if( WPF()->db->insert( |
| 114 |
WPF()->tables->subscribes, |
| 115 |
[ |
| 116 |
'itemid' => $itemid, |
| 117 |
'type' => $type, |
| 118 |
'confirmkey' => $confirmkey, |
| 119 |
'userid' => $userid, |
| 120 |
'active' => $active, |
| 121 |
'user_name' => $user_name, |
| 122 |
'user_email' => $user_email, |
| 123 |
], |
| 124 |
[ '%d', '%s', '%s', '%d', '%d', '%s', '%s' ] |
| 125 |
) ) { |
| 126 |
if( isset( $active ) && $active == 1 ) { |
| 127 |
if( intval( $userid ) === WPF()->current_userid ) { |
| 128 |
WPF()->notice->add( 'You have been successfully subscribed', 'success' ); |
| 129 |
} else { |
| 130 |
WPF()->notice->add( 'Success!', 'success' ); |
| 131 |
} |
| 132 |
} else { |
| 133 |
if( intval( $userid ) === WPF()->current_userid ) { |
| 134 |
WPF()->notice->add( 'Success! Thank you. Please check your email and click confirmation link below to complete this step.', 'success' ); |
| 135 |
} else { |
| 136 |
WPF()->notice->add( 'Success!', 'success' ); |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
return $confirmkey; |
| 141 |
} |
| 142 |
|
| 143 |
} |
| 144 |
|
| 145 |
WPF()->notice->add( 'Can\'t subscribe to this item', 'error' ); |
| 146 |
|
| 147 |
return false; |
| 148 |
} |
| 149 |
|
| 150 |
function edit( $confirmkey = '' ) { |
| 151 |
if( ! $confirmkey && isset( $_REQUEST['key'] ) && $_REQUEST['key'] ) $confirmkey = $_REQUEST['key']; |
| 152 |
if( ! $confirmkey ) { |
| 153 |
WPF()->notice->add( 'Invalid request!', 'error' ); |
| 154 |
return false; |
| 155 |
} |
| 156 |
|
| 157 |
if( WPF()->db->update( WPF()->tables->subscribes, [ 'active' => 1 ], [ 'confirmkey' => sanitize_text_field( $confirmkey ) ], [ '%d' ], [ '%s' ] ) ) { |
| 158 |
if( $sbs = $this->get_subscribe( $confirmkey ) ) WPF()->member->set_is_email_confirmed( $sbs['userid'], 1 ); |
| 159 |
|
| 160 |
WPF()->notice->add( 'You have been successfully subscribed', 'success' ); |
| 161 |
return true; |
| 162 |
} |
| 163 |
|
| 164 |
WPF()->notice->add( 'Your subscription for this item could not be confirmed', 'error' ); |
| 165 |
return false; |
| 166 |
} |
| 167 |
|
| 168 |
public function reset( $data = [], $all = '', $user = null ) { |
| 169 |
if( ! $user && ! WPF()->current_userid && ! WPF()->current_user_email ) return false; |
| 170 |
if( ! $user ) $user = ( WPF()->current_userid ? WPF()->current_userid : WPF()->current_user_email ); |
| 171 |
$data = array_filter( (array) $data ); |
| 172 |
$args = [ |
| 173 |
'itemid' => 0, |
| 174 |
'type' => '', |
| 175 |
'userid' => 0, |
| 176 |
'active' => ( wpforo_setting( 'subscriptions', 'subscribe_confirmation' ) ? 0 : 1 ), |
| 177 |
'user_name' => '', |
| 178 |
'user_email' => '', |
| 179 |
]; |
| 180 |
if( is_numeric( $user ) ) { |
| 181 |
$args['userid'] = $user; |
| 182 |
$where = WPF()->db->prepare( "`userid` = %d", $user ); |
| 183 |
} else { |
| 184 |
$args['user_email'] = $user; |
| 185 |
$args['user_name'] = WPF()->current_user_display_name; |
| 186 |
$where = WPF()->db->prepare( "`user_email` = %s", $user ); |
| 187 |
} |
| 188 |
|
| 189 |
if( $args['active'] !== 1 && $this->is_email_confirmed( $user ) ) $args['active'] = 1; |
| 190 |
|
| 191 |
$types = [ 'forum', 'forum-topic' ]; |
| 192 |
if( ! $all ) array_push( $types, 'forums', 'forums-topics' ); |
| 193 |
$sql = "DELETE FROM `" . WPF()->tables->subscribes . "` WHERE `type` IN('" . implode( "','", $types ) . "') AND " . $where; |
| 194 |
if( ! $all && $data ) { |
| 195 |
$forumids = array_keys( $data ); |
| 196 |
$sql .= " AND `itemid` NOT IN(" . implode( ',', $forumids ) . ")"; |
| 197 |
} |
| 198 |
WPF()->db->query( $sql ); |
| 199 |
|
| 200 |
if( ! $all && $data ) { |
| 201 |
foreach( $data as $forumid => $type ) { |
| 202 |
$sql = "SELECT `subid` FROM `" . WPF()->tables->subscribes . "` WHERE `type` IN('forum', 'forum-topic') AND `itemid` = %d AND " . $where; |
| 203 |
$sql = WPF()->db->prepare( $sql, $forumid ); |
| 204 |
if( $subid = WPF()->db->get_var( $sql ) ) { |
| 205 |
WPF()->db->update( WPF()->tables->subscribes, [ 'type' => sanitize_text_field( $type ), 'active' => $args['active'] ], [ 'subid' => $subid ], [ '%s', '%d' ], [ '%d' ] ); |
| 206 |
} else { |
| 207 |
$args['itemid'] = intval( $forumid ); |
| 208 |
$args['type'] = sanitize_text_field( $type ); |
| 209 |
$this->add( $args ); |
| 210 |
} |
| 211 |
} |
| 212 |
} |
| 213 |
|
| 214 |
if( $all ) { |
| 215 |
$sql = "SELECT `subid` FROM `" . WPF()->tables->subscribes . "` WHERE `type` IN('forums', 'forums-topics') AND `itemid` = 0 AND " . $where; |
| 216 |
if( $subid = WPF()->db->get_var( $sql ) ) { |
| 217 |
WPF()->db->update( WPF()->tables->subscribes, [ 'type' => sanitize_text_field( $all ), 'active' => $args['active'] ], [ 'subid' => $subid ], [ '%s', '%d' ], [ '%d' ] ); |
| 218 |
} else { |
| 219 |
$args['itemid'] = 0; |
| 220 |
$args['type'] = sanitize_text_field( $all ); |
| 221 |
$this->add( $args ); |
| 222 |
} |
| 223 |
} |
| 224 |
|
| 225 |
return true; |
| 226 |
} |
| 227 |
|
| 228 |
function delete( $where = [], $table = '' ) { |
| 229 |
if( ! $where && $confirmkey = wpfval( $_REQUEST, 'confirmkey' ) ) $where = $confirmkey; |
| 230 |
if( ! $where ) { |
| 231 |
WPF()->notice->add( 'Invalid request!', 'error' ); |
| 232 |
return false; |
| 233 |
} |
| 234 |
|
| 235 |
if( ! is_array( $where ) ) $where = [ 'confirmkey' => $where ]; |
| 236 |
$where = (array) $where; |
| 237 |
|
| 238 |
$where = wpforo_array_ordered_intersect_key( $where, $this->default->subscribe_format ); |
| 239 |
if( false !== WPF()->db->delete( |
| 240 |
$table ?: WPF()->tables->subscribes, |
| 241 |
$where, |
| 242 |
wpforo_array_ordered_intersect_key( $this->default->subscribe_format, $where ) |
| 243 |
) ) { |
| 244 |
WPF()->notice->add( 'You have been successfully unsubscribed', 'success' ); |
| 245 |
return true; |
| 246 |
} |
| 247 |
|
| 248 |
WPF()->notice->add( 'Could not be unsubscribe from this item', 'error' ); |
| 249 |
return false; |
| 250 |
} |
| 251 |
|
| 252 |
public function delete_for_all_active_boards( $where = [] ) { |
| 253 |
if ( $boardids = WPF()->board->get_active_boardids() ) { |
| 254 |
foreach ( $boardids as $boardid ) { |
| 255 |
WPF()->change_board( $boardid ); |
| 256 |
$this->delete( $where ); |
| 257 |
} |
| 258 |
} |
| 259 |
} |
| 260 |
|
| 261 |
/** |
| 262 |
* @param $args array|string |
| 263 |
* @param $operator string |
| 264 |
* |
| 265 |
* @return array |
| 266 |
*/ |
| 267 |
function get_subscribe( $args, $operator = 'AND' ) { |
| 268 |
if( is_string( $args ) ) $args = [ "confirmkey" => sanitize_text_field( $args ) ]; |
| 269 |
|
| 270 |
$operator = strtoupper( (string) $operator ); |
| 271 |
if( ! in_array( $operator, [ 'AND', 'OR' ], true ) ) $operator = 'AND'; |
| 272 |
|
| 273 |
$default = [ |
| 274 |
'subid' => null, |
| 275 |
'itemid' => null, |
| 276 |
'type' => null, |
| 277 |
'confirmkey' => null, |
| 278 |
'userid' => null, |
| 279 |
'user_email' => null, |
| 280 |
'active' => null, |
| 281 |
'order' => '`subid` DESC', |
| 282 |
'offset' => null, |
| 283 |
'row_count' => null, |
| 284 |
]; |
| 285 |
|
| 286 |
$args = array_merge( $default, $args ); |
| 287 |
|
| 288 |
$sql = "SELECT * FROM `" . WPF()->tables->subscribes . "`"; |
| 289 |
|
| 290 |
$wheres = []; |
| 291 |
if( ! is_null( $args['subid'] ) ) $wheres[] = "`subid` = " . wpforo_bigintval( $args['subid'] ); |
| 292 |
if( ! is_null( $args['itemid'] ) ) $wheres[] = "`itemid` = " . wpforo_bigintval( $args['itemid'] ); |
| 293 |
if( ! is_null( $args['userid'] ) ) $wheres[] = "`userid` = " . wpforo_bigintval( $args['userid'] ); |
| 294 |
if( ! wpforo_bigintval( $args['userid'] ) |
| 295 |
&& ! is_null( $args['user_email'] ) ) $wheres[] = "`user_email` = '" . esc_sql( $args['user_email'] ) . "'"; |
| 296 |
if( ! is_null( $args['confirmkey'] ) ) $wheres[] = "`confirmkey` = '" . esc_sql( $args['confirmkey'] ) . "'"; |
| 297 |
if( ! is_null( $args['active'] ) ) $wheres[] = "`active` = " . intval( $args['active'] ); |
| 298 |
if( ! is_null( $args['type'] ) ) $wheres[] = "`type` IN( '" . implode( "','", array_map( 'esc_sql', (array) $args['type'] ) ) . "' )"; |
| 299 |
|
| 300 |
if( $wheres ) $sql .= sprintf( ' WHERE %1$s', implode( sprintf(' %1$s ', $operator), $wheres ) ); |
| 301 |
if( (int) $args['row_count'] ) $sql .= sprintf( ' LIMIT %1$d,%2$d', intval( $args['offset'] ), intval( $args['row_count'] ) ); |
| 302 |
|
| 303 |
if( WPF()->ram_cache->exists( $sql ) ) { |
| 304 |
$subscribe = WPF()->ram_cache->get( $sql ); |
| 305 |
} else { |
| 306 |
$subscribe = (array) WPF()->db->get_row( $sql, ARRAY_A ); |
| 307 |
WPF()->ram_cache->set( $sql, $subscribe ); |
| 308 |
} |
| 309 |
|
| 310 |
return $subscribe; |
| 311 |
} |
| 312 |
|
| 313 |
function get_subscribes( $args = [], &$items_count = 0 ) { |
| 314 |
$default = [ |
| 315 |
'itemid' => null, |
| 316 |
'type' => [], // topic | forum |
| 317 |
'userid' => null, // |
| 318 |
'active' => 1, |
| 319 |
'orderby' => 'subid', // order by `field` |
| 320 |
'order' => 'DESC', // ASC DESC |
| 321 |
'offset' => null, // OFFSET |
| 322 |
'row_count' => null, // ROW COUNT |
| 323 |
]; |
| 324 |
|
| 325 |
$args = wpforo_parse_args( $args, $default ); |
| 326 |
extract( $args ); |
| 327 |
|
| 328 |
$sql = "SELECT * FROM `" . WPF()->tables->subscribes . "`"; |
| 329 |
$wheres = []; |
| 330 |
|
| 331 |
if( $type ) $wheres[] = " `type` IN( '" . implode( "','", array_map( 'esc_sql', (array) $type ) ) . "')"; |
| 332 |
if( ! is_null( $active ) ) $wheres[] = " `active` = " . intval( $active ); |
| 333 |
if( ! is_null( $itemid ) ) $wheres[] = " `itemid` = " . wpforo_bigintval( $itemid ); |
| 334 |
if( ! is_null( $userid ) ) $wheres[] = " `userid` = " . wpforo_bigintval( $userid ); |
| 335 |
|
| 336 |
if( ! empty( $wheres ) ) $sql .= " WHERE " . implode( " AND ", $wheres ); |
| 337 |
|
| 338 |
$item_count_sql = preg_replace( '#SELECT.+?FROM#isu', 'SELECT count(*) FROM', $sql ); |
| 339 |
if( $item_count_sql ) $items_count = WPF()->db->get_var( $item_count_sql ); |
| 340 |
|
| 341 |
$sql .= " ORDER BY `$orderby` " . $order; |
| 342 |
|
| 343 |
if( ! is_null( $row_count ) ) { |
| 344 |
if( ! is_null( $offset ) ) { |
| 345 |
$sql .= esc_sql( " LIMIT $offset,$row_count" ); |
| 346 |
} else { |
| 347 |
$sql .= esc_sql( " LIMIT $row_count" ); |
| 348 |
} |
| 349 |
} |
| 350 |
|
| 351 |
return WPF()->db->get_results( $sql, ARRAY_A ); |
| 352 |
|
| 353 |
} |
| 354 |
|
| 355 |
function get_confirm_link( $args ) { |
| 356 |
if( is_string( $args ) ) return wpforo_home_url( "?wpfaction=sbscrbconfirm&key=" . sanitize_text_field( $args ) ); |
| 357 |
|
| 358 |
if( $args['type'] === 'forum' ) { |
| 359 |
$url = WPF()->forum->get_forum_url( $args['itemid'] ) . '/'; |
| 360 |
} elseif( $args['type'] === 'topic' ) { |
| 361 |
$url = WPF()->topic->get_url( $args['itemid'] ) . '/'; |
| 362 |
} else { |
| 363 |
$url = wpforo_home_url(); |
| 364 |
} |
| 365 |
|
| 366 |
return wpforo_home_url( $url . "?wpfaction=sbscrbconfirm&key=" . sanitize_text_field( $args['confirmkey'] ) ); |
| 367 |
} |
| 368 |
|
| 369 |
function get_unsubscribe_link( $confirmkey ) { |
| 370 |
return wpforo_home_url( "?wpfaction=unsbscrb&key=" . sanitize_text_field( $confirmkey ) ); |
| 371 |
} |
| 372 |
|
| 373 |
public function is_email_confirmed( $user = null ) { |
| 374 |
if( ! $user && ! WPF()->current_userid && ! WPF()->current_user_email ) return false; |
| 375 |
if( ! $user ) $user = ( WPF()->current_userid ? WPF()->current_userid : WPF()->current_user_email ); |
| 376 |
|
| 377 |
$sql = ( is_numeric( $user ) ? "`userid` = %d" : "`user_email` = %s" ); |
| 378 |
$where = WPF()->db->prepare( $sql, $user ); |
| 379 |
|
| 380 |
if( WPF()->current_userid === $user && wpfval( WPF()->current_user, 'is_email_confirmed' ) ) { |
| 381 |
$has_confirmed = WPF()->current_user['is_email_confirmed']; |
| 382 |
} elseif( is_numeric( $user ) ) { |
| 383 |
$has_confirmed = WPF()->member->get_is_email_confirmed( WPF()->current_userid ); |
| 384 |
} else { |
| 385 |
$has_confirmed = WPF()->db->get_var( "SELECT `subid` FROM `" . WPF()->tables->subscribes . "` WHERE `active` = 1 AND " . $where ); |
| 386 |
} |
| 387 |
|
| 388 |
return (bool) $has_confirmed; |
| 389 |
} |
| 390 |
|
| 391 |
public function get_sbj_msg( $type, $pitem, $item, $owner, $user, $unsubscribe_link ){ |
| 392 |
$sbj = ''; |
| 393 |
$msg = ''; |
| 394 |
switch( $type ){ |
| 395 |
case 'new_topic': |
| 396 |
$sbj = wpforo_setting( 'subscriptions', 'new_topic_notification_email_subject' ); |
| 397 |
$msg = wpforo_setting( 'subscriptions', 'new_topic_notification_email_message' ); |
| 398 |
if( (int) $item['status'] ) { |
| 399 |
$sbj = __( 'Please Moderate: ', 'wpforo' ) . $sbj; |
| 400 |
$msg .= sprintf( '<br><br><p style="color: #DD0000;">%1$s</p>', __( 'This topic is currently unapproved. You can approve topics in Dashboard » Forums » Moderation admin page.', 'wpforo' ) ); |
| 401 |
} |
| 402 |
break; |
| 403 |
case 'new_post': |
| 404 |
$sbj = wpforo_setting( 'subscriptions', 'new_post_notification_email_subject' ); |
| 405 |
$msg = wpforo_setting( 'subscriptions', 'new_post_notification_email_message' ); |
| 406 |
if( (int) $item['status'] ) { |
| 407 |
$sbj = __( 'Please Moderate: ', 'wpforo' ) . $sbj; |
| 408 |
$msg .= sprintf( '<br><br><p style="color: #DD0000;">%1$s</p>', __( 'This post is currently unapproved. You can approve posts in Dashboard » Forums » Moderation admin page.', 'wpforo' ) ); |
| 409 |
} |
| 410 |
break; |
| 411 |
case 'user_follow'; |
| 412 |
$sbj = wpforo_setting( 'subscriptions', 'user_following_email_subject' ); |
| 413 |
$msg = wpforo_setting( 'subscriptions', 'user_following_email_message' ); |
| 414 |
break; |
| 415 |
case 'user_mention'; |
| 416 |
$sbj = wpforo_setting( 'subscriptions', 'user_mention_email_subject' ); |
| 417 |
$msg = wpforo_setting( 'subscriptions', 'user_mention_email_message' ); |
| 418 |
break; |
| 419 |
} |
| 420 |
|
| 421 |
$sbj = wpforo_apply_email_shortcodes( $sbj, $pitem, $item, $owner, $user, $unsubscribe_link ); |
| 422 |
$msg = wpforo_apply_email_shortcodes( $msg, $pitem, $item, $owner, $user, $unsubscribe_link ); |
| 423 |
|
| 424 |
return compact( 'sbj', 'msg' ); |
| 425 |
} |
| 426 |
} |
| 427 |
|