<?php
/**
* This is the handler for asynchronous 'AJAX' calls. This requires access to the back office.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* fp> TODO: it would be better to have the code for the actions below part of the controllers they belong to.
* This would require some refectoring but would be better for maintenance and code clarity.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
*
* @package evocore
*/
/**
* Do the MAIN initializations:
*/
require_once dirname(__FILE__).'/../conf/_config.php';
/**
* @global boolean Is this AJAX request? Use {@link is_ajax_request()} to query it, because it may change.
*/
$is_ajax_request = true;
/**
* HEAVY :(
*
* @todo dh> refactor _main.inc.php to be able to include small parts
* (e.g. $current_User, charset init, ...) only..
* It worked already for $DB (_connect_db.inc.php).
* fp> I think I'll try _core_main.inc , _evo_main.inc , _blog_main.inc ; this file would only need _core_main.inc
*/
require_once $inc_path.'_main.inc.php';
// create global $blog variable
global $blog;
// Init $blog with NULL to avoid injections, it will get the correct value from param where it is required
$blog = NULL;
param( 'action', 'string', '' );
// Check global permission:
if( $action != 'test_api' && ! check_user_perm( 'admin', 'restricted' ) )
{ // No permission to access admin... (Exclude action of API testing in order to make a quick request without logging in)
require $adminskins_path.'_access_denied.main.php';
}
// Send the predefined cookies:
evo_sendcookies();
// Make sure the async responses are never cached:
header_nocache();
header_content_type( 'text/html', $io_charset );
// Save current debug values
$current_debug = $debug;
$current_debug_jslog = $debug_jslog;
// Do not append Debuglog to response!
$debug = false;
// Do not append Debug JSlog to response!
$debug_jslog = false;
// Don't check new updates from b2evolution.net (@see b2evonet_get_updates()),
// in order to don't break the response data:
$allow_evo_stats = false;
// Init AJAX log
$ajax_Log = new Log();
ajax_log_add( sprintf( T_('action: %s'), $action ), 'note' );
$incorrect_action = false;
$add_response_end_comment = true;
// fp> Does the following have an HTTP fallback when Javascript/AJ is not available?
// dh> yes, but not through this file..
// dh> IMHO it does not make sense to let the "normal controller" handle the AJAX call
// if there's something lightweight like calling "$UserSettings->param_Request()"!
// Hmm.. bad example (but valid). Better example: something like the actions below, which
// output only a small part of what the "real controller" does..
switch( $action )
{
case 'get_whois_info':
param( 'query', 'string' );
param( 'window_height', 'integer' );
load_funcs( 'antispam/model/_antispam.funcs.php' );
echo antispam_get_whois( $query, $window_height );
break;
case 'add_plugin_sett_set':
// Dislay a new Plugin(User)Settings set ( it's used only from plugins with "array" type settings):
// This does not require CSRF because it doesn't update the db, it only displays a new block of empty plugin setting fields
// Check permission to view plugin settings:
check_user_perm( 'options', 'view', true );
// Set admin skin, used for buttons, @see button_class()
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
param( 'plugin_ID', 'integer', true );
param( 'set_type', 'string', '' ); // 'Settings', 'UserSettings', 'CollSettings', 'MsgSettings', 'EmailSettings', 'Skin', 'Widget'
if( ! in_array( $set_type, array( 'Settings', 'UserSettings', 'CollSettings', 'MsgSettings', 'EmailSettings', 'Skin', 'Widget' ) ) )
{
bad_request_die( 'Invalid set_type param!' );
}
param( 'blog', 'integer', 0 );
$BlogCache = & get_BlogCache();
$Blog = & $BlogCache->get_by_ID( $blog, false, false );
$target_Object = NULL;
switch( $set_type )
{
case 'Widget':
$WidgetCache = & get_WidgetCache();
$Widget = & $WidgetCache->get_by_ID( $plugin_ID );
if( ( $Plugin = & $Widget->get_Plugin() ) )
{ // Set abstract type for Widget initialized from Plugin:
$set_type = 'PluginWidget';
}
else
{ // This is a normal Widget:
$Plugin = $Widget;
}
$plugin_Object = $Widget;
break;
case 'Skin':
$SkinCache = & get_SkinCache();
$Skin = & $SkinCache->get_by_ID( $plugin_ID );
$Plugin = $Skin;
$plugin_Object = $Skin;
break;
default:
// 'Settings', 'UserSettings', 'CollSettings', 'MsgSettings', 'EmailSettings'
$admin_Plugins = & get_Plugins_admin(); // use Plugins_admin, because a plugin might be disabled
$Plugin = & $admin_Plugins->get_by_ID( $plugin_ID );
$plugin_Object = $Plugin;
if( $set_type == 'UserSettings' )
{ // Initialize User object for this plugin type:
param( 'user_ID', 'integer', true );
$UserCache = & get_UserCache();
$target_Object = & $UserCache->get_by_ID( $user_ID );
}
break;
}
if( ! $Plugin )
{
bad_request_die('Invalid Plugin.');
}
param( 'param_name', 'string', '' );
param( 'param_num', 'integer', '' );
$set_path = $param_name.'['.$param_num.']';
load_funcs('plugins/_plugin.funcs.php');
// Init the new setting set:
$set_node = _set_setting_by_path( $Plugin, $set_type, $set_path, array() );
// Get the new plugin setting set and display it with a fake Form
$r = get_plugin_settings_node_by_path( $Plugin, $set_type, $set_path, /* create: */ false );
$Form = new Form(); // fake Form to display plugin setting
autoform_display_field( $set_path, $r['set_meta'], $Form, $set_type, $plugin_Object, $target_Object, $set_node );
break;
case 'edit_comment':
// Used to edit a comment from back-office (Note: Only for internal comments now!)
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'comment' );
$comment_ID = param( 'commentid', 'integer' );
// Get Comment by ID
$CommentCache = & get_CommentCache();
$edited_Comment = & $CommentCache->get_by_ID( $comment_ID );
// Load Item
$edited_Comment_Item = & $edited_Comment->get_Item();
// Check user permission to edit this internal comment
check_user_perm( 'meta_comment', 'edit', true, $edited_Comment );
// Load Blog of the Item
$Collection = $Blog = & $edited_Comment_Item->get_Blog();
$comment_action = param( 'comment_action', 'string' );
switch( $comment_action )
{
case 'form':
// Display a form to change a content of the Comment
$comment_title = '';
$comment_content = htmlspecialchars_decode( $edited_Comment->content );
// Format content for editing, if we were not already in editing...
$Plugins_admin = & get_Plugins_admin();
$params = array( 'object_type' => 'Comment', 'object_Blog' => & $Blog );
$Plugins_admin->unfilter_contents( $comment_title /* by ref */, $comment_content /* by ref */, $edited_Comment_Item->get_renderers_validated(), $params );
// Display <textarea> to change a content
$rows_approx = round( strlen( $comment_content ) / 200 );
$rows_number = substr_count( $comment_content, "\n" );
$rows_number = ( ( $rows_number > 3 && $rows_number > $rows_approx ) ? $rows_number : $rows_approx ) + 2;
echo '<textarea class="form_textarea_input form-control'.( check_autocomplete_usernames( $edited_Comment ) ? ' autocomplete_usernames' : '' ).'" rows="'.$rows_number.'">'.$comment_content.'</textarea>';
// Display a button to Save the changes
echo '<input type="button" value="'.T_('Save Changes!').'" class="SaveButton btn btn-primary" onclick="edit_comment( \'update\', '.$edited_Comment->ID.' )" /> ';
// Display a button to Cancel the changes
echo '<input type="button" value="'.T_('Cancel').'" class="ResetButton btn btn-danger" onclick="edit_comment( \'cancel\', '.$edited_Comment->ID.' )" />';
break;
case 'update':
// Save the changed content
if( $Blog->get_setting( 'allow_html_comment' ) )
{ // HTML is allowed for this comment
$text_format = 'html';
}
else
{ // HTML is disallowed for this comment
$text_format = 'htmlspecialchars';
}
$comment_content = param( 'comment_content', $text_format );
// Trigger event: a Plugin could add a $category="error" message here..
// This must get triggered before any internal validation and must pass all relevant params.
// The OpenID plugin will validate a given OpenID here (via redirect and coming back here).
$Plugins->trigger_event( 'CommentFormSent', array(
'dont_remove_pre' => true,
'comment_item_ID' => $edited_Comment_Item->ID,
'comment' => & $comment_content,
'renderers' => $edited_Comment->get_renderers_validated(),
) );
// Update the content
$edited_Comment->set( 'content', $comment_content );
$edited_Comment->dbupdate();
// Display new content
$edited_Comment->content( 'htmlbody', 'true' );
break;
case 'cancel':
// The changes were canceled, Display old content
$edited_Comment->content( 'htmlbody', 'true' );
break;
}
break;
case 'get_opentrash_link':
// Used to get a link 'Open recycle bin' in order to show it in the header of comments list
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'comment' );
// Set admin skin, used for buttons, @see button_class()
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
param( 'blog', 'integer', 0 );
echo get_opentrash_link( true, true, array(
'before' => ' <span id="recycle_bin">',
'after' => '</span>',
'class' => 'btn btn-default'.( param( 'request_from', 'string' ) == 'items' ? '' : ' btn-sm' ),
) );
break;
case 'delete_comment':
// Delete a comment from the list on dashboard, on comments full text view screen or on a view item screen
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'comment' );
$result_success = false;
// Set admin skin, used for buttons, @see button_class()
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
// Check comment moderate permission below after we have the $edited_Comment objects
$is_admin_page = true;
$blog = param( 'blogid', 'integer' );
$comment_ID = param( 'commentid', 'integer' );
$statuses = param( 'statuses', 'string', NULL );
$expiry_status = param( 'expiry_status', 'string', 'active' );
$item_ID = param( 'itemid', 'integer' );
$currentpage = param( 'currentpage', 'integer', 1 );
$limit = param( 'limit', 'integer', 0 );
$request_from = param( 'request_from', 'string', NULL );
$comment_type = param( 'comment_type', 'string', 'feedback' );
$edited_Comment = & Comment_get_by_ID( $comment_ID, false );
if( $edited_Comment !== false )
{ // The comment still exists
// Check permission:
check_user_perm( 'comment!CURSTATUS', 'delete', true, $edited_Comment );
$result_success = $edited_Comment->dbdelete();
}
if( $result_success === false )
{ // Some errors on deleting of the comment, Exit here
header_http_response( '500 '.T_('Comment cannot be deleted!'), 500 );
exit(0);
}
if( in_array( $request_from, array( 'items', 'comments' ) ) )
{ // AJAX request goes from backoffice and ctrl = items or comments:
// In case of comments_fullview we must set a filterset name to be abble to restore filterset.
// If $item_ID is not valid, then this requests came from the comments_fullview
// TODO: asimo> This should be handled with a better solution
$filterset_name = /*'';*/( $item_ID > 0 ) ? '' : ( $comment_type == 'meta' ? 'meta' : 'fullview' );
echo_item_comments( $blog, $item_ID, $statuses, $currentpage, $limit, array(), $filterset_name, $expiry_status, $comment_type );
}
break;
case 'delete_comment_url':
// Delete spam URL from a comment directly in the dashboard - comment remains otherwise untouched
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'comment' );
// Check comment edit permission below after we have the $edited_Comment object
$blog = param( 'blogid', 'integer' );
$edited_Comment = & Comment_get_by_ID( param( 'commentid', 'integer' ), false );
if( $edited_Comment !== false && $edited_Comment->author_url != NULL )
{ // The comment still exists
// Check permission:
check_user_perm( 'comment!CURSTATUS', 'edit', true, $edited_Comment );
$edited_Comment->set( 'author_url', NULL );
$edited_Comment->dbupdate();
}
break;
case 'refresh_comments':
// Refresh the comments list on dashboard by clicking on the refresh icon or after ban url
// Refresh item comments on the item view screen, or refresh all blog comments on comments view, if param itemid = -1
// A refresh is used on the actions:
// 1) click on the refresh icon.
// 2) limit by selected status(radioboxes 'Draft', 'Published', 'All comments').
// 3) ban by url of a comment
$is_admin_page = true;
$blog = param( 'blogid', 'integer' );
$item_ID = param( 'itemid', 'integer', NULL );
$statuses = param( 'statuses', 'string', NULL );
$expiry_status = param( 'expiry_status', 'string', 'active' );
$currentpage = param( 'currentpage', 'string', 1 );
$request_from = param( 'request_from', 'string', 'items' );
$comment_type = param( 'comment_type', 'string', 'feedback' );
// Ininitialize global collection object:
$BlogCache = & get_BlogCache();
$Blog = & $BlogCache->get_by_ID( $blog );
// Check minimum permissions ( The comment specific permissions are checked when displaying the comments )
check_user_perm( 'blog_ismember', 'view', true, $blog );
// Set admin skin, used for buttons, @see button_class()
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
if( in_array( $request_from, array( 'items', 'comments' ) ) )
{ // AJAX request goes from backoffice and ctrl = items or comments
echo_item_comments( $blog, $item_ID, $statuses, $currentpage, NULL, array(), '', $expiry_status, $comment_type );
}
elseif( $request_from == 'dashboard' || $request_from == 'coll_settings' )
{ // AJAX request goes from backoffice dashboard
load_funcs( 'dashboard/model/_dashboard.funcs.php' );
show_comments_awaiting_moderation( $blog, NULL, 10, array(), false );
}
break;
case 'dom_type_edit':
// Update type of a reffering domain from list screen by clicking on the type column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'domtype' );
// Check permission:
check_user_perm( 'stats', 'edit', true );
load_funcs('sessions/model/_hitlog.funcs.php');
$dom_type = param( 'new_dom_type', 'string' );
$dom_name = param( 'dom_name', 'string' );
$DB->query( 'UPDATE T_basedomains
SET dom_type = '.$DB->quote($dom_type).'
WHERE dom_name =' . $DB->quote($dom_name));
echo '<a href="#" rel="'.$dom_type.'">'.stats_dom_type_title( $dom_type ).'</a>';
break;
case 'dom_status_edit':
// Update status of a reffering domain from list screen by clicking on the type column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'domstatus' );
// Check permission:
check_user_perm( 'stats', 'edit', true );
load_funcs('sessions/model/_hitlog.funcs.php');
$dom_status = param( 'new_dom_status', 'string' );
$dom_name = param( 'dom_name', 'string' );
$DB->query( 'UPDATE T_basedomains
SET dom_status = '.$DB->quote($dom_status).'
WHERE dom_name =' . $DB->quote($dom_name));
echo '<a href="#" rel="'.$dom_status.'" color="'.stats_dom_status_color( $dom_status ).'">'.stats_dom_status_title( $dom_status ).'</a>';
break;
case 'iprange_status_edit':
// Update status of IP range from list screen by clicking on the status column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'iprange' );
// Check permission:
check_user_perm( 'spamblacklist', 'edit', true );
$new_status = param( 'new_status', 'string' );
$iprange_ID = param( 'iprange_ID', 'integer', true );
$DB->query( 'UPDATE T_antispam__iprange
SET aipr_status = '.( empty( $new_status ) ? 'NULL' : $DB->quote( $new_status ) ).'
WHERE aipr_ID =' . $DB->quote( $iprange_ID ) );
echo '<a href="#" rel="'.$new_status.'" color="'.aipr_status_color( $new_status ).'">'.aipr_status_title( $new_status ).'</a>';
break;
case 'emadr_status_edit':
// Update status of email address
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'emadrstatus' );
// Check permission:
check_user_perm( 'emails', 'edit', true );
$new_status = param( 'new_status', 'string' );
$emadr_ID = param( 'emadr_ID', 'integer', true );
load_funcs('tools/model/_email.funcs.php');
$DB->query( 'UPDATE T_email__address
SET emadr_status = '.( empty( $new_status ) ? 'NULL' : $DB->quote( $new_status ) ).'
WHERE emadr_ID =' . $DB->quote( $emadr_ID ) );
echo '<a href="#" rel="'.$new_status.'" color="'.emadr_get_status_color( $new_status ).'">'.emadr_get_status_title( $new_status ).'</a>';
break;
case 'user_level_edit':
// Update level of an user from list screen by clicking on the level column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'userlevel' );
$user_level = param( 'new_user_level', 'integer' );
$user_ID = param( 'user_ID', 'integer' );
// Check permission:
$current_User->can_moderate_user( $user_ID, true );
$UserCache = & get_UserCache();
if( $User = & $UserCache->get_by_ID( $user_ID, false ) )
{
$User->set( 'level', $user_level );
$User->dbupdate();
echo '<a href="#" rel="'.$user_level.'">'.$user_level.'</a>';
}
break;
case 'group_level_edit':
// Update level of a group from list screen by clicking on the level column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'grouplevel' );
// Check permission:
check_user_perm( 'users', 'edit', true );
$group_level = param( 'new_group_level', 'integer' );
$group_ID = param( 'group_ID', 'integer' );
$GroupCache = & get_GroupCache();
if( $Group = & $GroupCache->get_by_ID( $group_ID, false, false ) )
{
$Group->set( 'level', $group_level );
$Group->dbupdate();
echo '<a href="#" rel="'.$group_level.'">'.$group_level.'</a>';
}
break;
case 'country_status_edit':
// Update status of Country from list screen by clicking on the status column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'country' );
// Check permission:
check_user_perm( 'options', 'edit', true );
load_funcs( 'regional/model/_regional.funcs.php' );
$new_status = param( 'new_status', 'string' );
$ctry_ID = param( 'ctry_ID', 'integer', true );
$DB->query( 'UPDATE T_regional__country
SET ctry_status = '.( empty( $new_status ) ? 'NULL' : $DB->quote( $new_status ) ).'
WHERE ctry_ID =' . $DB->quote( $ctry_ID ) );
echo '<a href="#" rel="'.$new_status.'" color="'.ctry_status_color( $new_status ).'">'.ctry_status_title( $new_status ).'</a>';
break;
case 'item_task_edit':
// Update task fields of Item from list screen by clicking on the cell
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'itemtask' );
$field = param( 'field', 'string' );
if( ! in_array( $field, array( 'priority', 'status', 'assigned' ) ) )
{ // Invalid field
ajax_log_add( sprintf( 'Invalid field: %s', $field ), 'error' );
break;
}
$post_ID = param( 'post_ID', 'integer', true );
$ItemCache = & get_ItemCache();
$Item = & $ItemCache->get_by_ID( $post_ID );
// Check permission:
check_user_perm( 'item_post!CURSTATUS', 'edit', true, $Item );
$new_attrs = '';
switch( $field )
{
case 'priority':
// Update task priority
$new_value = param( 'new_priority', 'integer', NULL );
$new_attrs = ' color="'.item_priority_color( $new_priority ).'"';
$new_title = item_priority_title( $new_priority );
$Item->set_from_Request( 'priority', 'new_priority', true );
$Item->dbupdate();
break;
case 'assigned':
// Update task assigned user
$new_assigned_ID = param( 'new_assigned_ID', 'integer', NULL );
$new_assigned_login = param( 'new_assigned_login', 'string', NULL );
if( $Item->assign_to( $new_assigned_ID, $new_assigned_login ) )
{ // An assigned user can be changed
$Item->dbupdate();
$Item->send_assignment_notification();
}
else
{ // Error on changing of an assigned user
load_funcs('_core/_template.funcs.php');
headers_content_mightcache( 'text/html', 0, '#', false ); // Do NOT cache error messages! (Users would not see they fixed them)
header_http_response('400 Bad Request');
// This message is displayed after an input field
echo T_('Username not found!');
die(2); // Error code 2. Note: this will still call the shutdown function.
// EXIT here!
}
if( empty( $Item->assigned_user_ID ) )
{
$new_title = T_('No user');
}
else
{
$is_admin_page = true;
$UserCache = & get_UserCache();
$User = & $UserCache->get_by_ID( $Item->assigned_user_ID );
$new_title = $User->get_colored_login( array( 'mask' => '$avatar$ $login$' ) );
}
$new_value = $Item->assigned_user_ID;
break;
case 'status':
// Update task status
$new_value = param( 'new_status', 'string', NULL );
// Remove '_' that is used to don't break a sorting by name on jeditable:
$new_value = intval( str_replace( '_', '', $new_value ) );
set_param( 'new_status', $new_value );
$Item->set_from_Request( 'pst_ID', 'new_status', true );
$Item->dbupdate();
$new_title = empty( $Item->pst_ID ) ? T_('No status') : $Item->get( 't_extra_status' );
if( ! empty( $new_value ) )
{ // Add '_' to don't break a sorting by name on jeditable:
$new_value = '_'.$new_value;
}
break;
}
// Return a link to make the cell editable on next time
echo '<a href="#" rel="'.$new_value.'"'.$new_attrs.'>'.$new_title.'</a>';
break;
case 'item_order_edit':
// Update an order of Item from list screen by clicking on the cell:
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'itemorder' );
$item_order = param( 'new_item_order', 'string' );
$post_ID = param( 'post_ID', 'integer' );
$blog = param( 'blog', 'integer', 0 );
$cat_ID = param( 'cat_ID', 'integer', NULL );
$ItemCache = & get_ItemCache();
$Item = & $ItemCache->get_by_ID( $post_ID );
// Check permission:
check_user_perm( 'item_post!CURSTATUS', 'edit', true, $Item );
if( $item_order === '-' || $item_order === '' )
{ // Set NULL for these values:
$item_order = NULL;
}
else
{ // Make an order to double:
$item_order = floatval( $item_order );
}
$Item->update_order( $item_order, $cat_ID, $blog );
// Return a link to make the cell editable on next time:
echo '<a href="#" rel="'.$Item->ID.'">'.( $item_order === NULL ? '-' : $item_order ).'</a>';
break;
case 'cat_order_edit':
// Update order of a chapter from list screen by clicking on the order column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'catorder' );
$blog = param( 'blogid', 'integer' );
$cat_order = param( 'new_cat_order', 'string' );
$cat_ID = param( 'cat_ID', 'integer' );
// Check permission:
check_user_perm( 'blog_cats', 'edit', true, $blog );
if( $cat_order === '-' || $cat_order === '' || intval( $cat_order ) == '' )
{ // Set NULL for these values
$cat_order = NULL;
}
$ChapterCache = & get_ChapterCache();
if( $Chapter = & $ChapterCache->get_by_ID( $cat_ID, false ) )
{ // Update cat order if it exists in DB
$Chapter->set( 'order', ( $cat_order === '' ? NULL : $cat_order ), true );
$Chapter->dbupdate();
echo '<a href="#">'.( $cat_order === NULL ? '-' : $cat_order ).'</a>';
}
break;
case 'item_status_order_edit':
// Update order of a item status from list screen by clicking on the order column
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'itemstatus' );
$item_status_order = param( 'new_item_status_order', 'string' );
// Make sure we got an pst_ID:
$item_status_ID = param( 'pst_ID', 'integer', true );
// Check permission:
check_user_perm( 'options', 'edit', true );
if( $item_status_order === '-' || $item_status_order === '' )
{ // Set NULL for these values:
$item_status_order = NULL;
}
else
{ // Make an order to integer:
$item_status_order = intval( $item_status_order );
}
$ItemStatusCache = & get_ItemStatusCache();
if( $edited_ItemStatus = & $ItemStatusCache->get_by_ID( $item_status_ID, false ) )
{ // Update item status order if it exists in DB
$edited_ItemStatus->set( 'order', ( $item_status_order === '' ? NULL : $item_status_order ), true );
$edited_ItemStatus->dbupdate();
echo '<a href="#">'.( $item_status_order === NULL ? '-' : $item_status_order ).'</a>';
}
break;
case 'cat_ityp_ID_edit':
// Update default Item Type of a chapter from list screen by clicking on the order column:
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'catityp' );
$blog = param( 'blogid', 'integer' );
$cat_ityp_ID = param( 'new_ityp_ID', 'string', NULL );
$cat_ID = param( 'cat_ID', 'integer' );
// Check permission:
check_user_perm( 'blog_cats', '', true, $blog );
if( ! empty( $cat_ityp_ID ) )
{ // Remove prefix "_" which is used only for correct order in jeditable selector:
$cat_ityp_ID = substr( $cat_ityp_ID, 1 );
}
if( $cat_ityp_ID === false || $cat_ityp_ID === '' )
{ // Convert empty value to NULL to update DB:
$cat_ityp_ID = NULL;
}
$ChapterCache = & get_ChapterCache();
if( $Chapter = & $ChapterCache->get_by_ID( $cat_ID, false ) )
{ // Update cat Item Type if it exists in DB:
$ItemTypeCache = & get_ItemTypeCache();
if( ! empty( $cat_ityp_ID ) &&
( ! ( $ItemType = & $ItemTypeCache->get_by_ID( $cat_ityp_ID, false, false ) ) ||
! $ItemType->is_enabled( $blog ) ) )
{ // Revert back to use previous Item Type if new is wrong for current category:
$cat_ityp_ID = $Chapter->get( 'ityp_ID' );
}
$Chapter->set( 'ityp_ID', $cat_ityp_ID, true );
$Chapter->dbupdate();
if( $Chapter->get( 'ityp_ID' ) === NULL )
{
$cat_ityp_title = T_('Same as collection default');
}
elseif( $Chapter->get( 'ityp_ID' ) == '0' )
{
$cat_ityp_title = '<b>'.T_('No default type').'</b>';
}
elseif( $ItemType = & $ItemTypeCache->get_by_ID( $Chapter->get( 'ityp_ID' ), false, false ) )
{
$cat_ityp_title = $ItemType->get_name();
}
else
{
$cat_ityp_title = '<span class="red">'.T_('Not Found').' #'.$Chapter->get( 'ityp_ID' ).'</span>';
}
echo '<a href="#" rel="_'.$Chapter->get( 'ityp_ID' ).'">'.$cat_ityp_title.'</a>';
}
break;
case 'get_goals':
// Get option list with goals by selected category
$blog = param( 'blogid', 'integer' );
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'itemgoal' );
// Check permission:
check_user_perm( 'blog_post_statuses', 'edit', true, $blog );
$cat_ID = param( 'cat_id', 'integer', 0 );
$SQL = new SQL();
$SQL->SELECT( 'goal_ID, goal_name' );
$SQL->FROM( 'T_track__goal' );
$SQL->WHERE( 'goal_redir_url IS NULL' );
if( empty( $cat_ID ) )
{ // Select the goals without category
$SQL->WHERE_and( 'goal_gcat_ID IS NULL' );
}
else
{ // Get the goals from a selected category
$SQL->WHERE_and( 'goal_gcat_ID = '.$DB->quote( $cat_ID ) );
}
$goals = $DB->get_assoc( $SQL->get() );
echo '<option value="">'.T_('None').'</option>';
foreach( $goals as $goal_ID => $goal_name )
{
echo '<option value="'.$goal_ID.'">'.$goal_name.'</option>';
}
break;
case 'conflict_files':
// Replace old file with new and set new name for old file
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'conflictfiles' );
param( 'fileroot_ID', 'string' );
// Check permission:
check_user_perm( 'files', 'add', true, $fileroot_ID );
param( 'path', 'filepath' );
param( 'oldfile', 'filepath' );
param( 'newfile', 'filepath' );
param( 'format', 'string' );
$fileroot = explode( '_', $fileroot_ID );
$fileroot_type = $fileroot[0];
$fileroot_type_ID = empty( $fileroot[1] ) ? 0 : $fileroot[1];
$result = replace_old_file_with_new( $fileroot_type, $fileroot_type_ID, $path, $newfile, $oldfile, false );
$data = array();
if( $format == 'full_path_link' )
{ // User link with full path to file
$FileCache = & get_FileCache();
$new_File = & $FileCache->get_by_root_and_path( $fileroot_type, $fileroot_type_ID, trailing_slash( $path ).$newfile, true );
$old_File = & $FileCache->get_by_root_and_path( $fileroot_type, $fileroot_type_ID, trailing_slash( $path ).$oldfile, true );
$data['new'] = $new_File->get_view_link();
$data['old'] = $old_File->get_view_link();
}
else
{ // Simple text format
$data['new'] = $newfile;
$data['old'] = $oldfile;
}
if( $result !== true )
{ // Send an error if it was created during the replacing
$data['error'] = $result;
}
echo evo_json_encode( $data );
exit(0);
case 'link_attachment':
// The content for popup window to link the files to the items/comments
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'link' );
// Check permission:
check_user_perm( 'files', 'view' );
param( 'iframe_name', 'string', '' );
param( 'link_owner_type', 'string', true );
param( 'link_owner_ID', 'integer', true );
// Additional params, Used to highlight file/folder
param( 'root', 'string', '' );
param( 'path', 'filepath', '' );
param( 'fm_highlight', 'string', '' );
param( 'prefix', 'string' );
$additional_params = empty( $root ) ? '' : '&root='.$root;
$additional_params .= empty( $path ) ? '' : '&path='.$path;
$additional_params .= empty( $fm_highlight ) ? '' : '&fm_highlight='.$fm_highlight;
echo '<span id="link_attachment_loader" class="loader_img absolute_center" title="'.T_('Loading...').'"></span>'
.'<iframe src="'.$admin_url.'?ctrl=files&mode=upload&ajax_request=1&iframe_name='.$iframe_name.'&fm_mode=link_object&link_type='.$link_owner_type.'&link_object_ID='.$link_owner_ID.$additional_params.'&prefix='.$prefix.'"'
.' width="100%" height="100%" marginwidth="0" marginheight="0" align="top" scrolling="auto" frameborder="0"'
.' onload="document.getElementById(\'link_attachment_loader\').style.display=\'none\'">loading</iframe>';
break;
case 'file_attachment':
// The content for popup window to link the files to the items/comments
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'file_attachment' );
// Check permission:
check_user_perm( 'files', 'view' );
param( 'iframe_name', 'string', '' );
param( 'field_name', 'string', '' );
param( 'file_type', 'string', 'image' );
// Additional params, Used to highlight file/folder
param( 'root', 'string', '' );
param( 'path', 'string', '' );
param( 'fm_highlight', 'string', '' );
$additional_params = empty( $root ) ? '' : '&root='.$root;
$additional_params .= empty( $path ) ? '' : '&path='.$path;
$additional_params .= empty( $fm_highlight ) ? '' : '&fm_highlight='.$fm_highlight;
//$additional_params .= empty( $field_name ) ? '' : '&field_name='.$field_name;
echo '<span id="link_attachment_loader" class="loader_img absolute_center" title="'.T_('Loading...').'"></span>'
.'<iframe src="'.$admin_url.'?ctrl=files&mode=upload&field_name='.$field_name.'&file_type='.$file_type.'&ajax_request=1&iframe_name='.$iframe_name.'&fm_mode=file_select'.$additional_params.'"'
.' width="100%" height="100%" marginwidth="0" marginheight="0" align="top" scrolling="auto" frameborder="0"'
.' onload="document.getElementById(\'link_attachment_loader\').style.display=\'none\'">loading</iframe>';
break;
case 'import_files':
// The content for popup window to import the files for XML importer
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'import' );
$FileRootCache = & get_FileRootCache();
$FileRoot = & $FileRootCache->get_by_type_and_ID( 'import', '0', true );
// Check permission:
check_user_perm( 'files', 'view', true, $FileRoot );
echo '<span id="import_files_loader" class="loader_img absolute_center" title="'.T_('Loading...').'"></span>'
.'<iframe src="'.$admin_url.'?ctrl=files&mode=import&ajax_request=1&root=import_0&path='.param( 'path', 'string' ).'"'
.' width="100%" height="100%" marginwidth="0" marginheight="0" align="top" scrolling="auto" frameborder="0"'
.' onload="document.getElementById(\'import_files_loader\').style.display=\'none\'">loading</iframe>';
break;
case 'test_api':
// Spec action to test API from ctrl=system:
echo 'ok';
break;
case 'get_userlist_automation':
// Get automation data for current users list selection:
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'users' );
// Check permission:
check_user_perm( 'options', 'view', true );
param( 'autm_ID', 'integer', true );
param( 'enlt_ID', 'integer', NULL );
$AutomationCache = & get_AutomationCache();
$Automation = & $AutomationCache->get_by_ID( $autm_ID );
$NewsletterCache = & get_NewsletterCache();
$autm_data = array();
if( $enlt_ID === NULL )
{ // Get newsletters tied to the automation:
$NewsletterCache->load_list( $Automation->get_newsletter_IDs() );
$autm_data['newsletters'] = array();
foreach( $NewsletterCache->cache as $automation_Newsletter )
{
$autm_data['newsletters'][ $automation_Newsletter->ID ] = $automation_Newsletter->get( 'name' );
}
}
else
{ // Get automation data for selected newsletter:
$automation_Newsletter = & $NewsletterCache->get_by_ID( $enlt_ID );
$autm_data['newsletter_name'] = $automation_Newsletter->get( 'name' );
load_funcs( 'email_campaigns/model/_emailcampaign.funcs.php' );
$filterset_user_IDs = get_filterset_user_IDs();
$no_subs_SQL = new SQL( 'Get a count of not subscribed users' );
$no_subs_SQL->SELECT( 'COUNT( user_ID )' );
$no_subs_SQL->FROM( 'T_users' );
$no_subs_SQL->FROM_add( 'LEFT JOIN T_email__newsletter_subscription ON enls_user_ID = user_ID AND enls_enlt_ID = '.$automation_Newsletter->ID );
$no_subs_SQL->WHERE( 'user_ID IN ( '.$DB->quote( $filterset_user_IDs ).' )' );
$no_subs_SQL->WHERE_and( 'enls_subscribed = 0 OR enls_user_ID IS NULL' );
$autm_data['users_no_subs_num'] = intval( $DB->get_var( $no_subs_SQL ) );
$automated_SQL = new SQL( 'Get a count of automated users' );
$automated_SQL->SELECT( 'COUNT( user_ID )' );
$automated_SQL->FROM( 'T_users' );
$automated_SQL->FROM_add( 'INNER JOIN T_automation__user_state ON aust_user_ID = user_ID' );
$automated_SQL->WHERE( 'aust_autm_ID = '.$Automation->ID );
$automated_SQL->WHERE_and( 'user_ID IN ( '.$DB->quote( $filterset_user_IDs ).' )' );
$autm_data['users_automated_num'] = intval( $DB->get_var( $automated_SQL ) );
$autm_data['users_new_num'] = count( $filterset_user_IDs ) - $autm_data['users_automated_num'];
}
echo evo_json_encode( $autm_data );
exit(0); // Exit here in order to don't display the AJAX debug info after JSON formatted data
case 'get_campaign_recipients':
// Get recipients of Email Campaign depending on requested skip tags:
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'campaign' );
// Check permission:
check_user_perm( 'options', 'view', true );
param( 'ecmp_ID', 'integer', true );
param( 'skip_tags', 'string', '' );
$EmailCampaignCache = & get_EmailCampaignCache();
if( $edited_Campaign = & $EmailCampaignCache->get_by_ID( $ecmp_ID, false, false ) )
{ // If Email Campaign is found in DB:
// Set temporarily the requested skip tags in order to calculate a count of recipients depending on them:
$edited_Campaign->set( 'user_tag_sendskip', $skip_tags );
load_funcs( 'email_campaigns/model/_emailcampaign.funcs.php' );
$recipients_data = array(
'status' => 'ok',
'skipped_tag' => $edited_Campaign->get_recipients_count( 'skipped_tag' ),
'wait' => $edited_Campaign->get_recipients_count( 'wait' ),
);
}
else
{ // Wrong request, unknown Email Campaign:
$recipients_data = array(
'status' => 'error',
'error' => 'email campaign not found'
);
}
echo evo_json_encode( $recipients_data );
exit(0); // Exit here in order to don't display the AJAX debug info after JSON formatted data
case 'get_automation_status':
// Get automation status:
// Check permission:
check_user_perm( 'options', 'view', true );
param( 'autm_ID', 'integer', true );
$AutomationCache = & get_AutomationCache();
$Automation = & $AutomationCache->get_by_ID( $autm_ID );
echo $Automation->get( 'status' );
exit(0); // Exit here in order to don't display the AJAX debug info.
case 'get_item_add_version_form':
// Form to add version for the Item:
$item_ID = param( 'item_ID', 'integer', true );
$ItemCache = & get_ItemCache();
$edited_Item = & $ItemCache->get_by_ID( $item_ID );
// Initialize back-office skin:
global $UserSettings, $adminskins_path, $AdminUI;
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
require $inc_path.'items/views/_item_add_version.form.php';
break;
case 'get_link_locale_selector':
// Get a selector to link a collection with other collectios which have same main or extra locale as requested
param( 'coll_ID', 'integer', true );
param( 'coll_locale', 'string' );
param( 'field_name', 'string' );
$BlogCache = & get_BlogCache();
$Blog = & $BlogCache->get_by_ID( $coll_ID );
echo $Blog->get_link_locale_selector( $field_name, $coll_locale, false );
break;
case 'get_item_mass_change_cat_form':
// Form to mass change category of Items:
param( 'blog', 'integer', true );
param( 'selected_items', 'array:integer' );
param( 'cat_type', 'string' );
param( 'redirect_to', 'url', true );
// Initialize objects for proper displaying of categories selector table:
$BlogCache = & get_BlogCache();
$Blog = & $BlogCache->get_by_ID( $blog );
load_class( 'items/model/_item.class.php', 'Item' );
$edited_Item = new Item();
$post_extracats = array();
// Initialize back-office skin:
global $UserSettings, $adminskins_path, $AdminUI;
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
require $inc_path.'items/views/_item_mass_change_cat.form.php';
break;
case 'get_item_mass_change_renderer_form':
// Form to mass change renderer of Items:
param( 'blog', 'integer', true );
param( 'selected_items', 'array:integer' );
param( 'renderer_change_type', 'string' );
param( 'redirect_to', 'url', true );
// Initialize objects for proper displaying of list of renderers:
$BlogCache = & get_BlogCache();
$Blog = & $BlogCache->get_by_ID( $blog );
load_class( 'items/model/_item.class.php', 'Item' );
$edited_Item = new Item();
// Initialize back-office skin:
global $UserSettings, $adminskins_path, $AdminUI;
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
require $inc_path.'items/views/_item_mass_change_renderer.form.php';
break;
case 'clear_itemprecache':
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'tools' );
load_funcs( 'tools/model/_maintenance.funcs.php' );
dbm_delete_itemprecache();
break;
case 'browse_subdirs':
// Load sub-directories for Files Browser:
// Use the glyph or font-awesome icons if requested by skin
param( 'b2evo_icons_type', 'string', '' );
// Path to parent directory with root data:
param( 'path', 'filepath' );
if( ! preg_match( '#^([a-z]+)_(\d+):(.+)$#', $path, $path_data ) )
{ // Invalid path:
debug_die( 'Invalid path!' );
}
// Try to get File Root by requested path:
$FileRootCache = & get_FileRootCache();
$dir_FileRoot = & $FileRootCache->get_by_type_and_ID( $path_data[1], $path_data[2] );
// Check permission:
check_user_perm( 'files', 'view', true, $dir_FileRoot );
$FileCache = & get_FileCache();
if( ! ( $dir_File = & $FileCache->get_by_root_and_path( $path_data[1], $path_data[2], $path_data[3] ) ) ||
! $dir_File->is_dir() )
{ // Invalid directory:
debug_die( 'Invalid directory!' );
}
// Create list to load sub-folders:
load_class( 'files/model/_filelist.class.php', 'Filelist' );
$dir_Filelist = new Filelist( $dir_FileRoot, trailing_slash( $dir_File->get_full_path() ) );
check_showparams( $dir_Filelist );
$dir_Filelist->load();
$dir_Filelist->sort( 'name' );
if( ! $dir_Filelist->count_dirs() )
{ // Wrong requested directory:
debug_die( 'No sub-directories!' );
}
// Return sub-directories of the requested directory:
while( $subdir_File = & $dir_Filelist->get_next( 'dir' ) )
{
echo '<li>'.get_directory_tree( $dir_FileRoot, $subdir_File->get_full_path(), $dir_File->get_full_path(), false, $subdir_File->get_rdfs_rel_path(), true ).'</li>';
}
break;
case 'browse_existing_attachments':
global $DB;
$mode = 'upload';
$FileRootCache = & get_FileRootCache();
// Get all Item comments:
$link_type = param( 'link_type', 'string', true );
$link_object_ID = param( 'link_object_ID', 'integer', true );
$LinkOwner = get_LinkOwner( $link_type, $link_object_ID );
$LinkCache = & get_LinkCache();
$links = array();
$link_owner_class = get_class( $LinkOwner->link_Object );
load_class( '_core/model/dataobjects/_dataobjectlist2.class.php', 'DataObjectList2' );
$LinkCache = & get_LinkCache();
$ea_Linklist = new DataObjectList2( $LinkCache );
switch( $link_owner_class )
{
case 'Item':
case 'Comment':
if( $link_owner_class == 'Comment' )
{
$edited_Item = $LinkOwner->get_Item();
}
else
{
$edited_Item = $LinkOwner->Item;
}
$item_ID = $edited_Item->ID;
// Get list of comment IDs under Item or related to Comment:
$comments_SQL = new SQL( 'Get all the comments of an Item' );
$comments_SQL->SELECT( 'comment_ID' );
$comments_SQL->FROM( 'T_comments' );
$comments_SQL->WHERE( 'comment_item_ID = '.$DB->quote( $item_ID ) );
if( ! $edited_Item->can_meta_comment() )
{ // If current User doesn't have an access to meta comments:
$comments_SQL->WHERE( 'comment_type != "meta"' );
}
$comment_IDs = $DB->get_col( $comments_SQL );
$links_SQL = new SQL( 'Get all the links belonging to comments of an Item' );
$links_SQL->SELECT( '*' );
$links_SQL->FROM( 'T_links AS l' );
if( $comment_IDs )
{
$links_SQL->WHERE( 'link_cmt_ID IN ('.$DB->quote( $comment_IDs ).')' );
}
$links_SQL->WHERE_or( 'link_itm_ID = '.$DB->quote( $item_ID ) );
$links_SQL->ORDER_BY( 'link_datemodified DESC, link_datecreated DESC' );
$ea_Linklist->sql = $links_SQL->get();
$ea_Linklist->run_query( false, false, false, 'get_attachment_LinkList' );
// Get FileRoot and dummy FileList:
if( $ea_Linklist->get_total_rows() )
{ // Use first attachment to get the FileRoot:
$Link = & $ea_Linklist->get_by_idx( 0 );
$File = & $Link->get_File();
$fm_FileRoot = & $File->get_FileRoot();
}
else
{
global $Blog;
if( empty( $Blog ) )
{
$Blog = $edited_Item->get_Blog();
}
$fm_FileRoot = & $FileRootCache->get_by_type_and_ID( 'collection', $Blog->ID );
}
load_class( 'files/model/_filelist.class.php', 'FileList' );
$fm_Filelist = new Filelist( $fm_FileRoot, false ); // Arbitrary list of attached files
$selected_Filelist = new Filelist( $fm_FileRoot, false ); // Arbitrary list of attached files
break;
case 'EmailCampaign':
if( $edited_Newsletter = & $LinkOwner->link_Object->get_Newsletter() )
{
// Get list of email campaign IDs under the same Newsletter:
$email_campaigns_SQL = new SQL( 'Get all the email campaigns of a List' );
$email_campaigns_SQL->SELECT( 'ecmp_ID' );
$email_campaigns_SQL->FROM( 'T_email__campaign' );
$email_campaigns_SQL->WHERE( 'ecmp_enlt_ID = '.$DB->quote( $edited_Newsletter->ID ) );
$email_campaign_IDs = $DB->get_col( $email_campaigns_SQL );
if( $email_campaign_IDs )
{
$links_SQL = new SQL( 'Get all the links belonging to email campaigns of a List' );
$links_SQL->SELECT( '*' );
$links_SQL->FROM( 'T_links AS l' );
$links_SQL->WHERE( 'link_ecmp_ID IN ('.$DB->quote( $email_campaign_IDs ).')' );
$links_SQL->ORDER_BY( 'link_datemodified DESC, link_datecreated DESC' );
$ea_Linklist->sql = $links_SQL->get();
$ea_Linklist->run_query( false, false, false, 'get_attachment_LinkList' );
}
}
// Get FileRoot and dummy FileList:
if( $ea_Linklist->get_total_rows() )
{ // Use first attachment to get the FileRoot:
$Link = & $ea_Linklist->get_by_idx( 0 );
$File = & $Link->get_File();
$fm_FileRoot = & $File->get_FileRoot();
}
else
{
$fm_FileRoot = & $FileRootCache->get_by_type_and_ID( 'emailcampaign', $LinkOwner->link_Object->ID );
}
load_class( 'files/model/_filelist.class.php', 'FileList' );
$fm_Filelist = new Filelist( $fm_FileRoot, false ); // Arbitrary list of attached files
$selected_Filelist = new Filelist( $fm_FileRoot, false ); // Arbitrary list of attached files
break;
default:
debug_die( 'Existing attachments list not available to '.$link_owner_class );
}
global $current_User, $UserSettings, $is_admin_page, $adminskins_path;
$admin_skin = $UserSettings->get( 'admin_skin', $current_User->ID );
$is_admin_page = true;
require_once $adminskins_path.$admin_skin.'/_adminUI.class.php';
$AdminUI = new AdminUI();
$Widget = new Widget( 'file_browser' );
$Widget->disp_template_replaced( 'block_start' );
require $inc_path.'links/views/_link_file_list.inc.php';
$Widget->disp_template_raw( 'block_end' );
break;
default:
$incorrect_action = true;
break;
}
if( !$incorrect_action )
{
if( $current_debug || $current_debug_jslog )
{ // debug is ON
ajax_log_display();
}
if( $add_response_end_comment )
{ // add ajax response end comment
echo '<!-- Ajax response end -->';
}
exit(0);
}
?>