Files
IPB/applications/nexus/sources/Support/Reply.php
T
2025-12-19 05:32:19 -08:00

402 lines
11 KiB
PHP

<?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 ) ? $this->item()->department->email : \IPS\Settings::i()->email_out;
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 );
}
}
}