Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

@@ -2,9 +2,9 @@
/**
* @brief Autoresolve Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 25 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -34,7 +34,18 @@ class _autoresolve extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'autoresolve_manage' );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_autoresolve_on', \IPS\Settings::i()->nexus_autoresolve_days, FALSE, array( 'togglesOn' => array( 'nexus_autoresolve_departments', 'nexus_autoresolve_applicable', 'nexus_autoresolve_days', 'nexus_autoresolve_notify', 'nexus_autoresolve_status' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'nexus_autoresolve_on', \IPS\Settings::i()->nexus_autoresolve_days, FALSE, array( 'togglesOn' => array( 'reply_request_resolved', 'nexus_autoresolve_departments', 'nexus_autoresolve_applicable', 'nexus_autoresolve_days', 'nexus_autoresolve_notify', 'nexus_autoresolve_status' ) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'reply_request_resolved', \IPS\Settings::i()->reply_request_resolved, FALSE, array(
'options' => array(
'reopen' => 'reopen_request_autoresolve',
'create' => 'create_new_request_autoresolve',
'reject' => 'reject_notify_user_autoresolve'
),
'descriptions' => array(
'create' => \IPS\Member::loggedIn()->language()->addToStack( 'create_new_request_autoresolve_desc' ),
'reject' => \IPS\Member::loggedIn()->language()->addToStack( 'reject_notify_user_autoresolve_desc' )
)
) ) );
$form->addSeparator();
$form->add( new \IPS\Helpers\Form\Node( 'nexus_autoresolve_departments', \IPS\Settings::i()->nexus_autoresolve_departments === '*' ? 0 : explode( ',', \IPS\Settings::i()->nexus_autoresolve_departments ), FALSE, array( 'class' => 'IPS\nexus\Support\Department', 'multiple' => TRUE, 'zeroVal' => 'any' ), NULL, NULL, NULL, 'nexus_autoresolve_departments' ) );
$form->add( new \IPS\Helpers\Form\Node( 'nexus_autoresolve_applicable', \IPS\Settings::i()->nexus_autoresolve_applicable, FALSE, array( 'class' => 'IPS\nexus\Support\Status', 'multiple' => TRUE ), NULL, NULL, NULL, 'nexus_autoresolve_applicable' ) );
@@ -44,16 +55,16 @@ class _autoresolve extends \IPS\Dispatcher\Controller
if ( $values = $form->values() )
{
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => (int) $values['nexus_autoresolve_on'] ), "`key`='supportAutoresolve'" );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => (int) $values['nexus_autoresolve_on'] ), "`key`='supportAutoresolve'" );
if ( !$values['nexus_autoresolve_on'] )
{
$values['nexus_autoresolve_days'] = 0;
}
unset( $values['nexus_autoresolve_on'] );
$values['nexus_autoresolve_departments'] = $values['nexus_autoresolve_departments'] ? implode( ',' , array_keys( $values['nexus_autoresolve_departments'] ) ) : '*';
$values['nexus_autoresolve_applicable'] = implode( ',', array_keys( $values['nexus_autoresolve_applicable'] ) );
$values['nexus_autoresolve_applicable'] = is_array( $values['nexus_autoresolve_applicable'] ) ? implode( ',', array_keys( $values['nexus_autoresolve_applicable'] ) ) : $values['nexus_autoresolve_applicable'];
$values['nexus_autoresolve_status'] = $values['nexus_autoresolve_status']->id;
$form->saveAsSettings( $values );
@@ -2,9 +2,9 @@
/**
* @brief Customer Feedback Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 23 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -2,9 +2,9 @@
/**
* @brief Support Departments
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 08 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -50,7 +50,12 @@ class _departments extends \IPS\Node\Controller
try
{
$node = \IPS\nexus\Support\Department::load( \IPS\Request::i()->id );
if( \IPS\Settings::i()->contact_type == 'contact_nexus_department' AND \IPS\Settings::i()->contact_nexus_department == $node->id )
{
\IPS\Output::i()->error( 'nexus_nodeletedept_contactus', '1X344/1', 403, '' );
}
if ( $node->canDelete() and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'r_department=?', $node->id ) ) )
{
$form = new \IPS\Helpers\Form( 'delete', 'delete' );
@@ -62,15 +67,16 @@ class _departments extends \IPS\Node\Controller
{
\IPS\Db::i()->update( 'nexus_support_requests', array( 'r_department' => $values['move_existing_requests_to']->id ), array( 'r_department=?', $node->id ) );
\IPS\Request::i()->form_submitted = TRUE;
\IPS\Request::i()->wasConfirmed = TRUE;
return parent::delete();
}
\IPS\Output::i()->output = $form;
return;
}
}
catch ( \OutOfRangeException $e ){}
return parent::delete();
}
}
@@ -2,9 +2,9 @@
/**
* @brief Support Custom Fields
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 16 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -2,9 +2,9 @@
/**
* @brief Incoming Email Setup
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 16 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -93,6 +93,10 @@ class _incomingemail extends \IPS\Dispatcher\Controller
{
$content = \IPS\Theme::i()->getTemplate('incomingemailsetup')->pop3( $this->_pop3() );
}
elseif ( \IPS\Request::i()->type === 'sendgrid' )
{
$content = \IPS\Theme::i()->getTemplate('incomingemailsetup')->sendgrid();
}
else
{
$content = \IPS\Theme::i()->getTemplate('incomingemailsetup')->splash( (string) $table );
@@ -127,8 +131,15 @@ class _incomingemail extends \IPS\Dispatcher\Controller
*/
protected function disablePop3()
{
foreach ( array( 'pop3_server', 'pop3_port', 'pop3_user', 'pop3_password' ) as $k )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', $k ) );
\IPS\Settings::i()->$k = '';
}
unset( \IPS\Data\Store::i()->settings );
\IPS\Session::i()->log( 'acplogs__pop3_settings' );
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( 'app=? AND `key`=?', 'core', 'pop' ) );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( 'app=? AND `key`=?', 'core', 'pop' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=settings&tab=incomingemail') );
}
@@ -148,28 +159,20 @@ class _incomingemail extends \IPS\Dispatcher\Controller
if ( $values = $form->values() )
{
require_once \IPS\ROOT_PATH . '/system/3rd_party/pop3/pop3.class.inc';
$pop3 = new \POP3;
try
{
if ( !$pop3->connect( ( $values['pop3_tls'] ? 'ssl://' : '' ) . $values['pop3_server'], $values['pop3_port'] ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('pop3_connect_err') );
}
if ( !$pop3->login( $values['pop3_user'], $values['pop3_password'] ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('pop3_login_err') );
}
$pop3 = new \IPS\Email\Incoming\PopImap( $values['pop3_server'], $values['pop3_tls'], $values['pop3_port'], $values['pop3_user'], $values['pop3_password'] );
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplogs__pop3_settings' );
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( 'app=? AND `key`=?', 'core', 'pop' ) );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( 'app=? AND `key`=?', 'core', 'pop' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=settings&tab=incomingemail') );
}
catch ( \Exception $e )
catch ( \IPS\Email\Incoming\PopImapException $e )
{
$form->error = $e->getMessage();
$form->error = \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() );
}
}
@@ -242,7 +245,10 @@ class _incomingemail extends \IPS\Dispatcher\Controller
* @return void
*/
protected function incomingEmailDelete()
{
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\Db::i()->delete( 'core_incoming_emails', array( 'rule_id=?', \IPS\Request::i()->id ) );
\IPS\Session::i()->log( 'acplogs__incomingemail_deleted' );
@@ -2,9 +2,9 @@
/**
* @brief Outgoing Email Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 18 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -2,9 +2,9 @@
/**
* @brief Support Reports
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 23 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -45,7 +45,7 @@ class _reports extends \IPS\Dispatcher\Controller
/* Tabs */
$tabs = array(
'overview' => 'overview',
'replies' => 'replies',
'replies' => 'latest_replies',
'feedback_ratings' => 'feedback_ratings',
'latest_feedback' => 'latest_feedback',
);
@@ -55,64 +55,81 @@ class _reports extends \IPS\Dispatcher\Controller
/* Staff Productivity */
if ( $activeTab === 'overview' )
{
/* Build table */
$staffProductivityTable = new \IPS\Helpers\Table\Db(
'nexus_support_replies',
\IPS\Http\Url::internal( 'app=nexus&module=support&controller=reports&act=productivity_table' ),
array(
array( 'reply_type=?', \IPS\nexus\Support\Reply::REPLY_STAFF ),
\IPS\Db::i()->in( 'reply_member', array_keys( \IPS\nexus\Support\Request::staff() ) )
),
'reply_member'
/* Filters */
$filters = array(
'last_24_hours' => \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp(),
'last_7_days' => \IPS\DateTime::create()->sub( new \DateInterval( 'P7D' ) )->getTimestamp(),
'last_30_days' => \IPS\DateTime::create()->sub( new \DateInterval( 'P30D' ) )->getTimestamp(),
);
/* Set default values */
$data = array();
foreach ( \IPS\nexus\Support\Request::staff() as $staffId => $name )
{
$data[ $staffId ] = array( 'name' => $name, 'reply_count' => 0 );
if ( \IPS\Settings::i()->nexus_support_satisfaction )
{
$data[ $staffId ]['rating_count'] = 0;
$data[ $staffId ]['rating_average'] = 0;
}
}
/* Get their replies */
$where = array( array( \IPS\Db::i()->in( 'reply_member', array_keys( $data ) ) ) );
if ( isset( \IPS\Request::i()->filter ) and array_key_exists( \IPS\Request::i()->filter, $filters ) )
{
$where[] = array( 'reply_date>?', $filters[ \IPS\Request::i()->filter ] );
}
foreach ( \IPS\Db::i()->select( 'COUNT(*) AS count, reply_member', 'nexus_support_replies', $where, NULL, NULL, 'reply_member' ) as $row )
{
$data[ $row['reply_member'] ]['reply_count'] = $row['count'];
}
/* And their ratings */
if ( \IPS\Settings::i()->nexus_support_satisfaction )
{
$where = array( \IPS\Db::i()->in( 'rating_staff', array_keys( $data ) ) );
if ( isset( \IPS\Request::i()->filter ) and array_key_exists( \IPS\Request::i()->filter, $filters ) )
{
$where[] = array( 'rating_date>?', $filters[ \IPS\Request::i()->filter ] );
}
foreach ( \IPS\Db::i()->select( 'COUNT(*) AS count, AVG(rating_rating) AS rating, rating_staff', 'nexus_support_ratings', $where, NULL, NULL, 'rating_staff' ) as $row )
{
$data[ $row['rating_staff'] ]['rating_count'] = $row['count'];
$data[ $row['rating_staff'] ]['rating_average'] = $row['rating'];
}
}
/* Build the table */
$staffProductivityTable = new \IPS\Helpers\Table\Custom( $data, \IPS\Http\Url::internal( 'app=nexus&module=support&controller=reports&tab=overview' ) );
$staffProductivityTable->langPrefix = 'staff_';
$staffProductivityTable->selects = array( 'COUNT(*) AS reply_count' );
$staffProductivityTable->include = array( 'name', 'reply_count' );
$staffProductivityTable->widths = array( 'name' => 75, 'reply_count' => 25 );
$staffProductivityTable->parsers['reply_count'] = function( $val ) { return intval( $val ); };
$staffProductivityTable->widths = \IPS\Settings::i()->nexus_support_satisfaction ? array( 'name' => 50, 'reply_count' => 25, 'rating_average' => 25 ) : array( 'name' => 75, 'reply_count' => 25 );
if ( \IPS\Settings::i()->nexus_support_satisfaction )
{
$staffProductivityTable->joins[] = array(
'select' => 'rating_count, rating_average',
'from' => \IPS\Db::i()->select( 'rating_reply, COUNT(*) AS rating_count, AVG(rating_rating) AS rating_average', 'nexus_support_ratings' ),
'where' => 'rating_reply=reply_id'
);
$staffProductivityTable->include[] = 'rating_average';
$staffProductivityTable->widths = array( 'name' => 50, 'reply_count' => 25, 'rating_average' => 25 );
$staffProductivityTable->parsers['rating_average'] = function( $val, $row ) {
return \IPS\Theme::i()->getTemplate('supportreports')->averageRatingCell( $val, $row['rating_count'] );
};
$staffProductivityTable->include = array( 'name', 'reply_count', 'rating_average' );
}
$staffProductivityTable->sortBy = $staffProductivityTable->sortBy ?: 'reply_count';
/* We need to join the members table for the name */
$staffProductivityTable->joins[] = array(
'select' => 'name',
'from' => 'core_members',
'where' => 'member_id=reply_member'
);
$staffProductivityTable->quickSearch = 'name';
/* Specify the filters and search options */
$staffProductivityTable->filters = array(
'last_24_hours' => array( 'reply_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp() ),
'last_7_days' => array( 'reply_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P7D' ) )->getTimestamp() ),
'last_30_days' => array( 'reply_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P30D' ) )->getTimestamp() ),
);
$staffProductivityTable->filters = $filters;
/* Buttons for each member */
$staffProductivityTable->rowButtons = function( $row )
$staffProductivityTable->rowButtons = function( $row, $id )
{
return array(
'report' => array(
'icon' => 'search',
'title' => 'view_report',
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=reports&do=staff')->setQueryString( 'id', $row['reply_member'] ),
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=reports&do=staff')->setQueryString( 'id', $id ),
),
);
};
/* Output */
$activeTabContents = (string) $staffProductivityTable;
}
@@ -122,6 +139,7 @@ class _reports extends \IPS\Dispatcher\Controller
$staffRepliesChart = new \IPS\Helpers\Chart\Dynamic( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=reports&tab=replies' ), 'nexus_support_replies', 'reply_date', '',
array(
'vAxis' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('replies_made') ),
'height' => 700
),
'LineChart', 'daily', array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) ), 'end' => 0 )
);
@@ -141,8 +159,9 @@ class _reports extends \IPS\Dispatcher\Controller
$staffRatingsChart = new \IPS\Helpers\Chart\Dynamic( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=reports&tab=feedback_ratings' ), 'nexus_support_ratings', 'rating_date', '',
array(
'vAxis' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('average_rating'), 'viewWindow' => array( 'min' => 0, 'max' => 5 ) ),
'height' => 700
),
'ColumnChart', 'monthly'
'ColumnChart', 'monthly', array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) ), 'end' => \IPS\DateTime::create() )
);
$staffRatingsChart->plotZeros = FALSE;
$staffRatingsChart->groupBy = 'rating_staff';
@@ -253,19 +272,44 @@ class _reports extends \IPS\Dispatcher\Controller
/* Get average replies by hour for this staff member */
$thisStaffMember = array();
foreach( \IPS\Db::i()->select( "COUNT(*) AS count, reply_date AS unixtime, DATE_FORMAT( FROM_UNIXTIME( reply_date ), '{$group}' ) AS hour", 'nexus_support_replies', array_merge( $where, array( array( 'reply_member=?', $staff->member_id ) ) ), NULL, NULL, 'hour' ) as $row )
{
$thisStaffMemberCount = array();
foreach( \IPS\Db::i()->select( "COUNT(*) AS count, reply_date AS unixtime, DATE_FORMAT( FROM_UNIXTIME( reply_date ), '{$group}' ) AS hour", 'nexus_support_replies', array_merge( $where, array( array( 'reply_member=?', $staff->member_id ) ) ), NULL, NULL, array( 'hour', 'reply_date' ) ) as $row )
{
$_group = $span === 'day' ? \IPS\DateTime::ts( $row['unixtime'] )->format('G') : \IPS\DateTime::ts( $row['unixtime'] )->format('w');
$thisStaffMember[ $_group ] = round( ( $type === 'average' ) ? ( $row['count'] / $daysInTimeframe ) : $row['count'], 1 );
if ( !isset( $thisStaffMemberCount[ $_group ] ) )
{
$thisStaffMemberCount[ $_group ] = 0;
}
$thisStaffMemberCount[ $_group ] = $thisStaffMemberCount[ $_group ] + $row['count'];
}
foreach( $thisStaffMemberCount AS $_group => $count )
{
$thisStaffMember[ $_group ] = round( ( $type === 'average' ) ? ( $count / $daysInTimeframe ) : $count, 1 );
}
/* Get average replies by hour for all staff members */
if ( $numberOfStaffMembers > 1 )
{
foreach( \IPS\Db::i()->select( "COUNT(*) AS count, reply_date AS unixtime, DATE_FORMAT( FROM_UNIXTIME( reply_date ), '{$group}' ) AS hour", 'nexus_support_replies', $where, NULL, NULL, 'hour' ) as $row )
$allStaffMembers = array();
$allStaffMembersCount = array();
foreach( \IPS\Db::i()->select( "COUNT(*) AS count, reply_date AS unixtime, DATE_FORMAT( FROM_UNIXTIME( reply_date ), '{$group}' ) AS hour", 'nexus_support_replies', $where, NULL, NULL, array( 'hour', 'reply_date' ) ) as $row )
{
$_group = $span === 'day' ? \IPS\DateTime::ts( $row['unixtime'] )->format('G') : \IPS\DateTime::ts( $row['unixtime'] )->format('w');
$allStaffMembers[ $_group ] = round( ( ( $type === 'average' ) ? ( $row['count'] / $daysInTimeframe ) : $row['count'] ) / $numberOfStaffMembers, 1 );
if ( !isset( $allStaffMembersCount[ $_group ] ) )
{
$allStaffMembersCount[ $_group ] = 0;
}
$allStaffMembersCount[ $_group ] = $allStaffMembersCount[ $_group ] + $row['count'];
}
foreach( $allStaffMembersCount AS $_group => $count )
{
$allStaffMembers[ $_group ] = round( ( ( $type === 'average' ) ? ( $count / $daysInTimeframe ) : $count ) / $numberOfStaffMembers, 1 );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Support Request View
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 09 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -123,7 +123,7 @@ class _request extends \IPS\nexus\modules\front\support\view
/* Setting Order? */
if ( isset( \IPS\Request::i()->order ) )
{
\IPS\Request::i()->setCookie( 'support_order', \IPS\Request::i()->order, \IPS\DateTime::create()->add( new \DateInterval('P1Y') ) );
\IPS\Request::i()->setCookie( 'support_replies_order', \IPS\Request::i()->order, \IPS\DateTime::create()->add( new \DateInterval('P1Y') ) );
}
/* Views */
@@ -146,21 +146,24 @@ class _request extends \IPS\nexus\modules\front\support\view
'title' => $this->request->status->_title,
'menu' => array(),
'menuClass' => 'ipsMenu_selectable ipsMenu_narrow',
'data' => array( 'controller' => 'nexus.admin.support.metamenu' )
'data' => array( 'role' => 'statusMenu', 'controller' => 'nexus.admin.support.metamenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_status')
),
'severity' => array(
'icon' => 'exclamation',
'title' => $this->request->severity->_title,
'menu' => array(),
'menuClass' => 'ipsMenu_selectable',
'data' => array( 'controller' => 'nexus.admin.support.metamenu' )
'data' => array( 'role' => 'severityMenu', 'controller' => 'nexus.admin.support.metamenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_severity')
),
'department' => array(
'icon' => 'folder',
'title' => $this->request->department->_title,
'menu' => array(),
'menuClass' => 'ipsMenu_selectable ipsMenu_narrow',
'data' => array( 'controller' => 'nexus.admin.support.metamenu' )
'data' => array( 'role' => 'departmentMenu', 'controller' => 'nexus.admin.support.metamenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_department')
),
'staff' => array(
'icon' => 'user',
@@ -168,9 +171,17 @@ class _request extends \IPS\nexus\modules\front\support\view
'menu' => array(),
'menuClass' => 'ipsMenu_selectable',
'data' => array( 'controller' => 'nexus.admin.support.metamenu', 'role' => 'staffMenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_staff')
),
'purchase' => array(
'icon' => 'cube',
'title' => 'associate_purchase',
'link' => $this->request->acpUrl()->setQueryString( 'do', 'associate' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('associate'), 'ipsDialog-size' => 'narrow', 'role' => 'associatePurchaseMenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_purchase')
),
'track' => array(
'icon' => 'star',
'icon' => 'bookmark',
'title' => $trackLang,
'menu' => array(
array(
@@ -190,7 +201,8 @@ class _request extends \IPS\nexus\modules\front\support\view
)
),
'menuClass' => 'ipsMenu_selectable',
'data' => array( 'controller' => 'nexus.admin.support.metamenu' )
'data' => array( 'role' => 'trackMenu', 'controller' => 'nexus.admin.support.metamenu' ),
'tooltip' => \IPS\Member::loggedIn()->language()->addToStack('keyboard_shortcut_tracking')
)
);
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'support', 'requests_delete' ) )
@@ -289,8 +301,10 @@ class _request extends \IPS\nexus\modules\front\support\view
);
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'request_x', FALSE, array( 'sprintf' => "#{$this->request->id}" ) );
\IPS\Output::i()->title = "#{$this->request->id} " . $this->request->mapped('title');
\IPS\Output::i()->showTitle = FALSE;
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_support.js', 'nexus', 'admin' ) );
\IPS\Output::i()->globalControllers[] = 'nexus.admin.support.request';
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'support.css', 'nexus', 'admin' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
@@ -298,6 +312,175 @@ class _request extends \IPS\nexus\modules\front\support\view
}
}
/**
* Hovercard
*
* @return void
*/
protected function hovercard()
{
/* Load request */
try
{
$request = \IPS\nexus\Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X208/K', 404, '' );
}
/* Start with the first message */
$overview = array( 'firstMessage' => array( 'support_first_message', $request->comments( 1, 0, 'date', 'asc', NULL, FALSE ) ) );
/* Add the last customer reply */
if ( $request->last_reply != $request->started )
{
if ( $latestPost = $request->comments( 1, 0, 'date', 'desc', NULL, FALSE, NULL, array( '( reply_type=? OR reply_type=? OR reply_type=? )', \IPS\nexus\Support\Reply::REPLY_MEMBER, \IPS\nexus\Support\Reply::REPLY_ALTCONTACT, \IPS\nexus\Support\Reply::REPLY_EMAIL ) ) )
{
$overview['lastCustomerReply'] = array( 'support_last_customer_reply', $latestPost );
}
}
/* Add the last staff reply */
if ( $request->last_staff_reply )
{
if ( $latestStaffReply = $request->comments( 1, 0, 'date', 'desc', NULL, FALSE, NULL, array( 'reply_type=?', \IPS\nexus\Support\Reply::REPLY_STAFF ) ) )
{
$overview['lastStaffReply'] = array( 'support_last_staff_reply', $latestStaffReply );
}
}
/* And the latest note */
if ( $latestNote = $request->comments( 1, 0, 'date', 'desc', NULL, NULL, NULL, array( 'reply_type=?', \IPS\nexus\Support\Reply::REPLY_HIDDEN ) ) )
{
$overview['lastNote'] = array( 'support_last_note', $latestNote );
}
/* Display */
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'support' )->requestHover( $request, $overview ) );
}
/**
* Go to first unread
*
* @return void
*/
public function getNewComment()
{
/* Load request */
try
{
$request = \IPS\nexus\Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X208/L', 404, '' );
}
/* What order are we viewing? */
$order = isset( \IPS\Request::i()->cookie['support_replies_order'] ) ? mb_strtolower( \IPS\Request::i()->cookie['support_replies_order'] ) : 'desc';
/* Have we read it before? */
$timeLastRead = $request->timeLastRead();
if ( $timeLastRead instanceof \IPS\DateTime )
{
if( $unreadComment = $request->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead ) )
{
$where = array( array( 'reply_request=?', $request->id ) );
if ( $order === 'desc' )
{
$where[] = array( 'reply_id>?', $unreadComment->id );
}
else
{
$where[] = array( 'reply_id<?', $unreadComment->id );
}
$commentPosition = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', $where )->first();
$url = $request->acpUrl();
$page = ceil( $commentPosition / \IPS\nexus\Support\Request::getCommentsPerPage() );
if ( $page != 1 )
{
$url = $url->setQueryString( 'page', $page );
}
$url = $url->setFragment( "reply-{$unreadComment->id}" );
\IPS\Output::i()->redirect( $url );
}
else
{
\IPS\Output::i()->redirect( $request->acpUrl() );
}
}
/* Nope? Just go to the first message */
else
{
$url = $request->acpUrl();
if ( $order === 'desc' )
{
$lastPage = $request->commentPageCount();
if ( $lastPage != 1 )
{
$url = $url->setQueryString( 'page', $lastPage );
}
}
$firstMessage = $request->comments( 1, 0, 'date', 'asc', NULL, FALSE );
$url = $url->setFragment( "reply-{$firstMessage->id}" );
\IPS\Output::i()->redirect( $url );
}
}
/**
* Find a Comment
*
* @return void
*/
public function findComment()
{
/* Load request and comment */
try
{
$request = \IPS\nexus\Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
$comment = \IPS\nexus\Support\Reply::load( \IPS\Request::i()->comment );
if ( $comment->request != $request->id )
{
throw new \OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X208/M', 404, '' );
}
/* Find its position */
$order = isset( \IPS\Request::i()->cookie['support_replies_order'] ) ? mb_strtolower( \IPS\Request::i()->cookie['support_replies_order'] ) : 'desc';
$where = array( array( 'reply_request=?', $request->id ) );
if ( $order === 'desc' )
{
$where[] = array( 'reply_id>?', $comment->id );
}
else
{
$where[] = array( 'reply_id<?', $comment->id );
}
$commentPosition = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', $where )->first();
/* Redirect */
$url = $request->acpUrl();
$page = ceil( $commentPosition / \IPS\nexus\Support\Request::getCommentsPerPage() );
if ( $page != 1 )
{
$url = $url->setQueryString( 'page', $page );
}
$url = $url->setFragment( "reply-{$comment->id}" );
\IPS\Output::i()->redirect( $url );
}
/**
* Pending Response Send/Discard
*
@@ -318,7 +501,34 @@ class _request extends \IPS\nexus\modules\front\support\view
$message->delete();
}
\IPS\Output::i()->redirect( $message->item()->acpUrl()->setQueryString( array( 'filter' => \IPS\Request::i()->filter, 'sort' => \IPS\Request::i()->sort ) ) );
if ( isset( \IPS\Request::i()->department ) and \IPS\Request::i()->department != -1 )
{
$newDepartment = Support\Department::load( \IPS\Request::i()->department );
if ( $message->item()->department != $newDepartment )
{
$message->item()->log( 'department', $message->item()->department, $newDepartment );
$message->item()->department = $newDepartment;
}
}
if ( isset( \IPS\Request::i()->status ) and \IPS\Request::i()->status != -1 )
{
$message->item()->status = Support\Status::load( \IPS\Request::i()->status );
}
if ( isset( \IPS\Request::i()->staff ) and \IPS\Request::i()->staff != -1 )
{
$newStaff = \IPS\Request::i()->staff ? \IPS\Member::load( \IPS\Request::i()->staff ) : NULL;
if ( $message->item()->staff != $newStaff )
{
if ( $newStaff )
{
$message->item()->log( 'staff', $message->item()->staff, $newStaff );
}
$message->item()->staff = $newStaff;
}
}
$message->item()->save();
\IPS\Output::i()->redirect( $message->item()->acpUrl() );
}
catch ( \OutOfRangeException $e )
{
@@ -403,7 +613,7 @@ class _request extends \IPS\nexus\modules\front\support\view
try
{
/* Init */
$return = array();
$return = array( 'note_status' => \IPS\Request::i()->status );
$request = Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
$status = Support\Status::load( \IPS\Request::i()->status );
$oldStatus = $request->status;
@@ -418,12 +628,16 @@ class _request extends \IPS\nexus\modules\front\support\view
}
$request->staff = \IPS\Member::loggedIn();
$return['staff'] = array( 'id' => \IPS\Member::loggedIn()->member_id, 'name' => \IPS\Member::loggedIn()->name );
$return['note_assign_to'] = \IPS\Member::loggedIn()->member_id;
$return['staffBadge'] = \IPS\Member::loggedIn()->language()->addToStack( 'assigned_to_x', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('you') ) ) );
}
/* Or set the previous status was "Working", release our assigning */
elseif ( $oldStatus->assign and $request->staff )
{
$request->staff = NULL;
$return['staff'] = array( 'id' => 0, 'name' => \IPS\Member::loggedIn()->language()->addToStack('unassigned') );
$return['note_assign_to'] = 0;
$return['staffBadge'] = '';
}
$request->save();
@@ -434,6 +648,7 @@ class _request extends \IPS\nexus\modules\front\support\view
}
/* Return */
$return['statusBadge'] = \IPS\Theme::i()->getTemplate('support')->status( $request->status );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( $return );
@@ -465,7 +680,9 @@ class _request extends \IPS\nexus\modules\front\support\view
$request->save();
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array() );
$return = array();
$return['severityBadge'] = $request->severity->color != '000' ? \IPS\Theme::i()->getTemplate('support')->severity( $request->severity ) : '';
\IPS\Output::i()->json( $return );
}
\IPS\Output::i()->redirect( $request->acpUrl() );
}
@@ -548,7 +765,25 @@ class _request extends \IPS\nexus\modules\front\support\view
$stockActions[ $action->id ] = $action->_title;
}
\IPS\Output::i()->json( array( 'department' => \IPS\Request::i()->department, 'stockActions' => $stockActions, 'requiresPurchase' => (bool) $request->department->require_package ) );
$purchaseWarning = NULL;
if ( $request->department->packages )
{
if ( !$request->purchase )
{
$purchaseWarning = 'purchaseWarningNone';
}
elseif ( !$request->purchase->active )
{
$purchaseWarning = 'purchaseWarningInactive';
}
if ( $purchaseWarning )
{
$purchaseWarning .= ( $request->department->require_package ? 'Required' : 'Optional' );
}
}
\IPS\Output::i()->json( array( 'department' => \IPS\Request::i()->department, 'note_department' => \IPS\Request::i()->department, 'stockActions' => $stockActions, 'purchaseWarning' => $purchaseWarning ) );
}
\IPS\Output::i()->redirect( $request->acpUrl() );
}
@@ -574,7 +809,11 @@ class _request extends \IPS\nexus\modules\front\support\view
$request->save();
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'assign_to' => ( $request->staff_lock ? ( $request->staff ? $request->staff->member_id : 0 ) : 0 ) ) );
\IPS\Output::i()->json( array(
'assign_to' => ( $request->staff_lock ? ( $request->staff ? $request->staff->member_id : 0 ) : 0 ),
'note_assign_to' => $request->staff ? $request->staff->member_id : 0,
'staffBadge' => $request->staff ? \IPS\Member::loggedIn()->language()->addToStack( 'assigned_to_x', FALSE, array( 'sprintf' => array( $request->staff->name ) ) ) : ''
) );
}
\IPS\Output::i()->redirect( $request->acpUrl() );
}
@@ -634,12 +873,52 @@ class _request extends \IPS\nexus\modules\front\support\view
$request = Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Node( 'associated_purchase', $request->purchase, TRUE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => $request->author(), 'zeroVal' => 'none' ) ) );
$parentContacts = \IPS\nexus\Customer::load( $request->author()->member_id )->parentContacts();
if ( count( $parentContacts ) )
{
$form->class = 'ipsForm_vertical';
$options = array();
$toggles = array();
foreach ( $parentContacts as $contact )
{
$options[ $contact->main_id->member_id ] = $contact->main_id->cm_name;
$toggles[ $contact->main_id->member_id ] = array( 'associated_purchase_' . $contact->main_id->member_id );
}
$options[ $request->author()->member_id ] = $request->author()->name;
$toggles[ $request->author()->member_id ] = array( 'associated_purchase_' . $request->author()->member_id );
$form->add( new \IPS\Helpers\Form\Radio( 'support_account', $request->author()->member_id, TRUE, array( 'options' => $options, 'toggles' => $toggles, 'parse' => 'none' ) ) );
foreach ( $options as $memberId => $memberName )
{
$field = new \IPS\Helpers\Form\Node( 'associated_purchase_' . $memberId, $memberId == $request->author()->member_id ? $request->purchase : NULL, TRUE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => \IPS\Member::load( $memberId ), 'zeroVal' => 'none' ), NULL, NULL, NULL, 'associated_purchase_' . $memberId );
$field->label = \IPS\Member::loggedIn()->language()->addToStack('associated_purchase');
$form->add( $field );
}
}
else
{
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Node( 'associated_purchase', $request->purchase, TRUE, array( 'class' => 'IPS\nexus\Purchase', 'forceOwner' => $request->author(), 'zeroVal' => 'none' ) ) );
}
if ( $values = $form->values() )
{
$request->log( 'purchase', $request->purchase, $values['associated_purchase'] ?: NULL );
$request->purchase = $values['associated_purchase'] ?: NULL;
if ( isset( $values['support_account'] ) )
{
if ( $values['support_account'] != $request->member )
{
\IPS\Db::i()->update( 'nexus_support_replies', array( 'reply_type' => \IPS\nexus\Support\Reply::REPLY_MEMBER ), array( 'reply_request=? AND reply_member=?', $request->id, $values['support_account'] ) );
\IPS\Db::i()->update( 'nexus_support_replies', array( 'reply_type' => \IPS\nexus\Support\Reply::REPLY_ALTCONTACT ), array( 'reply_request=? AND reply_member=?', $request->id, $request->member ) );
$request->member = $values['support_account'];
}
$request->log( 'purchase', $request->purchase, $values[ 'associated_purchase_' . $values['support_account'] ] ?: NULL );
$request->purchase = $values[ 'associated_purchase_' . $values['support_account'] ] ?: NULL;
}
else
{
$request->log( 'purchase', $request->purchase, $values['associated_purchase'] ?: NULL );
$request->purchase = $values['associated_purchase'] ?: NULL;
}
$request->save();
\IPS\Output::i()->redirect( $request->acpUrl() );
}
@@ -673,6 +952,114 @@ class _request extends \IPS\nexus\modules\front\support\view
}
}
/**
* Multimod
*
* @return void
*/
protected function multimod()
{
/* CSRF check */
\IPS\Session::i()->csrfCheck();
/* Load request */
$request = Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
/* Are we going to leave any messages in the request? */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', array( array( 'reply_request=? AND reply_hidden=0', $request->id ), \IPS\Db::i()->in( 'reply_id', array_keys( \IPS\Request::i()->multimod ), TRUE ) ) )->first();
if ( !$count )
{
\IPS\Output::i()->error( 'can_not_multimod_all', '1X208/H', 403, '' );
}
/* Splitting? */
if ( \IPS\Request::i()->modaction === 'split' )
{
/* Permission check */
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_split' );
/* Check we're not trying to split notes only */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', array( array( 'reply_hidden=0', $request->id ), \IPS\Db::i()->in( 'reply_id', array_keys( \IPS\Request::i()->multimod ) ) ) )->first();
if ( !$count )
{
\IPS\Output::i()->error( 'can_not_split_notes_only', '1S208/J', 403, '' );
}
/* Create form */
$url = $request->acpUrl()->setQueryString( array( 'do' => 'multimod', 'modaction' => 'split', 'multimod' => \IPS\Request::i()->multimod ) )->csrf();
$form = new \IPS\Helpers\Form( 'split_form', 'split', $url, array( 'data-controller' => 'nexus.admin.support.splitForm' ) );
$form->add( new \IPS\Helpers\Form\Text( 'support_title', sprintf( \IPS\Member::loggedIn()->language()->get( 'split_request_title' ), $request->title, $request->id ), TRUE ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_department', $request->department, TRUE, array( 'class' => 'IPS\nexus\Support\Department', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'r_status', $request->status, TRUE, array( 'class' => 'IPS\nexus\Support\Status', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_severity', $request->severity, TRUE, array( 'class' => 'IPS\nexus\Support\Severity', 'url' => $url ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', $request->staff ? $request->staff->member_id : 0, FALSE, array( 'options' => array( 0 => 'unassigned' ) + \IPS\nexus\Support\Request::staff() ) ) );
if ( $values = $form->values() )
{
$newRequest = new \IPS\nexus\Support\Request;
$newRequest->title = $values['support_title'];
$newRequest->member = $request->member;
$newRequest->email = $request->email;
$newRequest->department = $values['support_department'];
if ( $request->purchase )
{
$newRequest->purchase = $request->purchase;
}
$newRequest->status = $values['r_status'];
$newRequest->severity = $values['support_severity'];
if ( $values['r_staff'] )
{
$newRequest->staff = \IPS\Member::load( $values['r_staff']);
}
$newRequest->cfields = $request->cfields;
$newRequest->notify = $request->notify;
$newRequest->save();
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_support_replies', array( array( 'reply_request=?', $request->id ), \IPS\Db::i()->in( 'reply_id', array_keys( \IPS\Request::i()->multimod ) ) ) ), 'IPS\nexus\Support\Reply' ) as $comment )
{
$comment->move( $newRequest );
}
$request->rebuildFirstAndLastCommentData();
$newRequest->rebuildFirstAndLastCommentData();
$request->log( 'split_away', $request, $newRequest );
$newRequest->log( 'split_new', $request, $newRequest );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'oldUrl' => (string) $request->acpUrl(), 'newUrl' => (string) $newRequest->acpUrl() ) );
}
else
{
\IPS\Output::i()->redirect( $newRequest->acpUrl() );
}
}
\IPS\Output::i()->output = $form;
}
/* Or deleting? */
elseif ( \IPS\Request::i()->modaction === 'delete' )
{
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_reply_delete' );
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_support_replies', array( array( 'reply_request=?', $request->id ), \IPS\Db::i()->in( 'reply_id', array_keys( \IPS\Request::i()->multimod ) ) ) ), 'IPS\nexus\Support\Reply' ) as $comment )
{
$comment->delete();
}
$request->rebuildFirstAndLastCommentData();
\IPS\Output::i()->redirect( $request->acpUrl() );
}
else
{
\IPS\Output::i()->error( 'generic_error', '3X208/I', 403, '' );
}
}
/**
* Delete
*
@@ -682,9 +1069,13 @@ class _request extends \IPS\nexus\modules\front\support\view
{
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$request = Support\Request::loadAndCheckPerms( \IPS\Request::i()->id );
\IPS\Session::i()->log( 'acplogs__deleted_request', array( $request->id => FALSE ) );
$request->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=nexus&module=support&controller=requests" ) );
}
@@ -703,9 +1094,13 @@ class _request extends \IPS\nexus\modules\front\support\view
{
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_reply_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$reply = Support\Reply::loadAndCheckPerms( \IPS\Request::i()->id );
\IPS\Session::i()->log( 'acplogs__deleted_reply', array( $reply->id => FALSE ) );
$reply->delete();
\IPS\Output::i()->redirect( $reply->item()->acpUrl() );
}
@@ -745,4 +1140,25 @@ class _request extends \IPS\nexus\modules\front\support\view
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->feedback( $rating );
}
/**
* Get default action
*
* @return string
*/
public static function defaultReplyAction()
{
$defaultAction = NULL;
try
{
$defaultAction = \IPS\Db::i()->select( 'action', 'nexus_support_staff_preferences', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ) )->first();
}
catch ( \UnderflowException $e ) {}
if ( !$defaultAction )
{
$defaultAction = isset( \IPS\Request::i()->cookie['support_primary_action'] ) ? \IPS\Request::i()->cookie['support_primary_action'] : 'first';
}
return $defaultAction;
}
}
@@ -2,9 +2,9 @@
/**
* @brief Support Requests
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 09 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -38,6 +38,8 @@ class _requests extends \IPS\Dispatcher\Controller
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'support_responsive.css', 'nexus', 'admin' ) );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_support.js', 'nexus', 'admin' ) );
\IPS\Dispatcher::i()->checkAcpPermission( 'requests_manage' );
parent::execute();
}
@@ -61,93 +63,143 @@ class _requests extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'err_no_departments_with_perm2', '1X261/2', 403, '' );
}
}
/* URL */
$url = \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests' );
$customer = NULL;
$where = array();
if ( isset( \IPS\Request::i()->member ) )
{
try
{
$customer = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
$url = $url->setQueryString( 'member', $customer->member_id );
$where[] = array( 'r_member=?', $customer->member_id );
}
catch ( \OutOfRangeException $e ) { }
}
/* Permissions */
$where[] = array( "( dpt_staff='*' OR " . \IPS\Db::i()->findInSet( 'dpt_staff', \IPS\nexus\Support\Department::staffDepartmentPerms() ) . ')' );
/* Filters */
if ( isset( \IPS\Request::i()->assigned ) )
{
$where[] = array( 'r_staff=?', \IPS\Member::loggedIn()->member_id );
}
if ( isset( \IPS\Request::i()->tracked ) )
{
$where[] = array( 'request_id IS NOT NULL' );
}
if ( isset( \IPS\Request::i()->replied ) )
{
$where[] = array( 'r_id IN(?)', \IPS\Db::i()->select( 'DISTINCT(reply_request)', 'nexus_support_replies', array( 'reply_member=?', \IPS\Member::loggedIn()->member_id ) ) );
}
/* Departments / Statuses */
$myFilters = \IPS\nexus\Support\Request::myFilters();
if ( isset( \IPS\Request::i()->departments ) or isset( \IPS\Request::i()->statuses ) )
{
$newFilters = array( 'departments' => isset( \IPS\Request::i()->departments ) ? explode( ',', \IPS\Request::i()->departments ) : $myFilters['departments'], 'statuses' => isset( \IPS\Request::i()->statuses ) ? explode( ',', \IPS\Request::i()->statuses ) : $myFilters['statuses'] );
\IPS\Request::i()->setCookie( 'support_filters', json_encode( $newFilters ), \IPS\DateTime::create()->add( new \DateInterval( 'P1Y' ) ) );
$myFilters = \IPS\nexus\Support\Request::myFilters( $newFilters );
}
$where[] = $myFilters['whereClause'];
/* Create the table */
$table = \IPS\nexus\Support\Request::table( $url, $where );
$table->classes[] = 'cNexusSupportTable';
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'support', 'nexus', 'admin' ), 'requestTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'support', 'nexus', 'admin' ), 'requestRows' );
/* Search */
$table->quickSearch = 'r_title';
$table->advancedSearch = array(
'r_title_or_message'=> array( \IPS\Helpers\Table\SEARCH_CUSTOM, array(
'getHtml' => function( $field )
{
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->text( $field->name, 'text', $field->value, $field->required );
}
), function( $v )
{
return array( 'r_title LIKE ? OR ' . \IPS\Db::i()->in( 'r_id', \IPS\Db::i()->select( 'reply_request', 'nexus_support_replies', array( "MATCH(reply_post) AGAINST (? IN BOOLEAN MODE)", $v ) ) ), '%' . $v . '%' );
} ),
'r_severity' => array( \IPS\Helpers\Table\SEARCH_NODE, array( 'class' => 'IPS\nexus\Support\Severity', 'multiple' => TRUE ) ),
'r_department' => array( \IPS\Helpers\Table\SEARCH_NODE, array( 'class' => 'IPS\nexus\Support\Department', 'multiple' => TRUE ) ),
'r_member' => \IPS\Helpers\Table\SEARCH_MEMBER,
'r_email' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'r_replies' => \IPS\Helpers\Table\SEARCH_NUMERIC,
'r_started' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'r_last_new_reply' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'r_last_reply' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'r_last_reply_by' => \IPS\Helpers\Table\SEARCH_MEMBER,
'r_last_staff_reply'=> \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'r_status' => array( \IPS\Helpers\Table\SEARCH_NODE, array( 'class' => 'IPS\nexus\Support\Status', 'multiple' => TRUE ) ),
'r_staff' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => \IPS\nexus\Support\Request::staff(), 'multiple' => TRUE, 'noDefault' => TRUE ) ),
);
/* Permissions */
$where = array();
$where[] = array( "( dpt_staff='*' OR " . \IPS\Db::i()->findInSet( 'dpt_staff', \IPS\nexus\Support\Department::staffDepartmentPerms() ) . ')' );
/* Get my stream */
$stream = NULL;
if ( isset( \IPS\Request::i()->cookie['support_stream'] ) or isset( \IPS\Request::i()->stream ) or isset( \IPS\Request::i()->member ) )
{
if ( isset( \IPS\Request::i()->member ) )
{
try
{
$customer = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
$stream = \IPS\nexus\Support\Stream::customer( $customer );
$stream->temporary = TRUE;
$stream->owner = \IPS\Member::loggedIn()->member_id;
$stream->save();
\IPS\Request::i()->setCookie( 'support_stream', $stream->id, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
\IPS\Db::i()->delete( 'nexus_support_streams', array( 'stream_owner=? AND stream_temporary=1 AND stream_id<>?', \IPS\Member::loggedIn()->member_id, $stream->id ) );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X261/4', 404, '' );
}
}
else
{
$streamId = isset( \IPS\Request::i()->stream ) ? \IPS\Request::i()->stream : \IPS\Request::i()->cookie['support_stream'];
try
{
$stream = \IPS\nexus\Support\Stream::load( $streamId );
if ( isset( \IPS\Request::i()->stream ) )
{
\IPS\Request::i()->setCookie( 'support_stream', $streamId, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
\IPS\Db::i()->delete( 'nexus_support_streams', array( 'stream_owner=? AND stream_temporary=1 AND stream_id<>?', \IPS\Member::loggedIn()->member_id, $streamId ) );
}
}
catch ( \OutOfRangeException $e ) { }
}
}
$stream = $stream ?: \IPS\nexus\Support\Stream::load('open');
/* Are we grouping by department? */
if ( isset( \IPS\Request::i()->groupByDepartment ) )
{
if ( \IPS\Request::i()->groupByDepartment )
{
\IPS\Request::i()->setCookie( 'support_dpt_group', 1, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
else
{
\IPS\Request::i()->setCookie( 'support_dpt_group', 0, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
}
$groupByDepartment = ( isset( \IPS\Request::i()->cookie['support_dpt_group'] ) and \IPS\Request::i()->cookie['support_dpt_group'] );
/* What's our order? */
if ( \IPS\Request::i()->sortBy )
{
\IPS\Request::i()->setCookie( 'support_sort', \IPS\Request::i()->sortBy, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
if ( \IPS\Request::i()->sortDir )
{
\IPS\Request::i()->setCookie( 'support_order', \IPS\Request::i()->sortDir, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
if ( isset( \IPS\Request::i()->honorSeverities ) )
{
\IPS\Request::i()->setCookie( 'support_honor_severities', \IPS\Request::i()->honorSeverities, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
$order = array();
if ( $groupByDepartment )
{
$order[] = 'dpt_position';
}
$honorSeverities = ( !isset( \IPS\Request::i()->cookie['support_honor_severities'] ) or \IPS\Request::i()->cookie['support_honor_severities'] );
if ( $honorSeverities )
{
$order[] = 'sev_position ASC';
}
$sortBy = ( isset( \IPS\Request::i()->cookie['support_sort'] ) and in_array( \IPS\Request::i()->cookie['support_sort'], array( 'r_started', 'r_last_new_reply', 'r_last_reply', 'r_last_staff_reply' ) ) ) ? \IPS\Request::i()->cookie['support_sort'] : 'r_last_new_reply';
$sortDir = ( isset( \IPS\Request::i()->cookie['support_order'] ) and in_array( \IPS\Request::i()->cookie['support_order'], array( 'ASC', 'DESC' ) ) ) ? \IPS\Request::i()->cookie['support_order'] : 'ASC';
$order[] = $sortBy . ' ' . $sortDir;
$order = implode( ', ', $order );
/* Get the results and pagination */
$perPage = 25;
$count = $stream->count( \IPS\Member::loggedIn() );
$numberOfPages = ceil( $count / $perPage );
$page = ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page <= $numberOfPages ) ? intval( \IPS\Request::i()->page ) : 1;
$results = $stream->results( \IPS\Member::loggedIn(), $order, $page, $perPage );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( \IPS\Http\Url::internal('app=nexus&module=support&controller=requests'), $numberOfPages, $page, $perPage );
/* Are any of those tracked/participated in? */
$supportRequestsInView = array_keys( iterator_to_array( $results ) );
$tracked = iterator_to_array( \IPS\Db::i()->select( array( 'request_id', 'notify' ), 'nexus_support_tracker', array( array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'request_id', $supportRequestsInView ) ) ) )->setKeyField( 'request_id' )->setValueField( 'notify' ) );
$participatedIn = iterator_to_array( \IPS\Db::i()->select( 'DISTINCT reply_request', 'nexus_support_replies', array( array( 'reply_member=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'reply_request', $supportRequestsInView ) ) ) ) );
/* Filter form */
$form = \IPS\nexus\Support\Stream::load('open')->form( $stream, \IPS\Http\Url::internal('app=nexus&module=support&controller=requests') );
if ( $values = $form->values() )
{
if ( $values['stream'] == 'custom' )
{
\IPS\Db::i()->delete( 'nexus_support_streams', array( 'stream_owner=? AND stream_temporary=1', \IPS\Member::loggedIn()->member_id ) );
$stream = \IPS\nexus\Support\Stream::createFromForm( $values );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&stream=') . $stream->id );
}
else
{
\IPS\Request::i()->setCookie( 'support_stream', $values['stream'], \IPS\DateTime::create()->add( new \DateInterval( 'P1Y') ), FALSE );
}
}
$form = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'support' ) ), 'filterForm' ) );
/* Display */
\IPS\Output::i()->title = $customer ? \IPS\Member::loggedIn()->language()->addToStack( 'members_support_requests', FALSE, array( 'sprintf' => array( $customer->cm_name ) ) ) : \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_support_requests');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array(
'form' => $form,
'results' => \IPS\Theme::i()->getTemplate( 'support' )->requestsTable( $results, $pagination, $groupByDepartment, $sortBy, $sortDir, $tracked, $participatedIn, $honorSeverities )
) );
return;
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_support_requests');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'support' )->requests( $form, $stream, $results, $pagination, $groupByDepartment, $sortBy, $sortDir, $tracked, $participatedIn, $honorSeverities );
}
/* Create Button */
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'support', 'requests_create' ) )
{
$createUrl = \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=create&_new=1');
if ( $customer )
{
$createUrl = $createUrl->setQueryString( 'member', $customer->member_id );
}
\IPS\Output::i()->sidebar['actions']['create'] = array(
'icon' => 'plus',
'title' => 'add',
@@ -156,40 +208,211 @@ class _requests extends \IPS\Dispatcher\Controller
}
/* Settings */
\IPS\Output::i()->sidebar['actions']['notifications'] = array(
'icon' => 'envelope',
'title' => 'my_notifications',
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=notifications'),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('my_notifications') )
\IPS\Output::i()->sidebar['actions']['my_preferences'] = array(
'icon' => 'cog',
'title' => 'my_preferences',
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=preferences'),
);
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'support', 'support_display_settings' ) )
/* History Button */
\IPS\Output::i()->sidebar['actions']['history'] = array(
'icon' => 'clock-o',
'title' => 'my_history',
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=history'),
);
}
/**
* Filter form
*
* @return \IPS\Helpers\Form
*/
protected function filters()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__nexus_support_requests');
\IPS\Output::i()->output = \IPS\nexus\Support\Stream::load('open')->form( NULL, \IPS\Http\Url::internal('app=nexus&module=support&controller=requests') )->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'support' ) ), 'filterForm' ) );
}
/**
* Save a temporary stream
*
* @return void
*/
protected function saveStream()
{
if ( isset( \IPS\Request::i()->stream_title ) )
{
\IPS\Output::i()->sidebar['actions']['settings'] = array(
'icon' => 'cog',
'title' => 'display_settings',
'link' => \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=settings'),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('display_settings') )
);
\IPS\Db::i()->update( 'nexus_support_streams', array(
'stream_title' => \IPS\Request::i()->stream_title,
'stream_temporary' => 0
), array( 'stream_owner=? AND stream_temporary=1', \IPS\Member::loggedIn()->member_id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=requests' ) );
}
else
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'stream_title', '', TRUE ) );
\IPS\Output::i()->output = $form;
}
}
/**
* Reset my departments
* Edit a saved stream
*
* @return void
* @return void
*/
protected function resetMyDepartments()
protected function editStream()
{
\IPS\Request::i()->setCookie( 'support_filters', '', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=requests') );
try
{
$stream = \IPS\nexus\Support\Stream::load( \IPS\Request::i()->id );
if ( $stream->temporary or $stream->owner != \IPS\Member::loggedIn()->member_id )
{
throw new \OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2X261/3', 404, '' );
}
$form = $stream->form( $stream, \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests&do=editStream&id=' . $stream->id ) );
$form->addTab('title');
$form->add( new \IPS\Helpers\Form\Text( 'stream_title', $stream->title, TRUE ) );
$form->addButton( 'delete', 'submit', NULL, 'ipsButton ipsButton_light', array( 'name' => 'deleteButton', 'value' => 1 ) );
if ( $values = $form->values() )
{
if ( isset( \IPS\Request::i()->deleteButton ) and \IPS\Request::i()->deleteButton )
{
$stream->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests' ) );
}
else
{
$stream->title = $values['stream_title'];
$stream->updateFromForm( $values );
$stream->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests&stream=' . $stream->id ) );
}
}
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'support' ) ), 'filterForm' ) );
}
/**
* My Notifications
* Multimod
*
* @return void
*/
protected function notifications()
protected function multimod()
{
\IPS\Session::i()->csrfCheck();
$notices = array();
/* Tracking? */
if ( \IPS\Request::i()->modaction === 'track_off' )
{
\IPS\Db::i()->delete( 'nexus_support_tracker', array( array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'request_id', array_keys( \IPS\Request::i()->multimod ) ) ) ) );
}
elseif ( \IPS\Request::i()->modaction === 'track_on' or \IPS\Request::i()->modaction === 'track_notify' )
{
foreach ( array_keys( \IPS\Request::i()->multimod ) as $requestId )
{
\IPS\Db::i()->insert( 'nexus_support_tracker', array(
'member_id' => \IPS\Member::loggedIn()->member_id,
'request_id' => $requestId,
'notify' => \IPS\Request::i()->modaction === 'track_notify'
), TRUE );
}
}
/* Everything else requires a loop... */
else
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_support_requests', \IPS\Db::i()->in( 'r_id', array_keys( \IPS\Request::i()->multimod ) ) ), 'IPS\nexus\Support\Request' ) as $request )
{
if ( $request->canView() )
{
/* Set status */
if ( mb_substr( \IPS\Request::i()->modaction, 0, 7 ) === 'status_' )
{
/* Set it */
$status = \IPS\nexus\Support\Status::load( mb_substr( \IPS\Request::i()->modaction, 7 ) );
$oldStatus = $request->status;
$request->status = $status;
/* Assign it if we have to */
if ( $status->assign )
{
if ( $request->staff and $request->staff->member_id != \IPS\Member::loggedIn()->member_id )
{
$notices[] = \IPS\Member::loggedIn()->language()->addToStack( 'you_have_stolen_request_multimod', FALSE, array( 'sprintf' => array( $request->id, $request->staff->name ) ) );
}
$request->staff = \IPS\Member::loggedIn();
}
/* Or set the previous status was "Working", release our assigning */
elseif ( $oldStatus->assign and $request->staff )
{
$request->staff = NULL;
}
/* Save and Log */
$request->save();
if ( $status->log )
{
$request->log( 'status', $oldStatus, $status );
}
}
/* Set severity */
elseif ( mb_substr( \IPS\Request::i()->modaction, 0, 9 ) === 'severity_' )
{
$new = \IPS\nexus\Support\Severity::load( mb_substr( \IPS\Request::i()->modaction, 9 ) );
$request->log( 'severity', $request->severity, $new );
$request->severity = $new;
$request->save();
}
/* Set department */
elseif ( mb_substr( \IPS\Request::i()->modaction, 0, 11 ) === 'department_' )
{
$new = \IPS\nexus\Support\Department::load( mb_substr( \IPS\Request::i()->modaction, 11 ) );
$request->log( 'department', $request->department, $new );
$request->department = $new;
$request->save();
}
/* Assign */
elseif ( mb_substr( \IPS\Request::i()->modaction, 0, 6 ) === 'staff_' )
{
$staff = mb_substr( \IPS\Request::i()->modaction, 6 );
$new = $staff ? \IPS\Member::load( $staff ) : NULL;
$request->log( 'staff', $request->staff, $new );
$request->staff = $new;
$request->save();
}
/* Delete? */
elseif ( \IPS\Request::i()->modaction === 'delete' and \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'support', 'requests_delete' ) )
{
$request->delete();
}
}
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=nexus&module=support&controller=requests' ), implode( ', ', $notices ) );
}
/**
* My Preferences
*
* @return void
*/
protected function preferences()
{
$types = array( 'support_notify_new' => 'n', 'support_notify_replies' => 'r', 'support_notify_assign' => 'a' );
@@ -202,15 +425,76 @@ class _requests extends \IPS\Dispatcher\Controller
}
$form = new \IPS\Helpers\Form;
$form->addMessage( 'support_notify_blurb' );
$form->addHeader('my_preferences');
try
{
$preferences = \IPS\Db::i()->select( '*', 'nexus_support_staff_preferences', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ) )->first();
}
catch ( \UnderflowException $e )
{
$preferences = NULL;
}
$form->add( new \IPS\Helpers\Form\Editor( 'nexus_default_support_content', $preferences ? $preferences['content'] : NULL, FALSE, array( 'app' => 'nexus', 'key' => 'Support', 'autoSaveKey' => 'default_content', 'tags' => array(
'{customer_first_name}' => \IPS\Member::loggedIn()->language()->addToStack('customer_first_name'),
'{customer_last_name}' => \IPS\Member::loggedIn()->language()->addToStack('customer_first_name'),
'{customer_full_name}' => \IPS\Member::loggedIn()->language()->addToStack('customer_full_name'),
'{department_name}' => \IPS\Member::loggedIn()->language()->addToStack('department_name'),
'{department_email}' => \IPS\Member::loggedIn()->language()->addToStack('department_email'),
) ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'nexus_default_support_action', $preferences ? $preferences['action'] : '', FALSE, array( 'options' => array(
'' => 'reply_remember_last',
'first' => 'reply_and_go_to_first',
'stay' => 'reply_and_stay',
'next' => 'reply_and_go_to_next',
'list' => 'reply_and_go_to_list',
) ) ) );
$_myDepartments = iterator_to_array( \IPS\nexus\Support\Department::departmentsWithPermission() );
$myOrder = array();
foreach ( \IPS\Db::i()->select( array( 'department_id' ), 'nexus_support_staff_dpt_order', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ), 'dpt_position ASC' ) as $departmentId )
{
if ( array_key_exists( $departmentId, $_myDepartments ) )
{
$myOrder[ $departmentId ] = $_myDepartments[ $departmentId ]->_title;
}
}
foreach( $_myDepartments as $department )
{
if ( !array_key_exists( $department->id, $myOrder ) )
{
$myOrder[ $department->id ] = $department->_title;
}
}
$form->add( new \IPS\Helpers\Form\Sort( 'nexus_group_departments_order', $myOrder, FALSE ) );
$form->addHeader('notify_me_when');
$form->addMessage( 'support_notify_blurb' );
foreach ( $types as $k => $t )
{
$form->add( new \IPS\Helpers\Form\Select( $k, isset( $existing[ $t ] ) ? ( $existing[ $t ] === '*' ? 0 : explode( ',', $existing[ $t ] ) ) : NULL, FALSE, array( 'options' => $myDepartments, 'multiple' => TRUE, 'unlimited' => 0, 'unlimitedLang' => 'all' ) ) );
$form->add( new \IPS\Helpers\Form\Select( $k, isset( $existing[ $t ] ) ? ( $existing[ $t ] === '*' ? 0 : explode( ',', $existing[ $t ] ) ) : NULL, FALSE, array( 'options' => $myDepartments, 'multiple' => TRUE, 'unlimited' => 0, 'unlimitedLang' => 'all', 'noDefault' => TRUE ) ) );
}
if ( $values = $form->values() )
{
\IPS\Db::i()->insert( 'nexus_support_staff_preferences', array(
'staff_id' => \IPS\Member::loggedIn()->member_id,
'content' => $values['nexus_default_support_content'],
'action' => $values['nexus_default_support_action'],
), TRUE );
\IPS\Db::i()->delete( 'nexus_support_staff_dpt_order', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ) );
$i = 1;
foreach ( $values['nexus_group_departments_order'] as $k => $v )
{
\IPS\Db::i()->insert( 'nexus_support_staff_dpt_order', array(
'staff_id' => \IPS\Member::loggedIn()->member_id,
'department_id' => $k,
'dpt_position' => $i++,
) );
}
\IPS\Db::i()->delete( 'nexus_support_notify', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ) );
foreach ( $types as $k => $t )
@@ -228,72 +512,10 @@ class _requests extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal("app=nexus&module=support&controller=requests") );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('my_notifications');
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('my_preferences');
\IPS\Output::i()->output = $form;
}
/**
* Display Settings
*
* @return void
*/
protected function settings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'support_display_settings' );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Custom( 'support_old_highlight', array( \IPS\Settings::i()->support_old_stat, \IPS\Settings::i()->support_old_number ), FALSE, array(
'getHtml' => function( $obj )
{
$number = \IPS\Settings::i()->support_old_number;
$numberType = $number ? 'minutes' : 'hours';
if ( $number % 1440 === 0 )
{
$number /= 1440; # Fun fact: that's the first time I've used that operator
$numberType = 'days';
}
elseif ( $number % 60 === 0 )
{
$number /= 60; # Fun fact: that's the second time I've used that operator
$numberType = 'hours';
}
return \IPS\Theme::i()->getTemplate('support')->highlightSetting( $obj->name, $obj->value[0], $number, $numberType );
}
) ) );
if ( $values = $form->values() )
{
$save = array();
if ( isset( $values['support_old_highlight'][3] ) )
{
$save['support_old_number'] = 0;
}
else
{
$save['support_old_stat'] = $values['support_old_highlight'][0];
switch ( $values['support_old_highlight'][2] )
{
case 'minutes':
$save['support_old_number'] = $values['support_old_highlight'][1];
break;
case 'hours':
$save['support_old_number'] = $values['support_old_highlight'][1] * 60;
break;
case 'days':
$save['support_old_number'] = $values['support_old_highlight'][1] * 1440;
break;
}
}
$form->saveAsSettings( $save );
\IPS\Session::i()->log( 'acplogs__support_display_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests' ), 'saved' );
}
\IPS\Output::i()->output = $form;
}
/**
* Create
*
@@ -306,50 +528,53 @@ class _requests extends \IPS\Dispatcher\Controller
$steps = array();
/* Owner */
$steps['request_owner'] = function( $data )
if ( !isset( \IPS\Request::i()->member ) )
{
$form = new \IPS\Helpers\Form( 'owner', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'request_owner_type', 'member', TRUE, array(
'options' => array( 'member' => 'request_owner_member', 'email' => 'request_owner_email' ),
'toggles' => array( 'member' => array( 'request_owner_member' ), 'email' => array( 'request_owner_email' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Member( 'request_owner_member', isset( \IPS\Request::i()->member ) ? \IPS\Member::load( \IPS\Request::i()->member ) : NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_member' ) );
$form->add( new \IPS\Helpers\Form\Email( 'request_owner_email', NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_email' ) );
if ( $values = $form->values() )
$steps['request_owner'] = function( $data )
{
if ( $values['request_owner_type'] === 'member' )
$form = new \IPS\Helpers\Form( 'owner', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'request_owner_type', 'member', TRUE, array(
'options' => array( 'member' => 'request_owner_member', 'email' => 'request_owner_email' ),
'toggles' => array( 'member' => array( 'request_owner_member' ), 'email' => array( 'request_owner_email' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Member( 'request_owner_member', isset( \IPS\Request::i()->member ) ? \IPS\Member::load( \IPS\Request::i()->member ) : NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_member' ) );
$form->add( new \IPS\Helpers\Form\Email( 'request_owner_email', NULL, FALSE, array(), NULL, NULL, NULL, 'request_owner_email' ) );
if ( $values = $form->values() )
{
if ( !$values['request_owner_member'] )
if ( $values['request_owner_type'] === 'member' )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('request_owner_req');
return (string) $form;
}
$data['member'] = $values['request_owner_member']->member_id;
}
else
{
if ( !$values['request_owner_email'] )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('request_owner_req');
return (string) $form;
}
$member = \IPS\Member::load( $values['request_owner_email'], 'email' );
if ( $member->member_id )
{
$data['member'] = $member->member_id;
if ( !$values['request_owner_member'] )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('request_owner_req');
return (string) $form;
}
$data['member'] = $values['request_owner_member']->member_id;
}
else
{
$data['email'] = $values['request_owner_email'];
if ( !$values['request_owner_email'] )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('request_owner_req');
return (string) $form;
}
$member = \IPS\Member::load( $values['request_owner_email'], 'email' );
if ( $member->member_id )
{
$data['member'] = $member->member_id;
}
else
{
$data['email'] = $values['request_owner_email'];
}
}
return $data;
}
return $data;
}
return (string) $form;
};
return (string) $form;
};
}
/* Stock Actions */
$stockActions = \IPS\nexus\Support\StockAction::roots();
@@ -380,6 +605,11 @@ class _requests extends \IPS\Dispatcher\Controller
/* Request Details */
$steps['request_details'] = function( $data ) use ( $stockActions )
{
if ( !isset( $data['member'] ) AND isset( \IPS\Request::i()->member ) )
{
$data['member'] = \IPS\Request::i()->member;
}
$stockAction = NULL;
if ( isset( $data['stock_action'] ) and isset( $stockActions[ $data['stock_action'] ] ) )
{
@@ -395,7 +625,7 @@ class _requests extends \IPS\Dispatcher\Controller
}
$form->add( new \IPS\Helpers\Form\Node( 'r_status', $stockAction ? $stockAction->status : \IPS\nexus\Support\Status::load( TRUE, 'status_default_staff' ), TRUE, array( 'class' => 'IPS\nexus\Support\Status' ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'support_severity', \IPS\nexus\Support\Severity::load( TRUE, 'sev_default' ), TRUE, array( 'class' => 'IPS\nexus\Support\Severity' ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', 0, FALSE, array( 'options' => array_merge( array( 0 => '' ), \IPS\nexus\Support\Request::staff() ) ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'r_staff', 0, FALSE, array( 'options' => array( 0 => 'unassigned' ) + \IPS\nexus\Support\Request::staff() ) ) );
if ( $values = $form->values() )
{
$data['title'] = $values['support_title'];
@@ -449,11 +679,35 @@ class _requests extends \IPS\Dispatcher\Controller
$stockAction = $stockActions[ $data['stock_action'] ];
}
$department = \IPS\nexus\Support\Department::load( $data['department'] );
try
{
$owner = isset( $data['member'] ) ? \IPS\nexus\Customer::load( $data['member'] ) : NULL;
$defaultContent = \IPS\Db::i()->select( 'content', 'nexus_support_staff_preferences', array( 'staff_id=?', \IPS\Member::loggedIn()->member_id ) )->first();
$defaultContent = str_replace(
array( '{customer_first_name}', '{customer_last_name}', '{customer_full_name}', '{department_name}', '{department_email}' ),
array(
$owner ? $owner->cm_first_name : '',
$owner ? $owner->cm_last_name : '',
$owner ? $owner->cm_name : $data['email'],
$department->_title,
$department->email
),
$defaultContent
);
}
catch ( \UnderflowException $e )
{
$defaultContent = NULL;
}
$form = new \IPS\Helpers\Form( 'your_message' );
$form->add( new \IPS\Helpers\Form\Email( 'to', isset( $data['member'] ) ? \IPS\Member::load( $data['member'] )->email : $data['email'] ) );
$form->add( new \IPS\Helpers\Form\Text( 'cc', array(), FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'forceLower' => TRUE ) ), array( 'IPS\nexus\Support\Request', '_validateEmail' ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'bcc', array(), FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'forceLower' => TRUE ) ), array( 'IPS\nexus\Support\Request', '_validateEmail' ) ) );
$form->add( new \IPS\Helpers\Form\Editor( 'message', $stockAction ? $stockAction->message : NULL, TRUE, array( 'app' => 'nexus', 'key' => 'Support', 'autoSaveKey' => md5( "new-req-message" ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'support_email_customer', TRUE, TRUE, array( 'togglesOn' => array( 'support_create_to', 'support_create_cc', 'support_create_bcc' ) ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'to', isset( $data['member'] ) ? \IPS\Member::load( $data['member'] )->email : $data['email'], NULL, array(), NULL, NULL, NULL, 'support_create_to' ) );
$form->add( new \IPS\Helpers\Form\Text( 'cc', array(), FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'forceLower' => TRUE ) ), array( 'IPS\nexus\Support\Request', '_validateEmail' ), NULL, NULL, 'support_create_cc' ) );
$form->add( new \IPS\Helpers\Form\Text( 'bcc', array(), FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'forceLower' => TRUE ) ), array( 'IPS\nexus\Support\Request', '_validateEmail' ), NULL, NULL, 'support_create_bcc' ) );
$form->add( new \IPS\Helpers\Form\Editor( 'message', $stockAction ? $stockAction->message : $defaultContent, TRUE, array( 'app' => 'nexus', 'key' => 'Support', 'autoSaveKey' => "new-req-message", 'defaultIfNoAutoSave' => TRUE ) ) );
if ( $values = $form->values() )
{
$request = new \IPS\nexus\Support\Request;
@@ -467,7 +721,7 @@ class _requests extends \IPS\Dispatcher\Controller
{
$request->email = $data['email'];
}
$request->department = \IPS\nexus\Support\Department::load( $data['department'] );
$request->department = $department;
if ( isset( $data['purchase'] ) and $data['purchase'] )
{
$request->purchase = \IPS\nexus\Purchase::load( $data['purchase'] );
@@ -481,10 +735,17 @@ class _requests extends \IPS\Dispatcher\Controller
if ( isset( $data['custom_fields'] ) )
{
$cfields = array();
$customFieldObjects = \IPS\nexus\Support\CustomField::roots();
foreach ( $data['custom_fields'] as $k => $v )
{
$cfields[ mb_substr( $k, 13 ) ] = $v;
if ( mb_substr( $k, 0, 13 ) === 'nexus_cfield_' )
{
$k = mb_substr( $k, 13 );
$class = $customFieldObjects[ $k ]->buildHelper();
$cfields[ $k ] = $class::stringValue( $v );
}
}
$request->cfields = $cfields;
}
@@ -534,9 +795,14 @@ class _requests extends \IPS\Dispatcher\Controller
$reply->ip_address = \IPS\Request::i()->ipAddress();
$reply->bcc = implode( ',', $values['bcc'] );
$reply->save();
\IPS\File::claimAttachments( 'new-req-message', $request->id, $reply->id );
$request->processAfterCreate( $reply, $data );
$reply->sendCustomerNotifications( $values['to'], $values['cc'], $values['bcc'] );
if ( $values['support_email_customer'] )
{
$reply->sendCustomerNotifications( $values['to'], $values['cc'], $values['bcc'] );
}
$reply->sendNotifications();
$url = NULL;
@@ -581,8 +847,169 @@ class _requests extends \IPS\Dispatcher\Controller
return $form;
};
/* Set member */
$url = \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=create');
$initialData = NULL;
if ( isset( \IPS\Request::i()->member ) )
{
$initialData = array( 'member' => \IPS\Request::i()->member );
$url = $url->setQueryString( 'member', \IPS\Request::i()->member );
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('create_support_request');
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( $steps, \IPS\Http\Url::internal('app=nexus&module=support&controller=requests&do=create') );
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( $steps, $url, TRUE, $initialData );
}
/**
* View History
*
* @return void
*/
protected function history()
{
/* Jump to the right date */
if ( isset( \IPS\Request::i()->date_jump ) )
{
try
{
$timezone = \IPS\Member::loggedIn()->timezone ? new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) : NULL;
}
catch ( \Exception $e )
{
$timezone = NULL;
}
$date = new \IPS\DateTime( \IPS\Helpers\Form\Date::_convertDateFormat( \IPS\Request::i()->date_jump ), $timezone );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests&do=history&date=' . $date->getTimestamp() ) );
}
/* Get our dates */
$date = isset( \IPS\Request::i()->date ) ? \IPS\DateTime::ts( \IPS\Request::i()->date ) : \IPS\DateTime::ts( time() )->setTime( 0, 0, 0 );
$tomorrow = clone $date;
$tomorrow = $tomorrow->add( new \DateInterval('P1D') );
$yesterday = clone $date;
$yesterday = $yesterday->sub( new \DateInterval('P1D') );
/* What page are we on? */
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$perPage = 25;
/* Get our replies */
$replyWhere = array(
array( 'reply_member=? AND reply_date>? AND reply_date<?', \IPS\Member::loggedIn()->member_id, $date->getTimestamp(), $tomorrow->getTimestamp() ),
array( \IPS\Db::i()->in( 'r_department', array_keys( iterator_to_array( \IPS\nexus\Support\Department::departmentsWithPermission( \IPS\Member::loggedIn() ) ) ) ) )
);
$replies = new \IPS\Patterns\ActiveRecordIterator(
\IPS\Db::i()->select( 'nexus_support_replies.*, nexus_support_ratings.*', 'nexus_support_replies',
$replyWhere,
'reply_id DESC',
array( ( $page - 1 ) * $perPage, $perPage ),
NULL,
NULL,
\IPS\Db::SELECT_SQL_CALC_FOUND_ROWS + \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS
)
->join( 'nexus_support_requests', 'r_id=reply_request' )
->join( 'nexus_support_departments', 'dpt_id=r_department' )
->join( 'nexus_support_ratings', 'reply_id=rating_reply' )
, 'IPS\nexus\Support\Reply'
);
/* Work out pagination */
$count = $replies->count( TRUE );
$numberOfPages = ceil( $count / $perPage );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests&do=history&date=' . $date->getTimestamp() ), $numberOfPages, $page, $perPage );
/* Any tracked? */
$supportRequestsInView = array();
$first = NULL;
$last = NULL;
foreach ( $replies as $reply )
{
if ( $first === NULL )
{
$first = $reply;
}
$supportRequestsInView[] = $reply->request;
$last = $reply;
}
$tracked = iterator_to_array( \IPS\Db::i()->select( array( 'request_id', 'notify' ), 'nexus_support_tracker', array( array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'request_id', $supportRequestsInView ) ) ) )->setKeyField( 'request_id' )->setValueField( 'notify' ) );
/* Add in actions */
if ( $last )
{
$logWhere = array( array( 'rlog_member=? AND rlog_date>=?', \IPS\Member::loggedIn()->member_id, $last->date ) );
try
{
$firstOnNextPage = \IPS\Db::i()->select( 'reply_date', 'nexus_support_replies', array_merge( $replyWhere, array( array( 'reply_date>?', $first->date ) ) ), 'reply_date ASC', 1 )->join( 'nexus_support_requests', 'r_id=reply_request' )->join( 'nexus_support_departments', 'dpt_id=r_department' )->first();
$logWhere[] = array( 'rlog_date<?', $firstOnNextPage );
}
catch ( \UnderflowException $e )
{
$logWhere[] = array( 'rlog_date<?', $tomorrow->getTimestamp() );
}
}
else
{
$logWhere = array( array( 'rlog_member=? AND rlog_date>? AND rlog_date<?', \IPS\Member::loggedIn()->member_id, $date->getTimestamp(), $tomorrow->getTimestamp() ) );
}
$iterator = new \IPS\Patterns\UnionIterator( 'desc' );
$iterator->attachIterator( $replies, 'date' );
$iterator->attachIterator( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_support_request_log', $logWhere, 'rlog_date DESC' ), 'IPS\nexus\Support\Log' ), 'date' );
/* Make a 30 day chart */
$data = array();
$workingDate = \IPS\DateTime::ts( time() - ( 86400 * 29 ) )->setTime( 0, 0, 0 );
$thirtyDaysAgo = $workingDate->getTimestamp();
for ( $i = 0; $i < 30; $i++ )
{
$data[ $workingDate->format( 'Y-n-j' ) ] = 0;
$workingDate->add( new \DateInterval('P1D') );
}
$chart = new \IPS\Helpers\Chart;
$chart->addHeader( \IPS\Member::loggedIn()->language()->addToStack('date'), 'date' );
$chart->addHeader( \IPS\Member::loggedIn()->language()->addToStack('staff_reply_count'), 'number' );
foreach ( \IPS\Db::i()->select( "COUNT(*) AS count, DATE_FORMAT( FROM_UNIXTIME( reply_date ), '%Y-%c-%e' ) AS time", 'nexus_support_replies', array( 'reply_member=? AND reply_type=? AND reply_date>?', \IPS\Member::loggedIn()->member_id, \IPS\nexus\Support\Reply::REPLY_STAFF, $thirtyDaysAgo ), NULL, NULL, 'time' ) as $row )
{
$data[ $row['time'] ] = $row['count'];
}
foreach ( $data as $dateString => $count )
{
$datetime = new \IPS\DateTime;
$exploded = explode( '-', $dateString );
$datetime->setDate( (float) $exploded[0], $exploded[1], $exploded[2] );
$datetime->setTime( 0, 0, 0 );
$chart->addRow( array( $datetime, $count ) );
}
$chart = $chart->render( 'ColumnChart', array(
'backgroundColor' => '#f5f5f5',
'chartArea' => array( 'width' => '97%', 'height' => '81%' ),
'colors' => array( '#394248' ),
'fontSize' => 10,
'height' => 150,
'vAxis' => array( 'gridlines' => array( 'count' => 4 ), 'maxValue' => max( $data ), 'textPosition' => 'none' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'legend' => array( 'position' => 'none' )
) );
/* Stats */
$sixtyDaysAgo = ( $thirtyDaysAgo - ( 86400 * 30 ) );
$resolvedStatuses = iterator_to_array( \IPS\Db::i()->select( 'status_id', 'nexus_support_statuses', 'status_is_locked=1' ) );
$stats = array();
$stats['totalRepliesThis'] = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', array( 'reply_member=? AND reply_type=? AND reply_date>?', \IPS\Member::loggedIn()->member_id, \IPS\nexus\Support\Reply::REPLY_STAFF, $thirtyDaysAgo ) )->first();
$stats['totalRepliesPrev'] = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_replies', array( 'reply_member=? AND reply_type=? AND reply_date>? AND reply_date<?', \IPS\Member::loggedIn()->member_id, \IPS\nexus\Support\Reply::REPLY_STAFF, $sixtyDaysAgo, $thirtyDaysAgo ) )->first();
$stats['customersHelpedThis'] = \IPS\Db::i()->select( 'COUNT( DISTINCT IF( nexus_support_requests.r_member, nexus_support_requests.r_member, nexus_support_requests.r_email ) )', 'nexus_support_replies', array( 'reply_member=? AND reply_type=? AND reply_date>?', \IPS\Member::loggedIn()->member_id, \IPS\nexus\Support\Reply::REPLY_STAFF, $thirtyDaysAgo ) )->join( 'nexus_support_requests', 'reply_request=r_id' )->first();
$stats['customersHelpedPrev'] = \IPS\Db::i()->select( 'COUNT( DISTINCT IF( nexus_support_requests.r_member, nexus_support_requests.r_member, nexus_support_requests.r_email ) )', 'nexus_support_replies', array( 'reply_member=? AND reply_type=? AND reply_date>? AND reply_date<?', \IPS\Member::loggedIn()->member_id, \IPS\nexus\Support\Reply::REPLY_STAFF, $sixtyDaysAgo, $thirtyDaysAgo ) )->join( 'nexus_support_requests', 'reply_request=r_id' )->first();
$stats['issuesResolvedThis'] = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'reply_member=? AND r_last_staff_reply>?', \IPS\Member::loggedIn()->member_id, $thirtyDaysAgo ) )->join( 'nexus_support_replies', 'reply_date=r_last_staff_reply' )->first();
$stats['issuesResolvedPrev'] = \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'reply_member=? AND r_last_staff_reply>? AND r_last_staff_reply<?', \IPS\Member::loggedIn()->member_id, $sixtyDaysAgo, $thirtyDaysAgo ) )->join( 'nexus_support_replies', 'reply_date=r_last_staff_reply' )->first();
$stats['averageRatingThis'] = round( \IPS\Db::i()->select( 'AVG(rating_rating)', 'nexus_support_ratings', array( 'rating_staff=? AND rating_date>?', \IPS\Member::loggedIn()->member_id, $thirtyDaysAgo ) )->first(), 1 );
$stats['averageRatingPrev'] = round( \IPS\Db::i()->select( 'AVG(rating_rating)', 'nexus_support_ratings', array( 'rating_staff=? AND rating_date>? AND rating_date<?', \IPS\Member::loggedIn()->member_id, $sixtyDaysAgo, $thirtyDaysAgo ) )->first(), 1 );
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('my_history');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('support')->myHistory( $date, $tomorrow, $yesterday, $iterator, $pagination, $tracked, $chart, $stats );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Support Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 15 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -2,10 +2,10 @@
/**
* @brief severities
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Nexus
* @since 09 Apr 2014
* @version SVN_VERSION_NUMBER
*/
@@ -91,7 +91,7 @@ class _severities extends \IPS\Node\Controller
\IPS\Db::i()->update( 'nexus_support_requests', array( 'r_severity' => $values['set_existing_requests_to']->id ), array( 'r_severity=?', $node->id ) );
/* Delete it */
\IPS\Session::i()->log( 'acplog__node_deleted', array( $this->title => TRUE, $node->_logKey => TRUE ) );
\IPS\Session::i()->log( 'acplog__node_deleted', array( $this->title => TRUE, $node->titleForLog() => FALSE ) );
$node->delete();
/* Clear out member's cached "Create Menu" contents */
@@ -2,9 +2,9 @@
/**
* @brief Support Statuses
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 09 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -2,10 +2,10 @@
/**
* @brief stockactions
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Nexus
* @since 15 Apr 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief New Support Request Volumme
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Nexus
* @since 25 Apr 2014
* @version SVN_VERSION_NUMBER