Version 4.7.23
This commit is contained in:
1 parent
7124a02564
commit
25ddeb65d6
1791 files changed
+76990
-44452
No files matched your search
@@ -102,7 +102,7 @@ class _ContentPromotion extends \IPS\core\Achievements\Actions\AbstractContentAc
|
||||
|
||||
/**
|
||||
* Get identifier to prevent the member being awarded points for the same action twice
|
||||
* Must be unique within within of this domain, must not exceed 32 chars.
|
||||
* Must be unique within of this domain, must not exceed 32 chars.
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
@@ -333,7 +333,7 @@ class _ContentPromotion extends \IPS\core\Achievements\Actions\AbstractContentAc
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
$subWhere[] = [ \IPS\Db::i()->in( $itemClass::$databaseColumnId, $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'meta_item_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
@@ -371,7 +371,7 @@ class _ContentPromotion extends \IPS\core\Achievements\Actions\AbstractContentAc
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
$subWhere[] = [ \IPS\Db::i()->in( $itemClass::$databaseColumnId, $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'feature_content_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
@@ -409,7 +409,7 @@ class _ContentPromotion extends \IPS\core\Achievements\Actions\AbstractContentAc
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
$subWhere[] = [ \IPS\Db::i()->in( $itemClass::$databaseColumnId, $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'promote_class_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
|
||||
@@ -20,7 +20,14 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _Reaction extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
{
|
||||
protected static $includeItems = FALSE;
|
||||
|
||||
/**
|
||||
* @var bool Exclude content items that require a first comment
|
||||
*/
|
||||
protected static $excludeItemsWithRequiredComment = TRUE;
|
||||
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
|
||||
@@ -146,7 +146,7 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
}
|
||||
|
||||
/* Cache Set Up */
|
||||
if ( \IPS\CACHE_METHOD AND \IPS\CACHE_METHOD != 'None' AND \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None )
|
||||
if ( !\IPS\CIC AND \IPS\CACHE_METHOD AND \IPS\CACHE_METHOD != 'None' AND \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None )
|
||||
{
|
||||
\IPS\core\AdminNotification::send( 'core', 'ConfigurationError', 'cacheBroken', FALSE );
|
||||
}
|
||||
@@ -265,8 +265,7 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
$member->hasAcpRestriction( 'core', 'settings', 'general_manage' ) or
|
||||
$member->hasAcpRestriction( 'core', 'settings', 'advanced_manage' ) or
|
||||
$member->hasAcpRestriction( 'core', 'settings', 'advanced_manage' ) or
|
||||
$member->hasAcpRestriction( 'core', 'overview', 'system_notifications' ) or
|
||||
$member->hasAcpRestriction( 'core', 'marketplace', 'marketplace_manage' ) or
|
||||
$member->hasAcpRestriction( 'core', 'overview', 'system_notifications' ) or
|
||||
$member->hasAcpRestriction( 'core', 'settings', 'login_access' )
|
||||
);
|
||||
}
|
||||
@@ -327,10 +326,6 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return $member->hasAcpRestriction( 'core', 'overview', 'system_notifications' );
|
||||
}
|
||||
elseif ( $this->extra === 'marketplaceSetup' )
|
||||
{
|
||||
return $member->hasAcpRestriction( 'core', 'marketplace', 'marketplace_manage' );
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return $member->hasAcpRestriction( 'core', 'settings', 'login_access' );
|
||||
@@ -392,14 +387,14 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('dashboard_cic_email_quota');
|
||||
}
|
||||
elseif ( $this->extra === 'marketplaceSetup' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('marketplace_onboard_title');
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('username_login_enabled');
|
||||
}
|
||||
elseif( $this->extra === 'groupPromotionGroup' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('grouppromotion_error_group');
|
||||
}
|
||||
else
|
||||
{
|
||||
return htmlentities( $this->extra, ENT_DISALLOWED, 'UTF-8', FALSE );
|
||||
@@ -461,10 +456,6 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('dashboard_cic_email_quota_subtitle');
|
||||
}
|
||||
elseif ( $this->extra === 'marketplaceSetup' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('marketplace_onboard_notification');
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('username_login_enabled_desc');
|
||||
@@ -559,14 +550,14 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('dashboard_cic_email_quota_desc');
|
||||
}
|
||||
elseif ( $this->extra === 'marketplaceSetup' )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->marketplaceSetup();
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->usernameLoginEnabled();
|
||||
}
|
||||
elseif( $this->extra === 'groupPromotionGroup' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('grouppromotion_error_group_desc');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,7 +626,7 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
return static::STYLE_ERROR;
|
||||
}
|
||||
|
||||
if ( mb_substr( $this->extra, 0, 12 ) === 'supportAdmin' or $this->extra === 'origTables' or $this->extra === 'marketplaceSetup' )
|
||||
if ( mb_substr( $this->extra, 0, 12 ) === 'supportAdmin' or $this->extra === 'origTables' )
|
||||
{
|
||||
return static::STYLE_INFORMATION;
|
||||
}
|
||||
@@ -660,10 +651,6 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::load( \intval( mb_substr( $this->extra, 13 ) ) )->acpUrl();
|
||||
}
|
||||
elseif ( $this->extra === 'marketplaceSetup' )
|
||||
{
|
||||
return \IPS\Http\Url::internal( 'app=core&module=marketplace&controller=onboard&_new=1', 'admin' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::link();
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief ACP Notification Extension
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
|
||||
* @since 16 Jan 2025
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AdminNotifications;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ACP Notification Extension
|
||||
*/
|
||||
class _VersionFive extends \IPS\core\AdminNotification
|
||||
{
|
||||
/**
|
||||
* @brief Identifier for what to group this notification type with on the settings form
|
||||
*/
|
||||
public static $group = 'important';
|
||||
|
||||
/**
|
||||
* @brief Priority 1-5 (1 being highest) for this group compared to others
|
||||
*/
|
||||
public static $groupPriority = 3;
|
||||
|
||||
/**
|
||||
* @brief Priority 1-5 (1 being highest) for this notification type compared to others in the same group
|
||||
*/
|
||||
public static $itemPriority = 3;
|
||||
|
||||
/**
|
||||
* Title for settings
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function settingsTitle()
|
||||
{
|
||||
return 'acp_notification_VersionFive';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a member access this type of notification?
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @return bool
|
||||
*/
|
||||
public static function permissionCheck( \IPS\Member $member ): bool
|
||||
{
|
||||
if( \IPS\CIC AND \IPS\IPS::isManaged() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this type of notification ever optional (controls if it will be selectable as "viewable" in settings)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function mayBeOptional()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this type of notification might recur (controls what options will be available for the email setting)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function mayRecur(): bool
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification Title (full HTML, must be escaped where necessary)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('v5_notification_title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification Body (full HTML, must be escaped where necessary)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function body(): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('v5_notification_body' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Severity
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function severity(): string
|
||||
{
|
||||
return static::SEVERITY_HIGH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismissible?
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dismissible(): string
|
||||
{
|
||||
return static::DISMISSIBLE_UNTIL_RECUR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function style(): string
|
||||
{
|
||||
return static::STYLE_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick link from popup menu
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function link(): \IPS\Http\Url
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=core&module=support&controller=v5" );
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,8 @@ class _Ckeditor
|
||||
\exec( "rm -R \"{$path}/applications/core/interface/ckeditor/ckeditor/samples\"" );
|
||||
}
|
||||
|
||||
\file_put_contents( "{$path}/applications/core/interface/ckeditor/ckeditor/legal.txt", "This software is bound by the Mozilla Public License Version 1.1\n(https://www.mozilla.org/en-US/MPL/1.1/)" );
|
||||
|
||||
if( \in_array( 'Release process completed:', $output ) )
|
||||
{
|
||||
$this->finish();
|
||||
|
||||
@@ -56,10 +56,13 @@ class _Codemirror
|
||||
}
|
||||
|
||||
/* Minify and write */
|
||||
require_once( \IPS\ROOT_PATH . '/system/3rd_party/JShrink/Minifier.php' );
|
||||
require_once( \IPS\ROOT_PATH . '/system/3rd_party/JsMinify/Minifier.php' );
|
||||
require_once( \IPS\ROOT_PATH . '/system/3rd_party/JsMinify/MinifierError.php' );
|
||||
require_once( \IPS\ROOT_PATH . '/system/3rd_party/JsMinify/MinifierExpressions.php' );
|
||||
|
||||
\file_put_contents( \IPS\ROOT_PATH . '/applications/core/interface/codemirror/codemirror.css', $css );
|
||||
$css = \IPS\Theme::minifyCss( $css );
|
||||
$js = \JShrink\Minifier::minify( $js, array( 'flaggedComments' => false ) );
|
||||
$js = \Garfix\JsMinify\Minifier::minify( $js, array( 'flaggedComments' => false ) );
|
||||
\file_put_contents( \IPS\ROOT_PATH . '/applications/core/interface/codemirror/codemirror.js', $js );
|
||||
|
||||
/* Finish */
|
||||
|
||||
@@ -40,7 +40,7 @@ class _FacebookPixel
|
||||
/**
|
||||
* @brief Icon data
|
||||
*/
|
||||
public $icon = "facebook.png";
|
||||
public $icon = "meta.png";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
||||
@@ -40,7 +40,7 @@ class _GoogleMaps
|
||||
/**
|
||||
* @brief Icon data
|
||||
*/
|
||||
public $icon = "google_maps.jpeg";
|
||||
public $icon = "google_maps.png";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Community Enhancements
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
|
||||
* @since 21 Aug 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\CommunityEnhancements;
|
||||
|
||||
use IPS\core\Hive;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Login;
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
use IPS\Settings;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Community Enhancement
|
||||
*/
|
||||
class _Hive
|
||||
{
|
||||
/**
|
||||
* @brief Enhancement is enabled?
|
||||
*/
|
||||
public $enabled = FALSE;
|
||||
|
||||
/**
|
||||
* @brief IPS-provided enhancement?
|
||||
*/
|
||||
public $ips = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Enhancement has configuration options?
|
||||
*/
|
||||
public $hasOptions = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Icon data
|
||||
*/
|
||||
public $icon = "communityhive.svg";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = ( !empty( Settings::i()->hive_enabled ) AND !empty( Settings::i()->hive_key ) AND !empty( Settings::i()->hive_site_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$hostname = \defined( 'COMMUNITYHIVE_URL' ) ? COMMUNITYHIVE_URL : 'https://communityhive.com';
|
||||
$output = '';
|
||||
|
||||
if( empty( Settings::i()->hive_key ) )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form('hive', 'enable' );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'hive_community_name', Settings::i()->board_name, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Email( 'hive_email_address', Member::loggedIn()->email, TRUE ) );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$randomKey = Login::generateRandomString( 40 );
|
||||
$request = Url::external( $hostname . '/api/v1/activate')
|
||||
->request()
|
||||
->put( json_encode([
|
||||
'site_name' => $values['hive_community_name'],
|
||||
'site_url' => Settings::i()->base_url,
|
||||
'site_api_url' => (string) Url::internal('app=core&module=hive&controller=content', 'front', 'hive_content'),
|
||||
'site_key' => $randomKey,
|
||||
'site_email' => $values['hive_email_address'],
|
||||
'site_software' => 'invisioncommunity',
|
||||
'hive_system_version' => \IPS\Application::load('core')->version
|
||||
]) );
|
||||
|
||||
if( (int) $request->httpResponseCode !== 200 )
|
||||
{
|
||||
throw new \LogicException( $request->decodeJson()['error'] ?? 'There was an issue connecting to Community Hive.' );
|
||||
}
|
||||
|
||||
$response = $request->decodeJson();
|
||||
|
||||
Settings::i()->changeValues([
|
||||
'hive_key' => $response['hive_key'],
|
||||
'hive_site_id' => $response['hive_site_id'],
|
||||
'hive_site_key' => $randomKey,
|
||||
'hive_enabled' => TRUE
|
||||
]);
|
||||
|
||||
/* Subscribe site manager */
|
||||
$response = Hive::api( 'subscribe', [
|
||||
'site_member_id' => Member::loggedIn()->member_id,
|
||||
'group_hash' => Hive::groupHash( Member::loggedin() ),
|
||||
'member_email' => $values['hive_email_address'],
|
||||
]);
|
||||
|
||||
/* Save subscribe */
|
||||
try
|
||||
{
|
||||
Db::i()->insert( 'core_hive_subscribers', [ 'member_id' => Member::loggedIn()->member_id, 'subscribe_date' => time() ] );
|
||||
}
|
||||
catch( Db\Exception $e ) {}
|
||||
|
||||
$redirectUrl = Url::external( $response['redirect_url'] );
|
||||
$output = \IPS\Theme::i()->getTemplate( 'hive', 'core', 'admin' )->wrapper( 'activated', null, $redirectUrl );
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
$form->error = $e->getMessage();
|
||||
$output = \IPS\Theme::i()->getTemplate( 'hive', 'core', 'admin' )->wrapper( 'activation', $form );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$output = \IPS\Theme::i()->getTemplate( 'hive', 'core', 'admin' )->wrapper( 'activation', $form );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$form = new \IPS\Helpers\Form('hive', 'save' );
|
||||
|
||||
/* Work out all the different classes */
|
||||
$classes = array();
|
||||
|
||||
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
|
||||
{
|
||||
if ( is_subclass_of( $class, 'IPS\Content\Searchable' ) AND isset( $class::$databaseColumnMap['date'] ) )
|
||||
{
|
||||
$classes[ $class ] = $class::$title . '_pl';
|
||||
}
|
||||
}
|
||||
|
||||
$settings = json_decode( Settings::i()->hive_content, TRUE );
|
||||
|
||||
/* Work out all the different classes */
|
||||
$classes = array();
|
||||
$classToggles = array();
|
||||
|
||||
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
|
||||
{
|
||||
if ( is_subclass_of( $class, 'IPS\Content\Searchable' ) AND isset( $class::$databaseColumnMap['date'] ) )
|
||||
{
|
||||
$bits = explode( '\\', $class );
|
||||
if( method_exists( $class, 'database' ) )
|
||||
{
|
||||
$label = $class::database()->_title . ' - ' . Member::loggedIn()->language()->addToStack( $class::$title . '_pl' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$label = Member::loggedIn()->language()->addToStack( '__app_' . $bits[1] ) . ' - ' . Member::loggedIn()->language()->addToStack( $class::$title . '_pl' );
|
||||
}
|
||||
$classes[ $class ] = $label;
|
||||
if ( isset( $class::$containerNodeClass ) )
|
||||
{
|
||||
$classToggles[ $class ][] = 'hive_containers_' . $class::$title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$containers = $settings['content_containers'] ?? [];
|
||||
|
||||
/* Add the fields for them */
|
||||
$default = (!isset( $settings['content_classes'] ) OR $settings['content_classes'] === '*') ? '*' : explode( ',', $settings['content_classes'] );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'hive_content_classes', $default, NULL, array( 'options' => $classes, 'unlimited' => '*', 'unlimitedLang' => 'all', 'impliedUnlimited' => TRUE, 'toggles' => $classToggles ), NULL, NULL, NULL, 'hive_classes' ) );
|
||||
|
||||
/* Nodes */
|
||||
foreach ( $classToggles as $class => $id )
|
||||
{
|
||||
if ( isset( $class::$containerNodeClass ) )
|
||||
{
|
||||
$nodeClass = $class::$containerNodeClass;
|
||||
$value = isset( $containers[ $class ] ) ? implode( ',', $containers[ $class ] ) : 0;
|
||||
|
||||
$field = new \IPS\Helpers\Form\Node( 'hive_containers_' . $class::$title, $value, FALSE, array( 'class' => $nodeClass, 'clubs' => TRUE, 'multiple' => TRUE, 'zeroVal' => 'all', 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE, 'subnodes' => FALSE ), NULL, NULL, NULL, 'hive_containers_' . $class::$title );
|
||||
|
||||
if( method_exists( $class, 'database' ) )
|
||||
{
|
||||
$field->label = $class::database()->_title . ' - ' . Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle );
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->label = Member::loggedIn()->language()->addToStack( $class::$title . '_pl' ) . ' - ' . Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle );
|
||||
}
|
||||
$form->add( $field );
|
||||
}
|
||||
}
|
||||
|
||||
if( $values = $form->values() )
|
||||
{
|
||||
if ( isset( $values['hive_content_classes'] ) )
|
||||
{
|
||||
$containers = NULL;
|
||||
foreach ( ( $values['hive_content_classes'] == '*' ? array_keys( $classes ) : $values['hive_content_classes'] ) as $class )
|
||||
{
|
||||
if ( isset( $values[ 'hive_containers_' . $class::$title ] ) and $values[ 'hive_containers_' . $class::$title ] )
|
||||
{
|
||||
$containers[ $class ] = array_keys( $values[ 'hive_containers_' . $class::$title ] );
|
||||
}
|
||||
}
|
||||
|
||||
$settings['content_containers'] = $containers;
|
||||
}
|
||||
|
||||
$settings['content_classes'] = \is_array( $values['hive_content_classes'] ) ? implode( ',', $values['hive_content_classes'] ) : $values['hive_content_classes'];
|
||||
Settings::i()->changeValues([ 'hive_content' => json_encode( $settings ) ]);
|
||||
Output::i()->inlineMessage = Member::loggedIn()->language()->addToStack('saved');
|
||||
}
|
||||
|
||||
$output = \IPS\Theme::i()->getTemplate( 'hive', 'core', 'admin' )->wrapper( 'config', $form );
|
||||
}
|
||||
|
||||
Output::i()->sidebar['actions'] = array(
|
||||
'help' => array(
|
||||
'title' => 'help',
|
||||
'icon' => 'question-circle',
|
||||
'link' => Url::external( $hostname ),
|
||||
'target' => '_blank'
|
||||
),
|
||||
);
|
||||
|
||||
Output::i()->output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable
|
||||
*
|
||||
* @param $enabled bool Enable/Disable
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function toggle( $enabled )
|
||||
{
|
||||
Settings::i()->changeValues([ 'hive_enabled' => (bool) $enabled ]);
|
||||
|
||||
if( empty( Settings::i()->hive_key ) OR empty( Settings::i()->hive_site_id ) )
|
||||
{
|
||||
throw new \LogicException( 'error' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function testSettings()
|
||||
{
|
||||
if ( FALSE )
|
||||
{
|
||||
throw new \LogicException( 'error' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @brief Integrations: Postmark
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 19 November 2024
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\CommunityEnhancements;
|
||||
|
||||
use IPS\Email\Outgoing\Postmark;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Password;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
use IPS\Session;
|
||||
use IPS\Settings;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrations: Postmark
|
||||
*/
|
||||
class _Postmark
|
||||
{
|
||||
/**
|
||||
* @brief IPS-provided enhancement?
|
||||
*/
|
||||
public $ips = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Enhancement is enabled?
|
||||
*/
|
||||
public $enabled = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Enhancement has configuration options?
|
||||
*/
|
||||
public $hasOptions = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Icon data
|
||||
*/
|
||||
public $icon = "postmark.png";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = !empty( Settings::i()->postmark_server_api_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$form = new Form;
|
||||
$form->addHeader('postmark_settings');
|
||||
$form->add( new Password( 'postmark_server_api_key', Settings::i()->postmark_server_api_key, TRUE, suffix: Member::loggedIn()->language()->addToStack( 'postmark_server_api_key_suffix' ) ) );
|
||||
$form->add( new YesNo( 'postmark_track_opens', Settings::i()->postmark_track_opens, FALSE ) );
|
||||
|
||||
if( !empty( Settings::i()->postmark_server_api_key ) )
|
||||
{
|
||||
$postmark = new Postmark( Settings::i()->postmark_server_api_key );
|
||||
$currentSetting = json_decode( Settings::i()->postmark_streams, TRUE );
|
||||
$streams = $descriptions = [];
|
||||
foreach( $postmark->api('message-streams')['MessageStreams'] as $stream )
|
||||
{
|
||||
if( $stream['MessageStreamType'] == 'Inbound' ) continue;
|
||||
$streams[ $stream['ID'] ] = $stream['Name'];
|
||||
$descriptions[ $stream['ID'] ] = '<br>'.$stream['Description'];
|
||||
}
|
||||
|
||||
$form->addHeader('postmark_message_streams');
|
||||
$form->addMessage( 'postmark_message_description');
|
||||
$form->addMessage( 'postmark_stream_choose');
|
||||
$form->add( new Form\Radio( 'postmark_transactional_stream', $currentSetting['transactional'], true, [ 'options' => $streams, 'descriptions' => $descriptions, 'parse' => 'normal' ] ) );
|
||||
$form->add( new Form\Radio( 'postmark_bulk_stream', $currentSetting['bulk'], true, [ 'options' => $streams, 'descriptions' => $descriptions, 'parse' => 'normal' ] ) );
|
||||
}
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->testSettings( $values );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
Output::i()->error( $e->getMessage(), '2C438/1', 500 );
|
||||
}
|
||||
|
||||
if( isset( $values['postmark_bulk_stream'] ) )
|
||||
{
|
||||
$values['postmark_streams'] = json_encode( [ 'bulk' => $values['postmark_bulk_stream'], 'transactional' => $values['postmark_transactional_stream'] ] );
|
||||
unset( $values['postmark_bulk_stream'], $values['postmark_transactional_stream'] );
|
||||
}
|
||||
|
||||
$form->saveAsSettings( $values );
|
||||
Session::i()->log( 'acplog__enhancements_edited', array( 'enhancements__core_Postmark' => TRUE ) );
|
||||
Output::i()->inlineMessage = Member::loggedIn()->language()->addToStack( 'saved' );
|
||||
}
|
||||
|
||||
Output::i()->sidebar['actions'] = array(
|
||||
'help' => array(
|
||||
'title' => 'learn_more',
|
||||
'icon' => 'question-circle',
|
||||
'link' => Url::ips( 'docs/postmark_api_key' ),
|
||||
'target' => '_blank'
|
||||
),
|
||||
);
|
||||
|
||||
Output::i()->output = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable
|
||||
*
|
||||
* @param $enabled bool Enable/Disable
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function toggle( $enabled )
|
||||
{
|
||||
/* If we're disabling, just disable */
|
||||
if ( !$enabled )
|
||||
{
|
||||
Settings::i()->changeValues( array( 'postmark_server_api_key' => '' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We need an API key. */
|
||||
throw new \DomainException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @param array $values Form values
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function testSettings( $values )
|
||||
{
|
||||
/* Test Postmark settings */
|
||||
$postmark = new Postmark( $values['postmark_server_api_key'] );
|
||||
$server = $postmark->api('server');
|
||||
|
||||
if( $server === null OR !empty( $server['ErrorCode'] ) )
|
||||
{
|
||||
throw new \DomainException( Member::loggedIn()->language()->addToStack( 'postmark_api_error', false, [ 'sprintf' => [ (string) $server['ErrorCode'], $server['Message'] ] ] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace IPS\core\extensions\core\CommunityEnhancements;
|
||||
|
||||
use IPS\Settings;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
@@ -41,6 +43,20 @@ class _SendGrid
|
||||
* @brief Icon data
|
||||
*/
|
||||
public $icon = "sendgrid.png";
|
||||
|
||||
/**
|
||||
* Can we use this?
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function isAvailable()
|
||||
{
|
||||
if( Settings::i()->sendgrid_deprecated )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -49,7 +65,7 @@ class _SendGrid
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->enabled = ( \IPS\Settings::i()->sendgrid_api_key && \IPS\Settings::i()->sendgrid_use_for );
|
||||
$this->enabled = ( static::isAvailable() && \IPS\Settings::i()->sendgrid_api_key && \IPS\Settings::i()->sendgrid_use_for );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,6 +66,7 @@ class _Email
|
||||
$fromName = ( \IPS\Member::loggedIn()->member_id ) ? \IPS\Member::loggedIn()->name : $values['contact_name'];
|
||||
$fromEmail = ( \IPS\Member::loggedIn()->member_id ) ? \IPS\Member::loggedIn()->email : $values['email_address'];
|
||||
$content = $values['contact_text'];
|
||||
$referrer = $values['contact_referrer'] ?? NULL;
|
||||
|
||||
if ( \IPS\Settings::i()->contact_type == 'contact_internal' )
|
||||
{
|
||||
@@ -75,7 +76,7 @@ class _Email
|
||||
{
|
||||
$sender = explode( ',', \IPS\Settings::i()->contact_emails );
|
||||
}
|
||||
$mail = \IPS\Email::buildFromTemplate( 'core', 'contact_form', array( \IPS\Member::loggedIn(), $fromName, $fromEmail, $content ), \IPS\Email::TYPE_TRANSACTIONAL );
|
||||
$mail = \IPS\Email::buildFromTemplate( 'core', 'contact_form', array( \IPS\Member::loggedIn(), $fromName, $fromEmail, $content, $referrer ), \IPS\Email::TYPE_TRANSACTIONAL );
|
||||
$mail->send( $sender , array(), array(), NULL, $fromName, array( 'Reply-To' => \IPS\Email::encodeHeader( $fromName, ( \IPS\Member::loggedIn()->member_id ? \IPS\Member::loggedIn()->email : $values['email_address'] ) ) ), FALSE );
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -22,6 +22,11 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _Icons
|
||||
{
|
||||
/**
|
||||
* @var int Cache icons for 3mo
|
||||
*/
|
||||
public static $cacheControlTtl = 7776000; // 3 mo
|
||||
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
|
||||
@@ -26,7 +26,7 @@ class _Theme
|
||||
* Some file storage engines need to store a gzip version of some files that can be served to a browser gzipped
|
||||
*/
|
||||
public static $storeGzipExtensions = array( 'css', 'js' );
|
||||
|
||||
|
||||
/**
|
||||
* The configuration settings have been updated
|
||||
*
|
||||
|
||||
@@ -175,10 +175,14 @@ class _Content
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'g_avoid_flood', $group->g_avoid_flood ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'g_avoid_q', $group->g_avoid_q, FALSE, array( 'togglesOff' => array( 'g_mod_preview' ), 'toggleValue' => FALSE ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'g_mod_preview', $group->g_mod_preview, FALSE, array( 'togglesOn' => array( 'g_mod_post_unit' ) ), NULL, NULL, NULL, 'g_mod_preview' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'g_mod_post_unit', array( $group->g_mod_post_unit ? : 0, $group->g_bitoptions['gbw_mod_post_unit_type'] ), FALSE, array( 'getHtml' => function( $element )
|
||||
if( $group->g_id != \IPS\Settings::i()->guest_group )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'members' )->moderationLimits( $element->name, $element->value );
|
||||
} ), NULL, NULL, NULL, 'g_mod_post_unit' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'g_mod_post_unit', [$group->g_mod_post_unit ?: 0, $group->g_bitoptions[ 'gbw_mod_post_unit_type' ]], FALSE, ['getHtml' => function( $element ){
|
||||
return \IPS\Theme::i()->getTemplate( 'members' )->moderationLimits( $element->name, $element->value );
|
||||
}
|
||||
], NULL, NULL, NULL, 'g_mod_post_unit' )
|
||||
);
|
||||
}
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'g_bypass_badwords', $group->g_bypass_badwords ) );
|
||||
if ( \IPS\Settings::i()->ips_imagescanner_enable )
|
||||
{
|
||||
@@ -239,8 +243,12 @@ class _Content
|
||||
}
|
||||
|
||||
/* Mod Queue */
|
||||
$group->g_mod_post_unit = isset( $values['g_mod_post_unit'][2] ) ? 0 : $values['g_mod_post_unit'][0];
|
||||
$group->g_bitoptions['gbw_mod_post_unit_type'] = isset( $values['g_mod_post_unit'][2] ) ? 0 : $values['g_mod_post_unit'][1];
|
||||
if( $group->g_id != \IPS\Settings::i()->guest_group )
|
||||
{
|
||||
$group->g_mod_post_unit = isset( $values[ 'g_mod_post_unit' ][ 2 ] ) ? 0 : $values[ 'g_mod_post_unit' ][ 0 ];
|
||||
$group->g_bitoptions['gbw_mod_post_unit_type'] = isset( $values['g_mod_post_unit'][2] ) ? 0 : $values['g_mod_post_unit'][1];
|
||||
}
|
||||
|
||||
|
||||
/* Bitwise */
|
||||
$values['gbw_disable_tagging'] = \IPS\Settings::i()->tags_enabled ? !$values['gbw_disable_tagging'] : $group->g_bitoptions['gbw_disable_tagging'];
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
namespace IPS\core\extensions\core\IpAddresses;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Member;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
@@ -113,12 +116,13 @@ class _Content extends \IPS\Content\ExtensionGenerator
|
||||
try
|
||||
{
|
||||
$comment = $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] );
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $comment->item()->mapped('title') );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return '';
|
||||
if( $comment->canView() )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $comment->item()->mapped('title') );
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e ){}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
}
|
||||
);
|
||||
|
||||
@@ -154,7 +158,16 @@ class _Content extends \IPS\Content\ExtensionGenerator
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] )->url(), TRUE, $val );
|
||||
try
|
||||
{
|
||||
$item = $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] );
|
||||
if( $item->canView() )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, $val );
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException ){}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
},
|
||||
);
|
||||
if( isset( $class::$databaseColumnMap['container'] ) )
|
||||
@@ -163,7 +176,11 @@ class _Content extends \IPS\Content\ExtensionGenerator
|
||||
{
|
||||
$nodeClass = $class::$containerNodeClass;
|
||||
$node = $nodeClass::load( $val );
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $node->url(), TRUE, $node->_title );
|
||||
if( $node->canView() )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $node->url(), TRUE, $node->_title );
|
||||
}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,6 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _Dnames
|
||||
{
|
||||
/**
|
||||
* Removes the logged IP address
|
||||
*
|
||||
* @param int $timestamp
|
||||
* @return void
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_member_history', [ 'log_ip_address=?', '' ] , [ 'log_ip_address != "" AND log_type=? AND log_date <?', 'display_name', $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported in the ACP IP address lookup tool?
|
||||
*
|
||||
|
||||
@@ -30,7 +30,7 @@ class _Logins
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_members_known_ip_addresses', [ 'ip_address=?', '' ] , [ "ip_address != '' AND last_seen <?", $time ] );
|
||||
// Main cleanup task takes care of this
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _MemberHistory
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_member_history', [ 'log_ip_address=?', '' ] , [ "log_ip_address != '' AND log_date <?", $time ] );
|
||||
\IPS\Db::i()->update('core_member_history', [ 'log_ip_address' => '' ] , [ "log_ip_address != '' and log_date <?", $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _Ratings
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_ratings', [ 'ip=?', '' ] , [ "ip != '' AND rating_date <?", $time ] );
|
||||
\IPS\Db::i()->update('core_ratings', [ 'ip' => '' ] , [ "ip != '' AND rating_date IS NOT NULL AND rating_date <?", $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _Registration
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_members', [ 'ip_address=?', '' ] , [ "ip_address != '' AND joined <?", $time ] );
|
||||
\IPS\Db::i()->update('core_members', [ 'ip_address' => '' ] , [ "ip_address != '' and joined <?", $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _ReportComments
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_rc_comments', [ 'ip_address=?', '' ] , [ 'comment_date <?', $time ] );
|
||||
\IPS\Db::i()->update('core_rc_comments', [ 'ip_address' => '' ] , [ 'comment_date <?', $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _Reports
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_rc_reports', [ 'ip_address=?', '' ] , [ 'date_reported <?', $time ] );
|
||||
\IPS\Db::i()->update('core_rc_reports', [ 'ip_address' => '' ] , [ 'date_reported <?', $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class _Votes
|
||||
*/
|
||||
public function pruneIpAddresses(int $time)
|
||||
{
|
||||
\IPS\Db::i()->update('core_voters', [ 'ip_address=?', '' ] , [ "ip_address != '' AND vote_date <?", $time ] );
|
||||
\IPS\Db::i()->update('core_voters', [ 'ip_address' => '' ] , [ "ip_address != '' and vote_date <?", $time ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ class _DevicesAndIPAddresses extends \IPS\core\MemberACPProfile\Block
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$lastUsedIp = $this->member->lastUsedIp();
|
||||
$lastUsedIp = $this->member->lastUsedIp() ?? '';
|
||||
$devices = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members_known_devices', array( 'member_id=?', $this->member->member_id ), 'last_seen DESC', 5 ), 'IPS\Member\Device' );
|
||||
|
||||
return \IPS\Theme::i()->getTemplate('memberprofile')->devicesAndIPAddresses( $this->member, $lastUsedIp, $devices );
|
||||
|
||||
@@ -194,10 +194,24 @@ class _ProfileFields
|
||||
$type = 'IPS\Helpers\Form\\' . $field['pf_type'];
|
||||
$helper = NULL;
|
||||
$langKey = "core_pfield_{$id}";
|
||||
|
||||
if( empty( $data[ $langKey ] ) )
|
||||
|
||||
/* We need to handle YesNo and Checkbox fields specially, as it will intentionally try and pass '0' which is valid, but returns true in empty() */
|
||||
switch( $type )
|
||||
{
|
||||
continue;
|
||||
case 'IPS\Helpers\Form\YesNo':
|
||||
case 'IPS\Helpers\Form\Checkbox':
|
||||
if ( !isset( $data[ $langKey ] ) OR $data[ $langKey ] === '' )
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( empty( $data[ $langKey ] ) )
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( $type )
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Member Sync
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
|
||||
* @since 21 Aug 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\MemberSync;
|
||||
use IPS\core\Hive;
|
||||
use IPS\Db;
|
||||
use IPS\Member;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Member Sync
|
||||
*/
|
||||
class _Hive
|
||||
{
|
||||
/**
|
||||
* Member account has been updated
|
||||
*
|
||||
* @param $member Member Member updating profile
|
||||
* @param $changes array The changes
|
||||
* @return void
|
||||
*/
|
||||
public function onProfileUpdate( $member, $changes )
|
||||
{
|
||||
if( \in_array( [ 'member_group_id', 'mgroup_others', 'temp_ban' ], array_keys( $changes ) ) )
|
||||
{
|
||||
$this->_updateHive( $member, 'update' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Member is merged with another member
|
||||
*
|
||||
* @param Member $member Member being kept
|
||||
* @param Member $member2 Member being removed
|
||||
* @return void
|
||||
*/
|
||||
public function onMerge( $member, $member2 )
|
||||
{
|
||||
$this->_updateHive( $member2, 'merge', $member->member_id );
|
||||
try
|
||||
{
|
||||
Db::i()->insert( 'core_hive_subscribers', [ 'member_id' => $member->member_id, 'subscribe_date' => time() ] );
|
||||
}
|
||||
catch( Db\Exception $e ) {}
|
||||
Db::i()->delete( 'core_hive_subscribers', [ 'member_id=?', $member2->member_id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Member is deleted
|
||||
*
|
||||
* @param $member Member The member
|
||||
* @return void
|
||||
*/
|
||||
public function onDelete( $member )
|
||||
{
|
||||
$this->_updateHive( $member, 'delete' );
|
||||
Db::i()->delete( 'core_hive_subscribers', [ 'member_id=?', $member->member_id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update HIVE API
|
||||
*
|
||||
* @param Member $member
|
||||
* @param string $type
|
||||
* @param int|null $newMergeId
|
||||
* @return void
|
||||
*/
|
||||
protected function _updateHive( Member $member, string $type, int $newMergeId=null )
|
||||
{
|
||||
/* Check to see if we might be subscribed before pushing this change */
|
||||
try
|
||||
{
|
||||
Db::i()->select( '*', 'core_hive_subscribers', [ 'member_id=?', $member->member_id ] )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'site_member_id' => $member->member_id,
|
||||
'group_hash' => $type == 'delete' ? 'guest' : Hive::groupHash( $member ),
|
||||
];
|
||||
|
||||
if( $type === 'delete' )
|
||||
{
|
||||
$data['new_site_member_id'] = 0;
|
||||
}
|
||||
elseif( $type === 'merge' AND $newMergeId )
|
||||
{
|
||||
$data['new_site_member_id'] = $newMergeId;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Hive::api( 'groupupdate', $data );
|
||||
}
|
||||
catch( \Exception | \Throwable | \LogicException $e ) { }
|
||||
}
|
||||
}
|
||||
@@ -166,7 +166,6 @@ class _System
|
||||
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'id=? AND class=?', $member2->member_id, 'IPS\core\Member' ) );
|
||||
\IPS\Db::i()->delete( 'core_acp_notifcations_dismissals', array( '`member`=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->delete( 'core_acp_notifications_preferences', array( '`member`=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->delete( 'core_marketplace_tokens', array( 'id=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->delete( 'core_achievements_log_milestones', array( 'milestone_member_id=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->delete( 'core_member_privacy_actions', ['member_id=?', $member2->member_id] );
|
||||
|
||||
@@ -327,7 +326,6 @@ class _System
|
||||
array( 'core_referrals', 'referred_by' ),
|
||||
array( 'core_referrals', 'member_id' ),
|
||||
array( 'core_anonymous_posts', 'anonymous_member_id' ),
|
||||
array( 'core_marketplace_tokens', 'id' ),
|
||||
array( 'core_member_badges', 'member' ),
|
||||
array( 'core_notifications_pwa_keys', 'member' ),
|
||||
array( 'core_achievements_log_milestones', 'milestone_member_id' ),
|
||||
|
||||
@@ -142,7 +142,7 @@ class _Content
|
||||
|
||||
/* Display */
|
||||
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( \IPS\Http\Url::internal( "app=core&module=modcp&controller=modcp&tab=hidden", 'front', 'modcp_content' ), ceil( $results->count( TRUE ) / $query->resultsToGet ), $page, $query->resultsToGet ) );
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp' )->tableWrapper( \IPS\Theme::i()->getTemplate('search')->resultStream( $results, $pagination, \IPS\Http\Url::internal( "app=core&module=modcp&controller=modcp&tab=hidden", 'front', 'modcp_content' ), TRUE ), 'modcp_hidden' );
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp' )->tableWrapper( \IPS\Theme::i()->getTemplate('search')->resultStream( $results, $pagination, \IPS\Http\Url::internal( "app=core&module=modcp&controller=modcp&tab=hidden", 'front', 'modcp_content' ), TRUE, $results->count( TRUE ) ), 'modcp_hidden' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,19 @@
|
||||
namespace IPS\core\extensions\core\ModCp;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\core\Reports\Report;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use function count;
|
||||
use function intval;
|
||||
use function iterator_to_array;
|
||||
use function rtrim;
|
||||
use function str_replace;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
@@ -35,7 +48,7 @@ class _Reports extends \IPS\Content\Controller
|
||||
public function getTab()
|
||||
{
|
||||
/* Check Permissions */
|
||||
if ( ! \IPS\Member::loggedIn()->modPermission('can_view_reports') )
|
||||
if ( ! Member::loggedIn()->modPermission('can_view_reports') )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -50,18 +63,18 @@ class _Reports extends \IPS\Content\Controller
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if ( !\IPS\Member::loggedIn()->modPermission( 'can_view_reports' ) )
|
||||
if ( !Member::loggedIn()->modPermission( 'can_view_reports' ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2C139/1', 403, '' );
|
||||
Output::i()->error( 'no_module_permission', '2C139/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sidebar['enabled'] = FALSE;
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp.css' ) );
|
||||
Output::i()->sidebar['enabled'] = FALSE;
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp.css' ) );
|
||||
if ( \IPS\Theme::i()->settings['responsive'] )
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp_responsive.css' ) );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp_responsive.css' ) );
|
||||
}
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_modcp.js', 'core' ) );
|
||||
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_modcp.js', 'core' ) );
|
||||
|
||||
parent::execute();
|
||||
}
|
||||
@@ -77,7 +90,7 @@ class _Reports extends \IPS\Content\Controller
|
||||
$where = [ \IPS\core\Reports\Report::where() ];
|
||||
|
||||
/* Make sure we're loading the correct statuses */
|
||||
if( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->overview ) )
|
||||
if( Request::i()->isAjax() and isset( Request::i()->overview ) )
|
||||
{
|
||||
$where[] = array( "status IN( 1,2 )" );
|
||||
}
|
||||
@@ -117,22 +130,23 @@ class _Reports extends \IPS\Content\Controller
|
||||
}
|
||||
|
||||
$table->filters['filter_report_status_1_' . $appKey ] = [ 'status=1 and ' . \IPS\Db::i()->in( 'class', $classes ) ];
|
||||
\IPS\Member::loggedIn()->language()->words[ 'filter_report_status_1_' . $appKey ] = \IPS\Member::loggedIn()->language()->addToStack( 'filter_report_status_1_app', NULL, [ 'sprintf' => [ \IPS\Application::applications()[ $appKey ]->_title ] ] );
|
||||
Member::loggedIn()->language()->words[ 'filter_report_status_1_' . $appKey ] = Member::loggedIn()->language()->addToStack( 'filter_report_status_1_app', NULL, [ 'sprintf' => [ \IPS\Application::applications()[ $appKey ]->_title ] ] );
|
||||
}
|
||||
|
||||
$table->filters['filter_report_status_2'] = [ 'status=2' ];
|
||||
$table->filters['filter_report_status_3'] = [ 'status=3' ];
|
||||
$table->title = \IPS\Member::loggedIn()->language()->addToStack( 'report_center_header' );
|
||||
$table->filters['filter_report_status_4'] = [ 'status=4' ];
|
||||
$table->title = Member::loggedIn()->language()->addToStack( 'report_center_header' );
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->overview ) )
|
||||
if ( Request::i()->isAjax() and isset( Request::i()->overview ) )
|
||||
{
|
||||
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'modcp', 'core' ), 'reportListOverview' );
|
||||
\IPS\Output::i()->json( array( 'data' => (string) $table ) );
|
||||
Output::i()->json( array( 'data' => (string) $table ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'modcp_reports' ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'modcp_reports' );
|
||||
Output::i()->breadcrumb[] = array( NULL, Member::loggedIn()->language()->addToStack( 'modcp_reports' ) );
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack( 'modcp_reports' );
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp' )->reportList( (string) $table );
|
||||
}
|
||||
}
|
||||
@@ -147,16 +161,16 @@ class _Reports extends \IPS\Content\Controller
|
||||
/* Load Report */
|
||||
try
|
||||
{
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( Request::i()->id );
|
||||
$report->markRead();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C139/3', 404, '' );
|
||||
Output::i()->error( 'node_error', '2C139/3', 404, '' );
|
||||
}
|
||||
|
||||
/* Check permission. We do it this way rather than loadAndCheckPerms() since we need to know if the user *had* permission if the content has been deleted */
|
||||
$allowedPermIds = iterator_to_array( \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', \IPS\Member::loggedIn()->permissionArray() ) . " OR perm_view='*'" ) );
|
||||
$allowedPermIds = iterator_to_array( \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', Member::loggedIn()->permissionArray() ) . " OR perm_view='*'" ) );
|
||||
$workingClass = $report->class;
|
||||
if ( isset( $workingClass::$itemClass ) )
|
||||
{
|
||||
@@ -168,43 +182,31 @@ class _Reports extends \IPS\Content\Controller
|
||||
}
|
||||
if ( isset( $workingClass::$permissionMap ) and isset( $workingClass::$permissionMap['read'] ) and $workingClass::$permissionMap['read'] !== 'view' )
|
||||
{
|
||||
$allowedPermIds = array_intersect( $allowedPermIds, iterator_to_array( \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_' . $workingClass::$permissionMap['read'], \IPS\Member::loggedIn()->permissionArray() ) . " OR perm_" . $workingClass::$permissionMap['read'] . "='*'" ) ) );
|
||||
$allowedPermIds = array_intersect( $allowedPermIds, iterator_to_array( \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_' . $workingClass::$permissionMap['read'], Member::loggedIn()->permissionArray() ) . " OR perm_" . $workingClass::$permissionMap['read'] . "='*'" ) ) );
|
||||
}
|
||||
|
||||
if ( \in_array( 'IPS\Content\Permissions', class_implements( $workingClass ) ) and !\in_array( $report->perm_id, $allowedPermIds ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error_no_perm', '2C139/5', 403, '' );
|
||||
Output::i()->error( 'node_error_no_perm', '2C139/5', 403, '' );
|
||||
}
|
||||
|
||||
/* Setting status? */
|
||||
if( isset( \IPS\Request::i()->setStatus ) and \in_array( \IPS\Request::i()->setStatus, range( 1, 3 ) ) )
|
||||
if( isset( Request::i()->setStatus ) and \in_array( Request::i()->setStatus, range( 1, 4 ) ) )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
$report->changeStatus( (int) Request::i()->setStatus );
|
||||
|
||||
$report->status = (int) \IPS\Request::i()->setStatus;
|
||||
$report->save();
|
||||
|
||||
/* Post a comment on the report */
|
||||
$content = \IPS\Member::loggedIn()->language()->addToStack( 'update_report_status_content', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'report_status_' . $report->status ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $content );
|
||||
|
||||
$comment = \IPS\core\Reports\Comment::create( $report, $content, TRUE, NULL, NULL, \IPS\Member::loggedIn(), new \IPS\DateTime );
|
||||
$comment->save();
|
||||
|
||||
/* And add to the moderator log */
|
||||
\IPS\Session::i()->modLog( 'modlog__action_update_report_status', array( $report->url()->__toString() => FALSE ) );
|
||||
|
||||
\IPS\Output::i()->redirect( $report->url() );
|
||||
Output::i()->redirect( $report->url()->setQueryString( 'changed', '1' ) );
|
||||
}
|
||||
|
||||
/* Deleting? */
|
||||
if( isset( \IPS\Request::i()->_action ) and \IPS\Request::i()->_action == 'delete' and $report->canDelete() )
|
||||
if( isset( Request::i()->_action ) and Request::i()->_action == 'delete' and $report->canDelete() )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
$report->delete();
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', NULL, 'modcp_reports' ) );
|
||||
Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', NULL, 'modcp_reports' ) );
|
||||
}
|
||||
|
||||
/* Load */
|
||||
@@ -252,7 +254,7 @@ class _Reports extends \IPS\Content\Controller
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
|
||||
/* Next/Previous Links */
|
||||
$permSubQuery = \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', array_merge( array( \IPS\Member::loggedIn()->member_group_id ) , array_filter( explode( ',', \IPS\Member::loggedIn()->mgroup_others ) ) ) ) . " or perm_view='*'" );
|
||||
$permSubQuery = \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', array_merge( array( Member::loggedIn()->member_group_id ) , array_filter( explode( ',', Member::loggedIn()->mgroup_others ) ) ) ) . " or perm_view='*'" );
|
||||
|
||||
$prevReport = NULL;
|
||||
$prevItem = NULL;
|
||||
@@ -298,20 +300,160 @@ class _Reports extends \IPS\Content\Controller
|
||||
catch ( \UnderflowException $e ) {}
|
||||
|
||||
/* Display */
|
||||
if ( \IPS\Request::i()->isAjax() and !isset( \IPS\Request::i()->_contentReply ) and !isset( \IPS\Request::i()->getUploader ) AND !isset( \IPS\Request::i()->page ) AND !isset( \IPS\Request::i()->_previewField ) )
|
||||
if ( Request::i()->isAjax() and !isset( Request::i()->_contentReply ) and !isset( Request::i()->getUploader ) AND !isset( Request::i()->page ) AND !isset( Request::i()->_previewField ) )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'modcp' )->reportPanel( $report, $comment, $ref );
|
||||
Output::i()->output = \IPS\Theme::i()->getTemplate( 'modcp' )->reportPanel( $report, $comment, $ref );
|
||||
}
|
||||
else
|
||||
{
|
||||
$sprintf = $item ? htmlspecialchars( $item->mapped('title'), ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : \IPS\Member::loggedIn()->language()->addToStack('content_deleted');
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'modcp_reports_view', FALSE, array( 'sprintf' => array( $sprintf ) ) );
|
||||
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', 'front', 'modcp_reports' ), \IPS\Member::loggedIn()->language()->addToStack( 'modcp_reports' ) );
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, $item ? $item->mapped('title') : \IPS\Member::loggedIn()->language()->addToStack( 'content_deleted' ) );
|
||||
if ( isset( Request::i()->changed ) )
|
||||
{
|
||||
/* Show a flash message */
|
||||
Output::i()->inlineMessage = Member::loggedIn()->language()->addToStack( 'report_status_changed');
|
||||
}
|
||||
|
||||
$sprintf = $item ? htmlspecialchars( $item->mapped('title'), ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : Member::loggedIn()->language()->addToStack('content_deleted');
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack( 'modcp_reports_view', FALSE, array( 'sprintf' => array( $sprintf ) ) );
|
||||
Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', 'front', 'modcp_reports' ), Member::loggedIn()->language()->addToStack( 'modcp_reports' ) );
|
||||
Output::i()->breadcrumb[] = array( NULL, $item ? $item->mapped('title') : Member::loggedIn()->language()->addToStack( 'content_deleted' ) );
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp' )->report( $report, $comment, $item, $ref, $prevReport, $prevItem, $nextReport, $nextItem, $delLog );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the report center modal
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reportCenterConfirmModal()
|
||||
{
|
||||
$id = intval( Request::i()->id );
|
||||
|
||||
try
|
||||
{
|
||||
$report = Report::load( $id );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
Output::i()->error( 'node_error', '2S319/1', 404 );
|
||||
}
|
||||
|
||||
$form = new Form( 'form', 'modal_author_notification_form_submit' );
|
||||
$form->class .= 'ipsForm_vertical';
|
||||
$form->addButton( 'cancel', 'link', $report->url() );
|
||||
|
||||
/* Get the optional notifications */
|
||||
$notifications = [ 0 => 'modal_author_notification_none' ];
|
||||
foreach( Report::getAuthorNotifications() as $notification )
|
||||
{
|
||||
$notifications[ $notification['id'] ] = $notification['title'];
|
||||
}
|
||||
$form->add( new Select( 'modal_author_notification', null, null, [ 'options' => $notifications ] ) );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $report->class;
|
||||
$thing = $class::load( $report->content_id );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
Output::i()->error( 'node_error', '2S319/2', 404 );
|
||||
}
|
||||
|
||||
/* Fix the language string */
|
||||
Member::loggedIn()->language()->words['modal_author_notification'] = Member::loggedIn()->language()->addToStack('modal_author__notification', null, [ 'sprintf' => [ $thing->author()->name ] ] );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
$report->changeStatus( (int) Request::i()->status, $values['modal_author_notification'] );
|
||||
|
||||
Output::i()->redirect( $report->url()->setQueryString( 'changed', '1' ) );
|
||||
}
|
||||
|
||||
Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->genericBlock( (string) $form, null, 'ipsPadding' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Report Reason (report_type)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeType()
|
||||
{
|
||||
|
||||
/* Load the report and the main object */
|
||||
try
|
||||
{
|
||||
$report = \IPS\Db::i()->select( '*', 'core_rc_reports', [ 'id=?', Request::i()->id ] )->first();
|
||||
$item = \IPS\core\Reports\Report::loadAndCheckPerms( $report['rid'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
Output::i()->error( 'node_error', '2C139/6', 404, '' );
|
||||
}
|
||||
|
||||
/* Build form */
|
||||
$form = new Form;
|
||||
$options = array( \IPS\core\Reports\Report::TYPE_MESSAGE => Member::loggedIn()->language()->addToStack('report_message_comment') );
|
||||
foreach( \IPS\core\Reports\Types::roots() as $type )
|
||||
{
|
||||
$options[ $type->id ] = $type->_title;
|
||||
}
|
||||
|
||||
if ( count( $options ) > 1 )
|
||||
{
|
||||
$form->add( new Select( 'report_type', $report['report_type'], null, [ 'options' => $options ] ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'report_type_change_log', true, null ) );
|
||||
}
|
||||
$form->class .= 'ipsForm_vertical';
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* Update the new reason */
|
||||
\IPS\Db::i()->update( 'core_rc_reports', array( 'report_type' => $values['report_type'] ), [ 'id=?', $report['id'] ] );
|
||||
|
||||
if ( ! empty( $values['report_type_change_log'] ) )
|
||||
{
|
||||
$old = Member::loggedIn()->language()->get('none');
|
||||
$new = Member::loggedIn()->language()->get('none');
|
||||
|
||||
if ( $values['report_type'] )
|
||||
{
|
||||
$new = \IPS\core\Reports\Types::load( $values['report_type'] )->_title;
|
||||
}
|
||||
|
||||
if ( $report['report_type'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$old = \IPS\core\Reports\Types::load( $report['report_type'] )->_title;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
Output::i()->error( 'node_error', '2C139/7', 403, '' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $report['report_type'] != $values['report_type'] )
|
||||
{
|
||||
$url = $item->url()->setQueryString( 'tab', 'reports' )->setFragment( 'report' . $report['id'] );
|
||||
$content = Member::loggedIn()->language()->addToStack('report_type_changed', FALSE, array( 'sprintf' => array( $new, $old, $url, $report['id'] ) ) );
|
||||
Member::loggedIn()->language()->parseOutputForDisplay( $content );
|
||||
$content = str_replace( rtrim( \IPS\Settings::i()->base_url, '/' ), '<___base_url___>', $content );
|
||||
|
||||
$comment = \IPS\core\Reports\Comment::create( $item, $content, TRUE, NULL, NULL, Member::loggedIn(), new \IPS\DateTime );
|
||||
$comment->save();
|
||||
}
|
||||
}
|
||||
|
||||
Output::i()->redirect( $item->url() );
|
||||
}
|
||||
|
||||
/* Display form */
|
||||
Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the original content for a report
|
||||
*
|
||||
@@ -321,19 +463,19 @@ class _Reports extends \IPS\Content\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( Request::i()->id );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C139/4', 404, '' );
|
||||
Output::i()->error( 'node_error', '2C139/4', 404, '' );
|
||||
}
|
||||
|
||||
$reportClass = $report->class;
|
||||
$comment = $reportClass::load( $report->content_id );
|
||||
$url = \IPS\Request::i()->parent ? $comment->item()->url() : $comment->url();
|
||||
$url = Request::i()->parent ? $comment->item()->url() : $comment->url();
|
||||
$url = $url->setQueryString( '_report', $report->id );
|
||||
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,12 +487,12 @@ class _Reports extends \IPS\Content\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$comment = \IPS\core\Reports\Comment::load( \IPS\Request::i()->comment );
|
||||
$report = \IPS\core\Reports\Report::loadAndCheckPerms( Request::i()->id );
|
||||
$comment = \IPS\core\Reports\Comment::load( Request::i()->comment );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C139/4', 404, '' );
|
||||
Output::i()->error( 'node_error', '2C139/4', 404, '' );
|
||||
}
|
||||
|
||||
$url = $report->url()->setQueryString( 'activeTab', 'comments' );
|
||||
@@ -366,6 +508,6 @@ class _Reports extends \IPS\Content\Controller
|
||||
}
|
||||
|
||||
|
||||
\IPS\Output::i()->redirect( $url->setFragment( 'comment-' . $comment->$commentIdColumn ) );
|
||||
Output::i()->redirect( $url->setFragment( 'comment-' . $comment->$commentIdColumn ) );
|
||||
}
|
||||
}
|
||||
@@ -439,13 +439,27 @@ class _Content
|
||||
{
|
||||
$where[] = array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'] . ' NOT IN(?,?)', -2, -3 );
|
||||
}
|
||||
|
||||
/* Skip Anonymous authors, we'll do this later */
|
||||
if( isset( $commentClass::$databaseColumnMap['is_anon'] ) )
|
||||
{
|
||||
$where[] = array( "( " . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['is_anon'] . ' IS NULL OR ' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['is_anon'] . '!=? )', 1);
|
||||
}
|
||||
|
||||
$commenters = \IPS\Db::i()->select( 'DISTINCT ' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'], $commentClass::$databaseTable, $where );
|
||||
|
||||
|
||||
|
||||
$names = array();
|
||||
|
||||
$comment = $commentClass::loadAndCheckPerms( $notification->item_sub_id );
|
||||
/* If we have an anonymous author, add "anonymous" to the list */
|
||||
if( $comment->isAnonymous() )
|
||||
{
|
||||
$names[] = \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' );
|
||||
}
|
||||
|
||||
foreach ( $commenters as $member )
|
||||
{
|
||||
$name = ( $item->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : \IPS\Member::load( $member )->name;
|
||||
$name = \IPS\Member::load( $member )->name;
|
||||
if ( \count( $names ) > 2 )
|
||||
{
|
||||
$names[] = \IPS\Member::loggedIn()->language()->addToStack( 'x_others', FALSE, array( 'pluralize' => array( \count( $commenters ) - 3 ) ) );
|
||||
@@ -453,8 +467,6 @@ class _Content
|
||||
}
|
||||
$names[] = $name;
|
||||
}
|
||||
|
||||
$comment = $commentClass::loadAndCheckPerms( $notification->item_sub_id );
|
||||
|
||||
/* If the comment is in the deletion queue, add the showDeleted=1 parameter otherwise it just won't show up */
|
||||
$url = $comment->url('find');
|
||||
@@ -463,9 +475,9 @@ class _Content
|
||||
{
|
||||
$url = $url->setQueryString( 'showDeleted', 1 );
|
||||
}
|
||||
|
||||
|
||||
/* Unread? */
|
||||
$unread = false;
|
||||
$unread = true;
|
||||
if ( $item->timeLastRead() instanceof \IPS\DateTime )
|
||||
{
|
||||
$unread = (bool) ( $item->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
namespace IPS\core\extensions\core\Notifications;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use function md5;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
@@ -115,7 +118,21 @@ class _Moderation
|
||||
'disabled' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Do we have any report types, and can we report things? ? */
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_automatic_moderation_types' )->first() and ( ! $member or $member->group['g_can_report'] ) )
|
||||
{
|
||||
$return['reports'] = [
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => ['report_outcome'],
|
||||
'title' => 'notifications__core_Moderation_reports',
|
||||
'showTitle' => true,
|
||||
'description' => 'notifications__core_Moderation_reports_desc',
|
||||
'default' => ['email'],
|
||||
'disabled' => [ 'push', 'inline' ],
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -190,6 +207,52 @@ class _Moderation
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: Report outcomes
|
||||
*
|
||||
* @param \IPS\Notification\Inline $notification The notification
|
||||
* @param bool $htmlEscape TRUE to escape HTML in title
|
||||
* @return array
|
||||
* @code
|
||||
return array(
|
||||
'title' => "Mark has replied to A Topic", // The notification title
|
||||
'url' => \IPS\Http\Url::internal( ... ), // The URL the notification should link to
|
||||
'content' => "Lorem ipsum dolar sit", // [Optional] Any appropriate content. Do not format this like an email where the text
|
||||
// explains what the notification is about - just include any appropriate content.
|
||||
// For example, if the notification is about a post, set this as the body of the post.
|
||||
'author' => \IPS\Member::load( 1 ), // [Optional] The user whose photo should be displayed for this notification
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
public function parse_report_outcome( $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
if ( ! $notification->item_sub or ! count( $notification->extra ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
$reported = $notification->item_sub;
|
||||
$item = ( $reported instanceof \IPS\Content\Item ) ? $reported : $reported->item();
|
||||
|
||||
try
|
||||
{
|
||||
$reportType = \IPS\core\Reports\Types::load( $notification->extra['reportType'] );
|
||||
$class = $item->class;
|
||||
$url = $class::load( $item->content_id )->url();
|
||||
}
|
||||
catch( \UnderflowException )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__report_outcome', FALSE, array(
|
||||
( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array( $item->mapped('title'), $reportType->_title, \IPS\Member::loggedIn()->language()->addToStack( 'report_status_' . $item->status ) ) )
|
||||
),
|
||||
'url' => $url,
|
||||
'author' => \IPS\Member::loggedIn(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: unapproved_content_bulk
|
||||
@@ -497,10 +560,18 @@ class _Moderation
|
||||
if ( $item instanceof \IPS\Content\Comment OR $item instanceof \IPS\Content\Review )
|
||||
{
|
||||
$title = $item->item()->mapped('title');
|
||||
|
||||
/* Unread? */
|
||||
$unread = false;
|
||||
if ( $item->item()->timeLastRead() instanceof \IPS\DateTime )
|
||||
{
|
||||
$unread = (bool) ( $item->item()->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = $item->mapped('title');
|
||||
$unread = (bool) ( $item->unread() );
|
||||
}
|
||||
|
||||
$name = ( $item->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $item->author()->name;
|
||||
@@ -510,6 +581,7 @@ class _Moderation
|
||||
'url' => $item->url(),
|
||||
'content' => $item->content(),
|
||||
'author' => $item->author(),
|
||||
'unread' => $unread,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class _Devices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$where[] = ['type=?', 'devices'];
|
||||
$result = \IPS\Db::i()->select( 'SUM(value_1) as mobiles, SUM(value_2) AS tablets, SUM(value_3) as consoles, SUM(value_4) as desktops', 'core_statistics', $where )->first();
|
||||
$total = $result['mobiles'] + $result['tablets'] + $result['consoles'] + $result['desktops'];
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class _ProfileFields
|
||||
$pieBarData[] = array(
|
||||
'name' => \IPS\Member::loggedIn()->language()->addToStack('stats_pfields__checked'),
|
||||
'value' => isset( $results[1] ) ? $results[1]['total'] : 0,
|
||||
'percentage' => ( isset( $results[1] ) AND $results[0]['total'] > 0 ) ? round( ( $results[1]['total'] / $total ) * 100, 2 ) : 0
|
||||
'percentage' => ( isset( $results[1] ) AND $results[1]['total'] > 0 ) ? round( ( $results[1]['total'] / $total ) * 100, 2 ) : 0
|
||||
);
|
||||
}
|
||||
elseif( $field['pf_type'] == 'YesNo' )
|
||||
|
||||
@@ -47,6 +47,8 @@ class _MemberContent
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$data['last_id'] = 0;
|
||||
|
||||
/* Get count - only do this if we're deleting member content, not guest content */
|
||||
if ( $data['member_id'] )
|
||||
@@ -77,21 +79,25 @@ class _MemberContent
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$idColumn = $classname::$databaseColumnId;
|
||||
$exploded = explode( '\\', $classname );
|
||||
if ( !class_exists( $classname ) or !\IPS\Application::appIsEnabled( $exploded[1] ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
$select = $classname::db()->select( '*', $classname::$databaseTable, static::_getWhere( $data ), $classname::$databasePrefix.$classname::$databaseColumnId, array( 0, \IPS\REBUILD_NORMAL ) );
|
||||
$select = $classname::db()->select( '*', $classname::$databaseTable, static::_getWhere( $data ), $classname::$databasePrefix.$classname::$databaseColumnId, \IPS\REBUILD_SLOW );
|
||||
|
||||
/* Keep track of how many we did since we cannot rely on the count for guests */
|
||||
$did = 0;
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( $select, $classname ) as $item )
|
||||
{
|
||||
$did++;
|
||||
$data['last_id'] = $item->$idColumn;
|
||||
|
||||
/* If this is the first comment on an item where a first comment is required (e.g. posts) do nothing, as when we get to the item, that will handle it */
|
||||
if ( $item instanceof \IPS\Content\Comment )
|
||||
{
|
||||
@@ -108,7 +114,7 @@ class _MemberContent
|
||||
}
|
||||
catch( \OutOfRangeException $e ) {}
|
||||
}
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -142,29 +148,16 @@ class _MemberContent
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$did++;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$did++;
|
||||
}
|
||||
catch( \ErrorException $e )
|
||||
{
|
||||
$did++;
|
||||
}
|
||||
catch( \OutOfRangeException | \ErrorException $e ) {}
|
||||
}
|
||||
|
||||
if ( !$did )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
else if( isset( $data['count'] ) AND ( $offset + \IPS\REBUILD_NORMAL >= $data['count'] ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return ( $offset + \IPS\REBUILD_NORMAL );
|
||||
return ( $offset + $did );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,11 +209,19 @@ class _MemberContent
|
||||
protected static function _getWhere( $data )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$where = array( array( $classname::$databasePrefix . $classname::$databaseColumnMap['author'] . '=?', $data['member_id'] ) );
|
||||
|
||||
$where = [
|
||||
[
|
||||
$classname::$databasePrefix . $classname::$databaseColumnId . '>?', $data['last_id']
|
||||
]
|
||||
];
|
||||
|
||||
if ( !$data['member_id'] )
|
||||
{
|
||||
$where = array( $classname::$databasePrefix . $classname::$databaseColumnMap['author_name'] . '=?', $data['name'] );
|
||||
$where[] = [ $classname::$databasePrefix . $classname::$databaseColumnMap['author_name'] . '=?', $data['name'] ];
|
||||
}
|
||||
else
|
||||
{
|
||||
$where[] = [ $classname::$databasePrefix . $classname::$databaseColumnMap['author'] . '=?', $data['member_id'] ];
|
||||
}
|
||||
|
||||
if ( $data['action'] == 'hide' )
|
||||
|
||||
@@ -217,6 +217,7 @@ class _RebuildAchievements
|
||||
public function postComplete( $data, $processed = TRUE )
|
||||
{
|
||||
/* The core_queue row is deleted before this is run */
|
||||
/* @note SELECT_FROM_WRITE_SERVER: Avoid race conditions with the task */
|
||||
if ( ! \IPS\Db::i()->select( 'COUNT(*)', 'core_queue', [ [ '`key`=?', 'RebuildAchievements' ] ], NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() )
|
||||
{
|
||||
/* Rebuilding is complete! */
|
||||
|
||||
@@ -61,9 +61,52 @@ class _RebuildSearchIndex
|
||||
|
||||
if( \IPS\Settings::i()->search_method == 'mysql' and \IPS\Settings::i()->search_index_timeframe )
|
||||
{
|
||||
if( isset( $classname::$databaseColumnMap['date'] ) )
|
||||
$cutoff = \IPS\DateTime::ts( time() - ( 86400 * \IPS\Settings::i()->search_index_timeframe ) )->getTimestamp();
|
||||
|
||||
/* If we store the time of the last comment / review, use that. If not, then use normal start date. */
|
||||
if ( isset( $classname::$databaseColumnMap['last_comment'] ) OR isset( $classname::$databaseColumnMap['last_review'] ) )
|
||||
{
|
||||
$where[] = array( $classname::$databasePrefix . $classname::$databaseColumnMap['date'] . '> ?', \IPS\DateTime::ts( time() - ( 86400 * \IPS\Settings::i()->search_index_timeframe ) )->getTimestamp() );
|
||||
$columns = array();
|
||||
$binds = array();
|
||||
if ( isset( $classname::$databaseColumnMap['last_comment'] ) )
|
||||
{
|
||||
if ( is_array( $classname::$databaseColumnMap['last_comment'] ) )
|
||||
{
|
||||
foreach( $classname::$databaseColumnMap['last_comment'] AS $column )
|
||||
{
|
||||
$columns[] = $classname::$databasePrefix . $column . " > ?";
|
||||
$binds[] = $cutoff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$columns[] = $classname::$databasePrefix . $classname::$databaseColumnMap['last_comment'] . " > ?";
|
||||
$binds[] = $cutoff;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $classname::$databaseColumnMap['last_review'] ) )
|
||||
{
|
||||
if ( is_array( $classname::$databaseColumnMap['last_review'] ) )
|
||||
{
|
||||
foreach( $classname::$databaseColumnMap['last_review'] AS $column )
|
||||
{
|
||||
$columns[] = $classname::$databasePrefix . $column . " > ?";
|
||||
$binds[] = $cutoff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$columns[] = $classname::$databasePrefix . $classname::$databaseColumnMap['last_review'] . " > ?";
|
||||
$binds[] = $cutoff;
|
||||
}
|
||||
}
|
||||
|
||||
$where[] = array( '(' . implode( ' OR ', $columns ) . ')', ...$binds );
|
||||
}
|
||||
else if( isset( $classname::$databaseColumnMap['date'] ) )
|
||||
{
|
||||
$where[] = array( $classname::$databasePrefix . $classname::$databaseColumnMap['date'] . '> ?', $cutoff );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
namespace IPS\core\extensions\core\Sitemap;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Member;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use function array_merge;
|
||||
use function class_implements;
|
||||
use function implode;
|
||||
use function json_encode;
|
||||
use function md5;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
@@ -182,14 +192,54 @@ class _Content extends \IPS\Content\ExtensionGenerator
|
||||
|
||||
if ( isset( $class::$containerNodeClass ) )
|
||||
{
|
||||
$nodeClass = $class::$containerNodeClass;
|
||||
$containerClass = $class::$containerNodeClass;
|
||||
|
||||
/* We need one file for the nodes */
|
||||
$files[] = 'sitemap_content_' . str_replace( '\\', '_', mb_substr( $nodeClass, 4 ) );
|
||||
}
|
||||
$files[] = 'sitemap_content_' . str_replace( '\\', '_', mb_substr( $containerClass, 4 ) );
|
||||
$where = [];
|
||||
|
||||
/* And however many for the content items */
|
||||
$contentItems = $class::getItemsWithPermission( $class::sitemapWhere(), NULL, NULL, 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, new \IPS\Member, NULL, NULL, NULL, TRUE );
|
||||
/* Get the count in the most efficient way possible */
|
||||
if ( \in_array( 'IPS\Content\Permissions', class_implements( $class ) ) )
|
||||
{
|
||||
$member = new Member;
|
||||
$containerWhere = [];
|
||||
$categories = [];
|
||||
/* @var $permissionMap array */
|
||||
$permQuery = \IPS\Db::i()->select( 'perm_type_id', 'core_permission_index', array( "core_permission_index.app='" . $containerClass::$permApp . "' AND core_permission_index.perm_type='" . $containerClass::$permType . "' AND (" . \IPS\Db::i()->findInSet( 'perm_' . $containerClass::$permissionMap['read'], $member->permissionArray() ) . ' OR ' . 'perm_' . $containerClass::$permissionMap['read'] . "='*' )" ) );
|
||||
|
||||
/* If we cannot access clubs, skip them */
|
||||
if ( \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) AND !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'clubs', 'front' ) ) )
|
||||
{
|
||||
$containerWhere[] = array( $containerClass::$databaseTable . '.' . $containerClass::$databasePrefix . $containerClass::clubIdColumn() . ' IS NULL' );
|
||||
}
|
||||
|
||||
if ( count( $containerWhere ) )
|
||||
{
|
||||
$permQuery->join( $containerClass::$databaseTable, array_merge( $containerWhere, array( 'core_permission_index.perm_type_id=' . $containerClass::$databaseTable . '.' . $containerClass::$databasePrefix . $containerClass::$databaseColumnId ) ), 'STRAIGHT_JOIN' );
|
||||
}
|
||||
|
||||
foreach( $permQuery as $result )
|
||||
{
|
||||
$categories[] = $result;
|
||||
}
|
||||
|
||||
if( count( $categories ) )
|
||||
{
|
||||
$where[] = array( $containerClass::$databasePrefix . $containerClass::$databaseColumnId . ' IN(' . implode( ',', $categories ) . ')' );
|
||||
}
|
||||
}
|
||||
|
||||
$contentItems = 0;
|
||||
foreach( new ActiveRecordIterator( Db::i()->select( '*', $containerClass::$databaseTable, $where ), $containerClass ) as $node )
|
||||
{
|
||||
$contentItems += $node->_items;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* And however many for the content items */
|
||||
$contentItems = $class::getItemsWithPermission( $class::sitemapWhere(), NULL, NULL, 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, new \IPS\Member, NULL, NULL, NULL, TRUE );
|
||||
}
|
||||
|
||||
/* Choose which count to use to calculate the number of filess */
|
||||
$usedCount = ( $requestedCount > $contentItems OR $requestedCount <= 0 ) ? $contentItems : $requestedCount;
|
||||
@@ -226,7 +276,7 @@ class _Content extends \IPS\Content\ExtensionGenerator
|
||||
$select = array();
|
||||
if ( \in_array( 'IPS\Content\Permissions', class_implements( $nodeClass ) ) or \in_array( 'IPS\Node\Permissions', class_implements( $nodeClass ) ) )
|
||||
{
|
||||
$select = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $nodeClass::$databaseTable, array( '(' . \IPS\Db::i()->findInSet( "perm_{$nodeClass::$permissionMap['read']}", array( \IPS\Settings::i()->guest_group ) ) . ' OR ' . "perm_{$nodeClass::$permissionMap['read']}=? )", '*' ) )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id={$nodeClass::$databaseTable}.{$nodeClass::$databasePrefix}{$nodeClass::$databaseColumnId}", $nodeClass::$permApp, $nodeClass::$permType ) ), $nodeClass );
|
||||
$select = new ActiveRecordIterator( \IPS\Db::i()->select( '*', $nodeClass::$databaseTable, array( '(' . \IPS\Db::i()->findInSet( "perm_{$nodeClass::$permissionMap['read']}", array( \IPS\Settings::i()->guest_group ) ) . ' OR ' . "perm_{$nodeClass::$permissionMap['read']}=? )", '*' ) )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id={$nodeClass::$databaseTable}.{$nodeClass::$databasePrefix}{$nodeClass::$databaseColumnId}", $nodeClass::$permApp, $nodeClass::$permType ) ), $nodeClass );
|
||||
}
|
||||
else if ( $nodeClass::$ownerTypes !== NULL and is_subclass_of( $nodeClass, 'IPS\Node\Model' ) )
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ class _Keywords extends \IPS\core\Statistics\Chart
|
||||
/**
|
||||
* @brief Controller
|
||||
*/
|
||||
public $controller = 'core_activitystats_keywords';
|
||||
public $controller = 'core_activitystats_keywords_time';
|
||||
|
||||
/**
|
||||
* Render Chart
|
||||
|
||||
@@ -10,8 +10,22 @@
|
||||
|
||||
namespace IPS\core\extensions\core\Statistics;
|
||||
|
||||
use IPS\core\Statistics\Chart as ParentClass;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Helpers\Chart;
|
||||
use IPS\Helpers\Chart\Database;
|
||||
use IPS\Member;
|
||||
use IPS\Theme;
|
||||
use IPS\DateTime as IPSDateTime;
|
||||
use IPS\Db;
|
||||
|
||||
use function defined;
|
||||
use function header;
|
||||
use function count;
|
||||
use function implode;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -20,7 +34,7 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
/**
|
||||
* Statistics Chart Extension
|
||||
*/
|
||||
class _Moderators extends \IPS\core\Statistics\Chart
|
||||
class _Moderators extends ParentClass
|
||||
{
|
||||
/**
|
||||
* @brief Controller
|
||||
@@ -33,34 +47,42 @@ class _Moderators extends \IPS\core\Statistics\Chart
|
||||
* @param \IPS\Http\Url $url URL the chart is being shown on.
|
||||
* @return \IPS\Helpers\Chart
|
||||
*/
|
||||
public function getChart( \IPS\Http\Url $url ): \IPS\Helpers\Chart
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( $url, 'core_moderator_logs', 'ctime', '', array(
|
||||
$chart = new Database( $url, 'core_moderator_logs', 'ctime', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'member_id', 'ctime' ), 'spam' );
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'member_id', 'ctime' ), 'users' );
|
||||
$chart->setExtension( $this );
|
||||
|
||||
$chart->groupBy = 'member_id';
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_moderator_activity_title');
|
||||
$chart->title = Member::loggedIn()->language()->addToStack('stats_moderator_activity_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
|
||||
$chart->tableLangPrefix = 'mod_stats_';
|
||||
$chart->tableInclude = array( 'member_id', 'lang_key', 'ctime' );
|
||||
$chart->tableParsers = array(
|
||||
'member_id' => function( $val ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinkWithPhoto( Member::load( $val ) );
|
||||
},
|
||||
'lang_key' => function( $val ) {
|
||||
return Member::loggedIn()->language()->addToStack( $val . '_stats' );
|
||||
},
|
||||
'ctime' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
return (string) IPSDateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
/* Didn't find any specified? Do the default of the top 50 moderators */
|
||||
$where = array();
|
||||
if ( $chart->start instanceof \IPS\DateTime or $chart->end instanceof \IPS\DateTime )
|
||||
if ( $chart->start instanceof IPSDateTime or $chart->end instanceof IPSDateTime )
|
||||
{
|
||||
$start = $chart->start instanceof \IPS\DateTime ? $chart->start->getTimestamp() : 0;
|
||||
$end = $chart->end instanceof \IPS\DateTime ? $chart->end->getTimestamp() : time();
|
||||
$start = $chart->start instanceof IPSDateTime ? $chart->start->getTimestamp() : 0;
|
||||
$end = $chart->end instanceof IPSDateTime ? $chart->end->getTimestamp() : time();
|
||||
$where[] = array( 'ctime BETWEEN ? AND ?', $start, $end );
|
||||
}
|
||||
|
||||
@@ -68,7 +90,7 @@ class _Moderators extends \IPS\core\Statistics\Chart
|
||||
$modMember = [];
|
||||
$modGroup = [];
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
|
||||
foreach ( Db::i()->select( '*', 'core_moderators' ) as $mod )
|
||||
{
|
||||
if ( $mod['type'] == 'g' )
|
||||
{
|
||||
@@ -82,28 +104,28 @@ class _Moderators extends \IPS\core\Statistics\Chart
|
||||
|
||||
$query = [];
|
||||
|
||||
if ( \count( $modGroup ) )
|
||||
if ( count( $modGroup ) )
|
||||
{
|
||||
$query[] = \IPS\Db::i()->in( 'member_group_id', $modGroup );
|
||||
$query[] = \IPS\Db::i()->findInSet( 'mgroup_others', $modGroup );
|
||||
$query[] = Db::i()->in( 'member_group_id', $modGroup );
|
||||
$query[] = Db::i()->findInSet( 'mgroup_others', $modGroup );
|
||||
}
|
||||
|
||||
if ( \count( $modMember ) )
|
||||
if ( count( $modMember ) )
|
||||
{
|
||||
$query[] = \IPS\Db::i()->in( 'member_id', $modMember );
|
||||
$query[] = Db::i()->in( 'member_id', $modMember );
|
||||
}
|
||||
|
||||
/* I mean $query should never be empty, but lets not wait for a ticket and have to release a patch to find out that it could be... */
|
||||
if ( \count( $query ) )
|
||||
if ( count( $query ) )
|
||||
{
|
||||
$where[] = [ 'member_id IN(?)', \IPS\Db::i()->select( 'member_id', 'core_members', implode( ' OR ', $query ) ) ];
|
||||
$where[] = [ 'member_id IN(?)', Db::i()->select( 'member_id', 'core_members', implode( ' OR ', $query ) ) ];
|
||||
}
|
||||
|
||||
$topModerators = \IPS\Db::i()->select( 'member_id, COUNT(*) as _mod_count', 'core_moderator_logs', $where, '_mod_count DESC', 50, array( 'member_id' ) );
|
||||
$topModerators = Db::i()->select( 'member_id, COUNT(*) as _mod_count', 'core_moderator_logs', $where, '_mod_count DESC', 50, array( 'member_id' ) );
|
||||
|
||||
foreach ( $topModerators as $moderatorRow )
|
||||
{
|
||||
$member = \IPS\Member::load( $moderatorRow['member_id'] );
|
||||
$member = Member::load( $moderatorRow['member_id'] );
|
||||
$chart->addSeries(
|
||||
( $member->member_id ) ? $member->name : \IPS\Member::loggedIn()->language()->addToStack( 'deleted_member' ),
|
||||
'number',
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Statistics Chart Extension
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
|
||||
* @since 20 Dec 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\Statistics;
|
||||
|
||||
use IPS\core\Statistics\Chart as ParentClass;
|
||||
use IPS\Helpers\Chart;
|
||||
use IPS\Helpers\Chart\Database;
|
||||
use IPS\Http\Url;
|
||||
use IPS\DateTime as IPSDateTime;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
use IPS\Db;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Theme;
|
||||
|
||||
use DateInterval;
|
||||
|
||||
use function defined;
|
||||
use function header;
|
||||
use function array_values;
|
||||
use function explode;
|
||||
use function is_array;
|
||||
use function count;
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistics Chart Extension
|
||||
*/
|
||||
class _ModeratorsByAction extends ParentClass
|
||||
{
|
||||
/**
|
||||
* @brief Controller
|
||||
*/
|
||||
public $controller = 'core_stats_moderators_actions';
|
||||
|
||||
/**
|
||||
* Render Chart
|
||||
*
|
||||
* @param \IPS\Http\Url $url URL the chart is being shown on.
|
||||
* @return \IPS\Helpers\Chart
|
||||
*/
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
$chart = new Database( $url, 'core_moderator_logs', 'ctime', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => IPSDateTime::create()->sub( new DateInterval( 'P90D' ) ), 'end' => IPSDateTime::create() ), array( 'lang_key', 'ctime' ), 'actions' );
|
||||
$chart->setExtension( $this );
|
||||
|
||||
$chart->groupBy = 'lang_key';
|
||||
$chart->title = Member::loggedIn()->language()->addToStack('stats_moderator_activity_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->joins = array( array( 'core_members', "core_moderator_logs.member_id=core_members.member_id" ) );
|
||||
|
||||
$chart->tableInclude = array( 'member_id', 'lang_key', 'ctime' );
|
||||
$chart->tableParsers = array(
|
||||
'member_id' => function( $val, $row ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinKWithPhoto( Member::constructFromData( $row ) );
|
||||
},
|
||||
'lang_key' => function( $val ) {
|
||||
return Member::loggedIn()->language()->addToStack( $val . '_stats' );
|
||||
},
|
||||
'ctime' => function( $val )
|
||||
{
|
||||
return (string) IPSDateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
$chart->tableLangPrefix = 'mod_stats_';
|
||||
|
||||
$customActionValues = ( isset( $chart->savedCustomFilters['chart_actions'] ) ) ? array_values( explode( ',', $chart->savedCustomFilters['chart_actions'] ) ) : -1;
|
||||
$customGroupValues = ( isset( $chart->savedCustomFilters['chart_groups'] ) ) ? array_values( explode( ',', $chart->savedCustomFilters['chart_groups'] ) ) : -1;
|
||||
|
||||
$allActions = array();
|
||||
foreach( Db::i()->select( 'DISTINCT(lang_key)', 'core_moderator_logs' ) AS $action )
|
||||
{
|
||||
$allActions[ $action ] = $action . '_stats';
|
||||
}
|
||||
|
||||
$allGroups = array();
|
||||
foreach( Group::groups( TRUE, FALSE ) AS $group )
|
||||
{
|
||||
$allGroups[ $group->g_id ] = $group->name;
|
||||
}
|
||||
|
||||
$chart->customFiltersForm = array(
|
||||
'form' => array(
|
||||
new Select( 'chart_actions', $customActionValues, FALSE, array( 'options' => $allActions, 'multiple' => TRUE, 'noDefault' => TRUE, 'unlimited' => -1 ), NULL, NULL, NULL, 'chart_actions' ),
|
||||
new Select( 'chart_groups', $customGroupValues, FALSE, array( 'options' => $allGroups, 'multiple' => TRUE, 'noDefault' => TRUE, 'unlimited' => -1 ), NULL, NULL, NULL, 'chart_groups' ),
|
||||
),
|
||||
'where' => function( $values )
|
||||
{
|
||||
$actions = array();
|
||||
if ( $values['chart_actions'] != -1 )
|
||||
{
|
||||
$actions = is_array( $values['chart_actions'] ) ? array_values( $values['chart_actions'] ) : explode( ',', $values['chart_actions'] );
|
||||
}
|
||||
|
||||
$groups = array();
|
||||
if ( $values['chart_groups'] != -1 )
|
||||
{
|
||||
$groups = is_array( $values['chart_groups'] ) ? array_values( $values['chart_groups'] ) : explode( ',', $values['chart_groups'] );
|
||||
}
|
||||
|
||||
$where = array();
|
||||
if ( count( $actions ) )
|
||||
{
|
||||
$where[] = Db::i()->in( 'lang_key', $actions );
|
||||
}
|
||||
|
||||
if ( count( $groups ) )
|
||||
{
|
||||
$where[] = Db::i()->in( 'core_members.member_group_id', $groups );
|
||||
}
|
||||
|
||||
if ( count( $where ) )
|
||||
{
|
||||
return array( implode( ' AND ', $where ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
},
|
||||
'groupBy' => 'lang_key',
|
||||
'series' => function( $values ) use ( $allActions )
|
||||
{
|
||||
$series = array();
|
||||
if ( $values['chart_actions'] == -1 )
|
||||
{
|
||||
$custom = array_keys( $allActions );
|
||||
}
|
||||
else
|
||||
{
|
||||
$custom = is_array( $values['chart_actions'] ) ? array_values( $values['chart_actions'] ) : explode( ',', $values['chart_actions'] );
|
||||
}
|
||||
|
||||
foreach( $custom as $key )
|
||||
{
|
||||
$series[] = array( Member::loggedIn()->language()->addToStack( $key . '_stats' ), 'number', 'COUNT(*)', FALSE, $key );
|
||||
}
|
||||
return $series;
|
||||
},
|
||||
'defaultSeries' => function() use ( $allActions )
|
||||
{
|
||||
$series = array();
|
||||
foreach( $allActions as $key => $lang )
|
||||
{
|
||||
$series[] = array( Member::loggedIn()->language()->addToStack( $lang ), 'number', 'COUNT(*)', FALSE, $key );
|
||||
}
|
||||
|
||||
return $series;
|
||||
}
|
||||
);
|
||||
|
||||
return $chart;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ class _Points extends \IPS\core\Statistics\Chart
|
||||
/**
|
||||
* @brief Controller
|
||||
*/
|
||||
public $controller = NULL;
|
||||
public $controller = 'core_stats_points';
|
||||
|
||||
/**
|
||||
* Render Chart
|
||||
@@ -35,7 +35,7 @@ class _Points extends \IPS\core\Statistics\Chart
|
||||
*/
|
||||
public function getChart( \IPS\Http\Url $url ): \IPS\Helpers\Chart
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=points' ), 'core_points_log', 'datetime', '', array(
|
||||
$chart = new \IPS\Helpers\Chart\Database( $url, 'core_points_log', 'datetime', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde' ),
|
||||
|
||||
@@ -25,7 +25,7 @@ class _Tags extends \IPS\core\Statistics\Chart
|
||||
/**
|
||||
* @brief Controller
|
||||
*/
|
||||
public $controller = NULL;
|
||||
public $controller = 'core_activitystats_tags';
|
||||
|
||||
/**
|
||||
* Render Chart
|
||||
|
||||
@@ -10,8 +10,20 @@
|
||||
|
||||
namespace IPS\core\extensions\core\Statistics;
|
||||
|
||||
use IPS\core\Statistics\Chart as ParentClass;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Helpers\Chart;
|
||||
use IPS\Helpers\Chart\Database;
|
||||
use IPS\core\Warnings\Reason;
|
||||
use IPS\Member;
|
||||
use IPS\DateTime as IPSDateTime;
|
||||
use IPS\Theme;
|
||||
|
||||
use function defined;
|
||||
use function header;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -20,7 +32,7 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
/**
|
||||
* Statistics Chart Extension
|
||||
*/
|
||||
class _WarningReasons extends \IPS\core\Statistics\Chart
|
||||
class _WarningReasons extends ParentClass
|
||||
{
|
||||
/**
|
||||
* @brief Controller
|
||||
@@ -33,9 +45,9 @@ class _WarningReasons extends \IPS\core\Statistics\Chart
|
||||
* @param \IPS\Http\Url $url URL the chart is being shown on.
|
||||
* @return \IPS\Helpers\Chart
|
||||
*/
|
||||
public function getChart( \IPS\Http\Url $url ): \IPS\Helpers\Chart
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( $url, 'core_members_warn_logs', 'wl_date', '', array(
|
||||
$chart = new Database( $url, 'core_members_warn_logs', 'wl_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
@@ -46,19 +58,29 @@ class _WarningReasons extends \IPS\core\Statistics\Chart
|
||||
|
||||
$chart->groupBy = 'wl_reason';
|
||||
|
||||
foreach( \IPS\core\Warnings\Reason::roots() as $reason )
|
||||
foreach( Reason::roots() as $reason )
|
||||
{
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('core_warn_reason_' . $reason->id ), 'number', 'COUNT(*)', TRUE, $reason->id );
|
||||
$chart->addSeries( Member::loggedIn()->language()->addToStack('core_warn_reason_' . $reason->id ), 'number', 'COUNT(*)', TRUE, $reason->id );
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_warnings_title');
|
||||
$chart->title = Member::loggedIn()->language()->addToStack('stats_warnings_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->extension = $this;
|
||||
|
||||
$chart->tableInclude = array( 'wl_moderator', 'wl_member', 'wl_reason', 'wl_date' );
|
||||
$chart->tableParsers = array(
|
||||
'wl_moderator' => function( $val ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinkWithPhoto( Member::load( $val ) );
|
||||
},
|
||||
'wl_member' => function( $val ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinkWithPhoto( Member::load( $val ) );
|
||||
},
|
||||
'wl_reason' => function( $val ) {
|
||||
return Member::loggedIn()->language()->addToStack( Reason::$titleLangPrefix . $val );
|
||||
},
|
||||
'wl_date' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
return (string) IPSDateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -10,8 +10,20 @@
|
||||
|
||||
namespace IPS\core\extensions\core\Statistics;
|
||||
|
||||
use IPS\core\Statistics\Chart as ParentClass;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Helpers\Chart;
|
||||
use IPS\Helpers\Chart\Database;
|
||||
use IPS\core\Warnings\Reason;
|
||||
use IPS\Member;
|
||||
use IPS\DateTime as IPSDateTime;
|
||||
use IPS\Theme;
|
||||
|
||||
use function defined;
|
||||
use function header;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -20,7 +32,7 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
/**
|
||||
* Statistics Chart Extension
|
||||
*/
|
||||
class _WarningSuspended extends \IPS\core\Statistics\Chart
|
||||
class _WarningSuspended extends ParentClass
|
||||
{
|
||||
/**
|
||||
* @brief Controller
|
||||
@@ -33,9 +45,9 @@ class _WarningSuspended extends \IPS\core\Statistics\Chart
|
||||
* @param \IPS\Http\Url $url URL the chart is being shown on.
|
||||
* @return \IPS\Helpers\Chart
|
||||
*/
|
||||
public function getChart( \IPS\Http\Url $url ): \IPS\Helpers\Chart
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( $url, 'core_members_warn_logs', 'wl_date', '', array(
|
||||
$chart = new Database( $url, 'core_members_warn_logs', 'wl_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
@@ -46,16 +58,26 @@ class _WarningSuspended extends \IPS\core\Statistics\Chart
|
||||
|
||||
$chart->where = array( 'wl_suspend IS NOT NULL' );
|
||||
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('suspended' ), 'number', 'COUNT(*)', TRUE );
|
||||
$chart->addSeries( Member::loggedIn()->language()->addToStack('suspended' ), 'number', 'COUNT(*)', TRUE );
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_warnings_title');
|
||||
$chart->title = Member::loggedIn()->language()->addToStack('stats_suspended_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->extension = $this;
|
||||
|
||||
$chart->tableInclude = array( 'wl_moderator', 'wl_member', 'wl_reason', 'wl_date' );
|
||||
$chart->tableParsers = array(
|
||||
'wl_moderator' => function( $val ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinkWithPhoto( Member::load( $val ) );
|
||||
},
|
||||
'wl_member' => function( $val ) {
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'admin' )->userLinkWithPhoto( Member::load( $val ) );
|
||||
},
|
||||
'wl_reason' => function( $val ) {
|
||||
return Member::loggedIn()->language()->addToStack( Reason::$titleLangPrefix . $val );
|
||||
},
|
||||
'wl_date' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
return (string) IPSDateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user