Seditio Source
Root |
./othercms/b2evolution_7.2.3/inc/cron/jobs/_post_moderation_reminder.job.php
<?php
/**
 * This file implements the posts moderation reminder cron job
 *
 * @author yura: Yura Bakhtin
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );

global
$DB, $Settings, $UserSettings;

global
$servertimenow;

// Check if UserSettings exists because it must be initialized before email sending
if( empty( $UserSettings ) )
{
// initialize UserSettings, because in CLI mode is not initialized yet
   
load_class( 'users/model/_usersettings.class.php', 'UserSettings' );
   
$UserSettings = new UserSettings();
}

// Only those blogs are selected for moderation where we can find at least one post awaiting moderation which is older then the threshold date defined below
$threshold_date = date2mysql( $servertimenow - $Settings->get( 'post_moderation_reminder_threshold' ) );

// Statuses defined in this array should be notified. This should be configurable, but this is the default value.
$notify_statuses = get_visibility_statuses( 'moderation' );

// Select blogs where are posts awaiting moderation more then x ( = configured threshold ) hours
$SQL = new SQL();
$SQL->SELECT( 'DISTINCT cat_blog_ID' );
$SQL->FROM( 'T_categories' );
$SQL->FROM_add( 'INNER JOIN T_items__item ON post_main_cat_ID = cat_ID' );
$SQL->WHERE( 'post_status IN ('.$DB->quote( $notify_statuses ).')' );
$SQL->WHERE_and( 'post_datecreated < '.$DB->quote( $threshold_date ) );

$moderation_blogs = $DB->get_col( $SQL->get() );

if( empty(
$moderation_blogs ) )
{
// There are no blogs where exists draft posts older then the threshold ( 24 hours by default )
   
cron_log_append( sprintf( 'No posts have been awaiting moderation for more than %s.', seconds_to_period( $Settings->get( 'post_moderation_reminder_threshold' ) ) ) );
    return
1;
}

$moderation_blogs_cond = '%s IN ( '.implode( ',', $moderation_blogs ).' )';

// Select global moderators
$SQL = new SQL();
$SQL->SELECT( 'user_ID' );
$SQL->FROM( 'T_users' );
$SQL->FROM_add( 'LEFT JOIN T_groups ON grp_ID = user_grp_ID' );
$SQL->WHERE( 'grp_perm_blogs = '.$DB->quote( 'editall' ) );

$global_moderators = $DB->get_col( $SQL->get() );
$not_global_moderator = ( count( $global_moderators ) ) ? '%s NOT IN ( '.implode( ',', $global_moderators ).' )' : NULL;

// Select blog owners, because they are moderators in their own blogs
$SQL = new SQL();
$SQL->SELECT( 'blog_owner_user_ID, GROUP_CONCAT( DISTINCT cast(blog_ID as CHAR) ORDER BY blog_ID SEPARATOR \',\') as blogs' );
$SQL->FROM( 'T_blogs' );
$SQL->WHERE( sprintf( $not_global_moderator, 'blog_owner_user_ID' ) );
$SQL->WHERE_and( sprintf( $moderation_blogs_cond, 'blog_ID' ) );
$SQL->GROUP_BY( 'blog_owner_user_ID' );
// Get blog owner users with their blogs
$blog_owners = $DB->get_assoc( $SQL->get() );

// Select post moderators based on the blogs advanced user permissions
$bloguser_SQL = new SQL();
$bloguser_SQL->SELECT( 'bloguser_user_ID as user_ID, bloguser_blog_ID as blog_ID, bloguser_perm_poststatuses + 0 as perm_poststatuses, bloguser_perm_edit as perm_edit, bloguser_perm_edit + 0 AS perm_edit_num' );
$bloguser_SQL->FROM( 'T_coll_user_perms' );
$bloguser_SQL->FROM_add( 'LEFT JOIN T_blogs ON blog_ID = bloguser_blog_ID' );
$bloguser_SQL->WHERE( sprintf( $not_global_moderator, 'bloguser_user_ID' ) );
$bloguser_SQL->WHERE_and( 'blog_advanced_perms <> 0' );
$bloguser_SQL->WHERE_and( sprintf( $moderation_blogs_cond, 'bloguser_blog_ID' ) );
$bloguser_SQL->WHERE_and( 'bloguser_perm_poststatuses <> "" AND bloguser_perm_edit <> "no" AND bloguser_perm_edit <> "own"' );
// Select post moderators based on the blogs advanced group permissions
$bloggroup_SQL = new  SQL();
$bloggroup_SQL->SELECT( 'user_ID, bloggroup_blog_ID as blog_ID, bloggroup_perm_poststatuses + 0 as perm_poststatuses, bloggroup_perm_edit as perm_edit, bloggroup_perm_edit + 0 AS perm_edit_num' );
$bloggroup_SQL->FROM( 'T_users' );
$bloggroup_SQL->FROM_add( 'LEFT JOIN T_coll_group_perms ON ( bloggroup_group_ID = user_grp_ID
    OR bloggroup_group_ID IN ( SELECT sug_grp_ID FROM T_users__secondary_user_groups WHERE sug_user_ID = user_ID ) )'
);
$bloggroup_SQL->FROM_add( 'LEFT JOIN T_blogs ON blog_ID = bloggroup_blog_ID' );
$bloggroup_SQL->WHERE( sprintf( $not_global_moderator, 'user_ID' ) );
$bloggroup_SQL->WHERE_and( 'blog_advanced_perms <> 0' );
$bloggroup_SQL->WHERE_and( sprintf( $moderation_blogs_cond, 'bloggroup_blog_ID' ) );
$bloggroup_SQL->WHERE_and( 'bloggroup_perm_poststatuses <> "" AND bloggroup_perm_edit <> "no" AND bloggroup_perm_edit <> "own"' );
// Get specific moderator users with their permissions in each different blog
$specific_blog_moderators = $DB->get_results( '( '.$bloguser_SQL->get().' ) UNION ( '.$bloggroup_SQL->get().' ) ORDER BY user_ID, blog_ID' );

// Highest edit level
$max_perm_edit = 'all';
// Highest value of the post statuses perm
$max_perm_statuses = 127;
// Create a general moderators array to collect all blog owners and different blog moderators
$moderators = array();
foreach(
$specific_blog_moderators as $row )
{
// Loop through each different blog's moderator users and their permissions
   
if( !isset( $moderators[$row->user_ID] ) )
    {
// Initialize user perm array
       
$moderators[$row->user_ID] = array();
    }
    if( isset(
$moderators[$row->user_ID][$row->blog_ID] ) )
    {    
// Update user permissions on this collection:
        // perm_edit    : 'no', 'own', 'lt', 'le', 'all' (real value from DB)
        // perm_edit_num:  1,    2,     3,    4,    5    (index of the value from DB)
       
if( $moderators[$row->user_ID][$row->blog_ID]['perm_edit_num'] < $row->perm_edit_num )
        {    
// The user and the group advanced post edit perm for this user are not the same, keep the higher perm value:
           
$moderators[$row->user_ID][$row->blog_ID]['perm_edit_num'] = intval( $row->perm_edit_num );
           
$moderators[$row->user_ID][$row->blog_ID]['perm_edit'] = $row->perm_edit;
        }
       
$current_perm_statuses = $moderators[$row->user_ID][$row->blog_ID]['perm_statuses'];
       
$row_perm_status = intval( $row->perm_poststatuses );
        if(
$current_perm_statuses != $row_perm_status )
        {
// The advanced user and the group post statuses perm for this user are not the same, the union of this perms must be accepted
           
$moderators[$row->user_ID][$row->blog_ID]['perm_statuses'] = ( $current_perm_statuses | $row_perm_status );
        }
    }
    else
    {    
// Initialize a new setting for the moderator per collection:
       
$moderators[$row->user_ID][$row->blog_ID] = array(
               
'perm_edit'     => $row->perm_edit,
               
'perm_edit_num' => intval( $row->perm_edit_num ),
               
'perm_statuses' => intval( $row->perm_poststatuses ),
            );
    }
}
foreach(
$blog_owners as $moderator_ID => $moderator_blogs )
{
// Loop through each blog owner users and set the highest permission in their own blogs
   
$blogs = explode( ',', $moderator_blogs );
    foreach(
$blogs as $blog_ID )
    {
// Loop through each blogs of this user
       
if( !isset( $moderators[$moderator_ID] ) )
        {
// Init this user moderator perms if it was not initialized yet
           
$moderators[$moderator_ID] = array();
        }
       
$moderators[$moderator_ID][$blog_ID] = array( 'perm_edit' => $max_perm_edit, 'perm_statuses' => $max_perm_statuses );
    }
}

// Set notify moderation condition
$def_send_moderation_reminder = $UserSettings->get_default( 'send_pst_moderation_reminder' );
if(
$def_send_moderation_reminder )
{
// Send post moderation reminder is set by default
   
$send_moderation_reminder_cond = '( ( uset_value IS NOT NULL AND uset_value <> \'0\' ) OR ( uset_value IS NULL ) )';
}
else
{
// Send post moderation reminder is NOT set by default
   
$send_moderation_reminder_cond = '( uset_value IS NOT NULL AND uset_value <> \'0\' )';
}

// Select blocked and spam email addresses to prevent sending emails to them
$blocked_emails = $DB->get_col( 'SELECT emadr_address FROM T_email__address WHERE '.get_mail_blocked_condition() );
$blocked_emails_condition = ( count( $blocked_emails ) ) ? 'user_email NOT IN ( "'.implode( '","', $blocked_emails ).'" )' : NULL;

// load all required Users ( global moderators, blog owners and users with advanced blog perms )
$all_required_users = array_unique( array_merge( $global_moderators, array_keys( $moderators ) ) );
$SQL = new SQL();
$SQL->SELECT( 'T_users.*' );
$SQL->FROM( 'T_users' );
$SQL->FROM_add( 'LEFT JOIN T_users__usersettings ON uset_user_ID = user_ID AND uset_name = "send_pst_moderation_reminder"' );
$SQL->WHERE( 'user_ID IN ('.implode( ',', $all_required_users ).')' );
$SQL->WHERE_and( 'user_status IN ( "activated", "autoactivated", "manualactivated" )' );
$SQL->WHERE_and( $send_moderation_reminder_cond );
$SQL->WHERE_and( 'LENGTH(TRIM(user_email)) > 0' );
$SQL->WHERE_and( $blocked_emails_condition );

// Load moderator users who would like to get notificaions
$UserCache = & get_UserCache();
$UserCache->clear( true );
$UserCache->load_by_sql( $SQL );
$loaded_ids = $UserCache->get_ID_array();

if( empty(
$loaded_ids ) )
{
// UserCache result is empty which means nobody wants to receive notifications
   
cron_log_append( 'Could not find any moderators wanting to receive post moderation notifications for the blogs that have posts pending moderation!' );
    return
1;
}

// load all required Blogs
$BlogCache = & get_BlogCache();
$BlogCache->load_list( $moderation_blogs );

// count all posts awaiting for moderation in the required blogs, group by blog/post_status/author_level
$SQL = new SQL();
$SQL->SELECT( 'cat_blog_ID as blog_ID, post_status, user_level as author_level, count( post_ID ) as post_count' );
$SQL->FROM( 'T_items__item' );
$SQL->FROM_add( 'LEFT JOIN T_users ON user_ID = post_creator_user_ID' );
$SQL->FROM_add( 'LEFT JOIN T_categories ON cat_ID = post_main_cat_ID' );
$SQL->WHERE( 'post_status IN ( '.$DB->quote( $notify_statuses ).' )' );
$SQL->WHERE_and( 'cat_blog_ID IN ('.implode( ',', $moderation_blogs ).')' );
$SQL->GROUP_BY( 'cat_blog_ID, post_status, author_level' );
$blog_posts = $DB->get_results( $SQL->get() );

// Create a posts map by blog_ID:post_status:author_level:count. This way it will be much easier to get allowed posts for a specific permission
$posts_map = array();
$last_blog_ID = NULL;
foreach(
$blog_posts as $row )
{
    if(
$last_blog_ID != $row->blog_ID )
    {
       
$Collection = $Blog = & $BlogCache->get_by_ID( $row->blog_ID );
       
$blog_moderation_statuses = $Blog->get_setting( 'post_moderation_statuses' );
       
$last_blog_ID = $row->blog_ID;
    }
    if(
strpos( $blog_moderation_statuses, $row->post_status ) === false )
    {
// This status shouldn't be notified on this blog
       
continue;
    }
    if( isset(
$posts_map[$row->blog_ID] ) )
    {
// This blog posts were already initialized
       
if( isset( $posts_map[$row->blog_ID][$row->post_status] ) )
        {
// Comments with this status were already initialized
            // Set new author level filter for this status and the corresponding amount of posts
           
$posts_map[$row->blog_ID][$row->post_status][$row->author_level] = $row->post_count;
        }
        else
        {
// Initialize blog posts with this status, and set the first element
           
$posts_map[$row->blog_ID][$row->post_status] = array( $row->author_level => $row->post_count );
        }
    }
    else
    {
// Initialize blog array, and set the first element
       
$posts_map[$row->blog_ID] = array( $row->post_status => array( $row->author_level => $row->post_count ) );
    }
}

$mail_sent = 0;
$mail_failed = 0;
$params = array();

// Collect posts data for global moderators
$moderator_posts = array();
foreach(
$moderation_blogs as $blog_ID )
{
// Collect the number of posts from all blogs
   
if( !isset( $posts_map[$blog_ID] ) )
    {
// this blog doesn't contains posts awaiting moderation which statuses corresponds to this blog moderation statutes
       
continue;
    }
   
$post_count = 0;
    foreach(
$posts_map[$blog_ID] as $status => $content )
    {
// collect the number of posts with all statuses
       
foreach( $content as $level => $count )
        {
// collect the number of posts with all kind of users
           
$post_count += $count;
        }
    }
   
$moderator_posts[$blog_ID] = $post_count;
}

foreach(
$loaded_ids as $moderator_ID )
{
// Loop trhough each moderators and send post moderation emails if it is required
   
$moderator_User = $UserCache->get_by_ID( $moderator_ID );
   
$blog_posts = array();
    if(
in_array( $moderator_ID, $global_moderators ) )
    {
// This is a global moderator user
       
$blog_posts = $moderator_posts;
    }
    else
    {
// This moderator user may have different permission on different blogs, collect the posts corresponding to the perms
       
foreach( $moderators[$moderator_ID] as $blog_ID => $perms )
        {
            if( !isset(
$posts_map[$blog_ID] ) )
            {
// this blog doesn't contains posts awaiting moderation which statuses corresponds to this blog moderation statutes
               
continue;
            }
           
$post_count = 0;
            foreach(
$posts_map[$blog_ID] as $status => $content )
            {
               
$status_perm_value = get_status_permvalue( $status );
                if(
$perms['perm_statuses'] & $status_perm_value )
                {
// User has permission to edit posts with this status
                    // TODO asimo> Here probably we should also check if user is able to deprecate/recycle the post.
                    // Check if User has permission to raise post status
                   
$ordered_statuses = get_visibility_statuses( 'ordered-index' );
                   
$raise_status_allowed = false;
                   
$current_status_found = false;
                    foreach(
$ordered_statuses as $ordered_status => $order_index )
                    {
                        if(
$ordered_status == $status )
                        {
                           
$current_status_found = true;
                        }
                        elseif(
$current_status_found  && ( $order_index !== 0 ) )
                        {
// This is a higher status then the currently checked status
                           
$ordered_status_perm_value = get_status_permvalue( $ordered_status );
                            if(
$perms['perm_statuses'] & $ordered_status_perm_value )
                            {
// User has permission to a higher status, so the post status can be raised
                               
$raise_status_allowed = true;
                                break;
                            }
                        }
                    }
                    if( !
$raise_status_allowed )
                    {
// User is not allowed to raise these post statuses
                       
continue;
                    }
                   
// Check if the post author level allows the edit permission:
                   
foreach( $content as $level => $count )
                    {
                        switch(
$perms['perm_edit'] )
                        {
                            case
'all':
                               
$allowed = true;
                                break;
                            case
'le':
                               
$allowed = ( $level <= $moderator_User->level );
                                break;
                            case
'lt':
                               
$allowed = ( $level < $moderator_User->level );
                                break;
                            case
'anon':
                               
$allowed = ( $level == 0 );
                                break;
                            default:
                               
$allowed = false;
                        }
                        if(
$allowed )
                        {
// User has permission to edit posts with this author level
                           
$post_count += $count;
                        }
                    }
                }
            }
            if(
$post_count > 0 )
            {
// There are posts awaiting moderation on this blog and user has permission to moderate
               
$blog_posts[$blog_ID] = $post_count;
            }
        }
    }

    if( empty(
$blog_posts ) )
    {
// There are no posts awaiting moderation that this user could moderate
       
continue;
    }

   
$params['blogs'] = array_keys( $blog_posts ); // This can be remvoved if this solution will remain
   
$params['posts'] = $blog_posts;

   
// Change locale here to localize the email subject and content
   
locale_temp_switch( $moderator_User->get( 'locale' ) );
    if(
send_mail_to_User( $moderator_ID, T_( 'Post moderation reminder' ), 'posts_unmoderated_reminder', $params, false ) )
    {    
// Log success mail sending:
       
cron_log_action_end( 'User '.$moderator_User->get_identity_link().' has been notified' );
       
$mail_sent++;
    }
    else
    {    
// Log failed mail sending:
       
global $mail_log_message;
       
cron_log_action_end( 'User '.$moderator_User->get_identity_link().' could not be notified because of error: '
           
.'"'.( empty( $mail_log_message ) ? 'Unknown Error' : $mail_log_message ).'"', 'warning' );
       
$mail_failed++;
    }
   
locale_restore_previous();
}

cron_log_append( ( ( $mail_sent + $mail_failed ) ? "\n" : '' ).sprintf( '%d of %d moderators have been notified!', $mail_sent, ( $mail_sent + $mail_failed ) ) );
return
1; /*OK*/
?>