Version 4.0.13.1

This commit is contained in:
Neo committed 2025-12-19 04:57:54 -08:00
1 parent f9e857d255
commit c6a86f0d9b
7517 files changed
+597400 -668041

No files matched your search

@@ -0,0 +1,125 @@
<?php
/**
* @brief Support Author Model - Email
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 15 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support\Author;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Author Model - Email
*/
class _Email
{
/**
* @brief Email Address
*/
protected $email;
/**
* Constructor
*
* @param string $email Email address
* @return void
*/
public function __construct( $email )
{
$this->email = $email;
}
/**
* Get name
*
* @return string
*/
public function name()
{
return $this->email;
}
/**
* Get photo
*
* @return string
*/
public function photo()
{
if ( \IPS\Settings::i()->allow_gravatars )
{
return \IPS\Http\Url::external( "https://secure.gravatar.com/avatar/" . md5( trim( mb_strtolower( $this->email ) ) ) )->setQueryString( 'd', (string) \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' ) )->makeSafeForAcp( TRUE );
}
return \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
}
/**
* Get email
*
* @return string
*/
public function email()
{
return $this->email;
}
/**
* Get url
*
* @return \IPS\Http\Url
*/
public function url()
{
return NULL;
}
/**
* Get meta data
*
* @return array
*/
public function meta()
{
return array( 'email' => $this->email );
}
/**
* Get latest invoices
*
* @return \IPS\Patterns\ActiveRecordIterator|NULL
*/
public function invoices( $limit=10 )
{
return NULL;
}
/**
* Support Requests
*
* @param int $limit Number to get
* @para, \IPS\nexus\Support\Request $exclude A request to exclude
* @param string $order Order clause
* @return \IPS\Patterns\ActiveRecordIterator
*/
public function supportRequests( $limit, \IPS\nexus\Support\Request $exclude = NULL, $order='r_started DESC' )
{
$where = array( array( 'r_email=?', $this->email ) );
if ( $exclude )
{
$where[] = array( 'r_id<>?', $exclude->id );
}
return \IPS\nexus\Support\Request::getItemsWithPermission( $where, $order, $limit, 'read', NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS );
}
}
@@ -0,0 +1,135 @@
<?php
/**
* @brief Support Author Model - Member
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 10 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support\Author;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Author Model - Member
*/
class _Member
{
/**
* @brief Customer object
*/
protected $customer;
/**
* Constructor
*
* @param \IPS\nexus\Customer $customer Customer object
* @return void
*/
public function __construct( \IPS\nexus\Customer $customer )
{
$this->customer = $customer;
}
/**
* Get name
*
* @return string
*/
public function name()
{
return $this->customer->cm_name;
}
/**
* Get email
*
* @return string
*/
public function email()
{
return $this->customer->email;
}
/**
* Get photo
*
* @return string
*/
public function photo()
{
return $this->customer->photo;
}
/**
* Get url
*
* @return \IPS\Http\Url
*/
public function url()
{
return $this->customer->acpUrl();
}
/**
* Get meta data
*
* @return array
*/
public function meta()
{
return array(
$this->customer->email,
\IPS\Member::loggedIn()->language()->addToStack( 'transaction_customer_since', FALSE, array( 'sprintf' => array( $this->customer->joined->localeDate() ) ) ),
\IPS\Member::loggedIn()->language()->addToStack( 'transaction_spent', FALSE, array( 'sprintf' => array( $this->customer->totalSpent() ) ) ),
);
}
/**
* Get nuber of notes
*
* @return array
*/
public function noteCount()
{
return \IPS\Db::i()->select( 'COUNT(*)', 'nexus_notes', array( 'note_member=?', $this->customer->member_id ) )->first();
}
/**
* Get latest invoices
*
* @return \IPS\Patterns\ActiveRecordIterator|NULL
*/
public function invoices( $limit=10 )
{
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'nexus_invoices', array( 'i_member=?', $this->customer->member_id ), 'i_date DESC', $limit, NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS ), 'IPS\nexus\Invoice' );
}
/**
* Support Requests
*
* @param int $limit Number to get
* @para, \IPS\nexus\Support\Request $exclude A request to exclude
* @param string $order Order clause
* @return \IPS\Patterns\ActiveRecordIterator
*/
public function supportRequests( $limit, \IPS\nexus\Support\Request $exclude = NULL, $order='r_started DESC' )
{
$where = array( array( 'r_member=?', $this->customer->member_id ) );
if ( $exclude )
{
$where[] = array( 'r_id<>?', $exclude->id );
}
return \IPS\nexus\Support\Request::getItemsWithPermission( $where, $order, $limit, 'read', NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS );
}
}
Whitespace-only changes.
@@ -0,0 +1,219 @@
<?php
/**
* @brief Custom Support Field Node
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 16 Apr 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Custom Profile Field Node
*/
class _CustomField extends \IPS\CustomField
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_fields';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'sf_';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [CustomField] Title/Description lang prefix
*/
protected static $langKey = 'nexus_cfield';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'nexus',
'module' => 'support',
'all' => 'scfields_manage'
);
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'custom_support_fields';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'nexus_cfield_';
/**
* @brief [CustomField] Column Map
*/
public static $databaseColumnMap = array(
'content' => 'extra',
'not_null' => 'required',
);
/**
* @brief [CustomField] Additional Field Classes
*/
public static $additionalFieldTypes = array(
'UserPass' => 'sf_type_UserPass',
'Ftp' => 'sf_type_Ftp'
);
/**
* @brief [CustomField] Additional Field Toggles
*/
public static $additionalFieldToggles = array(
'Ftp' => array( 'pf_not_null', 'sf_validate_ftp' )
);
/**
* @brief [CustomField] Upload Field Storage Extension
*/
public static $uploadStorageExtension = 'nexus_Support';
/**
* @brief [CustomField] Editor Options
*/
public static $editorOptions = array( 'app' => 'nexus', 'key' => 'Support' );
/**
* Get
*
* @param string $key Key
* @return mixed $value Value
*/
public function __get( $key )
{
/* Required fields aren't actually required because they may be department specific */
if ( $key == 'not_null' )
{
return $this->required ? NULL : FALSE;
}
return parent::__get( $key );
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
parent::form( $form );
$form->add( new \IPS\Helpers\Form\Node( 'sf_departments', $this->departments === '*' ? 0 : explode( ',', $this->departments ), TRUE, array( 'class' => 'IPS\nexus\Support\Department', 'multiple' => TRUE, 'zeroVal' => 'all' ) ), 'pf_desc' );
$form->add( new \IPS\Helpers\Form\YesNo( 'sf_validate_ftp', extension_loaded('ftp') ? $this->validate : FALSE, FALSE, array( 'disabled' => !extension_loaded('ftp') ), NULL, NULL, NULL, 'sf_validate_ftp' ), 'pf_not_null' );
if ( !extension_loaded('ftp') )
{
\IPS\Member::loggedIn()->language()->words['sf_validate_ftp_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'sf_validate_ftp_noftp' );
}
elseif( !extension_loaded('ssh2') )
{
\IPS\Member::loggedIn()->language()->words['sf_validate_ftp_warning'] = \IPS\Member::loggedIn()->language()->addToStack( 'sf_validate_ftp_nosftp' );
}
unset( $form->elements[''][1] );
unset( $form->elements['']['pf_search_type'] );
unset( $form->elements['']['pf_format'] );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if( isset( $values['sf_validate_ftp'] ) )
{
$values['departments'] = $values['sf_departments'] ? implode( ',', array_keys( $values['sf_departments'] ) ) : '*';
unset( $values['sf_departments'] );
}
if( isset( $values['sf_validate_ftp'] ) )
{
$values['validate'] = $values['sf_validate_ftp'];
unset( $values['sf_validate_ftp'] );
}
return parent::formatFormValues( $values );
}
/**
* Build Form Helper
*
* @param mixed $value The value
* @param callback $customValidationCode Custom validation code
* @return \IPS\Helpers\Form\FormAbstract
*/
public function buildHelper( $value=NULL, $customValidationCode=NULL )
{
if ( $this->type === 'UserPass' )
{
return new \IPS\nexus\Form\UserPass( static::$langKey . '_' . $this->id, $value, $this->not_null, array(), NULL, NULL, NULL, static::$langKey . '_' . $this->id );
}
elseif ( $this->type === 'Ftp' )
{
return new \IPS\Helpers\Form\Ftp( static::$langKey . '_' . $this->id, $value, $this->not_null, array( 'validate' => $this->validate ), NULL, NULL, NULL, static::$langKey . '_' . $this->id );
}
return parent::buildHelper( $value, $customValidationCode );
}
/**
* Display Value
*
* @param mixed $value The value
* @return string
*/
public function displayValue( $value=NULL )
{
if ( $this->type === 'UserPass' )
{
return \IPS\Theme::i()->getTemplate( 'forms', 'nexus', 'global' )->usernamePasswordDisplay( json_decode( \IPS\Text\Encrypt::fromTag( $value )->decrypt(), TRUE ) );
}
return parent::displayValue( $value );
}
}
@@ -0,0 +1,383 @@
<?php
/**
* @brief Support Department Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 8 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Department Model
*/
class _Department extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_departments';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'dpt_';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'departments';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'dpt_email' );
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'nexus_department_';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'nexus',
'module' => 'support',
'all' => 'departments_manage'
);
/**
* Set Default Values
*
* @return void
*/
protected function setDefaultValues()
{
$this->ppi = json_encode( array() );
}
/**
* Get the permission array used to get the departments that a staff member has access to
*
* @param \IPS\Member|NULL $staff The staff member
* @return array|NULL NULL indicates all departments
*/
public static function staffDepartmentPerms( \IPS\Member $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
$return = array( "m{$member->member_id}" );
foreach ( $member->groups as $groupId )
{
$return[] = "g{$groupId}";
}
return $return;
}
/**
* Cache for departmentsWithPermission()
*/
protected static $departmentsWithPermission = array();
/**
* Departments that a staff member has access to
*
* @return \IPS\Patterns\ActiveRecordIterator
*/
public static function departmentsWithPermission( \IPS\Member $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( !isset( static::$departmentsWithPermission[ $member->member_id ] ) )
{
static::$departmentsWithPermission[ $member->member_id ] = new \IPS\Patterns\ActiveRecordIterator(
\IPS\Db::i()->select( '*', 'nexus_support_departments', array( "( dpt_staff='*' OR " . \IPS\Db::i()->findInSet( 'dpt_staff', \IPS\nexus\Support\Department::staffDepartmentPerms( $member ) ) . ')' ) )->setKeyField( 'dpt_id' ),
'IPS\nexus\Support\Department'
);
}
return static::$departmentsWithPermission[ $member->member_id ];
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
$form->addHeader('department_settings');
$form->add( new \IPS\Helpers\Form\Translatable( 'dpt_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_department_{$this->id}" : NULL ) ) ) );
/* PHP 5.3 does not allow the use of $this in anonymous functions */
$obj = &$this;
$form->add( new \IPS\Helpers\Form\Email( 'dpt_email', $this->email, FALSE, array( 'placeholder' => 'support@example.com' ), function ( $val ) use ( $obj )
{
if ( $val )
{
try
{
$other = \IPS\Db::i()->select( '*', 'nexus_support_departments', array( 'dpt_email=? AND dpt_id<>?', $val, $obj->id ?: 0 ) )->first();
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'dpt_email_error', FALSE, array( 'sprintf' => array( \IPS\nexus\Support\Department::constructFromData( $other)->_title ) ) ) );
}
catch ( \UnderflowException $e ) { }
}
} ) );
$form->addHeader( 'department_submissions' );
$form->add( new \IPS\Helpers\Form\YesNo( 'dpt_open', $this->id ? $this->open : TRUE, FALSE, array( 'togglesOn' => array( 'dpt_desc_editor', 'dpt_ppi' ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'dpt_desc', NULL, FALSE, array(
'app' => 'nexus',
'key' => ( $this->id ? "nexus_department_{$this->id}_desc" : NULL ),
'editor' => array(
'app' => 'nexus',
'key' => 'Admin',
'autoSaveKey' => ( $this->id ? "nexus-dpt-{$this->id}" : "nexus-new-dpt" ),
'attachIds' => $this->id ? array( $this->id, NULL, 'dpt' ) : NULL, 'minimize' => 'dpt_desc_placeholder'
)
), NULL, NULL, NULL, 'dpt_desc_editor' ) );
$form->add( new \IPS\nexus\Form\Money( 'dpt_ppi', ( !$this->ppi or $this->ppi === '*' ) ? '*' : json_decode( $this->ppi, TRUE ), FALSE, array( 'unlimitedLang' => 'no_charge', 'unlimitedTogglesOff' => array( 'dpt_ppi_tax' ) ), NULL, NULL, NULL, 'dpt_ppi' ) );
$form->add( new \IPS\Helpers\Form\Node( 'dpt_ppi_tax', $this->ppi_tax ?: 0, FALSE, array( 'class' => 'IPS\nexus\Tax', 'zeroVal' => 'do_not_tax' ), NULL, NULL, NULL, 'dpt_ppi_tax' ) );
$form->add( new \IPS\Helpers\Form\Node( 'dpt_packages', $this->packages ? array_filter( array_map( function( $val )
{
try
{
return \IPS\nexus\Package::load( $val );
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
}, explode( ',', $this->packages ) ) ) : 0, FALSE, array( 'zeroVal' => 'do_not_associate_requests', 'multiple' => TRUE, 'class' => 'IPS\nexus\Package\Group', 'zeroValTogglesOff' => array( 'dpt_require_package' ), 'permissionCheck' => function( $node )
{
return !( $node instanceof \IPS\nexus\Package\Group );
} ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'dpt_require_package', $this->require_package, FALSE, array(), NULL, NULL, NULL, 'dpt_require_package' ) );
$form->addHeader( 'department_staff' );
$admins = array();
foreach ( \IPS\Db::i()->select( '*', 'core_admin_permission_rows' ) as $row )
{
if ( $row['row_id_type'] === 'group' )
{
$admins[ 'dpt_staff_group' ][ 'g' . $row['row_id'] ] = \IPS\Member\Group::load( $row['row_id'] )->name;
}
else
{
$admins[ 'dpt_staff_member' ][ 'm' . $row['row_id'] ] = \IPS\Member::load( $row['row_id'] )->name;
}
}
$form->add( new \IPS\Helpers\Form\Select( 'dpt_staff', ( $this->id and $this->staff !== '*' ) ? explode( ',', $this->staff ) : '*', TRUE, array( 'options' => $admins, 'multiple' => TRUE, 'unlimited' => '*' ) ) );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( !$this->id )
{
$this->save();
\IPS\File::claimAttachments( 'nexus-new-dpt', $this->id, NULL, 'dpt', TRUE );
}
if( isset( $values['dpt_name'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_department_{$this->id}", $values['dpt_name'] );
unset( $values['dpt_name'] );
}
if( isset( $values['dpt_desc'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_department_{$this->id}_desc", $values['dpt_desc'] );
unset( $values['dpt_desc'] );
}
if( isset( $values['dpt_ppi'] ) )
{
$values['dpt_ppi'] = $values['dpt_ppi'] === '*' ? '*' : json_encode( $values['dpt_ppi'] );
}
if( isset( $values['dpt_staff'] ) )
{
$values['dpt_staff'] = $values['dpt_staff'] === '*' ? '*' : implode( ',', $values['dpt_staff'] );
}
if( isset( $values['dpt_ppi_tax'] ) )
{
$values['dpt_ppi_tax'] = $values['dpt_ppi_tax'] ? $values['dpt_ppi_tax']->id : NULL;
}
if( isset( $values['dpt_packages'] ) )
{
$values['dpt_packages'] = is_array( $values['dpt_packages'] ) ? implode( ',', array_map( function( $val )
{
return ltrim( $val, 's' );
}, array_keys( $values['dpt_packages'] ) ) ) : 0;
}
return $values;
}
/**
* Get serialised package IDs
*
* @return string
*/
public function serializedPackageIds()
{
if ( $this->packages and $this->packages !== '*' )
{
$allowedPackages = explode( ',', $this->packages );
sort( $allowedPackages );
$allowedPackages = array_filter( $allowedPackages );
$allowedPackages = array_unique( $allowedPackages );
return md5( implode( ',', $allowedPackages ) );
}
else
{
return '*';
}
}
/**
* @brief Available severities
*/
protected $_availableSeverities = NULL;
/**
* Get available severities
*
* @return array
*/
public function availableSeverities()
{
if ( $this->_availableSeverities === NULL )
{
$this->_availableSeverities = array();
foreach ( Severity::roots( NULL, NULL, array( 'sev_public=1' ) ) as $severity )
{
if ( $severity->public )
{
if ( !$severity->departments or $severity->departments === '*' or in_array( $this->id, explode( ',', $severity->departments ) ) )
{
$this->_availableSeverities[] = $severity;
}
}
}
}
return $this->_availableSeverities;
}
/**
* Get serialised severity IDs
*
* @return string
*/
public function serializedSeverityIds()
{
$allowedSeverityIds = array_keys( $this->availableSeverities() );
sort( $allowedSeverityIds );
$allowedSeverityIds = array_filter( $allowedSeverityIds );
$allowedSeverityIds = array_unique( $allowedSeverityIds );
return md5( implode( ',', $allowedSeverityIds ) );
}
/**
* Get custom fields
*
* @return array
*/
public function customFields()
{
return CustomField::roots( NULL, NULL, "sf_departments='*' OR " . \IPS\Db::i()->findInSet( 'sf_departments', array( $this->id ) ) );
}
/**
* Pay-Per-Incident Cost
*
* @param string|NULL $currency Desired currency (NULL for the current user's preference)
* @return \IPS\nexus\Money|NULL
*/
public function ppiCost( $currency = NULL )
{
if ( $this->ppi and $this->ppi !== '*' )
{
$costs = json_decode( $this->ppi, TRUE );
if( isset( $costs[ $currency ?: \IPS\nexus\Customer::loggedIn()->defaultCurrency() ] ) )
{
$cost = $costs[ $currency ?: \IPS\nexus\Customer::loggedIn()->defaultCurrency() ];
return new \IPS\nexus\Money( $cost['amount'], $cost['currency'] );
}
}
return NULL;
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
*
* @code
array(
array(
'icon' => 'plus-circle', // Name of FontAwesome icon to use
'title' => 'foo', // Language key to use for button's title parameter
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
'class' => 'modalLink' // CSS Class to use on link (Optional)
),
... // Additional buttons
);
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
if ( isset( $buttons['delete'] ) and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'r_department=?', $this->id ) ) )
{
$buttons['delete']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('delete') );
}
return $buttons;
}
}
+197
View File
@@ -0,0 +1,197 @@
<?php
/**
* @brief Support Log Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 14 Nov 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Log Model
*/
class _Log extends \IPS\Patterns\ActiveRecord
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_request_log';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'rlog_';
/**
* Set request
*
* @param \IPS\nexus\Support\Request $request The request
* @return void
*/
public function set_request( \IPS\nexus\Support\Request $request )
{
$this->_data['request'] = $request->id;
}
/**
* Get request
*
* @return \IPS\nexus\Support\Request
*/
public function get_request()
{
return \IPS\nexus\Support\Request::load( $this->_data['request'] );
}
/**
* Set member performing the action
*
* @param \IPS\nexus\Support\Request $member The member performing the action
* @return void
*/
public function set_member( \IPS\Member $member )
{
$this->_data['member'] = $member->member_id;
}
/**
* Get member performing the action
*
* @return \IPS\nexus\Customer
*/
public function get_member()
{
return \IPS\nexus\Customer::load( $this->_data['member'] );
}
/**
* Set old value
*
* @param mixed $old The old value
* @return void
*/
public function set_old( $old )
{
$this->_data['old'] = $old ? $old->id : NULL;
}
/**
* Get old value
*
* @return mixed
*/
public function get_old()
{
return $this->getValue( $this->_data['old'] );
}
/**
* Set new value
*
* @param mixed $new The new value
* @return void
*/
public function set_new( $new )
{
if ( $new )
{
if ( $new instanceof \IPS\Member )
{
$this->_data['new'] = $new->member_id;
}
else
{
$this->_data['new'] = $new->id;
}
}
else
{
$this->_data['new'] = NULL;
}
}
/**
* Get new value
*
* @return mixed
*/
public function get_new()
{
return $this->getValue( $this->_data['new'] );
}
/**
* Set date
*
* @param \IPS\DateTime $date The date
* @return void
*/
public function set_date( \IPS\DateTime $date )
{
$this->_data['date'] = $date->getTimestamp();
}
/**
* Get old value
*
* @return \IPS\DateTime
*/
public function get_date()
{
return \IPS\DateTime::ts( $this->_data['date'] );
}
/**
* Get object from ID
*
* @param int $id
* @return mixed
*/
protected function getValue( $id )
{
if ( !$id )
{
return NULL;
}
try
{
switch ( $this->action )
{
case 'status':
return \IPS\nexus\Support\Status::load( $id );
case 'department':
return \IPS\nexus\Support\Department::load( $id );
case 'purchase':
return \IPS\nexus\Purchase::load( $id );
case 'severity':
return \IPS\nexus\Support\Severity::load( $id );
case 'staff':
return \IPS\Member::load( $id );
}
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
throw new \InvalidArgumentException( $this->action );
}
}
@@ -0,0 +1,402 @@
<?php
/**
* @brief Support Reply Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 9 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Reply Model
*/
class _Reply extends \IPS\Content\Comment implements \IPS\Content\Hideable
{
const REPLY_MEMBER = 'm';
const REPLY_ALTCONTACT = 'a';
const REPLY_STAFF = 's';
const REPLY_HIDDEN = 'h';
const REPLY_EMAIL = 'e';
const REPLY_PENDING = 'p';
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief Application
*/
public static $application = 'nexus';
/**
* @brief [Content\Comment] Item Class
*/
public static $itemClass = 'IPS\nexus\Support\Request';
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_replies';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'reply_';
/**
* @brief Database Column Map
*/
public static $databaseColumnMap = array(
'item' => 'request',
'author' => 'member',
'content' => 'post',
'date' => 'date',
'ip_address' => 'ip_address',
'hidden' => 'hidden'
);
/**
* @brief [Content\Comment] Comment Template
*/
public static $commentTemplate = array( array( 'support', 'nexus' ), 'replyContainer' );
/**
* @brief Icon
*/
public static $icon = 'life-ring';
/**
* @brief Title
*/
public static $title = 'support_request';
/**
* @brief Rating data
*/
public $ratingData;
/**
* Construct ActiveRecord from database row
*
* @param array $data Row from database table
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
* @return static
*/
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
{
$obj = parent::constructFromData( $data, $updateMultitonStoreIfExists );
if ( isset( $data['nexus_support_ratings'] ) and $data['nexus_support_ratings']['rating_rating'] )
{
$obj->ratingData = $data['nexus_support_ratings'];
}
return $obj;
}
/**
* Set Default Values
*
* @return void
*/
public function setDefaultValues()
{
$this->type = static::REPLY_MEMBER;
}
/**
* Create comment
*
* @param \IPS\Content\Item $item The content item just created
* @param string $comment The comment
* @param bool $first Is the first comment?
* @param string $guestName If author is a guest, the name to use
* @param bool|NULL $incrementPostCount Increment post count? If NULL, will use static::incrementPostCount()
* @param \IPS\Member|NULL $member The author of this comment. If NULL, uses currently logged in member.
* @param \IPS\DateTime|NULL $time The time
* @return \IPS\Content\Comment
*/
public static function create( $item, $comment, $first=FALSE, $guestName=NULL, $incrementPostCount=NULL, $member=NULL, \IPS\DateTime $time=NULL )
{
$obj = call_user_func_array( 'parent::create', func_get_args() );
if ( $obj->type === static::REPLY_MEMBER and $obj->author()->member_id !== $obj->item()->author()->member_id )
{
$obj->type = static::REPLY_ALTCONTACT;
$obj->save();
$notify = $obj->item()->notify;
$in = FALSE;
foreach ( $notify as $n )
{
if ( $n['type'] === 'm' and $n['value'] == $obj->author()->member_id )
{
$in = TRUE;
}
}
if ( !$in )
{
$notify[] = array( 'type' => 'm', 'value' => $obj->author()->member_id );
$obj->item()->notify = $notify;
$obj->item()->save();
}
}
return $obj;
}
/**
* Should posting this increment the poster's post count?
*
* @param \IPS\Node\Model|NULL $container Container
* @return void
*/
public static function incrementPostCount( \IPS\Node\Model $container = NULL )
{
return FALSE;
}
/**
* Joins (when loading comments)
*
* @param \IPS\Content\Item $item The item
* @return array
*/
public static function joins( \IPS\Content\Item $item )
{
$return = parent::joins( $item );
if ( \IPS\Settings::i()->nexus_support_satisfaction )
{
$return['nexus_support_ratings'] = array(
'select' => 'nexus_support_ratings.*',
'from' => 'nexus_support_ratings',
'where' => 'rating_reply=reply_id'
);
}
return $return;
}
/**
* Can edit?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canEdit( $member=NULL )
{
return FALSE;
}
/**
* Can delete?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canDelete( $member=NULL )
{
return FALSE;
}
/**
* Can split this comment off?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canSplit( $member=NULL )
{
return FALSE;
}
/**
* Get author
*
* @return \IPS\nexus\Customer
*/
public function author()
{
if ( $this->member )
{
try
{
return \IPS\nexus\Customer::load( $this->member );
}
catch ( \OutOfRangeException $e ) { }
}
return new \IPS\nexus\Customer;
}
/**
* Can see moderation tools
*
* @note This is used generally to control if the user has permission to see multi-mod tools. Individual content items may have specific permissions
* @param \IPS\Member|NULL $member The member to check for or NULL for the currently logged in member
* @param \IPS\Node\Model|NULL $container The container
* @return bool
*/
public static function canSeeMultiModTools( \IPS\Member $member = NULL, \IPS\Node\Model $container = NULL )
{
// If we decide to support multimod in future, we need to make sure it either doesn't show, or shows correctly when viewing a staff member's latest replies in the "Performance" section
return FALSE;
}
/**
* Send if it's pending
*
* @return void
*/
public function sendPending()
{
if ( $this->type === static::REPLY_PENDING )
{
$this->type = static::REPLY_STAFF;
$this->save();
$defaultRecipients = $this->item()->getDefaultRecipients();
$this->sendCustomerNotifications( $defaultRecipients['to'], $defaultRecipients['cc'], $defaultRecipients['bcc'] );
$this->sendNotifications();
}
}
/**
* Send staff notifications
*
* @return void
*/
public function sendNotifications()
{
$staffIds = array_keys( Request::staff() );
$type = array( 'type=?', 'r' );
if ( $assignedTo = $this->item()->staff )
{
$type[0] .= ' OR ( type=? AND staff_id=? )';
$type[] = 'a';
$type[] = $assignedTo->member_id;
}
$sentTo = array( $this->member );
foreach ( \IPS\Db::i()->select( 'staff_id', 'nexus_support_notify', array( $type, array( "departments='*' OR " . \IPS\Db::i()->findInSet( 'departments', array( $this->item()->department->id ) ) ) ) ) as $staffId )
{
if ( in_array( $staffId, $staffIds ) )
{
if ( !in_array( $staffId, $sentTo ) and ( $this->item()->department->staff === '*' or in_array( $staffId, explode( ',', $this->item()->department->staff ) ) ) )
{
$email = \IPS\Email::buildFromTemplate( 'nexus', $this->type === static::REPLY_HIDDEN ? 'staffNotifyNote' : 'staffNotifyReply', array( $this ) );
$email->from = $this->item()->department->email;
switch ( \IPS\Settings::i()->nexus_sout_from )
{
case 'staff':
if ( $this->member )
{
$email->fromName = $this->author()->name;
}
break;
case 'dpt':
$email->fromName = $email->language->get( 'nexus_department_' . $this->item()->department->_id );
break;
default:
$email->fromName = \IPS\Settings::i()->nexus_sout_from;
break;
}
$email->unsubscribe = array( 'text' => 'manage_notification_settings', 'link' => \IPS\Http\Url::internal( 'app=nexus&module=support&controller=requests&do=notifications', 'admin' ) );
$email->send( \IPS\Member::load( $staffId ) );
$sentTo[] = $staffId;
}
}
else
{
\IPS\Db::i()->delete( 'nexus_support_notify', array( 'staff_id=?', $staffId ) );
}
}
}
/**
* Send Customer Notifications
*
* @param string $to Primary "To" email address
* @param array $cc Emails to Cc
* @param array $bcc Emails to Bcc
* @return void
*/
public function sendCustomerNotifications( $to, $cc, $bcc )
{
if ( \IPS\Settings::i()->nexus_sout_chrome )
{
$email = \IPS\Email::buildFromTemplate( 'nexus', 'staffReply', array( $this ) );
}
else
{
$email = \IPS\Email::buildFromTemplate( 'nexus', 'staffReplyNoChrome', array( $this ) );
$email->useWrapper = FALSE;
}
$email->from = $this->item()->department->email ?: \IPS\Settings::i()->email_out;
switch ( \IPS\Settings::i()->nexus_sout_from )
{
case 'staff':
$email->fromName = $this->author()->name;
break;
case 'dpt':
$email->fromName = $email->language->get( 'nexus_department_' . $this->item()->department->_id );
break;
default:
$email->fromName = \IPS\Settings::i()->nexus_sout_from;
break;
}
$email->send( $to, $cc, $bcc );
}
/**
* Do stuff after creating (abstracted as comments and reviews need to do different things)
*
* @return void
*/
public function postCreate()
{
$item = $this->item();
if ( $this->type === Reply::REPLY_MEMBER or $this->type === Reply::REPLY_ALTCONTACT )
{
$item->status = Status::load( TRUE, 'status_default_member' );
}
return parent::postCreate();
}
/**
* Get ACP URL
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
*/
public function acpUrl( $action=NULL )
{
$url = \IPS\Http\Url::internal( "app=nexus&module=support&controller=request&id={$this->id}", 'admin' );
if( $action )
{
return $url->setQueryString( 'do', $action . 'Comment' )->setQueryString( 'comment', $this->id );
}
else
{
$commentPosition = \IPS\Db::i()->select( 'COUNT(*) AS position', static::$databaseTable, array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=? AND ' . static::$databasePrefix . static::$databaseColumnId . '<=?', $this->request, $this->id ), static::$databasePrefix . static::$databaseColumnMap['date'] . ' asc' )->first();
$page = ceil( $commentPosition / \IPS\nexus\Support\Request::getCommentsPerPage() );
if ( $page != 1 )
{
$url = $url->setQueryString( 'page', $page );
}
return $url->setFragment( 'comment-' . $this->id );
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,180 @@
<?php
/**
* @brief Support Severity Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 9 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Severity Model
*/
class _Severity extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_severities';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'sev_';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'severities';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'sev_default' );
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'nexus_severity_';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'nexus',
'module' => 'support',
'all' => 'severities_manage'
);
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
$form->addHeader( 'severity_settings' );
$form->add( new \IPS\Helpers\Form\Translatable( 'sev_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_severity_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'sev_default', $this->default ) );
$form->addHeader( 'severity_submissions' );
$form->add( new \IPS\Helpers\Form\YesNo( 'sev_public', $this->public, FALSE, array( 'togglesOn' => array( 'sev_departments', 'sev_desc' ) ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'sev_departments', ( $this->departments and $this->departments !== '*' ) ? explode( ',', $this->departments ) : 0, FALSE, array( 'class' => 'IPS\nexus\Support\Department', 'multiple' => TRUE, 'zeroVal' => 'all' ), NULL, NULL, NULL, 'sev_departments' ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'sev_desc', NULL, FALSE, array(
'app' => 'nexus',
'key' => ( $this->id ? "nexus_severity_{$this->id}_desc" : NULL ),
'textArea' => TRUE
), NULL, NULL, NULL, 'sev_desc' ) );
$form->addHeader( 'severity_acp_list' );
$form->add( new \IPS\Helpers\Form\Upload( 'sev_icon', $this->icon ? \IPS\File::get( 'nexus_Support', $this->icon ) : NULL, FALSE, array( 'storageExtension' => 'nexus_Support', 'image' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Color( 'sev_color', $this->color ?: '000' ) );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( !$this->id )
{
$this->save();
}
if( isset( $values['sev_name'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_severity_{$this->id}", $values['sev_name'] );
unset( $values['sev_name'] );
}
if( isset( $values['sev_desc'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_severity_{$this->id}_desc", $values['sev_desc'] );
unset( $values['sev_desc'] );
}
if ( isset( $values['sev_default'] ) AND $values['sev_default'] )
{
\IPS\Db::i()->update( 'nexus_support_severities', array( 'sev_default' => 0 ) );
}
if( isset( $values['sev_color'] ) )
{
$values['sev_color'] = ltrim( $values['sev_color'], '#' );
}
if( isset( $values['sev_departments'] ) )
{
$values['sev_departments'] = $values['sev_departments'] == 0 ? '*' : implode( ',', array_keys( $values['sev_departments'] ) );
}
return $values;
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
*
* @code
array(
array(
'icon' => 'plus-circle', // Name of FontAwesome icon to use
'title' => 'foo', // Language key to use for button's title parameter
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
'class' => 'modalLink' // CSS Class to use on link (Optional)
),
... // Additional buttons
);
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
if ( isset( $buttons['delete'] ) and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'r_severity=?', $this->id ) ) )
{
$buttons['delete']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('delete') );
}
return $buttons;
}
}
@@ -0,0 +1,261 @@
<?php
/**
* @brief Support Status Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 8 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Status Model
*/
class _Status extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_statuses';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'status_';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'statuses';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'status_default_member', 'status_default_staff' );
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'nexus',
'module' => 'support',
'all' => 'statuses_manage'
);
/**
* Statuses that the member can set
*
* @param \IPS\nexus\Support\Request|NULL $request If provided, the status of that request will be excluded
* @return array
*/
public static function publicSetStatuses( \IPS\nexus\Support\Request $request = NULL )
{
$return = array();
foreach ( parent::roots() as $status )
{
if ( \IPS\Member::loggedIn()->language()->checkKeyExists("nexus_status_{$status->id}_set") and ( $request === NULL or $request->status->id != $status->id ) )
{
$return[ $status->id ] = \IPS\Member::loggedIn()->language()->addToStack("nexus_status_{$status->id}_set");
}
}
return $return;
}
/**
* Get name
*
* @return string
*/
public function get__title()
{
return \IPS\Member::loggedIn()->language()->addToStack( 'nexus_status_' . $this->id . '_' . \IPS\Dispatcher::i()->controllerLocation );
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
$form->addHeader( 'internal_settings' );
$form->add( new \IPS\Helpers\Form\Translatable( 'status_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_status_{$this->id}_admin" : NULL ) ) ) );
$defaults = array();
if ( $this->id )
{
if ( $this->default_member )
{
$defaults[] = 'member';
}
if ( $this->default_staff )
{
$defaults[] = 'staff';
}
}
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'status_default', $defaults, FALSE, array( 'options' => array( 'member' => 'status_default_member', 'staff' => 'status_default_staff' ) ), function( $val ) use ( $defaults )
{
$diff = array_diff( $defaults, $val );
if ( !empty( $diff ) )
{
throw new \DomainException( 'status_default_change' );
}
} ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'status_open', $this->open ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'status_assign', $this->assign ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'status_log', $this->log ) );
$form->add( new \IPS\Helpers\Form\Color( 'status_color', $this->color ?: 'C04848' ) );
$form->addHeader( 'public_settings' );
$form->add( new \IPS\Helpers\Form\Translatable( 'status_public_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_status_{$this->id}_front" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'status_public_set', $this->id ? \IPS\Member::loggedIn()->language()->checkKeyExists("nexus_status_{$this->id}_set") : FALSE, FALSE, array( 'togglesOn' => array( 'status_public_set_text' ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'status_public_set_text', NULL, FALSE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_status_{$this->id}_set" : NULL ) ), NULL, NULL, NULL, 'status_public_set_text' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'status_is_locked', $this->id ? !$this->is_locked : FALSE ) );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( !$this->id )
{
$this->save();
}
if( isset( $values['status_name'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_status_{$this->id}_admin", $values['status_name'] );
unset( $values['status_name'] );
}
if( isset( $values['status_public_name'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_status_{$this->id}_front", $values['status_public_name'] );
unset( $values['status_public_name'] );
}
if( isset( $values['status_public_set'] ) )
{
if ( $values['status_public_set'] )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_status_{$this->id}_set", $values['status_public_set_text'] );
}
else
{
\IPS\Db::i()->delete( 'core_sys_lang_words', array( 'word_app=? AND word_key=?', 'nexus', "nexus_status_{$this->id}_set" ) );
}
unset( $values['status_public_set_text'] );
}
if( isset( $values['status_is_locked'] ) )
{
$values['status_is_locked'] = !$values['status_is_locked'];
}
if( isset( $values[ "status_member" ] ) OR isset( $values['status_staff'] ) )
{
foreach ( array( 'member', 'staff' ) as $k )
{
if ( isset( $values[ "status_{$k}" ] ) and in_array( $k, $values[ "status_{$k}" ] ) )
{
$values["default_{$k}"] = TRUE;
\IPS\Db::i()->update( 'nexus_support_statuses', array( 'default_member' => 0 ) );
}
else
{
$values["default_{$k}"] = FALSE;
}
}
}
if( isset( $values['status_default'] ) )
{
if ( in_array( 'member', $values['status_default'] ) )
{
$this->default_member = TRUE;
\IPS\Db::i()->update( 'nexus_support_statuses', array( 'status_default_member' => 0 ) );
}
if ( in_array( 'staff', $values['status_default'] ) )
{
$this->default_staff = TRUE;
\IPS\Db::i()->update( 'nexus_support_statuses', array( 'status_default_staff' => 0 ) );
}
unset( $values['status_default'] );
}
if( isset( $values['status_color'] ) )
{
$values['status_color'] = ltrim( $values['status_color'], '#' );
}
return $values;
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
*
* @code
array(
array(
'icon' => 'plus-circle', // Name of FontAwesome icon to use
'title' => 'foo', // Language key to use for button's title parameter
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
'class' => 'modalLink' // CSS Class to use on link (Optional)
),
... // Additional buttons
);
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
if ( isset( $buttons['delete'] ) and \IPS\Db::i()->select( 'COUNT(*)', 'nexus_support_requests', array( 'r_status=?', $this->id ) ) )
{
$buttons['delete']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('delete') );
}
return $buttons;
}
}
@@ -0,0 +1,237 @@
<?php
/**
* @brief Support Stock Action Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Nexus
* @since 15 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\nexus\Support;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Support Stock Action Model
*/
class _StockAction extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'nexus_support_stock_actions';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'action_';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'stock_actions';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'nexus_stockaction_';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'nexus',
'module' => 'support',
'all' => 'stockactions_manage'
);
/**
* Set Default Values
*
* @return void
*/
public function setDefaultValues()
{
$this->status = NULL;
$this->department = NULL;
$this->staff = NULL;
}
/**
* Get department
*
* @return \IPS\nexus\Support\Department|NULL
*/
public function get_department()
{
try
{
return $this->_data['department'] ? Department::load( $this->_data['department'] ) : NULL;
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
}
/**
* Set department
*
* @param \IPS\nexus\Support\Department|NULL $department The department
* @return void
*/
public function set_department( Department $department = NULL )
{
$this->_data['department'] = $department ? $department->id : 0;
}
/**
* Get status
*
* @return \IPS\nexus\Support\Status|NULL
*/
public function get_status()
{
try
{
return $this->_data['status'] ? Status::load( $this->_data['status'] ) : NULL;
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
}
/**
* Set purchase
*
* @param \IPS\nexus\Support\Status|NULL $status The status
* @return void
*/
public function set_status( Status $status = NULL )
{
$this->_data['status'] = $status ? $status->id : 0;
}
/**
* Get staff
*
* @return \IPS\Member|NULL
*/
public function get_staff()
{
try
{
return $this->_data['staff'] ? \IPS\Member::load( $this->_data['staff'] ) : NULL;
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
}
/**
* Set staff
*
* @param \IPS\Member|NULL $member The staff member to assign to
* @return void
*/
public function set_staff( \IPS\Member $member = NULL )
{
$this->_data['staff'] = $member ? $member->member_id : 0;
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
$form->add( new \IPS\Helpers\Form\Translatable( 'action_name', NULL, TRUE, array( 'app' => 'nexus', 'key' => ( $this->id ? "nexus_stockaction_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'action_status', $this->status ?: 0, FALSE, array( 'class' => 'IPS\nexus\Support\Status', 'zeroVal' => 'do_not_change' ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'action_department', $this->department ?: 0, FALSE, array( 'class' => 'IPS\nexus\Support\Department', 'zeroVal' => 'do_not_move' ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'action_staff', $this->staff ? $this->staff->member_id : 0, FALSE, array( 'options' => array_merge( array( 0 => 'do_not_change' ), \IPS\nexus\Support\Request::staff() ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'action_message_on', $this->message, FALSE, array( 'togglesOn' => array( 'action_message_editor' ) ) ) );
$form->add( new \IPS\Helpers\Form\Editor( 'action_message', $this->message, FALSE, array( 'app' => 'nexus', 'key' => 'Support', 'autoSaveKey' => md5( 'stockaction-' . ( $this->id ?: 'new' ) ) ), NULL, NULL, NULL, 'action_message_editor' ) );
$form->add( new \IPS\Helpers\Form\Node( 'action_show_in', ( !$this->show_in or $this->show_in === '*' ) ? 0 : explode( ',', $this->show_in ), FALSE, array( 'class' => 'IPS\nexus\Support\Department', 'zeroVal' => 'all', 'multiple' => TRUE ) ) );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( !$this->id )
{
$this->save();
}
if( isset( $values['action_name'] ) )
{
\IPS\Lang::saveCustom( 'nexus', "nexus_stockaction_{$this->id}", $values['action_name'] );
unset( $values['action_name'] );
}
if ( isset( $values['action_message_on'] ) AND !$values['action_message_on'] )
{
$values['action_message'] = NULL;
}
unset( $values['action_message_on'] );
foreach ( array( 'status', 'department' ) as $k )
{
if( isset( $values["action_{$k}"] ) )
{
$values["action_{$k}"] = $values["action_{$k}"] ?: NULL;
}
}
if( isset( $values['action_staff'] ) )
{
$values['action_staff'] = $values['action_staff'] ? \IPS\Member::load( $values['action_staff'] ) : NULL;
}
if( isset( $values['action_show_in'] ) )
{
$values['action_show_in'] = $values['action_show_in'] ? implode( ',', array_keys( $values['action_show_in'] ) ) : '*';
}
return $values;
}
}
Whitespace-only changes.