Version 4.0.13.1
This commit is contained in:
1 parent
f9e857d255
commit
c6a86f0d9b
7517 files changed
+597400
-668041
No files matched your search
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Acronym 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
|
||||
* @since 10 Sept 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acronym Model
|
||||
*/
|
||||
class _Acronym extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_acronyms';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = '';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'a_id';
|
||||
|
||||
/**
|
||||
* Display Form
|
||||
*
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
public static function form( $acronym )
|
||||
{
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form();
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'acronym_a_short', ( $acronym ) ? $acronym->a_short : NULL, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'acronym_a_long', ( $acronym ) ? $acronym->a_long : NULL, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'acronym_a_casesensitive', ( $acronym ) ? $acronym->a_casesensitive : NULL, FALSE, array(), NULL, NULL, NULL, 'acronym_a_casesensitive' ) );
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from form
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return \IPS\core\Acronym
|
||||
*/
|
||||
public static function createFromForm( $values, $current )
|
||||
{
|
||||
if( $current )
|
||||
{
|
||||
$obj = static::load( $current->a_id );
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj = new static;
|
||||
}
|
||||
|
||||
$obj->a_short = $values['acronym_a_short'];
|
||||
$obj->a_long = $values['acronym_a_long'];
|
||||
$obj->a_casesensitive = $values['acronym_a_casesensitive'];
|
||||
|
||||
$obj->save();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Advertisements 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
|
||||
* @since 30 Sept 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advertisements Model
|
||||
*/
|
||||
class _Advertisement extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_advertisements';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'ad_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief Advertisements loaded during this request (used to update impression count)
|
||||
* @see \IPS\Output::sendOutput()
|
||||
*/
|
||||
public static $advertisementIds = array();
|
||||
|
||||
/**
|
||||
* @brief Stored advertisements we can display on this page
|
||||
*/
|
||||
protected static $advertisements = NULL;
|
||||
|
||||
/**
|
||||
* Fetch advertisements and return the appropriate one to display
|
||||
*
|
||||
* @param string $location Advertisement location
|
||||
* @return \IPS\core\Advertisement|NULL
|
||||
*/
|
||||
public static function loadByLocation( $location )
|
||||
{
|
||||
/* If we know there are no ads, we don't need to bother */
|
||||
if ( !\IPS\Settings::i()->ads_exist )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fetch our advertisements, if we haven't already done so */
|
||||
if( static::$advertisements === NULL )
|
||||
{
|
||||
static::$advertisements = array();
|
||||
|
||||
if( !isset( \IPS\Data\Cache::i()->advertisements ) )
|
||||
{
|
||||
$ads = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*' ,'core_advertisements', array( "ad_active=1 AND ad_start < ? AND ( ad_end=0 OR ad_end > ? )", time(), time() ) ) as $row )
|
||||
{
|
||||
foreach ( explode( ',', $row['ad_location'] ) as $_location )
|
||||
{
|
||||
$ads[ $_location ][ $row['ad_id'] ] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Data\Cache::i()->advertisements = $ads;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ads = \IPS\Data\Cache::i()->advertisements;
|
||||
}
|
||||
|
||||
foreach( $ads as $loc => $rows )
|
||||
{
|
||||
foreach ( $rows as $row )
|
||||
{
|
||||
static::$advertisements[ $loc ][] = static::constructFromData( $row );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Weed out any we don't see due to our group. This is done after loading the advertisements so that the cache can be properly primed regardless of group. */
|
||||
foreach( static::$advertisements as $adLocation => $ads )
|
||||
{
|
||||
foreach( $ads as $index => $ad )
|
||||
{
|
||||
if ( $ad->exempt != '*' )
|
||||
{
|
||||
$groupsToHideFrom = array_diff( array_keys(\IPS\Member\Group::groups()), json_decode( $ad->exempt, TRUE ) );
|
||||
|
||||
if ( \IPS\Member::loggedIn()->inGroup( $groupsToHideFrom ) )
|
||||
{
|
||||
unset( static::$advertisements[ $adLocation ][ $index ] );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No advertisements? Just return then */
|
||||
if( !count( static::$advertisements ) OR !isset( static::$advertisements[ $location ] ) OR !count( static::$advertisements[ $location ] ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reset so doesn't throw error */
|
||||
static::$advertisements[ $location ] = array_values( static::$advertisements[ $location ] );
|
||||
|
||||
/* If we only have one, that is the one we will show */
|
||||
if( count( static::$advertisements[ $location ] ) === 1 )
|
||||
{
|
||||
$advertisement = static::$advertisements[ $location ][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Figure out which one to show you */
|
||||
switch( \IPS\Settings::i()->ads_circulation )
|
||||
{
|
||||
case 'random':
|
||||
$advertisement = static::$advertisements[ $location ][ array_rand( static::$advertisements[ $location ] ) ];
|
||||
break;
|
||||
|
||||
case 'newest':
|
||||
usort( static::$advertisements[ $location ], function( $a, $b ){
|
||||
return strcmp( $a->start, $b->start );
|
||||
} );
|
||||
|
||||
$advertisement = static::$advertisements[ $location ][0];
|
||||
break;
|
||||
|
||||
case 'oldest':
|
||||
usort( static::$advertisements[ $location ], function( $a, $b ){
|
||||
return strcmp( $b->start, $a->start );
|
||||
} );
|
||||
|
||||
$advertisement = static::$advertisements[ $location ][0];
|
||||
break;
|
||||
|
||||
case 'least':
|
||||
usort( static::$advertisements[ $location ], function( $a, $b ){
|
||||
return strcmp( $a->impressions, $b->impressions );
|
||||
} );
|
||||
|
||||
$advertisement = static::$advertisements[ $location ][0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $advertisement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the advertisement to an HTML string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
/* Showing HTML or an image? */
|
||||
if( $this->html )
|
||||
{
|
||||
if( \IPS\Request::i()->isSecure() AND $this->html_https_set )
|
||||
{
|
||||
$result = $this->html_https;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $this->html;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->advertisementImage( $this );
|
||||
}
|
||||
|
||||
/* Did we just hit the maximum impression count? If so, disable and then clear the cache so it will rebuild next time. */
|
||||
if( $this->maximum_unit == 'i' AND $this->maximum_value > -1 AND $this->impressions + 1 >= $this->maximum_value )
|
||||
{
|
||||
$this->active = 0;
|
||||
$this->save();
|
||||
|
||||
if ( !\IPS\Db::i()->select( 'COUNT(*)', 'core_advertisements', 'ad_active=1' )->first() )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 0 ), array( 'conf_key=?', 'ads_exist' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the id so we can update impression count and return the ad */
|
||||
self::$advertisementIds[] = $this->id;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get images
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get__images()
|
||||
{
|
||||
if( !isset( $this->_data['_images'] ) )
|
||||
{
|
||||
$this->_data['_images'] = $this->_data['images'] ? json_decode( $this->_data['images'], TRUE ) : array();
|
||||
}
|
||||
|
||||
return $this->_data['_images'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
parent::save();
|
||||
unset( \IPS\Data\Cache::i()->advertisements );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file system storage extension
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function storageExtension()
|
||||
{
|
||||
if ( $this->member )
|
||||
{
|
||||
return 'nexus_Ads';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'core_Advertisements';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
/* If we have images, delete them */
|
||||
if( count( $this->_images ) )
|
||||
{
|
||||
\IPS\File::get( $this->storageExtension(), $this->_images['large'] )->delete();
|
||||
|
||||
if( isset( $this->_images['small'] ) )
|
||||
{
|
||||
\IPS\File::get( $this->storageExtension(), $this->_images['small'] )->delete();
|
||||
}
|
||||
|
||||
if( isset( $this->_images['medium'] ) )
|
||||
{
|
||||
\IPS\File::get( $this->storageExtension(), $this->_images['medium'] )->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete */
|
||||
parent::delete();
|
||||
|
||||
/* Empty the cache */
|
||||
unset( \IPS\Data\Cache::i()->advertisements );
|
||||
if ( !\IPS\Db::i()->select( 'COUNT(*)', 'core_advertisements', 'ad_active=1' )->first() )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 0 ), array( 'conf_key=?', 'ads_exist' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
}
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Announcement 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
|
||||
* @since 22 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Announcements;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Announcements Model
|
||||
*/
|
||||
class _Announcement extends \IPS\Content\Item
|
||||
{
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_announcements';
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'announce_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'id' );
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'title' => 'title',
|
||||
'date' => 'start',
|
||||
'author' => 'member_id',
|
||||
'views' => 'views',
|
||||
'content' => 'content'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'announcement';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $icon = 'bullhorn';
|
||||
|
||||
/**
|
||||
* Get SEO name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_seo_title()
|
||||
{
|
||||
if( !$this->_data['seo_title'] )
|
||||
{
|
||||
$this->seo_title = \IPS\Http\Url::seoTitle( $this->title );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this->_data['seo_title'] ?: \IPS\Http\Url::seoTitle( $this->title );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Form
|
||||
*
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
public static function form( $announcement )
|
||||
{
|
||||
/* Build the form */
|
||||
$form = new \IPS\Helpers\Form( NULL, 'save' );
|
||||
$form->class = 'ipsForm_vertical';
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'announce_title', ( $announcement ) ? $announcement->title : NULL, TRUE, array( 'maxLength' => 255 ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Date( 'announce_start', ( $announcement ) ? $announcement->start : new \IPS\DateTime ) );
|
||||
$form->add( new \IPS\Helpers\Form\Date( 'announce_end', ( $announcement ) ? $announcement->end : 0, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'indefinitely' ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'announce_content', ( $announcement ) ? $announcement->content : NULL, TRUE, array( 'app' => 'core', 'key' => 'Announcement', 'autoSaveKey' => ( $announcement ? 'editAnnouncement__' . $announcement->id : 'createAnnouncement' ), 'attachIds' => $announcement ? array( $announcement->id, NULL, 'announcement' ) : NULL ) ) );
|
||||
|
||||
/* Apps */
|
||||
$apps = array();
|
||||
|
||||
foreach( \IPS\Application::applications() as $key => $data )
|
||||
{
|
||||
if ( $key != 'core' )
|
||||
{
|
||||
$apps[ $key ] = $data->_title;
|
||||
}
|
||||
}
|
||||
$apps['core'] = 'announce_other_areas';
|
||||
|
||||
$toggles = array();
|
||||
$formFields = array();
|
||||
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'Announcements', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
$app = mb_substr( $key, 0, mb_strpos( $key, '_' ) );
|
||||
|
||||
if( method_exists( $extension, 'getSettingField' ) )
|
||||
{
|
||||
/* Grab our fields and add to the form */
|
||||
$field = $extension->getSettingField( $announcement );
|
||||
|
||||
$toggles[ $app ][] = $field->name;
|
||||
$formFields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'announce_app', ( $announcement ) ? $announcement->app : '*', TRUE, array( 'options' => $apps,'toggles' => $toggles, 'unlimited' => "*", 'unlimitedLang' => "everywhere" ) ) );
|
||||
|
||||
foreach( $formFields as $field )
|
||||
{
|
||||
$form->add( $field );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from form
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @param \IPS\core\Announcements\Announcement|NULL $current Current announcement
|
||||
* @return \IPS\core\Announcements\Announcement
|
||||
*/
|
||||
public static function _createFromForm( $values, $current )
|
||||
{
|
||||
if( $current )
|
||||
{
|
||||
$obj = static::load( $current->id );
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj = new static;
|
||||
$obj->member_id = \IPS\Member::loggedIn()->member_id;
|
||||
}
|
||||
|
||||
$obj->title = $values['announce_title'];
|
||||
$obj->seo_title = \IPS\Http\Url::seoTitle( $values['announce_title'] );
|
||||
$obj->content = $values['announce_content'];
|
||||
$obj->start = $values['announce_start'] ? $values['announce_start']->getTimestamp() : time();
|
||||
$obj->end = $values['announce_end'] ? $values['announce_end']->getTimestamp() : 0;
|
||||
$obj->app = $values['announce_app'] ? $values['announce_app'] : "*";
|
||||
|
||||
if( in_array( $obj->app, array_keys(\IPS\Application::applications() ) ) )
|
||||
{
|
||||
foreach ( \IPS\Application::load( $obj->app )->extensions( 'core', 'Announcements' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'getSettingField' ) )
|
||||
{
|
||||
$field = $extension->getSettingField( array() );
|
||||
$obj->ids = is_array( $values[ $field->name ] ) ? implode( ",", array_keys( $values[ $field->name ] ) ) : $values[ $field->name ];
|
||||
$obj->location = mb_substr( $key, mb_strpos( $key, '_' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj->location = "*";
|
||||
$obj->ids = NULL;
|
||||
}
|
||||
|
||||
$obj->save();
|
||||
|
||||
if( !$current )
|
||||
{
|
||||
\IPS\File::claimAttachments( 'createAnnouncement', $obj->id, NULL, 'announcement' );
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
if( $action )
|
||||
{
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=modcp&controller=modcp&tab=announcements&id={$this->id}", 'front', 'modcp_announcements' );
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'action', $action );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=system&controller=announcement&id={$this->id}", 'front', 'announcement', $this->seo_title );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get owner
|
||||
*
|
||||
* @return \IPS\Member
|
||||
*/
|
||||
public function owner()
|
||||
{
|
||||
return \IPS\Member::load( $this->member_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unclaim attachments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function unclaimAttachments()
|
||||
{
|
||||
\IPS\File::unclaimAttachments( 'core_Admin', $this->id, NULL, 'announcement' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Moderator Permission
|
||||
*
|
||||
* @param string $type 'edit', 'hide', 'unhide', 'delete', etc.
|
||||
* @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 modPermission( $type, \IPS\Member $member = NULL, \IPS\Node\Model $container = NULL )
|
||||
{
|
||||
if( in_array( $type, array( 'move', 'merge', 'lock', 'unlock', 'feature', 'unfeature', 'pin', 'unpin' ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if( $type == 'hide' OR $type == 'unhide' OR $type == 'active' OR $type == 'inactive' )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return parent::modPermission( $type, $member, $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that are available for selecting table rows
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getTableFilters()
|
||||
{
|
||||
return array(
|
||||
'active', 'inactive'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content table states
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tableStates()
|
||||
{
|
||||
$states = explode( ' ', parent::tableStates() );
|
||||
|
||||
if( !$this->active )
|
||||
{
|
||||
$states[] = "inactive";
|
||||
}
|
||||
else
|
||||
{
|
||||
$states[] = "active";
|
||||
}
|
||||
|
||||
return implode( ' ', $states );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do Moderator Action
|
||||
*
|
||||
* @param string $action The action
|
||||
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
|
||||
* @param string|NULL $reason Reason (for hides)
|
||||
* @return void
|
||||
* @throws \OutOfRangeException|\InvalidArgumentException|\RuntimeException
|
||||
*/
|
||||
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL )
|
||||
{
|
||||
if( static::modPermission( $action, $member ) )
|
||||
{
|
||||
if( $action == 'active' )
|
||||
{
|
||||
\IPS\Session::i()->modLog( 'modlog__action_announceactive', array( static::$title => TRUE, $this->url()->__toString() => FALSE, $this->mapped('title') => FALSE ), $this );
|
||||
|
||||
$this->active = 1;
|
||||
$this->save();
|
||||
|
||||
\IPS\Widget::deleteCaches( 'announcements', 'core' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( $action == 'inactive' )
|
||||
{
|
||||
\IPS\Session::i()->modLog( 'modlog__action_announceinactive', array( static::$title => TRUE, $this->url()->__toString() => FALSE, $this->mapped('title') => FALSE ), $this );
|
||||
|
||||
$this->active = 0;
|
||||
$this->save();
|
||||
|
||||
\IPS\Widget::deleteCaches( 'announcements', 'core' );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::modAction( $action, $member, $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any custom multimod actions this content item class supports
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function customMultimodActions()
|
||||
{
|
||||
if( !$this->active )
|
||||
{
|
||||
return array( "active" );
|
||||
}
|
||||
else
|
||||
{
|
||||
return array( "inactive" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any available custom multimod actions this content item class supports
|
||||
*
|
||||
* @note Return in format of array( array( 'action' => ..., 'icon' => ..., 'language' => ... ) )
|
||||
* @return array
|
||||
*/
|
||||
public static function availableCustomMultimodActions()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'groupaction' => 'active',
|
||||
'icon' => 'eye',
|
||||
'grouplabel' => 'announce_active_status',
|
||||
'action' => array(
|
||||
array(
|
||||
'action' => 'active',
|
||||
'icon' => 'eye',
|
||||
'label' => 'announce_mark_active'
|
||||
),
|
||||
array(
|
||||
'action' => 'inactive',
|
||||
'icon' => 'eye',
|
||||
'label' => 'announce_mark_inactive'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,506 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Bulkmail central library
|
||||
* @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 25 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\BulkMail;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk mail central library
|
||||
*/
|
||||
class _Bulkmailer extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_bulk_mail';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'mail_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief The number of bulk mails to send per cycle. You can override this by defining a constant BULK_MAILS_PER_CYCLE in constants.php, but setting too high may cause timeouts.
|
||||
*/
|
||||
public $perCycle = 500;
|
||||
|
||||
/**
|
||||
* Constructor - Create a blank object with default values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/* Do we want to send a different number of bulk emails per cycle? */
|
||||
if( defined( '\IPS\BULK_MAILS_PER_CYCLE' ) AND (int) \IPS\BULK_MAILS_PER_CYCLE > 0 )
|
||||
{
|
||||
$this->perCycle = (int) \IPS\BULK_MAILS_PER_CYCLE;
|
||||
}
|
||||
|
||||
return parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the bulk mail task
|
||||
*
|
||||
* @param int $force 0 or 1 to specify the task state or NULL to determine automatically
|
||||
* @return void
|
||||
*/
|
||||
public static function updateTask( $force=NULL )
|
||||
{
|
||||
/* Using Mandrill? */
|
||||
if( ( \IPS\Settings::i()->mandrill_api_key && \IPS\Settings::i()->mandrill_use_for ) AND $force === NULL )
|
||||
{
|
||||
$force = 0;
|
||||
}
|
||||
|
||||
/* Are we forcing the task enabled or disabled? */
|
||||
if( $force !== NULL )
|
||||
{
|
||||
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => (int) $force ), "`key`='bulkmail'" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out if we have any bulk mails to send and update task appropriately */
|
||||
if( \IPS\DB::i()->select( 'count(*)', 'core_bulk_mail', 'mail_active=1' )->first() > 0 )
|
||||
{
|
||||
/* Enable the task */
|
||||
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='bulkmail'" );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the task */
|
||||
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='bulkmail'" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get__options()
|
||||
{
|
||||
if ( !isset( $this->_data['opts'] ) )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return json_decode( $this->_data['opts'], TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mail options
|
||||
*
|
||||
* @param array $value Mail options
|
||||
* @return vpid
|
||||
*/
|
||||
public function set__options( $value )
|
||||
{
|
||||
$this->opts = json_encode( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the bulk mail. Determines if bulk mail should be sent via Mandrill or internally and dispatches appropriately.
|
||||
*
|
||||
* @return NULL|int
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
/* Mandrill can handle 2000 users in one cycle */
|
||||
if( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
|
||||
{
|
||||
$limit = array( $this->_data['sentto'], 2000 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$limit = array( $this->_data['sentto'], $this->perCycle );
|
||||
}
|
||||
|
||||
/* Get recipients */
|
||||
$results = $this->getQuery( $limit );
|
||||
|
||||
/* If there are no recipients we must be done */
|
||||
if( !count( $results ) )
|
||||
{
|
||||
self::updateTask( 0 );
|
||||
|
||||
$this->active = 0;
|
||||
$this->save();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Dispatch */
|
||||
if( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
|
||||
{
|
||||
$sent = $this->_sendMandrill( $results );
|
||||
}
|
||||
else
|
||||
{
|
||||
$sent = $this->_sendInternal( $results );
|
||||
}
|
||||
|
||||
/* Update bulk mail record */
|
||||
if( $sent === 0 )
|
||||
{
|
||||
$this->active = 0;
|
||||
$this->updated = time();
|
||||
$this->save();
|
||||
|
||||
self::updateTask( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->updated = time();
|
||||
$this->sentto = ( $this->_data['sentto'] + $sent );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/* Return the number of users the email was sent to */
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the bulk mail using our own internal mailer
|
||||
*
|
||||
* @param \IPS\Db\Select $recipients Result set for recipients for the bulk mail
|
||||
* @return int Number of users the bulk mail was sent to
|
||||
*/
|
||||
protected function _sendInternal( $recipients=array() )
|
||||
{
|
||||
$sent = 0;
|
||||
|
||||
/* Loop over recipients and send the email */
|
||||
foreach( $recipients as $recipient )
|
||||
{
|
||||
$_recipient = \IPS\Member::constructFromData( $recipient );
|
||||
$htmlBody = $this->formatBody( $_recipient );
|
||||
|
||||
$email = \IPS\Email::buildFromContent( $this->_data['subject'], $htmlBody );
|
||||
$email->headers['Precedence'] = 'bulk';
|
||||
$email->buildUnsubscribe( 'bulk', $_recipient );
|
||||
$email->send( $_recipient );
|
||||
|
||||
$sent++;
|
||||
}
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the bulk mail using Mandrill
|
||||
*
|
||||
* @param \IPS\Db\Select $recipients Result set for recipients for the bulk mail
|
||||
* @return int Number of users the bulk mail was sent to
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function _sendMandrill( $recipients=array() )
|
||||
{
|
||||
$sent = 0;
|
||||
|
||||
/* Get the email we want to send in the HTML template - we intentionally do not swap out tags as Mandrill does this for us. */
|
||||
$email = \IPS\Email::buildFromContent( $this->_data['subject'], $this->_data['content'] );
|
||||
$email->unsubscribe = array( 'link' => \IPS\Http\Url::internal( '' ), 'text' => '*|unsubscribe|*' );
|
||||
$body = $email->body['html'];
|
||||
|
||||
/* Determine the variables to use */
|
||||
$usedVars = array( 'unsubscribe' );
|
||||
|
||||
foreach( array_keys( self::getTags() ) as $k )
|
||||
{
|
||||
if ( mb_strpos( $body, $k ) !== FALSE )
|
||||
{
|
||||
$usedVars[] = $k;
|
||||
|
||||
/* While we're not actually parsing the tags, we do need to put into Mandrill format */
|
||||
$body = str_replace( $k, '*|' . str_replace( array( '{', '}' ), '', $k ) . '|*', $body );
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop over recipients and collect information */
|
||||
$recipientsTo = array();
|
||||
$recipientsMerge = array();
|
||||
|
||||
foreach( $recipients as $recipient )
|
||||
{
|
||||
$_recipient = \IPS\Member::constructFromData( $recipient );
|
||||
|
||||
/* While registration and other similar routines should validate the email, we need to filter out any bad ones that may have crept through else it causes Mandrill to ignore the batch */
|
||||
if ( !$_recipient->email OR !$_recipient->name OR filter_var( $_recipient->email, FILTER_VALIDATE_EMAIL ) === FALSE )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Put our recipients into an array */
|
||||
$recipientsTo[] = array( 'email' => $_recipient->email, 'name' => $_recipient->name );
|
||||
|
||||
/* Format variables */
|
||||
$vars = array();
|
||||
|
||||
foreach( $this->returnTagValues( 2, $_recipient ) as $k => $v )
|
||||
{
|
||||
if ( in_array( $k, $usedVars ) )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $v );
|
||||
$vars[] = array( 'name' => str_replace( array( '{', '}' ), '', $k ), 'content' => $v );
|
||||
}
|
||||
}
|
||||
|
||||
$email->buildUnsubscribe( 'bulk', $_recipient );
|
||||
$langKey = $email->unsubscribe['text'];
|
||||
|
||||
$vars[] = array( 'name' => 'unsubscribe', 'content' => "<a href='" . $email->unsubscribe['link'] . "'>" . $_recipient->language()->get( $langKey ) . "</a>" );
|
||||
|
||||
if ( !empty( $vars ) )
|
||||
{
|
||||
$recipientsMerge[] = array( 'rcpt' => $recipient['email'], 'vars' => $vars );
|
||||
}
|
||||
|
||||
$sent++;
|
||||
}
|
||||
|
||||
/* Sort out global vars */
|
||||
$globalMergeVars = array();
|
||||
|
||||
foreach ( $this->returnTagValues( 1 ) as $k => $v )
|
||||
{
|
||||
if ( in_array( $k, $usedVars ) )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $v );
|
||||
|
||||
$globalMergeVars[] = array( 'name' => str_replace( array( '{', '}' ), '', $k ), 'content' => $v );
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix language strings */
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $body );
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $this->_data['subject'] );
|
||||
|
||||
/* Replace attachment and emoticon URLs */
|
||||
\IPS\Output::i()->parseFileObjectUrls( $body );
|
||||
|
||||
$response = \IPS\Email::mandrill( 'messages_send', \IPS\Settings::i()->mandrill_api_key, array(
|
||||
'message' => array(
|
||||
'html' => $body,
|
||||
'subject' => $this->_data['subject'],
|
||||
'from_email' => \IPS\Settings::i()->email_out,
|
||||
'from_name' => \IPS\Settings::i()->board_name,
|
||||
'to' => $recipientsTo,
|
||||
'auto_text' => TRUE,
|
||||
'url_strip_qs' => FALSE,
|
||||
'preserve_recipients' => FALSE,
|
||||
'merge' => TRUE,
|
||||
'global_merge_vars' => $globalMergeVars,
|
||||
'merge_vars' => $recipientsMerge,
|
||||
'tags' => array_merge( array( 'ips' ), array_filter( $this->_options['mandrill_tags'], function( $v ) { return (bool) $v; } ) )
|
||||
),
|
||||
'async' => TRUE
|
||||
) );
|
||||
|
||||
if ( isset( $response->status ) and $response->status == 'error' )
|
||||
{
|
||||
throw new \UnexpectedValueException( \IPS\Member::loggedIn()->language()->addToStack('mandrill_error', FALSE, array( 'sprintf' => array( $response->message ) ) ) );
|
||||
}
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query to fetch members based on our filters
|
||||
*
|
||||
* @param array $limit The limit to apply to the query
|
||||
* @return \IPS\Db\Select
|
||||
* @note Returns a default limit of $this->perCycle which should be overridden typically. The default limit is simply to ensure we don't accidentally run a query against the members table without any limit if someone forgets.
|
||||
*/
|
||||
public function getQuery( $limit=array() )
|
||||
{
|
||||
/* Compile where */
|
||||
$where = array();
|
||||
$where[] = array( "core_members.allow_admin_mails=1" );
|
||||
$where[] = array( "core_members.temp_ban=0" );
|
||||
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', FALSE, 'core' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'getQueryWhereClause' ) )
|
||||
{
|
||||
/* Grab our fields and add to the form */
|
||||
if( !empty( $this->_options[ $key ] ) )
|
||||
{
|
||||
if( $_where = $extension->getQueryWhereClause( $this->_options[ $key ] ) )
|
||||
{
|
||||
if ( is_string( $_where ) )
|
||||
{
|
||||
$_where = array( $_where );
|
||||
}
|
||||
|
||||
$where = array_merge( $where, $_where );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compile query */
|
||||
$query = \IPS\Db::i()->select( 'core_members.member_id AS my_member_id, core_members.*', 'core_members', $where, 'core_members.member_id', $limit, 'member_id', NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS );
|
||||
|
||||
/* Run callbacks */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'queryCallback' ) )
|
||||
{
|
||||
/* Grab our fields and add to the form */
|
||||
if( !empty( $this->_options[ $key ] ) )
|
||||
{
|
||||
$data = $this->_options[ $key ];
|
||||
$extension->queryCallback( $data, $query );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a bulk mail by replacing out the tags with the proper values
|
||||
*
|
||||
* @param \IPS\Member $member Member data
|
||||
* @return string
|
||||
*/
|
||||
public function formatBody( $member )
|
||||
{
|
||||
if( empty($this->_data['content']) )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/* Default tags */
|
||||
$tags = $this->returnTagValues( 0, $member );
|
||||
|
||||
/* Work on a copy rather than the original template */
|
||||
$body = $this->_data['content'];
|
||||
|
||||
/* Loop over the tags and swap out as appropriate */
|
||||
foreach( $tags as $key => $value )
|
||||
{
|
||||
$body = str_replace( $key, $value, $body );
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tag values
|
||||
*
|
||||
* @param int $type 0=All, 1=Global, 2=Member-specific
|
||||
* @param NULL|\IPS\Member $member Member object if $type is 0 or 2
|
||||
* @return array
|
||||
*/
|
||||
protected function returnTagValues( $type, $member=NULL )
|
||||
{
|
||||
$tags = array();
|
||||
|
||||
/* Do we want global tags? */
|
||||
if( $type === 0 OR $type === 1 )
|
||||
{
|
||||
$mostOnline = json_decode( \IPS\Settings::i()->most_online, TRUE );
|
||||
|
||||
$tags['{suite_name}'] = \IPS\Settings::i()->board_name;
|
||||
$tags['{suite_url}'] = \IPS\Settings::i()->base_url;
|
||||
$tags['{busy_time}'] = \IPS\DateTime::ts( ( $mostOnline['time'] ) ? $mostOnline['time'] : time() )->localeDate();
|
||||
$tags['{busy_count}'] = $mostOnline['count'];
|
||||
|
||||
/* Only bother querying if we need the value */
|
||||
if( mb_strpos( $this->_data['content'], '{reg_total}' ) !== FALSE )
|
||||
{
|
||||
$tags['{reg_total}'] = \IPS\DB::i()->select( 'count(*)', 'core_members', 'member_id > 0' )->first();
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we want member tags? */
|
||||
if( $type === 0 OR $type === 2 )
|
||||
{
|
||||
$tags['{member_id}'] = $member->member_id;
|
||||
$tags['{member_name}'] = $member->name;
|
||||
$tags['{member_joined}'] = $member->joined->localeDate();
|
||||
$tags['{member_last_visit}'] = \IPS\DateTime::ts( $member->last_visit )->localeDate();
|
||||
$tags['{member_posts}'] = $member->member_posts;
|
||||
}
|
||||
|
||||
/* Now retrieve tags via any bulk mail extensions. We only want them to return an array of tags to perform formatting, but
|
||||
$body is passed in case a particular tag is computationally expensive so that the extension may "sniff" for it and elect
|
||||
not to perform the computation if it is not used. */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'returnTagValues' ) )
|
||||
{
|
||||
$tags = array_merge( $tags, $extension->returnTagValues( $this->_data['content'], $type, $member ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the tags that can be used in bulk mails
|
||||
*
|
||||
* @return array An array of tags in foramt of 'tag' => 'explanation text'
|
||||
*/
|
||||
public static function getTags()
|
||||
{
|
||||
/* Default tags */
|
||||
$tags = array(
|
||||
'{member_id}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_id'),
|
||||
'{member_name}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_name'),
|
||||
'{member_joined}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_joined'),
|
||||
'{member_last_visit}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_last_visit'),
|
||||
'{member_posts}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_posts'),
|
||||
'{reg_total}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_reg_total'),
|
||||
'{suite_name}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_suite_name'),
|
||||
'{suite_url}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_suite_url'),
|
||||
'{busy_count}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_busy_count'),
|
||||
'{busy_time}' => \IPS\Member::loggedIn()->language()->addToStack('bmtag_busy_time'),
|
||||
);
|
||||
|
||||
/* Now grab tags from any bulk mail extensions */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'getTags' ) )
|
||||
{
|
||||
$tags = array_merge( $tags, $extension->getTags() );
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
\IPS\File::unclaimAttachments( 'core_Admin', $this->id, NULL, 'bulkmail' );
|
||||
parent::delete();
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Digest Class
|
||||
* @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 08 May 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Digest;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Digest Class
|
||||
*/
|
||||
class _Digest
|
||||
{
|
||||
/**
|
||||
* @brief [IPS\Member] Digest member object
|
||||
*/
|
||||
public $member = NULL;
|
||||
|
||||
/**
|
||||
* @brief Output to include in digest email template
|
||||
*/
|
||||
public $output = array( 'html' => '', 'plain' => '' );
|
||||
|
||||
/**
|
||||
* @brief Frequency Daily/Weekly
|
||||
*/
|
||||
public $frequency = NULL;
|
||||
|
||||
/**
|
||||
* @brief Is there anything to send?
|
||||
*/
|
||||
public $hasContent = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Mail Object
|
||||
*/
|
||||
protected $mail;
|
||||
|
||||
/**
|
||||
* Build Digest
|
||||
*
|
||||
* @param array $data Array of follow records
|
||||
* @return void
|
||||
*/
|
||||
public function build( $data )
|
||||
{
|
||||
$this->mail = \IPS\Email::buildFromTemplate( 'core', 'digest', array( $this->member, $this->frequency ) );
|
||||
$this->mail->language = $this->member->language();
|
||||
|
||||
$max = ceil( 80 / count( array_keys( $data ) ) );
|
||||
$count = 0;
|
||||
$total = count( array_keys( $data ) );
|
||||
|
||||
foreach( $data as $app => $area )
|
||||
{
|
||||
foreach( $area as $key => $follows )
|
||||
{
|
||||
$areaPlainOutput = NULL;
|
||||
$areaHtmlOutput = NULL;
|
||||
$added = FALSE;
|
||||
|
||||
/* Following an item or node */
|
||||
$class = 'IPS\\' . $app . '\\' . ucfirst( $key );
|
||||
|
||||
if ( class_exists( $class ) )
|
||||
{
|
||||
$parents = class_parents( $class );
|
||||
|
||||
if ( in_array( 'IPS\Node\Model', $parents ) )
|
||||
{
|
||||
foreach ( $follows as $follow )
|
||||
{
|
||||
if ( property_exists( $class, 'contentItemClass' ) )
|
||||
{
|
||||
$itemClass= $class::$contentItemClass;
|
||||
|
||||
foreach ( $itemClass::getItemsWithPermission( array(
|
||||
array( $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['container'] . '=? AND ' . $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['date'] . ' > ? AND ' . $itemClass::$databaseTable . '.' .$itemClass::$databasePrefix . $itemClass::$databaseColumnMap['author'] . '!=?', $follow['follow_rel_id'], $follow['follow_notify_sent'] ?: $follow['follow_added'], $follow['follow_member_id'] ) ),
|
||||
$itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['date'] . ' ASC',
|
||||
$max,
|
||||
'read',
|
||||
FALSE,
|
||||
NULL,
|
||||
$this->member,
|
||||
TRUE
|
||||
) as $item )
|
||||
{
|
||||
try
|
||||
{
|
||||
$areaPlainOutput .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'plain' )->item( $item, $this->mail );
|
||||
$areaHtmlOutput .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'html' )->item( $item, $this->mail );
|
||||
|
||||
$added = TRUE;
|
||||
++$count;
|
||||
}
|
||||
catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( in_array( 'IPS\Content\Item', $parents ) )
|
||||
{
|
||||
foreach ( $follows as $follow )
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $class::load( $follow['follow_rel_id'] );
|
||||
|
||||
foreach( $item->comments( 5, NULL, 'date', 'asc', NULL, FALSE, \IPS\DateTime::ts( $follow['follow_notify_sent'] ?: $follow['follow_added'] ) ) as $comment )
|
||||
{
|
||||
/* If an app forgot digest templates, we don't want the entire task to fail to ever run again */
|
||||
if( !method_exists( \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'plain' ), 'comment' ) OR
|
||||
!method_exists( \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'html' ), 'comment' ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$areaPlainOutput .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'plain' )->comment( $comment, $this->mail );
|
||||
$areaHtmlOutput .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', $app, 'html' )->comment( $comment, $this->mail );
|
||||
|
||||
$added = TRUE;
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrapper */
|
||||
if( $added )
|
||||
{
|
||||
$this->output['plain'] .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', 'core', 'plain' )->areaWrapper( $areaPlainOutput, $app, $key, $max, $count, $total, $this->mail );
|
||||
$this->output['html'] .= \IPS\Email\Theme\Theme::i()->getTemplate( 'digests', 'core', 'html' )->areaWrapper( $areaHtmlOutput, $app, $key, $max, $count, $total, $this->mail );
|
||||
|
||||
$this->hasContent = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Digest
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
if( $this->hasContent )
|
||||
{
|
||||
$this->mail->parseTemplate();
|
||||
|
||||
$this->mail->emailBody['html'] = str_replace( "<%digest%>", $this->output['html'], $this->mail->emailBody['html'] );
|
||||
$this->mail->emailBody['plain'] = str_replace( "<%digest%>", $this->output['plain'], $this->mail->emailBody['plain'] );
|
||||
|
||||
//$this->mail->emailBody = $this->mail->wrapEmail();
|
||||
|
||||
$this->mail->send( $this->member );
|
||||
}
|
||||
|
||||
/* After sending digest update core_follows to set notify_sent (don't forget where clause for frequency) */
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_sent' => time() ), array( 'follow_member_id=? AND follow_notify_freq=?', $this->member->member_id, $this->frequency ) );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Table Builder for followed content
|
||||
* @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 Gallery
|
||||
* @since 16 Apr 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Followed;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table Builder for followed content
|
||||
*/
|
||||
class _Table extends \IPS\Helpers\Table\Db
|
||||
{
|
||||
/**
|
||||
* @brief Follow class data
|
||||
*/
|
||||
protected $currentType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $className Name of class to load data from
|
||||
* @param array $currentType Follow class data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $className, $currentType )
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->currentType = $currentType;
|
||||
$this->include = array( 'follow_added', 'follow_app', 'follow_area', 'follow_rel_id', 'follow_notify_freq', 'follow_is_anon' );
|
||||
$this->classes[] = 'ipsDataList_zebra';
|
||||
|
||||
$return = parent::__construct( 'core_follow', \IPS\Http\Url::internal( 'app=core&module=system&controller=followed', 'front', 'followed_content' )->setQueryString( 'type', "{$currentType[0]}_{$currentType[1]}" ), array( 'follow_member_id=? AND follow_app=? AND follow_area=?', \IPS\Member::loggedIn()->member_id, $currentType[0], $currentType[1] ) );
|
||||
|
||||
if ( !$this->sortBy )
|
||||
{
|
||||
$this->sortBy = 'follow_added';
|
||||
$this->sortDirection = 'desc';
|
||||
}
|
||||
|
||||
if( is_subclass_of( $className, 'IPS\Content\Item' ) )
|
||||
{
|
||||
$this->rowsTemplate = $className::contentTableTemplate();
|
||||
$containerClass = $className::$containerNodeClass;
|
||||
$this->group = 'follow_id';
|
||||
|
||||
$this->joins = array(
|
||||
array( 'from' => 'core_permission_index', 'where' => array( "core_permission_index.app=? AND core_permission_index.perm_type=?", $containerClass::$permApp, $containerClass::$permType ) ),
|
||||
array( 'from' => $className::$databaseTable, 'where' => array( $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnId . '=core_follow.follow_rel_id AND core_follow.follow_app=?', $currentType[0] ) )
|
||||
);
|
||||
|
||||
/* Exclude hidden items */
|
||||
if ( in_array( 'IPS\Content\Hideable', class_implements( $className ) ) and !$className::canViewHiddenItems() )
|
||||
{
|
||||
$authorCol = $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnMap['author'];
|
||||
if ( isset( $className::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$col = $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnMap['approved'];
|
||||
$this->where[0] .= " AND ( {$col}=1 OR ( {$col}=0 AND {$authorCol}=" . \IPS\Member::loggedIn()->member_id . " ) )";
|
||||
}
|
||||
elseif ( isset( $className::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$col = $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnMap['hidden'];
|
||||
$this->where[0] .= " AND ( {$col}=0 OR ( {$col}=1 AND {$authorCol}=" . \IPS\Member::loggedIn()->member_id . " ) )";
|
||||
}
|
||||
}
|
||||
|
||||
/* Permissions */
|
||||
if ( in_array( 'IPS\Content\Permissions', class_implements( $className ) ) )
|
||||
{
|
||||
$containerClass = $className::$containerNodeClass;
|
||||
$this->where[0] .= ' AND (' . \IPS\Db::i()->findInSet( 'core_permission_index.perm_' . $containerClass::$permissionMap['view'], \IPS\Member::loggedIn()->groups ) . ' OR core_permission_index.perm_' . $containerClass::$permissionMap['view'] . "='*' )";
|
||||
}
|
||||
|
||||
/* Additional where */
|
||||
$joinContainer = FALSE;
|
||||
$joins = array();
|
||||
if ( $extraWhere = $className::followWhere( $joinContainer, $joins ) )
|
||||
{
|
||||
if( isset( $extraWhere['item'] ) )
|
||||
{
|
||||
$this->where = array_merge( array( $this->where ), $extraWhere['item'] );
|
||||
|
||||
if( isset( $extraWhere['container'] ) )
|
||||
{
|
||||
$this->where = array_merge( $this->where, $extraWhere['container'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->where = array_merge( array( $this->where ), $extraWhere );
|
||||
}
|
||||
}
|
||||
if ( $joinContainer )
|
||||
{
|
||||
$containerClass = $className::$containerNodeClass;
|
||||
$this->joins[] = array( 'from' => $containerClass::$databaseTable, 'where' => $containerClass::$databaseTable . '.' . $containerClass::$databasePrefix . $containerClass::$databaseColumnId . '=' . $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnMap['container'] );
|
||||
}
|
||||
$this->joins = array_merge( $this->joins, $joins );
|
||||
}
|
||||
elseif( $className == "\IPS\Member" )
|
||||
{
|
||||
$this->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'system', 'core', 'front' ), 'followedContentMemberRow' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->rowsTemplate = $className::nodeTableTemplate();
|
||||
|
||||
$this->joins = array(
|
||||
array( 'from' => 'core_permission_index', 'where' => array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=?", $className::$permApp, $className::$permType, $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnId ) ),
|
||||
array( 'from' => $className::$databaseTable, 'where' => array( $className::$databaseTable . '.' . $className::$databasePrefix . $className::$databaseColumnId . '=follow_rel_id AND follow_app=?', $currentType[0] ) ),
|
||||
);
|
||||
|
||||
/* Permission check? */
|
||||
if ( in_array( 'IPS\Node\Permissions', class_implements( $className ) ) )
|
||||
{
|
||||
$this->where[1] .= ' AND (' . \IPS\Db::i()->findInSet( 'core_permission_index.perm_' . $className::$permissionMap['view'], \IPS\Member::loggedIn()->groups ) . ' OR ' . 'core_permission_index.perm_' . $className::$permissionMap['view'] . "='*' )";
|
||||
}
|
||||
|
||||
/* Additional where */
|
||||
if ( method_exists( $className, 'followWhere' ) )
|
||||
{
|
||||
$extraWhere = $className::followWhere();
|
||||
|
||||
if( isset( $extraWhere['item'] ) )
|
||||
{
|
||||
$this->where = array_merge( array( $this->where ), $extraWhere['item'] );
|
||||
|
||||
if( isset( $extraWhere['container'] ) )
|
||||
{
|
||||
$this->where = array_merge( $this->where, $extraWhere['container'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->where = array_merge( array( $this->where ), $extraWhere );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do any multi-mod */
|
||||
if ( isset( \IPS\Request::i()->modaction ) )
|
||||
{
|
||||
$this->multiMod();
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rows
|
||||
*
|
||||
* @param array $advancedSearchValues Values from the advanced search form
|
||||
* @return array
|
||||
*/
|
||||
public function getRows( $advancedSearchValues )
|
||||
{
|
||||
$rows = parent::getRows( $advancedSearchValues );
|
||||
|
||||
foreach( $rows as $index => $row )
|
||||
{
|
||||
if( $row['follow_area'] == 'member' AND $row['follow_app'] == 'core' )
|
||||
{
|
||||
$object = \IPS\Member::load( $row['follow_rel_id'] );
|
||||
$object->_followData = $row;
|
||||
$rows[ $index ] = $object;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( \IPS\Application::load( $row['follow_app'] )->extensions( 'core', 'ContentRouter' ) as $key => $router )
|
||||
{
|
||||
foreach( $router->classes as $class )
|
||||
{
|
||||
$followArea = mb_strtolower( mb_substr( $class, mb_strrpos( $class, '\\' ) + 1 ) );
|
||||
|
||||
if( $followArea == $row['follow_area'] AND $class::$application == $row['follow_app'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$object = $class::load( $row['follow_rel_id'] );
|
||||
$object->_followData = $row;
|
||||
$rows[ $index ] = $object;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
unset( $rows[ $index ] );
|
||||
|
||||
/* If the item doesn't exist we may as well clean up core_follow */
|
||||
\IPS\Db::i()->delete( 'core_follow', array( array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', $row['follow_app'], $row['follow_area'], $row['follow_rel_id'] ) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$containers = array();
|
||||
|
||||
if( isset( $class::$containerNodeClass ) )
|
||||
{
|
||||
$containers[ $class::$containerNodeClass ] = $class::$containerNodeClass;
|
||||
}
|
||||
|
||||
if( isset( $class::$containerFollowClasses ) )
|
||||
{
|
||||
foreach( $class::$containerFollowClasses as $followClass )
|
||||
{
|
||||
$containers[ $followClass ] = $followClass;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( $containers as $container )
|
||||
{
|
||||
$containerArea = mb_strtolower( mb_substr( $container, mb_strrpos( $container, '\\' ) + 1 ) );
|
||||
|
||||
if( $containerArea == $row['follow_area'] AND $class::$application == $row['follow_app'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$object = $container::load( $row['follow_rel_id'] );;
|
||||
$object->_followData = $row;
|
||||
$rows[ $index ] = $object;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
unset( $rows[ $index ] );
|
||||
|
||||
/* If the item doesn't exist we may as well clean up core_follow */
|
||||
\IPS\Db::i()->delete( 'core_follow', array( array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', $row['follow_app'], $row['follow_area'], $row['follow_rel_id'] ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return table filters
|
||||
*/
|
||||
public $showFilters = TRUE;
|
||||
|
||||
/**
|
||||
* Saved Actions (for multi-moderation)
|
||||
*/
|
||||
public $savedActions = array();
|
||||
|
||||
/**
|
||||
* Return the filters that are available for selecting table rows
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return array(
|
||||
'follow_freq_immediate', 'follow_freq_daily', 'follow_freq_weekly', 'follow_freq_none',
|
||||
'',
|
||||
'follow_privacy_1', 'follow_privacy_0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the user have permission to use the multi-mod checkboxes?
|
||||
*
|
||||
* @param string|null $action Specific action to check (hide/unhide, etc.) or NULL for a generic check
|
||||
* @return bool
|
||||
*/
|
||||
public function canModerate( $action=NULL )
|
||||
{
|
||||
if ( $action === NULL )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* What multimod actions are available
|
||||
*
|
||||
* @param object $item Item
|
||||
* @return array
|
||||
*/
|
||||
public function multimodActions( $item )
|
||||
{
|
||||
$return = array();
|
||||
|
||||
if ( $item->_followData )
|
||||
{
|
||||
if ( !( $item instanceof \IPS\Member ) )
|
||||
{
|
||||
foreach ( array( 'immediate', 'daily', 'weekly', 'none' ) as $k )
|
||||
{
|
||||
if ( $item->_followData['follow_notify_freq'] != $k )
|
||||
{
|
||||
$return[] = 'follow_' . $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $item->_followData['follow_is_anon'] )
|
||||
{
|
||||
$return[] = 'follow_public';
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[] = 'follow_anonymous';
|
||||
}
|
||||
|
||||
$return[] = 'unfollow';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multimod
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function multimod()
|
||||
{
|
||||
if( !is_array( \IPS\Request::i()->moderate ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$where = array( array( 'follow_member_id=? AND follow_app=? AND follow_area=?', \IPS\Member::loggedIn()->member_id, $this->currentType[0], $this->currentType[1] ), \IPS\Db::i()->in( 'follow_rel_id', array_keys( \IPS\Request::i()->moderate ) ) );
|
||||
|
||||
$update = array();
|
||||
switch ( \IPS\Request::i()->modaction )
|
||||
{
|
||||
case 'follow_immediate':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_freq' => 'immediate' ), $where );
|
||||
break;
|
||||
case 'follow_daily':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_freq' => 'daily' ), $where );
|
||||
break;
|
||||
case 'follow_weekly':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_freq' => 'weekly' ), $where );
|
||||
break;
|
||||
case 'follow_none':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_freq' => 'none' ), $where );
|
||||
break;
|
||||
|
||||
case 'follow_public':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_is_anon' => 0 ), $where );
|
||||
break;
|
||||
case 'follow_anonymous':
|
||||
\IPS\Db::i()->update( 'core_follow', array( 'follow_is_anon' => 1 ), $where );
|
||||
break;
|
||||
|
||||
case 'unfollow':
|
||||
\IPS\Db::i()->delete( 'core_follow', $where );
|
||||
break;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $this->baseUrl );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Ignore Record
|
||||
* @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 20 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore Record
|
||||
*/
|
||||
class _Ignore extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_ignored_users';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'ignore_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'ignore_ignore_id' );
|
||||
|
||||
/**
|
||||
* Get types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function types()
|
||||
{
|
||||
return array( 'topics', 'messages', 'signatures' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Form
|
||||
*
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
public static function form()
|
||||
{
|
||||
$ignore = NULL;
|
||||
try
|
||||
{
|
||||
$ignore = static::load( \IPS\Request::i()->id, 'ignore_ignore_id', array( 'ignore_owner_id=?', \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
if ( \IPS\Request::i()->id )
|
||||
{
|
||||
$ignore = new static;
|
||||
$ignore->ignore_id = \IPS\Request::i()->id;
|
||||
}
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form( NULL, $ignore ? 'ignore_edit' : 'ignore_submit' );
|
||||
$form->class = 'ipsForm_vertical';
|
||||
$form->add( new \IPS\Helpers\Form\Member( 'member', $ignore ? \IPS\Member::load( $ignore->ignore_id ) : NULL, TRUE, array( 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('ignore_placeholder') ) ) );
|
||||
|
||||
foreach ( static::types() as $type )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Checkbox( "ignore_{$type}", $ignore ? $ignore->$type : NULL ) );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from form
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return \IPS\core\Ignore
|
||||
*/
|
||||
public static function createFromForm( $values )
|
||||
{
|
||||
try
|
||||
{
|
||||
$obj = static::load( $values['member']->member_id, 'ignore_ignore_id', array( 'ignore_owner_id=?', \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$obj = new static;
|
||||
}
|
||||
|
||||
if ( $values['member']->member_id == \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'cannot_ignore_self' );
|
||||
}
|
||||
|
||||
if ( $values['member']->group['g_bitoptions']['gbw_cannot_be_ignored'] )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'cannot_ignore_that_member' );
|
||||
}
|
||||
|
||||
$obj->owner_id = \IPS\Member::loggedIn()->member_id;
|
||||
$obj->ignore_id = $values['member']->member_id;
|
||||
|
||||
foreach ( static::types() as $type )
|
||||
{
|
||||
$obj->$type = $values["ignore_{$type}"];
|
||||
}
|
||||
|
||||
$obj->save();
|
||||
|
||||
\IPS\Member::loggedIn()->members_bitoptions['has_no_ignored_users'] = FALSE;
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,615 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Personal Conversation 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
|
||||
* @since 5 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Messenger;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Personal Conversation Model
|
||||
*/
|
||||
class _Conversation extends \IPS\Content\Item
|
||||
{
|
||||
/* !\IPS\Patterns\ActiveRecord */
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_message_topics';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'mt_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Item] Include the ability to search this content item in global site searches
|
||||
*/
|
||||
public static $includeInSiteSearch = FALSE;
|
||||
|
||||
/**
|
||||
* Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
\IPS\Db::i()->delete( 'core_message_topic_user_map', array( 'map_topic_id=?', $this->id ) );
|
||||
}
|
||||
|
||||
/* !\IPS\Content\Item */
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'personal_conversation';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'title' => 'title',
|
||||
'date' => array( 'date', 'start_time', 'last_post_time' ),
|
||||
'author' => 'starter_id',
|
||||
'num_comments' => 'replies',
|
||||
'last_comment' => 'last_post_time',
|
||||
'first_comment_id' => 'first_msg_id',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief Module
|
||||
*/
|
||||
public static $module = 'messaging';
|
||||
|
||||
/**
|
||||
* @brief Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'messenger_';
|
||||
|
||||
/**
|
||||
* @brief Comment Class
|
||||
*/
|
||||
public static $commentClass = 'IPS\core\Messenger\Message';
|
||||
|
||||
/**
|
||||
* @brief [Content\Item] First "comment" is part of the item?
|
||||
*/
|
||||
public static $firstCommentRequired = TRUE;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a given member create this type of content?
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param int $container Container (e.g. forum) ID, if appropriate
|
||||
* @param bool $showError If TRUE, rather than returning a boolean value, will display an error
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreate( \IPS\Member $member, \IPS\Node\Model $container=NULL, $showError=FALSE )
|
||||
{
|
||||
/* Can we access the module? */
|
||||
if ( !parent::canCreate( $member, $container, $showError ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We have to be logged in */
|
||||
if ( !$member->member_id )
|
||||
{
|
||||
if ( $showError )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission_guest', '1C149/1', 403, '' );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Have we exceeded our limit for the day/minute? */
|
||||
if ( $member->group['g_pm_perday'] )
|
||||
{
|
||||
$messagesSentToday = \IPS\Db::i()->select( 'COUNT(*) AS count, MAX(mt_date) AS max', 'core_message_topics', array( 'mt_starter_id=? AND mt_date>?', $member->member_id, \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimeStamp() ) )->first();
|
||||
if ( $messagesSentToday['count'] >= $member->group['g_pm_perday'] )
|
||||
{
|
||||
$next = \IPS\DateTime::ts( $messagesSentToday['max'] )->add( new \DateInterval( 'P1D' ) );
|
||||
|
||||
if ( $showError )
|
||||
{
|
||||
\IPS\Output::i()->error( $member->language()->addToStack( 'err_too_many_pms_day', FALSE, array( 'pluralize' => array( $member->group['g_pm_perday'] ) ) ), '1C149/2', 429, '', array( 'Retry-After' => $next->format('r') ) );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if ( $member->group['g_pm_flood_mins'] )
|
||||
{
|
||||
$messagesSentThisMinute = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_topics', array( 'mt_starter_id=? AND mt_date>?', $member->member_id, \IPS\DateTime::create()->sub( new \DateInterval( 'PT1M' ) )->getTimeStamp() ) )->first();
|
||||
if ( $messagesSentThisMinute >= $member->group['g_pm_flood_mins'] )
|
||||
{
|
||||
if ( $showError )
|
||||
{
|
||||
\IPS\Output::i()->error( $member->language()->addToStack( 'err_too_many_pms_minute', FALSE, array( 'pluralize' => array( $member->group['g_pm_flood_mins'] ) ) ), '1C149/3', 429, '', array( 'Retry-After' => 3600 ) );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is our inbox full? */
|
||||
if ( $member->group['g_max_messages'] )
|
||||
{
|
||||
$messagesInInbox = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1', $member->member_id ) )->first();
|
||||
if ( $messagesInInbox > $member->group['g_max_messages'] )
|
||||
{
|
||||
if ( $showError )
|
||||
{
|
||||
\IPS\Output::i()->error( 'err_inbox_full', '1C149/4', 403, '' );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get elements for add/edit form
|
||||
*
|
||||
* @param \IPS\Content\Item|NULL $item The current item if editing or NULL if creating
|
||||
* @param int $container Container (e.g. forum) ID, if appropriate
|
||||
* @return array
|
||||
*/
|
||||
public static function formElements( $item=NULL, \IPS\Node\Model $container=NULL )
|
||||
{
|
||||
$return = array();
|
||||
foreach ( parent::formElements( $item, $container ) as $k => $v )
|
||||
{
|
||||
if ( $k == 'title' )
|
||||
{
|
||||
if( !$item )
|
||||
{
|
||||
$member = NULL;
|
||||
|
||||
if( \IPS\Request::i()->to )
|
||||
{
|
||||
$member = \IPS\Member::load( \IPS\Request::i()->to );
|
||||
|
||||
if( !$member->member_id )
|
||||
{
|
||||
$member = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
$return['to'] = new \IPS\Helpers\Form\Member( 'messenger_to', $member, TRUE, array( 'multiple' => ( \IPS\Member::loggedIn()->group['g_max_mass_pm'] == 0 ) ? NULL : \IPS\Member::loggedIn()->group['g_max_mass_pm'] ), function ( $members )
|
||||
{
|
||||
$messengerModule = \IPS\Application\Module::get( 'core', 'messaging' );
|
||||
|
||||
if ( $members instanceof \IPS\Member )
|
||||
{
|
||||
$members = array( $members );
|
||||
}
|
||||
|
||||
if ( !is_array( $members ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'messenger_invalid_recipient' );
|
||||
}
|
||||
|
||||
foreach ( $members as $m )
|
||||
{
|
||||
if ( $m->members_disable_pm or !$m->canAccessModule( $messengerModule ) or ( ( $m->group['g_max_messages'] > 0 AND $m->msg_count_total >= $m->group['g_max_messages'] ) and !\IPS\Member::loggedIn()->group['gbw_pm_override_inbox_full'] ) or $m->isIgnoring( \IPS\Member::loggedIn(), 'messages' ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('meesnger_err_bad_recipient', FALSE, array( 'sprintf' => array( $m->name ) ) ) );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
$return[ $k ] = $v;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process created object BEFORE the object has been created
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
protected function processBeforeCreate( $values )
|
||||
{
|
||||
$this->to_count = count( $values['messenger_to'] );
|
||||
|
||||
parent::processBeforeCreate( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process created object AFTER the object has been created
|
||||
*
|
||||
* @param \IPS\Content\Comment|NULL $comment The first comment
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
protected function processAfterCreate( $comment, $values )
|
||||
{
|
||||
/* Set the first message ID */
|
||||
$this->first_msg_id = $comment->id;
|
||||
$this->save();
|
||||
|
||||
if ( is_array( $values['messenger_to'] ) )
|
||||
{
|
||||
$members = array_map( function( $member )
|
||||
{
|
||||
return $member->member_id;
|
||||
}, $values['messenger_to'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$members[] = $values['messenger_to']->member_id;
|
||||
}
|
||||
|
||||
$members[] = $this->starter_id;
|
||||
|
||||
/* Authorize everyone */
|
||||
$this->authorize( $members );
|
||||
|
||||
/* Run parent */
|
||||
parent::processAfterCreate( $comment, $values );
|
||||
|
||||
/* Send the notification for the first message */
|
||||
$comment->sendNotifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a member have permission to access?
|
||||
*
|
||||
* @param \IPS\Member $member The member to check for
|
||||
* @return bool
|
||||
*/
|
||||
public function canView( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Is the user part of the conversation? */
|
||||
foreach ( $this->maps() as $map )
|
||||
{
|
||||
if ( $map['map_user_id'] === $member->member_id and $map['map_user_active'] )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Have we granted them temporary permission from the report center or a warning log? */
|
||||
if ( $member->modPermission('can_view_reports') )
|
||||
{
|
||||
$report = isset( $_SESSION['report'] ) ? $_SESSION['report'] : ( isset( \IPS\Request::i()->_report ) ? \IPS\Request::i()->_report : NULL );
|
||||
if ( $report )
|
||||
{
|
||||
try
|
||||
{
|
||||
$report = \IPS\core\Reports\Report::load( $report );
|
||||
if ( $report->class == 'IPS\core\Messenger\Message' and in_array( $report->content_id, iterator_to_array( \IPS\Db::i()->select( 'msg_id', 'core_message_posts', array( 'msg_topic_id=?', $this->id ) ) ) ) )
|
||||
{
|
||||
$_SESSION['report'] = $report->id;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e ){ }
|
||||
}
|
||||
}
|
||||
if ( $member->modPermission('mod_see_warn') )
|
||||
{
|
||||
$warning = isset( $_SESSION['warning'] ) ? $_SESSION['warning'] : ( isset( \IPS\Request::i()->_warning ) ? \IPS\Request::i()->_warning : NULL );
|
||||
if ( $warning )
|
||||
{
|
||||
$warning = \IPS\Db::i()->select( '*', 'core_members_warn_logs', array( 'wl_id=? AND wl_content_app=? AND wl_content_module=? AND wl_content_id1=?', $member->member_id, 'core', 'messaging', $this->id ) )->first();
|
||||
if ( $warning )
|
||||
{
|
||||
$_SESSION['report'] = $report->id;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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; // You don't delete a conversation. It gets deleted automatically when everyone has left.
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions to show in comment multi-mod
|
||||
*
|
||||
* @param \IPS\Member $member Member (NULL for currently logged in member)
|
||||
* @return array
|
||||
*/
|
||||
public function commentMultimodActions( \IPS\Member $member = NULL )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=messaging&controller=messenger&id={$this->id}", 'front', 'messenger_convo' );
|
||||
|
||||
if ( $action )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/* !\IPS\core\Messenger\Conversation */
|
||||
|
||||
/**
|
||||
* Get the number of active participants
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_activeParticipants()
|
||||
{
|
||||
return count( array_filter( $this->maps, function( $map )
|
||||
{
|
||||
return $map['map_user_active'];
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map for the current member
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_map()
|
||||
{
|
||||
$maps = $this->maps();
|
||||
|
||||
/* From a report? */
|
||||
if ( ( isset( $_SESSION['report'] ) ? $_SESSION['report'] : ( isset( \IPS\Request::i()->_report ) ? \IPS\Request::i()->_report : NULL ) ) AND \IPS\Member::loggedIn()->modPermission( 'can_view_reports' ) )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if ( isset( $maps[ \IPS\Member::loggedIn()->member_id ] ) )
|
||||
{
|
||||
return $maps[ \IPS\Member::loggedIn()->member_id ];
|
||||
}
|
||||
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent unread conversation and dismiss the popup
|
||||
*
|
||||
* @return \IPS\Conversation|NULL
|
||||
*/
|
||||
public static function latestUnreadConversation()
|
||||
{
|
||||
$return = NULL;
|
||||
$latestConversationMap = \IPS\Db::i()->select( 'map_topic_id', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1 AND map_has_unread=1 AND map_ignore_notification=0', \IPS\Member::loggedIn()->member_id ), 'map_last_topic_reply DESC' );
|
||||
|
||||
try
|
||||
{
|
||||
$return = static::loadAndCheckPerms( $latestConversationMap->first() );
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
catch ( \UnderflowException $e ) { }
|
||||
|
||||
\IPS\Member::loggedIn()->msg_show_notification = FALSE;
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recount the member's message counts
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildMessageCounts( \IPS\Member $member )
|
||||
{
|
||||
$total = \IPS\Db::i()->select( 'count(*)', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1', $member->member_id ) )->first();
|
||||
$member->msg_count_total = $total;
|
||||
|
||||
$new = \IPS\Db::i()->select( 'count(*)', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1 AND map_has_unread=1 AND map_ignore_notification=0 AND map_last_topic_reply>?', $member->member_id, $member->msg_count_reset ) )->first();
|
||||
$member->msg_count_new = $new;
|
||||
|
||||
$member->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maps cache
|
||||
*/
|
||||
protected $maps = NULL;
|
||||
|
||||
/**
|
||||
* Get maps
|
||||
*
|
||||
* @param boolean $refresh Force maps to be refreshed?
|
||||
* @return array
|
||||
*/
|
||||
public function maps( $refresh = FALSE )
|
||||
{
|
||||
if ( $this->maps === NULL || $refresh === TRUE )
|
||||
{
|
||||
$this->maps = iterator_to_array( \IPS\Db::i()->select( '*', 'core_message_topic_user_map', array( 'map_topic_id=?', $this->id ) )->setKeyField( 'map_user_id' ) );
|
||||
}
|
||||
return $this->maps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant a member access
|
||||
*
|
||||
* @param \IPS\Member|array $member The member(s) to grant access
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize( $members )
|
||||
{
|
||||
$members = is_array( $members ) ? $members : array( $members );
|
||||
|
||||
/* Go through each member */
|
||||
foreach ( $members as $member )
|
||||
{
|
||||
if ( is_int( $member ) )
|
||||
{
|
||||
$member = \IPS\Member::load( $member );
|
||||
}
|
||||
|
||||
$done = FALSE;
|
||||
|
||||
/* If they already have a map, update it */
|
||||
foreach ( $this->maps() as $map )
|
||||
{
|
||||
if ( $map['map_user_id'] == $member->member_id )
|
||||
{
|
||||
$this->maps[ $member->member_id ]['map_user_active'] = TRUE;
|
||||
$this->maps[ $member->member_id ]['map_user_banned'] = FALSE;
|
||||
\IPS\Db::i()->update( 'core_message_topic_user_map', array( 'map_user_active' => 1, 'map_user_banned' => 0 ), array( 'map_user_id=? AND map_topic_id=?', $member->member_id, $this->id ) );
|
||||
$done = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not, create one */
|
||||
if ( !$done )
|
||||
{
|
||||
/* Create map */
|
||||
$membersLastComment = $this->comments( 1, 0, 'date', 'desc', $member );
|
||||
$this->maps[ $member->member_id ] = array(
|
||||
'map_user_id' => $member->member_id,
|
||||
'map_topic_id' => $this->id,
|
||||
'map_folder_id' => 'myconvo',
|
||||
'map_read_time' => ( $member->member_id == $this->starter_id ) ? time() : 0,
|
||||
'map_user_active' => TRUE,
|
||||
'map_user_banned' => FALSE,
|
||||
'map_has_unread' => ( $member->member_id == $this->starter_id ) ? FALSE : TRUE,
|
||||
'map_is_system' => FALSE,
|
||||
'map_is_starter' => ( $member->member_id == $this->starter_id ),
|
||||
'map_left_time' => 0,
|
||||
'map_ignore_notification' => FALSE,
|
||||
'map_last_topic_reply' => $membersLastComment ? $membersLastComment->date : time(),
|
||||
);
|
||||
\IPS\Db::i()->insert( 'core_message_topic_user_map', $this->maps[ $member->member_id ] );
|
||||
}
|
||||
|
||||
if ( $member->members_bitoptions['show_pm_popup'] and $this->author()->member_id != $member->member_id )
|
||||
{
|
||||
$member->msg_show_notification = TRUE;
|
||||
$member->save();
|
||||
}
|
||||
|
||||
/* Note: emails for added participants are sent from controller, as this central method is called when conversation is first created also */
|
||||
|
||||
/* Rebuild the user's counts */
|
||||
static::rebuildMessageCounts( $member );
|
||||
}
|
||||
|
||||
/* Rebuild the participants of this conversation */
|
||||
$this->rebuildParticipants();
|
||||
|
||||
return $this->maps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a member access
|
||||
*
|
||||
* @param \IPS\Member|array $members The member(s) to remove access
|
||||
* @param bool $banned User is being blocked by the conversation starter (as opposed to leaving voluntarily)?
|
||||
* @return bool
|
||||
*/
|
||||
public function deauthorize( $members, $banned=FALSE )
|
||||
{
|
||||
$members = is_array( $members ) ? $members : array( $members );
|
||||
foreach ( $members as $member )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_message_topic_user_map', array( 'map_user_active' => 0, 'map_user_banned' => $banned ), array( 'map_user_id=? AND map_topic_id=?', $member->member_id, $this->id ) );
|
||||
static::rebuildMessageCounts( $member );
|
||||
}
|
||||
$this->rebuildParticipants();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild participants
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rebuildParticipants()
|
||||
{
|
||||
$activeParticipants = 0;
|
||||
foreach ( $this->maps( TRUE ) as $map )
|
||||
{
|
||||
if ( $map['map_user_active'] )
|
||||
{
|
||||
$activeParticipants++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $activeParticipants )
|
||||
{
|
||||
$this->to_count = $activeParticipants;
|
||||
$this->save();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Personal Conversation Message 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
|
||||
* @since 8 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Messenger;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Personal Conversation Message
|
||||
*/
|
||||
class _Message extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
|
||||
{
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_message_posts';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'msg_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Title
|
||||
*/
|
||||
public static $title = 'personal_conversation_message';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Icon
|
||||
*/
|
||||
public static $icon = 'envelope';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = 'IPS\core\Messenger\Conversation';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'topic_id',
|
||||
'date' => 'date',
|
||||
'content' => 'post',
|
||||
'author' => 'author_id',
|
||||
'ip_address'=> 'ip_address',
|
||||
'first' => 'is_first_post'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'messenger_';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] The ignore type
|
||||
*/
|
||||
public static $ignoreType = 'messages';
|
||||
|
||||
/**
|
||||
* Should this comment be ignored?
|
||||
* Override so that the person who starts the conversation sees all messages - if you send a
|
||||
* message to someone, you're always going to want to be able to see their replies.
|
||||
*
|
||||
* @param \IPS\Member|null $member The member to check for - NULL for currently logged in member
|
||||
* @return bool
|
||||
*/
|
||||
public function isIgnored( $member=NULL )
|
||||
{
|
||||
if ( $member === NULL )
|
||||
{
|
||||
$member = \IPS\Member::loggedIn();
|
||||
}
|
||||
|
||||
if ( $this->item()->author() == $member )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return parent::isIgnored( $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 )
|
||||
{
|
||||
if ( $member === NULL )
|
||||
{
|
||||
$member = \IPS\Member::loggedIn();
|
||||
}
|
||||
|
||||
$comment = call_user_func_array( 'parent::create', func_get_args() );
|
||||
|
||||
/* Mark unread for this person */
|
||||
\IPS\Db::i()->update( 'core_message_topic_user_map', array( 'map_has_unread' => FALSE, 'map_read_time' => time() ), array( 'map_user_id=? AND map_topic_id=?', $member->member_id, $item->id ) );
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendNotifications()
|
||||
{
|
||||
/* Update topic maps for other participants */
|
||||
\IPS\Db::i()->update( 'core_message_topic_user_map', array( 'map_has_unread' => 1, 'map_last_topic_reply' => time() ), array( 'map_topic_id=? AND map_user_id!=?', $this->item()->id, $this->author()->member_id ) );
|
||||
|
||||
/* Update topic map for this author */
|
||||
\IPS\Db::i()->update( 'core_message_topic_user_map', array( 'map_has_unread' => 0, 'map_last_topic_reply' => time(), 'map_read_time' => time() ), array( 'map_topic_id=? AND map_user_id=?', $this->item()->id, $this->author()->member_id ) );
|
||||
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'new_private_message', $this->item(), array( $this ) );
|
||||
foreach ( $this->item()->maps( TRUE ) as $map )
|
||||
{
|
||||
if ( $map['map_user_id'] !== $this->author()->member_id and $map['map_user_active'] and !$map['map_ignore_notification'] )
|
||||
{
|
||||
$member = \IPS\Member::load( $map['map_user_id'] );
|
||||
\IPS\core\Messenger\Conversation::rebuildMessageCounts( $member );
|
||||
|
||||
$notification->recipients->attach( $member );
|
||||
|
||||
if ( $member->members_bitoptions['show_pm_popup'] )
|
||||
{
|
||||
$member->msg_show_notification = TRUE;
|
||||
$member->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$notification->send();
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Custom Profile 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 11 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileFields;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
const PROFILE = 0;
|
||||
const REG = 1;
|
||||
const STAFF = 2;
|
||||
const CONTENT = 3;
|
||||
const SEARCH = 4;
|
||||
|
||||
|
||||
/**
|
||||
* Custom Profile Field Node
|
||||
*/
|
||||
class _Field extends \IPS\CustomField
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_pfields_data';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'pf_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node ID Database Column
|
||||
*/
|
||||
public static $parentNodeColumnId = 'group_id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node Class
|
||||
*/
|
||||
public static $parentNodeClass = 'IPS\core\ProfileFields\Group';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Title/Description lang prefix
|
||||
*/
|
||||
protected static $langKey = 'core_pfield';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'membersettings',
|
||||
'prefix' => 'profilefields_',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [CustomField] Editor Options
|
||||
*/
|
||||
public static $editorOptions = array( 'app' => 'core', 'key' => 'CustomField' );
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'core_pfield_';
|
||||
|
||||
/**
|
||||
* @brief [CustomField] FileStorage Extension for Upload fields
|
||||
*/
|
||||
public static $uploadStorageExtension = 'ProfileField';
|
||||
|
||||
/**
|
||||
* Get field data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function fieldData()
|
||||
{
|
||||
if ( !isset( \IPS\Data\Store::i()->profileFields ) )
|
||||
{
|
||||
$fields = array();
|
||||
$display = FALSE;
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_pfields_groups', NULL, 'pf_group_order' ) as $row )
|
||||
{
|
||||
$fields[ $row['pf_group_id'] ] = array();
|
||||
}
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_pfields_data', NULL, 'pf_position' ) as $row )
|
||||
{
|
||||
$fields[ $row['pf_group_id'] ][ $row['pf_id'] ] = $row;
|
||||
if ( $row['pf_format'] )
|
||||
{
|
||||
$display = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->profileFields = array( 'fields' => $fields, 'display' => $display );
|
||||
}
|
||||
|
||||
return \IPS\Data\Store::i()->profileFields['fields'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there fields to display in content view?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function fieldsForContentView()
|
||||
{
|
||||
if ( !isset( \IPS\Data\Store::i()->profileFields ) )
|
||||
{
|
||||
static::fieldData();
|
||||
}
|
||||
return \IPS\Data\Store::i()->profileFields['display'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Fields
|
||||
*
|
||||
* @param array $values Current values
|
||||
* @param int $location \IPS\core\ProfileFields\PROFILE for profile, \IPS\core\ProfileFields\REG for registration screen or \IPS\core\ProfileFields\STAFF for ModCP/ACP
|
||||
* @return array
|
||||
*/
|
||||
public static function fields( $values=array(), $location=0 )
|
||||
{
|
||||
if( !$values )
|
||||
{
|
||||
$values = array();
|
||||
}
|
||||
|
||||
$return = array();
|
||||
|
||||
foreach ( static::fieldData() as $groupId => $fields )
|
||||
{
|
||||
foreach ( $fields as $row )
|
||||
{
|
||||
if ( ( $row['pf_admin_only'] and $location !== STAFF ) or ( $location === REG and !$row['pf_show_on_reg'] ) or ( $location === PROFILE and !$row['pf_member_edit'] ) or ( $location === SEARCH and !$row['pf_search_type'] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !array_key_exists( 'field_' . $row['pf_id'], $values ) )
|
||||
{
|
||||
$values['field_' . $row['pf_id'] ] = NULL;
|
||||
}
|
||||
|
||||
static::$editorOptions['autoSaveKey'] = md5( get_called_class() . '-' . $row['pf_id'] ) . ( isset( \IPS\Request::i()->id ) ? '-' . \IPS\Request::i()->id : '' );
|
||||
|
||||
$return[ $groupId ][ $row['pf_id'] ] = static::constructFromData( $row )->buildHelper( $values[ 'field_' . $row['pf_id'] ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Values
|
||||
*
|
||||
* @param array $values Current values
|
||||
* @param int $location \IPS\core\ProfileFields\PROFILE for profile, \IPS\core\ProfileFields\REG for registration screen or \IPS\core\ProfileFields\STAFF for ModCP/ACP
|
||||
* @return array
|
||||
*/
|
||||
public static function values( $values, $location=0 )
|
||||
{
|
||||
$return = array();
|
||||
foreach ( static::fieldData() as $groupId => $fields )
|
||||
{
|
||||
foreach ( $fields as $row )
|
||||
{
|
||||
if ( $row['pf_admin_only'] and $location !== STAFF )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $location == CONTENT and $row['pf_format'] != '' and isset( $values[ 'field_' . $row['pf_id'] ] ) )
|
||||
{
|
||||
$row = static::constructFromData( $row );
|
||||
$value = $row->displayValue( $values[ 'field_' . $row->id ] );
|
||||
$return[ $row->group_id ][ $row->id ] = str_replace( array( '{title}', '{content}' ), array( \IPS\Member::loggedIn()->language()->addToStack( static::$langKey . '_' . $row->id ), $value ), $row->format );
|
||||
}
|
||||
else if ( $location !== CONTENT )
|
||||
{
|
||||
$return[ $groupId ][ static::$langKey . '_' . $row['pf_id'] ] = static::constructFromData( $row )->displayValue( $values[ 'field_' . $row['pf_id'] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
parent::form( $form );
|
||||
//$form->addHeader( 'pfield_displayoptions' );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'pf_search_type', $this->id ? $this->search_type : 'loose', FALSE, array( 'options' => array( 'exact' => 'pf_search_type_exact', 'loose' => 'pf_search_type_loose', '' => 'pf_search_type_none' ) ), NULL, NULL, NULL, 'pf_search_type' ) );
|
||||
$form->add( new \IPS\Helpers\Form\TextArea( 'pf_format', $this->id ? $this->format : '', FALSE, array( 'placeholder' => "<strong>{title}:</strong> {content}" ) ) );
|
||||
$form->addheader( 'pfield_permissions' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'pf_admin_only', $this->id ? !$this->admin_only : TRUE, FALSE, array( 'togglesOn' => array( 'pf_show_on_reg', 'pf_member_edit', 'pf_member_hide' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'pf_show_on_reg', $this->id ? $this->show_on_reg : TRUE, FALSE, array(), NULL, NULL, NULL, 'pf_show_on_reg' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'pf_member_edit', $this->id ? $this->member_edit : TRUE, FALSE, array(), NULL, NULL, NULL, 'pf_member_edit' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'pf_member_hide', $this->id ? !$this->member_hide : TRUE, FALSE, array(), NULL, NULL, NULL, 'pf_member_hide' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [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['pf_admin_only'] ) )
|
||||
{
|
||||
$values['pf_admin_only'] = $values['pf_admin_only'] ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
if( isset( $values['pf_member_hide'] ) )
|
||||
{
|
||||
$values['pf_member_hide'] = $values['pf_member_hide'] ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
if( isset( $values['pf_show_on_reg'] ) )
|
||||
{
|
||||
$values['pf_show_on_reg'] = $values['pf_show_on_reg'] ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
if( array_key_exists( 'pf_search_type', $values ) )
|
||||
{
|
||||
$values['pf_search_type'] = (string) $values['pf_search_type'];
|
||||
}
|
||||
|
||||
return parent::formatFormValues( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Save Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if( $this->_new )
|
||||
{
|
||||
$return = parent::save();
|
||||
\IPS\Db::i()->addColumn( 'core_pfields_content', array( 'name' => "field_{$this->id}", 'type' => 'TEXT' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = parent::save();
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->profileFields );
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
\IPS\Db::i()->dropColumn( 'core_pfields_content', "field_{$this->id}" );
|
||||
unset( \IPS\Data\Store::i()->profileFields );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Custom Profile Field Group 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 10 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileFields;
|
||||
|
||||
/* 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 Group Node
|
||||
*/
|
||||
class _Group extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_pfields_groups';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'pf_group_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'order';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'profile_fields';
|
||||
|
||||
/**
|
||||
* @brief [Node] Subnode class
|
||||
*/
|
||||
public static $subnodeClass = 'IPS\core\ProfileFields\Field';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'membersettings',
|
||||
'prefix' => 'profilefieldgroups_',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'core_pfieldgroups_';
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'pfield_group_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "core_pfieldgroups_{$this->id}" : NULL ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Save Add/Edit Form
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return void
|
||||
*/
|
||||
public function saveForm( $values )
|
||||
{
|
||||
if ( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
\IPS\Lang::saveCustom( 'core', "core_pfieldgroups_{$this->id}", $values['pfield_group_title'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to edit permissions for this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canManagePermissions()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* [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 );
|
||||
|
||||
$buttons['add']['title'] = 'add_profile_field';
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Facebook Profile Sync
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Facebook Profile Sync
|
||||
*/
|
||||
class _Facebook extends ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handler key
|
||||
*/
|
||||
public static $loginKey = 'Facebook';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'facebook-square';
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
return ( $this->member->fb_uid and $this->member->fb_token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url|\IPS\File|NULL
|
||||
*/
|
||||
public function photo()
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/{$this->member->fb_uid}/picture?type=large&redirect=false" )->request()->get()->decodeJson();
|
||||
if ( isset( $response['data']['is_silhouette'] ) AND $response['data']['is_silhouette'] === false )
|
||||
{
|
||||
$file = \IPS\Http\Url::external( $response['data']['url'] )->import( 'core_Profile' );
|
||||
$photo = \IPS\Image::create( $file->contents() );
|
||||
|
||||
if ( ( $photo->width > $photo->height ) OR ( $photo->height > $photo->width ) )
|
||||
{
|
||||
if ( $photo->width > $photo->height )
|
||||
{
|
||||
$difference = $photo->width - $photo->height;
|
||||
$photo->cropToPoints( ceil( $difference / 2 ), 0, ceil( $photo->width - ( $difference / 2 ) ), $photo->height );
|
||||
$file->replace( (string) $photo );
|
||||
}
|
||||
else if ( $photo->height > $photo->width )
|
||||
{
|
||||
$difference = $photo->height - $photo->width;
|
||||
$photo->cropToPoints( 0, ceil( $difference / 2 ), $photo->width, ceil( $photo->height - ( $difference / 2 ) ) );
|
||||
$file->replace( (string) $photo );
|
||||
}
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cover photo
|
||||
*
|
||||
* @return \IPS\Http\Url|NULL
|
||||
*/
|
||||
public function cover()
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/{$this->member->fb_uid}?access_token={$this->member->fb_token}&fields=cover" )->request()->get()->decodeJson();
|
||||
if ( isset( $response['cover'] ) )
|
||||
{
|
||||
return \IPS\Http\Url::external( $response['cover']['source'] )->import( 'core_Profile' );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/{$this->member->fb_uid}?access_token={$this->member->fb_token}" )->request()->get()->decodeJson();
|
||||
if ( isset( $response['name'] ) )
|
||||
{
|
||||
return $response['name'];
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status
|
||||
*
|
||||
* @return \IPS\core\Statuses\Status|null
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/{$this->member->fb_uid}/statuses?access_token={$this->member->fb_token}" )->request()->get()->decodeJson();
|
||||
if ( !empty( $response['data'] ) )
|
||||
{
|
||||
$statusData = array_shift( $response['data'] );
|
||||
|
||||
if( isset( $statusData['message'] ) )
|
||||
{
|
||||
$status = \IPS\core\Statuses\Status::createItem( $this->member, $this->member->ip_address, new \IPS\DateTime( $statusData['updated_time'] ) );
|
||||
$status->content = nl2br( $statusData['message'], FALSE );
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e ) { }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export Status
|
||||
*
|
||||
* @param \IPS\core\Statuses\Status $status The status
|
||||
* @return void
|
||||
*/
|
||||
public function exportStatus( \IPS\core\Statuses\Status $status )
|
||||
{
|
||||
\IPS\Http\Url::external( "https://graph.facebook.com/{$this->member->fb_uid}/feed" )->request()->post( array( 'access_token' => $this->member->fb_token, 'message' => strip_tags( $status->content ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _disassociate()
|
||||
{
|
||||
$this->member->fb_uid = 0;
|
||||
$this->member->fb_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Google Profile Sync
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Google Profile Sync
|
||||
*/
|
||||
class _Google extends ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handler key
|
||||
*/
|
||||
public static $loginKey = 'Google';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'google-plus';
|
||||
|
||||
/**
|
||||
* @brief Authorization token
|
||||
*/
|
||||
protected $authToken = NULL;
|
||||
|
||||
/**
|
||||
* @brief User data
|
||||
*/
|
||||
protected $user = NULL;
|
||||
|
||||
/**
|
||||
* Get user data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function user()
|
||||
{
|
||||
if ( $this->user === NULL and $this->member->google_token )
|
||||
{
|
||||
try
|
||||
{
|
||||
$loginHandler = \IPS\Login\LoginAbstract::load('google');
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://accounts.google.com/o/oauth2/token' )->request()->post( array(
|
||||
'client_id' => $loginHandler->settings['client_id'],
|
||||
'client_secret' => $loginHandler->settings['client_secret'],
|
||||
'refresh_token' => $this->member->google_token,
|
||||
'grant_type' => 'refresh_token'
|
||||
) )->decodeJson();
|
||||
|
||||
if ( isset( $response['access_token'] ) )
|
||||
{
|
||||
$this->authToken = $response['access_token'];
|
||||
$this->user = $this->get( 'people/' . $this->member->google_id );
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
$this->member->google_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
return (bool) ( $this->member->google_id and $this->member->google_token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url|\IPS\File|NULL
|
||||
*/
|
||||
public function photo()
|
||||
{
|
||||
$user = $this->user();
|
||||
if ( isset( $user['image'] ) )
|
||||
{
|
||||
return \IPS\Http\Url::external( preg_replace( '/\?sz=\d+$/', '', $user['image']['url'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cover photo
|
||||
*
|
||||
* @return \IPS\Http\Url|NULL
|
||||
*/
|
||||
public function cover()
|
||||
{
|
||||
$user = $this->user();
|
||||
if ( isset( $user['cover'] ) )
|
||||
{
|
||||
return \IPS\Http\Url::external( $user['cover']['coverPhoto']['url'] )->import( 'core_Profile' );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
$user = $this->user();
|
||||
return $user['displayName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status
|
||||
*
|
||||
* @return \IPS\core\Statuses\Status|null
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
$this->user();
|
||||
$statuses = $this->get( "people/me/activities/public" );
|
||||
if ( isset( $statuses['items'] ) )
|
||||
{
|
||||
foreach ( $statuses['items'] as $status )
|
||||
{
|
||||
if ( $status['object']['content'] )
|
||||
{
|
||||
$statusObj = \IPS\core\Statuses\Status::createItem( $this->member, $this->member->ip_address, new \IPS\DateTime( $status['published'] ) );
|
||||
$statusObj->content = nl2br( $status['object']['content'], FALSE );
|
||||
return $statusObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _disassociate()
|
||||
{
|
||||
$this->member->google_id = 0;
|
||||
$this->member->google_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API data
|
||||
*
|
||||
* @param string $uri The API URI
|
||||
* @return array
|
||||
* @throws \IPS\Http\Request\Exception
|
||||
*/
|
||||
protected function get( $uri )
|
||||
{
|
||||
return \IPS\Http\Url::external( 'https://www.googleapis.com/plus/v1/' . $uri )->request()->setHeaders( array( 'Authorization' => "Bearer {$this->authToken}" ) )->get()->decodeJson();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief LinkedIn Profile Sync
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* LinkedIn Profile Sync
|
||||
*/
|
||||
class _Linkedin extends ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handler key
|
||||
*/
|
||||
public static $loginKey = 'Linkedin';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'linkedin';
|
||||
|
||||
/**
|
||||
* @brief User data
|
||||
*/
|
||||
protected $user = NULL;
|
||||
|
||||
/**
|
||||
* Get user data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function user()
|
||||
{
|
||||
if ( $this->user === NULL and $this->member->linkedin_token )
|
||||
{
|
||||
$this->user = array();
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\Http\Url::external( "https://api.linkedin.com/v1/people/{$this->member->linkedin_id}:(formatted-name,picture-url,current-status)?oauth2_access_token={$this->member->linkedin_token}" )->request()->get()->decodeXml() as $k => $v )
|
||||
{
|
||||
$this->user[ $k ] = (string) $v;
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
$this->member->linkedin_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
return $this->member->linkedin_id and $this->member->linkedin_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url|null
|
||||
*/
|
||||
public function photo()
|
||||
{
|
||||
$user = $this->user();
|
||||
if ( isset( $user['picture-url'] ) )
|
||||
{
|
||||
return \IPS\Http\Url::external( $user['picture-url'] );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
$user = $this->user();
|
||||
return $user['formatted-name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _disassociate()
|
||||
{
|
||||
$this->member->linkedin_id = 0;
|
||||
$this->member->linkedin_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Microsoft Profile Sync
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Microsoft Profile Sync
|
||||
*/
|
||||
class _Microsoft extends ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handler key
|
||||
*/
|
||||
public static $loginKey = 'Live';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'windows';
|
||||
|
||||
/**
|
||||
* @brief Authorization token
|
||||
*/
|
||||
protected $authToken = NULL;
|
||||
|
||||
/**
|
||||
* Get user data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function authToken()
|
||||
{
|
||||
if ( $this->authToken === NULL and $this->member->live_token )
|
||||
{
|
||||
try
|
||||
{
|
||||
$loginHandler = \IPS\Login\LoginAbstract::load('live');
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://login.live.com/oauth20_token.srf' )->request()->post( array(
|
||||
'client_id' => $loginHandler->settings['client_id'],
|
||||
'client_secret' => $loginHandler->settings['client_secret'],
|
||||
'refresh_token' => $this->member->live_token,
|
||||
'grant_type' => 'refresh_token'
|
||||
) )->decodeJson();
|
||||
|
||||
if ( isset( $response['access_token'] ) and isset( $response['refresh_token'] ) )
|
||||
{
|
||||
$this->authToken = $response['access_token'];
|
||||
$this->member->live_token = $response['refresh_token'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->member->live_token = NULL;
|
||||
}
|
||||
|
||||
$this->member->save();
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
$this->member->live_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->authToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
return (bool) ( $this->member->live_id and $this->member->live_token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url|null
|
||||
*/
|
||||
public function photo()
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Http\Url::external( "https://apis.live.net/v5.0/{$this->member->live_id}/picture?type=large" );
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
try
|
||||
{
|
||||
$user = \IPS\Http\Url::external( "https://apis.live.net/v5.0/{$this->member->live_id}?access_token={$this->authToken()}" )->request()->get()->decodeJson();
|
||||
if ( isset( $user['name'] ) )
|
||||
{
|
||||
return $user['name'];
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _disassociate()
|
||||
{
|
||||
$this->member->live_id = 0;
|
||||
$this->member->live_token = NULL;
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Profile Sync Abstract Class
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile Sync Interface
|
||||
*/
|
||||
abstract class _ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handlers
|
||||
*/
|
||||
protected static $loginHandlers = NULL;
|
||||
|
||||
/**
|
||||
* Get services
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function services()
|
||||
{
|
||||
$services = array();
|
||||
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/applications/core/sources/ProfileSync' ) as $file )
|
||||
{
|
||||
if ( !$file->isDot() and mb_substr( $file, -4 ) === '.php' )
|
||||
{
|
||||
require_once $file->getPathname();
|
||||
$class = 'IPS\core\ProfileSync\\' . mb_substr( $file, 0, -4 );
|
||||
|
||||
if ( $class::enabled() )
|
||||
{
|
||||
$services[ mb_substr( $file, 0, -4 ) ] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabled?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function enabled()
|
||||
{
|
||||
if ( isset( static::$loginKey ) )
|
||||
{
|
||||
if ( static::$loginHandlers === NULL )
|
||||
{
|
||||
static::$loginHandlers = iterator_to_array( \IPS\Db::i()->select( '*', 'core_login_handlers' )->setKeyField( 'login_key' ) );
|
||||
}
|
||||
|
||||
if ( isset( static::$loginHandlers[ static::$loginKey ] ) )
|
||||
{
|
||||
return (bool) static::$loginHandlers[ static::$loginKey ]['login_enabled'];
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Member
|
||||
*/
|
||||
protected $member;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \IPS\Member $member The member
|
||||
*/
|
||||
public function __construct( \IPS\Member $member )
|
||||
{
|
||||
$this->member = $member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function connected();
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url|\IPS\File|NULL
|
||||
*/
|
||||
abstract public function photo();
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function name();
|
||||
|
||||
/**
|
||||
* Get settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function settings()
|
||||
{
|
||||
$settings = $this->member->profilesync ? json_decode( $this->member->profilesync, TRUE ) : array();
|
||||
return ( isset( $settings[ static::$loginKey ] ) ? $settings[ static::$loginKey ] : array(
|
||||
'photo' => FALSE,
|
||||
'cover' => FALSE,
|
||||
'status' => ''
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get settings as string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function settingsDesc()
|
||||
{
|
||||
$settings = $this->settings();
|
||||
$return = array();
|
||||
if ( $settings['photo'] or $settings['cover'] )
|
||||
{
|
||||
$_return = array();
|
||||
if ( $settings['photo'] )
|
||||
{
|
||||
$_return[] = \IPS\Member::loggedIn()->language()->addToStack('sync_settings_photo');
|
||||
}
|
||||
if ( $settings['cover'] )
|
||||
{
|
||||
$_return[] = \IPS\Member::loggedIn()->language()->addToStack('sync_settings_cover');
|
||||
}
|
||||
|
||||
if ( count( $_return ) > 1 )
|
||||
{
|
||||
$return[] = \IPS\Member::loggedIn()->language()->formatList( $_return, \IPS\Member::loggedIn()->language()->get('sync_settings_syncing') );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[] = $_return[0];
|
||||
}
|
||||
}
|
||||
if ( $settings['status'] )
|
||||
{
|
||||
$langKey = 'sync_settings_status_' . $settings['status'];
|
||||
$return[] = \IPS\Member::loggedIn()->language()->addToStack( $langKey );
|
||||
}
|
||||
|
||||
return empty( $return ) ? \IPS\Member::loggedIn()->language()->addToStack('profilesync_not_syncing') : \IPS\Member::loggedIn()->language()->formatList( $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Settings
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
public function save( $values )
|
||||
{
|
||||
$settings = $this->member->profilesync ? json_decode( $this->member->profilesync, TRUE ) : array(
|
||||
static::$loginKey => array(
|
||||
'photo' => FALSE,
|
||||
'cover' => FALSE,
|
||||
'status' => ''
|
||||
)
|
||||
);
|
||||
|
||||
$settings[ static::$loginKey ] = array(
|
||||
'photo' => isset( $values['profilesync_photo'] ) ? $values['profilesync_photo'] : ( isset( $settings[ static::$loginKey ]['photo'] ) ? $settings[ static::$loginKey ]['photo'] : FALSE ),
|
||||
'cover' => isset( $values['profilesync_cover'] ) ? $values['profilesync_cover'] : ( isset( $settings[ static::$loginKey ]['cover'] ) ? $settings[ static::$loginKey ]['cover'] : FALSE ),
|
||||
'status' => isset( $values['profilesync_status'] ) ? $values['profilesync_status'] : ( isset( $settings[ static::$loginKey ]['status'] ) ? $settings[ static::$loginKey ]['status'] : FALSE ),
|
||||
);
|
||||
$this->member->profilesync = json_encode( $settings );
|
||||
|
||||
/* If we're enabling status import, reset last sync time so we import the latest status */
|
||||
if ( isset( $values['profilesync_status'] ) AND $values['profilesync_status'] == 'import' )
|
||||
{
|
||||
$this->member->profilesync_lastsync = 0;
|
||||
}
|
||||
|
||||
$this->member->save();
|
||||
$this->sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sync()
|
||||
{
|
||||
$settings = $this->settings();
|
||||
if ( $settings['photo'] )
|
||||
{
|
||||
$class = get_called_class();
|
||||
try
|
||||
{
|
||||
if ( $photo = $this->photo() )
|
||||
{
|
||||
if ( $photo instanceof \IPS\File )
|
||||
{
|
||||
$this->member->pp_main_photo = (string) $photo;
|
||||
$this->member->pp_thumb_photo = NULL;
|
||||
$this->member->pp_photo_type = 'custom';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->member->pp_main_photo = (string) $photo;
|
||||
$this->member->pp_thumb_photo = NULL;
|
||||
$this->member->pp_photo_type = 'sync-' . mb_substr( $class, mb_strrpos( $class, '\\' ) + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e ) {}
|
||||
}
|
||||
if ( $settings['cover'] and $this->member->group['gbw_allow_upload_bgimage'] )
|
||||
{
|
||||
if ( $this->member->pp_cover_photo )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Profile', $this->member->pp_cover_photo )->delete();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
$this->member->pp_cover_photo = (string) $this->cover();
|
||||
}
|
||||
if ( $settings['status'] and $settings['status'] == 'import' )
|
||||
{
|
||||
if ( $status = $this->status() )
|
||||
{
|
||||
if ( $status->date > $this->member->profilesync_lastsync )
|
||||
{
|
||||
try
|
||||
{
|
||||
$status->member_id = $this->member->member_id;
|
||||
$status->imported = TRUE;
|
||||
$status->save();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
// May fail if status contains invalid data (like utf8mb4 characters if the database doesn't support that, etc)
|
||||
// In this case, we will just skip over the status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->member->profilesync_lastsync = time();
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disassociate()
|
||||
{
|
||||
$settings = $this->member->profilesync ? json_decode( $this->member->profilesync, TRUE ) : array();
|
||||
$class = get_called_class();
|
||||
unset( $settings[ $class::$loginKey ] );
|
||||
$this->member->profilesync = empty( $settings ) ? NULL : json_encode( $settings );
|
||||
|
||||
$this->_disassociate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Twitter Profile Sync
|
||||
* @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 13 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ProfileSync;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Twitter Profile Sync
|
||||
*/
|
||||
class _Twitter extends ProfileSyncAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Login handler key
|
||||
*/
|
||||
public static $loginKey = 'Twitter';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'twitter';
|
||||
|
||||
/**
|
||||
* @brief User data
|
||||
*/
|
||||
protected $user = NULL;
|
||||
|
||||
/**
|
||||
* Get user data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function user()
|
||||
{
|
||||
if ( $this->user === NULL and $this->member->twitter_token )
|
||||
{
|
||||
try
|
||||
{
|
||||
$loginHandler = \IPS\Login\LoginAbstract::load('twitter');
|
||||
$this->user = $loginHandler->sendRequest( 'get', "https://api.twitter.com/1.1/account/verify_credentials.json", array(), $this->member->twitter_token, $this->member->twitter_secret )->decodeJson();
|
||||
|
||||
if ( isset( $this->user['errors'] ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$this->member->twitter_token = '';
|
||||
$this->member->twitter_secret = '';
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected()
|
||||
{
|
||||
return (bool) ( $this->member->twitter_id and $this->member->twitter_token and $this->member->twitter_secret );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photo
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function photo()
|
||||
{
|
||||
$user = $this->user();
|
||||
|
||||
if ( ( \IPS\Http\Url::internal('')->data['scheme'] == 'https' or \IPS\Settings::i()->logins_over_https ) and isset( $user['profile_image_url_https'] ) and $user['profile_image_url_https'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Http\Url::external( $user['profile_image_url_https'] );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if( isset( $user['profile_image_url'] ) AND $user['profile_image_url'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Http\Url::external($user['profile_image_url']);
|
||||
}
|
||||
catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cover photo
|
||||
*
|
||||
* @return \IPS\File|NULL
|
||||
*/
|
||||
public function cover()
|
||||
{
|
||||
$user = $this->user();
|
||||
|
||||
if ( ( \IPS\Http\Url::internal('')->data['scheme'] == 'https' or \IPS\Settings::i()->logins_over_https ) and isset( $user['profile_image_url_https'] ) and $user['profile_background_image_url_https'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Http\Url::external( $user['profile_background_image_url_https'] );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if( isset( $user['profile_background_image_url'] ) AND $user['profile_background_image_url'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Http\Url::external( $user['profile_background_image_url'] )->import( 'core_Profile' );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
$user = $this->user();
|
||||
return ( isset( $user['screen_name'] ) ) ? $user['screen_name'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status
|
||||
*
|
||||
* @return \IPS\core\Statuses\Status|null
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
$user = $this->user();
|
||||
|
||||
if ( isset( $user['status'] ) )
|
||||
{
|
||||
$status = \IPS\core\Statuses\Status::createItem( $this->member, $this->member->ip_address, new \IPS\DateTime( $user['status']['created_at'] ) );
|
||||
$status->content = $user['status']['text'];
|
||||
return $status;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export Status
|
||||
*
|
||||
* @param \IPS\core\Statuses\Status $status The status
|
||||
* @return void
|
||||
*/
|
||||
public function exportStatus( \IPS\core\Statuses\Status $status )
|
||||
{
|
||||
$loginHandler = \IPS\Login\LoginAbstract::load('twitter');
|
||||
$loginHandler->sendRequest( 'post', "https://api.twitter.com/1.1/statuses/update.json", array( 'status' => trim( strip_tags( $status->content ) ) ), $this->member->twitter_token, $this->member->twitter_secret )->decodeJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _disassociate()
|
||||
{
|
||||
$this->member->twitter_id = 0;
|
||||
$this->member->twitter_token = '';
|
||||
$this->member->twitter_secret = '';
|
||||
$this->member->save();
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Report Comment 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
|
||||
* @since 15 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Reports;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report Comment Model
|
||||
*/
|
||||
class _Comment extends \IPS\Content\Comment
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_rc_comments';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = '';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = 'IPS\core\Reports\Report';
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'rid',
|
||||
'date' => 'comment_date',
|
||||
'content' => 'comment',
|
||||
'author' => 'comment_by',
|
||||
'author_name' => 'author_name',
|
||||
'ip_address' => 'ip_address',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'report_comment';
|
||||
|
||||
/**
|
||||
* Get URL for doing stuff
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$url = parent::url( $action );
|
||||
if ( isset( $url->queryString['do'] ) )
|
||||
{
|
||||
return $url->setQueryString( array( 'do' => NULL, 'action' => $url->queryString['do'] ) );
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Report Index 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
|
||||
* @since 15 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Reports;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report Model
|
||||
*/
|
||||
class _Report extends \IPS\Content\Item implements \IPS\Content\ReadMarkers
|
||||
{
|
||||
/* !\IPS\Patterns\ActiveRecord */
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_rc_index';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = '';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'content_id' );
|
||||
|
||||
/* !\IPS\Content\Item */
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $module = 'modcp';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'date' => 'first_report_date',
|
||||
'author' => 'first_report_by',
|
||||
'author_count' => 'num_reports',
|
||||
'title' => 'title',
|
||||
'last_comment' => 'last_updated',
|
||||
'num_comments' => 'num_comments',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'report_';
|
||||
|
||||
/**
|
||||
* @brief Comment Class
|
||||
*/
|
||||
public static $commentClass = 'IPS\core\Reports\Comment';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'report';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mapped value
|
||||
*
|
||||
* @param string $key date,content,ip_address,first
|
||||
* @return mixed
|
||||
*/
|
||||
public function mapped( $key )
|
||||
{
|
||||
if ( $key === 'title' )
|
||||
{
|
||||
$class = $this->_data['class'];
|
||||
|
||||
if( in_array( 'IPS\Content\Comment', class_parents( $class ) ) )
|
||||
{
|
||||
$class = $class::$itemClass;
|
||||
}
|
||||
|
||||
if( isset( $class::$databaseColumnMap['content'] ) AND $class::$databaseColumnMap['title'] === $class::$databaseColumnMap['content'] )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->get( $class::$title );
|
||||
}
|
||||
|
||||
return strip_tags( parent::mapped( 'title' ) );
|
||||
}
|
||||
|
||||
return parent::mapped( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=modcp&tab=reports&action=view&id={$this->id}", 'front', 'modcp_report' );
|
||||
|
||||
if ( $action )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'action', $action );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/* !\IPS\Helpers\Table */
|
||||
|
||||
/**
|
||||
* Method to add extra data to objects in this
|
||||
* class when displaying in a table view
|
||||
*
|
||||
* @param array $rows Array of objects of this class
|
||||
* @return void
|
||||
*/
|
||||
public static function tableGetRows( $rows )
|
||||
{
|
||||
$types = array();
|
||||
|
||||
foreach ( $rows as $row )
|
||||
{
|
||||
$types[ $row->class ][ $row->content_id ] = $row;
|
||||
}
|
||||
|
||||
foreach ( $types as $class => $objects )
|
||||
{
|
||||
if ( in_array( 'IPS\Content\Comment', class_parents( $class ) ) )
|
||||
{
|
||||
$itemClass = $class::$itemClass;
|
||||
$databaseTable = $class::$databaseTable;
|
||||
$itemDatabaseTable = $itemClass::$databaseTable;
|
||||
$itemTitleField = $itemClass::$databaseColumnMap['title']; # Strange PHP issue can cause this to be lost when added to the query below.
|
||||
|
||||
foreach( \IPS\Db::i()->select(
|
||||
"{$databaseTable}.{$class::$databasePrefix}{$class::$databaseColumnId}, {$databaseTable}.{$class::$databasePrefix}{$class::$databaseColumnMap['item']} AS itemId, {$itemClass::$databaseTable}.{$itemClass::$databasePrefix}{$itemTitleField} AS title",
|
||||
$databaseTable,
|
||||
\IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnId, array_keys( $objects ) )
|
||||
)->join(
|
||||
$itemDatabaseTable,
|
||||
"{$itemDatabaseTable}.{$itemClass::$databasePrefix}{$itemClass::$databaseColumnId}={$databaseTable}.{$class::$databasePrefix}{$class::$databaseColumnMap['item']}"
|
||||
)->setKeyField( $class::$databasePrefix . $class::$databaseColumnId ) as $k => $data
|
||||
)
|
||||
{
|
||||
$objects[ $k ]->_data = array_merge( $objects[ $k ]->_data, $data );
|
||||
}
|
||||
}
|
||||
elseif ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select(
|
||||
"{$class::$databasePrefix}{$class::$databaseColumnId}, {$class::$databasePrefix}{$class::$databaseColumnMap['title']} AS title",
|
||||
$class::$databaseTable,
|
||||
\IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnId, array_keys( $objects ) )
|
||||
)->setKeyField( $class::$databasePrefix . $class::$databaseColumnId ) as $k => $data
|
||||
)
|
||||
{
|
||||
$objects[ $k ]->_data = array_merge( $objects[ $k ]->_data, $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get description for table view
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tableDescription()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'tables', 'core', 'front' )->icon( $this->class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content table states
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tableStates()
|
||||
{
|
||||
$states = explode( ' ', parent::tableStates() );
|
||||
$states[] = "report_status_" . $this->status;
|
||||
|
||||
return implode( ' ', $states );
|
||||
}
|
||||
|
||||
/**
|
||||
* Stats for table view
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function stats( $includeFirstCommentInCommentCount=TRUE )
|
||||
{
|
||||
return array_merge( parent::stats( $includeFirstCommentInCommentCount ), array( 'num_reports' => $this->num_reports ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon for table view
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function tableIcon()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp', 'core', 'front' )->reportToggle( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a special class for the row
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tableClass()
|
||||
{
|
||||
switch ( $this->status )
|
||||
{
|
||||
case 2:
|
||||
return 'warning';
|
||||
break;
|
||||
case 1:
|
||||
return 'new';
|
||||
break;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Do Moderator Action
|
||||
*
|
||||
* @param string $action The action
|
||||
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
|
||||
* @param string|NULL $reason Reason (for hides)
|
||||
* @return void
|
||||
* @throws \OutOfRangeException|\InvalidArgumentException|\RuntimeException
|
||||
*/
|
||||
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL )
|
||||
{
|
||||
if ( mb_substr( $action, 0, -1 ) === 'report_status_' )
|
||||
{
|
||||
$this->status = mb_substr( $action, -1 );
|
||||
$this->save();
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::modAction( $action, $member, $reason );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any custom multimod actions this content item class supports
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function customMultimodActions()
|
||||
{
|
||||
return array_diff( array( 'report_status_1', 'report_status_2', 'report_status_3', ), array( 'report_status_' . $this->status ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any available custom multimod actions this content item class supports
|
||||
*
|
||||
* @note Return in format of array( array( 'action' => ..., 'icon' => ..., 'language' => ... ) )
|
||||
* @return array
|
||||
*/
|
||||
public static function availableCustomMultimodActions()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'groupaction' => 'report_status',
|
||||
'icon' => 'flag',
|
||||
'grouplabel' => 'mark_as',
|
||||
'action' => array(
|
||||
array(
|
||||
'action' => 'report_status_1',
|
||||
'icon' => 'flag',
|
||||
'label' => 'report_status_1'
|
||||
),
|
||||
array(
|
||||
'action' => 'report_status_2',
|
||||
'icon' => 'exclamation-triangle',
|
||||
'label' => 'report_status_2'
|
||||
),
|
||||
array(
|
||||
'action' => 'report_status_3',
|
||||
'icon' => 'check-circle',
|
||||
'label' => 'report_status_3'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* !\IPS\core\Reports\report */
|
||||
|
||||
/**
|
||||
* Get reports
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function reports()
|
||||
{
|
||||
return iterator_to_array( \IPS\Db::i()->select( '*', 'core_rc_reports', array( 'rid=?', $this->id ), 'date_reported' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rebuild()
|
||||
{
|
||||
$numReports = \IPS\Db::i()->select( 'COUNT(*)', 'core_rc_reports', array( 'rid=?', $this->id ) )->first();
|
||||
if ( !$numReports )
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
$this->num_reports = $numReports;
|
||||
|
||||
$numComments = \IPS\Db::i()->select( 'COUNT(*)', 'core_rc_comments', array( 'rid=?', $this->id ) )->first();
|
||||
$this->num_comments = $numComments;
|
||||
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Report
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
|
||||
\IPS\Db::i()->delete( 'core_rc_reports', array( 'rid=?', $this->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that are available for selecting table rows
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getTableFilters()
|
||||
{
|
||||
return array(
|
||||
'read', 'unread', 'report_status_1', 'report_status_2', 'report_status_3'
|
||||
);
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,865 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Installer
|
||||
* @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 3 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Setup;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer
|
||||
*/
|
||||
class _Install
|
||||
{
|
||||
/**
|
||||
* System Requirements
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function systemRequirements()
|
||||
{
|
||||
$return = array();
|
||||
|
||||
/* PHP Version */
|
||||
$phpVersion = PHP_VERSION;
|
||||
if ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_success', FALSE, array( 'sprintf' => array( $phpVersion ) ) )
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_fail', FALSE, array( 'sprintf' => array( $phpVersion ) ) ),
|
||||
);
|
||||
}
|
||||
if ( version_compare( PHP_VERSION, '5.4.0' ) == -1 )
|
||||
{
|
||||
$return['advice'][] = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_advice', FALSE, array( 'sprintf' => array( $phpVersion ) ) );
|
||||
}
|
||||
|
||||
/* cURL or allow_url_fopen */
|
||||
if ( extension_loaded('curl') and $version = curl_version() and version_compare( $version['version'], '7.36', '>=' ) )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_curl_success' ),
|
||||
);
|
||||
}
|
||||
elseif ( function_exists('fsockopen') )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_curl_fopen' ),
|
||||
);
|
||||
|
||||
$return['advice'][] = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_curl_advice' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_curl_fail' ),
|
||||
);
|
||||
}
|
||||
|
||||
/* mbstring can be configured with --disable-mbregex */
|
||||
if ( extension_loaded( 'mbstring' ) )
|
||||
{
|
||||
if ( function_exists( 'mb_eregi' ) )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_mb_success' ),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_mb_regex' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_mb_fail' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Extensions */
|
||||
foreach ( array(
|
||||
'required' => array( 'dom', 'gd', 'mysqli', 'openssl', 'session', 'simplexml', 'xml', 'xmlreader', 'xmlwriter' ),
|
||||
'advised' => array( 'phar', 'zip' ),
|
||||
) as $type => $extensions )
|
||||
{
|
||||
foreach ( $extensions as $extension )
|
||||
{
|
||||
if ( extension_loaded( $extension ) )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_extension_success', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( "requirements_extension_{$extension}" ) ) ) ),
|
||||
);
|
||||
}
|
||||
elseif ( $type === 'required' )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_extension_fail', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( "requirements_extension_{$extension}" ) ) ) ),
|
||||
);
|
||||
}
|
||||
elseif ( $type === 'advised' )
|
||||
{
|
||||
$return['advice'][] = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_extension_advice', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( "requirements_extension_{$extension}" ) ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory Limit */
|
||||
$_memoryLimit = @ini_get('memory_limit');
|
||||
$memoryLimit = $_memoryLimit;
|
||||
if ( $memoryLimit != -1 )
|
||||
{
|
||||
preg_match( "#^(\d+)(\w+)$#", mb_strtolower($memoryLimit), $match );
|
||||
if( $match[2] == 'g' )
|
||||
{
|
||||
$memoryLimit = intval( $memoryLimit ) * 1024 * 1024 * 1024;
|
||||
}
|
||||
else if ( $match[2] == 'm' )
|
||||
{
|
||||
$memoryLimit = intval( $memoryLimit ) * 1024 * 1024;
|
||||
}
|
||||
else if ( $match[2] == 'k' )
|
||||
{
|
||||
$memoryLimit = intval( $memoryLimit ) * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
$memoryLimit = intval( $memoryLimit );
|
||||
}
|
||||
}
|
||||
if ( $memoryLimit >= ( 128 * 1024 * 1024 ) OR $memoryLimit == -1 )
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => TRUE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_memory_limit_success', FALSE, array( 'sprintf' => array( ( $memoryLimit != -1 ) ? \IPS\Output\Plugin\Filesize::humanReadableFilesize( $memoryLimit ) : \IPS\Member::loggedIn()->language()->get( 'unlimited' ) ) ) )
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements']['PHP'][] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_memory_limit_fail', FALSE, array( 'sprintf' => array( \IPS\Output\Plugin\Filesize::humanReadableFilesize( $memoryLimit ) ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
/* Suhosin */
|
||||
if ( extension_loaded( 'suhosin' ) )
|
||||
{
|
||||
foreach ( array(
|
||||
'suhosin.post.max_vars' => 4096,
|
||||
'suhosin.request.max_vars' => 4096,
|
||||
'suhosin.get.max_value_length' => 2000,
|
||||
'suhosin.post.max_value_length' => 10000,
|
||||
'suhosin.request.max_value_length' => 10000,
|
||||
'suhosin.request.max_varname_length' => 350,
|
||||
) as $setting => $minimum )
|
||||
{
|
||||
$value = ini_get( 'suhosin.post.max_vars' );
|
||||
if ( $value and $value < $minimum )
|
||||
{
|
||||
$return['advisory'][] = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_suhosin_limit', FALSE, array( 'sprintf' => array( $setting, $value, $minimum ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Writeables */
|
||||
$writeablesKey = \IPS\Member::loggedIn()->language()->addToStack('requirements_file_system');
|
||||
foreach ( array( 'applications', 'datastore', 'plugins', 'uploads' ) as $dir )
|
||||
{
|
||||
$success = is_writable( \IPS\ROOT_PATH . '/' . $dir );
|
||||
|
||||
$return['requirements'][ $writeablesKey ][ $dir ] = array(
|
||||
'success' => $success,
|
||||
'message' => $success ? \IPS\Member::loggedIn()->language()->addToStack( 'requirements_file_writable', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH . '/' . $dir ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'err_not_writable', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH . '/' . $dir ) ) )
|
||||
);
|
||||
}
|
||||
$logMethods = \IPS\Log::getUsedMethods();
|
||||
if( isset( $logMethods['disk'] ) and !empty( $logMethods['disk'] ) )
|
||||
{
|
||||
$dir = \IPS\Log::i( 'Disk' )->logDir;
|
||||
$success = is_writable( $dir );
|
||||
$return['requirements'][ $writeablesKey ][ $dir ] = array(
|
||||
'success' => $success,
|
||||
'message' => $success ? \IPS\Member::loggedIn()->language()->addToStack( 'requirements_file_writable', FALSE, array( 'sprintf' => array( $dir ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'err_not_writable', FALSE, array( 'sprintf' => array( $dir ) ) )
|
||||
);
|
||||
}
|
||||
try
|
||||
{
|
||||
if ( !is_writable( \IPS\TEMP_DIRECTORY ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
if ( $tempFile === FALSE or !file_exists( $tempFile ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
if( file_exists( \IPS\ROOT_PATH . '/constants.php' ) )
|
||||
{
|
||||
$return['requirements'][ $writeablesKey ]['tmp'] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'err_tmp_dir_adjust', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH ) ) )
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['requirements'][ $writeablesKey ]['tmp'] = array(
|
||||
'success' => FALSE,
|
||||
'message' => \IPS\Member::loggedIn()->language()->addToStack( 'err_tmp_dir_create', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH ) ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Percentage of *this step* completed (used for the progress bar)
|
||||
*/
|
||||
protected $stepProgress = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $apps Application keys of apps to install
|
||||
* @param string $defaultApp The default applicaion
|
||||
* @param string $baseUrl Base URL
|
||||
* @param array $path Base Path
|
||||
* @param array $db Database connection detials [see \IPS\Db::i()]
|
||||
* @param string $adminName Admin Username
|
||||
* @param string $adminPass Admin Password
|
||||
* @param string $adminEmail Admin Email
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
* @see \IPS\Db::i()
|
||||
*/
|
||||
public function __construct( $apps, $defaultApp, $baseUrl, $path, $db, $adminName, $adminPass, $adminEmail )
|
||||
{
|
||||
/* Have core app? */
|
||||
if ( !in_array( 'core', $apps ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'NO_CORE_APP' );
|
||||
}
|
||||
|
||||
/* Put the default app first */
|
||||
usort( $apps, function( $a, $b ) use ( $defaultApp ){
|
||||
if ( $a == 'core' or ( $a == $defaultApp and $b != 'core' ) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ( $b == 'core' or ( $b == $defaultApp and $a != 'core' ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} );
|
||||
|
||||
/* Connect to DB */
|
||||
$db = \IPS\Db::i( NULL, $db );
|
||||
|
||||
/* Check we have everything else */
|
||||
if ( !$baseUrl or !$path or !$adminName or !$adminEmail or !$adminPass )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'INSUFFICIENT_DATA' );
|
||||
}
|
||||
|
||||
/* Store data */
|
||||
$this->apps = $apps;
|
||||
$this->defaultApp = $defaultApp;
|
||||
$this->baseUrl = $baseUrl;
|
||||
$this->path = $path;
|
||||
$this->adminName = $adminName;
|
||||
$this->adminPass = $adminPass;
|
||||
$this->adminEmail = $adminEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process
|
||||
*
|
||||
* @param array Multiple-Redirector Data
|
||||
* @return array|null Multiple-Redirector Data or NULL indicates done
|
||||
*/
|
||||
public function process( $data )
|
||||
{
|
||||
/* Start */
|
||||
if ( $data === 0 )
|
||||
{
|
||||
return array( array( 1 ), \IPS\Member::loggedIn()->language()->addToStack('installing') );
|
||||
}
|
||||
|
||||
/* Run the step */
|
||||
$step = intval( $data[0] );
|
||||
|
||||
if ( $step == 13 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
elseif ( !method_exists( $this, "step{$step}" ) )
|
||||
{
|
||||
throw new \BadMethodCallException( 'NO_STEP' );
|
||||
}
|
||||
$response = call_user_func( array( $this, "step{$step}" ), $data );
|
||||
|
||||
return array( $response, \IPS\Member::loggedIn()->language()->addToStack( 'install_step_' . $step ), ( ( ( 100/12 ) * $data[0] + ( ( 100/12 ) / 100 * $this->stepProgress ) ) ) ?: 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* App Looper
|
||||
*
|
||||
* @param array data Multiple-Redirector Data
|
||||
* @param callback $code Code to execute for each app
|
||||
* @return array Data to Multiple-Redirector Data
|
||||
*/
|
||||
protected function appLoop( $data, $code )
|
||||
{
|
||||
$this->stepProgress = 0;
|
||||
|
||||
$returnNext = FALSE;
|
||||
foreach ( $this->apps as $app )
|
||||
{
|
||||
$this->stepProgress += ( 100 / count( $this->apps ) );
|
||||
|
||||
if ( !isset( $data[1] ) )
|
||||
{
|
||||
return array( $data[0], $app );
|
||||
}
|
||||
elseif ( $data[1] == $app )
|
||||
{
|
||||
$val = call_user_func( $code, $app );
|
||||
|
||||
if ( is_array( $val ) )
|
||||
{
|
||||
return $val;
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnNext = true;
|
||||
}
|
||||
}
|
||||
elseif ( $returnNext )
|
||||
{
|
||||
return array( $data[0], $app );
|
||||
}
|
||||
}
|
||||
|
||||
return array( ( $data[0] + 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 1
|
||||
* Create database
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step1( $data )
|
||||
{
|
||||
$this->stepProgress = 0;
|
||||
$perAppProgress = floor( 100 / count( $this->apps ) );
|
||||
|
||||
$returnNext = FALSE;
|
||||
foreach ( $this->apps as $app )
|
||||
{
|
||||
$this->stepProgress += $perAppProgress;
|
||||
|
||||
if ( !isset( $data[1] ) )
|
||||
{
|
||||
return array( $data[0], $app );
|
||||
}
|
||||
elseif ( $data[1] == $app )
|
||||
{
|
||||
if ( !isset( $data[2] ) )
|
||||
{
|
||||
$data[2] = 0;
|
||||
}
|
||||
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ) )
|
||||
{
|
||||
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ), TRUE );
|
||||
if ( count( $schema ) )
|
||||
{
|
||||
$perTableProgress = ( $perAppProgress / count( $schema ) );
|
||||
$i = 0;
|
||||
foreach( $schema as $dbTable )
|
||||
{
|
||||
$i++;
|
||||
$this->stepProgress += $perTableProgress;
|
||||
while ( $data[2] > $i )
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->dropTable( $dbTable['name'], TRUE );
|
||||
\IPS\Db::i()->createTable( $dbTable );
|
||||
|
||||
if ( isset( $dbTable['inserts'] ) )
|
||||
{
|
||||
foreach ( $dbTable['inserts'] as $insertData )
|
||||
{
|
||||
$adminName = $this->adminName;
|
||||
\IPS\Db::i()->insert( $dbTable['name'], array_map( function( $column ) use( $adminName ) {
|
||||
if( !is_string( $column ) )
|
||||
{
|
||||
return $column;
|
||||
}
|
||||
|
||||
$column = str_replace( '<%TIME%>', time(), $column );
|
||||
$column = str_replace( '<%ADMIN_NAME%>', $adminName, $column );
|
||||
$column = str_replace( '<%IP_ADDRESS%>', $_SERVER['REMOTE_ADDR'], $column );
|
||||
return $column;
|
||||
}, $insertData ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !file_exists( \IPS\ROOT_PATH . "/applications/{$app}/setup/install/queries.json" ) )
|
||||
{
|
||||
$data[2]++;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app}/setup/install/queries.json" ) )
|
||||
{
|
||||
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/setup/install/queries.json" ), TRUE );
|
||||
|
||||
ksort($schema);
|
||||
|
||||
foreach( $schema as $instruction )
|
||||
{
|
||||
if ( $instruction['method'] === 'addColumn' )
|
||||
{
|
||||
/* Check to see if it exists first */
|
||||
$tableDefinition = \IPS\Db::i()->getTableDefinition( $instruction['params'][0] );
|
||||
|
||||
if ( ! empty( $tableDefinition['columns'][ $instruction['params'][1]['name'] ] ) )
|
||||
{
|
||||
/* Run an alter instead */
|
||||
\IPS\Db::i()->changeColumn( $instruction['params'][0], $instruction['params'][1]['name'], $instruction['params'][1] );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( isset( $instruction['params'][1] ) and is_array( $instruction['params'][1] ) )
|
||||
{
|
||||
$groups = array_filter( iterator_to_array( \IPS\Db::i()->select( 'g_id', 'core_groups' ) ), function( $groupId ) {
|
||||
if( $groupId == 2 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
});
|
||||
|
||||
foreach( $instruction['params'][1] as $column => $value )
|
||||
{
|
||||
if( $value === "<%NO_GUESTS%>" )
|
||||
{
|
||||
$instruction['params'][1][ $column ] = implode( ",", $groups );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_user_func_array( array( \IPS\Db::i(), $instruction['method'] ), $instruction['params'] );
|
||||
}
|
||||
}
|
||||
|
||||
$returnNext = TRUE;
|
||||
}
|
||||
elseif ( $returnNext )
|
||||
{
|
||||
return array( $data[0], $app );
|
||||
}
|
||||
}
|
||||
|
||||
return array( ( $data[0] + 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2
|
||||
* Insert application and module data
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step2( $data )
|
||||
{
|
||||
$pos = 0;
|
||||
$defaultApp = $this->defaultApp;
|
||||
return $this->appLoop( $data, function( $app ) use ( &$pos, $defaultApp )
|
||||
{
|
||||
/* Get version data */
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app}/data/versions.json" ) )
|
||||
{
|
||||
$versions = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/versions.json" ), TRUE );
|
||||
$keys = array_keys( $versions );
|
||||
|
||||
$info = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/application.json" ), TRUE );
|
||||
|
||||
/* App Data */
|
||||
\IPS\Db::i()->insert( 'core_applications', array(
|
||||
'app_author' => $info['app_author'],
|
||||
'app_version' => array_pop( $versions ),
|
||||
'app_long_version' => array_pop( $keys ),
|
||||
'app_directory' => $app,
|
||||
'app_added' => time(),
|
||||
'app_position' => ++$pos,
|
||||
'app_protected' => ( $app === 'core' ),
|
||||
'app_enabled' => TRUE,
|
||||
'app_default' => ( $app === $defaultApp ),
|
||||
) );
|
||||
|
||||
/* Modules */
|
||||
$modules = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/modules.json" ), TRUE );
|
||||
$modulePos = 0;
|
||||
foreach ( $modules as $area => $areaModules )
|
||||
{
|
||||
foreach ( $areaModules as $key => $data )
|
||||
{
|
||||
$insertId = \IPS\Db::i()->insert( 'core_modules', array(
|
||||
'sys_module_application' => $app,
|
||||
'sys_module_key' => $key,
|
||||
'sys_module_protected' => $data['protected'],
|
||||
'sys_module_visible' => TRUE,
|
||||
'sys_module_position' => ++$modulePos,
|
||||
'sys_module_area' => $area,
|
||||
'sys_module_default_controller' => $data['default_controller'],
|
||||
) );
|
||||
|
||||
\IPS\Db::i()->insert( 'core_permission_index', array(
|
||||
'app' => 'core',
|
||||
'perm_type' => 'module',
|
||||
'perm_type_id' => $insertId,
|
||||
'perm_view' => '*',
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 3
|
||||
* Insert Settings
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step3( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
\IPS\Application::load( $app )->installSettings();
|
||||
|
||||
if ( $app === 'core' )
|
||||
{
|
||||
require \IPS\ROOT_PATH . '/conf_global.php';
|
||||
|
||||
\IPS\Db::i()->insert( 'core_file_storage', array(
|
||||
'method' => 'FileSystem',
|
||||
'configuration' => json_encode( array(
|
||||
'dir' => '{root}/uploads',
|
||||
'url' => 'uploads'
|
||||
) )
|
||||
) );
|
||||
}
|
||||
|
||||
/* Set up File Storage methods */
|
||||
\IPS\Application::load( $app )->installExtensions();
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 4
|
||||
* Create admin account
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step4( $data )
|
||||
{
|
||||
\IPS\Settings::i()->member_group = 4;
|
||||
$member = new \IPS\Member;
|
||||
$member->name = $this->adminName;
|
||||
$member->email = $this->adminEmail;
|
||||
$member->ip_address = \IPS\Request::i()->ipAddress();
|
||||
$member->member_group_id = 4;
|
||||
$member->allow_admin_mails = 0;
|
||||
$member->joined = time();
|
||||
$member->members_pass_salt = $member->generateSalt();
|
||||
$member->members_pass_hash = $member->encryptedPassword( $this->adminPass );
|
||||
$member->members_bitoptions['view_sigs'] = TRUE;
|
||||
$member->save();
|
||||
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $this->adminEmail ), "conf_key = 'email_out'" );
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $this->adminEmail ), "conf_key = 'email_in'" );
|
||||
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
|
||||
return array( 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 5
|
||||
* Create Tasks
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step5( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
\IPS\Application::load( $app )->installTasks();
|
||||
|
||||
if( $app == 'core' )
|
||||
{
|
||||
\IPS\core\BulkMail\Bulkmailer::updateTask( 0 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 6
|
||||
* Install default Language
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step6( $data )
|
||||
{
|
||||
/* Install the default language */
|
||||
$locales = array( 'en_US', 'en_US.utf8', 'en_US.UTF8' );
|
||||
foreach ( $locales as $k => $localeCode )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Lang::validateLocale( $localeCode );
|
||||
}
|
||||
catch ( \InvalidArgumentException $e )
|
||||
{
|
||||
unset( $locales[ $k ] );
|
||||
}
|
||||
}
|
||||
|
||||
$locale = ( !empty( $locales ) ) ? array_shift( $locales ) : 'en_US';
|
||||
|
||||
\IPS\Db::i()->insert( 'core_sys_lang', array(
|
||||
'lang_id' => 1,
|
||||
'lang_short' => $locale,
|
||||
'lang_title' => "English (USA)",
|
||||
'lang_default' => 1,
|
||||
'lang_isrtl' => 0,
|
||||
'lang_protected' => 1,
|
||||
'lang_order' => 1
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( \IPS\Data\Store::i()->languages ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->languages );
|
||||
}
|
||||
|
||||
return array( 7 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 7
|
||||
* Create Languages
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step7( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app ) use ($data)
|
||||
{
|
||||
if ( !isset( $data[2] ) )
|
||||
{
|
||||
$data[2] = 0;
|
||||
}
|
||||
|
||||
$inserted = \IPS\Application::load( $app )->installLanguages( $data[2], 250 );
|
||||
|
||||
if ( $inserted )
|
||||
{
|
||||
$data[2] += $inserted;
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 8
|
||||
* Create Email Templates
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step8( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
\IPS\Application::load( $app )->installEmailTemplates();
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 9
|
||||
* Create Themes
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step9( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app ) use ($data)
|
||||
{
|
||||
if ( !isset( $data[2] ) )
|
||||
{
|
||||
$data[2] = 0;
|
||||
}
|
||||
|
||||
if( $data[2] == 0 )
|
||||
{
|
||||
\IPS\Application::load( $app )->installThemeSettings();
|
||||
}
|
||||
|
||||
$inserted = \IPS\Application::load( $app )->installTemplates( FALSE, $data[2], 150 );
|
||||
|
||||
if ( $inserted )
|
||||
{
|
||||
$data[2] += $inserted;
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Theme::load( \IPS\Theme::defaultTheme() )->saveSet();
|
||||
return null;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 10
|
||||
* Create Javascript
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step10( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
\IPS\Application::load( $app )->installJavascript();
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 11
|
||||
* Create Search Keywords
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step11( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
\IPS\Application::load( $app )->installSearchKeywords();
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 12
|
||||
* Install any widgets/extensions that need adding on install
|
||||
*
|
||||
* @return array Multiple-Redirector Data
|
||||
*/
|
||||
protected function step12( $data )
|
||||
{
|
||||
return $this->appLoop( $data, function( $app )
|
||||
{
|
||||
if( !file_exists( \IPS\ROOT_PATH . '/plugins/hooks.txt' ) )
|
||||
{
|
||||
@touch( \IPS\ROOT_PATH . '/plugins/hooks.txt' );
|
||||
@chmod( \IPS\ROOT_PATH . '/plugins/hooks.txt', 0777 );
|
||||
}
|
||||
|
||||
if( !is_writable( \IPS\ROOT_PATH . '/plugins/hooks.txt' ) )
|
||||
{
|
||||
throw new \RuntimeException( sprintf( \IPS\Member::loggedIn()->language()->get("hook_file_not_writable"), \IPS\ROOT_PATH . '/plugins/hooks.txt' ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\Application::load( $app )->installHooks();
|
||||
\IPS\Application::load( $app )->installWidgets();
|
||||
\IPS\Application::load( $app )->installOther();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Log::i( LOG_ERR )->write( $e, 'install_error' );
|
||||
}
|
||||
catch( \RuntimeException $e ){}
|
||||
}
|
||||
|
||||
/* Insert default emoticons */
|
||||
if( $app == 'core' )
|
||||
{
|
||||
$setId = md5( uniqid() );
|
||||
$position = 0;
|
||||
\IPS\Lang::saveCustom( 'core', "core_emoticon_group_{$setId}", "Default" );
|
||||
|
||||
$inserts = array();
|
||||
|
||||
foreach( json_decode( file_get_contents( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY ."/install/emoticons/data.json" ) ) as $type => $file )
|
||||
{
|
||||
$fileObj = \IPS\File::create( 'core_Emoticons', $file, file_get_contents( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . "/install/emoticons/" . $file ), 'emoticons', FALSE, NULL, FALSE );
|
||||
|
||||
$inserts[] = array(
|
||||
'typed' => $type,
|
||||
'image' => (string) $fileObj,
|
||||
'clickable' => TRUE,
|
||||
'emo_set' => $setId,
|
||||
'emo_position' => ++$position,
|
||||
);
|
||||
}
|
||||
|
||||
if( count( $inserts ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_emoticons', $inserts );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Share Links 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 12 Jun 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\ShareLinks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Share Link Node
|
||||
*/
|
||||
class _Service extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_share_links';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'share_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'share_key' );
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'sharelinks';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'settings',
|
||||
'prefix' => 'sharelinks_',
|
||||
);
|
||||
|
||||
/**
|
||||
* [Node] Reset our roots so they can be reloaded
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetRootResult()
|
||||
{
|
||||
static::$rootsResult = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch All Services
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function shareLinks()
|
||||
{
|
||||
if ( !isset( \IPS\Data\Store::i()->shareLinks ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->shareLinks = iterator_to_array( \IPS\Db::i()->select( '*', static::$databaseTable, NULL, static::$databasePrefix . static::$databaseColumnOrder ) );
|
||||
}
|
||||
|
||||
$return = array();
|
||||
foreach ( \IPS\Data\Store::i()->shareLinks as $service )
|
||||
{
|
||||
$return[] = static::constructFromData( $service );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [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 = array();
|
||||
|
||||
if ( $subnode )
|
||||
{
|
||||
$url = $url->setQueryString( array( 'subnode' => 1 ) );
|
||||
}
|
||||
|
||||
if( $this->canEdit() )
|
||||
{
|
||||
$buttons['edit'] = array(
|
||||
'icon' => 'pencil',
|
||||
'title' => 'edit',
|
||||
'link' => $url->setQueryString( array( 'do' => 'form', 'id' => $this->_id ) ),
|
||||
'data' => ( static::$modalForms ? array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit') ) : array() ),
|
||||
'hotkey'=> 'e return'
|
||||
);
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'share_title', $this->title, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'share_groups', ( $this->groups != '*' ) ? explode( ",", $this->groups ) : $this->groups, FALSE, array( 'options' => \IPS\Member\Group::groups(), 'parse' => 'normal', 'multiple' => TRUE, 'unlimited' => '*', 'unlimitedLang' => 'everyone' ) ) );
|
||||
|
||||
/* Find the service and see if it has any additional settings... */
|
||||
$className = "\\IPS\\Content\\ShareServices\\" . ucwords( $this->key );
|
||||
|
||||
$className::modifyForm( $form );
|
||||
|
||||
if ( $className::canAutoshare() )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Checkbox( 'share_autoshare', $this->autoshare, 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( count( $values ) )
|
||||
{
|
||||
foreach ( $values as $k => $v )
|
||||
{
|
||||
if( !in_array( $k, array( 'share_title', 'share_groups', 'share_autoshare' ) ) )
|
||||
{
|
||||
if ( $v instanceof \IPS\GeoLocation )
|
||||
{
|
||||
$v = json_encode( $v );
|
||||
}
|
||||
if ( is_array( $v ) )
|
||||
{
|
||||
$v = implode( ',', $v );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $v ), array( 'conf_key=?', $k ) );
|
||||
\IPS\Settings::i()->$k = $v;
|
||||
|
||||
unset( $values[ $k ] );
|
||||
}
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
|
||||
/* Remove prefix */
|
||||
$_values = $values;
|
||||
$values = array();
|
||||
foreach ( $_values as $k => $v )
|
||||
{
|
||||
if( mb_substr( $k, 0, 6 ) === 'share_' )
|
||||
{
|
||||
$values[ mb_substr( $k, 6 ) ] = $v;
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Node Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get__title()
|
||||
{
|
||||
if ( !$this->id )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get whether or not this node is enabled
|
||||
*
|
||||
* @note Return value NULL indicates the node cannot be enabled/disabled
|
||||
* @return bool|null
|
||||
*/
|
||||
protected function get__enabled()
|
||||
{
|
||||
return ( $this->enabled ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Set whether or not this node is enabled
|
||||
*
|
||||
* @param bool|int $enabled Whether to set it enabled or disabled
|
||||
* @return void
|
||||
*/
|
||||
protected function set__enabled( $enabled )
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to add a child node to this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdd()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to copy this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canCopy()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to edit permissions for this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canManagePermissions()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to delete this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canDelete()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search
|
||||
*
|
||||
* @param string $column Column to search
|
||||
* @param string $query Search query
|
||||
* @param string|null $order Column to order by
|
||||
* @param mixed $where Where clause
|
||||
* @return array
|
||||
*/
|
||||
public static function search( $column, $query, $order=NULL, $where=array() )
|
||||
{
|
||||
if ( $column === '_title' )
|
||||
{
|
||||
$column = 'share_title';
|
||||
}
|
||||
if ( $order === '_title' )
|
||||
{
|
||||
$order = 'share_title';
|
||||
}
|
||||
return parent::search( $column, $query, $order, $where );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
parent::save();
|
||||
unset( \IPS\Data\Store::i()->shareLinks );
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
unset( \IPS\Data\Store::i()->shareLinks );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Staff Directory Group 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 18 Sep 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\StaffDirectory;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff Directory Group Node
|
||||
*/
|
||||
class _Group extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_leaders_groups';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'group_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'staff_directory';
|
||||
|
||||
/**
|
||||
* @brief [Node] Subnode class
|
||||
*/
|
||||
public static $subnodeClass = 'IPS\core\StaffDirectory\User';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'staff',
|
||||
'prefix' => 'leaders_',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'core_staffgroups_';
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
/* Title field */
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'staff_group_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "core_staffgroups_{$this->id}" : NULL ) ) ) );
|
||||
|
||||
/* Build the layout selection radios */
|
||||
$templates = array();
|
||||
foreach ( \IPS\Theme::i()->getRawTemplates( 'core', 'front', 'staffdirectory', \IPS\Theme::RETURN_ARRAY_BIT_NAMES | \IPS\Theme::RETURN_NATIVE ) as $template )
|
||||
{
|
||||
if ( mb_strpos( $template, 'layout_' ) === 0 && mb_strpos( $template, '_preview' ) === FALSE )
|
||||
{
|
||||
$realTemplate = $template . '_preview';
|
||||
$templates[ $template ] = \IPS\Theme::i()->getTemplate( 'staffdirectory', 'core', 'front' )->$realTemplate( );
|
||||
}
|
||||
}
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'staff_group_template', $this->id ? $this->template : NULL, TRUE, array( 'options' => $templates, 'parse' => 'none' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [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['staff_group_title'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'core', "core_staffgroups_{$this->id}", $values['staff_group_title'] );
|
||||
unset( $values['staff_group_title'] );
|
||||
}
|
||||
|
||||
if( isset( $values['staff_group_template'] ) )
|
||||
{
|
||||
$values['template'] = $values['staff_group_template'];
|
||||
unset( $values['staff_group_template'] );
|
||||
}
|
||||
|
||||
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['add'] ) )
|
||||
{
|
||||
$buttons['add']['title'] = 'staff_add_record';
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to edit permissions for this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canManagePermissions()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get members
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function members()
|
||||
{
|
||||
$members = array();
|
||||
foreach ( $this->children() as $child )
|
||||
{
|
||||
if ( $child->type === 'm' )
|
||||
{
|
||||
$members[ $child->type_id ] = $child;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', array( 'member_group_id=?', $child->type_id ), 'name' ) as $m )
|
||||
{
|
||||
if ( !isset( $members[ $m['member_id'] ] ) )
|
||||
{
|
||||
$member = new User;
|
||||
$memberObj = \IPS\Member::constructFromData( $m );
|
||||
$member->member = $memberObj;
|
||||
$members[ $memberObj->member_id ] = $member;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $members;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Staff Directory User 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 18 Sep 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\StaffDirectory;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff Directory User Node
|
||||
*/
|
||||
class _User extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_leaders';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'leader_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'leader_type_id' );
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node ID Database Column
|
||||
*/
|
||||
public static $parentNodeColumnId = 'group_id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node Class
|
||||
*/
|
||||
public static $parentNodeClass = 'IPS\core\StaffDirectory\Group';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'staff',
|
||||
'prefix' => 'leaders_',
|
||||
);
|
||||
|
||||
/**
|
||||
* Get staff users in a group
|
||||
*
|
||||
* @param int|null $group [Optional] Group to return users from
|
||||
* @return array
|
||||
*/
|
||||
public static function staff( $group=NULL )
|
||||
{
|
||||
if( $group === NULL )
|
||||
{
|
||||
return static::roots();
|
||||
}
|
||||
|
||||
$users = array();
|
||||
|
||||
foreach ( static::roots() as $user )
|
||||
{
|
||||
if( $user->group_id === $group )
|
||||
{
|
||||
$users[] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'leader_type', $this->type ?: 'm', TRUE, array(
|
||||
'options' => array( 'm' => 'leader_type_member', 'g' => 'leader_type_group' ),
|
||||
'toggles' => array(
|
||||
'm' => array( 'leader_id_member', 'leader_name_toggle', 'leader_title_toggle', 'leader_custom_bio_id' ),
|
||||
'g' => array( 'leader_id_group' )
|
||||
),
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'leader_id_group', $this->type === 'g' ? $this->type_id : NULL, FALSE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal' ), NULL, NULL, NULL, 'leader_id_group' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Member( 'leader_id_member', ( $this->type === 'm' AND !$this->_new ) ? \IPS\Member::load( $this->type_id )->name : NULL, FALSE, array(), function( $val )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->leader_type === 'm' )
|
||||
{
|
||||
throw new \DomainException('form_required');
|
||||
}
|
||||
}, NULL, NULL, 'leader_id_member' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'leader_use_custom_name', ( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_name_{$this->id}") ) ? 1 : 0, FALSE, array( 'options' => array( 0 => 'leader_custom_name_default', 1 => 'leader_custom_name_custom' ), 'toggles' => array( 1 => array( 'leader_custom_name' ) ) ), NULL, NULL, NULL, 'leader_name_toggle' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'leader_custom_name', NULL, FALSE, array( 'app' => 'core', 'key' => ( $this->id ? "core_staff_directory_name_{$this->id}" : NULL ) ), NULL, NULL, NULL, 'leader_custom_name' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'leader_use_custom_title', ( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_title_{$this->id}") ) ? 1 : 0, FALSE, array( 'options' => array( 0 => 'leader_custom_title_default', 1 => 'leader_custom_title_custom' ), 'toggles' => array( 1 => array( 'leader_custom_title' ) ) ), NULL, NULL, NULL, 'leader_title_toggle' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'leader_custom_title', NULL, FALSE, array( 'app' => 'core', 'key' => ( $this->id ? "core_staff_directory_title_{$this->id}" : NULL ) ), NULL, NULL, NULL, 'leader_custom_title' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'leader_custom_bio', NULL, FALSE, array(
|
||||
'app' => 'core',
|
||||
'key' => ( $this->id ? "core_staff_directory_bio_{$this->id}" : NULL ),
|
||||
'editor' => array(
|
||||
'app' => 'core',
|
||||
'key' => 'Staffdirectory',
|
||||
'autoSaveKey' => ( $this->id ? ( 'leader-' . $this->id ) : ( 'leader-' . 999999999 ) ),
|
||||
'attachIds' => ( $this->id ? array( $this->id ) : NULL )
|
||||
),
|
||||
), NULL, NULL, NULL, 'leader_custom_bio_id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [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['leader_type'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( \IPS\Db::i()->select( '*', 'core_leaders', array( 'leader_type=? AND leader_type_id=?', $values['leader_type'], $values['leader_type'] === 'm' ? $values['leader_id_member']->member_id : $values['leader_id_group'] ) )->first() )
|
||||
{
|
||||
if( !$this->id OR ( $this->id AND $this->type != $values['leader_type'] OR $this->type_id != ( $values['leader_type'] === 'm' ? $values['leader_id_member']->member_id : $values['leader_id_group'] ) ) )
|
||||
{
|
||||
throw new \LogicException( \IPS\Member::loggedIn()->language()->addToStack("only_one_leader") );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ){}
|
||||
}
|
||||
|
||||
if( isset( $values['leader_type'] ) AND ( isset( $values['leader_id_member'] ) OR $values['leader_id_group'] ) )
|
||||
{
|
||||
$values['type_id'] = $values['leader_type'] === 'm' ? $values['leader_id_member']->member_id : $values['leader_id_group'];
|
||||
unset( $values['leader_id_group'], $values['leader_id_member'] );
|
||||
$this->type = $values['leader_type'];
|
||||
$this->type_id = $values['type_id'];
|
||||
}
|
||||
|
||||
if ( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
|
||||
$values['position'] = ( \IPS\Db::i()->select( 'MAX(leader_position)', 'core_leaders' )->first() + 1 );
|
||||
}
|
||||
|
||||
$toUnset = array();
|
||||
|
||||
if ( isset( $values['leader_use_custom_name'] ) )
|
||||
{
|
||||
$toUnset[] = 'leader_use_custom_name';
|
||||
$toUnset[] = 'leader_custom_name';
|
||||
|
||||
\IPS\Lang::deleteCustom( 'core', "core_staff_directory_name_{$this->id}" );
|
||||
}
|
||||
|
||||
if( isset( $values['leader_custom_name'] ) AND isset( $values['leader_use_custom_name'] ) AND $values['leader_use_custom_name'] )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'core', "core_staff_directory_name_{$this->id}", $values['leader_custom_name'] );
|
||||
}
|
||||
|
||||
if ( isset( $values['leader_use_custom_title'] ) )
|
||||
{
|
||||
$toUnset[] = 'leader_use_custom_title';
|
||||
$toUnset[] = 'leader_custom_title';
|
||||
|
||||
\IPS\Lang::deleteCustom( 'core', "core_staff_directory_title_{$this->id}" );
|
||||
}
|
||||
|
||||
if( isset( $values['leader_custom_title'] ) AND isset( $values['leader_use_custom_title'] ) AND $values['leader_use_custom_title'] )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'core', "core_staff_directory_title_{$this->id}", $values['leader_custom_title'] );
|
||||
}
|
||||
|
||||
if( isset( $values['leader_custom_bio'] ) )
|
||||
{
|
||||
$toUnset[] = 'leader_custom_bio';
|
||||
\IPS\Lang::saveCustom( 'core', "core_staff_directory_bio_{$this->id}", $values['leader_custom_bio'] );
|
||||
}
|
||||
|
||||
if( count( $toUnset ) )
|
||||
{
|
||||
foreach( $toUnset as $_key )
|
||||
{
|
||||
unset( $values[ $_key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process created object AFTER the object has been created
|
||||
*
|
||||
* @param \IPS\Content\Comment|NULL $comment The first comment
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
public function postSaveForm( $values )
|
||||
{
|
||||
parent::postSaveForm( $values );
|
||||
|
||||
\IPS\File::claimAttachments( 'leader-' . 999999999, $this->id );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Node Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get__title()
|
||||
{
|
||||
if ( !$this->id )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( $this->type === 'm' )
|
||||
{
|
||||
if( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_name_{$this->id}") and \IPS\Member::loggedIn()->language()->get("core_staff_directory_name_{$this->id}") )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( "core_staff_directory_name_{$this->id}" );
|
||||
}
|
||||
|
||||
return \IPS\Member::load( $this->type_id )->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member\Group::load( $this->type_id )->name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Node Icon
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get__icon()
|
||||
{
|
||||
return $this->type === 'm' ? 'fa-user' : 'fa-group';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Member
|
||||
*/
|
||||
public $member;
|
||||
|
||||
/**
|
||||
* Get member data for user
|
||||
*
|
||||
* @return \IPS\Member
|
||||
*/
|
||||
public function member()
|
||||
{
|
||||
if ( $this->member === NULL )
|
||||
{
|
||||
$this->member = \IPS\Member::load( $this->type_id );
|
||||
}
|
||||
|
||||
return $this->member;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to edit permissions for this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdd()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to copy this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canCopy()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to edit permissions for this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canManagePermissions()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
\IPS\File::unclaimAttachments( 'core_Staffdirectory', $this->id );
|
||||
parent::delete();
|
||||
static::updateEmptySetting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
parent::save();
|
||||
static::updateEmptySetting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any records and update setting so we can hide the link if there is nothing
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function updateEmptySetting()
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => !( (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_leaders' )->first() ) ), array( 'conf_key=?', 'staff_directory_empty' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Status Update 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
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Statuses;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status Update Reply
|
||||
*/
|
||||
class _Reply extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \IPS\Content\Hideable, \IPS\Content\Reputation
|
||||
{
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_member_status_replies';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'reply_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Title
|
||||
*/
|
||||
public static $title = 'status_reply';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Icon
|
||||
*/
|
||||
public static $icon = 'comment-o';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = 'IPS\core\Statuses\Status';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'status_id',
|
||||
'date' => 'date',
|
||||
'content' => 'content',
|
||||
'author' => 'member_id',
|
||||
'approved' => 'approved',
|
||||
'ip_address' => 'ip_address',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'status_';
|
||||
|
||||
/**
|
||||
* @brief Reputation Type
|
||||
*/
|
||||
public static $reputationType = 'status_reply_id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Comment Template
|
||||
*/
|
||||
public static $commentTemplate = array( array( 'profile', 'core', 'front' ), 'statusReplyContainer' );
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'status_reply';
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
if ( $action === 'find' )
|
||||
{
|
||||
return $this->item()->url();
|
||||
}
|
||||
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
$member = \IPS\Member::load( $this->item()->member_id );
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=members&controller=profile&id={$member->member_id}&status={$this->id}", 'front', 'profile', array( $member->members_seo_name ) )->setQueryString( 'type', 'status' );
|
||||
|
||||
if ( $action )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( array( 'do' => $action, 'type' => 'reply' ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendNotifications()
|
||||
{
|
||||
parent::sendNotifications();
|
||||
|
||||
/* Notify when somebody replies to status updates I am connected to */
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'profile_reply', $this, array( $this ) );
|
||||
|
||||
foreach (
|
||||
\IPS\Db::i()->select(
|
||||
'core_members.*', 'core_member_status_replies',
|
||||
array( 'reply_status_id=? and reply_member_id !=?', $this->item()->id, $this->author()->member_id )
|
||||
)->join(
|
||||
'core_members',
|
||||
'core_members.member_id=core_member_status_replies.reply_member_id'
|
||||
) as $member
|
||||
)
|
||||
{
|
||||
$notification->recipients->attach( \IPS\Member::constructFromData( $member ) );
|
||||
}
|
||||
|
||||
if( $this->author()->member_id != $this->item()->author()->member_id )
|
||||
{
|
||||
$notification->recipients->attach( $this->item()->author() );
|
||||
}
|
||||
|
||||
if( $this->author()->member_id != $this->item()->member_id )
|
||||
{
|
||||
$notification->recipients->attach( \IPS\Member::load( $this->item()->member_id ) );
|
||||
}
|
||||
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Profile owner should always be able to delete */
|
||||
if ( $member->member_id == $this->item()->member_id )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return parent::canDelete( $member );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Status Update 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
|
||||
* @since 10 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Statuses;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status Update Model
|
||||
*/
|
||||
class _Status extends \IPS\Content\Item implements \IPS\Content\ReportCenter, \IPS\Content\Reputation, \IPS\Content\Lockable, \IPS\Content\Hideable
|
||||
{
|
||||
/* !\IPS\Patterns\ActiveRecord */
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_member_status_updates';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'status_';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Icon
|
||||
*/
|
||||
public static $icon = 'comment-o';
|
||||
|
||||
/**
|
||||
* @brief Number of comments per page
|
||||
*/
|
||||
public static $commentsPerPage = 3;
|
||||
|
||||
/**
|
||||
* @brief Number of comments per page when requesting previous replies (ajax)
|
||||
*/
|
||||
public static $commentsPerPageAjax = 25;
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* Save Changed Columns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
parent::save();
|
||||
\IPS\Widget::deleteCaches( 'recentStatusUpdates', 'core' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_member_status_replies', array( 'reply_status_id=?', $this->id ) ), 'IPS\core\Statuses\Reply' ) AS $reply )
|
||||
{
|
||||
$reply->delete();
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
\IPS\Widget::deleteCaches( 'recentStatusUpdates', 'core' );
|
||||
}
|
||||
|
||||
/* !\IPS\Content\Item */
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'member_status';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'date' => 'date',
|
||||
'author' => 'author_id',
|
||||
'num_comments' => 'replies',
|
||||
'locked' => 'is_locked',
|
||||
'approved' => 'approved',
|
||||
'ip_address' => 'author_ip',
|
||||
'content' => 'content',
|
||||
'title' => 'content',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief Module
|
||||
*/
|
||||
public static $module = 'members';
|
||||
|
||||
/**
|
||||
* @brief Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'status_';
|
||||
|
||||
/**
|
||||
* @brief Comment Class
|
||||
*/
|
||||
public static $commentClass = 'IPS\core\Statuses\Reply';
|
||||
|
||||
/**
|
||||
* @brief [Content\Item] First "comment" is part of the item?
|
||||
*/
|
||||
public static $firstCommentRequired = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Reputation Type
|
||||
*/
|
||||
public static $reputationType = 'status_id';
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'status_status';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_title()
|
||||
{
|
||||
return strip_tags( $this->mapped('content') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mapped value
|
||||
*
|
||||
* @param string $key date,content,ip_address,first
|
||||
* @return mixed
|
||||
*/
|
||||
public function mapped( $key )
|
||||
{
|
||||
if ( $key === 'title' )
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
return parent::mapped( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a given member create a status update?
|
||||
*
|
||||
* @param \IPS\Member $member
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreateFromCreateMenu( \IPS\Member $member = null)
|
||||
{
|
||||
if ( !$member )
|
||||
{
|
||||
$member = \IPS\Member::loggedIn();
|
||||
}
|
||||
|
||||
/* Can we access the module? */
|
||||
if ( !parent::canCreate( $member, NULL, FALSE ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We have to be logged in */
|
||||
if ( !$member->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Disabled at the group level? */
|
||||
if( \IPS\Member::loggedIn()->group['gbw_no_status_update'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Or at the profile level? */
|
||||
if( \IPS\Member::loggedIn()->members_bitoptions['bw_no_status_update'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( !$member->pp_setting_count_comments or !\IPS\Settings::i()->profile_comments )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a given member create this type of content?
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param \IPS\Node\Model|NULL $container Container
|
||||
* @param bool $showError If TRUE, rather than returning a boolean value, will display an error
|
||||
* @return bool
|
||||
*/
|
||||
public static function canCreate( \IPS\Member $member, \IPS\Node\Model $container=NULL, $showError=FALSE )
|
||||
{
|
||||
$profileOwner = isset( \IPS\Request::i()->id ) ? \IPS\Member::load( \IPS\Request::i()->id ) : \IPS\Member::loggedIn();
|
||||
|
||||
/* Can we access the module? */
|
||||
if ( !parent::canCreate( $member, $container, $showError ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We have to be logged in */
|
||||
if ( !$member->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Is the user being ignored */
|
||||
if ( $profileOwner->isIgnoring( $member, 'messages' ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Disabled at the group level? */
|
||||
if( \IPS\Member::loggedIn()->group['gbw_no_status_update'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Or at the profile level? */
|
||||
if( \IPS\Member::loggedIn()->members_bitoptions['bw_no_status_update'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( !$profileOwner->pp_setting_count_comments and $member->member_id != \IPS\Request::i()->id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get elements for add/edit form
|
||||
*
|
||||
* @param \IPS\Content\Item|NULL $item The current item if editing or NULL if creating
|
||||
* @param \IPS\Node\Model|NULL $container Container (e.g. forum), if appropriate
|
||||
* @param bool $fromCreateMenu false to deactivate the minimize feature
|
||||
* @return array
|
||||
*/
|
||||
public static function formElements( $item=NULL, \IPS\Node\Model $container=NULL , $fromCreateMenu=FALSE)
|
||||
{
|
||||
$formElements = parent::formElements( $item, $container );
|
||||
|
||||
unset( $formElements['title'] );
|
||||
|
||||
if ( $fromCreateMenu )
|
||||
{
|
||||
$minimize = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$member = isset( \IPS\Request::i()->id ) ? \IPS\Member::load( \IPS\Request::i()->id ) : \IPS\Member::loggedIn();
|
||||
|
||||
$minimize = ( $member->member_id != \IPS\Member::loggedIn()->member_id ) ?
|
||||
\IPS\Member::loggedIn()->language()->addToStack( static::$formLangPrefix . '_update_placeholder_other', FALSE, array( 'sprintf' => array( $member->name ) ) ) :
|
||||
static::$formLangPrefix . '_update_placeholder';
|
||||
}
|
||||
|
||||
$formElements['status_content'] = new \IPS\Helpers\Form\Editor( static::$formLangPrefix . 'content' . ( $fromCreateMenu ? '_ajax' : '' ), ( $item ) ? $item->content : NULL, TRUE, array(
|
||||
'app' => static::$application,
|
||||
'key' => 'Members',
|
||||
'autoSaveKey' => 'status',
|
||||
'minimize' => $minimize,
|
||||
), '\IPS\Helpers\Form::floodCheck' );
|
||||
|
||||
return $formElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from form
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @param \IPS\Node\Model|NULL $container Container (e.g. forum), if appropriate
|
||||
* @param bool $sendNotification TRUE to automatically send new content notifications (useful for items that may be uploaded in bulk)
|
||||
* @return \IPS\Content\Item
|
||||
*/
|
||||
public static function createFromForm( $values, \IPS\Node\Model $container = NULL, $sendNotification = TRUE )
|
||||
{
|
||||
/* Create */
|
||||
$status = parent::createFromForm( $values, $container, $sendNotification );
|
||||
\IPS\File::claimAttachments( 'status', $status->id );
|
||||
|
||||
/* Sync */
|
||||
if ( $status->member_id == $status->author_id and $syncSettings = json_decode( \IPS\Member::loggedIn()->profilesync, TRUE ) )
|
||||
{
|
||||
foreach ( $syncSettings as $provider => $settings )
|
||||
{
|
||||
if ( isset( $settings['status'] ) and $settings['status'] === 'export' )
|
||||
{
|
||||
$class= 'IPS\core\ProfileSync\\' . ucfirst( $provider );
|
||||
$sync = new $class( \IPS\Member::loggedIn() );
|
||||
if ( method_exists( $sync, 'exportStatus' ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$sync->exportStatus( $status );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process create/edit form
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
public function processForm( $values )
|
||||
{
|
||||
parent::processForm( $values );
|
||||
|
||||
$this->member_id = isset( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : \IPS\Member::loggedIn()->member_id;
|
||||
|
||||
if ( !$this->_new )
|
||||
{
|
||||
$oldContent = $this->content;
|
||||
}
|
||||
$this->content = $values['status_content'];
|
||||
if ( !$this->_new )
|
||||
{
|
||||
$this->sendAfterEditNotifications( $oldContent );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
$member = \IPS\Member::load( $this->member_id );
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=members&controller=profile&id={$member->member_id}&status={$this->id}&type=status", 'front', 'profile', array( $member->members_seo_name ) );
|
||||
|
||||
if ( $action )
|
||||
{
|
||||
if ( $action == 'edit' )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', 'editStatus' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( array( 'do' => $action, 'type' => 'status' ) );
|
||||
}
|
||||
|
||||
if ( $action == 'moderate' AND \IPS\Request::i()->controller == 'feed' )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( '_fromFeed', 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendNotifications()
|
||||
{
|
||||
parent::sendNotifications();
|
||||
|
||||
/* Notify when somebody comments on my profile */
|
||||
if( $this->author()->member_id != $this->member_id )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'profile_comment', $this, array( $this ) );
|
||||
$member = \IPS\Member::load( $this->member_id );
|
||||
$notification->recipients->attach( $member );
|
||||
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
/* Notify when a follower posts a status update */
|
||||
if ( $this->author()->member_id == $this->member_id )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'new_status', $this, array( $this ) );
|
||||
$followers = \IPS\Member::load( $this->member_id )->followers( 3, array( 'immediate' ), $this->mapped('date'), NULL );
|
||||
|
||||
if( is_array( $followers ) )
|
||||
{
|
||||
foreach( $followers AS $follower )
|
||||
{
|
||||
$notification->recipients->attach( \IPS\Member::load( $follower['follow_member_id'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
$notification->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should new items be moderated?
|
||||
*
|
||||
* @param \IPS\Member $member The member posting
|
||||
* @param \IPS\Node\Model $container The container
|
||||
* @return bool
|
||||
*/
|
||||
public static function moderateNewItems( \IPS\Member $member, \IPS\Node\Model $container = NULL )
|
||||
{
|
||||
if ( $member->moderateNewContent() or \IPS\Settings::i()->profile_comment_approval )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return parent::moderateNewItems( $member, $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* Should new comments be moderated?
|
||||
*
|
||||
* @param \IPS\Member $member The member posting
|
||||
* @return bool
|
||||
*/
|
||||
public function moderateNewComments( \IPS\Member $member )
|
||||
{
|
||||
return ( $member->moderateNewContent() or \IPS\Settings::i()->profile_comment_approval );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Profile owner should always be able to delete */
|
||||
if ( $member->member_id == $this->member_id )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return parent::canDelete( $member );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments to display
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function commentsForDisplay()
|
||||
{
|
||||
/* Init */
|
||||
$limit = static::$commentsPerPage;
|
||||
$numberOfComments = $this->commentCount();
|
||||
|
||||
/* If there is more than 3 comments, we want to display the LAST 3 on page 1, the 3 before that on page 2, etc */
|
||||
if ( $numberOfComments >= static::$commentsPerPage )
|
||||
{
|
||||
/* Work out what page we're looking at, but only if we are actually paginating through comments */
|
||||
/* @future we should probably remove the dependancy on \IPS\Request::i()->page here, as the status may be display on a page that isn't necessarily the profile (ex: My Activity) */
|
||||
$page = ( isset( \IPS\Request::i()->page ) AND isset( \IPS\Request::i()->status ) ) ? intval( \IPS\Request::i()->page ) : 1;
|
||||
if( $page < 1 )
|
||||
{
|
||||
$page = 1;
|
||||
}
|
||||
|
||||
/* Start by making the offset to be the $numberOfComments - ( 3 * $page )
|
||||
For example, if there's 5 comments, and we're on page 1, the offset will be 2 */
|
||||
$offset = $numberOfComments - ( static::$commentsPerPage * $page );
|
||||
|
||||
/* However, if we've got to the start, set teh offset to 0 and adjust the limit to get whatever is left */
|
||||
if ( $offset < 0 )
|
||||
{
|
||||
$limit += $offset;
|
||||
$offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there's less than 3 comments, just display those */
|
||||
else
|
||||
{
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
$return = parent::comments( $limit, $offset );
|
||||
|
||||
/* If the limit is 1, comments() returns an object, but we want an array */
|
||||
return ( $limit == 1 ) ? array( $return ) : $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template for content tables
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
{
|
||||
return array( \IPS\Theme::i()->getTemplate( 'profile', 'core' ), 'statusContentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of comments to show per page
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function getCommentsPerPage()
|
||||
{
|
||||
return static::$commentsPerPage;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Warning Reason 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 23 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Warnings;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning Reason Node
|
||||
*/
|
||||
class _Reason extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_members_warn_reasons';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'wr_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'order';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'warn_reasons';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'core',
|
||||
'module' => 'membersettings',
|
||||
'prefix' => 'reasons_',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'core_warn_reason_';
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'wr_name', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "core_warn_reason_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'wr_points', $this->id ? $this->points : 0, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'wr_points_override', $this->id ? $this->points_override : TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'wr_remove', $this->id ? array( $this->remove, $this->remove_unit ) : NULL, FALSE, array(
|
||||
'getHtml' => function( $element )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'members' )->warningTime( $element->name, $element->value );
|
||||
}
|
||||
) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'wr_remove_override', $this->id ? $this->remove_override : 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( isset( $values['wr_remove'] ) )
|
||||
{
|
||||
$values['remove'] = (int) $values['wr_remove'][0];
|
||||
$values['remove_unit'] = $values['wr_remove'][1];
|
||||
unset( $values['wr_remove'] );
|
||||
}
|
||||
|
||||
if( !$this->id )
|
||||
{
|
||||
$values['order'] = 0;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
if( isset( $values['wr_name'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'core', "core_warn_reason_{$this->id}", $values['wr_name'] );
|
||||
unset( $values['wr_name'] );
|
||||
}
|
||||
|
||||
foreach( $values as $k => $v )
|
||||
{
|
||||
if( mb_substr( $k, 0, 3 ) === 'wr_' )
|
||||
{
|
||||
unset( $values[ $k ] );
|
||||
$values[ mb_substr( $k, 3 ) ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Perform actions after saving the form
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return void
|
||||
*/
|
||||
public function postSaveForm( $values )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to add a child node to this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdd()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,723 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Warning 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
|
||||
* @since 23 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\Warnings;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning Model
|
||||
*/
|
||||
class _Warning extends \IPS\Content\Item
|
||||
{
|
||||
/* !\IPS\Patterns\ActiveRecord */
|
||||
|
||||
/**
|
||||
* @brief Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_members_warn_logs';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'wl_';
|
||||
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'warning';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load record based on a URL
|
||||
*
|
||||
* @param \IPS\Http\Url $url URL to load from
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public static function loadFromUrl( \IPS\Http\Url $url )
|
||||
{
|
||||
return static::load( $url->queryString['w'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function undo()
|
||||
{
|
||||
$member = \IPS\Member::load( $this->member );
|
||||
|
||||
/* Take off the points */
|
||||
if ( ( !$this->expire_date or $this->expire_date == -1 ) or $this->expire_date > time() )
|
||||
{
|
||||
$member->warn_level -= $this->points;
|
||||
if ( $member->warn_level < 0 )
|
||||
{
|
||||
$member->warn_level = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Undo the actions */
|
||||
foreach ( array( 'mq' => 'mod_posts', 'rpa' => 'restrict_post', 'suspend' => 'temp_ban' ) as $w => $m )
|
||||
{
|
||||
if ( $this->$w and ( $this->$w < time() or $this->$w == -1 ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$latest = \IPS\Db::i()->select( '*', 'core_members_warn_logs', array( "wl_member=? AND wl_{$w}<>0 AND wl_id !=?", $member->member_id, $this->id ), 'wl_date DESC' )->first();
|
||||
$member->$m = $latest[ 'wl_' . $w ];
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$member->$m = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save */
|
||||
$member->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete warning
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
/* Unaknowledged Warnings? */
|
||||
$member = \IPS\Member::load( $this->member );
|
||||
|
||||
if ( \IPS\Settings::i()->warnings_acknowledge )
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members_warn_logs', array( "wl_member=? AND wl_id<>? AND wl_acknowledged=0", $member->member_id, $this->id ) )->first();
|
||||
$member->members_bitoptions['unacknowledged_warnings'] = (bool) $count;
|
||||
}
|
||||
else
|
||||
{
|
||||
$member->members_bitoptions['unacknowledged_warnings'] = FALSE;
|
||||
}
|
||||
$member->save();
|
||||
|
||||
/* Delete */
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unclaim attachments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function unclaimAttachments()
|
||||
{
|
||||
\IPS\File::unclaimAttachments( 'core_Modcp', $this->id, NULL, 'member' );
|
||||
\IPS\File::unclaimAttachments( 'core_Modcp', $this->id, NULL, 'mod' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Content for Warning
|
||||
*
|
||||
* @return \IPS\Content|NULL
|
||||
*/
|
||||
public function content()
|
||||
{
|
||||
if ( $this->content_app and $this->content_module )
|
||||
{
|
||||
if ( $this->content_app === 'core' and $this->content_module === 'messaging' )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( $this->content_id2 )
|
||||
{
|
||||
return \IPS\core\Messenger\Message::load( $this->content_id2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\core\Messenger\Conversation::load( $this->content_id2 );
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$extensions = \IPS\Application::load( $this->content_app )->extensions( 'core', 'ContentRouter' );
|
||||
foreach ( $extensions as $ext )
|
||||
{
|
||||
foreach ( $ext->classes as $class )
|
||||
{
|
||||
if ( $class::$module == $this->content_module )
|
||||
{
|
||||
try
|
||||
{
|
||||
return $class::load( $this->content_id1 );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
elseif ( $commentClass = $class::$commentClass and $class::$module . '-comment' == $this->content_module )
|
||||
{
|
||||
try
|
||||
{
|
||||
return $commentClass::load( $this->content_id2 );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if ( isset( $class::$reviewClass ) AND $reviewClass = $class::$reviewClass and $class::$module . '-review' == $this->content_module )
|
||||
{
|
||||
try
|
||||
{
|
||||
return $reviewClass::load( $this->content_id2 );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* !\IPS\Content\Item */
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'core';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'date' => 'date',
|
||||
'author' => 'moderator',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Language prefix for forms
|
||||
*/
|
||||
public static $formLangPrefix = 'warn_';
|
||||
|
||||
/**
|
||||
* Get elements for add/edit form
|
||||
*
|
||||
* @param \IPS\Content\Item|NULL $item The current item if editing or NULL if creating
|
||||
* @param int $container Container (e.g. forum) ID, if appropriate
|
||||
* @return array
|
||||
*/
|
||||
public static function formElements( $item=NULL, \IPS\Node\Model $container=NULL )
|
||||
{
|
||||
/* Get the reasons */
|
||||
$reasons = array();
|
||||
$roots = \IPS\core\Warnings\Reason::roots();
|
||||
foreach ( $roots as $reason )
|
||||
{
|
||||
$reasons[ $reason->_id ] = $reason->_title;
|
||||
}
|
||||
if ( \IPS\Member::loggedIn()->modPermission('warnings_enable_other') )
|
||||
{
|
||||
$reasons['other'] = 'core_warn_reason_other';
|
||||
}
|
||||
|
||||
/* Build the form */
|
||||
$elements[] = new \IPS\Helpers\Form\Select( 'warn_reason', NULL, TRUE, array( 'options' => $reasons ) );
|
||||
$elements[] = new \IPS\Helpers\Form\Number( 'warn_points', 0, FALSE, array( 'valueToggles' => array( 'warn_remove' ), 'disabled' => ( !$roots[1]->points_override ) ) );
|
||||
$elements[] = new \IPS\Helpers\Form\Date( 'warn_remove', -1, FALSE, array( 'time' => TRUE, 'unlimited' => -1, 'unlimitedLang' => 'never' ), NULL, NULL, NULL, 'warn_remove' );
|
||||
$elements[] = new \IPS\Helpers\Form\Editor( 'warn_member_note', NULL, FALSE, array( 'app' => 'core', 'key' => 'Modcp', 'autoSaveKey' => "warn-member-" . \IPS\Request::i()->id, 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'member' ) ), 'minimize' => 'warn_member_note_placeholder' ) );
|
||||
$elements[] = new \IPS\Helpers\Form\Editor( 'warn_mod_note', NULL, FALSE, array( 'app' => 'core', 'key' => 'Modcp', 'autoSaveKey' => "warn-mod-" . \IPS\Request::i()->id, 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'mod' ) ), 'minimize' => 'warn_mod_note_placeholder' ) );
|
||||
$elements[] = new \IPS\Helpers\Form\CheckboxSet( 'warn_punishment', array(), FALSE, array(
|
||||
'options' => array( 'mq' => 'warn_mq', 'rpa' => 'warn_rpa', 'suspend' => 'warn_suspend' ),
|
||||
'toggles' => array( 'mq' => array( 'form_warn_mq' ), 'rpa' => array( 'form_warn_rpa' ), 'suspend' => array( 'form_warn_suspend' ) ),
|
||||
) );
|
||||
$elements[] = new \IPS\Helpers\Form\Date( 'warn_mq', -1, FALSE, array( 'time' => TRUE, 'unlimited' => -1, 'unlimitedLang' => 'indefinitely' ), function( $val )
|
||||
{
|
||||
if( $val )
|
||||
{
|
||||
$now = new \IPS\DateTime;
|
||||
|
||||
if( $val !== -1 and $val->getTimestamp() < $now->getTimestamp() )
|
||||
{
|
||||
throw new \DomainException( 'error_date_not_future' );
|
||||
}
|
||||
}
|
||||
|
||||
}, \IPS\Member::loggedIn()->language()->addToStack('until'), NULL, NULL, 'warn_mq' );
|
||||
|
||||
$elements[] = new \IPS\Helpers\Form\Date( 'warn_rpa', -1, FALSE, array( 'time' => TRUE, 'unlimited' => -1, 'unlimitedLang' => 'indefinitely' ), function( $val )
|
||||
{
|
||||
if( $val )
|
||||
{
|
||||
$now = new \IPS\DateTime;
|
||||
|
||||
if( $val !== -1 and $val->getTimestamp() < $now->getTimestamp() )
|
||||
{
|
||||
throw new \DomainException( 'error_date_not_future' );
|
||||
}
|
||||
}
|
||||
|
||||
}, \IPS\Member::loggedIn()->language()->addToStack('until'), NULL, NULL, 'warn_rpa' );
|
||||
|
||||
$elements[] = new \IPS\Helpers\Form\Date( 'warn_suspend', -1, FALSE, array( 'time' => TRUE, 'unlimited' => -1, 'unlimitedLang' => 'indefinitely' ), function( $val )
|
||||
{
|
||||
if( $val )
|
||||
{
|
||||
$now = new \IPS\DateTime;
|
||||
|
||||
if( $val !== -1 and $val->getTimestamp() < $now->getTimestamp() )
|
||||
{
|
||||
throw new \DomainException( 'error_date_not_future' );
|
||||
}
|
||||
}
|
||||
|
||||
}, \IPS\Member::loggedIn()->language()->addToStack('until'), NULL, NULL, 'warn_suspend' );
|
||||
|
||||
/* Return */
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process created object BEFORE the object has been created
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
protected function processBeforeCreate( $values )
|
||||
{
|
||||
$this->member = \IPS\Request::i()->member;
|
||||
|
||||
foreach( $values['warn_punishment'] AS $p )
|
||||
{
|
||||
if ( $values['warn_' . $p ] === NULL )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_warning_action_time', '1C150/2', 403, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/* Work out points and expiry date */
|
||||
$this->expire_date = NULL;
|
||||
$this->points = $values['warn_points'];
|
||||
if ( is_numeric( $values['warn_reason'] ) )
|
||||
{
|
||||
$reason = \IPS\core\Warnings\Reason::load( $values['warn_reason'] );
|
||||
if ( !$reason->points_override )
|
||||
{
|
||||
$this->points = $reason->points;
|
||||
}
|
||||
if ( !$reason->remove_override )
|
||||
{
|
||||
if ( $reason->remove_override == -1 )
|
||||
{
|
||||
$this->points = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$expire = \IPS\DateTime::create();
|
||||
if ( $reason->remove_unit == 'h' )
|
||||
{
|
||||
$expire->add( new \DateInterval( "PT{$reason->remove}H" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$expire->add( new \DateInterval( "P{$reason->remove}D" ) );
|
||||
}
|
||||
$this->expire_date = $expire->getTimestamp();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $values['warn_remove'] instanceof \IPS\DateTime )
|
||||
{
|
||||
$this->expire_date = $values['warn_remove']->getTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->expire_date = $values['warn_remove'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->reason = $values['warn_reason'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->reason = 0;
|
||||
|
||||
if ( $values['warn_remove'] instanceof \IPS\DateTime )
|
||||
{
|
||||
$this->expire_date = $values['warn_remove']->getTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->expire_date = $values['warn_remove'];
|
||||
}
|
||||
}
|
||||
if ( !$this->points )
|
||||
{
|
||||
$this->expire_date = -1;
|
||||
}
|
||||
|
||||
/* If we can't override the action, change it back */
|
||||
try
|
||||
{
|
||||
$action = \IPS\Db::i()->select( '*', 'core_members_warn_actions', array( 'wa_points<=?', ( \IPS\Member::load( $this->member )->warn_level + $this->points ) ), 'wa_points DESC', 1 )->first();
|
||||
if ( !$action['wa_override'] )
|
||||
{
|
||||
foreach ( array( 'mq', 'rpa', 'suspend' ) as $k )
|
||||
{
|
||||
if ( $action[ 'wa_' . $k ] == -1 )
|
||||
{
|
||||
$values[ 'warn_' . $k ] = -1;
|
||||
}
|
||||
elseif ( $action[ 'wa_' . $k ] )
|
||||
{
|
||||
$values[ 'warn_' . $k ] = \IPS\DateTime::create()->add( new \DateInterval( $action[ 'wa_' . $k . '_unit' ] == 'h' ? "PT{$action[ 'wa_' . $k ]}H" : "P{$action[ 'wa_' . $k ]}D" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[ 'warn_' . $k ] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
if ( !\IPS\Member::loggedIn()->modPermission('warning_custom_noaction') )
|
||||
{
|
||||
foreach ( array( 'mq', 'rpa', 'suspend' ) as $k )
|
||||
{
|
||||
$values[ 'warn_' . $k ] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set notes */
|
||||
$this->note_member = $values['warn_member_note'];
|
||||
$this->note_mods = $values['warn_mod_note'];
|
||||
|
||||
/* Set acknowledged */
|
||||
$this->acknowledged = !\IPS\Settings::i()->warnings_acknowledge;
|
||||
|
||||
/* Construct referrer */
|
||||
$ref = \IPS\Request::i()->ref ? json_decode( base64_decode( \IPS\Request::i()->ref ), TRUE ) : NULL;
|
||||
$this->content_app = isset( $ref['app'] ) ? $ref['app'] : NULL;
|
||||
$this->content_module = isset( $ref['module'] ) ? $ref['module'] : NULL;
|
||||
$this->content_id1 = isset( $ref['id_1'] ) ? $ref['id_1'] : NULL;
|
||||
$this->content_id2 = isset( $ref['id_2'] ) ? $ref['id_2'] : NULL;
|
||||
|
||||
/* Work out the timeframes for the penalities */
|
||||
if ( count( $values['warn_punishment'] ) )
|
||||
{
|
||||
foreach ( array( 'mq', 'rpa', 'suspend' ) as $f )
|
||||
{
|
||||
if ( !in_array( $f, $values['warn_punishment'] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $values[ 'warn_' . $f ] instanceof \IPS\DateTime )
|
||||
{
|
||||
$difference = \IPS\DateTime::create()->diff( $values[ 'warn_' . $f ] );
|
||||
$period = 'P';
|
||||
foreach ( array( 'y' => 'Y', 'm' => 'M', 'd' => 'D' ) as $k => $v )
|
||||
{
|
||||
if ( $difference->$k )
|
||||
{
|
||||
$period .= $difference->$k . $v;
|
||||
}
|
||||
}
|
||||
$time = '';
|
||||
foreach ( array( 'h' => 'H', 'i' => 'M', 's' => 'S' ) as $k => $v )
|
||||
{
|
||||
if ( $difference->$k )
|
||||
{
|
||||
$time .= $difference->$k . $v;
|
||||
}
|
||||
}
|
||||
if ( $time )
|
||||
{
|
||||
$period .= 'T' . $time;
|
||||
}
|
||||
|
||||
$this->$f = $period;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->$f = $values[ 'warn_' . $f ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::processBeforeCreate( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process created object AFTER the object has been created
|
||||
*
|
||||
* @param \IPS\Content\Comment|NULL $comment The first comment
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
protected function processAfterCreate( $comment, $values )
|
||||
{
|
||||
\IPS\File::claimAttachments( "warn-member-{$this->member}", $this->id, NULL, 'member' );
|
||||
\IPS\File::claimAttachments( "warn-mod-{$this->member}", $this->id, NULL, 'mod' );
|
||||
|
||||
$member = \IPS\Member::load( $this->member );
|
||||
if ( $this->points )
|
||||
{
|
||||
$member->warn_level += $this->points;
|
||||
}
|
||||
foreach ( array( 'mq' => 'mod_posts', 'rpa' => 'restrict_post', 'suspend' => 'temp_ban' ) as $k => $v )
|
||||
{
|
||||
if ( $this->$k )
|
||||
{
|
||||
if ( $this->$k != -1 )
|
||||
{
|
||||
$member->$v = \IPS\DateTime::create()->add( new \DateInterval( $this->$k ) )->getTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$member->$v = $this->$k;
|
||||
}
|
||||
}
|
||||
}
|
||||
$member->members_bitoptions['unacknowledged_warnings'] = (bool) \IPS\Settings::i()->warnings_acknowledge;
|
||||
$member->save();
|
||||
|
||||
parent::processAfterCreate( $comment, $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendNotifications()
|
||||
{
|
||||
$moderators = array( 'm' => array(), 'g' => array() );
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
|
||||
{
|
||||
$canView = FALSE;
|
||||
|
||||
if ( $mod['perms'] == '*' )
|
||||
{
|
||||
$canView = TRUE;
|
||||
}
|
||||
|
||||
if ( $canView === FALSE )
|
||||
{
|
||||
$perms = json_decode( $mod['perms'], TRUE );
|
||||
|
||||
if ( isset( $perms['mod_see_warn'] ) AND $perms['mod_see_warn'] === TRUE )
|
||||
{
|
||||
$canView = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $canView === TRUE )
|
||||
{
|
||||
$moderators[ $mod['type'] ][] = $mod['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'warning_mods', $this, array( $this ) );
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', '(' . ( count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) . ' ) AND member_id!=' . \IPS\Member::loggedIn()->member_id ) as $member )
|
||||
{
|
||||
$notification->recipients->attach( \IPS\Member::constructFromData( $member ) );
|
||||
}
|
||||
|
||||
$notification->send();
|
||||
|
||||
$email = \IPS\Email::buildFromTemplate( 'core', 'warning', array( $this ) )->send( \IPS\Member::load( $this->member ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
*/
|
||||
protected $_url = array();
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$_key = md5( $action );
|
||||
|
||||
if( !isset( $this->_url[ $_key ] ) )
|
||||
{
|
||||
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=core&module=system&controller=warnings&id={$this->member}&w={$this->id}", 'front', 'warn_view', \IPS\Member::load( $this->member )->members_seo_name );
|
||||
|
||||
if ( $action )
|
||||
{
|
||||
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_url[ $_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mapped value
|
||||
*
|
||||
* @param string $key date,content,ip_address,first
|
||||
* @return mixed
|
||||
*/
|
||||
public function mapped( $key )
|
||||
{
|
||||
if ( $key === 'title' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( "core_warn_reason_{$this->reason}" );
|
||||
}
|
||||
return parent::mapped( $key );
|
||||
}
|
||||
|
||||
/* !Permissions */
|
||||
|
||||
/**
|
||||
* Can give warning?
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param \IPS\Node\Model|NULL $container Container (e.g. forum), if appropriate
|
||||
* @param bool $showError If TRUE, rather than returning a boolean value, will display an error
|
||||
* @return bool
|
||||
* @note If we can't see warnings, we can't issue them either
|
||||
*/
|
||||
public static function canCreate( \IPS\Member $member, \IPS\Node\Model $container=NULL, $showError=FALSE )
|
||||
{
|
||||
$return = $member->modPermission('mod_can_warn') && $member->modPermission('mod_see_warn');
|
||||
if ( !$return and $showError )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2C150/1', 403, '' );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a member have permission to access?
|
||||
*
|
||||
* @param \IPS\Member $member The member to check for
|
||||
* @return bool
|
||||
*/
|
||||
public function canView( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return $member->modPermission('mod_see_warn') or $this->member === $member->member_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a member have permission to view the details of the warning?
|
||||
*
|
||||
* @param \IPS\Member $member The member to check for
|
||||
* @return bool
|
||||
*/
|
||||
public function canViewDetails( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
if ( $member->modPermission('mod_see_warn') )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->warn_show_own and $this->member === $member->member_id )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can acknowledge?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public function canAcknowledge( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return $this->member === $member->member_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return $member->modPermission('mod_revoke_warn');
|
||||
}
|
||||
|
||||
/* !\IPS\Helpers\Table */
|
||||
|
||||
public $tableHoverUrl = TRUE;
|
||||
|
||||
/**
|
||||
* Icon for table view
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function tableIcon()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp', 'core', 'front' )->warningRowPoints( $this->points );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get description for table view
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tableDescription()
|
||||
{
|
||||
return $this->note_mods;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
Whitespace-only changes.
Reference in new issue
Block a user